|
1 |
|
2 /*-------------------------------------------------------------------------*/ |
|
3 /** |
|
4 @file iniparser.c |
|
5 @author N. Devillard |
|
6 @brief Parser for ini files. |
|
7 */ |
|
8 /*--------------------------------------------------------------------------*/ |
|
9 /*---------------------------- Includes ------------------------------------*/ |
|
10 #include <ctype.h> |
|
11 #include "iniparser.h" |
|
12 |
|
13 /*---------------------------- Defines -------------------------------------*/ |
|
14 #define ASCIILINESZ (1024) |
|
15 #define INI_INVALID_KEY ((char*)-1) |
|
16 |
|
17 /*--------------------------------------------------------------------------- |
|
18 Private to this module |
|
19 ---------------------------------------------------------------------------*/ |
|
20 /** |
|
21 * This enum stores the status for each parsed line (internal use only). |
|
22 */ |
|
23 typedef enum _line_status_ { |
|
24 LINE_UNPROCESSED, |
|
25 LINE_ERROR, |
|
26 LINE_EMPTY, |
|
27 LINE_COMMENT, |
|
28 LINE_SECTION, |
|
29 LINE_VALUE |
|
30 } line_status ; |
|
31 |
|
32 /*-------------------------------------------------------------------------*/ |
|
33 /** |
|
34 @brief Convert a string to lowercase. |
|
35 @param s String to convert. |
|
36 @return ptr to statically allocated string. |
|
37 |
|
38 This function returns a pointer to a statically allocated string |
|
39 containing a lowercased version of the input string. Do not free |
|
40 or modify the returned string! Since the returned string is statically |
|
41 allocated, it will be modified at each function call (not re-entrant). |
|
42 */ |
|
43 /*--------------------------------------------------------------------------*/ |
|
44 static char * strlwc(const char * s) |
|
45 { |
|
46 static char l[ASCIILINESZ+1]; |
|
47 int i ; |
|
48 |
|
49 if (s==NULL) return NULL ; |
|
50 memset(l, 0, ASCIILINESZ+1); |
|
51 i=0 ; |
|
52 while (s[i] && i<ASCIILINESZ) { |
|
53 l[i] = (char)tolower((int)s[i]); |
|
54 i++ ; |
|
55 } |
|
56 l[ASCIILINESZ]=(char)0; |
|
57 return l ; |
|
58 } |
|
59 |
|
60 /*-------------------------------------------------------------------------*/ |
|
61 /** |
|
62 @brief Remove blanks at the beginning and the end of a string. |
|
63 @param s String to parse. |
|
64 @return ptr to statically allocated string. |
|
65 |
|
66 This function returns a pointer to a statically allocated string, |
|
67 which is identical to the input string, except that all blank |
|
68 characters at the end and the beg. of the string have been removed. |
|
69 Do not free or modify the returned string! Since the returned string |
|
70 is statically allocated, it will be modified at each function call |
|
71 (not re-entrant). |
|
72 */ |
|
73 /*--------------------------------------------------------------------------*/ |
|
74 static char * strstrip(const char * s) |
|
75 { |
|
76 static char l[ASCIILINESZ+1]; |
|
77 char * last ; |
|
78 |
|
79 if (s==NULL) return NULL ; |
|
80 |
|
81 while (isspace((int)*s) && *s) s++; |
|
82 memset(l, 0, ASCIILINESZ+1); |
|
83 strcpy(l, s); |
|
84 last = l + strlen(l); |
|
85 while (last > l) { |
|
86 if (!isspace((int)*(last-1))) |
|
87 break ; |
|
88 last -- ; |
|
89 } |
|
90 *last = (char)0; |
|
91 return (char*)l ; |
|
92 } |
|
93 |
|
94 /*-------------------------------------------------------------------------*/ |
|
95 /** |
|
96 @brief Get number of sections in a dictionary |
|
97 @param d Dictionary to examine |
|
98 @return int Number of sections found in dictionary |
|
99 |
|
100 This function returns the number of sections found in a dictionary. |
|
101 The test to recognize sections is done on the string stored in the |
|
102 dictionary: a section name is given as "section" whereas a key is |
|
103 stored as "section:key", thus the test looks for entries that do not |
|
104 contain a colon. |
|
105 |
|
106 This clearly fails in the case a section name contains a colon, but |
|
107 this should simply be avoided. |
|
108 |
|
109 This function returns -1 in case of error. |
|
110 */ |
|
111 /*--------------------------------------------------------------------------*/ |
|
112 int iniparser_getnsec(dictionary * d) |
|
113 { |
|
114 int i ; |
|
115 int nsec ; |
|
116 |
|
117 if (d==NULL) return -1 ; |
|
118 nsec=0 ; |
|
119 for (i=0 ; i<d->size ; i++) { |
|
120 if (d->key[i]==NULL) |
|
121 continue ; |
|
122 if (strchr(d->key[i], ':')==NULL) { |
|
123 nsec ++ ; |
|
124 } |
|
125 } |
|
126 return nsec ; |
|
127 } |
|
128 |
|
129 /*-------------------------------------------------------------------------*/ |
|
130 /** |
|
131 @brief Get name for section n in a dictionary. |
|
132 @param d Dictionary to examine |
|
133 @param n Section number (from 0 to nsec-1). |
|
134 @return Pointer to char string |
|
135 |
|
136 This function locates the n-th section in a dictionary and returns |
|
137 its name as a pointer to a string statically allocated inside the |
|
138 dictionary. Do not free or modify the returned string! |
|
139 |
|
140 This function returns NULL in case of error. |
|
141 */ |
|
142 /*--------------------------------------------------------------------------*/ |
|
143 char * iniparser_getsecname(dictionary * d, int n) |
|
144 { |
|
145 int i ; |
|
146 int foundsec ; |
|
147 |
|
148 if (d==NULL || n<0) return NULL ; |
|
149 foundsec=0 ; |
|
150 for (i=0 ; i<d->size ; i++) { |
|
151 if (d->key[i]==NULL) |
|
152 continue ; |
|
153 if (strchr(d->key[i], ':')==NULL) { |
|
154 foundsec++ ; |
|
155 if (foundsec>n) |
|
156 break ; |
|
157 } |
|
158 } |
|
159 if (foundsec<=n) { |
|
160 return NULL ; |
|
161 } |
|
162 return d->key[i] ; |
|
163 } |
|
164 |
|
165 /*-------------------------------------------------------------------------*/ |
|
166 /** |
|
167 @brief Dump a dictionary to an opened file pointer. |
|
168 @param d Dictionary to dump. |
|
169 @param f Opened file pointer to dump to. |
|
170 @return void |
|
171 |
|
172 This function prints out the contents of a dictionary, one element by |
|
173 line, onto the provided file pointer. It is OK to specify @c stderr |
|
174 or @c stdout as output files. This function is meant for debugging |
|
175 purposes mostly. |
|
176 */ |
|
177 /*--------------------------------------------------------------------------*/ |
|
178 void iniparser_dump(dictionary * d, FILE * f) |
|
179 { |
|
180 int i ; |
|
181 |
|
182 if (d==NULL || f==NULL) return ; |
|
183 for (i=0 ; i<d->size ; i++) { |
|
184 if (d->key[i]==NULL) |
|
185 continue ; |
|
186 if (d->val[i]!=NULL) { |
|
187 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); |
|
188 } else { |
|
189 fprintf(f, "[%s]=UNDEF\n", d->key[i]); |
|
190 } |
|
191 } |
|
192 return ; |
|
193 } |
|
194 |
|
195 /*-------------------------------------------------------------------------*/ |
|
196 /** |
|
197 @brief Save a dictionary to a loadable ini file |
|
198 @param d Dictionary to dump |
|
199 @param f Opened file pointer to dump to |
|
200 @return void |
|
201 |
|
202 This function dumps a given dictionary into a loadable ini file. |
|
203 It is Ok to specify @c stderr or @c stdout as output files. |
|
204 */ |
|
205 /*--------------------------------------------------------------------------*/ |
|
206 void iniparser_dump_ini(dictionary * d, FILE * f) |
|
207 { |
|
208 int i ; |
|
209 int nsec ; |
|
210 char * secname ; |
|
211 |
|
212 if (d==NULL || f==NULL) return ; |
|
213 |
|
214 nsec = iniparser_getnsec(d); |
|
215 if (nsec<1) { |
|
216 /* No section in file: dump all keys as they are */ |
|
217 for (i=0 ; i<d->size ; i++) { |
|
218 if (d->key[i]==NULL) |
|
219 continue ; |
|
220 fprintf(f, "%s = %s\n", d->key[i], d->val[i]); |
|
221 } |
|
222 return ; |
|
223 } |
|
224 for (i=0 ; i<nsec ; i++) { |
|
225 secname = iniparser_getsecname(d, i) ; |
|
226 iniparser_dumpsection_ini(d, secname, f) ; |
|
227 } |
|
228 fprintf(f, "\n"); |
|
229 return ; |
|
230 } |
|
231 |
|
232 /*-------------------------------------------------------------------------*/ |
|
233 /** |
|
234 @brief Save a dictionary section to a loadable ini file |
|
235 @param d Dictionary to dump |
|
236 @param s Section name of dictionary to dump |
|
237 @param f Opened file pointer to dump to |
|
238 @return void |
|
239 |
|
240 This function dumps a given section of a given dictionary into a loadable ini |
|
241 file. It is Ok to specify @c stderr or @c stdout as output files. |
|
242 */ |
|
243 /*--------------------------------------------------------------------------*/ |
|
244 void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f) |
|
245 { |
|
246 int j ; |
|
247 char keym[ASCIILINESZ+1]; |
|
248 int seclen ; |
|
249 |
|
250 if (d==NULL || f==NULL) return ; |
|
251 if (! iniparser_find_entry(d, s)) return ; |
|
252 |
|
253 seclen = (int)strlen(s); |
|
254 fprintf(f, "\n[%s]\n", s); |
|
255 sprintf(keym, "%s:", s); |
|
256 for (j=0 ; j<d->size ; j++) { |
|
257 if (d->key[j]==NULL) |
|
258 continue ; |
|
259 if (!strncmp(d->key[j], keym, seclen+1)) { |
|
260 fprintf(f, |
|
261 "%-30s = %s\n", |
|
262 d->key[j]+seclen+1, |
|
263 d->val[j] ? d->val[j] : ""); |
|
264 } |
|
265 } |
|
266 fprintf(f, "\n"); |
|
267 return ; |
|
268 } |
|
269 |
|
270 /*-------------------------------------------------------------------------*/ |
|
271 /** |
|
272 @brief Get the number of keys in a section of a dictionary. |
|
273 @param d Dictionary to examine |
|
274 @param s Section name of dictionary to examine |
|
275 @return Number of keys in section |
|
276 */ |
|
277 /*--------------------------------------------------------------------------*/ |
|
278 int iniparser_getsecnkeys(dictionary * d, char * s) |
|
279 { |
|
280 int seclen, nkeys ; |
|
281 char keym[ASCIILINESZ+1]; |
|
282 int j ; |
|
283 |
|
284 nkeys = 0; |
|
285 |
|
286 if (d==NULL) return nkeys; |
|
287 if (! iniparser_find_entry(d, s)) return nkeys; |
|
288 |
|
289 seclen = (int)strlen(s); |
|
290 sprintf(keym, "%s:", s); |
|
291 |
|
292 for (j=0 ; j<d->size ; j++) { |
|
293 if (d->key[j]==NULL) |
|
294 continue ; |
|
295 if (!strncmp(d->key[j], keym, seclen+1)) |
|
296 nkeys++; |
|
297 } |
|
298 |
|
299 return nkeys; |
|
300 |
|
301 } |
|
302 |
|
303 /*-------------------------------------------------------------------------*/ |
|
304 /** |
|
305 @brief Get the number of keys in a section of a dictionary. |
|
306 @param d Dictionary to examine |
|
307 @param s Section name of dictionary to examine |
|
308 @return pointer to statically allocated character strings |
|
309 |
|
310 This function queries a dictionary and finds all keys in a given section. |
|
311 Each pointer in the returned char pointer-to-pointer is pointing to |
|
312 a string allocated in the dictionary; do not free or modify them. |
|
313 |
|
314 This function returns NULL in case of error. |
|
315 */ |
|
316 /*--------------------------------------------------------------------------*/ |
|
317 char ** iniparser_getseckeys(dictionary * d, char * s) |
|
318 { |
|
319 |
|
320 char **keys; |
|
321 |
|
322 int i, j ; |
|
323 char keym[ASCIILINESZ+1]; |
|
324 int seclen, nkeys ; |
|
325 |
|
326 keys = NULL; |
|
327 |
|
328 if (d==NULL) return keys; |
|
329 if (! iniparser_find_entry(d, s)) return keys; |
|
330 |
|
331 nkeys = iniparser_getsecnkeys(d, s); |
|
332 |
|
333 keys = (char**) malloc(nkeys*sizeof(char*)); |
|
334 |
|
335 seclen = (int)strlen(s); |
|
336 sprintf(keym, "%s:", s); |
|
337 |
|
338 i = 0; |
|
339 |
|
340 for (j=0 ; j<d->size ; j++) { |
|
341 if (d->key[j]==NULL) |
|
342 continue ; |
|
343 if (!strncmp(d->key[j], keym, seclen+1)) { |
|
344 keys[i] = d->key[j]; |
|
345 i++; |
|
346 } |
|
347 } |
|
348 |
|
349 return keys; |
|
350 |
|
351 } |
|
352 |
|
353 /*-------------------------------------------------------------------------*/ |
|
354 /** |
|
355 @brief Get the string associated to a key |
|
356 @param d Dictionary to search |
|
357 @param key Key string to look for |
|
358 @param def Default value to return if key not found. |
|
359 @return pointer to statically allocated character string |
|
360 |
|
361 This function queries a dictionary for a key. A key as read from an |
|
362 ini file is given as "section:key". If the key cannot be found, |
|
363 the pointer passed as 'def' is returned. |
|
364 The returned char pointer is pointing to a string allocated in |
|
365 the dictionary, do not free or modify it. |
|
366 */ |
|
367 /*--------------------------------------------------------------------------*/ |
|
368 char * iniparser_getstring(dictionary * d, const char * key, char * def) |
|
369 { |
|
370 char * lc_key ; |
|
371 char * sval ; |
|
372 |
|
373 if (d==NULL || key==NULL) |
|
374 return def ; |
|
375 |
|
376 lc_key = strlwc(key); |
|
377 sval = dictionary_get(d, lc_key, def); |
|
378 return sval ; |
|
379 } |
|
380 |
|
381 /*-------------------------------------------------------------------------*/ |
|
382 /** |
|
383 @brief Get the string associated to a key, convert to an int |
|
384 @param d Dictionary to search |
|
385 @param key Key string to look for |
|
386 @param notfound Value to return in case of error |
|
387 @return integer |
|
388 |
|
389 This function queries a dictionary for a key. A key as read from an |
|
390 ini file is given as "section:key". If the key cannot be found, |
|
391 the notfound value is returned. |
|
392 |
|
393 Supported values for integers include the usual C notation |
|
394 so decimal, octal (starting with 0) and hexadecimal (starting with 0x) |
|
395 are supported. Examples: |
|
396 |
|
397 "42" -> 42 |
|
398 "042" -> 34 (octal -> decimal) |
|
399 "0x42" -> 66 (hexa -> decimal) |
|
400 |
|
401 Warning: the conversion may overflow in various ways. Conversion is |
|
402 totally outsourced to strtol(), see the associated man page for overflow |
|
403 handling. |
|
404 |
|
405 Credits: Thanks to A. Becker for suggesting strtol() |
|
406 */ |
|
407 /*--------------------------------------------------------------------------*/ |
|
408 int iniparser_getint(dictionary * d, const char * key, int notfound) |
|
409 { |
|
410 char * str ; |
|
411 |
|
412 str = iniparser_getstring(d, key, INI_INVALID_KEY); |
|
413 if (str==INI_INVALID_KEY) return notfound ; |
|
414 return (int)strtol(str, NULL, 0); |
|
415 } |
|
416 |
|
417 /*-------------------------------------------------------------------------*/ |
|
418 /** |
|
419 @brief Get the string associated to a key, convert to a double |
|
420 @param d Dictionary to search |
|
421 @param key Key string to look for |
|
422 @param notfound Value to return in case of error |
|
423 @return double |
|
424 |
|
425 This function queries a dictionary for a key. A key as read from an |
|
426 ini file is given as "section:key". If the key cannot be found, |
|
427 the notfound value is returned. |
|
428 */ |
|
429 /*--------------------------------------------------------------------------*/ |
|
430 double iniparser_getdouble(dictionary * d, const char * key, double notfound) |
|
431 { |
|
432 char * str ; |
|
433 |
|
434 str = iniparser_getstring(d, key, INI_INVALID_KEY); |
|
435 if (str==INI_INVALID_KEY) return notfound ; |
|
436 return atof(str); |
|
437 } |
|
438 |
|
439 /*-------------------------------------------------------------------------*/ |
|
440 /** |
|
441 @brief Get the string associated to a key, convert to a boolean |
|
442 @param d Dictionary to search |
|
443 @param key Key string to look for |
|
444 @param notfound Value to return in case of error |
|
445 @return integer |
|
446 |
|
447 This function queries a dictionary for a key. A key as read from an |
|
448 ini file is given as "section:key". If the key cannot be found, |
|
449 the notfound value is returned. |
|
450 |
|
451 A true boolean is found if one of the following is matched: |
|
452 |
|
453 - A string starting with 'y' |
|
454 - A string starting with 'Y' |
|
455 - A string starting with 't' |
|
456 - A string starting with 'T' |
|
457 - A string starting with '1' |
|
458 |
|
459 A false boolean is found if one of the following is matched: |
|
460 |
|
461 - A string starting with 'n' |
|
462 - A string starting with 'N' |
|
463 - A string starting with 'f' |
|
464 - A string starting with 'F' |
|
465 - A string starting with '0' |
|
466 |
|
467 The notfound value returned if no boolean is identified, does not |
|
468 necessarily have to be 0 or 1. |
|
469 */ |
|
470 /*--------------------------------------------------------------------------*/ |
|
471 int iniparser_getboolean(dictionary * d, const char * key, int notfound) |
|
472 { |
|
473 char * c ; |
|
474 int ret ; |
|
475 |
|
476 c = iniparser_getstring(d, key, INI_INVALID_KEY); |
|
477 if (c==INI_INVALID_KEY) return notfound ; |
|
478 if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { |
|
479 ret = 1 ; |
|
480 } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { |
|
481 ret = 0 ; |
|
482 } else { |
|
483 ret = notfound ; |
|
484 } |
|
485 return ret; |
|
486 } |
|
487 |
|
488 /*-------------------------------------------------------------------------*/ |
|
489 /** |
|
490 @brief Finds out if a given entry exists in a dictionary |
|
491 @param ini Dictionary to search |
|
492 @param entry Name of the entry to look for |
|
493 @return integer 1 if entry exists, 0 otherwise |
|
494 |
|
495 Finds out if a given entry exists in the dictionary. Since sections |
|
496 are stored as keys with NULL associated values, this is the only way |
|
497 of querying for the presence of sections in a dictionary. |
|
498 */ |
|
499 /*--------------------------------------------------------------------------*/ |
|
500 int iniparser_find_entry( |
|
501 dictionary * ini, |
|
502 const char * entry |
|
503 ) |
|
504 { |
|
505 int found=0 ; |
|
506 if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { |
|
507 found = 1 ; |
|
508 } |
|
509 return found ; |
|
510 } |
|
511 |
|
512 /*-------------------------------------------------------------------------*/ |
|
513 /** |
|
514 @brief Set an entry in a dictionary. |
|
515 @param ini Dictionary to modify. |
|
516 @param entry Entry to modify (entry name) |
|
517 @param val New value to associate to the entry. |
|
518 @return int 0 if Ok, -1 otherwise. |
|
519 |
|
520 If the given entry can be found in the dictionary, it is modified to |
|
521 contain the provided value. If it cannot be found, -1 is returned. |
|
522 It is Ok to set val to NULL. |
|
523 */ |
|
524 /*--------------------------------------------------------------------------*/ |
|
525 int iniparser_set(dictionary * ini, const char * entry, const char * val) |
|
526 { |
|
527 return dictionary_set(ini, strlwc(entry), val) ; |
|
528 } |
|
529 |
|
530 /*-------------------------------------------------------------------------*/ |
|
531 /** |
|
532 @brief Delete an entry in a dictionary |
|
533 @param ini Dictionary to modify |
|
534 @param entry Entry to delete (entry name) |
|
535 @return void |
|
536 |
|
537 If the given entry can be found, it is deleted from the dictionary. |
|
538 */ |
|
539 /*--------------------------------------------------------------------------*/ |
|
540 void iniparser_unset(dictionary * ini, const char * entry) |
|
541 { |
|
542 dictionary_unset(ini, strlwc(entry)); |
|
543 } |
|
544 |
|
545 /*-------------------------------------------------------------------------*/ |
|
546 /** |
|
547 @brief Load a single line from an INI file |
|
548 @param input_line Input line, may be concatenated multi-line input |
|
549 @param section Output space to store section |
|
550 @param key Output space to store key |
|
551 @param value Output space to store value |
|
552 @return line_status value |
|
553 */ |
|
554 /*--------------------------------------------------------------------------*/ |
|
555 static line_status iniparser_line( |
|
556 const char * input_line, |
|
557 char * section, |
|
558 char * key, |
|
559 char * value) |
|
560 { |
|
561 line_status sta ; |
|
562 char line[ASCIILINESZ+1]; |
|
563 int len ; |
|
564 |
|
565 strcpy(line, strstrip(input_line)); |
|
566 len = (int)strlen(line); |
|
567 |
|
568 sta = LINE_UNPROCESSED ; |
|
569 if (len<1) { |
|
570 /* Empty line */ |
|
571 sta = LINE_EMPTY ; |
|
572 } else if (line[0]=='#' || line[0]==';') { |
|
573 /* Comment line */ |
|
574 sta = LINE_COMMENT ; |
|
575 } else if (line[0]=='[' && line[len-1]==']') { |
|
576 /* Section name */ |
|
577 sscanf(line, "[%[^]]", section); |
|
578 strcpy(section, strstrip(section)); |
|
579 strcpy(section, strlwc(section)); |
|
580 sta = LINE_SECTION ; |
|
581 } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 |
|
582 || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 |
|
583 || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { |
|
584 /* Usual key=value, with or without comments */ |
|
585 strcpy(key, strstrip(key)); |
|
586 strcpy(key, strlwc(key)); |
|
587 strcpy(value, strstrip(value)); |
|
588 /* |
|
589 * sscanf cannot handle '' or "" as empty values |
|
590 * this is done here |
|
591 */ |
|
592 if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { |
|
593 value[0]=0 ; |
|
594 } |
|
595 sta = LINE_VALUE ; |
|
596 } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 |
|
597 || sscanf(line, "%[^=] %[=]", key, value) == 2) { |
|
598 /* |
|
599 * Special cases: |
|
600 * key= |
|
601 * key=; |
|
602 * key=# |
|
603 */ |
|
604 strcpy(key, strstrip(key)); |
|
605 strcpy(key, strlwc(key)); |
|
606 value[0]=0 ; |
|
607 sta = LINE_VALUE ; |
|
608 } else { |
|
609 /* Generate syntax error */ |
|
610 sta = LINE_ERROR ; |
|
611 } |
|
612 return sta ; |
|
613 } |
|
614 |
|
615 /*-------------------------------------------------------------------------*/ |
|
616 /** |
|
617 @brief Parse an ini file and return an allocated dictionary object |
|
618 @param ininame Name of the ini file to read. |
|
619 @return Pointer to newly allocated dictionary |
|
620 |
|
621 This is the parser for ini files. This function is called, providing |
|
622 the name of the file to be read. It returns a dictionary object that |
|
623 should not be accessed directly, but through accessor functions |
|
624 instead. |
|
625 |
|
626 The returned dictionary must be freed using iniparser_freedict(). |
|
627 */ |
|
628 /*--------------------------------------------------------------------------*/ |
|
629 dictionary * iniparser_load(const char * ininame) |
|
630 { |
|
631 FILE * in ; |
|
632 |
|
633 char line [ASCIILINESZ+1] ; |
|
634 char section [ASCIILINESZ+1] ; |
|
635 char key [ASCIILINESZ+1] ; |
|
636 char tmp [ASCIILINESZ+1] ; |
|
637 char val [ASCIILINESZ+1] ; |
|
638 |
|
639 int last=0 ; |
|
640 int len ; |
|
641 int lineno=0 ; |
|
642 int errs=0; |
|
643 |
|
644 dictionary * dict ; |
|
645 |
|
646 if ((in=fopen(ininame, "r"))==NULL) { |
|
647 fprintf(stderr, "iniparser: cannot open %s\n", ininame); |
|
648 return NULL ; |
|
649 } |
|
650 |
|
651 dict = dictionary_new(0) ; |
|
652 if (!dict) { |
|
653 fclose(in); |
|
654 return NULL ; |
|
655 } |
|
656 |
|
657 memset(line, 0, ASCIILINESZ); |
|
658 memset(section, 0, ASCIILINESZ); |
|
659 memset(key, 0, ASCIILINESZ); |
|
660 memset(val, 0, ASCIILINESZ); |
|
661 last=0 ; |
|
662 |
|
663 while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { |
|
664 lineno++ ; |
|
665 len = (int)strlen(line)-1; |
|
666 if (len==0) |
|
667 continue; |
|
668 /* Safety check against buffer overflows */ |
|
669 if (line[len]!='\n') { |
|
670 fprintf(stderr, |
|
671 "iniparser: input line too long in %s (%d)\n", |
|
672 ininame, |
|
673 lineno); |
|
674 dictionary_del(dict); |
|
675 fclose(in); |
|
676 return NULL ; |
|
677 } |
|
678 /* Get rid of \n and spaces at end of line */ |
|
679 while ((len>=0) && |
|
680 ((line[len]=='\n') || (isspace(line[len])))) { |
|
681 line[len]=0 ; |
|
682 len-- ; |
|
683 } |
|
684 /* Detect multi-line */ |
|
685 if (line[len]=='\\') { |
|
686 /* Multi-line value */ |
|
687 last=len ; |
|
688 continue ; |
|
689 } else { |
|
690 last=0 ; |
|
691 } |
|
692 switch (iniparser_line(line, section, key, val)) { |
|
693 case LINE_EMPTY: |
|
694 case LINE_COMMENT: |
|
695 break ; |
|
696 |
|
697 case LINE_SECTION: |
|
698 errs = dictionary_set(dict, section, NULL); |
|
699 break ; |
|
700 |
|
701 case LINE_VALUE: |
|
702 sprintf(tmp, "%s:%s", section, key); |
|
703 errs = dictionary_set(dict, tmp, val) ; |
|
704 break ; |
|
705 |
|
706 case LINE_ERROR: |
|
707 fprintf(stderr, "iniparser: syntax error in %s (%d):\n", |
|
708 ininame, |
|
709 lineno); |
|
710 fprintf(stderr, "-> %s\n", line); |
|
711 errs++ ; |
|
712 break; |
|
713 |
|
714 default: |
|
715 break ; |
|
716 } |
|
717 memset(line, 0, ASCIILINESZ); |
|
718 last=0; |
|
719 if (errs<0) { |
|
720 fprintf(stderr, "iniparser: memory allocation failure\n"); |
|
721 break ; |
|
722 } |
|
723 } |
|
724 if (errs) { |
|
725 dictionary_del(dict); |
|
726 dict = NULL ; |
|
727 } |
|
728 fclose(in); |
|
729 return dict ; |
|
730 } |
|
731 |
|
732 /*-------------------------------------------------------------------------*/ |
|
733 /** |
|
734 @brief Free all memory associated to an ini dictionary |
|
735 @param d Dictionary to free |
|
736 @return void |
|
737 |
|
738 Free all memory associated to an ini dictionary. |
|
739 It is mandatory to call this function before the dictionary object |
|
740 gets out of the current context. |
|
741 */ |
|
742 /*--------------------------------------------------------------------------*/ |
|
743 void iniparser_freedict(dictionary * d) |
|
744 { |
|
745 dictionary_del(d); |
|
746 } |
|
747 |
|
748 /* vim: set ts=4 et sw=4 tw=75 */ |