0cb452b26550faaad36f9464b38f1ccb396ffb3b
[abartlet/samba.git/.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.14 $
8    @brief   Parser for ini files.
9 */
10 /*--------------------------------------------------------------------------*/
11
12 /*
13     $Id: iniparser.c,v 2.14 2002/12/12 10:49:01 ndevilla Exp $
14     $Author: ndevilla $
15     $Date: 2002/12/12 10:49:01 $
16     $Revision: 2.14 $
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 /*--------------------------------------------------------------------------*/
285 int iniparser_getint(dictionary * d, const char * key, int notfound)
286 {
287     char    *   str ;
288
289     str = iniparser_getstring(d, key, INI_INVALID_KEY);
290     if (str==INI_INVALID_KEY) return notfound ;
291     return atoi(str);
292 }
293
294
295 /*-------------------------------------------------------------------------*/
296 /**
297   @brief    Get the string associated to a key, convert to a double
298   @param    d Dictionary to search
299   @param    key Key string to look for
300   @param    notfound Value to return in case of error
301   @return   double
302
303   This function queries a dictionary for a key. A key as read from an
304   ini file is given as "section:key". If the key cannot be found,
305   the notfound value is returned.
306  */
307 /*--------------------------------------------------------------------------*/
308 double iniparser_getdouble(dictionary * d, char * key, double notfound)
309 {
310     char    *   str ;
311
312     str = iniparser_getstring(d, key, INI_INVALID_KEY);
313     if (str==INI_INVALID_KEY) return notfound ;
314     return atof(str);
315 }
316
317
318
319 /*-------------------------------------------------------------------------*/
320 /**
321   @brief    Get the string associated to a key, convert to a boolean
322   @param    d Dictionary to search
323   @param    key Key string to look for
324   @param    notfound Value to return in case of error
325   @return   integer
326
327   This function queries a dictionary for a key. A key as read from an
328   ini file is given as "section:key". If the key cannot be found,
329   the notfound value is returned.
330
331   A true boolean is found if one of the following is matched:
332
333   - A string starting with 'y'
334   - A string starting with 'Y'
335   - A string starting with 't'
336   - A string starting with 'T'
337   - A string starting with '1'
338
339   A false boolean is found if one of the following is matched:
340
341   - A string starting with 'n'
342   - A string starting with 'N'
343   - A string starting with 'f'
344   - A string starting with 'F'
345   - A string starting with '0'
346
347   The notfound value returned if no boolean is identified, does not
348   necessarily have to be 0 or 1.
349  */
350 /*--------------------------------------------------------------------------*/
351 int iniparser_getboolean(dictionary * d, const char * key, int notfound)
352 {
353     char    *   c ;
354     int         ret ;
355
356     c = iniparser_getstring(d, key, INI_INVALID_KEY);
357     if (c==INI_INVALID_KEY) return notfound ;
358     if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
359         ret = 1 ;
360     } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
361         ret = 0 ;
362     } else {
363         ret = notfound ;
364     }
365     return ret;
366 }
367
368
369 /*-------------------------------------------------------------------------*/
370 /**
371   @brief    Finds out if a given entry exists in a dictionary
372   @param    ini     Dictionary to search
373   @param    entry   Name of the entry to look for
374   @return   integer 1 if entry exists, 0 otherwise
375
376   Finds out if a given entry exists in the dictionary. Since sections
377   are stored as keys with NULL associated values, this is the only way
378   of querying for the presence of sections in a dictionary.
379  */
380 /*--------------------------------------------------------------------------*/
381
382 int iniparser_find_entry(
383     dictionary  *   ini,
384     char        *   entry
385 )
386 {
387     int found=0 ;
388     if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
389         found = 1 ;
390     }
391     return found ;
392 }
393
394
395
396 /*-------------------------------------------------------------------------*/
397 /**
398   @brief    Set an entry in a dictionary.
399   @param    ini     Dictionary to modify.
400   @param    entry   Entry to modify (entry name)
401   @param    val     New value to associate to the entry.
402   @return   int 0 if Ok, -1 otherwise.
403
404   If the given entry can be found in the dictionary, it is modified to
405   contain the provided value. If it cannot be found, -1 is returned.
406   It is Ok to set val to NULL.
407  */
408 /*--------------------------------------------------------------------------*/
409
410 int iniparser_setstr(dictionary * ini, char * entry, char * val)
411 {
412     dictionary_set(ini, strlwc(entry), val);
413     return 0 ;
414 }
415
416 /*-------------------------------------------------------------------------*/
417 /**
418   @brief    Delete an entry in a dictionary
419   @param    ini     Dictionary to modify
420   @param    entry   Entry to delete (entry name)
421   @return   void
422
423   If the given entry can be found, it is deleted from the dictionary.
424  */
425 /*--------------------------------------------------------------------------*/
426 void iniparser_unset(dictionary * ini, char * entry)
427 {
428     dictionary_unset(ini, strlwc(entry));
429 }
430
431
432 /*-------------------------------------------------------------------------*/
433 /**
434   @brief    Parse an ini file and return an allocated dictionary object
435   @param    ininame Name of the ini file to read.
436   @return   Pointer to newly allocated dictionary
437
438   This is the parser for ini files. This function is called, providing
439   the name of the file to be read. It returns a dictionary object that
440   should not be accessed directly, but through accessor functions
441   instead.
442
443   The returned dictionary must be freed using iniparser_freedict().
444  */
445 /*--------------------------------------------------------------------------*/
446
447 dictionary * iniparser_load(const char * ininame)
448 {
449     dictionary  *   d ;
450     char        lin[ASCIILINESZ+1];
451     char        sec[ASCIILINESZ+1];
452     char        key[ASCIILINESZ+1];
453     char        val[ASCIILINESZ+1];
454     char    *   where ;
455     FILE    *   ini ;
456     int         lineno ;
457
458     if ((ini=fopen(ininame, "r"))==NULL) {
459         return NULL ;
460     }
461
462     sec[0]=0;
463
464     /*
465      * Initialize a new dictionary entry
466      */
467     if (!(d = dictionary_new(0))) {
468             fclose(ini);
469             return NULL;
470     }
471     lineno = 0 ;
472     while (fgets(lin, ASCIILINESZ, ini)!=NULL) {
473         lineno++ ;
474         where = strskp(lin); /* Skip leading spaces */
475         if (*where==';' || *where=='#' || *where==0)
476             continue ; /* Comment lines */
477         else {
478             if (sscanf(where, "[%[^]]", sec)==1) {
479                 /* Valid section name */
480                 strcpy(sec, strlwc(sec));
481                 iniparser_add_entry(d, sec, NULL, NULL);
482             } else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2
483                    ||  sscanf (where, "%[^=] = '%[^\']'",   key, val) == 2
484                    ||  sscanf (where, "%[^=] = %[^;#]",     key, val) == 2) {
485                 strcpy(key, strlwc(strcrop(key)));
486                 /*
487                  * sscanf cannot handle "" or '' as empty value,
488                  * this is done here
489                  */
490                 if (!strcmp(val, "\"\"") || !strcmp(val, "''")) {
491                     val[0] = (char)0;
492                 } else {
493                     strcpy(val, strcrop(val));
494                 }
495                 iniparser_add_entry(d, sec, key, val);
496             }
497         }
498     }
499     fclose(ini);
500     return d ;
501 }
502
503
504
505 /*-------------------------------------------------------------------------*/
506 /**
507   @brief    Free all memory associated to an ini dictionary
508   @param    d Dictionary to free
509   @return   void
510
511   Free all memory associated to an ini dictionary.
512   It is mandatory to call this function before the dictionary object
513   gets out of the current context.
514  */
515 /*--------------------------------------------------------------------------*/
516
517 void iniparser_freedict(dictionary * d)
518 {
519     dictionary_del(d);
520 }
521
522 /* vim: set ts=4 et sw=4 tw=75 */