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