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