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 <atalk/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 Remove blanks at the beginning and the end of a string.
42 @param s String to parse.
43 @return ptr to statically allocated string.
45 This function returns a pointer to a statically allocated string,
46 which is identical to the input string, except that all blank
47 characters at the end and the beg. of the string have been removed.
48 Do not free or modify the returned string! Since the returned string
49 is statically allocated, it will be modified at each function call
52 /*--------------------------------------------------------------------------*/
53 static char * strstrip(char * s)
55 static char l[ASCIILINESZ+1];
58 if (s==NULL) return NULL ;
60 while (isspace((int)*s) && *s) s++;
61 memset(l, 0, ASCIILINESZ+1);
65 if (!isspace((int)*(last-1)))
73 /*-------------------------------------------------------------------------*/
75 @brief Get number of sections in a dictionary
76 @param d Dictionary to examine
77 @return int Number of sections found in dictionary
79 This function returns the number of sections found in a dictionary.
80 The test to recognize sections is done on the string stored in the
81 dictionary: a section name is given as "section" whereas a key is
82 stored as "section:key", thus the test looks for entries that do not
85 This clearly fails in the case a section name contains a colon, but
86 this should simply be avoided.
88 This function returns -1 in case of error.
90 /*--------------------------------------------------------------------------*/
91 int iniparser_getnsec(const dictionary * d)
96 if (d==NULL) return -1 ;
98 for (i=0 ; i<d->size ; i++) {
101 if (strchr(d->key[i], ':')==NULL) {
108 /*-------------------------------------------------------------------------*/
110 @brief Get name for section n in a dictionary.
111 @param d Dictionary to examine
112 @param n Section number (from 0 to nsec-1).
113 @return Pointer to char string
115 This function locates the n-th section in a dictionary and returns
116 its name as a pointer to a string statically allocated inside the
117 dictionary. Do not free or modify the returned string!
119 This function returns NULL in case of error.
121 /*--------------------------------------------------------------------------*/
122 const char * iniparser_getsecname(const dictionary * d, int n)
127 if (d==NULL || n<0) return NULL ;
129 for (i=0 ; i<d->size ; i++) {
132 if (strchr(d->key[i], ':')==NULL) {
144 /*-------------------------------------------------------------------------*/
146 @brief Dump a dictionary to an opened file pointer.
147 @param d Dictionary to dump.
148 @param f Opened file pointer to dump to.
151 This function prints out the contents of a dictionary, one element by
152 line, onto the provided file pointer. It is OK to specify @c stderr
153 or @c stdout as output files. This function is meant for debugging
156 /*--------------------------------------------------------------------------*/
157 void iniparser_dump(const dictionary * d, FILE * f)
161 if (d==NULL || f==NULL) return ;
162 for (i=0 ; i<d->size ; i++) {
165 if (d->val[i]!=NULL) {
166 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
168 fprintf(f, "[%s]=UNDEF\n", d->key[i]);
174 /*-------------------------------------------------------------------------*/
176 @brief Save a dictionary to a loadable ini file
177 @param d Dictionary to dump
178 @param f Opened file pointer to dump to
181 This function dumps a given dictionary into a loadable ini file.
182 It is Ok to specify @c stderr or @c stdout as output files.
184 /*--------------------------------------------------------------------------*/
185 void iniparser_dump_ini(const dictionary * d, FILE * f)
188 char keym[ASCIILINESZ+1];
190 const char * secname ;
193 if (d==NULL || f==NULL) return ;
195 nsec = iniparser_getnsec(d);
197 /* No section in file: dump all keys as they are */
198 for (i=0 ; i<d->size ; i++) {
201 fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
205 for (i=0 ; i<nsec ; i++) {
206 secname = iniparser_getsecname(d, i) ;
207 seclen = (int)strlen(secname);
208 fprintf(f, "\n[%s]\n", secname);
209 sprintf(keym, "%s:", secname);
210 for (j=0 ; j<d->size ; j++) {
213 if (!strncmp(d->key[j], keym, seclen+1)) {
217 d->val[j] ? d->val[j] : "");
225 /*-------------------------------------------------------------------------*/
227 @brief Get the string associated to a key
228 @param d Dictionary to search
229 @param section Section to search
230 @param key Key string to look for
231 @param def Default value to return if key not found.
232 @return pointer to statically allocated character string
234 This function queries a dictionary for a key. A key as read from an
235 ini file is given as "section:key". If the key cannot be found,
236 the pointer passed as 'def' is returned.
237 The returned char pointer is pointing to a string allocated in
238 the dictionary, do not free or modify it.
240 /*--------------------------------------------------------------------------*/
241 const char * iniparser_getstring(const dictionary * d, const char *section, const char * key, const char * def)
245 if (d==NULL || key==NULL)
248 sval = dictionary_get(d, section, key, def);
252 /*-------------------------------------------------------------------------*/
254 @brief Get the string associated to a key
255 @param d Dictionary to search
256 @param section Section to search
257 @param key Key string to look for
258 @param def Default value to return if key not found.
259 @return pointer to statically allocated character string
261 This function queries a dictionary for a key. A key as read from an
262 ini file is given as "section:key". If the key cannot be found,
263 the pointer passed as 'def' is returned.
264 The returned char pointer a strdup'ed allocated string, so the caller must free it.
266 /*--------------------------------------------------------------------------*/
267 char * iniparser_getstrdup(const dictionary * d, const char *section, const char * key, const char * def)
271 if (d==NULL || key==NULL)
274 if ((sval = dictionary_get(d, section, key, def)))
279 /*-------------------------------------------------------------------------*/
281 @brief Get the string associated to a key, convert to an int
282 @param d Dictionary to search
283 @param section Section to search
284 @param key Key string to look for
285 @param notfound Value to return in case of error
288 This function queries a dictionary for a key. A key as read from an
289 ini file is given as "section:key". If the key cannot be found,
290 the notfound value is returned.
292 Supported values for integers include the usual C notation
293 so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
294 are supported. Examples:
297 "042" -> 34 (octal -> decimal)
298 "0x42" -> 66 (hexa -> decimal)
300 Warning: the conversion may overflow in various ways. Conversion is
301 totally outsourced to strtol(), see the associated man page for overflow
304 Credits: Thanks to A. Becker for suggesting strtol()
306 /*--------------------------------------------------------------------------*/
307 int iniparser_getint(const dictionary * d, const char *section, const char * key, int notfound)
311 str = iniparser_getstring(d, section, key, INI_INVALID_KEY);
312 if (str==INI_INVALID_KEY) return notfound ;
313 return (int)strtol(str, NULL, 0);
316 /*-------------------------------------------------------------------------*/
318 @brief Get the string associated to a key, convert to a double
319 @param d Dictionary to search
320 @param section Section to search
321 @param key Key string to look for
322 @param notfound Value to return in case of error
325 This function queries a dictionary for a key. A key as read from an
326 ini file is given as "section:key". If the key cannot be found,
327 the notfound value is returned.
329 /*--------------------------------------------------------------------------*/
330 double iniparser_getdouble(const dictionary * d, const char *section, const char * key, double notfound)
334 str = iniparser_getstring(d, section, key, INI_INVALID_KEY);
335 if (str==INI_INVALID_KEY) return notfound ;
339 /*-------------------------------------------------------------------------*/
341 @brief Get the string associated to a key, convert to a boolean
342 @param d Dictionary to search
343 @param section Section to search
344 @param key Key string to look for
345 @param notfound Value to return in case of error
348 This function queries a dictionary for a key. A key as read from an
349 ini file is given as "section:key". If the key cannot be found,
350 the notfound value is returned.
352 A true boolean is found if one of the following is matched:
354 - A string starting with 'y'
355 - A string starting with 'Y'
356 - A string starting with 't'
357 - A string starting with 'T'
358 - A string starting with '1'
360 A false boolean is found if one of the following is matched:
362 - A string starting with 'n'
363 - A string starting with 'N'
364 - A string starting with 'f'
365 - A string starting with 'F'
366 - A string starting with '0'
368 The notfound value returned if no boolean is identified, does not
369 necessarily have to be 0 or 1.
371 /*--------------------------------------------------------------------------*/
372 int iniparser_getboolean(const dictionary * d, const char *section, const char * key, int notfound)
377 c = iniparser_getstring(d, section, key, INI_INVALID_KEY);
378 if (c==INI_INVALID_KEY) return notfound ;
379 if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
381 } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
389 /*-------------------------------------------------------------------------*/
391 @brief Finds out if a given entry exists in a dictionary
392 @param ini Dictionary to search
393 @param entry Name of the entry to look for
394 @return integer 1 if entry exists, 0 otherwise
396 Finds out if a given entry exists in the dictionary. Since sections
397 are stored as keys with NULL associated values, this is the only way
398 of querying for the presence of sections in a dictionary.
400 /*--------------------------------------------------------------------------*/
401 int iniparser_find_entry(const dictionary *ini, const char *entry)
404 if (iniparser_getstring(ini, entry, NULL, INI_INVALID_KEY)!=INI_INVALID_KEY) {
410 /*-------------------------------------------------------------------------*/
412 @brief Set an entry in a dictionary.
413 @param ini Dictionary to modify.
414 @param section Entry to modify (entry section)
415 @param key Entry to modify (entry key)
416 @param val New value to associate to the entry.
417 @return int 0 if Ok, -1 otherwise.
419 If the given entry can be found in the dictionary, it is modified to
420 contain the provided value. If it cannot be found, -1 is returned.
421 It is Ok to set val to NULL.
423 /*--------------------------------------------------------------------------*/
424 int iniparser_set(dictionary * ini, char *section, char * key, char * val)
426 return dictionary_set(ini, section, key, val) ;
429 /*-------------------------------------------------------------------------*/
431 @brief Delete an entry in a dictionary
432 @param ini Dictionary to modify
433 @param section Entry to delete (entry section)
434 @param key Entry to delete (entry key)
437 If the given entry can be found, it is deleted from the dictionary.
439 /*--------------------------------------------------------------------------*/
440 void iniparser_unset(dictionary * ini, char *section, char * key)
442 dictionary_unset(ini, section, key);
445 /*-------------------------------------------------------------------------*/
447 @brief Load a single line from an INI file
448 @param input_line Input line, may be concatenated multi-line input
449 @param section Output space to store section
450 @param key Output space to store key
451 @param value Output space to store value
452 @return line_status value
454 /*--------------------------------------------------------------------------*/
455 static line_status iniparser_line(
462 char line[ASCIILINESZ+1];
465 strcpy(line, strstrip(input_line));
466 len = (int)strlen(line);
468 sta = LINE_UNPROCESSED ;
472 } else if (line[0]=='#' || line[0]==';') {
475 } else if (line[0]=='[' && line[len-1]==']') {
477 sscanf(line, "[%[^]]", section);
478 strcpy(section, strstrip(section));
479 strcpy(section, section);
481 } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
482 || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
483 || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
484 /* Usual key=value, with or without comments */
485 strcpy(key, strstrip(key));
487 strcpy(value, strstrip(value));
489 * sscanf cannot handle '' or "" as empty values
492 if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
496 } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
497 || sscanf(line, "%[^=] %[=]", key, value) == 2) {
504 strcpy(key, strstrip(key));
509 /* Generate syntax error */
515 /*-------------------------------------------------------------------------*/
517 @brief Parse an ini file and return an allocated dictionary object
518 @param ininame Name of the ini file to read.
519 @return Pointer to newly allocated dictionary
521 This is the parser for ini files. This function is called, providing
522 the name of the file to be read. It returns a dictionary object that
523 should not be accessed directly, but through accessor functions
526 The returned dictionary must be freed using iniparser_freedict().
528 /*--------------------------------------------------------------------------*/
529 dictionary * iniparser_load(const char * ininame)
533 char line [ASCIILINESZ+1] ;
534 char section [ASCIILINESZ+1] ;
535 char key [ASCIILINESZ+1] ;
536 char tmp [ASCIILINESZ+1] ;
537 char val [ASCIILINESZ+1] ;
546 if ((in=fopen(ininame, "r"))==NULL) {
547 fprintf(stderr, "iniparser: cannot open %s\n", ininame);
551 dict = dictionary_new(0) ;
557 memset(line, 0, ASCIILINESZ);
558 memset(section, 0, ASCIILINESZ);
559 memset(key, 0, ASCIILINESZ);
560 memset(val, 0, ASCIILINESZ);
563 while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
565 len = (int)strlen(line)-1;
568 /* Safety check against buffer overflows */
569 if (line[len]!='\n') {
571 "iniparser: input line too long in %s (%d)\n",
574 dictionary_del(dict);
578 /* Get rid of \n and spaces at end of line */
580 ((line[len]=='\n') || (isspace(line[len])))) {
584 /* Detect multi-line */
585 if (line[len]=='\\') {
586 /* Multi-line value */
592 switch (iniparser_line(line, section, key, val)) {
598 errs = dictionary_set(dict, section, NULL, NULL);
602 errs = dictionary_set(dict, section, key, val) ;
606 fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
609 fprintf(stderr, "-> %s\n", line);
616 memset(line, 0, ASCIILINESZ);
619 fprintf(stderr, "iniparser: memory allocation failure\n");
624 dictionary_del(dict);
631 /*-------------------------------------------------------------------------*/
633 @brief Free all memory associated to an ini dictionary
634 @param d Dictionary to free
637 Free all memory associated to an ini dictionary.
638 It is mandatory to call this function before the dictionary object
639 gets out of the current context.
641 /*--------------------------------------------------------------------------*/
642 void iniparser_freedict(dictionary * d)