1*437bfbebSnyanmisaka
2*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
3*437bfbebSnyanmisaka /**
4*437bfbebSnyanmisaka @file iniparser.c
5*437bfbebSnyanmisaka @author N. Devillard
6*437bfbebSnyanmisaka @brief Parser for ini files.
7*437bfbebSnyanmisaka */
8*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
9*437bfbebSnyanmisaka /*---------------------------- Includes ------------------------------------*/
10*437bfbebSnyanmisaka #include <ctype.h>
11*437bfbebSnyanmisaka #include <stdarg.h>
12*437bfbebSnyanmisaka #include "iniparser.h"
13*437bfbebSnyanmisaka
14*437bfbebSnyanmisaka /*---------------------------- Defines -------------------------------------*/
15*437bfbebSnyanmisaka #define ASCIILINESZ (1024)
16*437bfbebSnyanmisaka #define INI_INVALID_KEY ((char*)-1)
17*437bfbebSnyanmisaka
18*437bfbebSnyanmisaka /*---------------------------------------------------------------------------
19*437bfbebSnyanmisaka Private to this module
20*437bfbebSnyanmisaka ---------------------------------------------------------------------------*/
21*437bfbebSnyanmisaka /**
22*437bfbebSnyanmisaka * This enum stores the status for each parsed line (internal use only).
23*437bfbebSnyanmisaka */
24*437bfbebSnyanmisaka typedef enum _line_status_ {
25*437bfbebSnyanmisaka LINE_UNPROCESSED,
26*437bfbebSnyanmisaka LINE_ERROR,
27*437bfbebSnyanmisaka LINE_EMPTY,
28*437bfbebSnyanmisaka LINE_COMMENT,
29*437bfbebSnyanmisaka LINE_SECTION,
30*437bfbebSnyanmisaka LINE_VALUE
31*437bfbebSnyanmisaka } line_status ;
32*437bfbebSnyanmisaka
33*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
34*437bfbebSnyanmisaka /**
35*437bfbebSnyanmisaka @brief Convert a string to lowercase.
36*437bfbebSnyanmisaka @param in String to convert.
37*437bfbebSnyanmisaka @param out Output buffer.
38*437bfbebSnyanmisaka @param len Size of the out buffer.
39*437bfbebSnyanmisaka @return ptr to the out buffer or NULL if an error occured.
40*437bfbebSnyanmisaka
41*437bfbebSnyanmisaka This function convert a string into lowercase.
42*437bfbebSnyanmisaka At most len - 1 elements of the input string will be converted.
43*437bfbebSnyanmisaka */
44*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
strlwc(const char * in,char * out,unsigned len)45*437bfbebSnyanmisaka static const char * strlwc(const char * in, char *out, unsigned len)
46*437bfbebSnyanmisaka {
47*437bfbebSnyanmisaka unsigned i ;
48*437bfbebSnyanmisaka
49*437bfbebSnyanmisaka if (in == NULL || out == NULL || len == 0) return NULL ;
50*437bfbebSnyanmisaka i = 0 ;
51*437bfbebSnyanmisaka while (in[i] != '\0' && i < len - 1) {
52*437bfbebSnyanmisaka out[i] = (char)tolower((int)in[i]);
53*437bfbebSnyanmisaka i++ ;
54*437bfbebSnyanmisaka }
55*437bfbebSnyanmisaka out[i] = '\0';
56*437bfbebSnyanmisaka return out ;
57*437bfbebSnyanmisaka }
58*437bfbebSnyanmisaka
59*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
60*437bfbebSnyanmisaka /**
61*437bfbebSnyanmisaka @brief Duplicate a string
62*437bfbebSnyanmisaka @param s String to duplicate
63*437bfbebSnyanmisaka @return Pointer to a newly allocated string, to be freed with free()
64*437bfbebSnyanmisaka
65*437bfbebSnyanmisaka This is a replacement for strdup(). This implementation is provided
66*437bfbebSnyanmisaka for systems that do not have it.
67*437bfbebSnyanmisaka */
68*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
xstrdup(const char * s)69*437bfbebSnyanmisaka static char * xstrdup(const char * s)
70*437bfbebSnyanmisaka {
71*437bfbebSnyanmisaka char * t ;
72*437bfbebSnyanmisaka size_t len ;
73*437bfbebSnyanmisaka if (!s)
74*437bfbebSnyanmisaka return NULL ;
75*437bfbebSnyanmisaka
76*437bfbebSnyanmisaka len = strlen(s) + 1 ;
77*437bfbebSnyanmisaka t = (char*) malloc(len) ;
78*437bfbebSnyanmisaka if (t) {
79*437bfbebSnyanmisaka memcpy(t, s, len) ;
80*437bfbebSnyanmisaka }
81*437bfbebSnyanmisaka return t ;
82*437bfbebSnyanmisaka }
83*437bfbebSnyanmisaka
84*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
85*437bfbebSnyanmisaka /**
86*437bfbebSnyanmisaka @brief Remove blanks at the beginning and the end of a string.
87*437bfbebSnyanmisaka @param str String to parse and alter.
88*437bfbebSnyanmisaka @return unsigned New size of the string.
89*437bfbebSnyanmisaka */
90*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
strstrip(char * s)91*437bfbebSnyanmisaka static unsigned strstrip(char * s)
92*437bfbebSnyanmisaka {
93*437bfbebSnyanmisaka char *last = NULL ;
94*437bfbebSnyanmisaka char *dest = s;
95*437bfbebSnyanmisaka
96*437bfbebSnyanmisaka if (s == NULL) return 0;
97*437bfbebSnyanmisaka
98*437bfbebSnyanmisaka last = s + strlen(s);
99*437bfbebSnyanmisaka while (isspace((int)*s) && *s) s++;
100*437bfbebSnyanmisaka while (last > s) {
101*437bfbebSnyanmisaka if (!isspace((int) * (last - 1)))
102*437bfbebSnyanmisaka break ;
103*437bfbebSnyanmisaka last -- ;
104*437bfbebSnyanmisaka }
105*437bfbebSnyanmisaka *last = (char)0;
106*437bfbebSnyanmisaka
107*437bfbebSnyanmisaka memmove(dest, s, last - s + 1);
108*437bfbebSnyanmisaka return last - s;
109*437bfbebSnyanmisaka }
110*437bfbebSnyanmisaka
111*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
112*437bfbebSnyanmisaka /**
113*437bfbebSnyanmisaka @brief Default error callback for iniparser: wraps `fprintf(stderr, ...)`.
114*437bfbebSnyanmisaka */
115*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
default_error_callback(const char * format,...)116*437bfbebSnyanmisaka static int default_error_callback(const char *format, ...)
117*437bfbebSnyanmisaka {
118*437bfbebSnyanmisaka int ret;
119*437bfbebSnyanmisaka va_list argptr;
120*437bfbebSnyanmisaka va_start(argptr, format);
121*437bfbebSnyanmisaka ret = vfprintf(stderr, format, argptr);
122*437bfbebSnyanmisaka va_end(argptr);
123*437bfbebSnyanmisaka return ret;
124*437bfbebSnyanmisaka }
125*437bfbebSnyanmisaka
126*437bfbebSnyanmisaka static int (*iniparser_error_callback)(const char*, ...) = default_error_callback;
127*437bfbebSnyanmisaka
128*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
129*437bfbebSnyanmisaka /**
130*437bfbebSnyanmisaka @brief Configure a function to receive the error messages.
131*437bfbebSnyanmisaka @param errback Function to call.
132*437bfbebSnyanmisaka
133*437bfbebSnyanmisaka By default, the error will be printed on stderr. If a null pointer is passed
134*437bfbebSnyanmisaka as errback the error callback will be switched back to default.
135*437bfbebSnyanmisaka */
136*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_set_error_callback(int (* errback)(const char *,...))137*437bfbebSnyanmisaka void iniparser_set_error_callback(int (*errback)(const char *, ...))
138*437bfbebSnyanmisaka {
139*437bfbebSnyanmisaka if (errback) {
140*437bfbebSnyanmisaka iniparser_error_callback = errback;
141*437bfbebSnyanmisaka } else {
142*437bfbebSnyanmisaka iniparser_error_callback = default_error_callback;
143*437bfbebSnyanmisaka }
144*437bfbebSnyanmisaka }
145*437bfbebSnyanmisaka
146*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
147*437bfbebSnyanmisaka /**
148*437bfbebSnyanmisaka @brief Get number of sections in a dictionary
149*437bfbebSnyanmisaka @param d Dictionary to examine
150*437bfbebSnyanmisaka @return int Number of sections found in dictionary
151*437bfbebSnyanmisaka
152*437bfbebSnyanmisaka This function returns the number of sections found in a dictionary.
153*437bfbebSnyanmisaka The test to recognize sections is done on the string stored in the
154*437bfbebSnyanmisaka dictionary: a section name is given as "section" whereas a key is
155*437bfbebSnyanmisaka stored as "section:key", thus the test looks for entries that do not
156*437bfbebSnyanmisaka contain a colon.
157*437bfbebSnyanmisaka
158*437bfbebSnyanmisaka This clearly fails in the case a section name contains a colon, but
159*437bfbebSnyanmisaka this should simply be avoided.
160*437bfbebSnyanmisaka
161*437bfbebSnyanmisaka This function returns -1 in case of error.
162*437bfbebSnyanmisaka */
163*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getnsec(const dictionary * d)164*437bfbebSnyanmisaka int iniparser_getnsec(const dictionary * d)
165*437bfbebSnyanmisaka {
166*437bfbebSnyanmisaka int i ;
167*437bfbebSnyanmisaka int nsec ;
168*437bfbebSnyanmisaka
169*437bfbebSnyanmisaka if (d == NULL) return -1 ;
170*437bfbebSnyanmisaka nsec = 0 ;
171*437bfbebSnyanmisaka for (i = 0 ; i < d->size ; i++) {
172*437bfbebSnyanmisaka if (d->key[i] == NULL)
173*437bfbebSnyanmisaka continue ;
174*437bfbebSnyanmisaka if (strchr(d->key[i], ':') == NULL) {
175*437bfbebSnyanmisaka nsec ++ ;
176*437bfbebSnyanmisaka }
177*437bfbebSnyanmisaka }
178*437bfbebSnyanmisaka return nsec ;
179*437bfbebSnyanmisaka }
180*437bfbebSnyanmisaka
181*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
182*437bfbebSnyanmisaka /**
183*437bfbebSnyanmisaka @brief Get name for section n in a dictionary.
184*437bfbebSnyanmisaka @param d Dictionary to examine
185*437bfbebSnyanmisaka @param n Section number (from 0 to nsec-1).
186*437bfbebSnyanmisaka @return Pointer to char string
187*437bfbebSnyanmisaka
188*437bfbebSnyanmisaka This function locates the n-th section in a dictionary and returns
189*437bfbebSnyanmisaka its name as a pointer to a string statically allocated inside the
190*437bfbebSnyanmisaka dictionary. Do not free or modify the returned string!
191*437bfbebSnyanmisaka
192*437bfbebSnyanmisaka This function returns NULL in case of error.
193*437bfbebSnyanmisaka */
194*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getsecname(const dictionary * d,int n)195*437bfbebSnyanmisaka const char * iniparser_getsecname(const dictionary * d, int n)
196*437bfbebSnyanmisaka {
197*437bfbebSnyanmisaka int i ;
198*437bfbebSnyanmisaka int foundsec ;
199*437bfbebSnyanmisaka
200*437bfbebSnyanmisaka if (d == NULL || n < 0) return NULL ;
201*437bfbebSnyanmisaka foundsec = 0 ;
202*437bfbebSnyanmisaka for (i = 0 ; i < d->size ; i++) {
203*437bfbebSnyanmisaka if (d->key[i] == NULL)
204*437bfbebSnyanmisaka continue ;
205*437bfbebSnyanmisaka if (strchr(d->key[i], ':') == NULL) {
206*437bfbebSnyanmisaka foundsec++ ;
207*437bfbebSnyanmisaka if (foundsec > n)
208*437bfbebSnyanmisaka break ;
209*437bfbebSnyanmisaka }
210*437bfbebSnyanmisaka }
211*437bfbebSnyanmisaka if (foundsec <= n) {
212*437bfbebSnyanmisaka return NULL ;
213*437bfbebSnyanmisaka }
214*437bfbebSnyanmisaka return d->key[i] ;
215*437bfbebSnyanmisaka }
216*437bfbebSnyanmisaka
217*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
218*437bfbebSnyanmisaka /**
219*437bfbebSnyanmisaka @brief Dump a dictionary to an opened file pointer.
220*437bfbebSnyanmisaka @param d Dictionary to dump.
221*437bfbebSnyanmisaka @param f Opened file pointer to dump to.
222*437bfbebSnyanmisaka @return void
223*437bfbebSnyanmisaka
224*437bfbebSnyanmisaka This function prints out the contents of a dictionary, one element by
225*437bfbebSnyanmisaka line, onto the provided file pointer. It is OK to specify @c stderr
226*437bfbebSnyanmisaka or @c stdout as output files. This function is meant for debugging
227*437bfbebSnyanmisaka purposes mostly.
228*437bfbebSnyanmisaka */
229*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_dump(const dictionary * d,FILE * f)230*437bfbebSnyanmisaka void iniparser_dump(const dictionary * d, FILE * f)
231*437bfbebSnyanmisaka {
232*437bfbebSnyanmisaka int i ;
233*437bfbebSnyanmisaka
234*437bfbebSnyanmisaka if (d == NULL || f == NULL) return ;
235*437bfbebSnyanmisaka for (i = 0 ; i < d->size ; i++) {
236*437bfbebSnyanmisaka if (d->key[i] == NULL)
237*437bfbebSnyanmisaka continue ;
238*437bfbebSnyanmisaka if (d->val[i] != NULL) {
239*437bfbebSnyanmisaka fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
240*437bfbebSnyanmisaka } else {
241*437bfbebSnyanmisaka fprintf(f, "[%s]=UNDEF\n", d->key[i]);
242*437bfbebSnyanmisaka }
243*437bfbebSnyanmisaka }
244*437bfbebSnyanmisaka return ;
245*437bfbebSnyanmisaka }
246*437bfbebSnyanmisaka
247*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
248*437bfbebSnyanmisaka /**
249*437bfbebSnyanmisaka @brief Save a dictionary to a loadable ini file
250*437bfbebSnyanmisaka @param d Dictionary to dump
251*437bfbebSnyanmisaka @param f Opened file pointer to dump to
252*437bfbebSnyanmisaka @return void
253*437bfbebSnyanmisaka
254*437bfbebSnyanmisaka This function dumps a given dictionary into a loadable ini file.
255*437bfbebSnyanmisaka It is Ok to specify @c stderr or @c stdout as output files.
256*437bfbebSnyanmisaka */
257*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_dump_ini(const dictionary * d,FILE * f)258*437bfbebSnyanmisaka void iniparser_dump_ini(const dictionary * d, FILE * f)
259*437bfbebSnyanmisaka {
260*437bfbebSnyanmisaka int i ;
261*437bfbebSnyanmisaka int nsec ;
262*437bfbebSnyanmisaka const char * secname ;
263*437bfbebSnyanmisaka
264*437bfbebSnyanmisaka if (d == NULL || f == NULL) return ;
265*437bfbebSnyanmisaka
266*437bfbebSnyanmisaka nsec = iniparser_getnsec(d);
267*437bfbebSnyanmisaka if (nsec < 1) {
268*437bfbebSnyanmisaka /* No section in file: dump all keys as they are */
269*437bfbebSnyanmisaka for (i = 0 ; i < d->size ; i++) {
270*437bfbebSnyanmisaka if (d->key[i] == NULL)
271*437bfbebSnyanmisaka continue ;
272*437bfbebSnyanmisaka fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
273*437bfbebSnyanmisaka }
274*437bfbebSnyanmisaka return ;
275*437bfbebSnyanmisaka }
276*437bfbebSnyanmisaka for (i = 0 ; i < nsec ; i++) {
277*437bfbebSnyanmisaka secname = iniparser_getsecname(d, i) ;
278*437bfbebSnyanmisaka iniparser_dumpsection_ini(d, secname, f);
279*437bfbebSnyanmisaka }
280*437bfbebSnyanmisaka fprintf(f, "\n");
281*437bfbebSnyanmisaka return ;
282*437bfbebSnyanmisaka }
283*437bfbebSnyanmisaka
284*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
285*437bfbebSnyanmisaka /**
286*437bfbebSnyanmisaka @brief Save a dictionary section to a loadable ini file
287*437bfbebSnyanmisaka @param d Dictionary to dump
288*437bfbebSnyanmisaka @param s Section name of dictionary to dump
289*437bfbebSnyanmisaka @param f Opened file pointer to dump to
290*437bfbebSnyanmisaka @return void
291*437bfbebSnyanmisaka
292*437bfbebSnyanmisaka This function dumps a given section of a given dictionary into a loadable ini
293*437bfbebSnyanmisaka file. It is Ok to specify @c stderr or @c stdout as output files.
294*437bfbebSnyanmisaka */
295*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_dumpsection_ini(const dictionary * d,const char * s,FILE * f)296*437bfbebSnyanmisaka void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
297*437bfbebSnyanmisaka {
298*437bfbebSnyanmisaka int j ;
299*437bfbebSnyanmisaka char keym[ASCIILINESZ + 1];
300*437bfbebSnyanmisaka int seclen ;
301*437bfbebSnyanmisaka
302*437bfbebSnyanmisaka if (d == NULL || f == NULL) return ;
303*437bfbebSnyanmisaka if (! iniparser_find_entry(d, s)) return ;
304*437bfbebSnyanmisaka
305*437bfbebSnyanmisaka seclen = (int)strlen(s);
306*437bfbebSnyanmisaka fprintf(f, "\n[%s]\n", s);
307*437bfbebSnyanmisaka sprintf(keym, "%s:", s);
308*437bfbebSnyanmisaka for (j = 0 ; j < d->size ; j++) {
309*437bfbebSnyanmisaka if (d->key[j] == NULL)
310*437bfbebSnyanmisaka continue ;
311*437bfbebSnyanmisaka if (!strncmp(d->key[j], keym, seclen + 1)) {
312*437bfbebSnyanmisaka fprintf(f,
313*437bfbebSnyanmisaka "%-30s = %s\n",
314*437bfbebSnyanmisaka d->key[j] + seclen + 1,
315*437bfbebSnyanmisaka d->val[j] ? d->val[j] : "");
316*437bfbebSnyanmisaka }
317*437bfbebSnyanmisaka }
318*437bfbebSnyanmisaka fprintf(f, "\n");
319*437bfbebSnyanmisaka return ;
320*437bfbebSnyanmisaka }
321*437bfbebSnyanmisaka
322*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
323*437bfbebSnyanmisaka /**
324*437bfbebSnyanmisaka @brief Get the number of keys in a section of a dictionary.
325*437bfbebSnyanmisaka @param d Dictionary to examine
326*437bfbebSnyanmisaka @param s Section name of dictionary to examine
327*437bfbebSnyanmisaka @return Number of keys in section
328*437bfbebSnyanmisaka */
329*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getsecnkeys(const dictionary * d,const char * s)330*437bfbebSnyanmisaka int iniparser_getsecnkeys(const dictionary * d, const char * s)
331*437bfbebSnyanmisaka {
332*437bfbebSnyanmisaka int seclen, nkeys ;
333*437bfbebSnyanmisaka char keym[ASCIILINESZ + 1];
334*437bfbebSnyanmisaka int j ;
335*437bfbebSnyanmisaka
336*437bfbebSnyanmisaka nkeys = 0;
337*437bfbebSnyanmisaka
338*437bfbebSnyanmisaka if (d == NULL) return nkeys;
339*437bfbebSnyanmisaka if (! iniparser_find_entry(d, s)) return nkeys;
340*437bfbebSnyanmisaka
341*437bfbebSnyanmisaka seclen = (int)strlen(s);
342*437bfbebSnyanmisaka strlwc(s, keym, sizeof(keym));
343*437bfbebSnyanmisaka keym[seclen] = ':';
344*437bfbebSnyanmisaka
345*437bfbebSnyanmisaka for (j = 0 ; j < d->size ; j++) {
346*437bfbebSnyanmisaka if (d->key[j] == NULL)
347*437bfbebSnyanmisaka continue ;
348*437bfbebSnyanmisaka if (!strncmp(d->key[j], keym, seclen + 1))
349*437bfbebSnyanmisaka nkeys++;
350*437bfbebSnyanmisaka }
351*437bfbebSnyanmisaka
352*437bfbebSnyanmisaka return nkeys;
353*437bfbebSnyanmisaka
354*437bfbebSnyanmisaka }
355*437bfbebSnyanmisaka
356*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
357*437bfbebSnyanmisaka /**
358*437bfbebSnyanmisaka @brief Get the number of keys in a section of a dictionary.
359*437bfbebSnyanmisaka @param d Dictionary to examine
360*437bfbebSnyanmisaka @param s Section name of dictionary to examine
361*437bfbebSnyanmisaka @param keys Already allocated array to store the keys in
362*437bfbebSnyanmisaka @return The pointer passed as `keys` argument or NULL in case of error
363*437bfbebSnyanmisaka
364*437bfbebSnyanmisaka This function queries a dictionary and finds all keys in a given section.
365*437bfbebSnyanmisaka The keys argument should be an array of pointers which size has been
366*437bfbebSnyanmisaka determined by calling `iniparser_getsecnkeys` function prior to this one.
367*437bfbebSnyanmisaka
368*437bfbebSnyanmisaka Each pointer in the returned char pointer-to-pointer is pointing to
369*437bfbebSnyanmisaka a string allocated in the dictionary; do not free or modify them.
370*437bfbebSnyanmisaka */
371*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getseckeys(const dictionary * d,const char * s,const char ** keys)372*437bfbebSnyanmisaka const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
373*437bfbebSnyanmisaka {
374*437bfbebSnyanmisaka int i, j, seclen ;
375*437bfbebSnyanmisaka char keym[ASCIILINESZ + 1];
376*437bfbebSnyanmisaka
377*437bfbebSnyanmisaka if (d == NULL || keys == NULL) return NULL;
378*437bfbebSnyanmisaka if (! iniparser_find_entry(d, s)) return NULL;
379*437bfbebSnyanmisaka
380*437bfbebSnyanmisaka seclen = (int)strlen(s);
381*437bfbebSnyanmisaka strlwc(s, keym, sizeof(keym));
382*437bfbebSnyanmisaka keym[seclen] = ':';
383*437bfbebSnyanmisaka
384*437bfbebSnyanmisaka i = 0;
385*437bfbebSnyanmisaka
386*437bfbebSnyanmisaka for (j = 0 ; j < d->size ; j++) {
387*437bfbebSnyanmisaka if (d->key[j] == NULL)
388*437bfbebSnyanmisaka continue ;
389*437bfbebSnyanmisaka if (!strncmp(d->key[j], keym, seclen + 1)) {
390*437bfbebSnyanmisaka keys[i] = d->key[j];
391*437bfbebSnyanmisaka i++;
392*437bfbebSnyanmisaka }
393*437bfbebSnyanmisaka }
394*437bfbebSnyanmisaka
395*437bfbebSnyanmisaka return keys;
396*437bfbebSnyanmisaka }
397*437bfbebSnyanmisaka
398*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
399*437bfbebSnyanmisaka /**
400*437bfbebSnyanmisaka @brief Get the string associated to a key
401*437bfbebSnyanmisaka @param d Dictionary to search
402*437bfbebSnyanmisaka @param key Key string to look for
403*437bfbebSnyanmisaka @param def Default value to return if key not found.
404*437bfbebSnyanmisaka @return pointer to statically allocated character string
405*437bfbebSnyanmisaka
406*437bfbebSnyanmisaka This function queries a dictionary for a key. A key as read from an
407*437bfbebSnyanmisaka ini file is given as "section:key". If the key cannot be found,
408*437bfbebSnyanmisaka the pointer passed as 'def' is returned.
409*437bfbebSnyanmisaka The returned char pointer is pointing to a string allocated in
410*437bfbebSnyanmisaka the dictionary, do not free or modify it.
411*437bfbebSnyanmisaka */
412*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getstring(const dictionary * d,const char * key,const char * def)413*437bfbebSnyanmisaka const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
414*437bfbebSnyanmisaka {
415*437bfbebSnyanmisaka const char * lc_key ;
416*437bfbebSnyanmisaka const char * sval ;
417*437bfbebSnyanmisaka char tmp_str[ASCIILINESZ + 1];
418*437bfbebSnyanmisaka
419*437bfbebSnyanmisaka if (d == NULL || key == NULL)
420*437bfbebSnyanmisaka return def ;
421*437bfbebSnyanmisaka
422*437bfbebSnyanmisaka lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
423*437bfbebSnyanmisaka sval = dictionary_get(d, lc_key, def);
424*437bfbebSnyanmisaka return sval ;
425*437bfbebSnyanmisaka }
426*437bfbebSnyanmisaka
427*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
428*437bfbebSnyanmisaka /**
429*437bfbebSnyanmisaka @brief Get the string associated to a key, convert to an long int
430*437bfbebSnyanmisaka @param d Dictionary to search
431*437bfbebSnyanmisaka @param key Key string to look for
432*437bfbebSnyanmisaka @param notfound Value to return in case of error
433*437bfbebSnyanmisaka @return long integer
434*437bfbebSnyanmisaka
435*437bfbebSnyanmisaka This function queries a dictionary for a key. A key as read from an
436*437bfbebSnyanmisaka ini file is given as "section:key". If the key cannot be found,
437*437bfbebSnyanmisaka the notfound value is returned.
438*437bfbebSnyanmisaka
439*437bfbebSnyanmisaka Supported values for integers include the usual C notation
440*437bfbebSnyanmisaka so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
441*437bfbebSnyanmisaka are supported. Examples:
442*437bfbebSnyanmisaka
443*437bfbebSnyanmisaka "42" -> 42
444*437bfbebSnyanmisaka "042" -> 34 (octal -> decimal)
445*437bfbebSnyanmisaka "0x42" -> 66 (hexa -> decimal)
446*437bfbebSnyanmisaka
447*437bfbebSnyanmisaka Warning: the conversion may overflow in various ways. Conversion is
448*437bfbebSnyanmisaka totally outsourced to strtol(), see the associated man page for overflow
449*437bfbebSnyanmisaka handling.
450*437bfbebSnyanmisaka
451*437bfbebSnyanmisaka Credits: Thanks to A. Becker for suggesting strtol()
452*437bfbebSnyanmisaka */
453*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getlongint(const dictionary * d,const char * key,long int notfound)454*437bfbebSnyanmisaka long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
455*437bfbebSnyanmisaka {
456*437bfbebSnyanmisaka const char * str ;
457*437bfbebSnyanmisaka
458*437bfbebSnyanmisaka str = iniparser_getstring(d, key, INI_INVALID_KEY);
459*437bfbebSnyanmisaka if (str == INI_INVALID_KEY) return notfound ;
460*437bfbebSnyanmisaka return strtol(str, NULL, 0);
461*437bfbebSnyanmisaka }
462*437bfbebSnyanmisaka
463*437bfbebSnyanmisaka
464*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
465*437bfbebSnyanmisaka /**
466*437bfbebSnyanmisaka @brief Get the string associated to a key, convert to an int
467*437bfbebSnyanmisaka @param d Dictionary to search
468*437bfbebSnyanmisaka @param key Key string to look for
469*437bfbebSnyanmisaka @param notfound Value to return in case of error
470*437bfbebSnyanmisaka @return integer
471*437bfbebSnyanmisaka
472*437bfbebSnyanmisaka This function queries a dictionary for a key. A key as read from an
473*437bfbebSnyanmisaka ini file is given as "section:key". If the key cannot be found,
474*437bfbebSnyanmisaka the notfound value is returned.
475*437bfbebSnyanmisaka
476*437bfbebSnyanmisaka Supported values for integers include the usual C notation
477*437bfbebSnyanmisaka so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
478*437bfbebSnyanmisaka are supported. Examples:
479*437bfbebSnyanmisaka
480*437bfbebSnyanmisaka "42" -> 42
481*437bfbebSnyanmisaka "042" -> 34 (octal -> decimal)
482*437bfbebSnyanmisaka "0x42" -> 66 (hexa -> decimal)
483*437bfbebSnyanmisaka
484*437bfbebSnyanmisaka Warning: the conversion may overflow in various ways. Conversion is
485*437bfbebSnyanmisaka totally outsourced to strtol(), see the associated man page for overflow
486*437bfbebSnyanmisaka handling.
487*437bfbebSnyanmisaka
488*437bfbebSnyanmisaka Credits: Thanks to A. Becker for suggesting strtol()
489*437bfbebSnyanmisaka */
490*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getint(const dictionary * d,const char * key,int notfound)491*437bfbebSnyanmisaka int iniparser_getint(const dictionary * d, const char * key, int notfound)
492*437bfbebSnyanmisaka {
493*437bfbebSnyanmisaka return (int)iniparser_getlongint(d, key, notfound);
494*437bfbebSnyanmisaka }
495*437bfbebSnyanmisaka
496*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
497*437bfbebSnyanmisaka /**
498*437bfbebSnyanmisaka @brief Get the string associated to a key, convert to a double
499*437bfbebSnyanmisaka @param d Dictionary to search
500*437bfbebSnyanmisaka @param key Key string to look for
501*437bfbebSnyanmisaka @param notfound Value to return in case of error
502*437bfbebSnyanmisaka @return double
503*437bfbebSnyanmisaka
504*437bfbebSnyanmisaka This function queries a dictionary for a key. A key as read from an
505*437bfbebSnyanmisaka ini file is given as "section:key". If the key cannot be found,
506*437bfbebSnyanmisaka the notfound value is returned.
507*437bfbebSnyanmisaka */
508*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getdouble(const dictionary * d,const char * key,double notfound)509*437bfbebSnyanmisaka double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
510*437bfbebSnyanmisaka {
511*437bfbebSnyanmisaka const char * str ;
512*437bfbebSnyanmisaka
513*437bfbebSnyanmisaka str = iniparser_getstring(d, key, INI_INVALID_KEY);
514*437bfbebSnyanmisaka if (str == INI_INVALID_KEY) return notfound ;
515*437bfbebSnyanmisaka return atof(str);
516*437bfbebSnyanmisaka }
517*437bfbebSnyanmisaka
518*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
519*437bfbebSnyanmisaka /**
520*437bfbebSnyanmisaka @brief Get the string associated to a key, convert to a boolean
521*437bfbebSnyanmisaka @param d Dictionary to search
522*437bfbebSnyanmisaka @param key Key string to look for
523*437bfbebSnyanmisaka @param notfound Value to return in case of error
524*437bfbebSnyanmisaka @return integer
525*437bfbebSnyanmisaka
526*437bfbebSnyanmisaka This function queries a dictionary for a key. A key as read from an
527*437bfbebSnyanmisaka ini file is given as "section:key". If the key cannot be found,
528*437bfbebSnyanmisaka the notfound value is returned.
529*437bfbebSnyanmisaka
530*437bfbebSnyanmisaka A true boolean is found if one of the following is matched:
531*437bfbebSnyanmisaka
532*437bfbebSnyanmisaka - A string starting with 'y'
533*437bfbebSnyanmisaka - A string starting with 'Y'
534*437bfbebSnyanmisaka - A string starting with 't'
535*437bfbebSnyanmisaka - A string starting with 'T'
536*437bfbebSnyanmisaka - A string starting with '1'
537*437bfbebSnyanmisaka
538*437bfbebSnyanmisaka A false boolean is found if one of the following is matched:
539*437bfbebSnyanmisaka
540*437bfbebSnyanmisaka - A string starting with 'n'
541*437bfbebSnyanmisaka - A string starting with 'N'
542*437bfbebSnyanmisaka - A string starting with 'f'
543*437bfbebSnyanmisaka - A string starting with 'F'
544*437bfbebSnyanmisaka - A string starting with '0'
545*437bfbebSnyanmisaka
546*437bfbebSnyanmisaka The notfound value returned if no boolean is identified, does not
547*437bfbebSnyanmisaka necessarily have to be 0 or 1.
548*437bfbebSnyanmisaka */
549*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_getboolean(const dictionary * d,const char * key,int notfound)550*437bfbebSnyanmisaka int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
551*437bfbebSnyanmisaka {
552*437bfbebSnyanmisaka int ret ;
553*437bfbebSnyanmisaka const char * c ;
554*437bfbebSnyanmisaka
555*437bfbebSnyanmisaka c = iniparser_getstring(d, key, INI_INVALID_KEY);
556*437bfbebSnyanmisaka if (c == INI_INVALID_KEY) return notfound ;
557*437bfbebSnyanmisaka if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T') {
558*437bfbebSnyanmisaka ret = 1 ;
559*437bfbebSnyanmisaka } else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f' || c[0] == 'F') {
560*437bfbebSnyanmisaka ret = 0 ;
561*437bfbebSnyanmisaka } else {
562*437bfbebSnyanmisaka ret = notfound ;
563*437bfbebSnyanmisaka }
564*437bfbebSnyanmisaka return ret;
565*437bfbebSnyanmisaka }
566*437bfbebSnyanmisaka
567*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
568*437bfbebSnyanmisaka /**
569*437bfbebSnyanmisaka @brief Finds out if a given entry exists in a dictionary
570*437bfbebSnyanmisaka @param ini Dictionary to search
571*437bfbebSnyanmisaka @param entry Name of the entry to look for
572*437bfbebSnyanmisaka @return integer 1 if entry exists, 0 otherwise
573*437bfbebSnyanmisaka
574*437bfbebSnyanmisaka Finds out if a given entry exists in the dictionary. Since sections
575*437bfbebSnyanmisaka are stored as keys with NULL associated values, this is the only way
576*437bfbebSnyanmisaka of querying for the presence of sections in a dictionary.
577*437bfbebSnyanmisaka */
578*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_find_entry(const dictionary * ini,const char * entry)579*437bfbebSnyanmisaka int iniparser_find_entry(const dictionary * ini, const char * entry)
580*437bfbebSnyanmisaka {
581*437bfbebSnyanmisaka int found = 0 ;
582*437bfbebSnyanmisaka if (iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) {
583*437bfbebSnyanmisaka found = 1 ;
584*437bfbebSnyanmisaka }
585*437bfbebSnyanmisaka return found ;
586*437bfbebSnyanmisaka }
587*437bfbebSnyanmisaka
588*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
589*437bfbebSnyanmisaka /**
590*437bfbebSnyanmisaka @brief Set an entry in a dictionary.
591*437bfbebSnyanmisaka @param ini Dictionary to modify.
592*437bfbebSnyanmisaka @param entry Entry to modify (entry name)
593*437bfbebSnyanmisaka @param val New value to associate to the entry.
594*437bfbebSnyanmisaka @return int 0 if Ok, -1 otherwise.
595*437bfbebSnyanmisaka
596*437bfbebSnyanmisaka If the given entry can be found in the dictionary, it is modified to
597*437bfbebSnyanmisaka contain the provided value. If it cannot be found, the entry is created.
598*437bfbebSnyanmisaka It is Ok to set val to NULL.
599*437bfbebSnyanmisaka */
600*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_set(dictionary * ini,const char * entry,const char * val)601*437bfbebSnyanmisaka int iniparser_set(dictionary * ini, const char * entry, const char * val)
602*437bfbebSnyanmisaka {
603*437bfbebSnyanmisaka char tmp_str[ASCIILINESZ + 1];
604*437bfbebSnyanmisaka return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ;
605*437bfbebSnyanmisaka }
606*437bfbebSnyanmisaka
607*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
608*437bfbebSnyanmisaka /**
609*437bfbebSnyanmisaka @brief Delete an entry in a dictionary
610*437bfbebSnyanmisaka @param ini Dictionary to modify
611*437bfbebSnyanmisaka @param entry Entry to delete (entry name)
612*437bfbebSnyanmisaka @return void
613*437bfbebSnyanmisaka
614*437bfbebSnyanmisaka If the given entry can be found, it is deleted from the dictionary.
615*437bfbebSnyanmisaka */
616*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_unset(dictionary * ini,const char * entry)617*437bfbebSnyanmisaka void iniparser_unset(dictionary * ini, const char * entry)
618*437bfbebSnyanmisaka {
619*437bfbebSnyanmisaka char tmp_str[ASCIILINESZ + 1];
620*437bfbebSnyanmisaka dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
621*437bfbebSnyanmisaka }
622*437bfbebSnyanmisaka
623*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
624*437bfbebSnyanmisaka /**
625*437bfbebSnyanmisaka @brief Load a single line from an INI file
626*437bfbebSnyanmisaka @param input_line Input line, may be concatenated multi-line input
627*437bfbebSnyanmisaka @param section Output space to store section
628*437bfbebSnyanmisaka @param key Output space to store key
629*437bfbebSnyanmisaka @param value Output space to store value
630*437bfbebSnyanmisaka @return line_status value
631*437bfbebSnyanmisaka */
632*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_line(const char * input_line,char * section,char * key,char * value)633*437bfbebSnyanmisaka static line_status iniparser_line(
634*437bfbebSnyanmisaka const char * input_line,
635*437bfbebSnyanmisaka char * section,
636*437bfbebSnyanmisaka char * key,
637*437bfbebSnyanmisaka char * value)
638*437bfbebSnyanmisaka {
639*437bfbebSnyanmisaka line_status sta ;
640*437bfbebSnyanmisaka char * line = NULL;
641*437bfbebSnyanmisaka size_t len ;
642*437bfbebSnyanmisaka
643*437bfbebSnyanmisaka line = xstrdup(input_line);
644*437bfbebSnyanmisaka len = strstrip(line);
645*437bfbebSnyanmisaka
646*437bfbebSnyanmisaka sta = LINE_UNPROCESSED ;
647*437bfbebSnyanmisaka if (len < 1) {
648*437bfbebSnyanmisaka /* Empty line */
649*437bfbebSnyanmisaka sta = LINE_EMPTY ;
650*437bfbebSnyanmisaka } else if (line[0] == '#' || line[0] == ';') {
651*437bfbebSnyanmisaka /* Comment line */
652*437bfbebSnyanmisaka sta = LINE_COMMENT ;
653*437bfbebSnyanmisaka } else if (line[0] == '[' && line[len - 1] == ']') {
654*437bfbebSnyanmisaka /* Section name */
655*437bfbebSnyanmisaka sscanf(line, "[%[^]]", section);
656*437bfbebSnyanmisaka strstrip(section);
657*437bfbebSnyanmisaka strlwc(section, section, len);
658*437bfbebSnyanmisaka sta = LINE_SECTION ;
659*437bfbebSnyanmisaka } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
660*437bfbebSnyanmisaka || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2) {
661*437bfbebSnyanmisaka /* Usual key=value with quotes, with or without comments */
662*437bfbebSnyanmisaka strstrip(key);
663*437bfbebSnyanmisaka strlwc(key, key, len);
664*437bfbebSnyanmisaka /* Don't strip spaces from values surrounded with quotes */
665*437bfbebSnyanmisaka sta = LINE_VALUE ;
666*437bfbebSnyanmisaka } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
667*437bfbebSnyanmisaka /* Usual key=value without quotes, with or without comments */
668*437bfbebSnyanmisaka strstrip(key);
669*437bfbebSnyanmisaka strlwc(key, key, len);
670*437bfbebSnyanmisaka strstrip(value);
671*437bfbebSnyanmisaka /*
672*437bfbebSnyanmisaka * sscanf cannot handle '' or "" as empty values
673*437bfbebSnyanmisaka * this is done here
674*437bfbebSnyanmisaka */
675*437bfbebSnyanmisaka if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
676*437bfbebSnyanmisaka value[0] = 0 ;
677*437bfbebSnyanmisaka }
678*437bfbebSnyanmisaka sta = LINE_VALUE ;
679*437bfbebSnyanmisaka } else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2
680*437bfbebSnyanmisaka || sscanf(line, "%[^=] %[=]", key, value) == 2) {
681*437bfbebSnyanmisaka /*
682*437bfbebSnyanmisaka * Special cases:
683*437bfbebSnyanmisaka * key=
684*437bfbebSnyanmisaka * key=;
685*437bfbebSnyanmisaka * key=#
686*437bfbebSnyanmisaka */
687*437bfbebSnyanmisaka strstrip(key);
688*437bfbebSnyanmisaka strlwc(key, key, len);
689*437bfbebSnyanmisaka value[0] = 0 ;
690*437bfbebSnyanmisaka sta = LINE_VALUE ;
691*437bfbebSnyanmisaka } else {
692*437bfbebSnyanmisaka /* Generate syntax error */
693*437bfbebSnyanmisaka sta = LINE_ERROR ;
694*437bfbebSnyanmisaka }
695*437bfbebSnyanmisaka
696*437bfbebSnyanmisaka free(line);
697*437bfbebSnyanmisaka return sta ;
698*437bfbebSnyanmisaka }
699*437bfbebSnyanmisaka
700*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
701*437bfbebSnyanmisaka /**
702*437bfbebSnyanmisaka @brief Parse an ini file and return an allocated dictionary object
703*437bfbebSnyanmisaka @param ininame Name of the ini file to read.
704*437bfbebSnyanmisaka @return Pointer to newly allocated dictionary
705*437bfbebSnyanmisaka
706*437bfbebSnyanmisaka This is the parser for ini files. This function is called, providing
707*437bfbebSnyanmisaka the name of the file to be read. It returns a dictionary object that
708*437bfbebSnyanmisaka should not be accessed directly, but through accessor functions
709*437bfbebSnyanmisaka instead.
710*437bfbebSnyanmisaka
711*437bfbebSnyanmisaka The returned dictionary must be freed using iniparser_freedict().
712*437bfbebSnyanmisaka */
713*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_load(const char * ininame)714*437bfbebSnyanmisaka dictionary * iniparser_load(const char * ininame)
715*437bfbebSnyanmisaka {
716*437bfbebSnyanmisaka FILE * in ;
717*437bfbebSnyanmisaka
718*437bfbebSnyanmisaka char line [ASCIILINESZ + 1] ;
719*437bfbebSnyanmisaka char section [ASCIILINESZ + 1] ;
720*437bfbebSnyanmisaka char key [ASCIILINESZ + 1] ;
721*437bfbebSnyanmisaka char tmp [(ASCIILINESZ * 2) + 2] ;
722*437bfbebSnyanmisaka char val [ASCIILINESZ + 1] ;
723*437bfbebSnyanmisaka
724*437bfbebSnyanmisaka int last = 0 ;
725*437bfbebSnyanmisaka int len ;
726*437bfbebSnyanmisaka int lineno = 0 ;
727*437bfbebSnyanmisaka int errs = 0;
728*437bfbebSnyanmisaka int mem_err = 0;
729*437bfbebSnyanmisaka
730*437bfbebSnyanmisaka dictionary * dict ;
731*437bfbebSnyanmisaka
732*437bfbebSnyanmisaka if ((in = fopen(ininame, "r")) == NULL) {
733*437bfbebSnyanmisaka iniparser_error_callback("iniparser: cannot open %s\n", ininame);
734*437bfbebSnyanmisaka return NULL ;
735*437bfbebSnyanmisaka }
736*437bfbebSnyanmisaka
737*437bfbebSnyanmisaka dict = dictionary_new(0) ;
738*437bfbebSnyanmisaka if (!dict) {
739*437bfbebSnyanmisaka fclose(in);
740*437bfbebSnyanmisaka return NULL ;
741*437bfbebSnyanmisaka }
742*437bfbebSnyanmisaka
743*437bfbebSnyanmisaka memset(line, 0, ASCIILINESZ);
744*437bfbebSnyanmisaka memset(section, 0, ASCIILINESZ);
745*437bfbebSnyanmisaka memset(key, 0, ASCIILINESZ);
746*437bfbebSnyanmisaka memset(val, 0, ASCIILINESZ);
747*437bfbebSnyanmisaka last = 0 ;
748*437bfbebSnyanmisaka
749*437bfbebSnyanmisaka while (fgets(line + last, ASCIILINESZ - last, in) != NULL) {
750*437bfbebSnyanmisaka lineno++ ;
751*437bfbebSnyanmisaka len = (int)strlen(line) - 1;
752*437bfbebSnyanmisaka if (len <= 0)
753*437bfbebSnyanmisaka continue;
754*437bfbebSnyanmisaka /* Safety check against buffer overflows */
755*437bfbebSnyanmisaka if (line[len] != '\n' && !feof(in)) {
756*437bfbebSnyanmisaka iniparser_error_callback(
757*437bfbebSnyanmisaka "iniparser: input line too long in %s (%d)\n",
758*437bfbebSnyanmisaka ininame,
759*437bfbebSnyanmisaka lineno);
760*437bfbebSnyanmisaka dictionary_del(dict);
761*437bfbebSnyanmisaka fclose(in);
762*437bfbebSnyanmisaka return NULL ;
763*437bfbebSnyanmisaka }
764*437bfbebSnyanmisaka /* Get rid of \n and spaces at end of line */
765*437bfbebSnyanmisaka while ((len >= 0) &&
766*437bfbebSnyanmisaka ((line[len] == '\n') || (isspace(line[len])))) {
767*437bfbebSnyanmisaka line[len] = 0 ;
768*437bfbebSnyanmisaka len-- ;
769*437bfbebSnyanmisaka }
770*437bfbebSnyanmisaka if (len < 0) { /* Line was entirely \n and/or spaces */
771*437bfbebSnyanmisaka len = 0;
772*437bfbebSnyanmisaka }
773*437bfbebSnyanmisaka /* Detect multi-line */
774*437bfbebSnyanmisaka if (line[len] == '\\') {
775*437bfbebSnyanmisaka /* Multi-line value */
776*437bfbebSnyanmisaka last = len ;
777*437bfbebSnyanmisaka continue ;
778*437bfbebSnyanmisaka } else {
779*437bfbebSnyanmisaka last = 0 ;
780*437bfbebSnyanmisaka }
781*437bfbebSnyanmisaka switch (iniparser_line(line, section, key, val)) {
782*437bfbebSnyanmisaka case LINE_EMPTY:
783*437bfbebSnyanmisaka case LINE_COMMENT:
784*437bfbebSnyanmisaka break ;
785*437bfbebSnyanmisaka
786*437bfbebSnyanmisaka case LINE_SECTION:
787*437bfbebSnyanmisaka mem_err = dictionary_set(dict, section, NULL);
788*437bfbebSnyanmisaka break ;
789*437bfbebSnyanmisaka
790*437bfbebSnyanmisaka case LINE_VALUE:
791*437bfbebSnyanmisaka sprintf(tmp, "%s:%s", section, key);
792*437bfbebSnyanmisaka mem_err = dictionary_set(dict, tmp, val);
793*437bfbebSnyanmisaka break ;
794*437bfbebSnyanmisaka
795*437bfbebSnyanmisaka case LINE_ERROR:
796*437bfbebSnyanmisaka iniparser_error_callback(
797*437bfbebSnyanmisaka "iniparser: syntax error in %s (%d):\n-> %s\n",
798*437bfbebSnyanmisaka ininame,
799*437bfbebSnyanmisaka lineno,
800*437bfbebSnyanmisaka line);
801*437bfbebSnyanmisaka errs++ ;
802*437bfbebSnyanmisaka break;
803*437bfbebSnyanmisaka
804*437bfbebSnyanmisaka default:
805*437bfbebSnyanmisaka break ;
806*437bfbebSnyanmisaka }
807*437bfbebSnyanmisaka memset(line, 0, ASCIILINESZ);
808*437bfbebSnyanmisaka last = 0;
809*437bfbebSnyanmisaka if (mem_err < 0) {
810*437bfbebSnyanmisaka iniparser_error_callback("iniparser: memory allocation failure\n");
811*437bfbebSnyanmisaka break ;
812*437bfbebSnyanmisaka }
813*437bfbebSnyanmisaka }
814*437bfbebSnyanmisaka if (errs) {
815*437bfbebSnyanmisaka dictionary_del(dict);
816*437bfbebSnyanmisaka dict = NULL ;
817*437bfbebSnyanmisaka }
818*437bfbebSnyanmisaka fclose(in);
819*437bfbebSnyanmisaka return dict ;
820*437bfbebSnyanmisaka }
821*437bfbebSnyanmisaka
822*437bfbebSnyanmisaka /*-------------------------------------------------------------------------*/
823*437bfbebSnyanmisaka /**
824*437bfbebSnyanmisaka @brief Free all memory associated to an ini dictionary
825*437bfbebSnyanmisaka @param d Dictionary to free
826*437bfbebSnyanmisaka @return void
827*437bfbebSnyanmisaka
828*437bfbebSnyanmisaka Free all memory associated to an ini dictionary.
829*437bfbebSnyanmisaka It is mandatory to call this function before the dictionary object
830*437bfbebSnyanmisaka gets out of the current context.
831*437bfbebSnyanmisaka */
832*437bfbebSnyanmisaka /*--------------------------------------------------------------------------*/
iniparser_freedict(dictionary * d)833*437bfbebSnyanmisaka void iniparser_freedict(dictionary * d)
834*437bfbebSnyanmisaka {
835*437bfbebSnyanmisaka dictionary_del(d);
836*437bfbebSnyanmisaka }
837