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