2
/*-------------------------------------------------------------------------*/
8
@brief Parser for ini files.
10
/*--------------------------------------------------------------------------*/
12
$Id: iniparser.c,v 2.18 2008-01-03 18:35:39 ndevilla Exp $
14
$Date: 2008-01-03 18:35:39 $
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(const char * s)
53
static char l[ASCIILINESZ+1];
56
if (s==NULL) return NULL ;
57
memset(l, 0, ASCIILINESZ+1);
59
while (s[i] && i<ASCIILINESZ) {
60
l[i] = (char)tolower((int)s[i]);
63
l[ASCIILINESZ]=(char)0;
67
/*-------------------------------------------------------------------------*/
69
@brief Remove blanks at the beginning and the end of a string.
70
@param s String to parse.
71
@return ptr to statically allocated string.
73
This function returns a pointer to a statically allocated string,
74
which is identical to the input string, except that all blank
75
characters at the end and the beg. of the string have been removed.
76
Do not free or modify the returned string! Since the returned string
77
is statically allocated, it will be modified at each function call
80
/*--------------------------------------------------------------------------*/
81
static char * strstrip(char * s)
83
static char l[ASCIILINESZ+1];
86
if (s==NULL) return NULL ;
88
while (isspace((int)*s) && *s) s++;
89
memset(l, 0, ASCIILINESZ+1);
93
if (!isspace((int)*(last-1)))
101
/*-------------------------------------------------------------------------*/
103
@brief Get number of sections in a dictionary
104
@param d Dictionary to examine
105
@return int Number of sections found in dictionary
107
This function returns the number of sections found in a dictionary.
108
The test to recognize sections is done on the string stored in the
109
dictionary: a section name is given as "section" whereas a key is
110
stored as "section:key", thus the test looks for entries that do not
113
This clearly fails in the case a section name contains a colon, but
114
this should simply be avoided.
116
This function returns -1 in case of error.
118
/*--------------------------------------------------------------------------*/
119
int iniparser_getnsec(dictionary * d)
124
if (d==NULL) return -1 ;
126
for (i=0 ; i<d->size ; i++) {
129
if (strchr(d->key[i], ':')==NULL) {
136
/*-------------------------------------------------------------------------*/
138
@brief Get name for section n in a dictionary.
139
@param d Dictionary to examine
140
@param n Section number (from 0 to nsec-1).
141
@return Pointer to char string
143
This function locates the n-th section in a dictionary and returns
144
its name as a pointer to a string statically allocated inside the
145
dictionary. Do not free or modify the returned string!
147
This function returns NULL in case of error.
149
/*--------------------------------------------------------------------------*/
150
char * iniparser_getsecname(dictionary * d, int n)
155
if (d==NULL || n<0) return NULL ;
157
for (i=0 ; i<d->size ; i++) {
160
if (strchr(d->key[i], ':')==NULL) {
172
/*-------------------------------------------------------------------------*/
174
@brief Get number of keys for section n in a dictionary.
175
@param d Dictionary to examine
176
@param n Section number (from 0 to nsec-1).
177
@return Number of keys in section
179
This function locates the n-th section in a dictionary and returns
180
the number of keys in this section.
182
This function returns -1 in case of error.
184
/*--------------------------------------------------------------------------*/
185
int iniparser_getnkey(dictionary * d, int n)
187
int i, i_sec, cnt = 0 ;
189
if (d==NULL) return -1 ;
190
for (i_sec=i=0 ; i<d->size ; i++) {
193
if (strchr(d->key[i], ':')==NULL) {
204
/*-------------------------------------------------------------------------*/
206
@brief Get key and string for key nkey in section nsec in a dictionary.
207
@param d Dictionary to examine
208
@param nsec Section number.
209
@param nkey Key number.
210
@param string Pointer where the string will be returned.
211
@return Pointer to char string
213
This function locates the nkey-th key in the nsec-th section in a dictionary
214
and returns the key name and the key string as a pointer to strings
215
statically allocated inside the dictionary.
216
Do not free or modify the returned strings!
218
This function returns NULL in case of error.
220
/*--------------------------------------------------------------------------*/
221
char * iniparser_getkeyname(dictionary * d, int nsec, int nkey, char ** string)
225
if (d==NULL) return 0 ;
226
for (i=0 ; i<d->size ; i++) {
229
if (strchr(d->key[i], ':')==NULL) {
235
keylen = strlen(d->key[i]) + 1;
237
for (; i<d->size ; i++) {
246
return d->key[i] + keylen;
249
/*-------------------------------------------------------------------------*/
251
@brief Dump a dictionary to an opened file pointer.
252
@param d Dictionary to dump.
253
@param f Opened file pointer to dump to.
256
This function prints out the contents of a dictionary, one element by
257
line, onto the provided file pointer. It is OK to specify @c stderr
258
or @c stdout as output files. This function is meant for debugging
261
/*--------------------------------------------------------------------------*/
262
void iniparser_dump(dictionary * d, FILE * f)
266
if (d==NULL || f==NULL) return ;
267
for (i=0 ; i<d->size ; i++) {
270
if (d->val[i]!=NULL) {
271
fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
273
fprintf(f, "[%s]=UNDEF\n", d->key[i]);
279
/*-------------------------------------------------------------------------*/
281
@brief Save a dictionary to a loadable ini file
282
@param d Dictionary to dump
283
@param f Opened file pointer to dump to
286
This function dumps a given dictionary into a loadable ini file.
287
It is Ok to specify @c stderr or @c stdout as output files.
289
/*--------------------------------------------------------------------------*/
290
void iniparser_dump_ini(dictionary * d, FILE * f)
293
char keym[ASCIILINESZ+1];
298
if (d==NULL || f==NULL) return ;
300
nsec = iniparser_getnsec(d);
302
/* No section in file: dump all keys as they are */
303
for (i=0 ; i<d->size ; i++) {
306
fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
310
for (i=0 ; i<nsec ; i++) {
311
secname = iniparser_getsecname(d, i) ;
312
seclen = (int)strlen(secname);
313
fprintf(f, "\n[%s]\n", secname);
314
sprintf(keym, "%s:", secname);
315
for (j=0 ; j<d->size ; j++) {
318
if (!strncmp(d->key[j], keym, seclen+1)) {
322
d->val[j] ? d->val[j] : "");
330
/*-------------------------------------------------------------------------*/
332
@brief Get the string associated to a key
333
@param d Dictionary to search
334
@param key Key string to look for
335
@param def Default value to return if key not found.
336
@return pointer to statically allocated character string
338
This function queries a dictionary for a key. A key as read from an
339
ini file is given as "section:key". If the key cannot be found,
340
the pointer passed as 'def' is returned.
341
The returned char pointer is pointing to a string allocated in
342
the dictionary, do not free or modify it.
344
/*--------------------------------------------------------------------------*/
345
char * iniparser_getstring(dictionary * d, const char * key, char * def)
350
if (d==NULL || key==NULL)
353
lc_key = strlwc(key);
354
sval = dictionary_get(d, lc_key, def);
358
/*-------------------------------------------------------------------------*/
360
@brief Get the string associated to a key, convert to an int
361
@param d Dictionary to search
362
@param key Key string to look for
363
@param notfound Value to return in case of error
366
This function queries a dictionary for a key. A key as read from an
367
ini file is given as "section:key". If the key cannot be found,
368
the notfound value is returned.
370
Supported values for integers include the usual C notation
371
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
372
are supported. Examples:
375
"042" -> 34 (octal -> decimal)
376
"0x42" -> 66 (hexa -> decimal)
378
Warning: the conversion may overflow in various ways. Conversion is
379
totally outsourced to strtol(), see the associated man page for overflow
382
Credits: Thanks to A. Becker for suggesting strtol()
384
/*--------------------------------------------------------------------------*/
385
int iniparser_getint(dictionary * d, const char * key, int notfound)
389
str = iniparser_getstring(d, key, INI_INVALID_KEY);
390
if (str==INI_INVALID_KEY) return notfound ;
391
return (int)strtol(str, NULL, 0);
394
/*-------------------------------------------------------------------------*/
396
@brief Get the string associated to a key, convert to a double
397
@param d Dictionary to search
398
@param key Key string to look for
399
@param notfound Value to return in case of error
402
This function queries a dictionary for a key. A key as read from an
403
ini file is given as "section:key". If the key cannot be found,
404
the notfound value is returned.
406
/*--------------------------------------------------------------------------*/
407
double iniparser_getdouble(dictionary * d, char * key, double notfound)
411
str = iniparser_getstring(d, key, INI_INVALID_KEY);
412
if (str==INI_INVALID_KEY) return notfound ;
416
/*-------------------------------------------------------------------------*/
418
@brief Get the string associated to a key, convert to a boolean
419
@param d Dictionary to search
420
@param key Key string to look for
421
@param notfound Value to return in case of error
424
This function queries a dictionary for a key. A key as read from an
425
ini file is given as "section:key". If the key cannot be found,
426
the notfound value is returned.
428
A true boolean is found if one of the following is matched:
430
- A string starting with 'y'
431
- A string starting with 'Y'
432
- A string starting with 't'
433
- A string starting with 'T'
434
- A string starting with '1'
436
A false boolean is found if one of the following is matched:
438
- A string starting with 'n'
439
- A string starting with 'N'
440
- A string starting with 'f'
441
- A string starting with 'F'
442
- A string starting with '0'
444
The notfound value returned if no boolean is identified, does not
445
necessarily have to be 0 or 1.
447
/*--------------------------------------------------------------------------*/
448
int iniparser_getboolean(dictionary * d, const char * key, int notfound)
453
c = iniparser_getstring(d, key, INI_INVALID_KEY);
454
if (c==INI_INVALID_KEY) return notfound ;
455
if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
457
} else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
465
/*-------------------------------------------------------------------------*/
467
@brief Finds out if a given entry exists in a dictionary
468
@param ini Dictionary to search
469
@param entry Name of the entry to look for
470
@return integer 1 if entry exists, 0 otherwise
472
Finds out if a given entry exists in the dictionary. Since sections
473
are stored as keys with NULL associated values, this is the only way
474
of querying for the presence of sections in a dictionary.
476
/*--------------------------------------------------------------------------*/
477
int iniparser_find_entry(
483
if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
489
/*-------------------------------------------------------------------------*/
491
@brief Set an entry in a dictionary.
492
@param ini Dictionary to modify.
493
@param entry Entry to modify (entry name)
494
@param val New value to associate to the entry.
495
@return int 0 if Ok, -1 otherwise.
497
If the given entry can be found in the dictionary, it is modified to
498
contain the provided value. If it cannot be found, -1 is returned.
499
It is Ok to set val to NULL.
501
/*--------------------------------------------------------------------------*/
502
int iniparser_set(dictionary * ini, char * entry, char * val)
504
return dictionary_set(ini, strlwc(entry), val) ;
507
/*-------------------------------------------------------------------------*/
509
@brief Delete an entry in a dictionary
510
@param ini Dictionary to modify
511
@param entry Entry to delete (entry name)
514
If the given entry can be found, it is deleted from the dictionary.
516
/*--------------------------------------------------------------------------*/
517
void iniparser_unset(dictionary * ini, char * entry)
519
dictionary_unset(ini, strlwc(entry));
522
/*-------------------------------------------------------------------------*/
524
@brief Load a single line from an INI file
525
@param input_line Input line, may be concatenated multi-line input
526
@param section Output space to store section
527
@param key Output space to store key
528
@param value Output space to store value
529
@return line_status value
531
/*--------------------------------------------------------------------------*/
532
static line_status iniparser_line(
539
char line[ASCIILINESZ+1];
542
strcpy(line, strstrip(input_line));
543
len = (int)strlen(line);
545
sta = LINE_UNPROCESSED ;
549
} else if (line[0]=='#' || line[0]==';') {
552
} else if (line[0]=='[' && line[len-1]==']') {
554
sscanf(line, "[%[^]]", section);
555
strcpy(section, strstrip(section));
556
strcpy(section, section);
558
} else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
559
|| sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
560
|| sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
561
/* Usual key=value, with or without comments */
562
strcpy(key, strstrip(key));
564
strcpy(value, strstrip(value));
566
* sscanf cannot handle '' or "" as empty values
569
if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
573
} else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
574
|| sscanf(line, "%[^=] %[=]", key, value) == 2) {
581
strcpy(key, strstrip(key));
586
/* Generate syntax error */
592
/*-------------------------------------------------------------------------*/
594
@brief Parse an ini file and return an allocated dictionary object
595
@param ininame Name of the ini file to read.
596
@return Pointer to newly allocated dictionary
598
This is the parser for ini files. This function is called, providing
599
the name of the file to be read. It returns a dictionary object that
600
should not be accessed directly, but through accessor functions
603
The returned dictionary must be freed using iniparser_freedict().
605
/*--------------------------------------------------------------------------*/
606
dictionary * iniparser_load(const char * ininame)
610
char line [ASCIILINESZ+1] ;
611
char section [ASCIILINESZ+1] ;
612
char key [ASCIILINESZ+1] ;
613
char tmp [ASCIILINESZ+1] ;
614
char val [ASCIILINESZ+1] ;
623
if ((in=fopen(ininame, "r"))==NULL) {
624
fprintf(stderr, "iniparser: cannot open %s\n", ininame);
628
dict = dictionary_new(0) ;
634
memset(line, 0, ASCIILINESZ);
635
memset(section, 0, ASCIILINESZ);
636
memset(key, 0, ASCIILINESZ);
637
memset(val, 0, ASCIILINESZ);
640
while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
642
len = (int)strlen(line)-1;
643
/* Safety check against buffer overflows */
644
if (line[len]!='\n') {
646
"iniparser: input line too long in %s (%d)\n",
649
dictionary_del(dict);
653
/* Get rid of \n and spaces at end of line */
655
((line[len]=='\n') || (isspace(line[len])))) {
659
/* Detect multi-line */
660
if (line[len]=='\\') {
661
/* Multi-line value */
667
switch (iniparser_line(line, section, key, val)) {
673
errs = dictionary_set(dict, section, NULL);
677
sprintf(tmp, "%s:%s", section, key);
678
errs = dictionary_set(dict, tmp, val) ;
682
fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
685
fprintf(stderr, "-> %s\n", line);
692
memset(line, 0, ASCIILINESZ);
695
fprintf(stderr, "iniparser: memory allocation failure\n");
700
dictionary_del(dict);
707
/*-------------------------------------------------------------------------*/
709
@brief Free all memory associated to an ini dictionary
710
@param d Dictionary to free
713
Free all memory associated to an ini dictionary.
714
It is mandatory to call this function before the dictionary object
715
gets out of the current context.
717
/*--------------------------------------------------------------------------*/
718
void iniparser_freedict(dictionary * d)
723
/* vim: set ts=4 et sw=4 tw=75 */