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