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