Rev 56 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
56 | elmo | 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 */ |