1 /*-------------------------------------------------------------------------*/
7 @brief Parser for ini files.
10 /*---------------------------- Includes ------------------------------------*/
13 #include <atalk/iniparser.h>
14 #include <atalk/logger.h>
16 /*---------------------------- Defines -------------------------------------*/
17 #define ASCIILINESZ (1024)
18 #define INI_INVALID_KEY ((char*)-1)
20 /*---------------------------------------------------------------------------
21 Private to this module
22 ---------------------------------------------------------------------------*/
24 * This enum stores the status for each parsed line (internal use only).
26 typedef enum _line_status_ {
35 /*-------------------------------------------------------------------------*/
37 @brief Remove blanks at the beginning and the end of a string.
38 @param s String to parse.
39 @return ptr to statically allocated string.
41 This function returns a pointer to a statically allocated string,
42 which is identical to the input string, except that all blank
43 characters at the end and the beg. of the string have been removed.
44 Do not free or modify the returned string! Since the returned string
45 is statically allocated, it will be modified at each function call
48 /*--------------------------------------------------------------------------*/
49 static char * strstrip(char * s)
51 static char l[ASCIILINESZ+1];
54 if (s==NULL) return NULL ;
56 while (isspace((int)*s) && *s) s++;
57 memset(l, 0, ASCIILINESZ+1);
61 if (!isspace((int)*(last-1)))
69 /*-------------------------------------------------------------------------*/
71 @brief Get number of sections in a dictionary
72 @param d Dictionary to examine
73 @return int Number of sections found in dictionary
75 This function returns the number of sections found in a dictionary.
76 The test to recognize sections is done on the string stored in the
77 dictionary: a section name is given as "section" whereas a key is
78 stored as "section:key", thus the test looks for entries that do not
81 This clearly fails in the case a section name contains a colon, but
82 this should simply be avoided.
84 This function returns -1 in case of error.
86 /*--------------------------------------------------------------------------*/
87 int iniparser_getnsec(const dictionary * d)
92 if (d==NULL) return -1 ;
94 for (i=0 ; i<d->size ; i++) {
97 if (strchr(d->key[i], ':')==NULL) {
104 /*-------------------------------------------------------------------------*/
106 @brief Get name for section n in a dictionary.
107 @param d Dictionary to examine
108 @param n Section number (from 0 to nsec-1).
109 @return Pointer to char string
111 This function locates the n-th section in a dictionary and returns
112 its name as a pointer to a string statically allocated inside the
113 dictionary. Do not free or modify the returned string!
115 This function returns NULL in case of error.
117 /*--------------------------------------------------------------------------*/
118 const char * iniparser_getsecname(const dictionary * d, int n)
123 if (d==NULL || n<0) return NULL ;
125 for (i=0 ; i<d->size ; i++) {
128 if (strchr(d->key[i], ':')==NULL) {
140 /*-------------------------------------------------------------------------*/
142 @brief Dump a dictionary to an opened file pointer.
143 @param d Dictionary to dump.
144 @param f Opened file pointer to dump to.
147 This function prints out the contents of a dictionary, one element by
148 line, onto the provided file pointer. It is OK to specify @c stderr
149 or @c stdout as output files. This function is meant for debugging
152 /*--------------------------------------------------------------------------*/
153 void iniparser_dump(const dictionary * d, FILE * f)
157 if (d==NULL || f==NULL) return ;
158 for (i=0 ; i<d->size ; i++) {
161 if (d->val[i]!=NULL) {
162 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
164 fprintf(f, "[%s]=UNDEF\n", d->key[i]);
170 /*-------------------------------------------------------------------------*/
172 @brief Save a dictionary to a loadable ini file
173 @param d Dictionary to dump
174 @param f Opened file pointer to dump to
177 This function dumps a given dictionary into a loadable ini file.
178 It is Ok to specify @c stderr or @c stdout as output files.
180 /*--------------------------------------------------------------------------*/
181 void iniparser_dump_ini(const dictionary * d, FILE * f)
184 char keym[ASCIILINESZ+1];
186 const char * secname ;
189 if (d==NULL || f==NULL) return ;
191 nsec = iniparser_getnsec(d);
193 /* No section in file: dump all keys as they are */
194 for (i=0 ; i<d->size ; i++) {
197 fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
201 for (i=0 ; i<nsec ; i++) {
202 secname = iniparser_getsecname(d, i) ;
203 seclen = (int)strlen(secname);
204 fprintf(f, "\n[%s]\n", secname);
205 sprintf(keym, "%s:", secname);
206 for (j=0 ; j<d->size ; j++) {
209 if (!strncmp(d->key[j], keym, seclen+1)) {
213 d->val[j] ? d->val[j] : "");
221 /*-------------------------------------------------------------------------*/
223 @brief Get the string associated to a key
224 @param d Dictionary to search
225 @param section Section to search
226 @param key Key string to look for
227 @param def Default value to return if key not found.
228 @return pointer to statically allocated character string
230 This function queries a dictionary for a key. A key as read from an
231 ini file is given as "section:key". If the key cannot be found,
232 the pointer passed as 'def' is returned.
233 The returned char pointer is pointing to a string allocated in
234 the dictionary, do not free or modify it.
236 /*--------------------------------------------------------------------------*/
237 const char * iniparser_getstring(const dictionary * d, const char *section, const char * key, const char * def)
241 if (d==NULL || key==NULL)
244 sval = dictionary_get(d, section, key, def);
248 /*-------------------------------------------------------------------------*/
250 @brief Get the string associated to a key
251 @param d Dictionary to search
252 @param section Section to search
253 @param key Key string to look for
254 @param def Default value to return if key not found.
255 @return pointer to statically allocated character string
257 This function queries a dictionary for a key. A key as read from an
258 ini file is given as "section:key". If the key cannot be found,
259 the pointer passed as 'def' is returned.
260 The returned char pointer a strdup'ed allocated string, so the caller must free it.
262 /*--------------------------------------------------------------------------*/
263 char * iniparser_getstrdup(const dictionary * d, const char *section, const char * key, const char * def)
267 if (d==NULL || key==NULL)
270 if ((sval = dictionary_get(d, section, key, def)))
275 /*-------------------------------------------------------------------------*/
277 @brief Get the string associated to a key, convert to an int
278 @param d Dictionary to search
279 @param section Section to search
280 @param key Key string to look for
281 @param notfound Value to return in case of error
284 This function queries a dictionary for a key. A key as read from an
285 ini file is given as "section:key". If the key cannot be found,
286 the notfound value is returned.
288 Supported values for integers include the usual C notation
289 so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
290 are supported. Examples:
293 "042" -> 34 (octal -> decimal)
294 "0x42" -> 66 (hexa -> decimal)
296 Warning: the conversion may overflow in various ways. Conversion is
297 totally outsourced to strtol(), see the associated man page for overflow
300 Credits: Thanks to A. Becker for suggesting strtol()
302 /*--------------------------------------------------------------------------*/
303 int iniparser_getint(const dictionary * d, const char *section, const char * key, int notfound)
307 str = iniparser_getstring(d, section, key, INI_INVALID_KEY);
308 if (str==INI_INVALID_KEY) return notfound ;
309 return (int)strtol(str, NULL, 0);
312 /*-------------------------------------------------------------------------*/
314 @brief Get the string associated to a key, convert to a double
315 @param d Dictionary to search
316 @param section Section to search
317 @param key Key string to look for
318 @param notfound Value to return in case of error
321 This function queries a dictionary for a key. A key as read from an
322 ini file is given as "section:key". If the key cannot be found,
323 the notfound value is returned.
325 /*--------------------------------------------------------------------------*/
326 double iniparser_getdouble(const dictionary * d, const char *section, const char * key, double notfound)
330 str = iniparser_getstring(d, section, key, INI_INVALID_KEY);
331 if (str==INI_INVALID_KEY) return notfound ;
335 /*-------------------------------------------------------------------------*/
337 @brief Get the string associated to a key, convert to a boolean
338 @param d Dictionary to search
339 @param section Section to search
340 @param key Key string to look for
341 @param notfound Value to return in case of error
344 This function queries a dictionary for a key. A key as read from an
345 ini file is given as "section:key". If the key cannot be found,
346 the notfound value is returned.
348 A true boolean is found if one of the following is matched:
350 - A string starting with 'y'
351 - A string starting with 'Y'
352 - A string starting with 't'
353 - A string starting with 'T'
354 - A string starting with '1'
356 A false boolean is found if one of the following is matched:
358 - A string starting with 'n'
359 - A string starting with 'N'
360 - A string starting with 'f'
361 - A string starting with 'F'
362 - A string starting with '0'
364 The notfound value returned if no boolean is identified, does not
365 necessarily have to be 0 or 1.
367 /*--------------------------------------------------------------------------*/
368 int iniparser_getboolean(const dictionary * d, const char *section, const char * key, int notfound)
373 c = iniparser_getstring(d, section, key, INI_INVALID_KEY);
374 if (c==INI_INVALID_KEY) return notfound ;
375 if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
377 } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
385 /*-------------------------------------------------------------------------*/
387 @brief Finds out if a given entry exists in a dictionary
388 @param ini Dictionary to search
389 @param entry Name of the entry to look for
390 @return integer 1 if entry exists, 0 otherwise
392 Finds out if a given entry exists in the dictionary. Since sections
393 are stored as keys with NULL associated values, this is the only way
394 of querying for the presence of sections in a dictionary.
396 /*--------------------------------------------------------------------------*/
397 int iniparser_find_entry(const dictionary *ini, const char *entry)
400 if (iniparser_getstring(ini, entry, NULL, INI_INVALID_KEY)!=INI_INVALID_KEY) {
406 /*-------------------------------------------------------------------------*/
408 @brief Set an entry in a dictionary.
409 @param ini Dictionary to modify.
410 @param section Entry to modify (entry section)
411 @param key Entry to modify (entry key)
412 @param val New value to associate to the entry.
413 @return int 0 if Ok, -1 otherwise.
415 If the given entry can be found in the dictionary, it is modified to
416 contain the provided value. If it cannot be found, -1 is returned.
417 It is Ok to set val to NULL.
419 /*--------------------------------------------------------------------------*/
420 int iniparser_set(dictionary * ini, char *section, char * key, char * val)
422 return dictionary_set(ini, section, key, val) ;
425 /*-------------------------------------------------------------------------*/
427 @brief Delete an entry in a dictionary
428 @param ini Dictionary to modify
429 @param section Entry to delete (entry section)
430 @param key Entry to delete (entry key)
433 If the given entry can be found, it is deleted from the dictionary.
435 /*--------------------------------------------------------------------------*/
436 void iniparser_unset(dictionary * ini, char *section, char * key)
438 dictionary_unset(ini, section, key);
441 /*-------------------------------------------------------------------------*/
443 @brief Load a single line from an INI file
444 @param input_line Input line, may be concatenated multi-line input
445 @param section Output space to store section
446 @param key Output space to store key
447 @param value Output space to store value
448 @return line_status value
450 /*--------------------------------------------------------------------------*/
451 static line_status iniparser_line(
458 char line[ASCIILINESZ+1];
461 strcpy(line, strstrip(input_line));
462 len = (int)strlen(line);
464 sta = LINE_UNPROCESSED ;
468 } else if (line[0]=='#' || line[0]==';') {
471 } else if (line[0]=='[' && line[len-1]==']') {
473 sscanf(line, "[%[^]]", section);
474 strcpy(section, strstrip(section));
475 strcpy(section, section);
477 } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
478 || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
479 || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
480 /* Usual key=value, with or without comments */
481 strcpy(key, strstrip(key));
483 strcpy(value, strstrip(value));
485 * sscanf cannot handle '' or "" as empty values
488 if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
492 } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
493 || sscanf(line, "%[^=] %[=]", key, value) == 2) {
500 strcpy(key, strstrip(key));
505 /* Generate syntax error */
511 /*-------------------------------------------------------------------------*/
513 @brief Parse an ini file and return an allocated dictionary object
514 @param ininame Name of the ini file to read.
515 @return Pointer to newly allocated dictionary
517 This is the parser for ini files. This function is called, providing
518 the name of the file to be read. It returns a dictionary object that
519 should not be accessed directly, but through accessor functions
522 The returned dictionary must be freed using iniparser_freedict().
524 /*--------------------------------------------------------------------------*/
525 dictionary * iniparser_load(const char * ininame)
527 FILE *in, *include = NULL, *inifile;
529 char line [ASCIILINESZ+1] ;
530 char section [ASCIILINESZ+1] ;
531 char key [ASCIILINESZ+1] ;
532 char tmp [ASCIILINESZ+1] ;
533 char val [ASCIILINESZ+1] ;
542 if ((inifile=fopen(ininame, "r"))==NULL) {
543 LOG(log_error, logtype_default, "iniparser: cannot open \"%s\"", ininame);
547 dict = dictionary_new(0) ;
553 memset(line, 0, ASCIILINESZ);
554 memset(section, 0, ASCIILINESZ);
555 memset(key, 0, ASCIILINESZ);
556 memset(val, 0, ASCIILINESZ);
561 if (fgets(line+last, ASCIILINESZ-last, in) == NULL) {
571 len = (int)strlen(line)-1;
574 /* Safety check against buffer overflows */
575 if (line[len]!='\n') {
576 LOG(log_error, logtype_default, "iniparser: input line too long in \"%s\" (lineno: %d)",
578 dictionary_del(dict);
582 /* Get rid of \n and spaces at end of line */
584 ((line[len]=='\n') || (isspace(line[len])))) {
588 /* Detect multi-line */
589 if (line[len]=='\\') {
590 /* Multi-line value */
596 switch (iniparser_line(line, section, key, val)) {
601 if (strchr(section, ':') != NULL)
602 LOG(log_error, logtype_default, "iniparser: syntax error \"%s\" section name must not contain \":\".", section);
603 errs = dictionary_set(dict, section, NULL, NULL);
606 if (strcmp(key, "include") == 0) {
607 if ((include = fopen(val, "r")) == NULL) {
608 LOG(log_error, logtype_default, "iniparser: cannot open \"%s\"", val);
614 errs = dictionary_set(dict, section, key, val) ;
617 LOG(log_error, logtype_default, "iniparser: syntax error in %s (lineno: %d): %s",
618 ininame, lineno, line);
624 memset(line, 0, ASCIILINESZ);
627 LOG(log_error, logtype_default, "iniparser: memory allocation failure");
632 dictionary_del(dict);
639 /*-------------------------------------------------------------------------*/
641 @brief Free all memory associated to an ini dictionary
642 @param d Dictionary to free
645 Free all memory associated to an ini dictionary.
646 It is mandatory to call this function before the dictionary object
647 gets out of the current context.
649 /*--------------------------------------------------------------------------*/
650 void iniparser_freedict(dictionary * d)