version 1.4.58b
[polyglot.git] / ini.c
1 // includes
2
3 #include <stdio.h>
4 #include "option.h"
5 #include "ini.h"
6 #include "string.h"
7 #include "util.h"
8 #include "errno.h"
9
10 // macros
11
12 #define StringSize ((int) 4096)
13
14 // types
15
16 typedef enum {
17     START               =0,
18     SECTION_NAME        =1,
19     NAME                =2,
20     NAME_SPACE          =3,
21     START_VALUE         =4,
22     VALUE               =5,
23     VALUE_SPACE         =6,
24     QUOTE_SPACE         =7,
25     FINISHED            =8,
26 } parse_state_t;
27
28 // variables
29
30 const char *ini_specials=";\\#[]=";
31
32 // functions
33
34 // ini_line_parse()
35
36 line_type_t ini_line_parse(const char *line,
37                                   char *section,
38                                   char *name,
39                                   char *value){
40     int i;
41     parse_state_t state=START;
42     int name_index=0;
43     int value_index=0;
44     int section_index=0;
45     int index=0;
46     char c;
47     int type=SYNTAX_ERROR;
48     int spaces=0;
49     bool quoted;
50     while(state!=FINISHED){
51         c=line[index++];
52         quoted=FALSE;
53         if(c=='\\'){
54           if(strchr(ini_specials,line[index])){
55             quoted=TRUE;
56             c=line[index++];
57           }
58         }
59         //             printf("STATE=%d quoted=%d c=[%c]\n",state,quoted,c);
60         switch(state){
61             case START:
62               if(!quoted && ((c==';')||(c=='#')||(c=='\r')||
63                              (c=='\n')||(c=='\0'))){
64                     type=EMPTY_LINE;
65                     state=FINISHED;
66                 }else if(!quoted && c=='['){
67                     state=SECTION_NAME;
68                 }else if(quoted || c!=' '){
69                     name[name_index++]=c;
70                     state=NAME;
71                 }
72                 goto next;
73                 break;
74             case NAME:
75                 if(!quoted && c=='='){
76                     state=START_VALUE;
77                 }else if(!quoted && c==' '){
78                     state=NAME_SPACE;
79                     spaces=1;
80                 }else if(!quoted && ((c==';')||(c=='#')||(c=='\r')
81                                      ||(c=='\n')||(c=='\0'))){
82                     type=SYNTAX_ERROR;
83                     state=FINISHED;
84                 }else{
85                     name[name_index++]=c;
86                 }
87                 goto next;
88                 break;    // we don't get here
89             case NAME_SPACE:
90                 if(!quoted && c==' '){
91                     spaces++;
92                 }else if(!quoted && c=='='){
93                     state=START_VALUE;
94                 }else if(!quoted && ((c==';')||(c=='#')||(c=='\r')||
95                                      (c=='\n')||(c=='\0'))){
96                     type=SYNTAX_ERROR;
97                     state=FINISHED;
98                 }else{
99                     for(i=0;i<spaces;i++){
100                         name[name_index++]=' ';
101                     }
102                     spaces=0;
103                     name[name_index++]=c;
104                     state=NAME;
105                 }
106                 goto next;
107                 break;    // we don't get here
108             case START_VALUE:
109                 if(!quoted && ((c==';')||(c=='#')||(c=='\r')||
110                              (c=='\n')||(c=='\0'))){
111                     type=EMPTY_VALUE;
112                     state=FINISHED;
113                 }else if(quoted || c!=' '){
114                     value[value_index++]=c;
115                     state=VALUE;
116                 }
117                 goto next;
118                 break;    // we don't get here
119             case VALUE:
120                 if(!quoted && c==' '){
121                     state=VALUE_SPACE;
122                     spaces=1;
123                 }else if(!quoted && ((c=='\r' || c=='\n' || c==';' || 
124                                       c=='#'||(c=='\0')))){
125                     type=NAME_VALUE;
126                     state=FINISHED;
127                 }else{
128                     value[value_index++]=c;
129                 }
130                 goto next;
131                 break;    // we don't get here
132             case VALUE_SPACE:
133                 if(!quoted && c==' '){
134                     spaces++;
135                 }else if(!quoted && ((c=='\r' || c=='\n' || c==';' || 
136                                       c=='#'||(c=='\0')))){
137                     type=NAME_VALUE;
138                     state=FINISHED;
139                 }else{
140                     for(i=0;i<spaces;i++){
141                         value[value_index++]=' ';
142                     }
143                     spaces=0;
144                     value[value_index++]=c;
145                     state=VALUE;
146                 }
147                 goto next;
148                 break;    // we don't get here
149             case SECTION_NAME:
150                 if(!quoted && c==']'){
151                     type=SECTION;
152                     state=FINISHED;
153                 }else{
154                     section[section_index++]=c;
155                 }
156                 goto next;
157                 break;    // we don't get here
158             default:
159                 break;
160         }
161       next:        if(!c) break;
162     }
163     section[section_index]='\0';
164     name[name_index]='\0';
165     value[value_index]='\0';
166     return type;
167 }
168
169 // ini_init()
170
171 void ini_init(ini_t *ini){
172     memset(ini,0,sizeof(ini_t));
173 }
174
175 // ini_clear()
176
177 void ini_clear(ini_t *ini){
178     int i;
179     ini_entry_t * entry;
180     for(i=0; i< ini->index; i++){
181         entry=ini->entries+i;
182         if(entry->name!=NULL){
183             my_string_clear(&entry->name);
184         }
185         if(entry->value!=NULL){
186             my_string_clear(&entry->value);
187         }
188         if(entry->comment!=NULL){
189             my_string_clear(&entry->comment);
190         }
191     }
192     ini->index=0;
193 }
194
195 // ini_copy()
196
197 void ini_copy(ini_t *dst, ini_t *src){
198   int i;
199   dst->index=src->index;
200   dst->iter=src->iter;
201   for(i=0;i<src->index;i++){
202     my_string_set(&dst->entries[i].section,src->entries[i].section);
203     my_string_set(&dst->entries[i].name,src->entries[i].name);
204     my_string_set(&dst->entries[i].value,src->entries[i].value);
205   }
206 }
207
208 // ini_find()
209
210 ini_entry_t *ini_find(ini_t *ini, const char *section, const char* name){
211     int i;
212     ini_entry_t * entry;
213     for(i=0; i< ini->index; i++){
214         entry=ini->entries+i;
215         if(my_string_case_equal(entry->name,name) &&
216            my_string_case_equal(entry->section,section)){
217             return entry;
218         }
219     }
220     return NULL;
221 }
222
223 // ini_insert()
224
225 void ini_insert(ini_t *ini, ini_entry_t *entry){
226     ini_entry_t * ini_entry;
227     ini_entry=ini_find(ini,entry->section,entry->name);
228     if(ini_entry!=NULL){
229         my_string_set(&ini_entry->value,entry->value);
230     }else{
231         if(ini->index>=IniEntriesNb){
232             my_fatal("ini_insert(): too many options\n");
233         }
234         ini_entry=ini->entries+(ini->index++);
235         my_string_set(&ini_entry->value,entry->value);
236         my_string_set(&ini_entry->name,entry->name);
237         my_string_set(&ini_entry->section,entry->section);
238     }
239 }
240
241 // ini_insert_ex()
242
243 void ini_insert_ex(ini_t *ini,
244                    const char *section,
245                    const char *name,
246                    const char *value){
247     ini_entry_t entry[1];
248     memset(entry,0,sizeof(ini_entry_t));
249     my_string_set(&entry->section,section);
250     my_string_set(&entry->name,name);
251     my_string_set(&entry->value,value);
252     ini_insert(ini,entry);
253     my_string_clear(&entry->section);
254     my_string_clear(&entry->name);
255     my_string_clear(&entry->value);
256 }
257
258 // ini_parse()
259
260 int ini_parse(ini_t *ini, const char *filename){
261     char name[StringSize];
262     char value[StringSize];
263     char section[StringSize];
264     char line[StringSize];
265     ini_entry_t entry[1];
266     line_type_t result;
267     const char *current_section=NULL;
268     FILE *f;
269     int line_nr=0;
270     my_string_set(&current_section,"Main");
271     memset(entry,0,sizeof(ini_entry_t));
272     f=fopen(filename,"r");
273     if(!f) {
274             //    my_fatal("ini_parse(): Can't open file \"%s\": %s\n",
275             //     filename,
276             //     strerror(errno));
277             // For now fail silently
278         return -1;
279     }
280     while(TRUE){
281         if(!fgets(line,StringSize,f)){
282             break;
283         }
284         line_nr++;
285         result=ini_line_parse(line,section,name,value);
286         if(result==SECTION){
287             my_string_set(&current_section,section);
288         }else if(result==NAME_VALUE){
289             ini_insert_ex(ini,current_section,name,value);
290         }else if(result==SYNTAX_ERROR){
291             my_fatal("ini_parse(): Syntax error in \"%s\": line %d\n",
292                      filename,
293                      line_nr);
294             
295         }else {  // empty line
296         }
297         
298     }
299     fclose(f);
300     return 0;
301
302 }
303
304 // ini_disp()
305
306 void ini_disp(ini_t *ini){
307     int i;
308     for(i=0;i<ini->index;i++){
309         my_log("POLYGLOT [%s] %s=\"%s\"\n",
310                (ini->entries)[i].section,
311                (ini->entries)[i].name,
312                (ini->entries)[i].value);
313     }
314 }
315
316 // ini_start_iter()
317
318 void ini_start_iter(ini_t *ini){
319     ini->iter=0;
320 }
321
322 // ini_next()
323
324 ini_entry_t * ini_next(ini_t *ini){
325     ASSERT(ini->iter<=ini->index);
326     if(ini->iter==ini->index){
327         return NULL;
328     }
329     return &ini->entries[ini->iter++];
330 }
331
332