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
ini_line_parse(const char * line,char * section,char * name,char * value)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
ini_init(ini_t * ini)167 void ini_init(ini_t *ini){
168 memset(ini,0,sizeof(ini_t));
169 }
170
171 // ini_clear()
172
ini_clear(ini_t * ini)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
ini_copy(ini_t * dst,ini_t * src)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
ini_find(ini_t * ini,const char * section,const char * name)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
ini_insert(ini_t * ini,ini_entry_t * entry)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
ini_insert_ex(ini_t * ini,const char * section,const char * name,const char * value)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
ini_parse(ini_t * ini,const char * filename)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(¤t_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(¤t_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
ini_disp(ini_t * ini)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
ini_start_iter(ini_t * ini)314 void ini_start_iter(ini_t *ini){
315 ini->iter=0;
316 }
317
318 // ini_next()
319
ini_next(ini_t * ini)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
329