OSDN Git Service

First version
[st-ro/stro.git] / 3rdparty / libconfig / 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 "libconfig.h"
28 #include "grammar.h"
29 #include "scanner.h"
30 #include "scanctx.h"
31 #include "parsectx.h"
32 #include "wincompat.h"
33
34 #include <locale.h>
35
36 #ifdef HAVE_XLOCALE_H
37 #include <xlocale.h>
38 #endif
39
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #define PATH_TOKENS ":./"
45 #define CHUNK_SIZE 16
46 #define FLOAT_PRECISION 10
47
48 #define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */
49 #define _delete(P) free((void *)(P))
50
51 /* ------------------------------------------------------------------------- */
52
53 #ifndef LIBCONFIG_STATIC
54 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
55
56 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
57 {
58   return(TRUE);
59 }
60
61 #endif /* WIN32 */
62 #endif /* LIBCONFIG_STATIC */
63
64 /* ------------------------------------------------------------------------- */
65
66 static const char *__io_error = "file I/O error";
67
68 static void __config_list_destroy(config_list_t *list);
69 static void __config_write_setting(const config_setting_t *setting,
70                                    FILE *stream, int depth,
71                                    unsigned short tab_width);
72
73 extern int libconfig_yyparse(void *scanner, struct parse_context *ctx,
74                              struct scan_context *scan_ctx);
75 extern int libconfig_yylex_init_extra(struct scan_context *scan_ctx,
76                                       yyscan_t *scanner);
77
78 /* ------------------------------------------------------------------------- */
79
80 static void __config_locale_override(void)
81 {
82 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
83   && ! defined(__MINGW32__)
84
85   _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
86   setlocale(LC_NUMERIC, "C");
87
88 #elif defined(__APPLE__)
89
90   locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
91   uselocale(loc);
92
93 #elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE))
94
95   locale_t loc = newlocale(LC_NUMERIC, "C", NULL);
96   uselocale(loc);
97
98 #else
99
100 /* locale overriding is pretty pointless (rathena doesn't make use of the area that uses locale functionality), but I'm actually removing it because it floods the buildbot with warnings  */
101 //#warning "No way to modify calling thread's locale!"
102
103 #endif
104 }
105
106 /* ------------------------------------------------------------------------- */
107
108 static void __config_locale_restore(void)
109 {
110 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
111   && ! defined(__MINGW32__)
112
113     _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
114
115 #elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE))
116
117   locale_t loc = uselocale(LC_GLOBAL_LOCALE);
118   freelocale(loc);
119
120 #else
121
122 /* locale overriding is pretty pointless (rathena doesn't make use of the area that uses locale functionality), but I'm actually removing it because it floods the buildbot with warnings  */
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 //  YY_BUFFER_STATE buffer = NULL;
560   int r;
561
562   /* Reinitialize the config */
563   void (*destructor)(void *) = config->destructor;
564   const char *include_dir = config->include_dir;
565   unsigned short tab_width = config->tab_width;
566   unsigned short flags = config->flags;
567
568   config->include_dir = NULL;
569   config_destroy(config);
570   config_init(config);
571
572   config->destructor = destructor;
573   config->include_dir = include_dir;
574   config->tab_width = tab_width;
575   config->flags = flags;
576
577   parsectx_init(&parse_ctx);
578   parse_ctx.config = config;
579   parse_ctx.parent = config->root;
580   parse_ctx.setting = config->root;
581
582   __config_locale_override();
583
584   scanctx_init(&scan_ctx, filename);
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  //   buffer = 
592         libconfig_yy_scan_string(str, scanner);
593
594   libconfig_yyset_lineno(1, scanner);
595   r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx);
596
597   if(r != 0)
598   {
599     YY_BUFFER_STATE buf;
600
601     config->error_file = scanctx_current_filename(&scan_ctx);
602     config->error_type = CONFIG_ERR_PARSE;
603
604     /* Unwind the include stack, freeing the buffers and closing the files. */
605     while((buf = (YY_BUFFER_STATE)scanctx_pop_include(&scan_ctx)) != NULL)
606       libconfig_yy_delete_buffer(buf, scanner);
607   }
608
609   libconfig_yylex_destroy(scanner);
610   config->filenames = scanctx_cleanup(&scan_ctx, &(config->num_filenames));
611   parsectx_cleanup(&parse_ctx);
612
613   __config_locale_restore();
614
615   return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE);
616 }
617
618 /* ------------------------------------------------------------------------- */
619
620 int config_read(config_t *config, FILE *stream)
621 {
622   return(__config_read(config, stream, NULL, NULL));
623 }
624
625 /* ------------------------------------------------------------------------- */
626
627 int config_read_string(config_t *config, const char *str)
628 {
629   return(__config_read(config, NULL, NULL, str));
630 }
631
632 /* ------------------------------------------------------------------------- */
633
634 static void __config_write_setting(const config_setting_t *setting,
635                                    FILE *stream, int depth,
636                                    unsigned short tab_width)
637 {
638   if(depth > 1)
639     __config_indent(stream, depth, tab_width);
640
641   if(setting->name)
642   {
643     fputs(setting->name, stream);
644     fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '='));
645   }
646
647   __config_write_value(&(setting->value), setting->type,
648                        config_setting_get_format(setting),
649                        depth, tab_width, stream);
650
651   if(depth > 0)
652   {
653     fputc(';', stream);
654     fputc('\n', stream);
655   }
656 }
657
658 /* ------------------------------------------------------------------------- */
659
660 void config_write(const config_t *config, FILE *stream)
661 {
662   __config_locale_override();
663
664   __config_write_setting(config->root, stream, 0, config->tab_width);
665
666   __config_locale_restore();
667 }
668
669 /* ------------------------------------------------------------------------- */
670
671 int config_read_file(config_t *config, const char *filename)
672 {
673   int ret;
674   FILE *stream = fopen(filename, "rt");
675   if(! stream)
676   {
677     config->error_text = __io_error;
678     config->error_type = CONFIG_ERR_FILE_IO;
679     return(CONFIG_FALSE);
680   }
681
682   ret = __config_read(config, stream, filename, NULL);
683   fclose(stream);
684
685   return(ret);
686 }
687
688 /* ------------------------------------------------------------------------- */
689
690 int config_write_file(config_t *config, const char *filename)
691 {
692   FILE *f = fopen(filename, "wt");
693   if(! f)
694   {
695     config->error_text = __io_error;
696     config->error_type = CONFIG_ERR_FILE_IO;
697     return(CONFIG_FALSE);
698   }
699
700   config_write(config, f);
701   fclose(f);
702   config->error_type = CONFIG_ERR_NONE;
703   return(CONFIG_TRUE);
704 }
705
706 /* ------------------------------------------------------------------------- */
707
708 void config_destroy(config_t *config)
709 {
710   unsigned int count = config->num_filenames;
711   const char **f;
712
713   __config_setting_destroy(config->root);
714
715   for(f = config->filenames; count > 0; ++f, --count)
716     _delete(*f);
717
718   _delete(config->filenames);
719   _delete(config->include_dir);
720
721   memset((void *)config, 0, sizeof(config_t));
722 }
723
724 /* ------------------------------------------------------------------------- */
725
726 void config_init(config_t *config)
727 {
728   memset((void *)config, 0, sizeof(config_t));
729
730   config->root = _new(config_setting_t);
731   config->root->type = CONFIG_TYPE_GROUP;
732   config->root->config = config;
733   config->tab_width = 2;
734 }
735
736 /* ------------------------------------------------------------------------- */
737
738 void config_set_auto_convert(config_t *config, int flag)
739 {
740   if(flag)
741     config->flags |= CONFIG_OPTION_AUTOCONVERT;
742   else
743     config->flags &= ~CONFIG_OPTION_AUTOCONVERT;
744 }
745
746 /* ------------------------------------------------------------------------- */
747
748 int config_get_auto_convert(const config_t *config)
749 {
750   return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0);
751 }
752
753 /* ------------------------------------------------------------------------- */
754
755 static config_setting_t *config_setting_create(config_setting_t *parent,
756                                                const char *name, int type)
757 {
758   config_setting_t *setting;
759   config_list_t *list;
760
761   if((parent->type != CONFIG_TYPE_GROUP)
762      && (parent->type != CONFIG_TYPE_ARRAY)
763      && (parent->type != CONFIG_TYPE_LIST))
764     return(NULL);
765
766   setting = _new(config_setting_t);
767   setting->parent = parent;
768   setting->name = (name == NULL) ? NULL : strdup(name);
769   setting->type = type;
770   setting->config = parent->config;
771   setting->hook = NULL;
772   setting->line = 0;
773
774   list = parent->value.list;
775
776   if(! list)
777     list = parent->value.list = _new(config_list_t);
778
779   __config_list_add(list, setting);
780
781   return(setting);
782 }
783
784 /* ------------------------------------------------------------------------- */
785
786 static int __config_setting_get_int(const config_setting_t *setting,
787                                     int *value)
788 {
789   switch(setting->type)
790   {
791     case CONFIG_TYPE_INT:
792       *value = setting->value.ival;
793       return(CONFIG_TRUE);
794
795     case CONFIG_TYPE_INT64:
796       if((setting->value.llval > INT32_MAX)
797          || (setting->value.llval < INT32_MIN))
798         *value = 0;
799       else
800         *value = (int)(setting->value.llval);
801       return(CONFIG_TRUE);
802
803     case CONFIG_TYPE_FLOAT:
804       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
805       {
806         *value = (int)(setting->value.fval);
807         return(CONFIG_TRUE);
808       }
809       else
810       { /* fall through */ }
811
812     default:
813       return(CONFIG_FALSE);
814   }
815 }
816
817 /* ------------------------------------------------------------------------- */
818
819 int config_setting_get_int(const config_setting_t *setting)
820 {
821   int value = 0;
822   __config_setting_get_int(setting, &value);
823   return(value);
824 }
825
826 /* ------------------------------------------------------------------------- */
827
828 static int __config_setting_get_int64(const config_setting_t *setting,
829                                       long long *value)
830 {
831   switch(setting->type)
832   {
833     case CONFIG_TYPE_INT64:
834       *value = setting->value.llval;
835       return(CONFIG_TRUE);
836
837     case CONFIG_TYPE_INT:
838       *value = (long long)(setting->value.ival);
839       return(CONFIG_TRUE);
840
841     case CONFIG_TYPE_FLOAT:
842       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
843       {
844         *value = (long long)(setting->value.fval);
845         return(CONFIG_TRUE);
846       }
847       else
848       { /* fall through */ }
849
850     default:
851       return(CONFIG_FALSE);
852   }
853 }
854
855 /* ------------------------------------------------------------------------- */
856
857 long long config_setting_get_int64(const config_setting_t *setting)
858 {
859   long long value = 0;
860   __config_setting_get_int64(setting, &value);
861   return(value);
862 }
863
864 /* ------------------------------------------------------------------------- */
865
866 int config_setting_lookup_int(const config_setting_t *setting,
867                               const char *name, int *value)
868 {
869   config_setting_t *member = config_setting_get_member(setting, name);
870   if(! member)
871     return(CONFIG_FALSE);
872
873   return(__config_setting_get_int(member, value));
874 }
875
876 /* ------------------------------------------------------------------------- */
877
878 int config_setting_lookup_int64(const config_setting_t *setting,
879                                 const char *name, long long *value)
880 {
881   config_setting_t *member = config_setting_get_member(setting, name);
882   if(! member)
883     return(CONFIG_FALSE);
884
885   return(__config_setting_get_int64(member, value));
886 }
887
888 /* ------------------------------------------------------------------------- */
889
890 static int __config_setting_get_float(const config_setting_t *setting,
891                                       double *value)
892 {
893   switch(setting->type)
894   {
895     case CONFIG_TYPE_FLOAT:
896       *value = setting->value.fval;
897       return(CONFIG_TRUE);
898
899     case CONFIG_TYPE_INT:
900       if(config_get_auto_convert(setting->config))
901       {
902         *value = (double)(setting->value.ival);
903         return(CONFIG_TRUE);
904       }
905       else
906         return(CONFIG_FALSE);
907
908     case CONFIG_TYPE_INT64:
909       if(config_get_auto_convert(setting->config))
910       {
911         *value = (double)(setting->value.llval);
912         return(CONFIG_TRUE);
913       }
914       else
915       { /* fall through */ }
916
917     default:
918       return(CONFIG_FALSE);
919   }
920 }
921
922 /* ------------------------------------------------------------------------- */
923
924 double config_setting_get_float(const config_setting_t *setting)
925 {
926   double value = 0.0;
927   __config_setting_get_float(setting, &value);
928   return(value);
929 }
930
931 /* ------------------------------------------------------------------------- */
932
933 int config_setting_lookup_float(const config_setting_t *setting,
934                                 const char *name, double *value)
935 {
936   config_setting_t *member = config_setting_get_member(setting, name);
937   if(! member)
938     return(CONFIG_FALSE);
939
940   return(__config_setting_get_float(member, value));
941 }
942
943 /* ------------------------------------------------------------------------- */
944
945 int config_setting_lookup_string(const config_setting_t *setting,
946                                  const char *name, const char **value)
947 {
948   config_setting_t *member = config_setting_get_member(setting, name);
949   if(! member)
950     return(CONFIG_FALSE);
951
952   if(config_setting_type(member) != CONFIG_TYPE_STRING)
953     return(CONFIG_FALSE);
954
955   *value = config_setting_get_string(member);
956   return(CONFIG_TRUE);
957 }
958
959 /* ------------------------------------------------------------------------- */
960
961 int config_setting_lookup_bool(const config_setting_t *setting,
962                                const char *name, int *value)
963 {
964   config_setting_t *member = config_setting_get_member(setting, name);
965   if(! member)
966     return(CONFIG_FALSE);
967
968   if(config_setting_type(member) != CONFIG_TYPE_BOOL)
969     return(CONFIG_FALSE);
970
971   *value = config_setting_get_bool(member);
972   return(CONFIG_TRUE);
973 }
974
975 /* ------------------------------------------------------------------------- */
976
977 int config_setting_set_int(config_setting_t *setting, int value)
978 {
979   switch(setting->type)
980   {
981     case CONFIG_TYPE_NONE:
982       setting->type = CONFIG_TYPE_INT;
983       /* fall through */
984
985     case CONFIG_TYPE_INT:
986       setting->value.ival = value;
987       return(CONFIG_TRUE);
988
989     case CONFIG_TYPE_FLOAT:
990       if(config_get_auto_convert(setting->config))
991       {
992         setting->value.fval = (float)value;
993         return(CONFIG_TRUE);
994       }
995       else
996         return(CONFIG_FALSE);
997
998     default:
999       return(CONFIG_FALSE);
1000   }
1001 }
1002
1003 /* ------------------------------------------------------------------------- */
1004
1005 int config_setting_set_int64(config_setting_t *setting, long long value)
1006 {
1007   switch(setting->type)
1008   {
1009     case CONFIG_TYPE_NONE:
1010       setting->type = CONFIG_TYPE_INT64;
1011       /* fall through */
1012
1013     case CONFIG_TYPE_INT64:
1014       setting->value.llval = value;
1015       return(CONFIG_TRUE);
1016
1017     case CONFIG_TYPE_INT:
1018       if((value > INT32_MAX) || (value < INT32_MIN))
1019         setting->value.ival = 0;
1020       else
1021         setting->value.ival = (int)value;
1022       return(CONFIG_TRUE);
1023
1024     case CONFIG_TYPE_FLOAT:
1025       if(config_get_auto_convert(setting->config))
1026       {
1027         setting->value.fval = (float)value;
1028         return(CONFIG_TRUE);
1029       }
1030       else
1031         return(CONFIG_FALSE);
1032
1033     default:
1034       return(CONFIG_FALSE);
1035   }
1036 }
1037
1038 /* ------------------------------------------------------------------------- */
1039
1040 int config_setting_set_float(config_setting_t *setting, double value)
1041 {
1042   switch(setting->type)
1043   {
1044     case CONFIG_TYPE_NONE:
1045       setting->type = CONFIG_TYPE_FLOAT;
1046       /* fall through */
1047
1048     case CONFIG_TYPE_FLOAT:
1049       setting->value.fval = value;
1050       return(CONFIG_TRUE);
1051
1052     case CONFIG_TYPE_INT:
1053       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
1054       {
1055         setting->value.ival = (int)value;
1056         return(CONFIG_TRUE);
1057       }
1058       else
1059         return(CONFIG_FALSE);
1060
1061     case CONFIG_TYPE_INT64:
1062       if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
1063       {
1064         setting->value.llval = (long long)value;
1065         return(CONFIG_TRUE);
1066       }
1067       else
1068         return(CONFIG_FALSE);
1069
1070     default:
1071       return(CONFIG_FALSE);
1072   }
1073 }
1074
1075 /* ------------------------------------------------------------------------- */
1076
1077 int config_setting_get_bool(const config_setting_t *setting)
1078 {
1079   return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0);
1080 }
1081
1082 /* ------------------------------------------------------------------------- */
1083
1084 int config_setting_set_bool(config_setting_t *setting, int value)
1085 {
1086   if(setting->type == CONFIG_TYPE_NONE)
1087     setting->type = CONFIG_TYPE_BOOL;
1088   else if(setting->type != CONFIG_TYPE_BOOL)
1089     return(CONFIG_FALSE);
1090
1091   setting->value.ival = value;
1092   return(CONFIG_TRUE);
1093 }
1094
1095 /* ------------------------------------------------------------------------- */
1096
1097 const char *config_setting_get_string(const config_setting_t *setting)
1098 {
1099   return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL);
1100 }
1101
1102 /* ------------------------------------------------------------------------- */
1103
1104 int config_setting_set_string(config_setting_t *setting, const char *value)
1105 {
1106   if(setting->type == CONFIG_TYPE_NONE)
1107     setting->type = CONFIG_TYPE_STRING;
1108   else if(setting->type != CONFIG_TYPE_STRING)
1109     return(CONFIG_FALSE);
1110
1111   if(setting->value.sval)
1112     _delete(setting->value.sval);
1113
1114   setting->value.sval = (value == NULL) ? NULL : strdup(value);
1115   return(CONFIG_TRUE);
1116 }
1117
1118 /* ------------------------------------------------------------------------- */
1119
1120 int config_setting_set_format(config_setting_t *setting, short format)
1121 {
1122   if(((setting->type != CONFIG_TYPE_INT)
1123       && (setting->type != CONFIG_TYPE_INT64))
1124      || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX)))
1125     return(CONFIG_FALSE);
1126
1127   setting->format = format;
1128
1129   return(CONFIG_TRUE);
1130 }
1131
1132 /* ------------------------------------------------------------------------- */
1133
1134 short config_setting_get_format(const config_setting_t *setting)
1135 {
1136   return(setting->format != 0 ? setting->format
1137          : setting->config->default_format);
1138 }
1139
1140 /* ------------------------------------------------------------------------- */
1141
1142 config_setting_t *config_lookup_from(config_setting_t *setting,
1143                                      const char *path)
1144 {
1145   const char *p = path;
1146   config_setting_t *found;
1147
1148   for(;;)
1149   {
1150     while(*p && strchr(PATH_TOKENS, *p))
1151       p++;
1152
1153     if(! *p)
1154       break;
1155
1156     if(*p == '[')
1157       found = config_setting_get_elem(setting, atoi(++p));
1158     else
1159       found = config_setting_get_member(setting, p);
1160
1161     if(! found)
1162       break;
1163
1164     setting = found;
1165
1166     while(! strchr(PATH_TOKENS, *p))
1167       p++;
1168   }
1169
1170   return(*p ? NULL : setting);
1171 }
1172
1173 /* ------------------------------------------------------------------------- */
1174
1175 config_setting_t *config_lookup(const config_t *config, const char *path)
1176 {
1177   return(config_lookup_from(config->root, path));
1178 }
1179
1180 /* ------------------------------------------------------------------------- */
1181
1182 int config_lookup_string(const config_t *config, const char *path,
1183                          const char **value)
1184 {
1185   const config_setting_t *s = config_lookup(config, path);
1186   if(! s)
1187     return(CONFIG_FALSE);
1188
1189   if(config_setting_type(s) != CONFIG_TYPE_STRING)
1190     return(CONFIG_FALSE);
1191
1192   *value = config_setting_get_string(s);
1193
1194   return(CONFIG_TRUE);
1195 }
1196
1197 /* ------------------------------------------------------------------------- */
1198
1199 int config_lookup_int(const config_t *config, const char *path,
1200                       int *value)
1201 {
1202   const config_setting_t *s = config_lookup(config, path);
1203   if(! s)
1204     return(CONFIG_FALSE);
1205
1206   return(__config_setting_get_int(s, value));
1207 }
1208
1209 /* ------------------------------------------------------------------------- */
1210
1211 int config_lookup_int64(const config_t *config, const char *path,
1212                         long long *value)
1213 {
1214   const config_setting_t *s = config_lookup(config, path);
1215   if(! s)
1216     return(CONFIG_FALSE);
1217
1218   return(__config_setting_get_int64(s, value));
1219 }
1220
1221 /* ------------------------------------------------------------------------- */
1222
1223 int config_lookup_float(const config_t *config, const char *path,
1224                         double *value)
1225 {
1226   const config_setting_t *s = config_lookup(config, path);
1227   if(! s)
1228     return(CONFIG_FALSE);
1229
1230   return(__config_setting_get_float(s, value));
1231 }
1232
1233 /* ------------------------------------------------------------------------- */
1234
1235 int config_lookup_bool(const config_t *config, const char *path, int *value)
1236 {
1237   const config_setting_t *s = config_lookup(config, path);
1238   if(! s)
1239     return(CONFIG_FALSE);
1240
1241   if(config_setting_type(s) != CONFIG_TYPE_BOOL)
1242     return(CONFIG_FALSE);
1243
1244   *value = config_setting_get_bool(s);
1245   return(CONFIG_TRUE);
1246 }
1247
1248 /* ------------------------------------------------------------------------- */
1249
1250 int config_setting_get_int_elem(const config_setting_t *vector, int idx)
1251 {
1252   const config_setting_t *element = config_setting_get_elem(vector, idx);
1253
1254   return(element ? config_setting_get_int(element) : 0);
1255 }
1256
1257 /* ------------------------------------------------------------------------- */
1258
1259 config_setting_t *config_setting_set_int_elem(config_setting_t *vector,
1260                                               int idx, int value)
1261 {
1262   config_setting_t *element = NULL;
1263
1264   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1265     return(NULL);
1266
1267   if(idx < 0)
1268   {
1269     if(! __config_vector_checktype(vector, CONFIG_TYPE_INT))
1270       return(NULL);
1271
1272     element = config_setting_create(vector, NULL, CONFIG_TYPE_INT);
1273   }
1274   else
1275   {
1276     element = config_setting_get_elem(vector, idx);
1277
1278     if(! element)
1279       return(NULL);
1280   }
1281
1282   if(! config_setting_set_int(element, value))
1283     return(NULL);
1284
1285   return(element);
1286 }
1287
1288 /* ------------------------------------------------------------------------- */
1289
1290 long long config_setting_get_int64_elem(const config_setting_t *vector,
1291                                         int idx)
1292 {
1293   const config_setting_t *element = config_setting_get_elem(vector, idx);
1294
1295   return(element ? config_setting_get_int64(element) : 0);
1296 }
1297
1298 /* ------------------------------------------------------------------------- */
1299
1300 config_setting_t *config_setting_set_int64_elem(config_setting_t *vector,
1301                                                 int idx, long long value)
1302 {
1303   config_setting_t *element = NULL;
1304
1305   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1306     return(NULL);
1307
1308   if(idx < 0)
1309   {
1310     if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64))
1311       return(NULL);
1312
1313     element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64);
1314   }
1315   else
1316   {
1317     element = config_setting_get_elem(vector, idx);
1318
1319     if(! element)
1320       return(NULL);
1321   }
1322
1323   if(! config_setting_set_int64(element, value))
1324     return(NULL);
1325
1326   return(element);
1327 }
1328
1329 /* ------------------------------------------------------------------------- */
1330
1331 double config_setting_get_float_elem(const config_setting_t *vector, int idx)
1332 {
1333   config_setting_t *element = config_setting_get_elem(vector, idx);
1334
1335   return(element ? config_setting_get_float(element) : 0.0);
1336 }
1337
1338 /* ------------------------------------------------------------------------- */
1339
1340 config_setting_t *config_setting_set_float_elem(config_setting_t *vector,
1341                                                 int idx, double value)
1342 {
1343   config_setting_t *element = NULL;
1344
1345   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1346     return(NULL);
1347
1348   if(idx < 0)
1349   {
1350     if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT))
1351       return(NULL);
1352
1353     element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT);
1354   }
1355   else
1356     element = config_setting_get_elem(vector, idx);
1357
1358   if(! element)
1359     return(NULL);
1360
1361   if(! config_setting_set_float(element, value))
1362     return(NULL);
1363
1364   return(element);
1365 }
1366
1367 /* ------------------------------------------------------------------------- */
1368
1369 int config_setting_get_bool_elem(const config_setting_t *vector, int idx)
1370 {
1371   config_setting_t *element = config_setting_get_elem(vector, idx);
1372
1373   if(! element)
1374     return(CONFIG_FALSE);
1375
1376   if(element->type != CONFIG_TYPE_BOOL)
1377     return(CONFIG_FALSE);
1378
1379   return(element->value.ival);
1380 }
1381
1382 /* ------------------------------------------------------------------------- */
1383
1384 config_setting_t *config_setting_set_bool_elem(config_setting_t *vector,
1385                                                int idx, int value)
1386 {
1387   config_setting_t *element = NULL;
1388
1389   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1390     return(NULL);
1391
1392   if(idx < 0)
1393   {
1394     if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL))
1395       return(NULL);
1396
1397     element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL);
1398   }
1399   else
1400     element = config_setting_get_elem(vector, idx);
1401
1402   if(! element)
1403     return(NULL);
1404
1405   if(! config_setting_set_bool(element, value))
1406     return(NULL);
1407
1408   return(element);
1409 }
1410
1411 /* ------------------------------------------------------------------------- */
1412
1413 const char *config_setting_get_string_elem(const config_setting_t *vector,
1414                                            int idx)
1415 {
1416   config_setting_t *element = config_setting_get_elem(vector, idx);
1417
1418   if(! element)
1419     return(NULL);
1420
1421   if(element->type != CONFIG_TYPE_STRING)
1422     return(NULL);
1423
1424   return(element->value.sval);
1425 }
1426
1427 /* ------------------------------------------------------------------------- */
1428
1429 config_setting_t *config_setting_set_string_elem(config_setting_t *vector,
1430                                                  int idx, const char *value)
1431 {
1432   config_setting_t *element = NULL;
1433
1434   if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
1435     return(NULL);
1436
1437   if(idx < 0)
1438   {
1439     if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING))
1440       return(NULL);
1441
1442     element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING);
1443   }
1444   else
1445     element = config_setting_get_elem(vector, idx);
1446
1447   if(! element)
1448     return(NULL);
1449
1450   if(! config_setting_set_string(element, value))
1451     return(NULL);
1452
1453   return(element);
1454 }
1455
1456 /* ------------------------------------------------------------------------- */
1457
1458 config_setting_t *config_setting_get_elem(const config_setting_t *vector,
1459                                           unsigned int idx)
1460 {
1461   config_list_t *list = vector->value.list;
1462
1463   if(((vector->type != CONFIG_TYPE_ARRAY)
1464       && (vector->type != CONFIG_TYPE_LIST)
1465       && (vector->type != CONFIG_TYPE_GROUP)) || ! list)
1466     return(NULL);
1467
1468   if(idx >= list->length)
1469     return(NULL);
1470
1471   return(list->elements[idx]);
1472 }
1473
1474 /* ------------------------------------------------------------------------- */
1475
1476 config_setting_t *config_setting_get_member(const config_setting_t *setting,
1477                                             const char *name)
1478 {
1479   if(setting->type != CONFIG_TYPE_GROUP)
1480     return(NULL);
1481
1482   return(__config_list_search(setting->value.list, name, NULL));
1483 }
1484
1485 /* ------------------------------------------------------------------------- */
1486
1487 void config_set_destructor(config_t *config, void (*destructor)(void *))
1488 {
1489   config->destructor = destructor;
1490 }
1491
1492 /* ------------------------------------------------------------------------- */
1493
1494 void config_set_include_dir(config_t *config, const char *include_dir)
1495 {
1496   _delete(config->include_dir);
1497   config->include_dir = strdup(include_dir);
1498 }
1499
1500 /* ------------------------------------------------------------------------- */
1501
1502 int config_setting_length(const config_setting_t *setting)
1503 {
1504   if((setting->type != CONFIG_TYPE_GROUP)
1505      && (setting->type != CONFIG_TYPE_ARRAY)
1506      && (setting->type != CONFIG_TYPE_LIST))
1507     return(0);
1508
1509   if(! setting->value.list)
1510     return(0);
1511
1512   return(setting->value.list->length);
1513 }
1514
1515 /* ------------------------------------------------------------------------- */
1516
1517 void config_setting_set_hook(config_setting_t *setting, void *hook)
1518 {
1519   setting->hook = hook;
1520 }
1521
1522 /* ------------------------------------------------------------------------- */
1523
1524 config_setting_t *config_setting_add(config_setting_t *parent,
1525                                      const char *name, int type)
1526 {
1527   if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST))
1528     return(NULL);
1529
1530   if(! parent)
1531     return(NULL);
1532
1533   if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST))
1534     name = NULL;
1535
1536   if(name)
1537   {
1538     if(! __config_validate_name(name))
1539       return(NULL);
1540   }
1541
1542   if(config_setting_get_member(parent, name) != NULL)
1543     return(NULL); /* already exists */
1544
1545   return(config_setting_create(parent, name, type));
1546 }
1547
1548 /* ------------------------------------------------------------------------- */
1549
1550 int config_setting_remove(config_setting_t *parent, const char *name)
1551 {
1552   unsigned int idx;
1553   config_setting_t *setting;
1554
1555   if(! parent)
1556     return(CONFIG_FALSE);
1557
1558   if(parent->type != CONFIG_TYPE_GROUP)
1559     return(CONFIG_FALSE);
1560
1561   if(! (setting = __config_list_search(parent->value.list, name, &idx)))
1562     return(CONFIG_FALSE);
1563
1564   __config_list_remove(parent->value.list, idx);
1565   __config_setting_destroy(setting);
1566
1567   return(CONFIG_TRUE);
1568 }
1569
1570 /* ------------------------------------------------------------------------- */
1571
1572 int config_setting_remove_elem(config_setting_t *parent, unsigned int idx)
1573 {
1574   config_list_t *list;
1575   config_setting_t *removed = NULL;
1576
1577   if(! parent)
1578     return(CONFIG_FALSE);
1579
1580   list = parent->value.list;
1581
1582   if(((parent->type != CONFIG_TYPE_ARRAY)
1583       && (parent->type != CONFIG_TYPE_LIST)
1584       && (parent->type != CONFIG_TYPE_GROUP)) || ! list)
1585     return(CONFIG_FALSE);
1586
1587   if(idx >= list->length)
1588     return(CONFIG_FALSE);
1589
1590   removed = __config_list_remove(list, idx);
1591   __config_setting_destroy(removed);
1592
1593   return(CONFIG_TRUE);
1594 }
1595
1596 /* ------------------------------------------------------------------------- */
1597
1598 int config_setting_index(const config_setting_t *setting)
1599 {
1600   config_setting_t **found = NULL;
1601   config_list_t *list;
1602   int i;
1603
1604   if(! setting->parent)
1605     return(-1);
1606
1607   list = setting->parent->value.list;
1608
1609   for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found)
1610   {
1611     if(*found == setting)
1612       return(i);
1613   }
1614
1615   return(-1);
1616 }
1617
1618 /* ------------------------------------------------------------------------- */
1619 /* eof */