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