Coverage Report

Created: 2026-10-28 06:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libconfig/lib/libconfig.c
Line
Count
Source
1
/* ----------------------------------------------------------------------------
2
   libconfig - A library for processing structured configuration files
3
   Copyright (C) 2005-2026  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
15.5k
#define PATH_TOKENS ":./"
51
149k
#define CHUNK_SIZE 16
52
2.45k
#define DEFAULT_TAB_WIDTH 2
53
2.45k
#define DEFAULT_FLOAT_PRECISION 6
54
55
/* ------------------------------------------------------------------------- */
56
57
#ifndef LIBCONFIG_STATIC
58
#ifdef LIBCONFIG_WINDOWS_OS
59
60
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
61
{
62
  return(TRUE);
63
}
64
65
#endif /* LIBCONFIG_WINDOWS_OS */
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
79
#ifdef LIBCONFIG_ASSERTS
80
81
static void __config_assert(const char *function, const char *expr)
82
{
83
  fprintf(stderr, "failed assertion in %s(): %s\n", function, expr);
84
  fflush(stderr);
85
  abort();
86
}
87
88
#define config_assert(expr) \
89
  if((expr) == 0) __config_assert(__FUNCTION__, #expr)
90
91
#else
92
93
#define config_assert(expr)
94
95
#endif
96
97
/* ------------------------------------------------------------------------- */
98
99
static void __config_locale_override(void)
100
3.63k
{
101
#if defined(LIBCONFIG_WINDOWS_OS) && !defined(LIBCONFIG_MINGW_OS)
102
103
  _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
104
  setlocale(LC_NUMERIC, "C");
105
106
#elif defined(__APPLE__)
107
108
  locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
109
  uselocale(loc);
110
111
#elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE))
112
113
3.63k
  locale_t loc = newlocale(LC_NUMERIC, "C", NULL);
114
3.63k
  uselocale(loc);
115
116
#else
117
118
#warning "No way to modify calling thread's locale!"
119
120
#endif
121
3.63k
}
122
123
/* ------------------------------------------------------------------------- */
124
125
static void __config_locale_restore(void)
126
3.63k
{
127
#if defined(LIBCONFIG_WINDOWS_OS) && !defined(LIBCONFIG_MINGW_OS)
128
129
    _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
130
131
#elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE))
132
133
3.63k
  locale_t loc = uselocale(LC_GLOBAL_LOCALE);
134
3.63k
  freelocale(loc);
135
136
#else
137
138
#warning "No way to modify calling thread's locale!"
139
140
#endif
141
3.63k
}
142
143
/* ------------------------------------------------------------------------- */
144
145
static void __config_indent(FILE *stream, int depth, unsigned short w)
146
10.5k
{
147
10.5k
  if(w)
148
10.5k
    fprintf(stream, "%*s", (depth - 1) * w, " ");
149
0
  else
150
0
  {
151
0
    int i;
152
0
    for(i = 0; i < (depth - 1); ++i)
153
0
      fputc('\t', stream);
154
0
  }
155
10.5k
}
156
157
/* ------------------------------------------------------------------------- */
158
159
static void __config_write_value(const config_t *config,
160
                                 const config_value_t *value, int type,
161
                                 int format, int depth, FILE *stream)
162
30.5k
{
163
  /* Long enough for 64-bit binary value + NULL terminator. */
164
30.5k
  char value_buf[(sizeof(int64_t) * BITS_IN_BYTE) + 1];
165
166
30.5k
  switch(type)
167
30.5k
  {
168
    /* boolean */
169
747
    case CONFIG_TYPE_BOOL:
170
747
      fputs(value->ival ? "true" : "false", stream);
171
747
      break;
172
173
    /* int */
174
6.62k
    case CONFIG_TYPE_INT:
175
6.62k
      switch(format)
176
6.62k
      {
177
935
        case CONFIG_FORMAT_HEX:
178
935
          fprintf(stream, "0x%X", value->ival);
179
935
          break;
180
181
772
        case CONFIG_FORMAT_BIN:
182
772
        {
183
          /* Once %b/%B become more widely supported, could feature test for them */
184
772
          char *str = libconfig_format_bin((uint32_t)value->ival, value_buf);
185
772
          fprintf(stream, "0b%s", str);
186
772
          break;
187
0
        }
188
189
0
        case CONFIG_FORMAT_OCT:
190
0
          fprintf(stream, "0o%o", value->ival);
191
0
          break;
192
193
4.91k
        case CONFIG_FORMAT_DEFAULT:
194
4.91k
        default:
195
4.91k
          fprintf(stream, "%d", value->ival);
196
4.91k
          break;
197
6.62k
      }
198
6.62k
      break;
199
200
    /* 64-bit int */
201
6.62k
    case CONFIG_TYPE_INT64:
202
2.34k
      switch(format)
203
2.34k
      {
204
369
        case CONFIG_FORMAT_HEX:
205
369
          fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval);
206
369
          break;
207
208
614
        case CONFIG_FORMAT_BIN:
209
614
        {
210
          /* Once %b/%B become more widely supported, could feature test for them */
211
614
          char *str = libconfig_format_bin(value->llval, value_buf);
212
614
          fprintf(stream, "0b%sL", str);
213
614
          break;
214
0
        }
215
216
0
        case CONFIG_FORMAT_OCT:
217
0
          fprintf(stream, "0o%lloL", value->llval);
218
0
          break;
219
220
1.35k
        case CONFIG_FORMAT_DEFAULT:
221
1.35k
        default:
222
1.35k
          fprintf(stream, INT64_FMT "L", value->llval);
223
1.35k
          break;
224
2.34k
      }
225
2.34k
      break;
226
227
    /* float */
228
12.8k
    case CONFIG_TYPE_FLOAT:
229
12.8k
    {
230
12.8k
      const int sci_ok = config_get_option(
231
12.8k
            config, CONFIG_OPTION_ALLOW_SCIENTIFIC_NOTATION);
232
12.8k
      libconfig_format_double(value->fval, config->float_precision, sci_ok,
233
12.8k
                              value_buf, sizeof(value_buf));
234
12.8k
      fputs(value_buf, stream);
235
12.8k
      break;
236
2.34k
    }
237
238
    /* string */
239
1.61k
    case CONFIG_TYPE_STRING:
240
1.61k
    {
241
1.61k
      char *p;
242
243
1.61k
      fputc('\"', stream);
244
245
1.61k
      if(value->sval)
246
1.61k
      {
247
6.05k
        for(p = value->sval; *p; p++)
248
4.43k
        {
249
4.43k
          int c = (int)*p & 0xFF;
250
4.43k
          switch(c)
251
4.43k
          {
252
369
            case '\"':
253
654
            case '\\':
254
654
              fputc('\\', stream);
255
654
              fputc(c, stream);
256
654
              break;
257
258
233
            case '\n':
259
233
              fputs("\\n", stream);
260
233
              break;
261
262
236
            case '\r':
263
236
              fputs("\\r", stream);
264
236
              break;
265
266
229
            case '\f':
267
229
              fputs("\\f", stream);
268
229
              break;
269
270
219
            case '\t':
271
219
              fputs("\\t", stream);
272
219
              break;
273
274
2.86k
            default:
275
2.86k
              if(c >= ' ')
276
2.31k
                fputc(c, stream);
277
547
              else
278
547
                fprintf(stream, "\\x%02X", c);
279
4.43k
          }
280
4.43k
        }
281
1.61k
      }
282
1.61k
      fputc('\"', stream);
283
1.61k
      break;
284
1.61k
    }
285
286
    /* list */
287
1.05k
    case CONFIG_TYPE_LIST:
288
1.05k
    {
289
1.05k
      config_list_t *list = value->list;
290
291
1.05k
      fputs("( ", stream);
292
293
1.05k
      if(list)
294
809
      {
295
809
        int len = list->length;
296
809
        config_setting_t **s;
297
298
13.9k
        for(s = list->elements; len--; s++)
299
13.1k
        {
300
13.1k
          __config_write_value(config, &((*s)->value), (*s)->type,
301
13.1k
                               config_setting_get_format(*s), depth + 1,
302
13.1k
                               stream);
303
304
13.1k
          if(len)
305
12.3k
            fputc(',', stream);
306
307
13.1k
          fputc(' ', stream);
308
13.1k
        }
309
809
      }
310
311
1.05k
      fputc(')', stream);
312
1.05k
      break;
313
1.61k
    }
314
315
    /* array */
316
1.17k
    case CONFIG_TYPE_ARRAY:
317
1.17k
    {
318
1.17k
      config_list_t *list = value->list;
319
320
1.17k
      fputs("[ ", stream);
321
322
1.17k
      if(list)
323
769
      {
324
769
        int len = list->length;
325
769
        config_setting_t **s;
326
327
7.60k
        for(s = list->elements; len--; s++)
328
6.83k
        {
329
6.83k
          __config_write_value(config, &((*s)->value), (*s)->type,
330
6.83k
                               config_setting_get_format(*s), depth + 1,
331
6.83k
                               stream);
332
333
6.83k
          if(len)
334
6.06k
            fputc(',', stream);
335
336
6.83k
          fputc(' ', stream);
337
6.83k
        }
338
769
      }
339
340
1.17k
      fputc(']', stream);
341
1.17k
      break;
342
1.61k
    }
343
344
    /* group */
345
4.05k
    case CONFIG_TYPE_GROUP:
346
4.05k
    {
347
4.05k
      config_list_t *list = value->list;
348
349
4.05k
      if(depth > 0)
350
2.78k
      {
351
2.78k
        if(config_get_option(config, CONFIG_OPTION_OPEN_BRACE_ON_SEPARATE_LINE))
352
2.78k
        {
353
2.78k
          fputc('\n', stream);
354
355
2.78k
          if(depth > 1)
356
2.13k
            __config_indent(stream, depth, config->tab_width);
357
2.78k
        }
358
359
2.78k
        fputs("{\n", stream);
360
2.78k
      }
361
362
4.05k
      if(list)
363
3.45k
      {
364
3.45k
        int len = list->length;
365
3.45k
        config_setting_t **s;
366
367
12.6k
        for(s = list->elements; len--; s++)
368
9.23k
          __config_write_setting(config, *s, stream, depth + 1);
369
3.45k
      }
370
371
4.05k
      if(depth > 1)
372
2.13k
        __config_indent(stream, depth, config->tab_width);
373
374
4.05k
      if(depth > 0)
375
2.78k
        fputc('}', stream);
376
377
4.05k
      break;
378
1.61k
    }
379
380
0
    default:
381
      /* this shouldn't happen, but handle it gracefully... */
382
0
      fputs("???", stream);
383
0
      break;
384
30.5k
  }
385
30.5k
}
386
387
/* ------------------------------------------------------------------------- */
388
389
static void __config_list_add(config_list_t *list, config_setting_t *setting)
390
91.9k
{
391
91.9k
  if((list->length % CHUNK_SIZE) == 0)
392
57.4k
  {
393
57.4k
    list->elements = (config_setting_t **)libconfig_reallocarray(
394
57.4k
      list->elements,
395
57.4k
      libconfig_size_add(list->length, CHUNK_SIZE),
396
57.4k
      sizeof(config_setting_t *));
397
57.4k
  }
398
399
91.9k
  list->elements[list->length] = setting;
400
91.9k
  list->length++;
401
91.9k
}
402
403
/* ------------------------------------------------------------------------- */
404
405
/* This function takes the length of the name to be searched for, so that one
406
 * component of a longer path can be passed in.
407
 */
408
static config_setting_t *__config_list_search(config_list_t *list,
409
                                              const char *name,
410
                                              size_t namelen,
411
                                              unsigned int *idx)
412
18.7k
{
413
18.7k
  config_setting_t **found = NULL;
414
18.7k
  unsigned int i;
415
416
18.7k
  if(! list || ! name)
417
6.03k
    return(NULL);
418
419
84.6k
  for(i = 0, found = list->elements; i < list->length; i++, found++)
420
75.2k
  {
421
75.2k
    if(! (*found)->name)
422
0
      continue;
423
424
75.2k
    if((strlen((*found)->name) == namelen)
425
23.9k
        && !strncmp(name, (*found)->name, namelen))
426
3.23k
    {
427
3.23k
      if(idx)
428
1.27k
        *idx = i;
429
430
3.23k
      return(*found);
431
3.23k
    }
432
75.2k
  }
433
434
9.44k
  return(NULL);
435
12.6k
}
436
437
/* ------------------------------------------------------------------------- */
438
439
static config_setting_t *__config_list_remove(config_list_t *list,
440
                                              unsigned int idx)
441
1.27k
{
442
1.27k
  config_setting_t *removed;
443
1.27k
  size_t count;
444
445
1.27k
  config_assert(idx < list->length);
446
447
1.27k
  removed = list->elements[idx];
448
1.27k
  count = list->length - 1 - idx; /* elements after idx */
449
450
1.27k
  memmove(list->elements + idx, list->elements + idx + 1,
451
1.27k
          count * sizeof(config_setting_t *));
452
453
1.27k
  list->length--;
454
455
  /* possibly realloc smaller? */
456
457
1.27k
  return(removed);
458
1.27k
}
459
460
/* ------------------------------------------------------------------------- */
461
462
static void __config_setting_destroy(config_setting_t *setting)
463
99.2k
{
464
99.2k
  if(setting)
465
96.7k
  {
466
96.7k
    if(setting->name)
467
13.8k
      __delete(setting->name);
468
469
96.7k
    if(setting->type == CONFIG_TYPE_STRING)
470
2.31k
      __delete(setting->value.sval);
471
472
94.4k
    else if(config_setting_is_aggregate(setting))
473
60.4k
    {
474
60.4k
      if(setting->value.list)
475
55.7k
        __config_list_destroy(setting->value.list);
476
60.4k
    }
477
478
96.7k
    if(setting->hook && setting->config->destructor)
479
0
      setting->config->destructor(setting->hook);
480
481
96.7k
    __delete(setting);
482
96.7k
  }
483
99.2k
}
484
485
/* ------------------------------------------------------------------------- */
486
487
static void __config_list_destroy(config_list_t *list)
488
55.7k
{
489
55.7k
  config_setting_t **p;
490
55.7k
  unsigned int i;
491
492
55.7k
  if(! list)
493
0
    return;
494
495
55.7k
  if(list->elements)
496
55.7k
  {
497
146k
    for(p = list->elements, i = 0; i < list->length; p++, i++)
498
90.6k
      __config_setting_destroy(*p);
499
500
55.7k
    __delete(list->elements);
501
55.7k
  }
502
503
55.7k
  __delete(list);
504
55.7k
}
505
506
/* ------------------------------------------------------------------------- */
507
508
static int __config_list_checktype(const config_setting_t *setting, int type)
509
27.2k
{
510
  /* if the array is empty, then it has no type yet */
511
512
27.2k
  if(! setting->value.list)
513
2.12k
    return(CONFIG_TRUE);
514
515
25.1k
  if(setting->value.list->length == 0)
516
0
    return(CONFIG_TRUE);
517
518
  /* if it's a list, any type is allowed */
519
520
25.1k
  if(setting->type == CONFIG_TYPE_LIST)
521
15.5k
    return(CONFIG_TRUE);
522
523
  /* otherwise the first element added determines the type of the array */
524
525
9.53k
  return((setting->value.list->elements[0]->type == type)
526
9.53k
         ? CONFIG_TRUE : CONFIG_FALSE);
527
25.1k
}
528
529
/* ------------------------------------------------------------------------- */
530
531
static int __config_type_is_scalar(int type)
532
0
{
533
0
  return((type >= CONFIG_TYPE_INT) && (type <= CONFIG_TYPE_BOOL));
534
0
}
535
536
/* ------------------------------------------------------------------------- */
537
538
static int __config_validate_name(const char *name)
539
14.4k
{
540
14.4k
  const char *p = name;
541
542
14.4k
  if(*p == '\0')
543
414
    return(CONFIG_FALSE);
544
545
14.0k
  if(! isalpha((int)*p) && (*p != '*'))
546
79
    return(CONFIG_FALSE);
547
548
73.1k
  for(++p; *p; ++p)
549
59.3k
  {
550
59.3k
    if(! (isalpha((int)*p) || isdigit((int)*p) || strchr("*_-", (int)*p)))
551
93
      return(CONFIG_FALSE);
552
59.3k
  }
553
554
13.8k
  return(CONFIG_TRUE);
555
13.9k
}
556
557
/* ------------------------------------------------------------------------- */
558
559
static int __config_read(config_t *config, FILE *stream, const char *filename,
560
                         const char *str)
561
2.35k
{
562
2.35k
  yyscan_t scanner;
563
2.35k
  struct scan_context scan_ctx;
564
2.35k
  struct parse_context parse_ctx;
565
2.35k
  int r;
566
567
2.35k
  config_clear(config);
568
569
2.35k
  libconfig_parsectx_init(&parse_ctx);
570
2.35k
  parse_ctx.config = config;
571
2.35k
  parse_ctx.parent = config->root;
572
2.35k
  parse_ctx.setting = config->root;
573
574
2.35k
  __config_locale_override();
575
576
2.35k
  libconfig_scanctx_init(&scan_ctx, filename);
577
2.35k
  config->root->file = libconfig_scanctx_current_filename(&scan_ctx);
578
2.35k
  scan_ctx.config = config;
579
2.35k
  libconfig_yylex_init_extra(&scan_ctx, &scanner);
580
581
2.35k
  if(stream)
582
0
    libconfig_yyrestart(stream, scanner);
583
2.35k
  else /* read from string */
584
2.35k
    (void)libconfig_yy_scan_string(str, scanner);
585
586
2.35k
  libconfig_yyset_lineno(1, scanner);
587
2.35k
  r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx);
588
589
2.35k
  if(r != 0)
590
488
  {
591
488
    YY_BUFFER_STATE buf;
592
593
488
    config->error_file = libconfig_scanctx_current_filename(&scan_ctx);
594
488
    config->error_type = CONFIG_ERR_PARSE;
595
596
    /* Unwind the include stack, freeing the buffers and closing the files. */
597
488
    while((buf = (YY_BUFFER_STATE)libconfig_scanctx_pop_include(&scan_ctx))
598
488
          != NULL)
599
0
      libconfig_yy_delete_buffer(buf, scanner);
600
488
  }
601
602
2.35k
  libconfig_yylex_destroy(scanner);
603
2.35k
  config->filenames = libconfig_scanctx_cleanup(&scan_ctx);
604
2.35k
  libconfig_parsectx_cleanup(&parse_ctx);
605
606
2.35k
  __config_locale_restore();
607
608
2.35k
  return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE);
609
2.35k
}
610
611
/* ------------------------------------------------------------------------- */
612
613
int config_read(config_t *config, FILE *stream)
614
0
{
615
0
  config_assert(config != NULL);
616
0
  config_assert(stream != NULL);
617
618
0
  return(__config_read(config, stream, NULL, NULL));
619
0
}
620
621
/* ------------------------------------------------------------------------- */
622
623
int config_read_string(config_t *config, const char *str)
624
2.35k
{
625
2.35k
  config_assert(config != NULL);
626
2.35k
  config_assert(str != NULL);
627
628
2.35k
  return(__config_read(config, NULL, NULL, str));
629
2.35k
}
630
631
/* ------------------------------------------------------------------------- */
632
633
static void __config_write_setting(const config_t *config,
634
                                   const config_setting_t *setting,
635
                                   FILE *stream, int depth)
636
10.5k
{
637
10.5k
  char group_assign_char = config_get_option(
638
10.5k
    config, CONFIG_OPTION_COLON_ASSIGNMENT_FOR_GROUPS) ? ':' : '=';
639
640
10.5k
  char nongroup_assign_char = config_get_option(
641
10.5k
    config, CONFIG_OPTION_COLON_ASSIGNMENT_FOR_NON_GROUPS) ? ':' : '=';
642
643
10.5k
  if(depth > 1)
644
6.23k
    __config_indent(stream, depth, config->tab_width);
645
646
647
10.5k
  if(setting->name)
648
9.23k
  {
649
9.23k
    fputs(setting->name, stream);
650
9.23k
    fprintf(stream, " %c ", ((setting->type == CONFIG_TYPE_GROUP)
651
9.23k
                             ? group_assign_char
652
9.23k
                             : nongroup_assign_char));
653
9.23k
  }
654
655
10.5k
  __config_write_value(config, &(setting->value), setting->type,
656
10.5k
                       config_setting_get_format(setting), depth, stream);
657
658
10.5k
  if(depth > 0)
659
9.23k
  {
660
9.23k
    if(config_get_option(config, CONFIG_OPTION_SEMICOLON_SEPARATORS))
661
9.23k
      fputc(';', stream);
662
663
9.23k
    fputc('\n', stream);
664
9.23k
  }
665
10.5k
}
666
667
/* ------------------------------------------------------------------------- */
668
669
void config_write(const config_t *config, FILE *stream)
670
1.27k
{
671
1.27k
  config_assert(config != NULL);
672
1.27k
  config_assert(stream != NULL);
673
674
1.27k
  __config_locale_override();
675
676
1.27k
  __config_write_setting(config, config->root, stream, 0);
677
678
1.27k
  __config_locale_restore();
679
1.27k
}
680
681
/* ------------------------------------------------------------------------- */
682
683
int config_read_file(config_t *config, const char *filename)
684
0
{
685
0
  int ret, ok = 0;
686
0
  FILE *stream;
687
688
0
  config_assert(config != NULL);
689
0
  config_assert(filename != NULL);
690
691
0
  stream = fopen(filename, "rt");
692
0
  if(stream != NULL)
693
0
  {
694
    /* On some operating systems, fopen() succeeds on a directory. */
695
0
    int fd = posix_fileno(stream);
696
0
    struct stat statbuf;
697
698
0
    if(fstat(fd, &statbuf) == 0)
699
0
    {
700
      /* Only proceed if this is not a directory. */
701
0
      if(!S_ISDIR(statbuf.st_mode))
702
0
        ok = 1;
703
0
    }
704
0
  }
705
706
0
  if(!ok)
707
0
  {
708
0
    if(stream != NULL)
709
0
      fclose(stream);
710
711
0
    config->error_text = __io_error;
712
0
    config->error_type = CONFIG_ERR_FILE_IO;
713
0
    return(CONFIG_FALSE);
714
0
  }
715
716
0
  ret = __config_read(config, stream, filename, NULL);
717
0
  fclose(stream);
718
719
0
  return(ret);
720
0
}
721
722
/* ------------------------------------------------------------------------- */
723
724
int config_write_file(config_t *config, const char *filename)
725
0
{
726
0
  FILE *stream;
727
728
0
  config_assert(config != NULL);
729
0
  config_assert(filename != NULL);
730
731
0
  stream = fopen(filename, "wt");
732
0
  if(stream == NULL)
733
0
  {
734
0
    config->error_text = __io_error;
735
0
    config->error_type = CONFIG_ERR_FILE_IO;
736
0
    return(CONFIG_FALSE);
737
0
  }
738
739
0
  config_write(config, stream);
740
741
0
  if(config_get_option(config, CONFIG_OPTION_FSYNC))
742
0
  {
743
0
    int fd = posix_fileno(stream);
744
745
0
    if(fd >= 0)
746
0
    {
747
0
      if(posix_fsync(fd) != 0)
748
0
      {
749
0
        fclose(stream);
750
0
        config->error_text = __io_error;
751
0
        config->error_type = CONFIG_ERR_FILE_IO;
752
0
        return(CONFIG_FALSE);
753
0
      }
754
0
    }
755
0
  }
756
757
0
  fclose(stream);
758
0
  config->error_type = CONFIG_ERR_NONE;
759
0
  return(CONFIG_TRUE);
760
0
}
761
762
/* ------------------------------------------------------------------------- */
763
764
void config_destroy(config_t *config)
765
2.47k
{
766
2.47k
  if(config == NULL)
767
0
    return;
768
769
2.47k
  __config_setting_destroy(config->root);
770
2.47k
  libconfig_strvec_delete(config->filenames);
771
2.47k
  __delete(config->include_dir);
772
2.47k
  __zero(config);
773
2.47k
}
774
775
/* ------------------------------------------------------------------------- */
776
777
void config_clear(config_t *config)
778
4.80k
{
779
4.80k
  config_assert(config != NULL);
780
781
  /* Destroy the root setting (recursively) and then create a new one. */
782
4.80k
  __config_setting_destroy(config->root);
783
784
4.80k
  libconfig_strvec_delete(config->filenames);
785
4.80k
  config->filenames = NULL;
786
787
4.80k
  config->root = __new(config_setting_t);
788
4.80k
  config->root->type = CONFIG_TYPE_GROUP;
789
4.80k
  config->root->config = config;
790
4.80k
}
791
792
/* ------------------------------------------------------------------------- */
793
794
void config_set_tab_width(config_t *config, unsigned short width)
795
0
{
796
0
  config_assert(config != NULL);
797
798
  /* As per documentation: valid range is 0 - 15. */
799
0
  config->tab_width = (width <= 15) ? width : 15;
800
0
}
801
802
/* ------------------------------------------------------------------------- */
803
804
unsigned short config_get_tab_width(const config_t *config)
805
0
{
806
0
  config_assert(config != NULL);
807
808
0
  return(config->tab_width);
809
0
}
810
811
/* ------------------------------------------------------------------------- */
812
813
void config_set_float_precision(config_t *config, unsigned short digits)
814
0
{
815
0
  config_assert(config != NULL);
816
817
0
  config->float_precision = digits;
818
0
}
819
820
/* ------------------------------------------------------------------------- */
821
822
unsigned short config_get_float_precision(const config_t *config)
823
0
{
824
0
  config_assert(config != NULL);
825
826
0
  return(config->float_precision);
827
0
}
828
829
/* ------------------------------------------------------------------------- */
830
831
void config_init(config_t *config)
832
2.45k
{
833
2.45k
  config_assert(config != NULL);
834
835
2.45k
  __zero(config);
836
2.45k
  config_clear(config);
837
838
  /* Set default options. */
839
2.45k
  config->options = (CONFIG_OPTION_SEMICOLON_SEPARATORS
840
2.45k
                     | CONFIG_OPTION_COLON_ASSIGNMENT_FOR_GROUPS
841
2.45k
                     | CONFIG_OPTION_OPEN_BRACE_ON_SEPARATE_LINE);
842
2.45k
  config->tab_width = DEFAULT_TAB_WIDTH;
843
2.45k
  config->float_precision = DEFAULT_FLOAT_PRECISION;
844
2.45k
  config->include_fn = config_default_include_func;
845
2.45k
}
846
847
/* ------------------------------------------------------------------------- */
848
849
void config_set_options(config_t *config, int options)
850
0
{
851
0
  config_assert(config != NULL);
852
853
0
  config->options = options;
854
0
}
855
856
/* ------------------------------------------------------------------------- */
857
858
int config_get_options(const config_t *config)
859
0
{
860
0
  config_assert(config != NULL);
861
862
0
  return(config->options);
863
0
}
864
865
/* ------------------------------------------------------------------------- */
866
867
void config_set_option(config_t *config, int option, int flag)
868
0
{
869
0
  config_assert(config != NULL);
870
871
0
  if(flag)
872
0
    config->options |= option;
873
0
  else
874
0
    config->options &= ~option;
875
0
}
876
877
/* ------------------------------------------------------------------------- */
878
879
int config_get_option(const config_t *config, int option)
880
45.9k
{
881
45.9k
  config_assert(config != NULL);
882
883
45.9k
  return((config->options & option) == option);
884
45.9k
}
885
886
/* ------------------------------------------------------------------------- */
887
888
void config_set_hook(config_t *config, void *hook)
889
0
{
890
0
  config_assert(config != NULL);
891
892
0
  config->hook = hook;
893
0
}
894
895
/* ------------------------------------------------------------------------- */
896
897
void config_set_fatal_error_func(config_fatal_error_fn_t func)
898
0
{
899
0
  libconfig_set_fatal_error_func(func);
900
0
}
901
902
/* ------------------------------------------------------------------------- */
903
904
static config_setting_t *__config_setting_create(config_setting_t *parent,
905
                                                 const char *name, int type)
906
91.9k
{
907
91.9k
  config_setting_t *setting;
908
91.9k
  config_list_t *list;
909
910
91.9k
  if(!config_setting_is_aggregate(parent))
911
0
    return(NULL);
912
913
91.9k
  setting = __new(config_setting_t);
914
91.9k
  setting->parent = parent;
915
91.9k
  setting->name = (name == NULL) ? NULL : libconfig_strdup(name);
916
91.9k
  setting->type = type;
917
91.9k
  setting->config = parent->config;
918
91.9k
  setting->hook = NULL;
919
91.9k
  setting->line = 0;
920
921
91.9k
  list = parent->value.list;
922
923
91.9k
  if(! list)
924
55.7k
    list = parent->value.list = __new(config_list_t);
925
926
91.9k
  __config_list_add(list, setting);
927
928
91.9k
  return(setting);
929
91.9k
}
930
931
/* ------------------------------------------------------------------------- */
932
933
static int __config_setting_get_int(const config_setting_t *setting,
934
                                    int *value)
935
171
{
936
171
  switch(setting->type)
937
171
  {
938
4
    case CONFIG_TYPE_INT:
939
4
      *value = setting->value.ival;
940
4
      return(CONFIG_TRUE);
941
942
160
    case CONFIG_TYPE_INT64:
943
160
      if((setting->value.llval >= INT32_MIN)
944
93
         && (setting->value.llval <= INT32_MAX))
945
74
      {
946
74
        *value = (int)(setting->value.llval);
947
74
        return(CONFIG_TRUE);
948
74
      }
949
86
      else
950
86
        return(CONFIG_FALSE);
951
952
2
    case CONFIG_TYPE_FLOAT:
953
2
      if(config_get_option(setting->config, CONFIG_OPTION_AUTOCONVERT))
954
0
      {
955
0
        *value = (int)(setting->value.fval);
956
0
        return(CONFIG_TRUE);
957
0
      }
958
2
      else
959
2
        return(CONFIG_FALSE);
960
961
5
    default:
962
5
      return(CONFIG_FALSE);
963
171
  }
964
171
}
965
966
/* ------------------------------------------------------------------------- */
967
968
int config_setting_get_int(const config_setting_t *setting)
969
0
{
970
0
  int value = 0;
971
972
0
  config_assert(setting != NULL);
973
974
0
  __config_setting_get_int(setting, &value);
975
0
  return(value);
976
0
}
977
978
/* ------------------------------------------------------------------------- */
979
980
int config_setting_get_int_safe(const config_setting_t *setting, int *value)
981
0
{
982
0
  config_assert(setting != NULL);
983
0
  config_assert(value != NULL);
984
985
0
  return __config_setting_get_int(setting, value);
986
0
}
987
988
/* ------------------------------------------------------------------------- */
989
990
static int __config_setting_get_int64(const config_setting_t *setting,
991
                                      long long *value)
992
10
{
993
10
  switch(setting->type)
994
10
  {
995
1
    case CONFIG_TYPE_INT64:
996
1
      *value = setting->value.llval;
997
1
      return(CONFIG_TRUE);
998
999
3
    case CONFIG_TYPE_INT:
1000
3
      *value = (long long)(setting->value.ival);
1001
3
      return(CONFIG_TRUE);
1002
1003
4
    case CONFIG_TYPE_FLOAT:
1004
4
      if(config_get_option(setting->config, CONFIG_OPTION_AUTOCONVERT))
1005
0
      {
1006
0
        *value = (long long)(setting->value.fval);
1007
0
        return(CONFIG_TRUE);
1008
0
      }
1009
4
      else
1010
4
        return(CONFIG_FALSE);
1011
1012
2
    default:
1013
2
      return(CONFIG_FALSE);
1014
10
  }
1015
10
}
1016
1017
/* ------------------------------------------------------------------------- */
1018
1019
long long config_setting_get_int64(const config_setting_t *setting)
1020
0
{
1021
0
  long long value = 0;
1022
1023
0
  config_assert(setting != NULL);
1024
1025
0
  __config_setting_get_int64(setting, &value);
1026
0
  return(value);
1027
0
}
1028
1029
/* ------------------------------------------------------------------------- */
1030
1031
int config_setting_get_int64_safe(const config_setting_t *setting,
1032
                                  long long *value)
1033
0
{
1034
0
  config_assert(setting != NULL);
1035
0
  config_assert(value != NULL);
1036
1037
0
  return(__config_setting_get_int64(setting, value));
1038
0
}
1039
1040
/* ------------------------------------------------------------------------- */
1041
1042
int config_setting_lookup_int(const config_setting_t *setting,
1043
                              const char *name, int *value)
1044
220
{
1045
220
  config_setting_t *member;
1046
1047
220
  config_assert(setting != NULL);
1048
220
  config_assert(value != NULL);
1049
1050
220
  member = config_setting_get_member(setting, name);
1051
220
  if(! member)
1052
49
    return(CONFIG_FALSE);
1053
1054
171
  return(__config_setting_get_int(member, value));
1055
220
}
1056
1057
/* ------------------------------------------------------------------------- */
1058
1059
int config_setting_lookup_int64(const config_setting_t *setting,
1060
                                const char *name, long long *value)
1061
49
{
1062
49
  config_setting_t *member;
1063
1064
49
  config_assert(setting != NULL);
1065
49
  config_assert(name != NULL);
1066
49
  config_assert(value != NULL);
1067
1068
49
  member = config_setting_get_member(setting, name);
1069
49
  if(! member)
1070
39
    return(CONFIG_FALSE);
1071
1072
10
  return(__config_setting_get_int64(member, value));
1073
49
}
1074
1075
/* ------------------------------------------------------------------------- */
1076
1077
static int __config_setting_get_float(const config_setting_t *setting,
1078
                                      double *value)
1079
11
{
1080
11
  switch(setting->type)
1081
11
  {
1082
4
    case CONFIG_TYPE_FLOAT:
1083
4
      *value = setting->value.fval;
1084
4
      return(CONFIG_TRUE);
1085
1086
3
    case CONFIG_TYPE_INT:
1087
3
      if(config_get_auto_convert(setting->config))
1088
0
      {
1089
0
        *value = (double)(setting->value.ival);
1090
0
        return(CONFIG_TRUE);
1091
0
      }
1092
3
      else
1093
3
        return(CONFIG_FALSE);
1094
1095
1
    case CONFIG_TYPE_INT64:
1096
1
      if(config_get_auto_convert(setting->config))
1097
0
      {
1098
0
        *value = (double)(setting->value.llval);
1099
0
        return(CONFIG_TRUE);
1100
0
      }
1101
1
      else
1102
1
        return(CONFIG_FALSE);
1103
1104
3
    default:
1105
3
      return(CONFIG_FALSE);
1106
11
  }
1107
11
}
1108
1109
/* ------------------------------------------------------------------------- */
1110
1111
double config_setting_get_float(const config_setting_t *setting)
1112
0
{
1113
0
  double value = 0.0;
1114
1115
0
  config_assert(setting != NULL);
1116
1117
0
  __config_setting_get_float(setting, &value);
1118
0
  return(value);
1119
0
}
1120
1121
/* ------------------------------------------------------------------------- */
1122
1123
int config_setting_get_float_safe(const config_setting_t *setting,
1124
                                  double *value)
1125
0
{
1126
0
  return __config_setting_get_float(setting, value);
1127
0
}
1128
1129
/* ------------------------------------------------------------------------- */
1130
1131
int config_setting_lookup_float(const config_setting_t *setting,
1132
                                const char *name, double *value)
1133
64
{
1134
64
  config_setting_t *member;
1135
1136
64
  config_assert(setting != NULL);
1137
64
  config_assert(name != NULL);
1138
64
  config_assert(value != NULL);
1139
1140
64
  member = config_setting_get_member(setting, name);
1141
64
  if(! member)
1142
53
    return(CONFIG_FALSE);
1143
1144
11
  return(__config_setting_get_float(member, value));
1145
64
}
1146
1147
/* ------------------------------------------------------------------------- */
1148
1149
int config_setting_lookup_string(const config_setting_t *setting,
1150
                                 const char *name, const char **value)
1151
52
{
1152
52
  config_setting_t *member;
1153
1154
52
  config_assert(setting != NULL);
1155
52
  config_assert(name != NULL);
1156
52
  config_assert(value != NULL);
1157
1158
52
  member = config_setting_get_member(setting, name);
1159
52
  if(! member)
1160
44
    return(CONFIG_FALSE);
1161
1162
8
  if(config_setting_type(member) != CONFIG_TYPE_STRING)
1163
7
    return(CONFIG_FALSE);
1164
1165
1
  *value = config_setting_get_string(member);
1166
1
  return(CONFIG_TRUE);
1167
8
}
1168
1169
/* ------------------------------------------------------------------------- */
1170
1171
int config_setting_lookup_bool(const config_setting_t *setting,
1172
                               const char *name, int *value)
1173
60
{
1174
60
  config_setting_t *member;
1175
1176
60
  config_assert(setting != NULL);
1177
60
  config_assert(name != NULL);
1178
60
  config_assert(value != NULL);
1179
1180
60
  member = config_setting_get_member(setting, name);
1181
60
  if(! member)
1182
52
    return(CONFIG_FALSE);
1183
1184
8
  if(config_setting_type(member) != CONFIG_TYPE_BOOL)
1185
7
    return(CONFIG_FALSE);
1186
1187
1
  *value = config_setting_get_bool(member);
1188
1
  return(CONFIG_TRUE);
1189
8
}
1190
1191
/* ------------------------------------------------------------------------- */
1192
1193
int config_setting_set_int(config_setting_t *setting, int value)
1194
9.52k
{
1195
9.52k
  config_assert(setting != NULL);
1196
1197
9.52k
  switch(setting->type)
1198
9.52k
  {
1199
4.39k
    case CONFIG_TYPE_NONE:
1200
4.39k
      setting->type = CONFIG_TYPE_INT;
1201
      /* fall through */
1202
1203
9.52k
    case CONFIG_TYPE_INT:
1204
9.52k
      setting->value.ival = value;
1205
9.52k
      return(CONFIG_TRUE);
1206
1207
0
    case CONFIG_TYPE_FLOAT:
1208
0
      if(config_get_auto_convert(setting->config))
1209
0
      {
1210
0
        setting->value.fval = (double)value;
1211
0
        return(CONFIG_TRUE);
1212
0
      }
1213
0
      else
1214
0
        return(CONFIG_FALSE);
1215
1216
0
    default:
1217
0
      return(CONFIG_FALSE);
1218
9.52k
  }
1219
9.52k
}
1220
1221
/* ------------------------------------------------------------------------- */
1222
1223
int config_setting_set_int64(config_setting_t *setting, long long value)
1224
4.37k
{
1225
4.37k
  config_assert(setting != NULL);
1226
1227
4.37k
  switch(setting->type)
1228
4.37k
  {
1229
1.32k
    case CONFIG_TYPE_NONE:
1230
1.32k
      setting->type = CONFIG_TYPE_INT64;
1231
      /* fall through */
1232
1233
4.37k
    case CONFIG_TYPE_INT64:
1234
4.37k
      setting->value.llval = value;
1235
4.37k
      return(CONFIG_TRUE);
1236
1237
0
    case CONFIG_TYPE_INT:
1238
0
      if((value >= INT32_MIN) && (value <= INT32_MAX))
1239
0
      {
1240
0
        setting->value.ival = (int)value;
1241
0
        return(CONFIG_TRUE);
1242
0
      }
1243
0
      else
1244
0
        return(CONFIG_FALSE);
1245
1246
0
    case CONFIG_TYPE_FLOAT:
1247
0
      if(config_get_auto_convert(setting->config))
1248
0
      {
1249
0
        setting->value.fval = (double)value;
1250
0
        return(CONFIG_TRUE);
1251
0
      }
1252
0
      else
1253
0
        return(CONFIG_FALSE);
1254
1255
0
    default:
1256
0
      return(CONFIG_FALSE);
1257
4.37k
  }
1258
4.37k
}
1259
1260
/* ------------------------------------------------------------------------- */
1261
1262
int config_setting_set_float(config_setting_t *setting, double value)
1263
19.1k
{
1264
19.1k
  config_assert(setting != NULL);
1265
1266
19.1k
  switch(setting->type)
1267
19.1k
  {
1268
1.58k
    case CONFIG_TYPE_NONE:
1269
1.58k
      setting->type = CONFIG_TYPE_FLOAT;
1270
      /* fall through */
1271
1272
18.7k
    case CONFIG_TYPE_FLOAT:
1273
18.7k
      setting->value.fval = value;
1274
18.7k
      return(CONFIG_TRUE);
1275
1276
12
    case CONFIG_TYPE_INT:
1277
12
      if(config_get_option(setting->config, CONFIG_OPTION_AUTOCONVERT))
1278
0
      {
1279
0
        setting->value.ival = (int)value;
1280
0
        return(CONFIG_TRUE);
1281
0
      }
1282
12
      else
1283
12
        return(CONFIG_FALSE);
1284
1285
2
    case CONFIG_TYPE_INT64:
1286
2
      if(config_get_option(setting->config, CONFIG_OPTION_AUTOCONVERT))
1287
0
      {
1288
0
        setting->value.llval = (long long)value;
1289
0
        return(CONFIG_TRUE);
1290
0
      }
1291
2
      else
1292
2
        return(CONFIG_FALSE);
1293
1294
434
    default:
1295
434
      return(CONFIG_FALSE);
1296
19.1k
  }
1297
19.1k
}
1298
1299
/* ------------------------------------------------------------------------- */
1300
1301
int config_setting_get_bool(const config_setting_t *setting)
1302
1
{
1303
1
  config_assert(setting != NULL);
1304
1305
1
  return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0);
1306
1
}
1307
1308
/* ------------------------------------------------------------------------- */
1309
1310
int config_setting_get_bool_safe(const config_setting_t *setting,
1311
                                 int *value)
1312
0
{
1313
0
  config_assert(setting != NULL);
1314
0
  config_assert(value != NULL);
1315
1316
0
  if(setting->type == CONFIG_TYPE_BOOL)
1317
0
  {
1318
0
    *value = setting->value.ival;
1319
0
    return(CONFIG_TRUE);
1320
0
  }
1321
1322
0
  return(CONFIG_FALSE);
1323
0
}
1324
1325
/* ------------------------------------------------------------------------- */
1326
1327
int config_setting_set_bool(config_setting_t *setting, int value)
1328
1.26k
{
1329
1.26k
  config_assert(setting != NULL);
1330
1331
1.26k
  if(setting->type == CONFIG_TYPE_NONE)
1332
299
    setting->type = CONFIG_TYPE_BOOL;
1333
970
  else if(setting->type != CONFIG_TYPE_BOOL)
1334
0
    return(CONFIG_FALSE);
1335
1336
1.26k
  setting->value.ival = value;
1337
1.26k
  return(CONFIG_TRUE);
1338
1.26k
}
1339
1340
/* ------------------------------------------------------------------------- */
1341
1342
const char *config_setting_get_string(const config_setting_t *setting)
1343
1
{
1344
1
  config_assert(setting != NULL);
1345
1346
1
  return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL);
1347
1
}
1348
1349
/* ------------------------------------------------------------------------- */
1350
1351
int config_setting_get_string_safe(const config_setting_t *setting,
1352
                                   const char **value)
1353
0
{
1354
0
  config_assert(setting != NULL);
1355
0
  config_assert(value != NULL);
1356
1357
0
  if(setting->type == CONFIG_TYPE_STRING)
1358
0
  {
1359
0
    *value = setting->value.sval;
1360
0
    return(CONFIG_TRUE);
1361
0
  }
1362
1363
0
  return(CONFIG_FALSE);
1364
0
}
1365
1366
/* ------------------------------------------------------------------------- */
1367
1368
int config_setting_set_string(config_setting_t *setting, const char *value)
1369
2.31k
{
1370
2.31k
  config_assert(setting != NULL);
1371
2.31k
  config_assert(value != NULL);
1372
1373
2.31k
  if(setting->type == CONFIG_TYPE_NONE)
1374
535
    setting->type = CONFIG_TYPE_STRING;
1375
1.77k
  else if(setting->type != CONFIG_TYPE_STRING)
1376
0
    return(CONFIG_FALSE);
1377
1378
2.31k
  if(setting->value.sval)
1379
0
    __delete(setting->value.sval);
1380
1381
2.31k
  setting->value.sval = (value == NULL) ? NULL : libconfig_strdup(value);
1382
1383
2.31k
  return(CONFIG_TRUE);
1384
2.31k
}
1385
1386
/* ------------------------------------------------------------------------- */
1387
1388
int config_setting_set_format(config_setting_t *setting, unsigned short format)
1389
13.9k
{
1390
13.9k
  config_assert(setting != NULL);
1391
1392
13.9k
  if(((setting->type != CONFIG_TYPE_INT)
1393
4.37k
      && (setting->type != CONFIG_TYPE_INT64))
1394
13.9k
     || ((format != CONFIG_FORMAT_DEFAULT)
1395
5.82k
         && (format != CONFIG_FORMAT_HEX)
1396
3.17k
         && (format != CONFIG_FORMAT_BIN)))
1397
1.22k
    return(CONFIG_FALSE);
1398
1399
12.6k
  setting->format = format;
1400
1401
12.6k
  return(CONFIG_TRUE);
1402
13.9k
}
1403
1404
/* ------------------------------------------------------------------------- */
1405
1406
unsigned short config_setting_get_format(const config_setting_t *setting)
1407
30.5k
{
1408
30.5k
  config_assert(setting != NULL);
1409
1410
30.5k
  return(setting->format != 0 ? setting->format
1411
30.5k
         : setting->config->default_format);
1412
30.5k
}
1413
1414
/* ------------------------------------------------------------------------- */
1415
1416
const config_setting_t *config_setting_lookup_const(
1417
  const config_setting_t *setting, const char *path)
1418
1.30k
{
1419
1.30k
  const char *p = path;
1420
1.30k
  const config_setting_t *found = setting;
1421
1422
1.30k
  config_assert(setting != NULL);
1423
1.30k
  config_assert(path != NULL);
1424
1425
2.59k
  while(*p && found)
1426
1.30k
  {
1427
1.30k
    if(strchr(PATH_TOKENS, *p))
1428
0
      ++p;
1429
1430
1.30k
    if(*p == '[')
1431
0
    {
1432
0
      char *q;
1433
0
      long index = strtol(++p, &q, 10);
1434
0
      if(*q != ']')
1435
0
        return NULL;
1436
1437
0
      p = ++q;
1438
0
      found = config_setting_get_elem(found, index);
1439
0
    }
1440
1.30k
    else if(found->type == CONFIG_TYPE_GROUP)
1441
1.28k
    {
1442
1.28k
      const char *q = p;
1443
1444
7.78k
      while(*q && !strchr(PATH_TOKENS, *q))
1445
6.49k
        ++q;
1446
1447
1.28k
      found = __config_list_search(found->value.list, p, (size_t)(q - p),
1448
1.28k
                                   NULL);
1449
1.28k
      p = q;
1450
1.28k
    }
1451
19
    else
1452
19
      break;
1453
1.30k
  }
1454
1455
1.30k
  return((*p || (found == setting)) ? NULL : found);
1456
1.30k
}
1457
1458
/* ------------------------------------------------------------------------- */
1459
1460
config_setting_t *config_setting_lookup(const config_setting_t *setting,
1461
                                        const char *path)
1462
1.27k
{
1463
1.27k
  config_assert(setting != NULL);
1464
1.27k
  config_assert(path != NULL);
1465
1466
1.27k
  return((config_setting_t *)config_setting_lookup_const(setting, path));
1467
1.27k
}
1468
1469
/* ------------------------------------------------------------------------- */
1470
1471
config_setting_t *config_lookup(const config_t *config, const char *path)
1472
0
{
1473
0
  config_assert(config != NULL);
1474
0
  config_assert(path != NULL);
1475
1476
0
  return(config_setting_lookup(config->root, path));
1477
0
}
1478
1479
/* ------------------------------------------------------------------------- */
1480
1481
const config_setting_t *config_lookup_const(const config_t *config,
1482
                                            const char *path)
1483
0
{
1484
0
  config_assert(config != NULL);
1485
0
  config_assert(path != NULL);
1486
1487
0
  return(config_setting_lookup(config->root, path));
1488
0
}
1489
1490
/* ------------------------------------------------------------------------- */
1491
1492
int config_lookup_string(const config_t *config, const char *path,
1493
                         const char **value)
1494
0
{
1495
0
  const config_setting_t *s;
1496
1497
0
  config_assert(config != NULL);
1498
0
  config_assert(path != NULL);
1499
0
  config_assert(value != NULL);
1500
1501
0
  s = config_lookup(config, path);
1502
0
  if(! s)
1503
0
    return(CONFIG_FALSE);
1504
1505
0
  if(config_setting_type(s) != CONFIG_TYPE_STRING)
1506
0
    return(CONFIG_FALSE);
1507
1508
0
  *value = config_setting_get_string(s);
1509
1510
0
  return(CONFIG_TRUE);
1511
0
}
1512
1513
/* ------------------------------------------------------------------------- */
1514
1515
int config_lookup_int(const config_t *config, const char *path,
1516
                      int *value)
1517
0
{
1518
0
  const config_setting_t *s;
1519
1520
0
  config_assert(config != NULL);
1521
0
  config_assert(path != NULL);
1522
0
  config_assert(value != NULL);
1523
1524
0
  s = config_lookup(config, path);
1525
0
  if(! s)
1526
0
    return(CONFIG_FALSE);
1527
1528
0
  return(__config_setting_get_int(s, value));
1529
0
}
1530
1531
/* ------------------------------------------------------------------------- */
1532
1533
int config_lookup_int64(const config_t *config, const char *path,
1534
                        long long *value)
1535
0
{
1536
0
  const config_setting_t *s;
1537
1538
0
  config_assert(config != NULL);
1539
0
  config_assert(path != NULL);
1540
0
  config_assert(value != NULL);
1541
1542
0
  s = config_lookup(config, path);
1543
0
  if(! s)
1544
0
    return(CONFIG_FALSE);
1545
1546
0
  return(__config_setting_get_int64(s, value));
1547
0
}
1548
1549
/* ------------------------------------------------------------------------- */
1550
1551
int config_lookup_float(const config_t *config, const char *path,
1552
                        double *value)
1553
0
{
1554
0
  const config_setting_t *s;
1555
1556
0
  config_assert(config != NULL);
1557
0
  config_assert(path != NULL);
1558
0
  config_assert(value != NULL);
1559
1560
0
  s = config_lookup(config, path);
1561
0
  if(! s)
1562
0
    return(CONFIG_FALSE);
1563
1564
0
  return(__config_setting_get_float(s, value));
1565
0
}
1566
1567
/* ------------------------------------------------------------------------- */
1568
1569
int config_lookup_bool(const config_t *config, const char *path, int *value)
1570
0
{
1571
0
  const config_setting_t *s;
1572
1573
0
  config_assert(config != NULL);
1574
0
  config_assert(path != NULL);
1575
0
  config_assert(value != NULL);
1576
1577
0
  s = config_lookup(config, path);
1578
0
  if(! s)
1579
0
    return(CONFIG_FALSE);
1580
1581
0
  if(config_setting_type(s) != CONFIG_TYPE_BOOL)
1582
0
    return(CONFIG_FALSE);
1583
1584
0
  *value = config_setting_get_bool(s);
1585
1586
0
  return(CONFIG_TRUE);
1587
0
}
1588
1589
/* ------------------------------------------------------------------------- */
1590
1591
int config_setting_get_int_elem(const config_setting_t *setting, int idx)
1592
0
{
1593
0
  const config_setting_t *element;
1594
1595
0
  config_assert(setting != NULL);
1596
1597
0
  element = config_setting_get_elem(setting, idx);
1598
1599
0
  return(element ? config_setting_get_int(element) : 0);
1600
0
}
1601
1602
/* ------------------------------------------------------------------------- */
1603
1604
config_setting_t *config_setting_set_int_elem(config_setting_t *setting,
1605
                                              int idx, int value)
1606
5.14k
{
1607
5.14k
  config_setting_t *element = NULL;
1608
1609
5.14k
  config_assert(setting != NULL);
1610
1611
5.14k
  if((setting->type != CONFIG_TYPE_ARRAY)
1612
3.09k
     && (setting->type != CONFIG_TYPE_LIST))
1613
0
    return(NULL);
1614
1615
5.14k
  if(idx < 0)
1616
5.14k
  {
1617
5.14k
    if(! __config_list_checktype(setting, CONFIG_TYPE_INT))
1618
16
      return(NULL);
1619
1620
5.13k
    element = __config_setting_create(setting, NULL, CONFIG_TYPE_INT);
1621
5.13k
  }
1622
0
  else
1623
0
  {
1624
0
    element = config_setting_get_elem(setting, idx);
1625
1626
0
    if(! element)
1627
0
      return(NULL);
1628
0
  }
1629
1630
5.13k
  if(! config_setting_set_int(element, value))
1631
0
    return(NULL);
1632
1633
5.13k
  return(element);
1634
5.13k
}
1635
1636
/* ------------------------------------------------------------------------- */
1637
1638
long long config_setting_get_int64_elem(const config_setting_t *setting,
1639
                                        int idx)
1640
0
{
1641
0
  const config_setting_t *element;
1642
1643
0
  config_assert(setting != NULL);
1644
1645
0
  element = config_setting_get_elem(setting, idx);
1646
1647
0
  return(element ? config_setting_get_int64(element) : 0);
1648
0
}
1649
1650
/* ------------------------------------------------------------------------- */
1651
1652
config_setting_t *config_setting_set_int64_elem(config_setting_t *setting,
1653
                                                int idx, long long value)
1654
3.05k
{
1655
3.05k
  config_setting_t *element = NULL;
1656
1657
3.05k
  config_assert(setting != NULL);
1658
1659
3.05k
  if((setting->type != CONFIG_TYPE_ARRAY)
1660
1.62k
     && (setting->type != CONFIG_TYPE_LIST))
1661
0
    return(NULL);
1662
1663
3.05k
  if(idx < 0)
1664
3.05k
  {
1665
3.05k
    if(! __config_list_checktype(setting, CONFIG_TYPE_INT64))
1666
4
      return(NULL);
1667
1668
3.04k
    element = __config_setting_create(setting, NULL, CONFIG_TYPE_INT64);
1669
3.04k
  }
1670
0
  else
1671
0
  {
1672
0
    element = config_setting_get_elem(setting, idx);
1673
1674
0
    if(! element)
1675
0
      return(NULL);
1676
0
  }
1677
1678
3.04k
  if(! config_setting_set_int64(element, value))
1679
0
    return(NULL);
1680
1681
3.04k
  return(element);
1682
3.04k
}
1683
1684
/* ------------------------------------------------------------------------- */
1685
1686
double config_setting_get_float_elem(const config_setting_t *setting, int idx)
1687
0
{
1688
0
  config_setting_t *element;
1689
1690
0
  config_assert(setting != NULL);
1691
1692
0
  element = config_setting_get_elem(setting, idx);
1693
1694
0
  return(element ? config_setting_get_float(element) : 0.0);
1695
0
}
1696
1697
/* ------------------------------------------------------------------------- */
1698
1699
config_setting_t *config_setting_set_float_elem(config_setting_t *setting,
1700
                                                int idx, double value)
1701
16.2k
{
1702
16.2k
  config_setting_t *element = NULL;
1703
1704
16.2k
  config_assert(setting != NULL);
1705
1706
16.2k
  if((setting->type != CONFIG_TYPE_ARRAY)
1707
10.1k
     && (setting->type != CONFIG_TYPE_LIST))
1708
0
    return(NULL);
1709
1710
16.2k
  if(idx < 0)
1711
16.2k
  {
1712
16.2k
    if(! __config_list_checktype(setting, CONFIG_TYPE_FLOAT))
1713
3
      return(NULL);
1714
1715
16.2k
    element = __config_setting_create(setting, NULL, CONFIG_TYPE_FLOAT);
1716
16.2k
  }
1717
0
  else
1718
0
    element = config_setting_get_elem(setting, idx);
1719
1720
16.2k
  if(! element)
1721
0
    return(NULL);
1722
1723
16.2k
  if(! config_setting_set_float(element, value))
1724
0
    return(NULL);
1725
1726
16.2k
  return(element);
1727
16.2k
}
1728
1729
/* ------------------------------------------------------------------------- */
1730
1731
int config_setting_get_bool_elem(const config_setting_t *setting, int idx)
1732
0
{
1733
0
  config_setting_t *element;
1734
1735
0
  config_assert(setting != NULL);
1736
1737
0
  element = config_setting_get_elem(setting, idx);
1738
1739
0
  if(! element)
1740
0
    return(CONFIG_FALSE);
1741
1742
0
  if(element->type != CONFIG_TYPE_BOOL)
1743
0
    return(CONFIG_FALSE);
1744
1745
0
  return(element->value.ival);
1746
0
}
1747
1748
/* ------------------------------------------------------------------------- */
1749
1750
config_setting_t *config_setting_set_bool_elem(config_setting_t *setting,
1751
                                               int idx, int value)
1752
973
{
1753
973
  config_setting_t *element = NULL;
1754
1755
973
  config_assert(setting != NULL);
1756
1757
973
  if((setting->type != CONFIG_TYPE_ARRAY)
1758
736
     && (setting->type != CONFIG_TYPE_LIST))
1759
0
    return(NULL);
1760
1761
973
  if(idx < 0)
1762
973
  {
1763
973
    if(! __config_list_checktype(setting, CONFIG_TYPE_BOOL))
1764
3
      return(NULL);
1765
1766
970
    element = __config_setting_create(setting, NULL, CONFIG_TYPE_BOOL);
1767
970
  }
1768
0
  else
1769
0
    element = config_setting_get_elem(setting, idx);
1770
1771
970
  if(! element)
1772
0
    return(NULL);
1773
1774
970
  if(! config_setting_set_bool(element, value))
1775
0
    return(NULL);
1776
1777
970
  return(element);
1778
970
}
1779
1780
/* ------------------------------------------------------------------------- */
1781
1782
const char *config_setting_get_string_elem(const config_setting_t *setting,
1783
                                           int idx)
1784
0
{
1785
0
  config_setting_t *element;
1786
1787
0
  config_assert(setting != NULL);
1788
1789
0
  element = config_setting_get_elem(setting, idx);
1790
0
  if(! element)
1791
0
    return(NULL);
1792
1793
0
  if(element->type != CONFIG_TYPE_STRING)
1794
0
    return(NULL);
1795
1796
0
  return(element->value.sval);
1797
0
}
1798
1799
/* ------------------------------------------------------------------------- */
1800
1801
config_setting_t *config_setting_set_string_elem(config_setting_t *setting,
1802
                                                 int idx, const char *value)
1803
1.77k
{
1804
1.77k
  config_setting_t *element = NULL;
1805
1806
1.77k
  config_assert(setting != NULL);
1807
1.77k
  config_assert(value != NULL);
1808
1809
1.77k
  if((setting->type != CONFIG_TYPE_ARRAY)
1810
836
     && (setting->type != CONFIG_TYPE_LIST))
1811
0
    return(NULL);
1812
1813
1.77k
  if(idx < 0)
1814
1.77k
  {
1815
1.77k
    if(! __config_list_checktype(setting, CONFIG_TYPE_STRING))
1816
3
      return(NULL);
1817
1818
1.77k
    element = __config_setting_create(setting, NULL, CONFIG_TYPE_STRING);
1819
1.77k
  }
1820
0
  else
1821
0
    element = config_setting_get_elem(setting, idx);
1822
1823
1.77k
  if(! element)
1824
0
    return(NULL);
1825
1826
1.77k
  if(! config_setting_set_string(element, value))
1827
0
    return(NULL);
1828
1829
1.77k
  return(element);
1830
1.77k
}
1831
1832
/* ------------------------------------------------------------------------- */
1833
1834
config_setting_t *config_setting_get_elem(const config_setting_t *setting,
1835
                                          unsigned int idx)
1836
35.7k
{
1837
35.7k
  config_list_t *list;
1838
1839
35.7k
  config_assert(setting != NULL);
1840
1841
35.7k
  if(! config_setting_is_aggregate(setting))
1842
38
    return(NULL);
1843
1844
35.6k
  list = setting->value.list;
1845
35.6k
  if(! list)
1846
20
    return(NULL);
1847
1848
35.6k
  if(idx >= list->length)
1849
0
    return(NULL);
1850
1851
35.6k
  return(list->elements[idx]);
1852
35.6k
}
1853
1854
/* ------------------------------------------------------------------------- */
1855
1856
config_setting_t *config_setting_get_member(const config_setting_t *setting,
1857
                                            const char *name)
1858
67.0k
{
1859
67.0k
  config_assert(setting != NULL);
1860
1861
67.0k
  if(setting->type != CONFIG_TYPE_GROUP)
1862
50.8k
    return(NULL);
1863
1864
16.1k
  if(!name)
1865
0
    return(NULL);
1866
1867
16.1k
  return(__config_list_search(setting->value.list, name, strlen(name), NULL));
1868
16.1k
}
1869
1870
/* ------------------------------------------------------------------------- */
1871
1872
void config_set_destructor(config_t *config, void (*destructor)(void *))
1873
0
{
1874
0
  config_assert(config != NULL);
1875
1876
0
  config->destructor = destructor;
1877
0
}
1878
1879
/* ------------------------------------------------------------------------- */
1880
1881
void config_set_include_dir(config_t *config, const char *include_dir)
1882
0
{
1883
0
  config_assert(config != NULL);
1884
1885
0
  __delete(config->include_dir);
1886
0
  config->include_dir = include_dir ? libconfig_strdup(include_dir) : NULL;
1887
0
}
1888
1889
/* ------------------------------------------------------------------------- */
1890
1891
void config_set_include_func(config_t *config, config_include_fn_t func)
1892
0
{
1893
0
  config_assert(config != NULL);
1894
1895
0
  config->include_fn = func ? func : config_default_include_func;
1896
0
}
1897
1898
/* ------------------------------------------------------------------------- */
1899
1900
int config_setting_length(const config_setting_t *setting)
1901
7.80k
{
1902
7.80k
  config_assert(setting != NULL);
1903
1904
7.80k
  if(! config_setting_is_aggregate(setting))
1905
38
    return(0);
1906
1907
7.77k
  if(! setting->value.list)
1908
1.81k
    return(0);
1909
1910
5.96k
  return(setting->value.list->length);
1911
7.77k
}
1912
1913
/* ------------------------------------------------------------------------- */
1914
1915
void config_setting_set_hook(config_setting_t *setting, void *hook)
1916
0
{
1917
0
  config_assert(setting != NULL);
1918
1919
0
  setting->hook = hook;
1920
0
}
1921
1922
/* ------------------------------------------------------------------------- */
1923
1924
config_setting_t *config_setting_add(config_setting_t *parent,
1925
                                     const char *name, int type)
1926
65.3k
{
1927
65.3k
  if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST))
1928
0
    return(NULL);
1929
1930
65.3k
  if(! parent)
1931
0
    return(NULL);
1932
1933
65.3k
  if((parent->type == CONFIG_TYPE_ARRAY) && !__config_type_is_scalar(type))
1934
0
    return(NULL); /* only scalars can be added to arrays */
1935
1936
65.3k
  if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST))
1937
50.8k
    name = NULL;
1938
1939
65.3k
  if(name)
1940
14.4k
  {
1941
14.4k
    if(! __config_validate_name(name))
1942
586
      return(NULL);
1943
14.4k
  }
1944
1945
64.7k
  if(config_setting_get_member(parent, name) != NULL)
1946
15
  {
1947
15
    if(config_get_option(parent->config, CONFIG_OPTION_ALLOW_OVERRIDES))
1948
0
      config_setting_remove(parent, name);
1949
15
    else
1950
15
      return(NULL); /* already exists */
1951
15
  }
1952
1953
64.7k
  return(__config_setting_create(parent, name, type));
1954
64.7k
}
1955
1956
/* ------------------------------------------------------------------------- */
1957
1958
int config_setting_remove(config_setting_t *parent, const char *name)
1959
1.27k
{
1960
1.27k
  unsigned int idx;
1961
1.27k
  config_setting_t *setting;
1962
1.27k
  const char *settingName;
1963
1.27k
  const char *lastFound;
1964
1965
1.27k
  if(! parent || !name)
1966
0
    return(CONFIG_FALSE);
1967
1968
1.27k
  if(parent->type != CONFIG_TYPE_GROUP)
1969
0
    return(CONFIG_FALSE);
1970
1971
1.27k
  setting = config_setting_lookup(parent, name);
1972
1.27k
  if(! setting)
1973
0
    return(CONFIG_FALSE);
1974
1975
1.27k
  settingName = name;
1976
1.27k
  do
1977
1.27k
  {
1978
1.27k
    lastFound = settingName;
1979
7.73k
    while(settingName && !strchr(PATH_TOKENS, *settingName))
1980
6.46k
      ++settingName;
1981
1982
1.27k
    if(*settingName == '\0')
1983
1.27k
    {
1984
1.27k
      settingName = lastFound;
1985
1.27k
      break;
1986
1.27k
    }
1987
1988
1.27k
  }
1989
1.27k
  while(*++settingName);
1990
1991
1.27k
  if(!(setting = __config_list_search(setting->parent->value.list, settingName,
1992
1.27k
                                      strlen(settingName), &idx)))
1993
0
    return(CONFIG_FALSE);
1994
1995
1.27k
  __config_list_remove(setting->parent->value.list, idx);
1996
1.27k
  __config_setting_destroy(setting);
1997
1998
1.27k
  return(CONFIG_TRUE);
1999
1.27k
}
2000
2001
/* ------------------------------------------------------------------------- */
2002
2003
int config_setting_remove_elem(config_setting_t *parent, unsigned int idx)
2004
0
{
2005
0
  config_list_t *list;
2006
0
  config_setting_t *removed = NULL;
2007
2008
0
  if(! parent)
2009
0
    return(CONFIG_FALSE);
2010
2011
0
  if(! config_setting_is_aggregate(parent))
2012
0
    return(CONFIG_FALSE);
2013
2014
0
  list = parent->value.list;
2015
0
  if(! list)
2016
0
    return(CONFIG_FALSE);
2017
2018
0
  if(idx >= list->length)
2019
0
    return(CONFIG_FALSE);
2020
2021
0
  removed = __config_list_remove(list, idx);
2022
0
  __config_setting_destroy(removed);
2023
2024
0
  return(CONFIG_TRUE);
2025
0
}
2026
2027
/* ------------------------------------------------------------------------- */
2028
2029
int config_setting_index(const config_setting_t *setting)
2030
0
{
2031
0
  config_setting_t **found = NULL;
2032
0
  config_list_t *list;
2033
0
  int i;
2034
2035
0
  if(! setting->parent)
2036
0
    return(-1);
2037
2038
0
  list = setting->parent->value.list;
2039
2040
0
  for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found)
2041
0
  {
2042
0
    if(*found == setting)
2043
0
      return(i);
2044
0
  }
2045
2046
0
  return(-1);
2047
0
}
2048
2049
/* ------------------------------------------------------------------------- */
2050
2051
const char **config_default_include_func(config_t *config,
2052
                                         const char *include_dir,
2053
                                         const char *path,
2054
                                         const char **error)
2055
0
{
2056
0
  char *file;
2057
0
  const char **files;
2058
2059
0
  config_assert(config != NULL);
2060
0
  config_assert(path != NULL);
2061
2062
0
  if(include_dir && IS_RELATIVE_PATH(path))
2063
0
  {
2064
0
    size_t dirlen = strlen(include_dir);
2065
0
    size_t seplen = strlen(FILE_SEPARATOR);
2066
0
    size_t pathlen = strlen(path);
2067
2068
0
    file = (char *)libconfig_malloc(
2069
0
      libconfig_size_add(libconfig_size_add(dirlen, seplen),
2070
0
                         libconfig_size_add(pathlen, 1))); /* add 1 for NUL */
2071
0
    memcpy(file, include_dir, dirlen);
2072
0
    memcpy(file + dirlen, FILE_SEPARATOR, seplen);
2073
0
    memcpy(file + dirlen + seplen, path, pathlen + 1); /* include NUL */
2074
0
  }
2075
0
  else
2076
0
    file = libconfig_strdup(path);
2077
2078
0
  *error = NULL;
2079
2080
0
  files = (const char **)libconfig_calloc(2, sizeof(const char *));
2081
0
  files[0] = file;
2082
0
  files[1] = NULL;
2083
2084
0
  return(files);
2085
0
}
2086
2087
/* ------------------------------------------------------------------------- */
2088
2089
int config_setting_is_scalar(const config_setting_t *setting)
2090
0
{
2091
0
  config_assert(setting != NULL);
2092
2093
0
  return(__config_type_is_scalar(setting->type));
2094
0
}
2095
2096
/* ------------------------------------------------------------------------- */
2097
2098
int config_setting_is_aggregate(const config_setting_t *setting)
2099
229k
{
2100
229k
  config_assert(setting != NULL);
2101
2102
229k
  return((setting->type == CONFIG_TYPE_ARRAY)
2103
205k
         || (setting->type == CONFIG_TYPE_LIST)
2104
69.7k
         || (setting->type == CONFIG_TYPE_GROUP));
2105
229k
}
2106
2107
/* ------------------------------------------------------------------------- */