2 /*-------------------------------------------------------------------------*/
7 @version $Revision: 2.14 $
8 @brief Parser for ini files.
10 The following four functions are added by Wong Chi Kwong (2004).
11 No warranty is given regarding the quality of this software.
13 dictionary * paraparser_load(int argc, char **argv, int booleanc, char **booleanv);
14 char* paraparser_argument(dictionary *d, int argumentNumber);
15 int paraparser_getnargument(dictionary * d);
16 unsigned int iniparser_getuint(dictionary * d, char * key, int notfound);
19 /*--------------------------------------------------------------------------*/
22 $Id: iniparser.c,v 2.14 2002/12/12 10:49:01 ndevilla Exp $
24 $Date: 2002/12/12 10:49:01 $
28 /*---------------------------------------------------------------------------
30 ---------------------------------------------------------------------------*/
32 #include "iniparser.h"
33 #include "inistrlib.h"
35 #define ASCIILINESZ 1024
36 #define INI_INVALID_KEY ((char*)-1)
38 /*---------------------------------------------------------------------------
39 Private to this module
40 ---------------------------------------------------------------------------*/
42 /* Private: add an entry to the dictionary */
43 static void iniparser_add_entry(
49 char longkey
[2*ASCIILINESZ
+1];
51 /* Make a key as section:keyword */
53 sprintf(longkey
, "%s:%s", sec
, key
);
58 /* Add (key,val) to dictionary */
59 dictionary_set(d
, longkey
, val
);
64 /*-------------------------------------------------------------------------*/
66 @brief Get number of sections in a dictionary
67 @param d Dictionary to examine
68 @return int Number of sections found in dictionary
70 This function returns the number of sections found in a dictionary.
71 The test to recognize sections is done on the string stored in the
72 dictionary: a section name is given as "section" whereas a key is
73 stored as "section:key", thus the test looks for entries that do not
76 This clearly fails in the case a section name contains a colon, but
77 this should simply be avoided.
79 This function returns -1 in case of error.
81 /*--------------------------------------------------------------------------*/
83 int iniparser_getnsec(dictionary
* d
)
88 if (d
==NULL
) return -1 ;
90 for (i
=0 ; i
<d
->size
; i
++) {
93 if (strchr(d
->key
[i
], ':')==NULL
) {
101 /*-------------------------------------------------------------------------*/
103 @brief Get name for section n in a dictionary.
104 @param d Dictionary to examine
105 @param n Section number (from 0 to nsec-1).
106 @return Pointer to char string
108 This function locates the n-th section in a dictionary and returns
109 its name as a pointer to a string statically allocated inside the
110 dictionary. Do not free or modify the returned string!
112 This function returns NULL in case of error.
114 /*--------------------------------------------------------------------------*/
116 char * iniparser_getsecname(dictionary
* d
, int n
)
121 if (d
==NULL
|| n
<0) return NULL
;
123 for (i
=0 ; i
<d
->size
; i
++) {
126 if (strchr(d
->key
[i
], ':')==NULL
) {
139 /*-------------------------------------------------------------------------*/
141 @brief Dump a dictionary to an opened file pointer.
142 @param d Dictionary to dump.
143 @param f Opened file pointer to dump to.
146 This function prints out the contents of a dictionary, one element by
147 line, onto the provided file pointer. It is OK to specify @c stderr
148 or @c stdout as output files. This function is meant for debugging
151 /*--------------------------------------------------------------------------*/
152 void iniparser_dump(dictionary
* d
, FILE * f
)
156 if (d
==NULL
|| f
==NULL
) return ;
157 for (i
=0 ; i
<d
->size
; i
++) {
160 if (d
->val
[i
]!=NULL
) {
161 fprintf(f
, "[%s]=[%s]\n", d
->key
[i
], d
->val
[i
]);
163 fprintf(f
, "[%s]=UNDEF\n", d
->key
[i
]);
169 /*-------------------------------------------------------------------------*/
171 @brief Save a dictionary to a loadable ini file
172 @param d Dictionary to dump
173 @param f Opened file pointer to dump to
176 This function dumps a given dictionary into a loadable ini file.
177 It is Ok to specify @c stderr or @c stdout as output files.
179 /*--------------------------------------------------------------------------*/
181 void iniparser_dump_ini(dictionary
* d
, FILE * f
)
184 char keym
[ASCIILINESZ
+1];
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
] : "");
224 /*-------------------------------------------------------------------------*/
226 @brief Get the string associated to a key, return NULL if not found
227 @param d Dictionary to search
228 @param key Key string to look for
229 @return pointer to statically allocated character string, or NULL.
231 This function queries a dictionary for a key. A key as read from an
232 ini file is given as "section:key". If the key cannot be found,
234 The returned char pointer is pointing to a string allocated in
235 the dictionary, do not free or modify it.
237 This function is only provided for backwards compatibility with
238 previous versions of iniparser. It is recommended to use
239 iniparser_getstring() instead.
241 /*--------------------------------------------------------------------------*/
242 char * iniparser_getstr(dictionary
* d
, char * key
)
244 return iniparser_getstring(d
, key
, NULL
);
248 /*-------------------------------------------------------------------------*/
250 @brief Get the string associated to a key
251 @param d Dictionary to search
252 @param key Key string to look for
253 @param def Default value to return if key not found.
254 @return pointer to statically allocated character string
256 This function queries a dictionary for a key. A key as read from an
257 ini file is given as "section:key". If the key cannot be found,
258 the pointer passed as 'def' is returned.
259 The returned char pointer is pointing to a string allocated in
260 the dictionary, do not free or modify it.
262 /*--------------------------------------------------------------------------*/
263 char * iniparser_getstring(dictionary
* d
, char * key
, char * def
)
268 if (d
==NULL
|| key
==NULL
)
271 // Check whether the dictionary is case-sensitive
272 if (d
->caseSensitive
) {
273 lc_key
= inistrdup(key
);
275 lc_key
= inistrdup(inistrlwc(key
));
277 sval
= dictionary_get(d
, lc_key
, def
);
282 /*-------------------------------------------------------------------------*/
284 @brief Copy the string associated to a key
285 @param d Dictionary to search
286 @param key Key string to look for
287 @param target target address to copy to
288 @param def Default value if key not found, which can be the same pointer as target
289 @param maxLen Maximum length of target
291 This function queries a dictionary for a key. A key as read from an
292 ini file is given as "section:key".
293 The dictionary content for the key will be copied into target for maxLen.
294 If the key cannot be found, the content in 'def' will be copied instead.
295 def can be the same pointer as target.
297 /*--------------------------------------------------------------------------*/
298 void iniparser_copystring(dictionary
* d
, char * key
, char *target
, char * def
, int maxLen
)
303 if (d
==NULL
|| key
==NULL
)
306 // Check whether the dictionary is case-sensitive
307 if (d
->caseSensitive
) {
308 lc_key
= inistrdup(key
);
310 lc_key
= inistrdup(inistrlwc(key
));
312 sval
= dictionary_get(d
, lc_key
, def
);
315 if (target
!= sval
) {
316 strncpy(target
, sval
, maxLen
);
317 target
[maxLen
] = '\0';
325 /*-------------------------------------------------------------------------*/
327 @brief Get the string associated to a key, convert to an int
328 @param d Dictionary to search
329 @param key Key string to look for
330 @param notfound Value to return in case of error
333 This function queries a dictionary for a key. A key as read from an
334 ini file is given as "section:key". If the key cannot be found,
335 the notfound value is returned.
337 /*--------------------------------------------------------------------------*/
338 int iniparser_getint(dictionary
* d
, char * key
, int notfound
)
342 str
= iniparser_getstring(d
, key
, INI_INVALID_KEY
);
343 if (str
==INI_INVALID_KEY
) return notfound
;
347 /*-------------------------------------------------------------------------*/
349 @brief Get the string associated to a key, convert to an unsigned int
350 @param d Dictionary to search
351 @param key Key string to look for
352 @param notfound Value to return in case of error
353 @return unsigned integer
355 This function queries a dictionary for a key. A key as read from an
356 ini file is given as "section:key". If the key cannot be found,
357 the notfound value is returned.
359 /*--------------------------------------------------------------------------*/
360 unsigned int iniparser_getuint(dictionary
* d
, char * key
, int notfound
)
365 str
= iniparser_getstring(d
, key
, INI_INVALID_KEY
);
366 if (str
==INI_INVALID_KEY
) return notfound
;
367 return strtoul(str
, &stopstr
, 10);
372 /*-------------------------------------------------------------------------*/
374 @brief Get the string associated to a key, convert to a double
375 @param d Dictionary to search
376 @param key Key string to look for
377 @param notfound Value to return in case of error
380 This function queries a dictionary for a key. A key as read from an
381 ini file is given as "section:key". If the key cannot be found,
382 the notfound value is returned.
384 /*--------------------------------------------------------------------------*/
385 double iniparser_getdouble(dictionary
* d
, char * key
, double notfound
)
389 str
= iniparser_getstring(d
, key
, INI_INVALID_KEY
);
390 if (str
==INI_INVALID_KEY
) return notfound
;
396 /*-------------------------------------------------------------------------*/
398 @brief Get the string associated to a key, convert to a boolean
399 @param d Dictionary to search
400 @param key Key string to look for
401 @param notfound Value to return in case of error
404 This function queries a dictionary for a key. A key as read from an
405 ini file is given as "section:key". If the key cannot be found,
406 the notfound value is returned.
408 A true boolean is found if one of the following is matched:
410 - A string starting with 'y'
411 - A string starting with 'Y'
412 - A string starting with 't'
413 - A string starting with 'T'
414 - A string starting with '1'
416 A false boolean is found if one of the following is matched:
418 - A string starting with 'n'
419 - A string starting with 'N'
420 - A string starting with 'f'
421 - A string starting with 'F'
422 - A string starting with '0'
424 The notfound value returned if no boolean is identified, does not
425 necessarily have to be 0 or 1.
427 /*--------------------------------------------------------------------------*/
428 int iniparser_getboolean(dictionary
* d
, char * key
, int notfound
)
433 c
= iniparser_getstring(d
, key
, INI_INVALID_KEY
);
434 if (c
==INI_INVALID_KEY
) return notfound
;
435 if (c
[0]=='y' || c
[0]=='Y' || c
[0]=='1' || c
[0]=='t' || c
[0]=='T') {
437 } else if (c
[0]=='n' || c
[0]=='N' || c
[0]=='0' || c
[0]=='f' || c
[0]=='F') {
446 /*-------------------------------------------------------------------------*/
448 @brief Finds out if a given entry exists in a dictionary
449 @param ini Dictionary to search
450 @param entry Name of the entry to look for
451 @return integer 1 if entry exists, 0 otherwise
453 Finds out if a given entry exists in the dictionary. Since sections
454 are stored as keys with NULL associated values, this is the only way
455 of querying for the presence of sections in a dictionary.
457 /*--------------------------------------------------------------------------*/
459 int iniparser_find_entry(
465 if (iniparser_getstring(ini
, entry
, INI_INVALID_KEY
)!=INI_INVALID_KEY
) {
473 /*-------------------------------------------------------------------------*/
475 @brief Set an entry in a dictionary.
476 @param ini Dictionary to modify.
477 @param entry Entry to modify (entry name)
478 @param val New value to associate to the entry.
479 @return int 0 if Ok, -1 otherwise.
481 If the given entry can be found in the dictionary, it is modified to
482 contain the provided value. If it cannot be found, -1 is returned.
483 It is Ok to set val to NULL.
485 /*--------------------------------------------------------------------------*/
487 int iniparser_setstr(dictionary
* ini
, char * entry
, char * val
)
489 // Check whether the dictionary is case-sensitive
490 if (ini
->caseSensitive
) {
491 dictionary_set(ini
, entry
, val
);
493 dictionary_set(ini
, inistrlwc(entry
), val
);
499 /*-------------------------------------------------------------------------*/
501 @brief Delete an entry in a dictionary
502 @param ini Dictionary to modify
503 @param entry Entry to delete (entry name)
506 If the given entry can be found, it is deleted from the dictionary.
508 /*--------------------------------------------------------------------------*/
509 void iniparser_unset(dictionary
* ini
, char * entry
)
511 // Check whether the dictionary is case-sensitive
512 if (ini
->caseSensitive
) {
513 dictionary_unset(ini
, entry
);
515 dictionary_unset(ini
, inistrlwc(entry
));
521 /*-------------------------------------------------------------------------*/
523 @brief Parse an ini file and return an allocated dictionary object
524 @param ininame Name of the ini file to read.
525 @return Pointer to newly allocated dictionary
527 This is the parser for ini files. This function is called, providing
528 the name of the file to be read. It returns a dictionary object that
529 should not be accessed directly, but through accessor functions
532 The returned dictionary must be freed using iniparser_freedict().
534 /*--------------------------------------------------------------------------*/
536 dictionary
* iniparser_load(char * ininame
, int caseSensitive
)
539 char lin
[ASCIILINESZ
+1];
540 char sec
[ASCIILINESZ
+1];
541 char key
[ASCIILINESZ
+1];
542 char val
[ASCIILINESZ
+1];
547 if ((ini
=fopen(ininame
, "r"))==NULL
) {
554 * Initialize a new dictionary entry
556 d
= dictionary_new(0, caseSensitive
); // Added case sensitive setting;
557 //d = dictionary_new(0);
559 while (fgets(lin
, ASCIILINESZ
, ini
)!=NULL
) {
561 where
= inistrskp(lin
); /* Skip leading spaces */
562 if (*where
==';' || *where
=='#' || *where
==0)
563 continue ; /* Comment lines */
565 if (sscanf(where
, "[%[^]]", sec
)==1) {
566 /* Valid section name */
570 strcpy(sec
, inistrlwc(sec
));
572 iniparser_add_entry(d
, sec
, NULL
, NULL
);
573 } else if (sscanf (where
, "%[^=] = \"%[^\"]\"", key
, val
) == 2
574 || sscanf (where
, "%[^=] = '%[^\']'", key
, val
) == 2
575 || sscanf (where
, "%[^=] = %[^;#]", key
, val
) == 2) {
577 strcpy(key
, inistrcrop(key
));
579 strcpy(key
, inistrlwc(inistrcrop(key
)));
582 * sscanf cannot handle "" or '' as empty value,
585 if (!strcmp(val
, "\"\"") || !strcmp(val
, "''")) {
588 strcpy(val
, inistrcrop(val
));
590 iniparser_add_entry(d
, sec
, key
, val
);
600 /*-------------------------------------------------------------------------*/
602 @brief Free all memory associated to an ini dictionary
603 @param d Dictionary to free
606 Free all memory associated to an ini dictionary.
607 It is mandatory to call this function before the dictionary object
608 gets out of the current context.
610 /*--------------------------------------------------------------------------*/
612 void iniparser_freedict(dictionary
* d
)
617 /* vim: set ts=4 et sw=4 tw=75 */
620 dictionary
* paraparser_load(int argc
, char *argv
[], int booleanc
, char *booleanv
[])
624 int booleanParameter
;
626 char argumentNumber
[3];
629 * Initialize a new dictionary entry
631 d
= dictionary_new(0, 1); // Case sensitive
633 argumentNumber
[0] = '0';
634 argumentNumber
[1] = '\0';
635 argumentNumber
[2] = '\0';
640 for(i
=0;i
<argc
;i
++) {
641 if (*argv
[i
] == '-') {
642 if (*(argv
[i
]+1) != '\0') {
643 // check if it is a boolean parameters
644 booleanParameter
= 0;
645 for (j
=0; j
<booleanc
; j
++) {
646 if (strcmp(argv
[i
], booleanv
[j
]) == 0) {
647 booleanParameter
= 1;
651 if (booleanParameter
== 1) {
652 iniparser_add_entry(d
, "parameter", argv
[i
], trueValue
);
655 // invalid input! Do nothing!
657 iniparser_add_entry(d
, "parameter", argv
[i
], argv
[i
+1]);
663 iniparser_add_entry(d
, "argument", argumentNumber
, argv
[i
]);
664 if (argumentNumber
[1] != '\0') {
665 if (argumentNumber
[1] == '9') {
666 if (argumentNumber
[0] == '9') {
670 argumentNumber
[1] = '0';
676 if (argumentNumber
[0] == '9') {
677 argumentNumber
[0] = '1';
678 argumentNumber
[1] = '0';
691 /*-------------------------------------------------------------------------*/
693 @brief Return the dictionary entry for an argument
694 @param dictionary, argument number
695 @return dictionary entry
697 Return the dictionary entry for an argument.
698 Used for looping on variable argument list.
700 /*--------------------------------------------------------------------------*/
702 char* paraparser_argument(dictionary
*d
, int argumentNumber
)
707 if (d
==NULL
|| argumentNumber
<0) return NULL
;
709 for (i
=0 ; i
<d
->size
; i
++) {
712 if (strncmp(d
->key
[i
], "argument:", 9)==0) {
714 if (foundsec
>argumentNumber
)
718 if (foundsec
<=argumentNumber
) {
724 /*-------------------------------------------------------------------------*/
726 @brief Get number of argument in a dictionary
727 @param d Dictionary to examine
728 @return int Number of argument found in dictionary
730 This function returns the number of argument found in a dictionary.
731 This function returns -1 in case of error.
733 /*--------------------------------------------------------------------------*/
735 int paraparser_getnargument(dictionary
* d
)
740 if (d
==NULL
) return -1 ;
742 for (i
=0 ; i
<d
->size
; i
++) {
745 if (strncmp(d
->key
[i
], "argument:", 9)==0) {