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