ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ARDroneLib / Soft / Lib / iniparser3.0b / src / iniparser.c
1
2 /*-------------------------------------------------------------------------*/
3 /**
4    @file    iniparser.c
5    @author  N. Devillard
6    @date    Sep 2007
7    @version 3.0
8    @brief   Parser for ini files.
9 */
10 /*--------------------------------------------------------------------------*/
11 /*
12     $Id: iniparser.c,v 1.1.2.1 2010-02-12 10:19:23 kleplat Exp $
13     $Revision: 1.1.2.1 $
14     $Date: 2010-02-12 10:19:23 $
15 */
16 /*---------------------------- Includes ------------------------------------*/
17 #include <ctype.h>
18 #include "iniparser.h"
19
20 #include <VP_Os/vp_os_print.h>
21
22 #include <Maths/matrices.h>
23
24
25 #undef ARDRONE_CONFIG_KEY_IMM
26 #undef ARDRONE_CONFIG_KEY_REF
27 #undef ARDRONE_CONFIG_KEY_STR
28 #define ARDRONE_CONFIG_KEY_IMM(KEY, NAME, INI_TYPE, C_TYPE, C_TYPE_PTR, RW, DEFAULT, CALLBACK)
29 #define ARDRONE_CONFIG_KEY_REF(KEY, NAME, INI_TYPE, C_TYPE, C_TYPE_PTR, RW, DEFAULT, CALLBACK)
30 #define ARDRONE_CONFIG_KEY_STR(KEY, NAME, INI_TYPE, C_TYPE, C_TYPE_PTR, RW, DEFAULT, CALLBACK)
31 #include <config_keys.h>
32
33 /*---------------------------- Defines -------------------------------------*/
34 #define ASCIILINESZ         (1024)
35 #define INI_INVALID_KEY     ((char*)-1)
36
37 /*---------------------------------------------------------------------------
38                         Private to this module
39  ---------------------------------------------------------------------------*/
40 /**
41  * This enum stores the status for each parsed line (internal use only).
42  */
43 typedef enum _line_status_ {
44     LINE_UNPROCESSED,
45     LINE_ERROR,
46     LINE_EMPTY,
47     LINE_COMMENT,
48     LINE_SECTION,
49     LINE_VALUE
50 } line_status ;
51
52 /*-------------------------------------------------------------------------*/
53 /**
54   @brief        Convert a string to lowercase.
55   @param        s       String to convert.
56   @return       ptr to statically allocated string.
57
58   This function returns a pointer to a statically allocated string
59   containing a lowercased version of the input string. Do not free
60   or modify the returned string! Since the returned string is statically
61   allocated, it will be modified at each function call (not re-entrant).
62  */
63 /*--------------------------------------------------------------------------*/
64 static char * strlwc(const char * s)
65 {
66     static char l[ASCIILINESZ+1];
67     int i ;
68
69     if (s==NULL) return NULL ;
70     memset(l, 0, sizeof(l));
71     i=0 ;
72     while (s[i] && i<ASCIILINESZ) {
73         l[i] = (char)tolower((int)s[i]);
74         i++ ;
75     }
76     l[ASCIILINESZ]=(char)0;
77     return l ;
78 }
79
80 /*-------------------------------------------------------------------------*/
81 /**
82   @brief        Remove blanks at the beginning and the end of a string.
83   @param        s       String to parse.
84   @return       ptr to statically allocated string.
85
86   This function returns a pointer to a statically allocated string,
87   which is identical to the input string, except that all blank
88   characters at the end and the beg. of the string have been removed.
89   Do not free or modify the returned string! Since the returned string
90   is statically allocated, it will be modified at each function call
91   (not re-entrant).
92  */
93 /*--------------------------------------------------------------------------*/
94 static char * strstrip(char * s)
95 {
96     static char l[ASCIILINESZ+1];
97         char * last ;
98
99     if (s==NULL) return NULL ;
100
101         while (isspace((int)*s) && *s) s++;
102         memset(l, 0, ASCIILINESZ+1);
103         strcpy(l, s);
104         last = l + strlen(l);
105         while (last > l) {
106                 if (!isspace((int)*(last-1)))
107                         break ;
108                 last -- ;
109         }
110         *last = (char)0;
111         return (char*)l ;
112 }
113
114 /*-------------------------------------------------------------------------*/
115 /**
116   @brief    Get number of sections in a dictionary
117   @param    d   Dictionary to examine
118   @return   int Number of sections found in dictionary
119
120   This function returns the number of sections found in a dictionary.
121   The test to recognize sections is done on the string stored in the
122   dictionary: a section name is given as "section" whereas a key is
123   stored as "section:key", thus the test looks for entries that do not
124   contain a colon.
125
126   This clearly fails in the case a section name contains a colon, but
127   this should simply be avoided.
128
129   This function returns -1 in case of error.
130  */
131 /*--------------------------------------------------------------------------*/
132 int iniparser_getnsec(dictionary * d)
133 {
134     int i ;
135     int nsec ;
136
137     if (d==NULL) return -1 ;
138     nsec=0 ;
139     for (i=0 ; i<d->size ; i++) {
140         if (d->key[i]==NULL)
141             continue ;
142         if (/*strchr(d->key[i], ':')*/d->values[i].type==INI_SECTION) {
143             nsec ++ ;
144         }
145     }
146     return nsec ;
147 }
148
149 /*-------------------------------------------------------------------------*/
150 /**
151   @brief    Get name for section n in a dictionary.
152   @param    d   Dictionary to examine
153   @param    n   Section number (from 0 to nsec-1).
154   @return   Pointer to char string
155
156   This function locates the n-th section in a dictionary and returns
157   its name as a pointer to a string statically allocated inside the
158   dictionary. Do not free or modify the returned string!
159
160   This function returns NULL in case of error.
161  */
162 /*--------------------------------------------------------------------------*/
163 char * iniparser_getsecname(dictionary * d, int n)
164 {
165     int i ;
166     int foundsec ;
167
168     if (d==NULL || n<0) return NULL ;
169     foundsec=0 ;
170     for (i=0 ; i<d->size ; i++) {
171         if (d->key[i]==NULL)
172             continue ;
173         if (/*strchr(d->key[i], ':')==NULL*/ d->values[i].type==INI_SECTION) {
174             foundsec++ ;
175             if (foundsec>n)
176                 break ;
177         }
178     }
179     if (foundsec<=n) {
180         return NULL ;
181     }
182     return d->key[i] ;
183 }
184
185 /*-------------------------------------------------------------------------*/
186 /**
187   @brief    Duplicate a string
188   @param    s String to duplicate
189   @return   Pointer to a newly allocated string, to be freed with free()
190
191   This is a replacement for strdup(). This implementation is provided
192   for systems that do not have it.
193  */
194 /*--------------------------------------------------------------------------*/
195 static char * xstrdup(const char * s)
196 {
197     char * t ;
198     if (!s)
199         return NULL ;
200     t = malloc(strlen(s)+1) ;
201     if (t) {
202         strcpy(t,s);
203     }
204     return t ;
205 }
206
207 void iniparser_ptr2val(dictionary_value* value)
208 {
209   if( value && value->ptr != NULL )
210   {
211     if(value->val)
212     {
213       free(value->val);
214       value->val = NULL;
215     }
216
217     switch( value->type )
218     {
219     case INI_STRING:
220       value->val = xstrdup(value->ptr);
221       break;
222
223     case INI_INT:
224       value->val = malloc(64);
225       sprintf(value->val, "%d", *(int*)(value->ptr));
226       break;
227
228     case INI_FLOAT:
229       value->val = malloc(64);
230       sprintf(value->val, "%.7e", *(float*)(value->ptr));
231       break;
232
233     case INI_DOUBLE:
234       value->val = malloc(64);
235       sprintf(value->val, "%.16e", *(double*)(value->ptr));
236       break;
237
238     case INI_BOOLEAN:
239       value->val = malloc(64);
240       sprintf(value->val, "%s", ( *(int*)(value->ptr) ? "TRUE" : "FALSE" ) );
241       break;
242
243     case INI_VECTOR:
244       value->val = malloc(256);
245       sprintf(value->val, "{ %.7e %.7e %.7e }", ((vector31_t*)value->ptr)->x, ((vector31_t*)value->ptr)->y, ((vector31_t*)value->ptr)->z);
246       break;
247
248     case INI_VECTOR21:
249       value->val = malloc(256);
250       sprintf(value->val, "{ %.7e %.7e }", ((vector21_t*)value->ptr)->x, ((vector21_t*)value->ptr)->y);
251       break;
252
253     case INI_MATRIX:
254       value->val = malloc(1024);
255       sprintf(value->val, "{  %.7e %.7e %.7e  %.7e %.7e %.7e  %.7e %.7e %.7e }",
256                           ((matrix33_t*)value->ptr)->m11, ((matrix33_t*)value->ptr)->m12, ((matrix33_t*)value->ptr)->m13,
257                           ((matrix33_t*)value->ptr)->m21, ((matrix33_t*)value->ptr)->m22, ((matrix33_t*)value->ptr)->m23,
258                           ((matrix33_t*)value->ptr)->m31, ((matrix33_t*)value->ptr)->m32, ((matrix33_t*)value->ptr)->m33 );
259       break;
260
261     case INI_UNKNOW:
262     default:
263       break;
264     }
265   }
266 }
267
268 void iniparser_val2ptr(dictionary_value* value)
269 {
270   if( value )
271   {
272     if( value->ptr != NULL && value->val != NULL )
273     {
274       switch( value->type )
275         {
276         case INI_STRING:
277           strcpy(value->ptr, value->val);
278           break;
279
280         case INI_INT:
281           *(int*)(value->ptr) = (int)strtol(value->val, NULL, 0);
282           break;
283
284         case INI_FLOAT:
285           *(float*)(value->ptr) = (float)atof(value->val);
286           break;
287
288         case INI_DOUBLE:
289           *(double*)(value->ptr) = (double)atof(value->val);
290           break;
291
292         case INI_BOOLEAN:
293           {
294             int ret;
295             char c = value->val[0];
296
297             if( c=='y' || c=='Y' || c=='1' || c=='t' || c=='T') {
298               ret = 1 ;
299             } else if (c=='n' || c=='N' || c=='0' || c=='f' || c=='F') {
300               ret = 0 ;
301             }
302             else {
303               ret = 0xdeadbeef;
304             }
305
306             *(int*)(value->ptr) = ret;
307           }
308           break;
309
310         case INI_VECTOR:
311           sscanf(value->val, "{ %e %e %e }", &((vector31_t*)value->ptr)->x, &((vector31_t*)value->ptr)->y, &((vector31_t*)value->ptr)->z);
312           break;
313
314         case INI_VECTOR21:
315           sscanf(value->val, "{ %e %e }", &((vector21_t*)value->ptr)->x, &((vector21_t*)value->ptr)->y);
316           break;
317
318         case INI_MATRIX:
319           sscanf(value->val, "{ %e %e %e %e %e %e %e %e %e }",
320                              &((matrix33_t*)value->ptr)->m11, &((matrix33_t*)value->ptr)->m12, &((matrix33_t*)value->ptr)->m13,
321                              &((matrix33_t*)value->ptr)->m21, &((matrix33_t*)value->ptr)->m22, &((matrix33_t*)value->ptr)->m23,
322                              &((matrix33_t*)value->ptr)->m31, &((matrix33_t*)value->ptr)->m32, &((matrix33_t*)value->ptr)->m33 );
323           break;
324
325         case INI_UNKNOW:
326         default:
327           break;
328         }
329       }
330     }
331 }
332
333
334
335 /*-------------------------------------------------------------------------*/
336 /**
337   @brief    Transfer values from the dictionary to the bound variables
338   @param    d   Dictionary to dump.
339   @param    scope Scope for which values must be transfered (set to -1 to tranfer all values)
340   @return   void
341  */
342 /*--------------------------------------------------------------------------*/
343 void iniparser_vals2ptrs(dictionary * d , int scope)
344 {
345     int     i ;
346
347     if (d==NULL) return ;
348     for (i=0 ; i<d->size ; i++) {
349
350         if (d->key[i]==NULL)
351             continue ;
352
353         if( d->values[i].ptr != NULL ) {
354                 if (scope==-1 || d->values[i].scope==scope) {
355                         iniparser_val2ptr(&d->values[i]);
356                 }
357         }
358     }
359
360     return ;
361 }
362
363
364 /*-------------------------------------------------------------------------*/
365 /**
366   @brief    Transfer values from the bound variables to the dictionary.
367   @param    d Dictionary to fill.
368   @param    scope Scope for which values must be transfered (set to -1 to tranfer all values)
369   @return   void
370  */
371 /*--------------------------------------------------------------------------*/
372 void iniparser_ptrs2vals(dictionary * d , int scope)
373 {
374     int     i ;
375
376     if (d==NULL) return ;
377     for (i=0 ; i<d->size ; i++) {
378
379         if (d->key[i]==NULL)
380             continue ;
381
382         if( d->values[i].ptr != NULL ) {
383                 if (scope==-1 || d->values[i].scope==scope) {
384                         iniparser_ptr2val(&d->values[i]);
385                 }
386         }
387     }
388
389     return ;
390 }
391
392 /*-------------------------------------------------------------------------*/
393 /**
394   @brief    Dump a dictionary to an opened file pointer.
395   @param    d   Dictionary to dump.
396   @param    f   Opened file pointer to dump to.
397   @return   void
398
399   This function prints out the contents of a dictionary, one element by
400   line, onto the provided file pointer. It is OK to specify @c stderr
401   or @c stdout as output files. This function is meant for debugging
402   purposes mostly.
403  */
404 /*--------------------------------------------------------------------------*/
405 void iniparser_dump(dictionary * d)
406 {
407     int     i ;
408
409     if (d==NULL) return ;
410     for (i=0 ; i<d->size ; i++) {
411         if (d->key[i]==NULL)
412             continue ;
413         if( d->values[i].ptr != NULL ) {
414           switch(d->values[i].type)
415           {
416             case INI_STRING:
417               PRINT("%s= %s [STRING]\n", d->key[i], d->values[i].val);
418               break;
419
420             case INI_INT:
421               PRINT("%s= %d [INT]\n", d->key[i], *(int*)d->values[i].ptr);
422               break;
423
424             case INI_FLOAT:
425               PRINT("%s= %f [FLOAT]\n", d->key[i], *(float*)d->values[i].ptr);
426               break;
427
428             case INI_DOUBLE:
429               PRINT("%s= %lf [DOUBLE]\n", d->key[i], *(double*)d->values[i].ptr);
430               break;
431
432             case INI_BOOLEAN:
433               PRINT("%s= %d [BOOLEAN]\n", d->key[i], *(int*)d->values[i].ptr);
434               break;
435
436             case INI_VECTOR:
437               PRINT("%s= { %f %f %f } [VECTOR]\n", d->key[i], ((vector31_t*)d->values[i].ptr)->x,
438                                                               ((vector31_t*)d->values[i].ptr)->y,
439                                                               ((vector31_t*)d->values[i].ptr)->z);
440               break;
441
442             case INI_VECTOR21:
443               PRINT("%s= { %f %f } [VECTOR21]\n", d->key[i],  ((vector21_t*)d->values[i].ptr)->x,
444                                                               ((vector21_t*)d->values[i].ptr)->y);
445               break;
446
447             case INI_MATRIX:
448               PRINT("%s= { %f %f %f %f %f %f %f %f %f } [MATRIX]\n", d->key[i],
449                       ((matrix33_t*)d->values[i].ptr)->m11, ((matrix33_t*)d->values[i].ptr)->m12, ((matrix33_t*)d->values[i].ptr)->m13,
450                       ((matrix33_t*)d->values[i].ptr)->m21, ((matrix33_t*)d->values[i].ptr)->m22, ((matrix33_t*)d->values[i].ptr)->m23,
451                       ((matrix33_t*)d->values[i].ptr)->m31, ((matrix33_t*)d->values[i].ptr)->m32, ((matrix33_t*)d->values[i].ptr)->m33 );
452               break;
453
454             case INI_UNKNOW:
455             default:
456               PRINT("%s=[%s]\n", d->key[i], d->values[i].val);
457               break;
458           }
459 //             fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
460         } else {
461           if (d->values[i].val!=NULL) {
462             PRINT("%s=[%s]\n", d->key[i], d->values[i].val);
463           }
464           else {
465             if( d->values[i].type == INI_SECTION )
466               PRINT("[%s]\n", d->key[i]);
467             else
468               PRINT("%s=UNDEF\n", d->key[i]);
469 //             fprintf(f, "[%s]=UNDEF\n", d->key[i]);
470         }
471       }
472     }
473     return ;
474 }
475
476 /*-------------------------------------------------------------------------*/
477 /**
478   @brief    Save a dictionary to a loadable ini file
479   @param    d   Dictionary to dump
480   @param    f   Opened file pointer to dump to
481   @param    flag_dump_k_shallows  If true, K_SHALLOW values are written on disk
482   @return   void
483
484   This function dumps a given dictionary into a loadable ini file.
485   It is Ok to specify @c stderr or @c stdout as output files.
486  */
487 /*--------------------------------------------------------------------------*/
488 void iniparser_dump_ini(dictionary * d, FILE * f)
489 { iniparser_dump_ini_a4(d,f,0,1);    }
490 void iniparser_dump_ini_a3(dictionary * d, FILE * f , int flag_dump_k_shallows)
491 { iniparser_dump_ini_a4(d,f,flag_dump_k_shallows,1); }
492
493 void iniparser_dump_ini_a4(dictionary * d, FILE * f , int flag_dump_k_shallows , int update_values_from_memory)
494 {
495     int     i, j ;
496     char    keym[ASCIILINESZ+1];
497     int     nsec ;
498     char *  secname ;
499     int     seclen ;
500
501     if (d==NULL || f==NULL) return ;
502
503     nsec = iniparser_getnsec(d);
504     if (nsec<1) {
505         /* No section in file: dump all keys as they are */
506         for (i=0 ; i<d->size ; i++) {
507             if (d->key[i]==NULL)
508                 continue ;
509             /* Stephane - add K_SHALLOW support */
510                 if (!flag_dump_k_shallows)
511                         if ((d->values[i].rw&K_SHALLOW)!=0)
512                                 continue;
513             if(update_values_from_memory)
514                 iniparser_ptr2val(&d->values[i]); // Make sure we are synchro before dump
515             fprintf(f, "%s = %s\n", d->key[i], d->values[i].val);
516         }
517         return ;
518     }
519     for (i=0 ; i<nsec ; i++) {
520         secname = iniparser_getsecname(d, i) ;
521         seclen  = (int)strlen(secname);
522         fprintf(f, "\n[%s]\n", secname);
523         sprintf(keym, "%s:", secname);
524         for (j=0 ; j<d->size ; j++) {
525             if (d->key[j]==NULL)
526                 continue ;
527             /* Stephane - add K_SHALLOW support */
528                 if (!flag_dump_k_shallows)
529                         if ((d->values[j].rw&K_SHALLOW)!=0)
530                                 continue;
531             if (!strncmp(d->key[j], strlwc(keym), seclen+1)) {
532                 if(update_values_from_memory)
533                         iniparser_ptr2val(&d->values[j]); // Make sure we are synchro before dump
534                 fprintf(f,
535                         "%-30s = %s\n",
536                         d->key[j]+seclen+1,
537                         d->values[j].val ? d->values[j].val : "");
538             }
539         }
540     }
541     fprintf(f, "\n");
542     return ;
543 }
544
545 static dictionary_value* iniparser_getdictionaryvalue(dictionary * d, const char * key)
546 {
547   char * lc_key;
548
549   if (d==NULL || key==NULL)
550     return NULL;
551
552   lc_key = strlwc(key);
553   return dictionary_get(d, lc_key);
554 }
555
556 int iniparser_alias_ex(dictionary * d, const char* kkey, int type, void* ptr, void (*cb)(void), char rw,int scope);
557 int iniparser_alias(dictionary * d, const char* kkey, int type, void* ptr, void (*cb)(void), char rw)
558 {       return iniparser_alias_ex(d,kkey,type,ptr,cb,rw,CAT_COMMON);  }
559
560 int iniparser_alias_ex(dictionary * d, const char* kkey, int type, void* ptr, void (*cb)(void), char rw,int scope)
561 {
562   dictionary_value* value;
563   char *pos;
564   char key[ASCIILINESZ];
565
566   strcpy(&key[0], kkey);
567
568   // Create a new section ?
569   pos = strchr(key, ':');
570   if( pos )
571   {
572     *pos = '\0';
573     value = iniparser_getdictionaryvalue(d, key);
574     if( value == NULL)
575       dictionary_set(d, key, NULL, INI_SECTION, NULL,NULL);
576     *pos = ':';
577   }
578   else
579   {
580     return -1;
581   }
582
583   value = iniparser_getdictionaryvalue(d, key);
584
585         // TODO: change hardcoded value
586   if( value == NULL )
587   {
588     if( ptr != NULL )
589     {
590       // Create a new value
591       value = dictionary_set(d, strlwc(key), NULL, type, ptr, cb);
592       value->callback = cb;
593       value->rw = rw;
594       value->scope = scope;
595       iniparser_ptr2val(value);
596
597       if( cb )
598         cb();
599     }
600     else
601     {
602       return -1;
603     }
604   }
605   else
606   {
607     if( ptr != NULL )
608     {
609       // setup existing value
610       value->type = type;
611       value->ptr  = ptr;
612       value->callback = cb;
613       value->rw = rw;
614       value->scope = scope;
615
616                         if(rw & 1<<2)
617                         {
618                                 iniparser_ptr2val(value);
619                         }
620                         else
621                         {
622                                 iniparser_val2ptr(value);
623                         }
624
625       if( cb )
626         cb();
627     }
628     else
629     {
630       dictionary_unset(d, key);
631     }
632   }
633
634   return 0;
635 }
636
637 /*-------------------------------------------------------------------------*/
638 /**
639   @brief    Get the string associated to a key
640   @param    d       Dictionary to search
641   @param    key     Key string to look for
642   @param    def     Default value to return if key not found.
643   @return   pointer to statically allocated character string
644
645   This function queries a dictionary for a key. A key as read from an
646   ini file is given as "section:key". If the key cannot be found,
647   the pointer passed as 'def' is returned.
648   The returned char pointer is pointing to a string allocated in
649   the dictionary, do not free or modify it.
650  */
651 /*--------------------------------------------------------------------------*/
652 char * iniparser_getstring(dictionary * d, const char * key, char * def)
653 {
654   dictionary_value* value = iniparser_getdictionaryvalue(d, key);
655
656   if( value == NULL )
657     return def;
658
659   return value->val;
660 }
661
662 /*-------------------------------------------------------------------------*/
663 /**
664   @brief    Get the string associated to a key, convert to an int
665   @param    d Dictionary to search
666   @param    key Key string to look for
667   @param    notfound Value to return in case of error
668   @return   integer
669
670   This function queries a dictionary for a key. A key as read from an
671   ini file is given as "section:key". If the key cannot be found,
672   the notfound value is returned.
673
674   Supported values for integers include the usual C notation
675   so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
676   are supported. Examples:
677
678   "42"      ->  42
679   "042"     ->  34 (octal -> decimal)
680   "0x42"    ->  66 (hexa  -> decimal)
681
682   Warning: the conversion may overflow in various ways. Conversion is
683   totally outsourced to strtol(), see the associated man page for overflow
684   handling.
685
686   Credits: Thanks to A. Becker for suggesting strtol()
687  */
688 /*--------------------------------------------------------------------------*/
689 int iniparser_getint(dictionary * d, const char * key, int notfound)
690 {
691   int i;
692
693   dictionary_value* value = iniparser_getdictionaryvalue(d, key);
694
695   if( value == NULL )
696     return notfound;
697
698   if( value->ptr )
699   {
700     i = *(int*)(value->ptr);
701   }
702   else
703   {
704     i = strtol(value->val, NULL, 0);
705   }
706
707   return i;
708 }
709
710 /*-------------------------------------------------------------------------*/
711 /**
712   @brief    Get the string associated to a key, convert to a double
713   @param    d Dictionary to search
714   @param    key Key string to look for
715   @param    notfound Value to return in case of error
716   @return   double
717
718   This function queries a dictionary for a key. A key as read from an
719   ini file is given as "section:key". If the key cannot be found,
720   the notfound value is returned.
721  */
722 /*--------------------------------------------------------------------------*/
723 double iniparser_getdouble(dictionary * dict, char * key, double notfound)
724 {
725   double d;
726   dictionary_value* value = iniparser_getdictionaryvalue(dict, key);
727
728   if( value == NULL )
729     return notfound;
730
731   if( value->ptr )
732   {
733     switch( value->type )
734     {
735       case INI_FLOAT:
736         d = (double)*(float*)(value->ptr);
737         break;
738       case INI_DOUBLE:
739         d = *(double*)(value->ptr);
740         break;
741       default:
742         d = notfound;
743         break;
744     }
745   }
746   else
747   {
748     d = (int)atof(value->val);
749   }
750
751   return d;
752 }
753
754 /*-------------------------------------------------------------------------*/
755 /**
756   @brief    Get the string associated to a key, convert to a boolean
757   @param    d Dictionary to search
758   @param    key Key string to look for
759   @param    notfound Value to return in case of error
760   @return   integer
761
762   This function queries a dictionary for a key. A key as read from an
763   ini file is given as "section:key". If the key cannot be found,
764   the notfound value is returned.
765
766   A true boolean is found if one of the following is matched:
767
768   - A string starting with 'y'
769   - A string starting with 'Y'
770   - A string starting with 't'
771   - A string starting with 'T'
772   - A string starting with '1'
773
774   A false boolean is found if one of the following is matched:
775
776   - A string starting with 'n'
777   - A string starting with 'N'
778   - A string starting with 'f'
779   - A string starting with 'F'
780   - A string starting with '0'
781
782   The notfound value returned if no boolean is identified, does not
783   necessarily have to be 0 or 1.
784  */
785 /*--------------------------------------------------------------------------*/
786 int iniparser_getboolean(dictionary* dict, const char* key, int notfound)
787 {
788   int ret;
789
790   dictionary_value* value = iniparser_getdictionaryvalue(dict, key);
791
792   if( value == NULL )
793     return notfound;
794
795   if( value->ptr )
796   {
797     ret = *(int*)(value->ptr);
798   }
799   else
800   {
801     char c = value->val[0];
802
803     if( c=='y' || c=='Y' || c=='1' || c=='t' || c=='T') {
804         ret = 1 ;
805     } else if (c=='n' || c=='N' || c=='0' || c=='f' || c=='F') {
806         ret = 0 ;
807     } else {
808         ret = notfound ;
809     }
810   }
811
812   return ret;
813 }
814
815 /*-------------------------------------------------------------------------*/
816 /**
817   @brief    Finds out if a given entry exists in a dictionary
818   @param    ini     Dictionary to search
819   @param    entry   Name of the entry to look for
820   @return   integer 1 if entry exists, 0 otherwise
821
822   Finds out if a given entry exists in the dictionary. Since sections
823   are stored as keys with NULL associated values, this is the only way
824   of querying for the presence of sections in a dictionary.
825  */
826 /*--------------------------------------------------------------------------*/
827 int iniparser_find_entry( dictionary  *   ini, char* entry )
828 {
829   return iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY ? 1 : 0;
830 }
831
832 /*-------------------------------------------------------------------------*/
833 /**
834   @brief    Set an entry in a dictionary.
835   @param    ini     Dictionary to modify.
836   @param    entry   Entry to modify (entry name)
837   @param    val     New value to associate to the entry.
838   @return   int 0 if Ok, -1 otherwise.
839
840   If the given entry can be found in the dictionary, it is modified to
841   contain the provided value. If it cannot be found, -1 is returned.
842   It is Ok to set val to NULL.
843  */
844 /*--------------------------------------------------------------------------*/
845
846 int iniparser_setstring(dictionary * ini, const char * entry, const char * val)
847 { return iniparser_setstring_a4(ini,entry,val,1); }
848
849 int iniparser_setstring_a4(dictionary * ini,const char * entry, const char * val , int trigger_callback)
850 {
851   dictionary_value* value = dictionary_set(ini, strlwc(entry), val, INI_UNKNOW, NULL,NULL);
852
853   if( value == NULL )
854     return -1;
855
856   iniparser_val2ptr(value);
857
858   if( (trigger_callback) && (value->callback) )
859     value->callback();
860
861   return 0;
862 }
863
864 /*-------------------------------------------------------------------------*/
865 /**
866   @brief    Delete an entry in a dictionary
867   @param    ini     Dictionary to modify
868   @param    entry   Entry to delete (entry name)
869   @return   void
870
871   If the given entry can be found, it is deleted from the dictionary.
872  */
873 /*--------------------------------------------------------------------------*/
874 void iniparser_unset(dictionary * ini, char * entry)
875 {
876     dictionary_unset(ini, strlwc(entry));
877 }
878
879 /*-------------------------------------------------------------------------*/
880 /**
881   @brief        Load a single line from an INI file
882   @param    input_line  Input line, may be concatenated multi-line input
883   @param    section     Output space to store section
884   @param    key         Output space to store key
885   @param    value       Output space to store value
886   @return   line_status value
887  */
888 /*--------------------------------------------------------------------------*/
889 static line_status iniparser_line(
890     char * input_line,
891     char * section,
892     char * key,
893     char * value)
894 {
895     line_status sta ;
896     char        line[ASCIILINESZ+1];
897     int         len ;
898
899     strcpy(line, strstrip(input_line));
900     len = (int)strlen(line);
901
902     sta = LINE_UNPROCESSED ;
903     if (len<1) {
904         /* Empty line */
905         sta = LINE_EMPTY ;
906     } else if (line[0]=='#') {
907         /* Comment line */
908         sta = LINE_COMMENT ; 
909     } else if (line[0]=='[' && line[len-1]==']') {
910         /* Section name */
911         sscanf(line, "[%[^]]", section);
912         strcpy(section, strstrip(section));
913         strcpy(section, strlwc(section));
914         sta = LINE_SECTION ;
915     } else if ((sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
916            ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
917            ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2) /*&& (strcmp(section,""))*/) {
918         /* Usual key=value, with or without comments */
919         strcpy(key, strstrip(key));
920         strcpy(key, strlwc(key));
921         strcpy(value, strstrip(value));
922         /*
923          * sscanf cannot handle '' or "" as empty values
924          * this is done here
925          */
926         if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
927             value[0]=0 ;
928         }
929         sta = LINE_VALUE ;
930     } else if ((sscanf(line, "%[^=] = %[;#]", key, value)==2
931            ||  sscanf(line, "%[^=] %[=]", key, value) == 2) /*&& (strcmp(section,""))*/) {
932         /*
933          * Special cases:
934          * key=
935          * key=;
936          * key=#
937          */
938         strcpy(key, strstrip(key));
939         strcpy(key, strlwc(key));
940         value[0]=0 ;
941         sta = LINE_VALUE ;
942     } else {
943         /* Generate syntax error */
944         sta = LINE_ERROR ;
945     }
946     return sta ;
947 }
948
949 /*-------------------------------------------------------------------------*/
950 /**
951   @brief    Parse an ini file and return an allocated dictionary object
952   @param    ininame Name of the ini file to read.
953   @return   Pointer to newly allocated dictionary
954
955   This is the parser for ini files. This function is called, providing
956   the name of the file to be read. It returns a dictionary object that
957   should not be accessed directly, but through accessor functions
958   instead.
959
960   The returned dictionary must be freed using iniparser_freedict().
961  */
962 /*--------------------------------------------------------------------------*/
963 dictionary * iniparser_load(FILE* in, dictionary * dict )
964 {
965     char line    [ASCIILINESZ+1] ;
966     char section [ASCIILINESZ+1] ;
967     char key     [ASCIILINESZ+1] ;
968     char tmp     [ASCIILINESZ+1] ;
969     char val     [ASCIILINESZ+1] ;
970
971     int  last=0 ;
972     int  len ;
973     int  lineno=0 ;
974     int  errs=0;
975 /*
976     if ((in=fopen(ininame, "r"))==NULL) {
977       fprintf(stderr, "iniparser: cannot open %s\n", ininame);
978       return dict ;
979     }
980 */
981     if( dict == NULL )
982       dict = dictionary_new(0) ;
983
984     if (!dict) {
985         // fclose(in);
986         return dict ;
987     }
988
989     memset(line,    0, ASCIILINESZ);
990     memset(section, 0, ASCIILINESZ);
991     memset(key,     0, ASCIILINESZ);
992     memset(val,     0, ASCIILINESZ);
993     last=0 ;
994
995     while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
996         lineno++ ;
997         len = (int)strlen(line)-1;
998         /* Safety check against buffer overflows */
999         if (line[len]!='\n') {
1000             fprintf(stderr,
1001                     "iniparser: input line too long in file (line %d)\n",
1002 //                    ininame,
1003                     lineno);
1004             dictionary_del(dict);
1005             dict = NULL;
1006             // fclose(in);
1007             return dict ;
1008         }
1009         /* Get rid of \n and spaces at end of line */
1010         while ((len>=0) &&
1011                 ((line[len]=='\n') || (isspace(line[len])))) {
1012             line[len]=0 ;
1013             len-- ;
1014         }
1015         /* Detect multi-line */
1016         if (line[len]=='\\') {
1017             /* Multi-line value */
1018             last=len ;
1019             continue ;
1020         } else {
1021             last=0 ;
1022         }
1023         switch (iniparser_line(line, section, key, val)) {
1024             case LINE_EMPTY:
1025             case LINE_COMMENT:
1026             break ;
1027
1028             case LINE_SECTION:
1029             errs = dictionary_set(dict, section, NULL, INI_SECTION, NULL,NULL) != NULL ? 0 : -1;
1030             break ;
1031
1032             case LINE_VALUE:
1033             if (strcmp(section,"")!=0)
1034               sprintf(tmp, "%s:%s", section, key);
1035             else
1036               strcpy(tmp,key);
1037             errs = iniparser_setstring(dict, tmp, val);
1038             // errs = dictionary_set(dict, tmp, val, UNKNOW, NULL) != NULL ? 0 : -1;
1039             break ;
1040
1041             case LINE_ERROR:
1042             fprintf(stderr, "iniparser: syntax error in file (%d):\n",
1043 //                    ininame,
1044                     lineno);
1045             fprintf(stderr, "-> %s\n", line);
1046             errs++ ;
1047             break;
1048
1049             default:
1050             break ;
1051         }
1052         memset(line, 0, ASCIILINESZ);
1053         last=0;
1054         if (errs<0) {
1055             fprintf(stderr, "iniparser: memory allocation failure\n");
1056             break ;
1057         }
1058     }
1059     if (errs) {
1060         dictionary_del(dict);
1061         dict = NULL ;
1062     }
1063     // fclose(in);
1064     return dict ;
1065 }
1066
1067 /*-------------------------------------------------------------------------*/
1068 /**
1069   @brief    Free all memory associated to an ini dictionary
1070   @param    d Dictionary to free
1071   @return   void
1072
1073   Free all memory associated to an ini dictionary.
1074   It is mandatory to call this function before the dictionary object
1075   gets out of the current context.
1076  */
1077 /*--------------------------------------------------------------------------*/
1078 void iniparser_freedict(dictionary * d)
1079 {
1080     dictionary_del(d);
1081 }
1082
1083 /* vim: set ts=4 et sw=4 tw=75 */