3eb8e23a05768b4c7627bb756e7dc97bf7ac3fad
[platform/upstream/libconfig.git] / lib / libconfig.c
1 /* ----------------------------------------------------------------------------
2    libconfig - A library for processing structured configuration files
3    Copyright (C) 2005-2010  Mark A Lindner
4
5    This file is part of libconfig.
6
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public License
9    as published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11
12    This library is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Library General Public
18    License along with this library; if not, see
19    <http://www.gnu.org/licenses/>.
20    ----------------------------------------------------------------------------
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "ac_config.h"
25 #endif
26
27 #include <locale.h>
28
29 #ifdef HAVE_XLOCALE_H
30 #include <xlocale.h>
31 #endif
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <float.h>
37
38 #include "libconfig.h"
39 #include "grammar.h"
40 #include "scanctx.h"
41 #include "parsectx.h"
42 #include "wincompat.h"
43 #include "scanner.h"
44
45
46 #define PATH_TOKENS ":./"
47 #define CHUNK_SIZE 16
48 #define FLOAT_PRECISION DBL_DIG
49
50 #define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */
51 #define _delete(P) free((void *)(P))
52
53 /* ------------------------------------------------------------------------- */
54
55 #ifndef LIBCONFIG_STATIC
56 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
57
58 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
59 {
60   return(TRUE);
61 }
62
63 #endif /* WIN32 */
64 #endif /* LIBCONFIG_STATIC */
65
66 /* ------------------------------------------------------------------------- */
67
68 static const char *__io_error = "file I/O error";
69
70 static void __config_list_destroy(config_list_t *list);
71 static void __config_write_setting(const config_setting_t *setting,
72                                    FILE *stream, int depth,
73                                    unsigned short tab_width);
74
75 extern int libconfig_yyparse(void *scanner, struct parse_context *ctx,
76                              struct scan_context *scan_ctx);
77 extern int libconfig_yylex_init_extra(struct scan_context *scan_ctx,
78                                       yyscan_t *scanner);
79
80 /* ------------------------------------------------------------------------- */
81
82 static void __config_locale_override(void)
83 {
84 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
85   && ! defined(__MINGW32__)
86
87   _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
88   setlocale(LC_NUMERIC, "C");
89
90 #elif defined(__APPLE__)
91
92   locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
93   uselocale(loc);
94
95 #elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE))
96
97   locale_t loc = newlocale(LC_NUMERIC, "C", NULL);
98   uselocale(loc);
99
100 #else
101
102 #warning "No way to modify calling thread's locale!"
103
104 #endif
105 }
106
107 /* ------------------------------------------------------------------------- */
108
109 static void __config_locale_restore(void)
110 {
111 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
112   && ! defined(__MINGW32__)
113
114     _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
115
116 #elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE))
117
118   locale_t loc = uselocale(LC_GLOBAL_LOCALE);
119   freelocale(loc);
120
121 #else
122
123 #warning "No way to modify calling thread's locale!"
124
125 #endif
126 }
127
128 /* ------------------------------------------------------------------------- */
129
130 static int __config_name_compare(const char *a, const char *b)
131 {
132   const char *p, *q;
133
134   for(p = a, q = b; ; p++, q++)
135   {
136     int pd = ((! *p) || strchr(PATH_TOKENS, *p));
137     int qd = ((! *q) || strchr(PATH_TOKENS, *q));
138
139     if(pd && qd)
140       break;
141     else if(pd)
142       return(-1);
143     else if(qd)
144       return(1);
145     else if(*p < *q)
146       return(-1);
147     else if(*p > *q)
148       return(1);
149   }
150
151   return(0);
152 }
153
154 /* ------------------------------------------------------------------------- */
155
156 static void __config_indent(FILE *stream, int depth, unsigned short w)
157 {
158   if(w)
159     fprintf(stream, "%*s", (depth - 1) * w, " ");
160   else
161   {
162     int i;
163     for(i = 0; i < (depth - 1); ++i)
164       fputc('\t', stream);
165   }
166 }
167
168 /* ------------------------------------------------------------------------- */
169
170 static void __config_write_value(const config_value_t *value, int type,
171                                  int format, int depth,
172                                  unsigned short tab_width, FILE *stream)
173 {
174   char fbuf[64];
175
176   switch(type)
177   {
178     /* boolean */
179     case CONFIG_TYPE_BOOL:
180       fputs(value->ival ? "true" : "false", stream);
181       break;
182
183     /* int */
184     case CONFIG_TYPE_INT:
185       switch(format)
186       {
187         case CONFIG_FORMAT_HEX:
188           fprintf(stream, "0x%X", value->ival);
189           break;
190
191         case CONFIG_FORMAT_DEFAULT:
192         default:
193           fprintf(stream, "%d", value->ival);
194           break;
195       }
196       break;
197
198     /* 64-bit int */
199     case CONFIG_TYPE_INT64:
200       switch(format)
201       {
202         case CONFIG_FORMAT_HEX:
203           fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval);
204           break;
205
206         case CONFIG_FORMAT_DEFAULT:
207         default:
208           fprintf(stream, INT64_FMT "L", value->llval);
209           break;
210       }
211       break;
212
213     /* float */
214     case CONFIG_TYPE_FLOAT:
215     {
216       char *q;
217
218       snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval);
219
220       /* check for exponent */
221       q = strchr(fbuf, 'e');
222       if(! q)
223       {
224         /* no exponent */
225         if(! strchr(fbuf, '.')) /* no decimal point */
226           strcat(fbuf, ".0");
227         else
228         {
229           /* has decimal point */
230           char *p;
231
232           for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p)
233           {
234             if(*p != '0')
235             {
236               *(++p) = '\0';
237               break;
238             }
239           }
240         }
241       }
242
243       fputs(fbuf, stream);
244       break;
245     }
246
247     /* string */
248     case CONFIG_TYPE_STRING:
249     {
250       char *p;
251
252       fputc('\"', stream);
253
254       if(value->sval)
255       {
256         for(p = value->sval; *p; p++)
257         {
258           int c = (int)*p & 0xFF;
259           switch(c)
260           {
261             case '\"':
262             case '\\':
263               fputc('\\', stream);
264               fputc(c, stream);
265               break;
266
267             case '\n':
268               fputs("\\n", stream);
269               break;
270
271             case '\r':
272               fputs("\\r", stream);
273               break;
274
275             case '\f':
276               fputs("\\f", stream);
277               break;
278
279             case '\t':
280               fputs("\\t", stream);
281               break;
282
283             default:
284               if(c >= ' ')
285                 fputc(c, stream);
286               else
287                 fprintf(stream, "\\x%02X", c);
288           }
289         }
290       }
291       fputc('\"', stream);
292       break;
293     }
294
295     /* list */
296     case CONFIG_TYPE_LIST:
297     {
298       config_list_t *list = value->list;
299
300       fprintf(stream, "( ");
301
302       if(list)
303       {
304         int len = list->length;
305         config_setting_t **s;
306
307         for(s = list->elements; len--; s++)
308         {
309           __config_write_value(&((*s)->value), (*s)->type,
310                                config_setting_get_format(*s),
311                                depth + 1, tab_width, stream);
312
313           if(len)
314             fputc(',', stream);
315
316           fputc(' ', stream);
317         }
318       }
319
320       fputc(')', stream);
321       break;
322     }
323
324     /* array */
325     case CONFIG_TYPE_ARRAY:
326     {
327       config_list_t *list = value->list;
328
329       fprintf(stream, "[ ");
330
331       if(list)
332       {
333         int len = list->length;
334         config_setting_t **s;
335
336         for(s = list->elements; len--; s++)
337         {
338           __config_write_value(&((*s)->value), (*s)->type,
339                                config_setting_get_format(*s),
340                                depth + 1, tab_width, stream);
341
342           if(len)
343             fputc(',', stream);
344
345           fputc(' ', stream);
346         }
347       }
348
349       fputc(']', stream);
350       break;
351     }
352
353     /* group */
354     case CONFIG_TYPE_GROUP:
355     {
356       config_list_t *list = value->list;
357
358       if(depth > 0)
359       {
360 #ifdef K_AND_R_STYLE /* Horrendous, but many people like it. */
361         fputc(' ', stream);
362 #else
363         fputc('\n', stream);
364
365         if(depth > 1)
366           __config_indent(stream, depth, tab_width);
367 #endif
368         fprintf(stream, "{\n");
369       }
370
371       if(list)
372       {
373         int len = list->length;
374         config_setting_t **s;
375
376         for(s = list->elements; len--; s++)
377           __config_write_setting(*s, stream, depth + 1, tab_width);
378       }
379
380       if(depth > 1)
381         __config_indent(stream, depth, tab_width);
382
383       if(depth > 0)
384         fputc('}', stream);
385
386       break;
387     }
388
389     default:
390       /* this shouldn't happen, but handle it gracefully... */
391       fputs("???", stream);
392       break;
393   }
394 }
395
396 /* ------------------------------------------------------------------------- */
397
398 static void __config_list_add(config_list_t *list, config_setting_t *setting)
399 {
400   if((list->length % CHUNK_SIZE) == 0)
401   {
402     list->elements = (config_setting_t **)realloc(
403       list->elements,
404       (list->length + CHUNK_SIZE) * sizeof(config_setting_t *));
405   }
406
407   list->elements[list->length] = setting;
408   list->length++;
409 }
410
411 /* ------------------------------------------------------------------------- */
412
413 static config_setting_t *__config_list_search(config_list_t *list,
414                                               const char *name,
415                                               unsigned int *idx)
416 {
417   config_setting_t **found = NULL;
418   unsigned int i;
419
420   if(! list)
421     return(NULL);
422
423   for(i = 0, found = list->elements; i < list->length; i++, found++)
424   {
425     if(! (*found)->name)
426       continue;
427
428     if(! __config_name_compare(name, (*found)->name))
429     {
430       if(idx)
431         *idx = i;
432
433       return(*found);
434     }
435   }
436
437   return(NULL);
438 }
439
440 /* ------------------------------------------------------------------------- */
441
442 static config_setting_t *__config_list_remove(config_list_t *list, int idx)
443 {
444   config_setting_t *removed = *(list->elements + idx);
445   int offset = (idx * sizeof(config_setting_t *));
446   int len = list->length - 1 - idx;
447   char *base = (char *)list->elements + offset;
448
449   memmove(base, base + sizeof(config_setting_t *),
450           len * sizeof(config_setting_t *));
451
452   list->length--;
453
454   /* possibly realloc smaller? */
455
456   return(removed);
457 }
458
459 /* ------------------------------------------------------------------------- */
460
461 static void __config_setting_destroy(config_setting_t *setting)
462 {
463   if(setting)
464   {
465     if(setting->name)
466       _delete(setting->name);
467
468     if(setting->type == CONFIG_TYPE_STRING)
469       _delete(setting->value.sval);
470
471     else if((setting->type == CONFIG_TYPE_GROUP)
472             || (setting->type == CONFIG_TYPE_ARRAY)
473             || (setting->type == CONFIG_TYPE_LIST))
474     {
475       if(setting->value.list)
476         __config_list_destroy(setting->value.list);
477     }
478
479     if(setting->hook && setting->config->destructor)
480       setting->config->destructor(setting->hook);
481
482     _delete(setting);
483   }
484 }
485
486 /* ------------------------------------------------------------------------- */
487
488 static void __config_list_destroy(config_list_t *list)
489 {
490   config_setting_t **p;
491   unsigned int i;
492
493   if(! list)
494     return;
495
496   if(list->elements)
497   {
498     for(p = list->elements, i = 0; i < list->length; p++, i++)
499       __config_setting_destroy(*p);
500
501     _delete(list->elements);
502   }
503
504   _delete(list);
505 }
506
507 /* ------------------------------------------------------------------------- */
508
509 static int __config_vector_checktype(const config_setting_t *vector, int type)
510 {
511   /* if the array is empty, then it has no type yet */
512
513   if(! vector->value.list)
514     return(CONFIG_TRUE);
515
516   if(vector->value.list->length == 0)
517     return(CONFIG_TRUE);
518
519   /* if it's a list, any type is allowed */
520
521   if(vector->type == CONFIG_TYPE_LIST)
522     return(CONFIG_TRUE);
523
524   /* otherwise the first element added determines the type of the array */
525
526   return((vector->value.list->elements[0]->type == type)
527          ? CONFIG_TRUE : CONFIG_FALSE);
528 }
529
530 /* ------------------------------------------------------------------------- */
531
532 static int __config_validate_name(const char *name)
533 {
534   const char *p = name;
535
536   if(*p == '\0')
537     return(CONFIG_FALSE);
538
539   if(! isalpha((int)*p) && (*p != '*'))
540     return(CONFIG_FALSE);
541
542   for(++p; *p; ++p)
543   {
544     if(! (isalpha((int)*p) || isdigit((int)*p) || strchr("*_-", (int)*p)))
545       return(CONFIG_FALSE);
546   }
547
548   return(CONFIG_TRUE);
549 }
550
551 /* ------------------------------------------------------------------------- */
552
553 static int __config_read(config_t *config, FILE *stream, const char *filename,
554                          const char *str)
555 {
556   yyscan_t scanner;
557   struct scan_context scan_ctx;
558   struct parse_context parse_ctx;
559   int r;
560
561   /* Reinitialize the config */
562   void (*destructor)(void *) = config->destructor;
563   const char *include_dir = config->include_dir;
564   unsigned short tab_width = config->tab_width;
565   unsigned short flags = config->flags;
566
567   config->include_dir = NULL;
568   config_destroy(config);
569   config_init(config);
570
571   config->destructor = destructor;
572   config->include_dir = include_dir;
573   config->tab_width = tab_width;
574   config->flags = flags;
575
576   parsectx_init(&parse_ctx);
577   parse_ctx.config = config;
578   parse_ctx.parent = config->root;
579   parse_ctx.setting = config->root;
580
581   __config_locale_override();
582
583   scanctx_init(&scan_ctx, filename);
584   config->root->file = scanctx_current_filename(&scan_ctx);
585   scan_ctx.config = config;
586   libconfig_yylex_init_extra(&scan_ctx, &scanner);
587
588   if(stream)
589     libconfig_yyrestart(stream, scanner);
590   else /* read from string */
591     (void)libconfig_yy_scan_string(str, scanner);
592
593   libconfig_yyset_lineno(1, scanner);
594   r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx);
595
596   if(r != 0)
597   {
598     YY_BUFFER_STATE buf;
599
600     config->error_file = scanctx_current_filename(&scan_ctx);
601     config->error_type = CONFIG_ERR_PARSE;
602
603     /* Unwind the include stack, freeing the buffers and closing the files. */
604     while((buf = (YY_BUFFER_STATE)scanctx_pop_include(&scan_ctx)) != NULL)
605       libconfig_yy_delete_buffer(buf, scanner);
606   }
607
608   libconfig_yylex_destroy(scanner);
609   config->filenames = scanctx_cleanup(&scan_ctx, &(config->num_filenames));
610   parsectx_cleanup(&parse_ctx);
611
612   __config_locale_restore();
613
614   return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE);
615 }
616
617 /* ------------------------------------------------------------------------- */
618
619 int config_read(config_t *config, FILE *stream)
620 {
621   return(__config_read(config, stream, NULL, NULL));
622 }
623
624 /* ------------------------------------------------------------------------- */
625
626 int config_read_string(config_t *config, const char *str)
627 {
628   return(__config_read(config, NULL, NULL, str));
629 }
630
631 /* ------------------------------------------------------------------------- */
632
633 static void __config_write_setting(const config_setting_t *setting,
634                                    FILE *stream, int depth,
635                                    unsigned short tab_width)
636 {
637   if(depth > 1)
638     __config_indent(stream, depth, tab_width);
639
640   if(setting->name)
641   {
642     fputs(setting->name, stream);
643     fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '='));
644   }
645
646   __config_write_value(&(setting->value), setting->type,
647                        config_setting_get_format(setting),
648                        depth, tab_width, stream);
649
650   if(depth > 0)
651   {
652     fputc(';', stream);
653     fputc('\n', stream);
654   }
655 }
656
657 /* ------------------------------------------------------------------------- */
658
659 void config_write(const config_t *config, FILE *stream)
660 {
661   __config_locale_override();
662
663   __config_write_setting(config->root, stream, 0, config->tab_width);
664
665   __config_locale_restore();
666 }
667
668 /* ------------------------------------------------------------------------- */
669
670 int config_read_file(config_t *config, const char *filename)
671 {
672   int ret;
673   FILE *stream = fopen(filename, "rt");
674   if(! stream)
675   {
676     config->error_text = __io_error;
677     config->error_type = CONFIG_ERR_FILE_IO;
678     return(CONFIG_FALSE);
679   }
680
681   ret = __config_read(config, stream, filename, NULL);
682   fclose(stream);
683
684   return(ret);
685 }
686
687 /* ------------------------------------------------------------------------- */
688
689 int config_write_file(config_t *config, const char *filename)
690 {
691   FILE *f = fopen(filename, "wt");
692   if(! f)
693   {
694     config->error_text = __io_error;
695     config->error_type = CONFIG_ERR_FILE_IO;
696     return(CONFIG_FALSE);
697   }
698
699   config_write(config, f);
700   fclose(f);
701   config->error_type = CONFIG_ERR_NONE;
702   return(CONFIG_TRUE);
703 }
704
705 /* ------------------------------------------------------------------------- */
706
707 void config_destroy(config_t *config)
708 {
709   unsigned int count = config->num_filenames;
710   const char **f;
711
712   __config_setting_destroy(config->root);
713
714   for(f = config->filenames; count > 0; ++f, --count)
715     _delete(*f);
716
717   _delete(config->filenames);
718   _delete(config->include_dir);
719
720   memset((void *)config, 0, sizeof(config_t));
721 }
722
723 /* ------------------------------------------------------------------------- */
724
725 void config_init(config_t *config)
726 {
727   memset((void *)config, 0, sizeof(config_t));
728
729   config->root = _new(config_setting_t);
730   config->root->type = CONFIG_TYPE_GROUP;
731   config->root->config = config;
732   config->tab_width = 2;
733 }
734
735 /* ------------------------------------------------------------------------- */
736
737 void config_set_auto_convert(config_t *config, int flag)
738 {
739   if(flag)
740     config->flags |= CONFIG_OPTION_AUTOCONVERT;
741   else
742     config->flags &= ~CONFIG_OPTION_AUTOCONVERT;
743 }
744
745 /* ------------------------------------------------------------------------- */
746
747 int config_get_auto_convert(const config_t *config)
748 {
749   return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0);
750 }
751
752 /* ------------------------------------------------------------------------- */
753
754 static config_setting_t *config_setting_create(config_setting_t *parent,
755                                                const char *name, int type)
756 {
757   config_setting_t *setting;
758   config_list_t *list;
759
760   if((parent->type != CONFIG_TYPE_GROUP)
761      && (parent->type != CONFIG_TYPE_ARRAY)
762      && (parent->type != CONFIG_TYPE_LIST))
763     return(NULL);
764
765   setting = _new(config_setting_t);
766   setting->parent = parent;
767   setting->name = (name == NULL) ? NULL : strdup(name);
768   setting->type = type;
769   setting->config = parent->config;
770   setting->hook = NULL;
771   setting->line = 0;
772
773   list = parent->value.list;
774
775   if(! list)
776     list = parent->value.list = _new(config_list_t);
777
778   __config_list_add(list, setting);
779
780   return(setting);
781 }
782
783 /* ------------------------------------------------------------------------- */
784
785 static int __config_setting_get_int(const config_setting_t *setting,
786                                     int *value)
787 {
788   switch(setting->type)
789   {
790     case CONFIG_TYPE_INT:
791       *value = setting->value.ival;
792       return(CONFIG_TRUE);
793
794     case CONFIG_TYPE_INT64:
795       if((setting->value.llval > INT32_MAX)
796          || (setting->value.llval < INT32_MIN))
797         *value = 0;
798       else
799         *value = (int)(setting->value.llval);
800       return(CONFIG_TRUE);
801
802     case CONFIG_TYPE_FLOAT:
803       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
804       {
805         *value = (int)(setting->value.fval);
806         return(CONFIG_TRUE);
807       }
808       else
809       { /* fall through */ }
810
811     default:
812       return(CONFIG_FALSE);
813   }
814 }
815
816 /* ------------------------------------------------------------------------- */
817
818 int config_setting_get_int(const config_setting_t *setting)
819 {
820   int value = 0;
821   __config_setting_get_int(setting, &value);
822   return(value);
823 }
824
825 /* ------------------------------------------------------------------------- */
826
827 static int __config_setting_get_int64(const config_setting_t *setting,
828                                       long long *value)
829 {
830   switch(setting->type)
831   {
832     case CONFIG_TYPE_INT64:
833       *value = setting->value.llval;
834       return(CONFIG_TRUE);
835
836     case CONFIG_TYPE_INT:
837       *value = (long long)(setting->value.ival);
838       return(CONFIG_TRUE);
839
840     case CONFIG_TYPE_FLOAT:
841       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
842       {
843         *value = (long long)(setting->value.fval);
844         return(CONFIG_TRUE);
845       }
846       else
847       { /* fall through */ }
848
849     default:
850       return(CONFIG_FALSE);
851   }
852 }
853
854 /* ------------------------------------------------------------------------- */
855
856 long long config_setting_get_int64(const config_setting_t *setting)
857 {
858   long long value = 0;
859   __config_setting_get_int64(setting, &value);
860   return(value);
861 }
862
863 /* ------------------------------------------------------------------------- */
864
865 int config_setting_lookup_int(const config_setting_t *setting,
866                               const char *name, int *value)
867 {
868   config_setting_t *member = config_setting_get_member(setting, name);
869   if(! member)
870     return(CONFIG_FALSE);
871
872   return(__config_setting_get_int(member, value));
873 }
874
875 /* ------------------------------------------------------------------------- */
876
877 int config_setting_lookup_int64(const config_setting_t *setting,
878                                 const char *name, long long *value)
879 {
880   config_setting_t *member = config_setting_get_member(setting, name);
881   if(! member)
882     return(CONFIG_FALSE);
883
884   return(__config_setting_get_int64(member, value));
885 }
886
887 /* ------------------------------------------------------------------------- */
888
889 static int __config_setting_get_float(const config_setting_t *setting,
890                                       double *value)
891 {
892   switch(setting->type)
893   {
894     case CONFIG_TYPE_FLOAT:
895       *value = setting->value.fval;
896       return(CONFIG_TRUE);
897
898     case CONFIG_TYPE_INT:
899       if(config_get_auto_convert(setting->config))
900       {
901         *value = (double)(setting->value.ival);
902         return(CONFIG_TRUE);
903       }
904       else
905         return(CONFIG_FALSE);
906
907     case CONFIG_TYPE_INT64:
908       if(config_get_auto_convert(setting->config))
909       {
910         *value = (double)(setting->value.llval);
911         return(CONFIG_TRUE);
912       }
913       else
914       { /* fall through */ }
915
916     default:
917       return(CONFIG_FALSE);
918   }
919 }
920
921 /* ------------------------------------------------------------------------- */
922
923 double config_setting_get_float(const config_setting_t *setting)
924 {
925   double value = 0.0;
926   __config_setting_get_float(setting, &value);
927   return(value);
928 }
929
930 /* ------------------------------------------------------------------------- */
931
932 int config_setting_lookup_float(const config_setting_t *setting,
933                                 const char *name, double *value)
934 {
935   config_setting_t *member = config_setting_get_member(setting, name);
936   if(! member)
937     return(CONFIG_FALSE);
938
939   return(__config_setting_get_float(member, value));
940 }
941
942 /* ------------------------------------------------------------------------- */
943
944 int config_setting_lookup_string(const config_setting_t *setting,
945                                  const char *name, const char **value)
946 {
947   config_setting_t *member = config_setting_get_member(setting, name);
948   if(! member)
949     return(CONFIG_FALSE);
950
951   if(config_setting_type(member) != CONFIG_TYPE_STRING)
952     return(CONFIG_FALSE);
953
954   *value = config_setting_get_string(member);
955   return(CONFIG_TRUE);
956 }
957
958 /* ------------------------------------------------------------------------- */
959
960 int config_setting_lookup_bool(const config_setting_t *setting,
961                                const char *name, int *value)
962 {
963   config_setting_t *member = config_setting_get_member(setting, name);
964   if(! member)
965     return(CONFIG_FALSE);
966
967   if(config_setting_type(member) != CONFIG_TYPE_BOOL)
968     return(CONFIG_FALSE);
969
970   *value = config_setting_get_bool(member);
971   return(CONFIG_TRUE);
972 }
973
974 /* ------------------------------------------------------------------------- */
975
976 int config_setting_set_int(config_setting_t *setting, int value)
977 {
978   switch(setting->type)
979   {
980     case CONFIG_TYPE_NONE:
981       setting->type = CONFIG_TYPE_INT;
982       /* fall through */
983
984     case CONFIG_TYPE_INT:
985       setting->value.ival = value;
986       return(CONFIG_TRUE);
987
988     case CONFIG_TYPE_FLOAT:
989       if(config_get_auto_convert(setting->config))
990       {
991         setting->value.fval = (float)value;
992         return(CONFIG_TRUE);
993       }
994       else
995         return(CONFIG_FALSE);
996
997     default:
998       return(CONFIG_FALSE);
999   }
1000 }
1001
1002 /* ------------------------------------------------------------------------- */
1003
1004 int config_setting_set_int64(config_setting_t *setting, long long value)
1005 {
1006   switch(setting->type)
1007   {
1008     case CONFIG_TYPE_NONE:
1009       setting->type = CONFIG_TYPE_INT64;
1010       /* fall through */
1011
1012     case CONFIG_TYPE_INT64:
1013       setting->value.llval = value;
1014       return(CONFIG_TRUE);
1015
1016     case CONFIG_TYPE_INT:
1017       if((value > INT32_MAX) || (value < INT32_MIN))
1018         setting->value.ival = 0;
1019       else
1020         setting->value.ival = (int)value;
1021       return(CONFIG_TRUE);
1022
1023     case CONFIG_TYPE_FLOAT:
1024       if(config_get_auto_convert(setting->config))
1025       {
1026         setting->value.fval = (float)value;
1027         return(CONFIG_TRUE);
1028       }
1029       else
1030         return(CONFIG_FALSE);
1031
1032     default:
1033       return(CONFIG_FALSE);
1034   }
1035 }
1036
1037 /* ------------------------------------------------------------------------- */
1038
1039 int config_setting_set_float(config_setting_t *setting, double value)
1040 {
1041   switch(setting->type)
1042   {
1043     case CONFIG_TYPE_NONE:
1044       setting->type = CONFIG_TYPE_FLOAT;
1045       /* fall through */
1046
1047     case CONFIG_TYPE_FLOAT:
1048       setting->value.fval = value;
1049       return(CONFIG_TRUE);
1050
1051     case CONFIG_TYPE_INT:
1052       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
1053       {
1054         setting->value.ival = (int)value;
1055         return(CONFIG_TRUE);
1056       }
1057       else
1058         return(CONFIG_FALSE);
1059
1060     case CONFIG_TYPE_INT64:
1061       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
1062       {
1063         setting->value.llval = (long long)value;
1064         return(CONFIG_TRUE);
1065       }
1066       else
1067         return(CONFIG_FALSE);
1068
1069     default:
1070       return(CONFIG_FALSE);
1071   }
1072 }
1073
1074 /* ------------------------------------------------------------------------- */
1075
1076 int config_setting_get_bool(const config_setting_t *setting)
1077 {
1078   return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0);
1079 }
1080
1081 /* ------------------------------------------------------------------------- */
1082
1083 int config_setting_set_bool(config_setting_t *setting, int value)
1084 {
1085   if(setting->type == CONFIG_TYPE_NONE)
1086     setting->type = CONFIG_TYPE_BOOL;
1087   else if(setting->type != CONFIG_TYPE_BOOL)
1088     return(CONFIG_FALSE);
1089
1090   setting->value.ival = value;
1091   return(CONFIG_TRUE);
1092 }
1093
1094 /* ------------------------------------------------------------------------- */
1095
1096 const char *config_setting_get_string(const config_setting_t *setting)
1097 {
1098   return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL);
1099 }
1100
1101 /* ------------------------------------------------------------------------- */
1102
1103 int config_setting_set_string(config_setting_t *setting, const char *value)
1104 {
1105   if(setting->type == CONFIG_TYPE_NONE)
1106     setting->type = CONFIG_TYPE_STRING;
1107   else if(setting->type != CONFIG_TYPE_STRING)
1108     return(CONFIG_FALSE);
1109
1110   if(setting->value.sval)
1111     _delete(setting->value.sval);
1112
1113   setting->value.sval = (value == NULL) ? NULL : strdup(value);
1114   return(CONFIG_TRUE);
1115 }
1116
1117 /* ------------------------------------------------------------------------- */
1118
1119 int config_setting_set_format(config_setting_t *setting, short format)
1120 {
1121   if(((setting->type != CONFIG_TYPE_INT)
1122       && (setting->type != CONFIG_TYPE_INT64))
1123      || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX)))
1124     return(CONFIG_FALSE);
1125
1126   setting->format = format;
1127
1128   return(CONFIG_TRUE);
1129 }
1130
1131 /* ------------------------------------------------------------------------- */
1132
1133 short config_setting_get_format(const config_setting_t *setting)
1134 {
1135   return(setting->format != 0 ? setting->format
1136          : setting->config->default_format);
1137 }
1138
1139 /* ------------------------------------------------------------------------- */
1140
1141 config_setting_t *config_setting_lookup(config_setting_t *setting,
1142                                         const char *path)
1143 {
1144   const char *p = path;
1145   config_setting_t *found;
1146
1147   for(;;)
1148   {
1149     while(*p && strchr(PATH_TOKENS, *p))
1150       p++;
1151
1152     if(! *p)
1153       break;
1154
1155     if(*p == '[')
1156       found = config_setting_get_elem(setting, atoi(++p));
1157     else
1158       found = config_setting_get_member(setting, p);
1159
1160     if(! found)
1161       break;
1162
1163     setting = found;
1164
1165     while(! strchr(PATH_TOKENS, *p))
1166       p++;
1167   }
1168
1169   return(*p ? NULL : setting);
1170 }
1171
1172 /* ------------------------------------------------------------------------- */
1173
1174 config_setting_t *config_lookup(const config_t *config, const char *path)
1175 {
1176   return(config_setting_lookup(config->root, path));
1177 }
1178
1179 /* ------------------------------------------------------------------------- */
1180
1181 int config_lookup_string(const config_t *config, const char *path,
1182                          const char **value)
1183 {
1184   const config_setting_t *s = config_lookup(config, path);
1185   if(! s)
1186     return(CONFIG_FALSE);
1187
1188   if(config_setting_type(s) != CONFIG_TYPE_STRING)
1189     return(CONFIG_FALSE);
1190
1191   *value = config_setting_get_string(s);
1192
1193   return(CONFIG_TRUE);
1194 }
1195
1196 /* ------------------------------------------------------------------------- */
1197
1198 int config_lookup_int(const config_t *config, const char *path,
1199                       int *value)
1200 {
1201   const config_setting_t *s = config_lookup(config, path);
1202   if(! s)
1203     return(CONFIG_FALSE);
1204
1205   return(__config_setting_get_int(s, value));
1206 }
1207
1208 /* ------------------------------------------------------------------------- */
1209
1210 int config_lookup_int64(const config_t *config, const char *path,
1211                         long long *value)
1212 {
1213   const config_setting_t *s = config_lookup(config, path);
1214   if(! s)
1215     return(CONFIG_FALSE);
1216
1217   return(__config_setting_get_int64(s, value));
1218 }
1219
1220 /* ------------------------------------------------------------------------- */
1221
1222 int config_lookup_float(const config_t *config, const char *path,
1223                         double *value)
1224 {
1225   const config_setting_t *s = config_lookup(config, path);
1226   if(! s)
1227     return(CONFIG_FALSE);
1228
1229   return(__config_setting_get_float(s, value));
1230 }
1231
1232 /* ------------------------------------------------------------------------- */
1233
1234 int config_lookup_bool(const config_t *config, const char *path, int *value)
1235 {
1236   const config_setting_t *s = config_lookup(config, path);
1237   if(! s)
1238     return(CONFIG_FALSE);
1239
1240   if(config_setting_type(s) != CONFIG_TYPE_BOOL)
1241     return(CONFIG_FALSE);
1242
1243   *value = config_setting_get_bool(s);
1244   return(CONFIG_TRUE);
1245 }
1246
1247 /* ------------------------------------------------------------------------- */
1248
1249 int config_setting_get_int_elem(const config_setting_t *vector, int idx)
1250 {
1251   const config_setting_t *element = config_setting_get_elem(vector, idx);
1252
1253   return(element ? config_setting_get_int(element) : 0);
1254 }
1255
1256 /* ------------------------------------------------------------------------- */
1257
1258 config_setting_t *config_setting_set_int_elem(config_setting_t *vector,
1259                                               int idx, int value)
1260 {
1261   config_setting_t *element = NULL;
1262
1263   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1264     return(NULL);
1265
1266   if(idx < 0)
1267   {
1268     if(! __config_vector_checktype(vector, CONFIG_TYPE_INT))
1269       return(NULL);
1270
1271     element = config_setting_create(vector, NULL, CONFIG_TYPE_INT);
1272   }
1273   else
1274   {
1275     element = config_setting_get_elem(vector, idx);
1276
1277     if(! element)
1278       return(NULL);
1279   }
1280
1281   if(! config_setting_set_int(element, value))
1282     return(NULL);
1283
1284   return(element);
1285 }
1286
1287 /* ------------------------------------------------------------------------- */
1288
1289 long long config_setting_get_int64_elem(const config_setting_t *vector,
1290                                         int idx)
1291 {
1292   const config_setting_t *element = config_setting_get_elem(vector, idx);
1293
1294   return(element ? config_setting_get_int64(element) : 0);
1295 }
1296
1297 /* ------------------------------------------------------------------------- */
1298
1299 config_setting_t *config_setting_set_int64_elem(config_setting_t *vector,
1300                                                 int idx, long long value)
1301 {
1302   config_setting_t *element = NULL;
1303
1304   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1305     return(NULL);
1306
1307   if(idx < 0)
1308   {
1309     if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64))
1310       return(NULL);
1311
1312     element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64);
1313   }
1314   else
1315   {
1316     element = config_setting_get_elem(vector, idx);
1317
1318     if(! element)
1319       return(NULL);
1320   }
1321
1322   if(! config_setting_set_int64(element, value))
1323     return(NULL);
1324
1325   return(element);
1326 }
1327
1328 /* ------------------------------------------------------------------------- */
1329
1330 double config_setting_get_float_elem(const config_setting_t *vector, int idx)
1331 {
1332   config_setting_t *element = config_setting_get_elem(vector, idx);
1333
1334   return(element ? config_setting_get_float(element) : 0.0);
1335 }
1336
1337 /* ------------------------------------------------------------------------- */
1338
1339 config_setting_t *config_setting_set_float_elem(config_setting_t *vector,
1340                                                 int idx, double value)
1341 {
1342   config_setting_t *element = NULL;
1343
1344   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1345     return(NULL);
1346
1347   if(idx < 0)
1348   {
1349     if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT))
1350       return(NULL);
1351
1352     element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT);
1353   }
1354   else
1355     element = config_setting_get_elem(vector, idx);
1356
1357   if(! element)
1358     return(NULL);
1359
1360   if(! config_setting_set_float(element, value))
1361     return(NULL);
1362
1363   return(element);
1364 }
1365
1366 /* ------------------------------------------------------------------------- */
1367
1368 int config_setting_get_bool_elem(const config_setting_t *vector, int idx)
1369 {
1370   config_setting_t *element = config_setting_get_elem(vector, idx);
1371
1372   if(! element)
1373     return(CONFIG_FALSE);
1374
1375   if(element->type != CONFIG_TYPE_BOOL)
1376     return(CONFIG_FALSE);
1377
1378   return(element->value.ival);
1379 }
1380
1381 /* ------------------------------------------------------------------------- */
1382
1383 config_setting_t *config_setting_set_bool_elem(config_setting_t *vector,
1384                                                int idx, int value)
1385 {
1386   config_setting_t *element = NULL;
1387
1388   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1389     return(NULL);
1390
1391   if(idx < 0)
1392   {
1393     if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL))
1394       return(NULL);
1395
1396     element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL);
1397   }
1398   else
1399     element = config_setting_get_elem(vector, idx);
1400
1401   if(! element)
1402     return(NULL);
1403
1404   if(! config_setting_set_bool(element, value))
1405     return(NULL);
1406
1407   return(element);
1408 }
1409
1410 /* ------------------------------------------------------------------------- */
1411
1412 const char *config_setting_get_string_elem(const config_setting_t *vector,
1413                                            int idx)
1414 {
1415   config_setting_t *element = config_setting_get_elem(vector, idx);
1416
1417   if(! element)
1418     return(NULL);
1419
1420   if(element->type != CONFIG_TYPE_STRING)
1421     return(NULL);
1422
1423   return(element->value.sval);
1424 }
1425
1426 /* ------------------------------------------------------------------------- */
1427
1428 config_setting_t *config_setting_set_string_elem(config_setting_t *vector,
1429                                                  int idx, const char *value)
1430 {
1431   config_setting_t *element = NULL;
1432
1433   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1434     return(NULL);
1435
1436   if(idx < 0)
1437   {
1438     if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING))
1439       return(NULL);
1440
1441     element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING);
1442   }
1443   else
1444     element = config_setting_get_elem(vector, idx);
1445
1446   if(! element)
1447     return(NULL);
1448
1449   if(! config_setting_set_string(element, value))
1450     return(NULL);
1451
1452   return(element);
1453 }
1454
1455 /* ------------------------------------------------------------------------- */
1456
1457 config_setting_t *config_setting_get_elem(const config_setting_t *vector,
1458                                           unsigned int idx)
1459 {
1460   config_list_t *list = vector->value.list;
1461
1462   if(((vector->type != CONFIG_TYPE_ARRAY)
1463       && (vector->type != CONFIG_TYPE_LIST)
1464       && (vector->type != CONFIG_TYPE_GROUP)) || ! list)
1465     return(NULL);
1466
1467   if(idx >= list->length)
1468     return(NULL);
1469
1470   return(list->elements[idx]);
1471 }
1472
1473 /* ------------------------------------------------------------------------- */
1474
1475 config_setting_t *config_setting_get_member(const config_setting_t *setting,
1476                                             const char *name)
1477 {
1478   if(setting->type != CONFIG_TYPE_GROUP)
1479     return(NULL);
1480
1481   return(__config_list_search(setting->value.list, name, NULL));
1482 }
1483
1484 /* ------------------------------------------------------------------------- */
1485
1486 void config_set_destructor(config_t *config, void (*destructor)(void *))
1487 {
1488   config->destructor = destructor;
1489 }
1490
1491 /* ------------------------------------------------------------------------- */
1492
1493 void config_set_include_dir(config_t *config, const char *include_dir)
1494 {
1495   _delete(config->include_dir);
1496   config->include_dir = strdup(include_dir);
1497 }
1498
1499 /* ------------------------------------------------------------------------- */
1500
1501 int config_setting_length(const config_setting_t *setting)
1502 {
1503   if((setting->type != CONFIG_TYPE_GROUP)
1504      && (setting->type != CONFIG_TYPE_ARRAY)
1505      && (setting->type != CONFIG_TYPE_LIST))
1506     return(0);
1507
1508   if(! setting->value.list)
1509     return(0);
1510
1511   return(setting->value.list->length);
1512 }
1513
1514 /* ------------------------------------------------------------------------- */
1515
1516 void config_setting_set_hook(config_setting_t *setting, void *hook)
1517 {
1518   setting->hook = hook;
1519 }
1520
1521 /* ------------------------------------------------------------------------- */
1522
1523 config_setting_t *config_setting_add(config_setting_t *parent,
1524                                      const char *name, int type)
1525 {
1526   if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST))
1527     return(NULL);
1528
1529   if(! parent)
1530     return(NULL);
1531
1532   if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST))
1533     name = NULL;
1534
1535   if(name)
1536   {
1537     if(! __config_validate_name(name))
1538       return(NULL);
1539   }
1540
1541   if(config_setting_get_member(parent, name) != NULL)
1542     return(NULL); /* already exists */
1543
1544   return(config_setting_create(parent, name, type));
1545 }
1546
1547 /* ------------------------------------------------------------------------- */
1548
1549 int config_setting_remove(config_setting_t *parent, const char *name)
1550 {
1551   unsigned int idx;
1552   config_setting_t *setting;
1553
1554   if(! parent)
1555     return(CONFIG_FALSE);
1556
1557   if(parent->type != CONFIG_TYPE_GROUP)
1558     return(CONFIG_FALSE);
1559
1560   if(! (setting = __config_list_search(parent->value.list, name, &idx)))
1561     return(CONFIG_FALSE);
1562
1563   __config_list_remove(parent->value.list, idx);
1564   __config_setting_destroy(setting);
1565
1566   return(CONFIG_TRUE);
1567 }
1568
1569 /* ------------------------------------------------------------------------- */
1570
1571 int config_setting_remove_elem(config_setting_t *parent, unsigned int idx)
1572 {
1573   config_list_t *list;
1574   config_setting_t *removed = NULL;
1575
1576   if(! parent)
1577     return(CONFIG_FALSE);
1578
1579   list = parent->value.list;
1580
1581   if(((parent->type != CONFIG_TYPE_ARRAY)
1582       && (parent->type != CONFIG_TYPE_LIST)
1583       && (parent->type != CONFIG_TYPE_GROUP)) || ! list)
1584     return(CONFIG_FALSE);
1585
1586   if(idx >= list->length)
1587     return(CONFIG_FALSE);
1588
1589   removed = __config_list_remove(list, idx);
1590   __config_setting_destroy(removed);
1591
1592   return(CONFIG_TRUE);
1593 }
1594
1595 /* ------------------------------------------------------------------------- */
1596
1597 int config_setting_index(const config_setting_t *setting)
1598 {
1599   config_setting_t **found = NULL;
1600   config_list_t *list;
1601   int i;
1602
1603   if(! setting->parent)
1604     return(-1);
1605
1606   list = setting->parent->value.list;
1607
1608   for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found)
1609   {
1610     if(*found == setting)
1611       return(i);
1612   }
1613
1614   return(-1);
1615 }
1616
1617 /* ------------------------------------------------------------------------- */
1618 /* eof */