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