third_party/iniparser: Initial copy of iniparser.
[bbaumbach/samba-autobuild/.git] / third_party / iniparser / src / iniparser.c
1
2 /*-------------------------------------------------------------------------*/
3 /**
4    @file    iniparser.c
5    @author  N. Devillard
6    @date    Mar 2000
7    @version $Revision: 2.17 $
8    @brief   Parser for ini files.
9 */
10 /*--------------------------------------------------------------------------*/
11
12 /*
13     $Id: iniparser.c,v 2.17 2007-05-27 13:03:43 ndevilla Exp $
14     $Author: ndevilla $
15     $Date: 2007-05-27 13:03:43 $
16     $Revision: 2.17 $
17 */
18
19 /*---------------------------------------------------------------------------
20                                 Includes
21  ---------------------------------------------------------------------------*/
22
23 #include "iniparser.h"
24 #include "strlib.h"
25
26 #define ASCIILINESZ         1024
27 #define INI_INVALID_KEY     ((char*)-1)
28
29 /*---------------------------------------------------------------------------
30                         Private to this module
31  ---------------------------------------------------------------------------*/
32
33 /* Private: add an entry to the dictionary */
34 static void iniparser_add_entry(
35     dictionary * d,
36     char * sec,
37     char * key,
38     char * val)
39 {
40     char longkey[2*ASCIILINESZ+1];
41     char *l;
42
43     /* Make a key as section:keyword */
44     if (key!=NULL) {
45         snprintf(longkey, sizeof(longkey), "%s:%s", sec, key);
46         l = longkey;
47     } else {
48         l = sec;
49     }
50
51     /* Add (key,val) to dictionary */
52     dictionary_set(d, l, val);
53     return ;
54 }
55
56
57 /*-------------------------------------------------------------------------*/
58 /**
59   @brief    Get number of sections in a dictionary
60   @param    d   Dictionary to examine
61   @return   int Number of sections found in dictionary
62
63   This function returns the number of sections found in a dictionary.
64   The test to recognize sections is done on the string stored in the
65   dictionary: a section name is given as "section" whereas a key is
66   stored as "section:key", thus the test looks for entries that do not
67   contain a colon.
68
69   This clearly fails in the case a section name contains a colon, but
70   this should simply be avoided.
71
72   This function returns -1 in case of error.
73  */
74 /*--------------------------------------------------------------------------*/
75
76 int iniparser_getnsec(dictionary * d)
77 {
78     int i ;
79     int nsec ;
80
81     if (d==NULL) return -1 ;
82     nsec=0 ;
83     for (i=0 ; i<d->size ; i++) {
84         if (d->key[i]==NULL)
85             continue ;
86         if (strchr(d->key[i], ':')==NULL) {
87             nsec ++ ;
88         }
89     }
90     return nsec ;
91 }
92
93
94 /*-------------------------------------------------------------------------*/
95 /**
96   @brief    Get name for section n in a dictionary.
97   @param    d   Dictionary to examine
98   @param    n   Section number (from 0 to nsec-1).
99   @return   Pointer to char string
100
101   This function locates the n-th section in a dictionary and returns
102   its name as a pointer to a string statically allocated inside the
103   dictionary. Do not free or modify the returned string!
104
105   This function returns NULL in case of error.
106  */
107 /*--------------------------------------------------------------------------*/
108
109 char * iniparser_getsecname(dictionary * d, int n)
110 {
111     int i ;
112     int foundsec ;
113
114     if (d==NULL || n<0) return NULL ;
115     foundsec=0 ;
116     for (i=0 ; i<d->size ; i++) {
117         if (d->key[i]==NULL)
118             continue ;
119         if (strchr(d->key[i], ':')==NULL) {
120             foundsec++ ;
121             if (foundsec>n)
122                 break ;
123         }
124     }
125     if (foundsec<=n) {
126         return NULL ;
127     }
128     return d->key[i] ;
129 }
130
131
132 /*-------------------------------------------------------------------------*/
133 /**
134   @brief    Dump a dictionary to an opened file pointer.
135   @param    d   Dictionary to dump.
136   @param    f   Opened file pointer to dump to.
137   @return   void
138
139   This function prints out the contents of a dictionary, one element by
140   line, onto the provided file pointer. It is OK to specify @c stderr
141   or @c stdout as output files. This function is meant for debugging
142   purposes mostly.
143  */
144 /*--------------------------------------------------------------------------*/
145 void iniparser_dump(dictionary * d, FILE * f)
146 {
147     int     i ;
148
149     if (d==NULL || f==NULL) return ;
150     for (i=0 ; i<d->size ; i++) {
151         if (d->key[i]==NULL)
152             continue ;
153         if (d->val[i]!=NULL) {
154             fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
155         } else {
156             fprintf(f, "[%s]=UNDEF\n", d->key[i]);
157         }
158     }
159     return ;
160 }
161
162 /*-------------------------------------------------------------------------*/
163 /**
164   @brief    Save a dictionary to a loadable ini file
165   @param    d   Dictionary to dump
166   @param    f   Opened file pointer to dump to
167   @return   void
168
169   This function dumps a given dictionary into a loadable ini file.
170   It is Ok to specify @c stderr or @c stdout as output files.
171  */
172 /*--------------------------------------------------------------------------*/
173
174 void iniparser_dump_ini(dictionary * d, FILE * f)
175 {
176     int     i, j ;
177     char    keym[ASCIILINESZ+1];
178     int     nsec ;
179     char *  secname ;
180     int     seclen ;
181
182     if (d==NULL || f==NULL) return ;
183
184     nsec = iniparser_getnsec(d);
185     if (nsec<1) {
186         /* No section in file: dump all keys as they are */
187         for (i=0 ; i<d->size ; i++) {
188             if (d->key[i]==NULL)
189                 continue ;
190             fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
191         }
192         return ;
193     }
194     for (i=0 ; i<nsec ; i++) {
195         secname = iniparser_getsecname(d, i) ;
196         seclen  = (int)strlen(secname);
197         fprintf(f, "\n[%s]\n", secname);
198         sprintf(keym, "%s:", secname);
199         for (j=0 ; j<d->size ; j++) {
200             if (d->key[j]==NULL)
201                 continue ;
202             if (!strncmp(d->key[j], keym, seclen+1)) {
203                 fprintf(f,
204                         "%-30s = %s\n",
205                         d->key[j]+seclen+1,
206                         d->val[j] ? d->val[j] : "");
207             }
208         }
209     }
210     fprintf(f, "\n");
211     return ;
212 }
213
214
215
216
217 /*-------------------------------------------------------------------------*/
218 /**
219   @brief        Get the string associated to a key, return NULL if not found
220   @param    d   Dictionary to search
221   @param    key Key string to look for
222   @return   pointer to statically allocated character string, or NULL.
223
224   This function queries a dictionary for a key. A key as read from an
225   ini file is given as "section:key". If the key cannot be found,
226   NULL is returned.
227   The returned char pointer is pointing to a string allocated in
228   the dictionary, do not free or modify it.
229
230   This function is only provided for backwards compatibility with 
231   previous versions of iniparser. It is recommended to use
232   iniparser_getstring() instead.
233  */
234 /*--------------------------------------------------------------------------*/
235 char * iniparser_getstr(dictionary * d, const char * key)
236 {
237     return iniparser_getstring(d, key, NULL);
238 }
239
240
241 /*-------------------------------------------------------------------------*/
242 /**
243   @brief    Get the string associated to a key
244   @param    d       Dictionary to search
245   @param    key     Key string to look for
246   @param    def     Default value to return if key not found.
247   @return   pointer to statically allocated character string
248
249   This function queries a dictionary for a key. A key as read from an
250   ini file is given as "section:key". If the key cannot be found,
251   the pointer passed as 'def' is returned.
252   The returned char pointer is pointing to a string allocated in
253   the dictionary, do not free or modify it.
254  */
255 /*--------------------------------------------------------------------------*/
256 char * iniparser_getstring(dictionary * d, const char * key, char * def)
257 {
258     char * lc_key ;
259     char * sval ;
260
261     if (d==NULL || key==NULL)
262         return def ;
263
264     if (!(lc_key = strdup(strlwc(key)))) {
265             return NULL;
266     }
267     sval = dictionary_get(d, lc_key, def);
268     free(lc_key);
269     return sval ;
270 }
271
272
273
274 /*-------------------------------------------------------------------------*/
275 /**
276   @brief    Get the string associated to a key, convert to an int
277   @param    d Dictionary to search
278   @param    key Key string to look for
279   @param    notfound Value to return in case of error
280   @return   integer
281
282   This function queries a dictionary for a key. A key as read from an
283   ini file is given as "section:key". If the key cannot be found,
284   the notfound value is returned.
285
286   Supported values for integers include the usual C notation
287   so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
288   are supported. Examples:
289
290   "42"      ->  42
291   "042"     ->  34 (octal -> decimal)
292   "0x42"    ->  66 (hexa  -> decimal)
293
294   Warning: the conversion may overflow in various ways. Conversion is
295   totally outsourced to strtol(), see the associated man page for overflow
296   handling.
297
298   Credits: Thanks to A. Becker for suggesting strtol()
299  */
300 /*--------------------------------------------------------------------------*/
301 int iniparser_getint(dictionary * d, const char * key, int notfound)
302 {
303     char    *   str ;
304
305     str = iniparser_getstring(d, key, INI_INVALID_KEY);
306     if (str==INI_INVALID_KEY) return notfound ;
307     return (int)strtol(str, NULL, 0);
308 }
309
310
311 /*-------------------------------------------------------------------------*/
312 /**
313   @brief    Get the string associated to a key, convert to a double
314   @param    d Dictionary to search
315   @param    key Key string to look for
316   @param    notfound Value to return in case of error
317   @return   double
318
319   This function queries a dictionary for a key. A key as read from an
320   ini file is given as "section:key". If the key cannot be found,
321   the notfound value is returned.
322  */
323 /*--------------------------------------------------------------------------*/
324 double iniparser_getdouble(dictionary * d, char * key, double notfound)
325 {
326     char    *   str ;
327
328     str = iniparser_getstring(d, key, INI_INVALID_KEY);
329     if (str==INI_INVALID_KEY) return notfound ;
330     return atof(str);
331 }
332
333
334
335 /*-------------------------------------------------------------------------*/
336 /**
337   @brief    Get the string associated to a key, convert to a boolean
338   @param    d Dictionary to search
339   @param    key Key string to look for
340   @param    notfound Value to return in case of error
341   @return   integer
342
343   This function queries a dictionary for a key. A key as read from an
344   ini file is given as "section:key". If the key cannot be found,
345   the notfound value is returned.
346
347   A true boolean is found if one of the following is matched:
348
349   - A string starting with 'y'
350   - A string starting with 'Y'
351   - A string starting with 't'
352   - A string starting with 'T'
353   - A string starting with '1'
354
355   A false boolean is found if one of the following is matched:
356
357   - A string starting with 'n'
358   - A string starting with 'N'
359   - A string starting with 'f'
360   - A string starting with 'F'
361   - A string starting with '0'
362
363   The notfound value returned if no boolean is identified, does not
364   necessarily have to be 0 or 1.
365  */
366 /*--------------------------------------------------------------------------*/
367 int iniparser_getboolean(dictionary * d, const char * key, int notfound)
368 {
369     char    *   c ;
370     int         ret ;
371
372     c = iniparser_getstring(d, key, INI_INVALID_KEY);
373     if (c==INI_INVALID_KEY) return notfound ;
374     if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
375         ret = 1 ;
376     } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
377         ret = 0 ;
378     } else {
379         ret = notfound ;
380     }
381     return ret;
382 }
383
384
385 /*-------------------------------------------------------------------------*/
386 /**
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
391
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.
395  */
396 /*--------------------------------------------------------------------------*/
397
398 int iniparser_find_entry(
399     dictionary  *   ini,
400     char        *   entry
401 )
402 {
403     int found=0 ;
404     if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
405         found = 1 ;
406     }
407     return found ;
408 }
409
410
411
412 /*-------------------------------------------------------------------------*/
413 /**
414   @brief    Set an entry in a dictionary.
415   @param    ini     Dictionary to modify.
416   @param    entry   Entry to modify (entry name)
417   @param    val     New value to associate to the entry.
418   @return   int 0 if Ok, -1 otherwise.
419
420   If the given entry can be found in the dictionary, it is modified to
421   contain the provided value. If it cannot be found, -1 is returned.
422   It is Ok to set val to NULL.
423  */
424 /*--------------------------------------------------------------------------*/
425
426 int iniparser_setstr(dictionary * ini, char * entry, char * val)
427 {
428     dictionary_set(ini, strlwc(entry), val);
429     return 0 ;
430 }
431
432 /*-------------------------------------------------------------------------*/
433 /**
434   @brief    Delete an entry in a dictionary
435   @param    ini     Dictionary to modify
436   @param    entry   Entry to delete (entry name)
437   @return   void
438
439   If the given entry can be found, it is deleted from the dictionary.
440  */
441 /*--------------------------------------------------------------------------*/
442 void iniparser_unset(dictionary * ini, char * entry)
443 {
444     dictionary_unset(ini, strlwc(entry));
445 }
446
447
448 /*-------------------------------------------------------------------------*/
449 /**
450   @brief    Parse an ini file and return an allocated dictionary object
451   @param    ininame Name of the ini file to read.
452   @return   Pointer to newly allocated dictionary
453
454   This is the parser for ini files. This function is called, providing
455   the name of the file to be read. It returns a dictionary object that
456   should not be accessed directly, but through accessor functions
457   instead.
458
459   The returned dictionary must be freed using iniparser_freedict().
460  */
461 /*--------------------------------------------------------------------------*/
462
463 dictionary * iniparser_load(const char * ininame)
464 {
465     dictionary  *   d ;
466     char        lin[ASCIILINESZ+1];
467     char        sec[ASCIILINESZ+1];
468     char        key[ASCIILINESZ+1];
469     char        val[ASCIILINESZ+1];
470     char    *   where ;
471     FILE    *   ini ;
472     int         lineno ;
473
474     if ((ini=fopen(ininame, "r"))==NULL) {
475         return NULL ;
476     }
477
478     sec[0]=0;
479
480     /*
481      * Initialize a new dictionary entry
482      */
483     if (!(d = dictionary_new(0))) {
484             fclose(ini);
485             return NULL;
486     }
487     lineno = 0 ;
488     while (fgets(lin, ASCIILINESZ, ini)!=NULL) {
489         lineno++ ;
490         where = strskp(lin); /* Skip leading spaces */
491         if (*where==';' || *where=='#' || *where==0)
492             continue ; /* Comment lines */
493         else {
494             if (sscanf(where, "[%[^]]", sec)==1) {
495                 /* Valid section name */
496                 strcpy(sec, strlwc(sec));
497                 iniparser_add_entry(d, sec, NULL, NULL);
498             } else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2
499                    ||  sscanf (where, "%[^=] = '%[^\']'",   key, val) == 2
500                    ||  sscanf (where, "%[^=] = %[^;#]",     key, val) == 2) {
501                 strcpy(key, strlwc(strcrop(key)));
502                 /*
503                  * sscanf cannot handle "" or '' as empty value,
504                  * this is done here
505                  */
506                 if (!strcmp(val, "\"\"") || !strcmp(val, "''")) {
507                     val[0] = (char)0;
508                 } else {
509                     strcpy(val, strcrop(val));
510                 }
511                 iniparser_add_entry(d, sec, key, val);
512             }
513         }
514     }
515     fclose(ini);
516     return d ;
517 }
518
519
520
521 /*-------------------------------------------------------------------------*/
522 /**
523   @brief    Free all memory associated to an ini dictionary
524   @param    d Dictionary to free
525   @return   void
526
527   Free all memory associated to an ini dictionary.
528   It is mandatory to call this function before the dictionary object
529   gets out of the current context.
530  */
531 /*--------------------------------------------------------------------------*/
532
533 void iniparser_freedict(dictionary * d)
534 {
535     dictionary_del(d);
536 }
537
538 /* vim: set ts=4 et sw=4 tw=75 */