Coverage Report

Created: 2025-11-09 06:53

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