2 /*-------------------------------------------------------------------------*/
8 @brief Parser for ini files.
10 /*--------------------------------------------------------------------------*/
12 $Id: iniparser.c,v 2.19 2011-03-02 20:15:13 ndevilla Exp $
14 $Date: 2011-03-02 20:15:13 $
16 /*---------------------------- Includes ------------------------------------*/
18 #include "iniparser.h"
20 /*---------------------------- Defines -------------------------------------*/
21 #define ASCIILINESZ (1024)
22 #define INI_INVALID_KEY ((char*)-1)
24 /*---------------------------------------------------------------------------
25 Private to this module
26 ---------------------------------------------------------------------------*/
28 * This enum stores the status for each parsed line (internal use only).
30 typedef enum _line_status_ {
39 /*-------------------------------------------------------------------------*/
41 @brief Convert a string to lowercase.
42 @param s String to convert.
43 @return ptr to statically allocated string.
45 This function returns a pointer to a statically allocated string
46 containing a lowercased version of the input string. Do not free
47 or modify the returned string! Since the returned string is statically
48 allocated, it will be modified at each function call (not re-entrant).
50 /*--------------------------------------------------------------------------*/
51 static char * strlwc(char * s)
55 static char l[ASCIILINESZ+1];
58 if (s==NULL) return NULL ;
59 memset(l, 0, ASCIILINESZ+1);
61 while (s[i] && i<ASCIILINESZ) {
62 l[i] = (char)tolower((int)s[i]);
65 l[ASCIILINESZ]=(char)0;
69 /*-------------------------------------------------------------------------*/
71 @brief Remove blanks at the beginning and the end of a string.
72 @param s String to parse.
73 @return ptr to statically allocated string.
75 This function returns a pointer to a statically allocated string,
76 which is identical to the input string, except that all blank
77 characters at the end and the beg. of the string have been removed.
78 Do not free or modify the returned string! Since the returned string
79 is statically allocated, it will be modified at each function call
82 /*--------------------------------------------------------------------------*/
83 static char * strstrip(char * s)
85 static char l[ASCIILINESZ+1];
88 if (s==NULL) return NULL ;
90 while (isspace((int)*s) && *s) s++;
91 memset(l, 0, ASCIILINESZ+1);
95 if (!isspace((int)*(last-1)))
103 /*-------------------------------------------------------------------------*/
105 @brief Get number of sections in a dictionary
106 @param d Dictionary to examine
107 @return int Number of sections found in dictionary
109 This function returns the number of sections found in a dictionary.
110 The test to recognize sections is done on the string stored in the
111 dictionary: a section name is given as "section" whereas a key is
112 stored as "section:key", thus the test looks for entries that do not
115 This clearly fails in the case a section name contains a colon, but
116 this should simply be avoided.
118 This function returns -1 in case of error.
120 /*--------------------------------------------------------------------------*/
121 int iniparser_getnsec(dictionary * d)
126 if (d==NULL) return -1 ;
128 for (i=0 ; i<d->size ; i++) {
131 if (strchr(d->key[i], ':')==NULL) {
138 /*-------------------------------------------------------------------------*/
140 @brief Get name for section n in a dictionary.
141 @param d Dictionary to examine
142 @param n Section number (from 0 to nsec-1).
143 @return Pointer to char string
145 This function locates the n-th section in a dictionary and returns
146 its name as a pointer to a string statically allocated inside the
147 dictionary. Do not free or modify the returned string!
149 This function returns NULL in case of error.
151 /*--------------------------------------------------------------------------*/
152 char * iniparser_getsecname(dictionary * d, int n)
157 if (d==NULL || n<0) return NULL ;
159 for (i=0 ; i<d->size ; i++) {
162 if (strchr(d->key[i], ':')==NULL) {
174 /*-------------------------------------------------------------------------*/
176 @brief Dump a dictionary to an opened file pointer.
177 @param d Dictionary to dump.
178 @param f Opened file pointer to dump to.
181 This function prints out the contents of a dictionary, one element by
182 line, onto the provided file pointer. It is OK to specify @c stderr
183 or @c stdout as output files. This function is meant for debugging
186 /*--------------------------------------------------------------------------*/
187 void iniparser_dump(dictionary * d, FILE * f)
191 if (d==NULL || f==NULL) return ;
192 for (i=0 ; i<d->size ; i++) {
195 if (d->val[i]!=NULL) {
196 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
198 fprintf(f, "[%s]=UNDEF\n", d->key[i]);
204 /*-------------------------------------------------------------------------*/
206 @brief Save a dictionary to a loadable ini file
207 @param d Dictionary to dump
208 @param f Opened file pointer to dump to
211 This function dumps a given dictionary into a loadable ini file.
212 It is Ok to specify @c stderr or @c stdout as output files.
214 /*--------------------------------------------------------------------------*/
215 void iniparser_dump_ini(dictionary * d, FILE * f)
218 char keym[ASCIILINESZ+1];
223 if (d==NULL || f==NULL) return ;
225 nsec = iniparser_getnsec(d);
227 /* No section in file: dump all keys as they are */
228 for (i=0 ; i<d->size ; i++) {
231 fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
235 for (i=0 ; i<nsec ; i++) {
236 secname = iniparser_getsecname(d, i) ;
237 seclen = (int)strlen(secname);
238 fprintf(f, "\n[%s]\n", secname);
239 sprintf(keym, "%s:", secname);
240 for (j=0 ; j<d->size ; j++) {
243 if (!strncmp(d->key[j], keym, seclen+1)) {
247 d->val[j] ? d->val[j] : "");
255 /*-------------------------------------------------------------------------*/
257 @brief Get the string associated to a key
258 @param d Dictionary to search
259 @param key Key string to look for
260 @param def Default value to return if key not found.
261 @return pointer to statically allocated character string
263 This function queries a dictionary for a key. A key as read from an
264 ini file is given as "section:key". If the key cannot be found,
265 the pointer passed as 'def' is returned.
266 The returned char pointer is pointing to a string allocated in
267 the dictionary, do not free or modify it.
269 /*--------------------------------------------------------------------------*/
270 char * iniparser_getstring(dictionary * d, char * key, char * def)
275 if (d==NULL || key==NULL)
278 lc_key = strlwc(key);
279 sval = dictionary_get(d, lc_key, def);
283 /*-------------------------------------------------------------------------*/
285 @brief Get the string associated to a key, convert to an int
286 @param d Dictionary to search
287 @param key Key string to look for
288 @param notfound Value to return in case of error
291 This function queries a dictionary for a key. A key as read from an
292 ini file is given as "section:key". If the key cannot be found,
293 the notfound value is returned.
295 Supported values for integers include the usual C notation
296 so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
297 are supported. Examples:
300 "042" -> 34 (octal -> decimal)
301 "0x42" -> 66 (hexa -> decimal)
303 Warning: the conversion may overflow in various ways. Conversion is
304 totally outsourced to strtol(), see the associated man page for overflow
307 Credits: Thanks to A. Becker for suggesting strtol()
309 /*--------------------------------------------------------------------------*/
310 int iniparser_getint(dictionary * d, char * key, int notfound)
314 str = iniparser_getstring(d, key, INI_INVALID_KEY);
315 if (str==INI_INVALID_KEY) return notfound ;
316 return (int)strtol(str, NULL, 0);
319 /*-------------------------------------------------------------------------*/
321 @brief Get the string associated to a key, convert to a double
322 @param d Dictionary to search
323 @param key Key string to look for
324 @param notfound Value to return in case of error
327 This function queries a dictionary for a key. A key as read from an
328 ini file is given as "section:key". If the key cannot be found,
329 the notfound value is returned.
331 /*--------------------------------------------------------------------------*/
332 double iniparser_getdouble(dictionary * d, char * key, double notfound)
336 str = iniparser_getstring(d, key, INI_INVALID_KEY);
337 if (str==INI_INVALID_KEY) return notfound ;
341 /*-------------------------------------------------------------------------*/
343 @brief Get the string associated to a key, convert to a boolean
344 @param d Dictionary to search
345 @param key Key string to look for
346 @param notfound Value to return in case of error
349 This function queries a dictionary for a key. A key as read from an
350 ini file is given as "section:key". If the key cannot be found,
351 the notfound value is returned.
353 A true boolean is found if one of the following is matched:
355 - A string starting with 'y'
356 - A string starting with 'Y'
357 - A string starting with 't'
358 - A string starting with 'T'
359 - A string starting with '1'
361 A false boolean is found if one of the following is matched:
363 - A string starting with 'n'
364 - A string starting with 'N'
365 - A string starting with 'f'
366 - A string starting with 'F'
367 - A string starting with '0'
369 The notfound value returned if no boolean is identified, does not
370 necessarily have to be 0 or 1.
372 /*--------------------------------------------------------------------------*/
373 int iniparser_getboolean(dictionary * d, char * key, int notfound)
378 c = iniparser_getstring(d, key, INI_INVALID_KEY);
379 if (c==INI_INVALID_KEY) return notfound ;
380 if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
382 } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
390 /*-------------------------------------------------------------------------*/
392 @brief Finds out if a given entry exists in a dictionary
393 @param ini Dictionary to search
394 @param entry Name of the entry to look for
395 @return integer 1 if entry exists, 0 otherwise
397 Finds out if a given entry exists in the dictionary. Since sections
398 are stored as keys with NULL associated values, this is the only way
399 of querying for the presence of sections in a dictionary.
401 /*--------------------------------------------------------------------------*/
402 int iniparser_find_entry(
408 if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
414 /*-------------------------------------------------------------------------*/
416 @brief Set an entry in a dictionary.
417 @param ini Dictionary to modify.
418 @param entry Entry to modify (entry name)
419 @param val New value to associate to the entry.
420 @return int 0 if Ok, -1 otherwise.
422 If the given entry can be found in the dictionary, it is modified to
423 contain the provided value. If it cannot be found, -1 is returned.
424 It is Ok to set val to NULL.
426 /*--------------------------------------------------------------------------*/
427 int iniparser_set(dictionary * ini, char * entry, char * val)
429 return dictionary_set(ini, strlwc(entry), val) ;
432 /*-------------------------------------------------------------------------*/
434 @brief Delete an entry in a dictionary
435 @param ini Dictionary to modify
436 @param entry Entry to delete (entry name)
439 If the given entry can be found, it is deleted from the dictionary.
441 /*--------------------------------------------------------------------------*/
442 void iniparser_unset(dictionary * ini, char * entry)
444 dictionary_unset(ini, strlwc(entry));
447 /*-------------------------------------------------------------------------*/
449 @brief Load a single line from an INI file
450 @param input_line Input line, may be concatenated multi-line input
451 @param section Output space to store section
452 @param key Output space to store key
453 @param value Output space to store value
454 @return line_status value
456 /*--------------------------------------------------------------------------*/
457 static line_status iniparser_line(
464 char line[ASCIILINESZ+1];
467 strcpy(line, strstrip(input_line));
468 len = (int)strlen(line);
470 sta = LINE_UNPROCESSED ;
474 } else if (line[0]=='#' || line[0]==';') {
477 } else if (line[0]=='[' && line[len-1]==']') {
479 sscanf(line, "[%[^]]", section);
480 strcpy(section, strstrip(section));
481 strcpy(section, strlwc(section));
483 } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
484 || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
485 || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
486 /* Usual key=value, with or without comments */
487 strcpy(key, strstrip(key));
488 strcpy(key, strlwc(key));
489 strcpy(value, strstrip(value));
491 * sscanf cannot handle '' or "" as empty values
494 if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
498 } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
499 || sscanf(line, "%[^=] %[=]", key, value) == 2) {
506 strcpy(key, strstrip(key));
507 strcpy(key, strlwc(key));
511 /* Generate syntax error */
517 /*-------------------------------------------------------------------------*/
519 @brief Parse an ini file and return an allocated dictionary object
520 @param ininame Name of the ini file to read.
521 @return Pointer to newly allocated dictionary
523 This is the parser for ini files. This function is called, providing
524 the name of the file to be read. It returns a dictionary object that
525 should not be accessed directly, but through accessor functions
528 The returned dictionary must be freed using iniparser_freedict().
530 /*--------------------------------------------------------------------------*/
531 dictionary * iniparser_load(char * ininame)
535 char line [ASCIILINESZ+1] ;
536 char section [ASCIILINESZ+1] ;
537 char key [ASCIILINESZ+1] ;
538 char tmp [ASCIILINESZ+1] ;
539 char val [ASCIILINESZ+1] ;
548 if ((in=fopen(ininame, "r"))==NULL) {
549 fprintf(stderr, "iniparser: cannot open %s\n", ininame);
553 dict = dictionary_new(0) ;
559 memset(line, 0, ASCIILINESZ);
560 memset(section, 0, ASCIILINESZ);
561 memset(key, 0, ASCIILINESZ);
562 memset(val, 0, ASCIILINESZ);
565 while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
567 len = (int)strlen(line)-1;
570 /* Safety check against buffer overflows */
571 if (line[len]!='\n') {
573 "iniparser: input line too long in %s (%d)\n",
576 dictionary_del(dict);
580 /* Get rid of \n and spaces at end of line */
582 ((line[len]=='\n') || (isspace(line[len])))) {
586 /* Detect multi-line */
587 if (line[len]=='\\') {
588 /* Multi-line value */
594 switch (iniparser_line(line, section, key, val)) {
600 errs = dictionary_set(dict, section, NULL);
604 sprintf(tmp, "%s:%s", section, key);
605 errs = dictionary_set(dict, tmp, val) ;
609 fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
612 fprintf(stderr, "-> %s\n", line);
619 memset(line, 0, ASCIILINESZ);
622 fprintf(stderr, "iniparser: memory allocation failure\n");
627 dictionary_del(dict);
634 /*-------------------------------------------------------------------------*/
636 @brief Free all memory associated to an ini dictionary
637 @param d Dictionary to free
640 Free all memory associated to an ini dictionary.
641 It is mandatory to call this function before the dictionary object
642 gets out of the current context.
644 /*--------------------------------------------------------------------------*/
645 void iniparser_freedict(dictionary * d)
650 /* vim: set ts=4 et sw=4 tw=75 */