2 Copyright (c) 2000-2011 by Nicolas Devillard.
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
24 /*-------------------------------------------------------------------------*/
28 @brief Parser for ini files.
30 /*--------------------------------------------------------------------------*/
31 /*---------------------------- Includes ------------------------------------*/
37 #include "iniparser.h"
39 /*---------------------------- Defines -------------------------------------*/
40 #define ASCIILINESZ (1024)
41 #define INI_INVALID_KEY ((char*)-1)
43 /*---------------------------------------------------------------------------
44 Private to this module
45 ---------------------------------------------------------------------------*/
47 * This enum stores the status for each parsed line (internal use only).
49 typedef enum _line_status_ {
58 /*-------------------------------------------------------------------------*/
60 @brief Convert a string to lowercase.
61 @param s String to convert.
62 @return ptr to statically allocated string.
64 This function returns a pointer to a statically allocated string
65 containing a lowercased version of the input string. Do not free
66 or modify the returned string! Since the returned string is statically
67 allocated, it will be modified at each function call (not re-entrant).
69 /*--------------------------------------------------------------------------*/
70 static char * strlwc(const char * s)
72 static char l[ASCIILINESZ+1];
75 if (s==NULL) return NULL ;
76 memset(l, 0, ASCIILINESZ+1);
78 while (s[i] && i<ASCIILINESZ) {
79 l[i] = (char)tolower((int)s[i]);
82 l[ASCIILINESZ]=(char)0;
86 /*-------------------------------------------------------------------------*/
88 @brief Remove blanks at the beginning and the end of a string.
89 @param s String to parse.
90 @return ptr to statically allocated string.
92 This function returns a pointer to a statically allocated string,
93 which is identical to the input string, except that all blank
94 characters at the end and the beg. of the string have been removed.
95 Do not free or modify the returned string! Since the returned string
96 is statically allocated, it will be modified at each function call
99 /*--------------------------------------------------------------------------*/
100 static char * strstrip(const char * s)
102 static char l[ASCIILINESZ+1];
105 if (s==NULL) return NULL ;
107 while (isspace((int)*s) && *s) s++;
108 memset(l, 0, ASCIILINESZ+1);
110 last = l + strlen(l);
112 if (!isspace((int)*(last-1)))
120 /*-------------------------------------------------------------------------*/
122 @brief Get number of sections in a dictionary
123 @param d Dictionary to examine
124 @return int Number of sections found in dictionary
126 This function returns the number of sections found in a dictionary.
127 The test to recognize sections is done on the string stored in the
128 dictionary: a section name is given as "section" whereas a key is
129 stored as "section:key", thus the test looks for entries that do not
132 This clearly fails in the case a section name contains a colon, but
133 this should simply be avoided.
135 This function returns -1 in case of error.
137 /*--------------------------------------------------------------------------*/
138 int iniparser_getnsec(dictionary * d)
143 if (d==NULL) return -1 ;
145 for (i=0 ; i<d->size ; i++) {
148 if (strchr(d->key[i], ':')==NULL) {
155 /*-------------------------------------------------------------------------*/
157 @brief Get name for section n in a dictionary.
158 @param d Dictionary to examine
159 @param n Section number (from 0 to nsec-1).
160 @return Pointer to char string
162 This function locates the n-th section in a dictionary and returns
163 its name as a pointer to a string statically allocated inside the
164 dictionary. Do not free or modify the returned string!
166 This function returns NULL in case of error.
168 /*--------------------------------------------------------------------------*/
169 char * iniparser_getsecname(dictionary * d, int n)
174 if (d==NULL || n<0) return NULL ;
176 for (i=0 ; i<d->size ; i++) {
179 if (strchr(d->key[i], ':')==NULL) {
191 /*-------------------------------------------------------------------------*/
193 @brief Dump a dictionary to an opened file pointer.
194 @param d Dictionary to dump.
195 @param f Opened file pointer to dump to.
198 This function prints out the contents of a dictionary, one element by
199 line, onto the provided file pointer. It is OK to specify @c stderr
200 or @c stdout as output files. This function is meant for debugging
203 /*--------------------------------------------------------------------------*/
204 void iniparser_dump(dictionary * d, FILE * f)
208 if (d==NULL || f==NULL) return ;
209 for (i=0 ; i<d->size ; i++) {
212 if (d->val[i]!=NULL) {
213 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
215 fprintf(f, "[%s]=UNDEF\n", d->key[i]);
221 /*-------------------------------------------------------------------------*/
223 @brief Save a dictionary to a loadable ini file
224 @param d Dictionary to dump
225 @param f Opened file pointer to dump to
228 This function dumps a given dictionary into a loadable ini file.
229 It is Ok to specify @c stderr or @c stdout as output files.
231 /*--------------------------------------------------------------------------*/
232 void iniparser_dump_ini(dictionary * d, FILE * f)
238 if (d==NULL || f==NULL) return ;
240 nsec = iniparser_getnsec(d);
242 /* No section in file: dump all keys as they are */
243 for (i=0 ; i<d->size ; i++) {
246 fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
250 for (i=0 ; i<nsec ; i++) {
251 secname = iniparser_getsecname(d, i) ;
252 iniparser_dumpsection_ini(d, secname, f) ;
258 /*-------------------------------------------------------------------------*/
260 @brief Save a dictionary section to a loadable ini file
261 @param d Dictionary to dump
262 @param s Section name of dictionary to dump
263 @param f Opened file pointer to dump to
266 This function dumps a given section of a given dictionary into a loadable ini
267 file. It is Ok to specify @c stderr or @c stdout as output files.
269 /*--------------------------------------------------------------------------*/
270 void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
273 char keym[ASCIILINESZ+1];
276 if (d==NULL || f==NULL) return ;
277 if (! iniparser_find_entry(d, s)) return ;
280 fprintf(f, "\n[%s]\n", s);
281 sprintf(keym, "%s:", s);
282 for (j=0 ; j<d->size ; j++) {
285 if (!strncmp(d->key[j], keym, seclen+1)) {
289 d->val[j] ? d->val[j] : "");
296 /*-------------------------------------------------------------------------*/
298 @brief Get the number of keys in a section of a dictionary.
299 @param d Dictionary to examine
300 @param s Section name of dictionary to examine
301 @return Number of keys in section
303 /*--------------------------------------------------------------------------*/
304 int iniparser_getsecnkeys(dictionary * d, char * s)
308 char keym[ASCIILINESZ+1];
313 if (d==NULL) return nkeys;
314 if (! iniparser_find_entry(d, s)) return nkeys;
317 sprintf(keym, "%s:", s);
319 for (j=0 ; j<d->size ; j++) {
322 if (!strncmp(d->key[j], keym, seclen+1))
330 /*-------------------------------------------------------------------------*/
332 @brief Get the number of keys in a section of a dictionary.
333 @param d Dictionary to examine
334 @param s Section name of dictionary to examine
335 @return pointer to statically allocated character strings
337 This function queries a dictionary and finds all keys in a given section.
338 Each pointer in the returned char pointer-to-pointer is pointing to
339 a string allocated in the dictionary; do not free or modify them.
341 This function returns NULL in case of error.
343 /*--------------------------------------------------------------------------*/
344 char ** iniparser_getseckeys(dictionary * d, char * s)
350 char keym[ASCIILINESZ+1];
356 if (d==NULL) return keys;
357 if (! iniparser_find_entry(d, s)) return keys;
359 nkeys = iniparser_getsecnkeys(d, s);
361 keys = (char**) malloc((size_t)nkeys*sizeof(char*));
367 sprintf(keym, "%s:", s);
371 for (j=0 ; j<d->size ; j++) {
374 if (!strncmp(d->key[j], keym, seclen+1)) {
384 /*-------------------------------------------------------------------------*/
386 @brief Get the string associated to a key
387 @param d Dictionary to search
388 @param key Key string to look for
389 @param def Default value to return if key not found.
390 @return pointer to statically allocated character string
392 This function queries a dictionary for a key. A key as read from an
393 ini file is given as "section:key". If the key cannot be found,
394 the pointer passed as 'def' is returned.
395 The returned char pointer is pointing to a string allocated in
396 the dictionary, do not free or modify it.
398 /*--------------------------------------------------------------------------*/
399 char * iniparser_getstring(dictionary * d, const char * key, char * def)
404 if (d==NULL || key==NULL)
407 lc_key = strlwc(key);
408 sval = dictionary_get(d, lc_key, def);
412 /*-------------------------------------------------------------------------*/
414 @brief Get the string associated to a key, convert to an int
415 @param d Dictionary to search
416 @param key Key string to look for
417 @param notfound Value to return in case of error
420 This function queries a dictionary for a key. A key as read from an
421 ini file is given as "section:key". If the key cannot be found,
422 the notfound value is returned.
424 Supported values for integers include the usual C notation
425 so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
426 are supported. Examples:
429 "042" -> 34 (octal -> decimal)
430 "0x42" -> 66 (hexa -> decimal)
432 Warning: the conversion may overflow in various ways. Conversion is
433 totally outsourced to strtol(), see the associated man page for overflow
436 Credits: Thanks to A. Becker for suggesting strtol()
438 /*--------------------------------------------------------------------------*/
439 int iniparser_getint(dictionary * d, const char * key, int notfound)
443 str = iniparser_getstring(d, key, INI_INVALID_KEY);
444 if (str==INI_INVALID_KEY) return notfound ;
445 return (int)strtol(str, NULL, 0);
448 /*-------------------------------------------------------------------------*/
450 @brief Get the string associated to a key, convert to a double
451 @param d Dictionary to search
452 @param key Key string to look for
453 @param notfound Value to return in case of error
456 This function queries a dictionary for a key. A key as read from an
457 ini file is given as "section:key". If the key cannot be found,
458 the notfound value is returned.
460 /*--------------------------------------------------------------------------*/
461 double iniparser_getdouble(dictionary * d, const char * key, double notfound)
465 str = iniparser_getstring(d, key, INI_INVALID_KEY);
466 if (str==INI_INVALID_KEY) return notfound ;
470 /*-------------------------------------------------------------------------*/
472 @brief Get the string associated to a key, convert to a boolean
473 @param d Dictionary to search
474 @param key Key string to look for
475 @param notfound Value to return in case of error
478 This function queries a dictionary for a key. A key as read from an
479 ini file is given as "section:key". If the key cannot be found,
480 the notfound value is returned.
482 A true boolean is found if one of the following is matched:
484 - A string starting with 'y'
485 - A string starting with 'Y'
486 - A string starting with 't'
487 - A string starting with 'T'
488 - A string starting with '1'
490 A false boolean is found if one of the following is matched:
492 - A string starting with 'n'
493 - A string starting with 'N'
494 - A string starting with 'f'
495 - A string starting with 'F'
496 - A string starting with '0'
498 The notfound value returned if no boolean is identified, does not
499 necessarily have to be 0 or 1.
501 /*--------------------------------------------------------------------------*/
502 int iniparser_getboolean(dictionary * d, const char * key, int notfound)
507 c = iniparser_getstring(d, key, INI_INVALID_KEY);
508 if (c==INI_INVALID_KEY) return notfound ;
509 if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
511 } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
519 /*-------------------------------------------------------------------------*/
521 @brief Finds out if a given entry exists in a dictionary
522 @param ini Dictionary to search
523 @param entry Name of the entry to look for
524 @return integer 1 if entry exists, 0 otherwise
526 Finds out if a given entry exists in the dictionary. Since sections
527 are stored as keys with NULL associated values, this is the only way
528 of querying for the presence of sections in a dictionary.
530 /*--------------------------------------------------------------------------*/
531 int iniparser_find_entry(
537 if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
543 /*-------------------------------------------------------------------------*/
545 @brief Set an entry in a dictionary.
546 @param ini Dictionary to modify.
547 @param entry Entry to modify (entry name)
548 @param val New value to associate to the entry.
549 @return int 0 if Ok, -1 otherwise.
551 If the given entry can be found in the dictionary, it is modified to
552 contain the provided value. If it cannot be found, -1 is returned.
553 It is Ok to set val to NULL.
555 /*--------------------------------------------------------------------------*/
556 int iniparser_set(dictionary * ini, const char * entry, const char * val)
558 return dictionary_set(ini, strlwc(entry), val) ;
561 /*-------------------------------------------------------------------------*/
563 @brief Delete an entry in a dictionary
564 @param ini Dictionary to modify
565 @param entry Entry to delete (entry name)
568 If the given entry can be found, it is deleted from the dictionary.
570 /*--------------------------------------------------------------------------*/
571 void iniparser_unset(dictionary * ini, const char * entry)
573 dictionary_unset(ini, strlwc(entry));
576 /*-------------------------------------------------------------------------*/
578 @brief Load a single line from an INI file
579 @param input_line Input line, may be concatenated multi-line input
580 @param section Output space to store section
581 @param key Output space to store key
582 @param value Output space to store value
583 @return line_status value
585 /*--------------------------------------------------------------------------*/
586 static line_status iniparser_line(
587 const char * input_line,
593 char line[ASCIILINESZ+1];
596 strcpy(line, strstrip(input_line));
597 len = (int)strlen(line);
599 sta = LINE_UNPROCESSED ;
603 } else if (line[0]=='#' || line[0]==';') {
606 } else if (line[0]=='[' && line[len-1]==']') {
608 sscanf(line, "[%[^]]", section);
609 strcpy(section, strstrip(section));
610 strcpy(section, strlwc(section));
612 } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
613 || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
614 || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
615 /* Usual key=value, with or without comments */
616 strcpy(key, strstrip(key));
617 strcpy(key, strlwc(key));
618 strcpy(value, strstrip(value));
620 * sscanf cannot handle '' or "" as empty values
623 if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
627 } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
628 || sscanf(line, "%[^=] %[=]", key, value) == 2) {
635 strcpy(key, strstrip(key));
636 strcpy(key, strlwc(key));
640 /* Generate syntax error */
646 /*-------------------------------------------------------------------------*/
648 @brief Parse an ini file and return an allocated dictionary object
649 @param ininame Name of the ini file to read.
650 @return Pointer to newly allocated dictionary
652 This is the parser for ini files. This function is called, providing
653 the name of the file to be read. It returns a dictionary object that
654 should not be accessed directly, but through accessor functions
657 The returned dictionary must be freed using iniparser_freedict().
659 /*--------------------------------------------------------------------------*/
660 dictionary * iniparser_load(const char * ininame)
664 char line [ASCIILINESZ+1] ;
665 char section [ASCIILINESZ+1] ;
666 char key [ASCIILINESZ+1] ;
667 char tmp [ASCIILINESZ+1] ;
668 char val [ASCIILINESZ+1] ;
677 if ((in=fopen(ininame, "r"))==NULL) {
678 fprintf(stderr, "iniparser: cannot open %s\n", ininame);
682 dict = dictionary_new(0) ;
688 memset(line, 0, ASCIILINESZ);
689 memset(section, 0, ASCIILINESZ);
690 memset(key, 0, ASCIILINESZ);
691 memset(val, 0, ASCIILINESZ);
694 while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
696 len = (int)strlen(line)-1;
699 /* Safety check against buffer overflows */
700 if (line[len]!='\n' && !feof(in)) {
702 "iniparser: input line too long in %s (%d)\n",
705 dictionary_del(dict);
709 /* Get rid of \n and spaces at end of line */
711 ((line[len]=='\n') || (isspace(line[len])))) {
715 /* Detect multi-line */
716 if (line[len]=='\\') {
717 /* Multi-line value */
723 switch (iniparser_line(line, section, key, val)) {
729 errs = dictionary_set(dict, section, NULL);
733 sprintf(tmp, "%s:%s", section, key);
734 errs = dictionary_set(dict, tmp, val) ;
738 fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
741 fprintf(stderr, "-> %s\n", line);
748 memset(line, 0, ASCIILINESZ);
751 fprintf(stderr, "iniparser: memory allocation failure\n");
756 dictionary_del(dict);
763 /*-------------------------------------------------------------------------*/
765 @brief Free all memory associated to an ini dictionary
766 @param d Dictionary to free
769 Free all memory associated to an ini dictionary.
770 It is mandatory to call this function before the dictionary object
771 gets out of the current context.
773 /*--------------------------------------------------------------------------*/
774 void iniparser_freedict(dictionary * d)
779 /* vim: set ts=4 et sw=4 tw=75 */