Coverage Report

Created: 2026-05-16 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libucl/src/ucl_util.c
Line
Count
Source
1
/* Copyright (c) 2013, Vsevolod Stakhov
2
 * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *       * Redistributions of source code must retain the above copyright
8
 *         notice, this list of conditions and the following disclaimer.
9
 *       * Redistributions in binary form must reproduce the above copyright
10
 *         notice, this list of conditions and the following disclaimer in the
11
 *         documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 */
24
25
#include "ucl.h"
26
#include "ucl_internal.h"
27
#include "ucl_chartable.h"
28
#include "kvec.h"
29
#include <limits.h>
30
#include <stdarg.h>
31
#include <stdio.h> /* for snprintf */
32
33
#ifndef _WIN32
34
#include <glob.h>
35
#include <sys/param.h>
36
#else
37
#ifndef NBBY
38
#define NBBY 8
39
#endif
40
#endif
41
42
#ifdef HAVE_LIBGEN_H
43
#ifndef _WIN32
44
#include <libgen.h> /* For dirname */
45
#endif
46
#endif
47
48
typedef kvec_t(ucl_object_t *) ucl_array_t;
49
50
2.76M
#define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \
51
2.76M
                   (ucl_array_t *) ((obj) != NULL ? (obj)->value.av : NULL)
52
53
#ifdef HAVE_OPENSSL
54
#include <openssl/err.h>
55
#include <openssl/sha.h>
56
#include <openssl/rsa.h>
57
#include <openssl/ssl.h>
58
#include <openssl/evp.h>
59
#endif
60
61
#ifdef CURL_FOUND
62
/* Seems to be broken */
63
#define CURL_DISABLE_TYPECHECK 1
64
#include <curl/curl.h>
65
#endif
66
#ifdef HAVE_FETCH_H
67
#include <fetch.h>
68
#endif
69
70
#if defined(_WIN32)
71
#include <windows.h>
72
#include <io.h>
73
#include <direct.h>
74
75
#ifndef PROT_READ
76
#define PROT_READ 1
77
#endif
78
#ifndef PROT_WRITE
79
#define PROT_WRITE 2
80
#endif
81
#ifndef PROT_READWRITE
82
#define PROT_READWRITE 3
83
#endif
84
#ifndef MAP_SHARED
85
#define MAP_SHARED 1
86
#endif
87
#ifndef MAP_PRIVATE
88
#define MAP_PRIVATE 2
89
#endif
90
#ifndef MAP_FAILED
91
#define MAP_FAILED ((void *) -1)
92
#endif
93
94
#define getcwd _getcwd
95
#define open _open
96
#define close _close
97
98
static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
99
{
100
  void *map = NULL;
101
  HANDLE handle = INVALID_HANDLE_VALUE;
102
103
  switch (prot) {
104
  default:
105
  case PROT_READ: {
106
    handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
107
    if (!handle) break;
108
    map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
109
    CloseHandle(handle);
110
    break;
111
  }
112
  case PROT_WRITE: {
113
    handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
114
    if (!handle) break;
115
    map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
116
    CloseHandle(handle);
117
    break;
118
  }
119
  case PROT_READWRITE: {
120
    handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
121
    if (!handle) break;
122
    map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
123
    CloseHandle(handle);
124
    break;
125
  }
126
  }
127
  if (map == (void *) NULL) {
128
    return (void *) MAP_FAILED;
129
  }
130
  return (void *) ((char *) map + offset);
131
}
132
133
static int ucl_munmap(void *map, size_t length)
134
{
135
  if (!UnmapViewOfFile(map)) {
136
    return (-1);
137
  }
138
  return (0);
139
}
140
141
static char *ucl_realpath(const char *path, char *resolved_path)
142
{
143
  char *p;
144
  char tmp[MAX_PATH + 1];
145
  strncpy(tmp, path, sizeof(tmp) - 1);
146
  p = tmp;
147
  while (*p) {
148
    if (*p == '/') *p = '\\';
149
    p++;
150
  }
151
  return _fullpath(resolved_path, tmp, MAX_PATH);
152
}
153
154
155
char *dirname(char *path)
156
{
157
  static char path_buffer[_MAX_PATH];
158
  char drive[_MAX_DRIVE];
159
  char dir[_MAX_DIR];
160
  char fname[_MAX_FNAME];
161
  char ext[_MAX_EXT];
162
163
  _splitpath(path, drive, dir, fname, ext);
164
  _makepath(path_buffer, drive, dir, NULL, NULL);
165
166
  return path_buffer;
167
}
168
169
char *basename(char *path)
170
{
171
  static char path_buffer[_MAX_PATH];
172
  char drive[_MAX_DRIVE];
173
  char dir[_MAX_DIR];
174
  char fname[_MAX_FNAME];
175
  char ext[_MAX_EXT];
176
177
  _splitpath(path, drive, dir, fname, ext);
178
  _makepath(path_buffer, NULL, NULL, fname, ext);
179
180
  return path_buffer;
181
}
182
#else
183
393
#define ucl_mmap mmap
184
393
#define ucl_munmap munmap
185
562k
#define ucl_realpath realpath
186
#endif
187
188
typedef void (*ucl_object_dtor)(ucl_object_t *obj);
189
static void ucl_object_free_internal(ucl_object_t *obj, bool allow_rec,
190
                   ucl_object_dtor dtor);
191
static void ucl_object_dtor_unref(ucl_object_t *obj);
192
193
static void
194
ucl_object_dtor_free(ucl_object_t *obj)
195
1.01M
{
196
1.01M
  if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
197
140k
    UCL_FREE(obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
198
140k
  }
199
1.01M
  if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
200
875k
    UCL_FREE(obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
201
875k
  }
202
  /* Do not free ephemeral objects */
203
1.01M
  if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
204
1.01M
    if (obj->type != UCL_USERDATA) {
205
1.01M
      UCL_FREE(sizeof(ucl_object_t), obj);
206
1.01M
    }
207
0
    else {
208
0
      struct ucl_object_userdata *ud = (struct ucl_object_userdata *) obj;
209
0
      if (ud->dtor) {
210
0
        ud->dtor(obj->value.ud);
211
0
      }
212
0
      UCL_FREE(sizeof(*ud), obj);
213
0
    }
214
1.01M
  }
215
1.01M
}
216
217
/*
218
 * This is a helper function that performs exactly the same as
219
 * `ucl_object_unref` but it doesn't iterate over elements allowing
220
 * to use it for individual elements of arrays and multiple values
221
 */
222
static void
223
ucl_object_dtor_unref_single(ucl_object_t *obj)
224
990k
{
225
990k
  if (obj != NULL) {
226
990k
#ifdef HAVE_ATOMIC_BUILTINS
227
990k
    unsigned int rc = __sync_sub_and_fetch(&obj->ref, 1);
228
990k
    if (rc == 0) {
229
#else
230
    if (--obj->ref == 0) {
231
#endif
232
990k
      ucl_object_free_internal(obj, false, ucl_object_dtor_unref);
233
990k
    }
234
990k
  }
235
990k
}
236
237
static void
238
ucl_object_dtor_unref(ucl_object_t *obj)
239
2.00M
{
240
2.00M
  if (obj->ref == 0) {
241
1.01M
    ucl_object_dtor_free(obj);
242
1.01M
  }
243
990k
  else {
244
    /* This may cause dtor unref being called one more time */
245
990k
    ucl_object_dtor_unref_single(obj);
246
990k
  }
247
2.00M
}
248
249
static void
250
ucl_object_free_internal(ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
251
1.01M
{
252
1.01M
  ucl_object_t *tmp, *sub;
253
254
1.04M
  while (obj != NULL) {
255
1.01M
    if (obj->type == UCL_ARRAY) {
256
21.7k
      UCL_ARRAY_GET(vec, obj);
257
21.7k
      unsigned int i;
258
259
21.7k
      if (vec != NULL) {
260
871k
        for (i = 0; i < vec->n; i++) {
261
850k
          sub = kv_A(*vec, i);
262
850k
          if (sub != NULL) {
263
850k
            tmp = sub;
264
1.70M
            while (sub) {
265
850k
              tmp = sub->next;
266
850k
              dtor(sub);
267
850k
              sub = tmp;
268
850k
            }
269
850k
          }
270
850k
        }
271
21.7k
        kv_destroy(*vec);
272
21.7k
        UCL_FREE(sizeof(*vec), vec);
273
21.7k
      }
274
21.7k
      obj->value.av = NULL;
275
21.7k
    }
276
997k
    else if (obj->type == UCL_OBJECT) {
277
107k
      if (obj->value.ov != NULL) {
278
106k
        ucl_hash_destroy(obj->value.ov, (ucl_hash_free_func) dtor);
279
106k
      }
280
107k
      obj->value.ov = NULL;
281
107k
    }
282
1.01M
    tmp = obj->next;
283
1.01M
    dtor(obj);
284
1.01M
    obj = tmp;
285
286
1.01M
    if (!allow_rec) {
287
990k
      break;
288
990k
    }
289
1.01M
  }
290
1.01M
}
291
292
void ucl_object_free(ucl_object_t *obj)
293
0
{
294
0
  ucl_object_free_internal(obj, true, ucl_object_dtor_free);
295
0
}
296
297
size_t
298
ucl_unescape_json_string(char *str, size_t len)
299
2.17k
{
300
2.17k
  char *t = str, *h = str;
301
2.17k
  int i, uval;
302
303
2.17k
  if (len <= 1) {
304
5
    return len;
305
5
  }
306
  /* t is target (tortoise), h is source (hare) */
307
308
4.12M
  while (len) {
309
4.12M
    if (*h == '\\') {
310
570k
      h++;
311
312
570k
      if (len == 1) {
313
        /*
314
         * If \ is last, then do not try to go further
315
         * Issue: #74
316
         */
317
2
        len--;
318
2
        *t++ = '\\';
319
2
        continue;
320
2
      }
321
322
570k
      switch (*h) {
323
0
      case 'n':
324
0
        *t++ = '\n';
325
0
        break;
326
6
      case 'r':
327
6
        *t++ = '\r';
328
6
        break;
329
0
      case 'b':
330
0
        *t++ = '\b';
331
0
        break;
332
2
      case 't':
333
2
        *t++ = '\t';
334
2
        break;
335
5
      case 'f':
336
5
        *t++ = '\f';
337
5
        break;
338
588
      case '\\':
339
588
        *t++ = '\\';
340
588
        break;
341
1.67k
      case '"':
342
1.67k
        *t++ = '"';
343
1.67k
        break;
344
561k
      case 'u':
345
        /* Unicode escape */
346
561k
        uval = 0;
347
561k
        h++; /* u character */
348
561k
        len--;
349
350
561k
        if (len > 3) {
351
1.68M
          for (i = 0; i < 4; i++) {
352
1.68M
            uval <<= 4;
353
1.68M
            if (isdigit(h[i])) {
354
88
              uval += h[i] - '0';
355
88
            }
356
1.68M
            else if (h[i] >= 'a' && h[i] <= 'f') {
357
1.12M
              uval += h[i] - 'a' + 10;
358
1.12M
            }
359
563k
            else if (h[i] >= 'A' && h[i] <= 'F') {
360
2.15k
              uval += h[i] - 'A' + 10;
361
2.15k
            }
362
561k
            else {
363
561k
              break;
364
561k
            }
365
1.68M
          }
366
367
          /* Encode */
368
561k
          if (uval < 0x80) {
369
167
            t[0] = (char) uval;
370
167
            t++;
371
167
          }
372
561k
          else if (uval < 0x800) {
373
143
            t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
374
143
            t[1] = 0x80 + ((uval & 0x03F));
375
143
            t += 2;
376
143
          }
377
561k
          else if (uval < 0x10000) {
378
561k
            t[0] = 0xE0 + ((uval & 0xF000) >> 12);
379
561k
            t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
380
561k
            t[2] = 0x80 + ((uval & 0x003F));
381
561k
            t += 3;
382
561k
          }
383
#if 0
384
          /* It's not actually supported now */
385
          else if(uval <= 0x10FFFF) {
386
            t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
387
            t[1] = 0x80 + ((uval & 0x03F000) >> 12);
388
            t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
389
            t[3] = 0x80 + ((uval & 0x00003F));
390
            t += 4;
391
          }
392
#endif
393
0
          else {
394
0
            *t++ = '?';
395
0
          }
396
397
          /* Consume 4 characters of source */
398
561k
          h += 4;
399
561k
          len -= 4;
400
401
561k
          if (len > 0) {
402
561k
            len--; /* for '\' character */
403
561k
          }
404
561k
          continue;
405
561k
        }
406
120
        else {
407
120
          *t++ = 'u';
408
120
        }
409
120
        break;
410
6.69k
      default:
411
6.69k
        *t++ = *h;
412
6.69k
        break;
413
570k
      }
414
9.09k
      h++;
415
9.09k
      len--;
416
9.09k
    }
417
3.55M
    else {
418
3.55M
      *t++ = *h++;
419
3.55M
    }
420
421
3.56M
    if (len > 0) {
422
3.56M
      len--;
423
3.56M
    }
424
3.56M
  }
425
2.16k
  *t = '\0';
426
427
2.16k
  return (t - str);
428
2.16k
}
429
430
size_t
431
ucl_unescape_squoted_string(char *str, size_t len)
432
2
{
433
2
  char *t = str, *h = str;
434
435
2
  if (len <= 1) {
436
0
    return len;
437
0
  }
438
439
  /* t is target (tortoise), h is source (hare) */
440
441
794k
  while (len) {
442
793k
    if (*h == '\\') {
443
24.4k
      h++;
444
445
24.4k
      if (len == 1) {
446
        /*
447
         * If \ is last, then do not try to go further
448
         * Issue: #74
449
         */
450
0
        len--;
451
0
        *t++ = '\\';
452
0
        continue;
453
0
      }
454
455
24.4k
      switch (*h) {
456
0
      case '\'':
457
0
        *t++ = '\'';
458
0
        break;
459
189
      case '\n':
460
        /* Ignore \<newline> style stuff */
461
189
        break;
462
0
      case '\r':
463
        /* Ignore \r and the following \n if needed */
464
0
        if (len > 1 && h[1] == '\n') {
465
0
          h++;
466
0
          len--;
467
0
        }
468
0
        break;
469
24.2k
      default:
470
        /* Ignore \ */
471
24.2k
        *t++ = '\\';
472
24.2k
        *t++ = *h;
473
24.2k
        break;
474
24.4k
      }
475
476
24.4k
      h++;
477
24.4k
      len--;
478
24.4k
    }
479
769k
    else {
480
769k
      *t++ = *h++;
481
769k
    }
482
483
793k
    if (len > 0) {
484
793k
      len--;
485
793k
    }
486
793k
  }
487
488
2
  *t = '\0';
489
490
2
  return (t - str);
491
2
}
492
493
char *
494
ucl_copy_key_trash(const ucl_object_t *obj)
495
1.06k
{
496
1.06k
  ucl_object_t *deconst;
497
498
1.06k
  if (obj == NULL) {
499
0
    return NULL;
500
0
  }
501
1.06k
  if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
502
1.06k
    deconst = __DECONST(ucl_object_t *, obj);
503
1.06k
    deconst->trash_stack[UCL_TRASH_KEY] = malloc(obj->keylen + 1);
504
1.06k
    if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
505
1.06k
      memcpy(deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
506
1.06k
      deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
507
1.06k
    }
508
1.06k
    deconst->key = obj->trash_stack[UCL_TRASH_KEY];
509
1.06k
    deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
510
1.06k
  }
511
512
1.06k
  return obj->trash_stack[UCL_TRASH_KEY];
513
1.06k
}
514
515
void ucl_chunk_free(struct ucl_chunk *chunk)
516
30.5k
{
517
30.5k
  if (chunk) {
518
30.5k
    struct ucl_parser_special_handler_chain *chain, *tmp;
519
520
30.5k
    LL_FOREACH_SAFE(chunk->special_handlers, chain, tmp)
521
0
    {
522
0
      if (chain->special_handler->free_function) {
523
0
        chain->special_handler->free_function(
524
0
          chain->begin,
525
0
          chain->len,
526
0
          chain->special_handler->user_data);
527
0
      }
528
0
      else {
529
0
        UCL_FREE(chain->len, chain->begin);
530
0
      }
531
532
0
      UCL_FREE(sizeof(*chain), chain);
533
0
    }
534
535
30.5k
    chunk->special_handlers = NULL;
536
537
30.5k
    if (chunk->fname) {
538
1.08k
      free(chunk->fname);
539
1.08k
    }
540
541
30.5k
    UCL_FREE(sizeof(*chunk), chunk);
542
30.5k
  }
543
30.5k
}
544
545
char *
546
ucl_copy_value_trash(const ucl_object_t *obj)
547
572k
{
548
572k
  ucl_object_t *deconst;
549
550
572k
  if (obj == NULL) {
551
12
    return NULL;
552
12
  }
553
572k
  if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
554
0
    deconst = __DECONST(ucl_object_t *, obj);
555
0
    if (obj->type == UCL_STRING) {
556
557
      /* Special case for strings */
558
0
      if (obj->flags & UCL_OBJECT_BINARY) {
559
0
        deconst->trash_stack[UCL_TRASH_VALUE] = malloc(obj->len);
560
0
        if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
561
0
          memcpy(deconst->trash_stack[UCL_TRASH_VALUE],
562
0
               obj->value.sv,
563
0
               obj->len);
564
0
          deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
565
0
        }
566
0
      }
567
0
      else {
568
0
        deconst->trash_stack[UCL_TRASH_VALUE] = malloc(obj->len + 1);
569
0
        if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
570
0
          memcpy(deconst->trash_stack[UCL_TRASH_VALUE],
571
0
               obj->value.sv,
572
0
               obj->len);
573
0
          deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
574
0
          deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
575
0
        }
576
0
      }
577
0
    }
578
0
    else {
579
      /* Just emit value in json notation */
580
0
      deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json(obj);
581
0
      deconst->len = strlen(obj->trash_stack[UCL_TRASH_VALUE]);
582
0
    }
583
0
    deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
584
0
  }
585
586
572k
  return obj->trash_stack[UCL_TRASH_VALUE];
587
572k
}
588
589
ucl_object_t *
590
ucl_parser_get_object(struct ucl_parser *parser)
591
9.79k
{
592
9.79k
  if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
593
9.79k
    return ucl_object_ref(parser->top_obj);
594
9.79k
  }
595
596
0
  return NULL;
597
9.79k
}
598
599
void ucl_parser_free(struct ucl_parser *parser)
600
29.5k
{
601
29.5k
  struct ucl_stack *stack, *stmp;
602
29.5k
  struct ucl_macro *macro, *mtmp;
603
29.5k
  struct ucl_chunk *chunk, *ctmp;
604
29.5k
  struct ucl_pubkey *key, *ktmp;
605
29.5k
  struct ucl_variable *var, *vtmp;
606
29.5k
  ucl_object_t *tr, *trtmp;
607
608
29.5k
  if (parser == NULL) {
609
0
    return;
610
0
  }
611
612
29.5k
  if (parser->top_obj != NULL) {
613
28.3k
    ucl_object_unref(parser->top_obj);
614
28.3k
  }
615
616
29.5k
  if (parser->includepaths != NULL) {
617
2
    ucl_object_unref(parser->includepaths);
618
2
  }
619
620
29.5k
  LL_FOREACH_SAFE(parser->stack, stack, stmp)
621
122k
  {
622
122k
    free(stack);
623
122k
  }
624
29.5k
  HASH_ITER(hh, parser->macroes, macro, mtmp)
625
177k
  {
626
177k
    free(macro->name);
627
177k
    HASH_DEL(parser->macroes, macro);
628
177k
    UCL_FREE(sizeof(struct ucl_macro), macro);
629
177k
  }
630
29.5k
  LL_FOREACH_SAFE(parser->chunks, chunk, ctmp)
631
29.5k
  {
632
29.5k
    ucl_chunk_free(chunk);
633
29.5k
  }
634
29.5k
  LL_FOREACH_SAFE(parser->keys, key, ktmp)
635
0
  {
636
0
    UCL_FREE(sizeof(struct ucl_pubkey), key);
637
0
  }
638
29.5k
  LL_FOREACH_SAFE(parser->variables, var, vtmp)
639
59.0k
  {
640
59.0k
    free(var->value);
641
59.0k
    free(var->var);
642
59.0k
    UCL_FREE(sizeof(struct ucl_variable), var);
643
59.0k
  }
644
29.5k
  LL_FOREACH_SAFE(parser->trash_objs, tr, trtmp)
645
36
  {
646
36
    ucl_object_free_internal(tr, false, ucl_object_dtor_free);
647
36
  }
648
649
29.5k
  if (parser->err != NULL) {
650
19.6k
    utstring_free(parser->err);
651
19.6k
  }
652
653
29.5k
  if (parser->cur_file) {
654
0
    UCL_FREE(strlen(parser->cur_file) + 1, parser->cur_file);
655
0
  }
656
657
29.5k
  if (parser->comments) {
658
0
    ucl_object_unref(parser->comments);
659
0
  }
660
661
29.5k
  UCL_FREE(sizeof(struct ucl_parser), parser);
662
29.5k
}
663
664
const char *
665
ucl_parser_get_error(struct ucl_parser *parser)
666
99
{
667
99
  if (parser == NULL) {
668
0
    return NULL;
669
0
  }
670
671
99
  if (parser->err == NULL) {
672
3
    return NULL;
673
3
  }
674
675
96
  return utstring_body(parser->err);
676
99
}
677
678
int ucl_parser_get_error_code(struct ucl_parser *parser)
679
0
{
680
0
  if (parser == NULL) {
681
0
    return 0;
682
0
  }
683
684
0
  return parser->err_code;
685
0
}
686
687
unsigned
688
ucl_parser_get_column(struct ucl_parser *parser)
689
0
{
690
0
  if (parser == NULL || parser->chunks == NULL) {
691
0
    return 0;
692
0
  }
693
694
0
  return parser->chunks->column;
695
0
}
696
697
unsigned
698
ucl_parser_get_linenum(struct ucl_parser *parser)
699
0
{
700
0
  if (parser == NULL || parser->chunks == NULL) {
701
0
    return 0;
702
0
  }
703
704
0
  return parser->chunks->line;
705
0
}
706
707
void ucl_parser_clear_error(struct ucl_parser *parser)
708
0
{
709
0
  if (parser != NULL && parser->err != NULL) {
710
0
    utstring_free(parser->err);
711
0
    parser->err = NULL;
712
0
    parser->err_code = 0;
713
0
  }
714
0
}
715
716
bool ucl_pubkey_add(struct ucl_parser *parser, const unsigned char *key, size_t len)
717
0
{
718
0
#ifndef HAVE_OPENSSL
719
0
  ucl_create_err(&parser->err, "cannot check signatures without openssl");
720
0
  return false;
721
#else
722
#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
723
  ucl_create_err(&parser->err, "cannot check signatures, openssl version is unsupported");
724
  return EXIT_FAILURE;
725
#else
726
  struct ucl_pubkey *nkey;
727
  BIO *mem;
728
729
  mem = BIO_new_mem_buf((void *) key, len);
730
  nkey = UCL_ALLOC(sizeof(struct ucl_pubkey));
731
  if (nkey == NULL) {
732
    ucl_create_err(&parser->err, "cannot allocate memory for key");
733
    return false;
734
  }
735
  nkey->key = PEM_read_bio_PUBKEY(mem, &nkey->key, NULL, NULL);
736
  BIO_free(mem);
737
  if (nkey->key == NULL) {
738
    UCL_FREE(sizeof(struct ucl_pubkey), nkey);
739
    ucl_create_err(&parser->err, "%s",
740
             ERR_error_string(ERR_get_error(), NULL));
741
    return false;
742
  }
743
  LL_PREPEND(parser->keys, nkey);
744
#endif
745
#endif
746
0
  return true;
747
0
}
748
749
void ucl_parser_add_special_handler(struct ucl_parser *parser,
750
                  struct ucl_parser_special_handler *handler)
751
0
{
752
0
  LL_APPEND(parser->special_handlers, handler);
753
0
}
754
755
#ifdef CURL_FOUND
756
struct ucl_curl_cbdata {
757
  unsigned char *buf;
758
  size_t buflen;
759
};
760
761
static size_t
762
ucl_curl_write_callback(void *contents, size_t size, size_t nmemb, void *ud)
763
{
764
  struct ucl_curl_cbdata *cbdata = ud;
765
  size_t realsize = size * nmemb;
766
767
  cbdata->buf = realloc(cbdata->buf, cbdata->buflen + realsize + 1);
768
  if (cbdata->buf == NULL) {
769
    return 0;
770
  }
771
772
  memcpy(&(cbdata->buf[cbdata->buflen]), contents, realsize);
773
  cbdata->buflen += realsize;
774
  cbdata->buf[cbdata->buflen] = 0;
775
776
  return realsize;
777
}
778
#endif
779
780
/**
781
 * Fetch a url and save results to the memory buffer
782
 * @param url url to fetch
783
 * @param len length of url
784
 * @param buf target buffer
785
 * @param buflen target length
786
 * @return
787
 */
788
bool ucl_fetch_url(const unsigned char *url, unsigned char **buf, size_t *buflen,
789
           UT_string **err, bool must_exist)
790
0
{
791
792
#ifdef HAVE_FETCH_H
793
  struct url *fetch_url;
794
  struct url_stat us;
795
  FILE *in;
796
797
  fetch_url = fetchParseURL(url);
798
  if (fetch_url == NULL) {
799
    ucl_create_err(err, "invalid URL %s: %s",
800
             url, strerror(errno));
801
    return false;
802
  }
803
  if ((in = fetchXGet(fetch_url, &us, "")) == NULL) {
804
    if (!must_exist) {
805
      ucl_create_err(err, "cannot fetch URL %s: %s",
806
               url, strerror(errno));
807
    }
808
    fetchFreeURL(fetch_url);
809
    return false;
810
  }
811
812
  *buflen = us.size;
813
  *buf = malloc(*buflen);
814
  if (*buf == NULL) {
815
    ucl_create_err(err, "cannot allocate buffer for URL %s: %s",
816
             url, strerror(errno));
817
    fclose(in);
818
    fetchFreeURL(fetch_url);
819
    return false;
820
  }
821
822
  if (fread(*buf, *buflen, 1, in) != 1) {
823
    ucl_create_err(err, "cannot read URL %s: %s",
824
             url, strerror(errno));
825
    fclose(in);
826
    fetchFreeURL(fetch_url);
827
    return false;
828
  }
829
830
  fetchFreeURL(fetch_url);
831
  return true;
832
#elif defined(CURL_FOUND)
833
  CURL *curl;
834
  int r;
835
  struct ucl_curl_cbdata cbdata;
836
837
  curl = curl_easy_init();
838
  if (curl == NULL) {
839
    ucl_create_err(err, "CURL interface is broken");
840
    return false;
841
  }
842
  if ((r = curl_easy_setopt(curl, CURLOPT_URL, url)) != CURLE_OK) {
843
    ucl_create_err(err, "invalid URL %s: %s",
844
             url, curl_easy_strerror(r));
845
    curl_easy_cleanup(curl);
846
    return false;
847
  }
848
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
849
  cbdata.buf = NULL;
850
  cbdata.buflen = 0;
851
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cbdata);
852
853
  if ((r = curl_easy_perform(curl)) != CURLE_OK) {
854
    if (!must_exist) {
855
      ucl_create_err(err, "error fetching URL %s: %s",
856
               url, curl_easy_strerror(r));
857
    }
858
    curl_easy_cleanup(curl);
859
    if (cbdata.buf) {
860
      free(cbdata.buf);
861
    }
862
    return false;
863
  }
864
  *buf = cbdata.buf;
865
  *buflen = cbdata.buflen;
866
867
  curl_easy_cleanup(curl);
868
869
  return true;
870
#else
871
0
  ucl_create_err(err, "URL support is disabled");
872
0
  return false;
873
0
#endif
874
0
}
875
876
/**
877
 * Fetch a file and save results to the memory buffer
878
 * @param filename filename to fetch
879
 * @param len length of filename
880
 * @param buf target buffer
881
 * @param buflen target length
882
 * @return
883
 */
884
bool ucl_fetch_file(const unsigned char *filename, unsigned char **buf, size_t *buflen,
885
          UT_string **err, bool must_exist)
886
8.48k
{
887
8.48k
  int fd;
888
8.48k
  struct stat st;
889
8.48k
  if ((fd = open(filename, O_RDONLY)) == -1) {
890
5.91k
    ucl_create_err(err, "cannot open file %s: %s",
891
5.91k
             filename, strerror(errno));
892
5.91k
    return false;
893
5.91k
  }
894
895
2.57k
  if (fstat(fd, &st) == -1) {
896
0
    if (must_exist || errno == EPERM) {
897
0
      ucl_create_err(err, "cannot stat file %s: %s",
898
0
               filename, strerror(errno));
899
0
    }
900
0
    close(fd);
901
902
0
    return false;
903
0
  }
904
2.57k
  if (!S_ISREG(st.st_mode)) {
905
12
    if (must_exist) {
906
12
      ucl_create_err(err, "file %s is not a regular file", filename);
907
12
    }
908
12
    close(fd);
909
910
12
    return false;
911
12
  }
912
913
2.55k
  if (st.st_size == 0) {
914
    /* Do not map empty files */
915
2.16k
    *buf = NULL;
916
2.16k
    *buflen = 0;
917
2.16k
  }
918
393
  else {
919
393
    if ((*buf = ucl_mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
920
0
      close(fd);
921
0
      ucl_create_err(err, "cannot mmap file %s: %s",
922
0
               filename, strerror(errno));
923
0
      *buf = NULL;
924
925
0
      return false;
926
0
    }
927
393
    *buflen = st.st_size;
928
393
  }
929
930
2.55k
  close(fd);
931
932
2.55k
  return true;
933
2.55k
}
934
935
936
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
937
static inline bool
938
ucl_sig_check(const unsigned char *data, size_t datalen,
939
        const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
940
{
941
  struct ucl_pubkey *key;
942
  char dig[EVP_MAX_MD_SIZE];
943
  unsigned int diglen;
944
  EVP_PKEY_CTX *key_ctx;
945
  EVP_MD_CTX *sign_ctx = NULL;
946
947
  sign_ctx = EVP_MD_CTX_create();
948
949
  LL_FOREACH(parser->keys, key)
950
  {
951
    key_ctx = EVP_PKEY_CTX_new(key->key, NULL);
952
    if (key_ctx != NULL) {
953
      if (EVP_PKEY_verify_init(key_ctx) <= 0) {
954
        EVP_PKEY_CTX_free(key_ctx);
955
        continue;
956
      }
957
      if (EVP_PKEY_CTX_set_rsa_padding(key_ctx, RSA_PKCS1_PADDING) <= 0) {
958
        EVP_PKEY_CTX_free(key_ctx);
959
        continue;
960
      }
961
      if (EVP_PKEY_CTX_set_signature_md(key_ctx, EVP_sha256()) <= 0) {
962
        EVP_PKEY_CTX_free(key_ctx);
963
        continue;
964
      }
965
      EVP_DigestInit(sign_ctx, EVP_sha256());
966
      EVP_DigestUpdate(sign_ctx, data, datalen);
967
      EVP_DigestFinal(sign_ctx, dig, &diglen);
968
969
      if (EVP_PKEY_verify(key_ctx, sig, siglen, dig, diglen) == 1) {
970
        EVP_MD_CTX_destroy(sign_ctx);
971
        EVP_PKEY_CTX_free(key_ctx);
972
        return true;
973
      }
974
975
      EVP_PKEY_CTX_free(key_ctx);
976
    }
977
  }
978
979
  EVP_MD_CTX_destroy(sign_ctx);
980
981
  return false;
982
}
983
#endif
984
985
struct ucl_include_params {
986
  bool check_signature;
987
  bool must_exist;
988
  bool use_glob;
989
  bool use_prefix;
990
  bool soft_fail;
991
  bool allow_glob;
992
  unsigned priority;
993
  enum ucl_duplicate_strategy strat;
994
  enum ucl_parse_type parse_type;
995
  const char *prefix;
996
  const char *target;
997
};
998
999
/**
1000
 * Include an url to configuration
1001
 * @param data
1002
 * @param len
1003
 * @param parser
1004
 * @param err
1005
 * @return
1006
 */
1007
static bool
1008
ucl_include_url(const unsigned char *data, size_t len,
1009
        struct ucl_parser *parser,
1010
        struct ucl_include_params *params)
1011
0
{
1012
1013
0
  bool res;
1014
0
  unsigned char *buf = NULL;
1015
0
  size_t buflen = 0;
1016
0
  struct ucl_chunk *chunk;
1017
0
  char urlbuf[PATH_MAX];
1018
0
  int prev_state;
1019
1020
0
  snprintf(urlbuf, sizeof(urlbuf), "%.*s", (int) len, data);
1021
1022
0
  if (!ucl_fetch_url(urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
1023
0
    if (!params->must_exist) {
1024
0
      ucl_parser_clear_error(parser);
1025
0
    }
1026
0
    return !params->must_exist;
1027
0
  }
1028
1029
0
  if (params->check_signature) {
1030
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
1031
    unsigned char *sigbuf = NULL;
1032
    size_t siglen = 0;
1033
    /* We need to check signature first */
1034
    snprintf(urlbuf, sizeof(urlbuf), "%.*s.sig", (int) len, data);
1035
    if (!ucl_fetch_url(urlbuf, &sigbuf, &siglen, &parser->err, true)) {
1036
      return false;
1037
    }
1038
    if (!ucl_sig_check(buf, buflen, sigbuf, siglen, parser)) {
1039
      ucl_create_err(&parser->err, "cannot verify url %s: %s",
1040
               urlbuf,
1041
               ERR_error_string(ERR_get_error(), NULL));
1042
      if (siglen > 0) {
1043
        free(sigbuf);
1044
      }
1045
      return false;
1046
    }
1047
    if (siglen > 0) {
1048
      free(sigbuf);
1049
    }
1050
#endif
1051
0
  }
1052
1053
0
  prev_state = parser->state;
1054
0
  parser->state = UCL_STATE_INIT;
1055
1056
0
  res = ucl_parser_add_chunk_full(parser, buf, buflen, params->priority,
1057
0
                  params->strat, params->parse_type);
1058
0
  if (res == true) {
1059
    /* Remove chunk from the stack */
1060
0
    chunk = parser->chunks;
1061
0
    if (chunk != NULL) {
1062
0
      parser->chunks = chunk->next;
1063
0
      ucl_chunk_free(chunk);
1064
0
    }
1065
0
  }
1066
1067
0
  parser->state = prev_state;
1068
0
  free(buf);
1069
1070
0
  return res;
1071
0
}
1072
1073
/**
1074
 * Include a single file to the parser
1075
 * @param data
1076
 * @param len
1077
 * @param parser
1078
 * @param check_signature
1079
 * @param must_exist
1080
 * @param allow_glob
1081
 * @param priority
1082
 * @return
1083
 */
1084
static bool
1085
ucl_include_file_single(const unsigned char *data, size_t len,
1086
            struct ucl_parser *parser, struct ucl_include_params *params)
1087
562k
{
1088
562k
  bool res;
1089
562k
  struct ucl_chunk *chunk;
1090
562k
  unsigned char *buf = NULL;
1091
562k
  char *old_curfile, *ext;
1092
562k
  size_t buflen = 0;
1093
562k
  char filebuf[PATH_MAX], realbuf[PATH_MAX];
1094
562k
  int prev_state;
1095
562k
  struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
1096
562k
                      *old_filename = NULL;
1097
562k
  ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL;
1098
562k
  ucl_hash_t *container = NULL;
1099
562k
  struct ucl_stack *st = NULL;
1100
1101
562k
  if (parser->state == UCL_STATE_ERROR) {
1102
    /* Return immediately if we are in the error state... */
1103
0
    return false;
1104
0
  }
1105
1106
562k
  snprintf(filebuf, sizeof(filebuf), "%.*s", (int) len, data);
1107
562k
  if (ucl_realpath(filebuf, realbuf) == NULL) {
1108
561k
    if (params->soft_fail) {
1109
0
      return false;
1110
0
    }
1111
561k
    if (!params->must_exist && errno != EPERM) {
1112
1
      return true;
1113
1
    }
1114
1115
561k
    ucl_create_err(&parser->err, "cannot open file %s: %s",
1116
561k
             filebuf,
1117
561k
             strerror(errno));
1118
561k
    return false;
1119
561k
  }
1120
1121
1.09k
  if (parser->cur_file && strcmp(realbuf, parser->cur_file) == 0) {
1122
    /* We are likely including the file itself */
1123
0
    if (params->soft_fail) {
1124
0
      return false;
1125
0
    }
1126
1127
0
    ucl_create_err(&parser->err, "trying to include the file %s from itself",
1128
0
             realbuf);
1129
0
    return false;
1130
0
  }
1131
1132
1.09k
  if (!ucl_fetch_file(realbuf, &buf, &buflen, &parser->err, params->must_exist)) {
1133
12
    if (params->soft_fail) {
1134
0
      return false;
1135
0
    }
1136
1137
12
    if (params->must_exist || parser->err != NULL) {
1138
      /* The case of fatal errors */
1139
12
      return false;
1140
12
    }
1141
1142
0
    ucl_parser_clear_error(parser);
1143
1144
0
    return true;
1145
12
  }
1146
1147
1.08k
  if (params->check_signature) {
1148
#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
1149
    unsigned char *sigbuf = NULL;
1150
    size_t siglen = 0;
1151
    /* We need to check signature first */
1152
    snprintf(filebuf, sizeof(filebuf), "%s.sig", realbuf);
1153
    if (!ucl_fetch_file(filebuf, &sigbuf, &siglen, &parser->err, true)) {
1154
      if (buf) {
1155
        ucl_munmap(buf, buflen);
1156
      }
1157
1158
      return false;
1159
    }
1160
    if (!ucl_sig_check(buf, buflen, sigbuf, siglen, parser)) {
1161
      ucl_create_err(&parser->err, "cannot verify file %s: %s",
1162
               filebuf,
1163
               ERR_error_string(ERR_get_error(), NULL));
1164
      if (sigbuf) {
1165
        ucl_munmap(sigbuf, siglen);
1166
      }
1167
      if (buf) {
1168
        ucl_munmap(buf, buflen);
1169
      }
1170
1171
      return false;
1172
    }
1173
1174
    if (sigbuf) {
1175
      ucl_munmap(sigbuf, siglen);
1176
    }
1177
#endif
1178
0
  }
1179
1180
1.08k
  old_curfile = parser->cur_file;
1181
1.08k
  parser->cur_file = NULL;
1182
1183
  /* Store old file vars */
1184
1.08k
  DL_FOREACH_SAFE(parser->variables, cur_var, tmp_var)
1185
2.17k
  {
1186
2.17k
    if (strcmp(cur_var->var, "CURDIR") == 0) {
1187
1.08k
      old_curdir = cur_var;
1188
1.08k
      DL_DELETE(parser->variables, cur_var);
1189
1.08k
    }
1190
1.08k
    else if (strcmp(cur_var->var, "FILENAME") == 0) {
1191
1.08k
      old_filename = cur_var;
1192
1.08k
      DL_DELETE(parser->variables, cur_var);
1193
1.08k
    }
1194
2.17k
  }
1195
1196
1.08k
  ucl_parser_set_filevars(parser, realbuf, false);
1197
1198
1.08k
  prev_state = parser->state;
1199
1.08k
  parser->state = UCL_STATE_INIT;
1200
1201
1.08k
  if (params->use_prefix && params->prefix == NULL) {
1202
    /* Auto generate a key name based on the included filename */
1203
0
    params->prefix = basename(realbuf);
1204
0
    ext = strrchr(params->prefix, '.');
1205
0
    if (ext != NULL && (strcmp(ext, ".conf") == 0 || strcmp(ext, ".ucl") == 0)) {
1206
      /* Strip off .conf or .ucl */
1207
0
      *ext = '\0';
1208
0
    }
1209
0
  }
1210
1.08k
  if (params->prefix != NULL) {
1211
    /* This is a prefixed include */
1212
873
    container = parser->stack->obj->value.ov;
1213
1214
873
    old_obj = __DECONST(ucl_object_t *, ucl_hash_search(container,
1215
873
                              params->prefix, strlen(params->prefix)));
1216
1217
873
    if (strcasecmp(params->target, "array") == 0) {
1218
7
      if (old_obj == NULL) {
1219
        /* Create an array with key: prefix */
1220
7
        old_obj = ucl_object_new_full(UCL_ARRAY, params->priority);
1221
7
        old_obj->key = params->prefix;
1222
7
        old_obj->keylen = strlen(params->prefix);
1223
7
        ucl_copy_key_trash(old_obj);
1224
7
        old_obj->prev = old_obj;
1225
7
        old_obj->next = NULL;
1226
1227
7
        container = ucl_hash_insert_object(container, old_obj,
1228
7
                           parser->flags & UCL_PARSER_KEY_LOWERCASE);
1229
7
        parser->stack->obj->len++;
1230
1231
7
        nest_obj = ucl_object_new_full(UCL_OBJECT, params->priority);
1232
7
        nest_obj->prev = nest_obj;
1233
7
        nest_obj->next = NULL;
1234
1235
7
        ucl_array_append(old_obj, nest_obj);
1236
7
      }
1237
0
      else {
1238
0
        if (ucl_object_type(old_obj) == UCL_ARRAY) {
1239
          /* Append to the existing array */
1240
0
          nest_obj = ucl_object_new_full(UCL_OBJECT,
1241
0
                           params->priority);
1242
0
          if (nest_obj == NULL) {
1243
0
            ucl_create_err(&parser->err,
1244
0
                     "cannot allocate memory for an object");
1245
0
            if (buf) {
1246
0
              ucl_munmap(buf, buflen);
1247
0
            }
1248
1249
0
            return false;
1250
0
          }
1251
0
          nest_obj->prev = nest_obj;
1252
0
          nest_obj->next = NULL;
1253
1254
0
          ucl_array_append(old_obj, nest_obj);
1255
0
        }
1256
0
        else {
1257
          /* Convert the object to an array */
1258
0
          new_obj = ucl_object_typed_new(UCL_ARRAY);
1259
0
          if (new_obj == NULL) {
1260
0
            ucl_create_err(&parser->err,
1261
0
                     "cannot allocate memory for an object");
1262
0
            if (buf) {
1263
0
              ucl_munmap(buf, buflen);
1264
0
            }
1265
1266
0
            return false;
1267
0
          }
1268
0
          new_obj->key = old_obj->key;
1269
0
          new_obj->keylen = old_obj->keylen;
1270
0
          new_obj->flags |= UCL_OBJECT_MULTIVALUE;
1271
0
          new_obj->prev = new_obj;
1272
0
          new_obj->next = NULL;
1273
1274
0
          nest_obj = ucl_object_new_full(UCL_OBJECT,
1275
0
                           params->priority);
1276
0
          if (nest_obj == NULL) {
1277
0
            ucl_create_err(&parser->err,
1278
0
                     "cannot allocate memory for an object");
1279
0
            if (buf) {
1280
0
              ucl_munmap(buf, buflen);
1281
0
            }
1282
1283
0
            ucl_object_unref(new_obj);
1284
1285
0
            return false;
1286
0
          }
1287
0
          nest_obj->prev = nest_obj;
1288
0
          nest_obj->next = NULL;
1289
1290
0
          ucl_array_append(new_obj, old_obj);
1291
0
          ucl_array_append(new_obj, nest_obj);
1292
0
          ucl_hash_replace(container, old_obj, new_obj);
1293
0
        }
1294
0
      }
1295
7
    }
1296
866
    else {
1297
      /* Case of object */
1298
866
      if (old_obj == NULL) {
1299
        /* Create an object with key: prefix */
1300
836
        nest_obj = ucl_object_new_full(UCL_OBJECT, params->priority);
1301
1302
836
        if (nest_obj == NULL) {
1303
0
          ucl_create_err(&parser->err, "cannot allocate memory for an object");
1304
0
          if (buf) {
1305
0
            ucl_munmap(buf, buflen);
1306
0
          }
1307
1308
0
          return false;
1309
0
        }
1310
1311
836
        nest_obj->key = params->prefix;
1312
836
        nest_obj->keylen = strlen(params->prefix);
1313
836
        ucl_copy_key_trash(nest_obj);
1314
836
        nest_obj->prev = nest_obj;
1315
836
        nest_obj->next = NULL;
1316
1317
836
        container = ucl_hash_insert_object(container, nest_obj,
1318
836
                           parser->flags & UCL_PARSER_KEY_LOWERCASE);
1319
836
        parser->stack->obj->len++;
1320
836
      }
1321
30
      else {
1322
30
        if (ucl_object_type(old_obj) == UCL_OBJECT) {
1323
          /* Append to existing Object*/
1324
30
          nest_obj = old_obj;
1325
30
        }
1326
0
        else {
1327
          /* The key is not an object */
1328
0
          ucl_create_err(&parser->err,
1329
0
                   "Conflicting type for key: %s, asked %s, has %s",
1330
0
                   params->prefix, params->target,
1331
0
                   ucl_object_type_to_string(ucl_object_type(old_obj)));
1332
0
          if (buf) {
1333
0
            ucl_munmap(buf, buflen);
1334
0
          }
1335
1336
0
          return false;
1337
0
        }
1338
30
      }
1339
866
    }
1340
1341
1342
    /* Put all of the content of the include inside that object */
1343
873
    parser->stack->obj->value.ov = container;
1344
1345
873
    st = UCL_ALLOC(sizeof(struct ucl_stack));
1346
873
    if (st == NULL) {
1347
0
      ucl_create_err(&parser->err, "cannot allocate memory for an object");
1348
0
      ucl_object_unref(nest_obj);
1349
1350
0
      if (buf) {
1351
0
        ucl_munmap(buf, buflen);
1352
0
      }
1353
1354
0
      return false;
1355
0
    }
1356
873
    st->obj = nest_obj;
1357
873
    st->e.params.level = parser->stack->e.params.level;
1358
873
    st->e.params.flags = parser->stack->e.params.flags;
1359
873
    st->e.params.line = parser->stack->e.params.line;
1360
873
    st->chunk = parser->chunks;
1361
873
    LL_PREPEND(parser->stack, st);
1362
873
    parser->cur_obj = nest_obj;
1363
873
  }
1364
1365
1.08k
  res = ucl_parser_add_chunk_full(parser, buf, buflen, params->priority,
1366
1.08k
                  params->strat, params->parse_type);
1367
1368
1.08k
  if (res) {
1369
    /* Stop nesting the include, take 1 level off the stack */
1370
1.08k
    if (params->prefix != NULL && nest_obj != NULL) {
1371
873
      parser->stack = st->next;
1372
873
      UCL_FREE(sizeof(struct ucl_stack), st);
1373
873
    }
1374
1375
    /* Remove chunk from the stack */
1376
1.08k
    chunk = parser->chunks;
1377
1.08k
    if (chunk != NULL) {
1378
1.08k
      parser->chunks = chunk->next;
1379
1.08k
      ucl_chunk_free(chunk);
1380
1.08k
      parser->recursion--;
1381
1.08k
    }
1382
1383
    /* Restore old file vars */
1384
1.08k
    if (parser->cur_file) {
1385
1.08k
      UCL_FREE(strlen(parser->cur_file) + 1, parser->cur_file);
1386
1.08k
    }
1387
1388
1.08k
    parser->cur_file = old_curfile;
1389
1.08k
    DL_FOREACH_SAFE(parser->variables, cur_var, tmp_var)
1390
2.17k
    {
1391
2.17k
      if (strcmp(cur_var->var, "CURDIR") == 0 && old_curdir) {
1392
1.08k
        DL_DELETE(parser->variables, cur_var);
1393
1.08k
        free(cur_var->var);
1394
1.08k
        free(cur_var->value);
1395
1.08k
        UCL_FREE(sizeof(struct ucl_variable), cur_var);
1396
1.08k
      }
1397
1.08k
      else if (strcmp(cur_var->var, "FILENAME") == 0 && old_filename) {
1398
1.08k
        DL_DELETE(parser->variables, cur_var);
1399
1.08k
        free(cur_var->var);
1400
1.08k
        free(cur_var->value);
1401
1.08k
        UCL_FREE(sizeof(struct ucl_variable), cur_var);
1402
1.08k
      }
1403
2.17k
    }
1404
1.08k
    if (old_filename) {
1405
1.08k
      DL_APPEND(parser->variables, old_filename);
1406
1.08k
    }
1407
1.08k
    if (old_curdir) {
1408
1.08k
      DL_APPEND(parser->variables, old_curdir);
1409
1.08k
    }
1410
1411
1.08k
    parser->state = prev_state;
1412
1.08k
  }
1413
1414
1.08k
  if (buflen > 0) {
1415
170
    ucl_munmap(buf, buflen);
1416
170
  }
1417
1418
1.08k
  return res;
1419
1.08k
}
1420
1421
/**
1422
 * Include a file to configuration
1423
 * @param data
1424
 * @param len
1425
 * @param parser
1426
 * @param err
1427
 * @return
1428
 */
1429
static bool
1430
ucl_include_file(const unsigned char *data, size_t len,
1431
         struct ucl_parser *parser,
1432
         struct ucl_include_params *params,
1433
         const ucl_object_t *args)
1434
562k
{
1435
562k
  const unsigned char *p = data, *end = data + len;
1436
562k
  bool need_glob = false;
1437
562k
  int cnt = 0;
1438
562k
  char glob_pattern[PATH_MAX];
1439
562k
  size_t i;
1440
1441
562k
#ifndef _WIN32
1442
562k
  if (!params->allow_glob) {
1443
562k
    return ucl_include_file_single(data, len, parser, params);
1444
562k
  }
1445
62
  else {
1446
    /* Check for special symbols in a filename */
1447
77.0k
    while (p != end) {
1448
76.9k
      if (*p == '*' || *p == '?') {
1449
43
        need_glob = true;
1450
43
        break;
1451
43
      }
1452
76.9k
      p++;
1453
76.9k
    }
1454
62
    if (need_glob) {
1455
43
      glob_t globbuf;
1456
43
      memset(&globbuf, 0, sizeof(globbuf));
1457
43
      ucl_strlcpy(glob_pattern, (const char *) data,
1458
43
            (len + 1 < sizeof(glob_pattern) ? len + 1 : sizeof(glob_pattern)));
1459
43
      if (glob(glob_pattern, 0, NULL, &globbuf) != 0) {
1460
43
        return (!params->must_exist || false);
1461
43
      }
1462
0
      for (i = 0; i < globbuf.gl_pathc; i++) {
1463
1464
0
        if (parser->include_trace_func) {
1465
0
          const ucl_object_t *parent = NULL;
1466
1467
0
          if (parser->stack) {
1468
0
            parent = parser->stack->obj;
1469
0
          }
1470
1471
0
          parser->include_trace_func(parser, parent, NULL,
1472
0
                         globbuf.gl_pathv[i],
1473
0
                         strlen(globbuf.gl_pathv[i]),
1474
0
                         parser->include_trace_ud);
1475
0
        }
1476
1477
0
        if (!ucl_include_file_single((unsigned char *) globbuf.gl_pathv[i],
1478
0
                       strlen(globbuf.gl_pathv[i]), parser, params)) {
1479
0
          if (params->soft_fail) {
1480
0
            continue;
1481
0
          }
1482
0
          globfree(&globbuf);
1483
0
          return false;
1484
0
        }
1485
0
        cnt++;
1486
0
      }
1487
0
      globfree(&globbuf);
1488
1489
0
      if (cnt == 0 && params->must_exist) {
1490
0
        ucl_create_err(&parser->err, "cannot match any files for pattern %s",
1491
0
                 glob_pattern);
1492
0
        return false;
1493
0
      }
1494
0
    }
1495
19
    else {
1496
19
      return ucl_include_file_single(data, len, parser, params);
1497
19
    }
1498
62
  }
1499
#else
1500
  /* Win32 compilers do not support globbing. Therefore, for Win32,
1501
     treat allow_glob/need_glob as a NOOP and just return */
1502
  return ucl_include_file_single(data, len, parser, params);
1503
#endif
1504
1505
0
  return true;
1506
562k
}
1507
1508
/**
1509
 * Common function to handle .*include* macros
1510
 * @param data
1511
 * @param len
1512
 * @param args
1513
 * @param parser
1514
 * @param default_try
1515
 * @param default_sign
1516
 * @return
1517
 */
1518
static bool
1519
ucl_include_common(const unsigned char *data, size_t len,
1520
           const ucl_object_t *args, struct ucl_parser *parser,
1521
           bool default_try,
1522
           bool default_sign)
1523
1.36k
{
1524
1.36k
  bool allow_url = false, search = false;
1525
1.36k
  const char *duplicate;
1526
1.36k
  const ucl_object_t *param;
1527
1.36k
  ucl_object_iter_t it = NULL, ip = NULL;
1528
1.36k
  char ipath[PATH_MAX];
1529
1.36k
  struct ucl_include_params params;
1530
1531
  /* Default values */
1532
1.36k
  params.soft_fail = default_try;
1533
1.36k
  params.allow_glob = false;
1534
1.36k
  params.check_signature = default_sign;
1535
1.36k
  params.use_prefix = false;
1536
1.36k
  params.target = "object";
1537
1.36k
  params.prefix = NULL;
1538
1.36k
  params.priority = 0;
1539
1.36k
  params.parse_type = UCL_PARSE_UCL;
1540
1.36k
  params.strat = UCL_DUPLICATE_APPEND;
1541
1.36k
  params.must_exist = !default_try;
1542
1543
1.36k
  if (parser->include_trace_func) {
1544
0
    const ucl_object_t *parent = NULL;
1545
1546
0
    if (parser->stack) {
1547
0
      parent = parser->stack->obj;
1548
0
    }
1549
1550
0
    parser->include_trace_func(parser, parent, args,
1551
0
                   data, len, parser->include_trace_ud);
1552
0
  }
1553
1554
  /* Process arguments */
1555
1.36k
  if (args != NULL && args->type == UCL_OBJECT) {
1556
3.14k
    while ((param = ucl_object_iterate(args, &it, true)) != NULL) {
1557
2.06k
      if (param->type == UCL_BOOLEAN) {
1558
86
        if (strncmp(param->key, "try", param->keylen) == 0) {
1559
1
          params.must_exist = !ucl_object_toboolean(param);
1560
1
        }
1561
85
        else if (strncmp(param->key, "sign", param->keylen) == 0) {
1562
0
          params.check_signature = ucl_object_toboolean(param);
1563
0
        }
1564
85
        else if (strncmp(param->key, "glob", param->keylen) == 0) {
1565
62
          params.allow_glob = ucl_object_toboolean(param);
1566
62
        }
1567
23
        else if (strncmp(param->key, "url", param->keylen) == 0) {
1568
2
          allow_url = ucl_object_toboolean(param);
1569
2
        }
1570
21
        else if (strncmp(param->key, "prefix", param->keylen) == 0) {
1571
0
          params.use_prefix = ucl_object_toboolean(param);
1572
0
        }
1573
86
      }
1574
1.98k
      else if (param->type == UCL_STRING) {
1575
1.90k
        if (strncmp(param->key, "key", param->keylen) == 0) {
1576
880
          params.prefix = ucl_object_tostring(param);
1577
880
        }
1578
1.02k
        else if (strncmp(param->key, "target", param->keylen) == 0) {
1579
847
          params.target = ucl_object_tostring(param);
1580
847
        }
1581
182
        else if (strncmp(param->key, "duplicate", param->keylen) == 0) {
1582
115
          duplicate = ucl_object_tostring(param);
1583
1584
115
          if (strcmp(duplicate, "append") == 0) {
1585
0
            params.strat = UCL_DUPLICATE_APPEND;
1586
0
          }
1587
115
          else if (strcmp(duplicate, "merge") == 0) {
1588
89
            params.strat = UCL_DUPLICATE_MERGE;
1589
89
          }
1590
26
          else if (strcmp(duplicate, "rewrite") == 0) {
1591
0
            params.strat = UCL_DUPLICATE_REWRITE;
1592
0
          }
1593
26
          else if (strcmp(duplicate, "error") == 0) {
1594
0
            params.strat = UCL_DUPLICATE_ERROR;
1595
0
          }
1596
115
        }
1597
1.90k
      }
1598
73
      else if (param->type == UCL_ARRAY) {
1599
11
        if (strncmp(param->key, "path", param->keylen) == 0) {
1600
6
          ucl_set_include_path(parser, __DECONST(ucl_object_t *, param));
1601
6
        }
1602
11
      }
1603
62
      else if (param->type == UCL_INT) {
1604
62
        if (strncmp(param->key, "priority", param->keylen) == 0) {
1605
12
          params.priority = ucl_object_toint(param);
1606
12
        }
1607
62
      }
1608
2.06k
    }
1609
1.07k
  }
1610
1611
1.36k
  if (parser->includepaths == NULL) {
1612
1.36k
    if (allow_url && ucl_strnstr(data, "://", len) != NULL) {
1613
      /* Globbing is not used for URL's */
1614
0
      return ucl_include_url(data, len, parser, &params);
1615
0
    }
1616
1.36k
    else if (data != NULL) {
1617
      /* Try to load a file */
1618
1.36k
      return ucl_include_file(data, len, parser, &params, args);
1619
1.36k
    }
1620
1.36k
  }
1621
6
  else {
1622
6
    if (allow_url && ucl_strnstr(data, "://", len) != NULL) {
1623
      /* Globbing is not used for URL's */
1624
0
      return ucl_include_url(data, len, parser, &params);
1625
0
    }
1626
1627
6
    ip = ucl_object_iterate_new(parser->includepaths);
1628
560k
    while ((param = ucl_object_iterate_safe(ip, true)) != NULL) {
1629
560k
      if (ucl_object_type(param) == UCL_STRING) {
1630
560k
        snprintf(ipath, sizeof(ipath), "%s/%.*s", ucl_object_tostring(param),
1631
560k
             (int) len, data);
1632
560k
        if ((search = ucl_include_file(ipath, strlen(ipath),
1633
560k
                         parser, &params, args))) {
1634
2
          if (!params.allow_glob) {
1635
1
            break;
1636
1
          }
1637
2
        }
1638
560k
      }
1639
560k
    }
1640
6
    ucl_object_iterate_free(ip);
1641
6
    if (search == true) {
1642
2
      return true;
1643
2
    }
1644
4
    else {
1645
4
      ucl_create_err(&parser->err,
1646
4
               "cannot find file: %.*s in search path",
1647
4
               (int) len, data);
1648
4
      return false;
1649
4
    }
1650
6
  }
1651
1652
0
  return false;
1653
1.36k
}
1654
1655
/**
1656
 * Handle include macro
1657
 * @param data include data
1658
 * @param len length of data
1659
 * @param args UCL object representing arguments to the macro
1660
 * @param ud user data
1661
 * @return
1662
 */
1663
bool ucl_include_handler(const unsigned char *data, size_t len,
1664
             const ucl_object_t *args, void *ud)
1665
1.36k
{
1666
1.36k
  struct ucl_parser *parser = ud;
1667
1668
1.36k
  return ucl_include_common(data, len, args, parser, false, false);
1669
1.36k
}
1670
1671
/**
1672
 * Handle includes macro
1673
 * @param data include data
1674
 * @param len length of data
1675
 * @param args UCL object representing arguments to the macro
1676
 * @param ud user data
1677
 * @return
1678
 */
1679
bool ucl_includes_handler(const unsigned char *data, size_t len,
1680
              const ucl_object_t *args, void *ud)
1681
0
{
1682
0
  struct ucl_parser *parser = ud;
1683
1684
0
  return ucl_include_common(data, len, args, parser, false, true);
1685
0
}
1686
1687
/**
1688
 * Handle tryinclude macro
1689
 * @param data include data
1690
 * @param len length of data
1691
 * @param args UCL object representing arguments to the macro
1692
 * @param ud user data
1693
 * @return
1694
 */
1695
bool ucl_try_include_handler(const unsigned char *data, size_t len,
1696
               const ucl_object_t *args, void *ud)
1697
1
{
1698
1
  struct ucl_parser *parser = ud;
1699
1700
1
  return ucl_include_common(data, len, args, parser, true, false);
1701
1
}
1702
1703
/**
1704
 * Handle priority macro
1705
 * @param data include data
1706
 * @param len length of data
1707
 * @param args UCL object representing arguments to the macro
1708
 * @param ud user data
1709
 * @return
1710
 */
1711
bool ucl_priority_handler(const unsigned char *data, size_t len,
1712
              const ucl_object_t *args, void *ud)
1713
18.2k
{
1714
18.2k
  struct ucl_parser *parser = ud;
1715
18.2k
  unsigned priority = 255;
1716
18.2k
  const ucl_object_t *param;
1717
18.2k
  bool found = false;
1718
18.2k
  char *value = NULL, *leftover = NULL;
1719
18.2k
  ucl_object_iter_t it = NULL;
1720
1721
18.2k
  if (parser == NULL) {
1722
0
    return false;
1723
0
  }
1724
1725
  /* Process arguments */
1726
18.2k
  if (args != NULL && args->type == UCL_OBJECT) {
1727
1.42k
    while ((param = ucl_object_iterate(args, &it, true)) != NULL) {
1728
986
      if (param->type == UCL_INT) {
1729
549
        if (strncmp(param->key, "priority", param->keylen) == 0) {
1730
0
          priority = ucl_object_toint(param);
1731
0
          found = true;
1732
0
        }
1733
549
      }
1734
986
    }
1735
440
  }
1736
1737
18.2k
  if (len > 0) {
1738
17.8k
    value = malloc(len + 1);
1739
17.8k
    ucl_strlcpy(value, (const char *) data, len + 1);
1740
17.8k
    priority = strtol(value, &leftover, 10);
1741
17.8k
    if (*leftover != '\0') {
1742
436
      ucl_create_err(&parser->err, "Invalid priority value in macro: %s",
1743
436
               value);
1744
436
      free(value);
1745
436
      return false;
1746
436
    }
1747
17.3k
    free(value);
1748
17.3k
    found = true;
1749
17.3k
  }
1750
1751
17.7k
  if (found == true) {
1752
17.3k
    parser->chunks->priority = priority;
1753
17.3k
    return true;
1754
17.3k
  }
1755
1756
404
  ucl_create_err(&parser->err, "Unable to parse priority macro");
1757
404
  return false;
1758
17.7k
}
1759
1760
/**
1761
 * Handle load macro
1762
 * @param data include data
1763
 * @param len length of data
1764
 * @param args UCL object representing arguments to the macro
1765
 * @param ud user data
1766
 * @return
1767
 */
1768
bool ucl_load_handler(const unsigned char *data, size_t len,
1769
            const ucl_object_t *args, void *ud)
1770
8.83k
{
1771
8.83k
  struct ucl_parser *parser = ud;
1772
8.83k
  const ucl_object_t *param;
1773
8.83k
  ucl_object_t *obj, *old_obj;
1774
8.83k
  ucl_object_iter_t it = NULL;
1775
8.83k
  bool try_load, multiline, test;
1776
8.83k
  const char *target, *prefix;
1777
8.83k
  char *load_file, *tmp;
1778
8.83k
  unsigned char *buf;
1779
8.83k
  size_t buflen;
1780
8.83k
  unsigned priority;
1781
8.83k
  int64_t iv;
1782
8.83k
  ucl_object_t *container = NULL;
1783
8.83k
  enum ucl_string_flags flags;
1784
1785
  /* Default values */
1786
8.83k
  try_load = false;
1787
8.83k
  multiline = false;
1788
8.83k
  test = false;
1789
8.83k
  target = "string";
1790
8.83k
  prefix = NULL;
1791
8.83k
  load_file = NULL;
1792
8.83k
  buf = NULL;
1793
8.83k
  buflen = 0;
1794
8.83k
  priority = 0;
1795
8.83k
  obj = NULL;
1796
8.83k
  old_obj = NULL;
1797
8.83k
  flags = 0;
1798
1799
8.83k
  if (parser == NULL) {
1800
0
    return false;
1801
0
  }
1802
1803
  /* Process arguments */
1804
8.83k
  if (args != NULL && args->type == UCL_OBJECT) {
1805
34.3k
    while ((param = ucl_object_iterate(args, &it, true)) != NULL) {
1806
26.5k
      if (param->type == UCL_BOOLEAN) {
1807
5.95k
        if (strncmp(param->key, "try", param->keylen) == 0) {
1808
0
          try_load = ucl_object_toboolean(param);
1809
0
        }
1810
5.95k
        else if (strncmp(param->key, "multiline", param->keylen) == 0) {
1811
438
          multiline = ucl_object_toboolean(param);
1812
438
        }
1813
5.51k
        else if (strncmp(param->key, "escape", param->keylen) == 0) {
1814
439
          test = ucl_object_toboolean(param);
1815
439
          if (test) {
1816
439
            flags |= UCL_STRING_ESCAPE;
1817
439
          }
1818
439
        }
1819
5.07k
        else if (strncmp(param->key, "trim", param->keylen) == 0) {
1820
35
          test = ucl_object_toboolean(param);
1821
35
          if (test) {
1822
35
            flags |= UCL_STRING_TRIM;
1823
35
          }
1824
35
        }
1825
5.95k
      }
1826
20.6k
      else if (param->type == UCL_STRING) {
1827
16.5k
        if (strncmp(param->key, "key", param->keylen) == 0) {
1828
7.62k
          prefix = ucl_object_tostring(param);
1829
7.62k
        }
1830
8.94k
        else if (strncmp(param->key, "target", param->keylen) == 0) {
1831
1.67k
          target = ucl_object_tostring(param);
1832
1.67k
        }
1833
16.5k
      }
1834
4.06k
      else if (param->type == UCL_INT) {
1835
0
        if (strncmp(param->key, "priority", param->keylen) == 0) {
1836
0
          priority = ucl_object_toint(param);
1837
0
        }
1838
0
      }
1839
26.5k
    }
1840
7.76k
  }
1841
1842
8.83k
  if (prefix == NULL || strlen(prefix) == 0) {
1843
1.21k
    ucl_create_err(&parser->err, "No Key specified in load macro");
1844
1.21k
    return false;
1845
1.21k
  }
1846
1847
7.61k
  if (len > 0) {
1848
7.38k
    load_file = malloc(len + 1);
1849
7.38k
    if (!load_file) {
1850
0
      ucl_create_err(&parser->err, "cannot allocate memory for suffix");
1851
1852
0
      return false;
1853
0
    }
1854
1855
7.38k
    snprintf(load_file, len + 1, "%.*s", (int) len, data);
1856
1857
7.38k
    if (!ucl_fetch_file(load_file, &buf, &buflen, &parser->err,
1858
7.38k
              !try_load)) {
1859
5.91k
      free(load_file);
1860
1861
5.91k
      if (try_load) {
1862
0
        ucl_parser_clear_error(parser);
1863
0
      }
1864
1865
5.91k
      return (try_load || false);
1866
5.91k
    }
1867
1868
1.47k
    free(load_file);
1869
1.47k
    container = parser->stack->obj;
1870
1.47k
    old_obj = __DECONST(ucl_object_t *, ucl_object_lookup(container,
1871
1.47k
                                prefix));
1872
1873
1.47k
    if (old_obj != NULL) {
1874
236
      ucl_create_err(&parser->err, "Key %s already exists", prefix);
1875
236
      if (buf) {
1876
0
        ucl_munmap(buf, buflen);
1877
0
      }
1878
1879
236
      return false;
1880
236
    }
1881
1882
1.23k
    if (strcasecmp(target, "string") == 0) {
1883
235
      obj = ucl_object_fromstring_common(buf, buflen, flags);
1884
235
      ucl_copy_value_trash(obj);
1885
235
      if (multiline) {
1886
182
        obj->flags |= UCL_OBJECT_MULTILINE;
1887
182
      }
1888
235
    }
1889
1.00k
    else if (strcasecmp(target, "int") == 0) {
1890
0
      tmp = malloc(buflen + 1);
1891
1892
0
      if (tmp == NULL) {
1893
0
        ucl_create_err(&parser->err, "Memory allocation failed");
1894
0
        if (buf) {
1895
0
          ucl_munmap(buf, buflen);
1896
0
        }
1897
1898
0
        return false;
1899
0
      }
1900
1901
0
      snprintf(tmp, buflen + 1, "%.*s", (int) buflen, buf);
1902
0
      iv = strtoll(tmp, NULL, 10);
1903
0
      obj = ucl_object_fromint(iv);
1904
0
      free(tmp);
1905
0
    }
1906
1907
1.23k
    if (buf) {
1908
223
      ucl_munmap(buf, buflen);
1909
223
    }
1910
1911
1.23k
    if (obj != NULL) {
1912
223
      obj->key = prefix;
1913
223
      obj->keylen = strlen(prefix);
1914
223
      ucl_copy_key_trash(obj);
1915
223
      obj->prev = obj;
1916
223
      obj->next = NULL;
1917
223
      ucl_object_set_priority(obj, priority);
1918
223
      ucl_object_insert_key(container, obj, obj->key, obj->keylen, false);
1919
223
    }
1920
1921
1.23k
    return true;
1922
1.23k
  }
1923
1924
234
  ucl_create_err(&parser->err, "Unable to parse load macro");
1925
234
  return false;
1926
7.61k
}
1927
1928
bool ucl_inherit_handler(const unsigned char *data, size_t len,
1929
             const ucl_object_t *args, const ucl_object_t *ctx, void *ud)
1930
1
{
1931
1
  const ucl_object_t *parent, *cur;
1932
1
  ucl_object_t *target, *copy;
1933
1
  ucl_object_iter_t it = NULL;
1934
1
  bool replace = false;
1935
1
  struct ucl_parser *parser = ud;
1936
1937
1
  parent = ucl_object_lookup_len(ctx, data, len);
1938
1939
  /* Some sanity checks */
1940
1
  if (parent == NULL || ucl_object_type(parent) != UCL_OBJECT) {
1941
1
    ucl_create_err(&parser->err, "Unable to find inherited object %.*s",
1942
1
             (int) len, data);
1943
1
    return false;
1944
1
  }
1945
1946
0
  if (parser->stack == NULL || parser->stack->obj == NULL ||
1947
0
    ucl_object_type(parser->stack->obj) != UCL_OBJECT) {
1948
0
    ucl_create_err(&parser->err, "Invalid inherit context");
1949
0
    return false;
1950
0
  }
1951
1952
0
  target = parser->stack->obj;
1953
1954
0
  if (args && (cur = ucl_object_lookup(args, "replace")) != NULL) {
1955
0
    replace = ucl_object_toboolean(cur);
1956
0
  }
1957
1958
0
  while ((cur = ucl_object_iterate(parent, &it, true))) {
1959
    /* We do not replace existing keys */
1960
0
    if (!replace && ucl_object_lookup_len(target, cur->key, cur->keylen)) {
1961
0
      continue;
1962
0
    }
1963
1964
0
    copy = ucl_object_copy(cur);
1965
1966
0
    if (!replace) {
1967
0
      copy->flags |= UCL_OBJECT_INHERITED;
1968
0
    }
1969
1970
0
    ucl_object_insert_key(target, copy, copy->key,
1971
0
                copy->keylen, false);
1972
0
  }
1973
1974
0
  return true;
1975
0
}
1976
1977
bool ucl_parser_set_filevars(struct ucl_parser *parser, const char *filename, bool need_expand)
1978
30.6k
{
1979
30.6k
  char realbuf[PATH_MAX], *curdir;
1980
1981
30.6k
  if (filename != NULL) {
1982
1.08k
    if (need_expand) {
1983
0
      if (ucl_realpath(filename, realbuf) == NULL) {
1984
0
        return false;
1985
0
      }
1986
0
    }
1987
1.08k
    else {
1988
1.08k
      ucl_strlcpy(realbuf, filename, sizeof(realbuf));
1989
1.08k
    }
1990
1991
1.08k
    if (parser->cur_file) {
1992
0
      UCL_FREE(strlen(parser->cur_file) + 1, parser->cur_file);
1993
0
    }
1994
1995
1.08k
    parser->cur_file = UCL_STRDUP(realbuf);
1996
1997
    /* Define variables */
1998
1.08k
    ucl_parser_register_variable(parser, "FILENAME", realbuf);
1999
1.08k
    curdir = dirname(realbuf);
2000
1.08k
    ucl_parser_register_variable(parser, "CURDIR", curdir);
2001
1.08k
  }
2002
29.5k
  else {
2003
    /* Set everything from the current dir */
2004
29.5k
    curdir = getcwd(realbuf, sizeof(realbuf));
2005
29.5k
    ucl_parser_register_variable(parser, "FILENAME", "undef");
2006
29.5k
    ucl_parser_register_variable(parser, "CURDIR", curdir);
2007
29.5k
  }
2008
2009
30.6k
  return true;
2010
30.6k
}
2011
2012
bool ucl_parser_add_file_full(struct ucl_parser *parser, const char *filename,
2013
                unsigned priority, enum ucl_duplicate_strategy strat,
2014
                enum ucl_parse_type parse_type)
2015
0
{
2016
0
  unsigned char *buf;
2017
0
  size_t len;
2018
0
  bool ret;
2019
0
  char realbuf[PATH_MAX];
2020
2021
0
  if (ucl_realpath(filename, realbuf) == NULL) {
2022
0
    ucl_create_err(&parser->err, "cannot open file %s: %s",
2023
0
             filename,
2024
0
             strerror(errno));
2025
0
    return false;
2026
0
  }
2027
2028
0
  if (!ucl_fetch_file(realbuf, &buf, &len, &parser->err, true)) {
2029
0
    return false;
2030
0
  }
2031
2032
0
  ucl_parser_set_filevars(parser, realbuf, false);
2033
0
  ret = ucl_parser_add_chunk_full(parser, buf, len, priority, strat,
2034
0
                  parse_type);
2035
2036
0
  if (len > 0) {
2037
0
    ucl_munmap(buf, len);
2038
0
  }
2039
2040
0
  return ret;
2041
0
}
2042
2043
bool ucl_parser_add_file_priority(struct ucl_parser *parser, const char *filename,
2044
                  unsigned priority)
2045
0
{
2046
0
  if (parser == NULL) {
2047
0
    return false;
2048
0
  }
2049
2050
0
  return ucl_parser_add_file_full(parser, filename, priority,
2051
0
                  UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2052
0
}
2053
2054
bool ucl_parser_add_file(struct ucl_parser *parser, const char *filename)
2055
0
{
2056
0
  if (parser == NULL) {
2057
0
    return false;
2058
0
  }
2059
2060
0
  return ucl_parser_add_file_full(parser, filename,
2061
0
                  parser->default_priority, UCL_DUPLICATE_APPEND,
2062
0
                  UCL_PARSE_UCL);
2063
0
}
2064
2065
2066
bool ucl_parser_add_fd_full(struct ucl_parser *parser, int fd,
2067
              unsigned priority, enum ucl_duplicate_strategy strat,
2068
              enum ucl_parse_type parse_type)
2069
0
{
2070
0
  unsigned char *buf;
2071
0
  size_t len;
2072
0
  bool ret;
2073
0
  struct stat st;
2074
2075
0
  if (fstat(fd, &st) == -1) {
2076
0
    ucl_create_err(&parser->err, "cannot stat fd %d: %s",
2077
0
             fd, strerror(errno));
2078
0
    return false;
2079
0
  }
2080
0
  if (st.st_size == 0) {
2081
0
    return true;
2082
0
  }
2083
0
  if ((buf = ucl_mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
2084
0
    ucl_create_err(&parser->err, "cannot mmap fd %d: %s",
2085
0
             fd, strerror(errno));
2086
0
    return false;
2087
0
  }
2088
2089
0
  if (parser->cur_file) {
2090
0
    UCL_FREE(strlen(parser->cur_file) + 1, parser->cur_file);
2091
0
  }
2092
0
  parser->cur_file = NULL;
2093
0
  len = st.st_size;
2094
0
  ret = ucl_parser_add_chunk_full(parser, buf, len, priority, strat,
2095
0
                  parse_type);
2096
2097
0
  if (len > 0) {
2098
0
    ucl_munmap(buf, len);
2099
0
  }
2100
2101
0
  return ret;
2102
0
}
2103
2104
bool ucl_parser_add_fd_priority(struct ucl_parser *parser, int fd,
2105
                unsigned priority)
2106
0
{
2107
0
  if (parser == NULL) {
2108
0
    return false;
2109
0
  }
2110
2111
0
  return ucl_parser_add_fd_full(parser, fd, parser->default_priority,
2112
0
                  UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2113
0
}
2114
2115
bool ucl_parser_add_fd(struct ucl_parser *parser, int fd)
2116
0
{
2117
0
  if (parser == NULL) {
2118
0
    return false;
2119
0
  }
2120
2121
0
  return ucl_parser_add_fd_priority(parser, fd, parser->default_priority);
2122
0
}
2123
2124
size_t
2125
ucl_strlcpy(char *dst, const char *src, size_t siz)
2126
38.0k
{
2127
38.0k
  char *d = dst;
2128
38.0k
  const char *s = src;
2129
38.0k
  size_t n = siz;
2130
2131
  /* Copy as many bytes as will fit */
2132
38.0k
  if (n != 0) {
2133
29.0M
    while (--n != 0) {
2134
29.0M
      if ((*d++ = *s++) == '\0') {
2135
4.05k
        break;
2136
4.05k
      }
2137
29.0M
    }
2138
38.0k
  }
2139
2140
38.0k
  if (n == 0 && siz != 0) {
2141
34.0k
    *d = '\0';
2142
34.0k
  }
2143
2144
38.0k
  return (s - src - 1); /* count does not include NUL */
2145
38.0k
}
2146
2147
size_t
2148
ucl_strlcpy_unsafe(char *dst, const char *src, size_t siz)
2149
967k
{
2150
967k
  memcpy(dst, src, siz - 1);
2151
967k
  dst[siz - 1] = '\0';
2152
2153
967k
  return siz - 1;
2154
967k
}
2155
2156
size_t
2157
ucl_strlcpy_tolower(char *dst, const char *src, size_t siz)
2158
0
{
2159
0
  char *d = dst;
2160
0
  const char *s = src;
2161
0
  size_t n = siz;
2162
2163
  /* Copy as many bytes as will fit */
2164
0
  if (n != 0) {
2165
0
    while (--n != 0) {
2166
0
      if ((*d++ = tolower(*s++)) == '\0') {
2167
0
        break;
2168
0
      }
2169
0
    }
2170
0
  }
2171
2172
0
  if (n == 0 && siz != 0) {
2173
0
    *d = '\0';
2174
0
  }
2175
2176
0
  return (s - src); /* count does not include NUL */
2177
0
}
2178
2179
/*
2180
 * Find the first occurrence of find in s
2181
 */
2182
char *
2183
ucl_strnstr(const char *s, const char *find, int len)
2184
2
{
2185
2
  char c, sc;
2186
2
  int mlen;
2187
2188
2
  if ((c = *find++) != 0) {
2189
2
    mlen = strlen(find);
2190
2
    do {
2191
2.72M
      do {
2192
2.72M
        if ((sc = *s++) == 0 || len-- < mlen)
2193
2
          return (NULL);
2194
2.72M
      } while (sc != c);
2195
2
    } while (strncmp(s, find, mlen) != 0);
2196
0
    s--;
2197
0
  }
2198
0
  return ((char *) s);
2199
2
}
2200
2201
/*
2202
 * Find the first occurrence of find in s, ignore case.
2203
 */
2204
char *
2205
ucl_strncasestr(const char *s, const char *find, int len)
2206
0
{
2207
0
  char c, sc;
2208
0
  int mlen;
2209
2210
0
  if ((c = *find++) != 0) {
2211
0
    c = tolower(c);
2212
0
    mlen = strlen(find);
2213
0
    do {
2214
0
      do {
2215
0
        if ((sc = *s++) == 0 || len-- == 0)
2216
0
          return (NULL);
2217
0
      } while (tolower(sc) != c);
2218
0
    } while (strncasecmp(s, find, mlen) != 0);
2219
0
    s--;
2220
0
  }
2221
0
  return ((char *) s);
2222
0
}
2223
2224
ucl_object_t *
2225
ucl_object_fromstring_common(const char *str, size_t len, enum ucl_string_flags flags)
2226
235
{
2227
235
  ucl_object_t *obj;
2228
235
  const char *start, *end, *p, *pos;
2229
235
  char *dst, *d;
2230
235
  size_t escaped_len;
2231
2232
235
  if (str == NULL) {
2233
12
    return NULL;
2234
12
  }
2235
2236
223
  obj = ucl_object_new();
2237
223
  if (obj) {
2238
223
    if (len == 0) {
2239
0
      len = strlen(str);
2240
0
    }
2241
223
    if (flags & UCL_STRING_TRIM) {
2242
      /* Skip leading spaces */
2243
35
      for (start = str; (size_t) (start - str) < len; start++) {
2244
35
        if (!ucl_test_character(*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2245
35
          break;
2246
35
        }
2247
35
      }
2248
      /* Skip trailing spaces */
2249
70
      for (end = str + len - 1; end > start; end--) {
2250
70
        if (!ucl_test_character(*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2251
35
          break;
2252
35
        }
2253
70
      }
2254
35
      end++;
2255
35
    }
2256
188
    else {
2257
188
      start = str;
2258
188
      end = str + len;
2259
188
    }
2260
2261
223
    obj->type = UCL_STRING;
2262
223
    if (flags & UCL_STRING_ESCAPE) {
2263
568k
      for (p = start, escaped_len = 0; p < end; p++, escaped_len++) {
2264
568k
        if (ucl_test_character(*p, UCL_CHARACTER_JSON_UNSAFE | UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2265
97.5k
          switch (*p) {
2266
0
          case '\v':
2267
0
          case '\0':
2268
0
            escaped_len += 5;
2269
0
            break;
2270
75.9k
          case ' ':
2271
75.9k
            break;
2272
21.5k
          default:
2273
21.5k
            escaped_len++;
2274
21.5k
            break;
2275
97.5k
          }
2276
97.5k
        }
2277
568k
      }
2278
195
      dst = malloc(escaped_len + 1);
2279
195
      if (dst != NULL) {
2280
568k
        for (p = start, d = dst; p < end; p++, d++) {
2281
568k
          if (ucl_test_character(*p, UCL_CHARACTER_JSON_UNSAFE | UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2282
97.5k
            switch (*p) {
2283
16.4k
            case '\n':
2284
16.4k
              *d++ = '\\';
2285
16.4k
              *d = 'n';
2286
16.4k
              break;
2287
0
            case '\r':
2288
0
              *d++ = '\\';
2289
0
              *d = 'r';
2290
0
              break;
2291
0
            case '\b':
2292
0
              *d++ = '\\';
2293
0
              *d = 'b';
2294
0
              break;
2295
24
            case '\t':
2296
24
              *d++ = '\\';
2297
24
              *d = 't';
2298
24
              break;
2299
0
            case '\f':
2300
0
              *d++ = '\\';
2301
0
              *d = 'f';
2302
0
              break;
2303
0
            case '\0':
2304
0
              *d++ = '\\';
2305
0
              *d++ = 'u';
2306
0
              *d++ = '0';
2307
0
              *d++ = '0';
2308
0
              *d++ = '0';
2309
0
              *d = '0';
2310
0
              break;
2311
0
            case '\v':
2312
0
              *d++ = '\\';
2313
0
              *d++ = 'u';
2314
0
              *d++ = '0';
2315
0
              *d++ = '0';
2316
0
              *d++ = '0';
2317
0
              *d = 'B';
2318
0
              break;
2319
195
            case '\\':
2320
195
              *d++ = '\\';
2321
195
              *d = '\\';
2322
195
              break;
2323
75.9k
            case ' ':
2324
75.9k
              *d = ' ';
2325
75.9k
              break;
2326
4.90k
            case '"':
2327
4.90k
              *d++ = '\\';
2328
4.90k
              *d = '"';
2329
4.90k
              break;
2330
97.5k
            }
2331
97.5k
          }
2332
471k
          else {
2333
471k
            *d = *p;
2334
471k
          }
2335
568k
        }
2336
195
        *d = '\0';
2337
195
        obj->value.sv = dst;
2338
195
        obj->trash_stack[UCL_TRASH_VALUE] = dst;
2339
195
        obj->len = escaped_len;
2340
195
      }
2341
195
    }
2342
28
    else {
2343
28
      dst = malloc(end - start + 1);
2344
28
      if (dst != NULL) {
2345
28
        ucl_strlcpy_unsafe(dst, start, end - start + 1);
2346
28
        obj->value.sv = dst;
2347
28
        obj->trash_stack[UCL_TRASH_VALUE] = dst;
2348
28
        obj->len = end - start;
2349
28
      }
2350
28
    }
2351
223
    if ((flags & UCL_STRING_PARSE) && dst != NULL) {
2352
      /* Parse what we have */
2353
0
      if (flags & UCL_STRING_PARSE_BOOLEAN) {
2354
0
        if (!ucl_maybe_parse_boolean(obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
2355
0
          ucl_maybe_parse_number(obj, dst, dst + obj->len, &pos,
2356
0
                       flags & UCL_STRING_PARSE_DOUBLE,
2357
0
                       flags & UCL_STRING_PARSE_BYTES,
2358
0
                       flags & UCL_STRING_PARSE_TIME);
2359
0
        }
2360
0
      }
2361
0
      else {
2362
0
        ucl_maybe_parse_number(obj, dst, dst + obj->len, &pos,
2363
0
                     flags & UCL_STRING_PARSE_DOUBLE,
2364
0
                     flags & UCL_STRING_PARSE_BYTES,
2365
0
                     flags & UCL_STRING_PARSE_TIME);
2366
0
      }
2367
0
    }
2368
223
  }
2369
2370
223
  return obj;
2371
223
}
2372
2373
static bool
2374
ucl_object_insert_key_common(ucl_object_t *top, ucl_object_t *elt,
2375
               const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
2376
223
{
2377
223
  ucl_object_t *found, *tmp;
2378
223
  const ucl_object_t *cur;
2379
223
  ucl_object_iter_t it = NULL;
2380
223
  const char *p;
2381
223
  int ret = true;
2382
2383
223
  if (elt == NULL || key == NULL) {
2384
0
    return false;
2385
0
  }
2386
2387
223
  if (top == NULL) {
2388
0
    return false;
2389
0
  }
2390
2391
223
  if (top->type != UCL_OBJECT) {
2392
    /* It is possible to convert NULL type to an object */
2393
0
    if (top->type == UCL_NULL) {
2394
0
      top->type = UCL_OBJECT;
2395
0
    }
2396
0
    else {
2397
      /* Refuse converting of other object types */
2398
0
      return false;
2399
0
    }
2400
0
  }
2401
2402
223
  if (top->value.ov == NULL) {
2403
0
    top->value.ov = ucl_hash_create(false);
2404
0
  }
2405
2406
223
  if (keylen == 0) {
2407
0
    keylen = strlen(key);
2408
0
  }
2409
2410
451
  for (p = key; p < key + keylen; p++) {
2411
233
    if (ucl_test_character(*p, UCL_CHARACTER_UCL_UNSAFE)) {
2412
5
      elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
2413
5
      break;
2414
5
    }
2415
233
  }
2416
2417
  /* workaround for some use cases */
2418
223
  if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
2419
223
    key != (const char *) elt->trash_stack[UCL_TRASH_KEY]) {
2420
    /* Remove copied key */
2421
0
    free(elt->trash_stack[UCL_TRASH_KEY]);
2422
0
    elt->trash_stack[UCL_TRASH_KEY] = NULL;
2423
0
    elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
2424
0
  }
2425
2426
223
  elt->key = key;
2427
223
  elt->keylen = keylen;
2428
2429
223
  if (copy_key) {
2430
0
    ucl_copy_key_trash(elt);
2431
0
  }
2432
2433
223
  found = __DECONST(ucl_object_t *, ucl_hash_search_obj(top->value.ov, elt));
2434
2435
223
  if (found == NULL) {
2436
223
    top->value.ov = ucl_hash_insert_object(top->value.ov, elt, false);
2437
223
    top->len++;
2438
    /* Key was inserted - return true regardless of replace flag */
2439
223
  }
2440
0
  else {
2441
0
    if (replace) {
2442
0
      ucl_hash_replace(top->value.ov, found, elt);
2443
0
      ucl_object_unref(found);
2444
0
    }
2445
0
    else if (merge) {
2446
0
      if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
2447
        /* Insert old elt to new one */
2448
0
        ucl_object_insert_key_common(elt, found, found->key,
2449
0
                       found->keylen, copy_key, false, false);
2450
0
        ucl_hash_delete(top->value.ov, found);
2451
0
        top->value.ov = ucl_hash_insert_object(top->value.ov, elt, false);
2452
0
      }
2453
0
      else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
2454
        /* Insert new to old */
2455
0
        ucl_object_insert_key_common(found, elt, elt->key,
2456
0
                       elt->keylen, copy_key, false, false);
2457
0
      }
2458
0
      else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
2459
        /* Mix two hashes */
2460
0
        while ((cur = ucl_object_iterate(elt, &it, true)) != NULL) {
2461
0
          tmp = ucl_object_ref(cur);
2462
0
          ucl_object_insert_key_common(found, tmp, cur->key,
2463
0
                         cur->keylen, copy_key, true, false);
2464
0
        }
2465
0
        ucl_object_unref(elt);
2466
0
      }
2467
0
      else {
2468
        /* Just make a list of scalars */
2469
0
        DL_CONCAT(found, elt);
2470
0
      }
2471
0
    }
2472
0
    else {
2473
0
      DL_CONCAT(found, elt);
2474
0
    }
2475
0
  }
2476
2477
223
  return ret;
2478
223
}
2479
2480
bool ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen)
2481
0
{
2482
0
  ucl_object_t *found;
2483
2484
0
  if (top == NULL || key == NULL) {
2485
0
    return false;
2486
0
  }
2487
2488
0
  found = __DECONST(ucl_object_t *, ucl_object_lookup_len(top, key, keylen));
2489
2490
0
  if (found == NULL) {
2491
0
    return false;
2492
0
  }
2493
2494
0
  ucl_hash_delete(top->value.ov, found);
2495
0
  ucl_object_unref(found);
2496
0
  top->len--;
2497
2498
0
  return true;
2499
0
}
2500
2501
bool ucl_object_delete_key(ucl_object_t *top, const char *key)
2502
0
{
2503
0
  return ucl_object_delete_keyl(top, key, strlen(key));
2504
0
}
2505
2506
ucl_object_t *
2507
ucl_object_pop_keyl(ucl_object_t *top, const char *key, size_t keylen)
2508
0
{
2509
0
  const ucl_object_t *found;
2510
2511
0
  if (top == NULL || key == NULL) {
2512
0
    return false;
2513
0
  }
2514
0
  found = ucl_object_lookup_len(top, key, keylen);
2515
2516
0
  if (found == NULL) {
2517
0
    return NULL;
2518
0
  }
2519
0
  ucl_hash_delete(top->value.ov, found);
2520
0
  top->len--;
2521
2522
0
  return __DECONST(ucl_object_t *, found);
2523
0
}
2524
2525
ucl_object_t *
2526
ucl_object_pop_key(ucl_object_t *top, const char *key)
2527
0
{
2528
0
  return ucl_object_pop_keyl(top, key, strlen(key));
2529
0
}
2530
2531
bool ucl_object_insert_key(ucl_object_t *top, ucl_object_t *elt,
2532
               const char *key, size_t keylen, bool copy_key)
2533
223
{
2534
223
  return ucl_object_insert_key_common(top, elt, key, keylen, copy_key, false, false);
2535
223
}
2536
2537
bool ucl_object_insert_key_merged(ucl_object_t *top, ucl_object_t *elt,
2538
                  const char *key, size_t keylen, bool copy_key)
2539
0
{
2540
0
  return ucl_object_insert_key_common(top, elt, key, keylen, copy_key, true, false);
2541
0
}
2542
2543
bool ucl_object_replace_key(ucl_object_t *top, ucl_object_t *elt,
2544
              const char *key, size_t keylen, bool copy_key)
2545
0
{
2546
0
  return ucl_object_insert_key_common(top, elt, key, keylen, copy_key, false, true);
2547
0
}
2548
2549
bool ucl_object_merge(ucl_object_t *top, ucl_object_t *elt, bool copy)
2550
0
{
2551
0
  ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
2552
0
  ucl_object_iter_t iter = NULL;
2553
2554
0
  if (top == NULL || elt == NULL) {
2555
0
    return false;
2556
0
  }
2557
2558
0
  if (top->type == UCL_ARRAY) {
2559
0
    if (elt->type == UCL_ARRAY) {
2560
      /* Merge two arrays */
2561
0
      return ucl_array_merge(top, elt, copy);
2562
0
    }
2563
0
    else {
2564
0
      if (copy) {
2565
0
        ucl_array_append(top, ucl_object_copy(elt));
2566
2567
0
        return true;
2568
0
      }
2569
0
      else {
2570
0
        ucl_array_append(top, ucl_object_ref(elt));
2571
2572
0
        return true;
2573
0
      }
2574
0
    }
2575
0
  }
2576
0
  else if (top->type == UCL_OBJECT) {
2577
0
    if (elt->type == UCL_OBJECT) {
2578
      /* Mix two hashes */
2579
0
      while ((cur = (ucl_object_t *) ucl_hash_iterate(elt->value.ov,
2580
0
                              &iter))) {
2581
2582
0
        if (copy) {
2583
0
          cp = ucl_object_copy(cur);
2584
0
        }
2585
0
        else {
2586
0
          cp = ucl_object_ref(cur);
2587
0
        }
2588
2589
0
        found = __DECONST(ucl_object_t *,
2590
0
                  ucl_hash_search(top->value.ov, cp->key, cp->keylen));
2591
2592
0
        if (found == NULL) {
2593
          /* The key does not exist */
2594
0
          top->value.ov = ucl_hash_insert_object(top->value.ov, cp,
2595
0
                               false);
2596
0
          top->len++;
2597
0
        }
2598
0
        else {
2599
          /* The key already exists, merge it recursively */
2600
0
          if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
2601
0
            if (!ucl_object_merge(found, cp, copy)) {
2602
0
              return false;
2603
0
            }
2604
0
            ucl_object_unref(cp);
2605
0
          }
2606
0
          else {
2607
0
            ucl_hash_replace(top->value.ov, found, cp);
2608
0
            ucl_object_unref(found);
2609
0
          }
2610
0
        }
2611
0
      }
2612
0
    }
2613
0
    else {
2614
0
      if (copy) {
2615
0
        cp = ucl_object_copy(elt);
2616
0
      }
2617
0
      else {
2618
0
        cp = ucl_object_ref(elt);
2619
0
      }
2620
2621
0
      found = __DECONST(ucl_object_t *,
2622
0
                ucl_hash_search(top->value.ov, cp->key, cp->keylen));
2623
2624
0
      if (found == NULL) {
2625
        /* The key does not exist */
2626
0
        top->value.ov = ucl_hash_insert_object(top->value.ov, cp,
2627
0
                             false);
2628
0
        top->len++;
2629
0
      }
2630
0
      else {
2631
        /* The key already exists, merge it recursively */
2632
0
        if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
2633
0
          if (!ucl_object_merge(found, cp, copy)) {
2634
0
            return false;
2635
0
          }
2636
0
          ucl_object_unref(cp);
2637
0
        }
2638
0
        else {
2639
0
          ucl_hash_replace(top->value.ov, found, cp);
2640
0
          ucl_object_unref(found);
2641
0
        }
2642
0
      }
2643
0
    }
2644
0
  }
2645
0
  else {
2646
    /* Cannot merge trivial objects */
2647
0
    return false;
2648
0
  }
2649
2650
0
  return true;
2651
0
}
2652
2653
const ucl_object_t *
2654
ucl_object_lookup_len(const ucl_object_t *obj, const char *key, size_t klen)
2655
1.47k
{
2656
1.47k
  const ucl_object_t *ret;
2657
1.47k
  ucl_object_t srch;
2658
2659
1.47k
  if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
2660
0
    return NULL;
2661
0
  }
2662
2663
1.47k
  srch.key = key;
2664
1.47k
  srch.keylen = klen;
2665
1.47k
  ret = ucl_hash_search_obj(obj->value.ov, &srch);
2666
2667
1.47k
  return ret;
2668
1.47k
}
2669
2670
const ucl_object_t *
2671
ucl_object_lookup(const ucl_object_t *obj, const char *key)
2672
1.47k
{
2673
1.47k
  if (key == NULL) {
2674
0
    return NULL;
2675
0
  }
2676
2677
1.47k
  return ucl_object_lookup_len(obj, key, strlen(key));
2678
1.47k
}
2679
2680
const ucl_object_t *
2681
ucl_object_lookup_any(const ucl_object_t *obj,
2682
            const char *key, ...)
2683
0
{
2684
0
  va_list ap;
2685
0
  const ucl_object_t *ret = NULL;
2686
0
  const char *nk = NULL;
2687
2688
0
  if (obj == NULL || key == NULL) {
2689
0
    return NULL;
2690
0
  }
2691
2692
0
  ret = ucl_object_lookup_len(obj, key, strlen(key));
2693
2694
0
  if (ret == NULL) {
2695
0
    va_start(ap, key);
2696
2697
0
    while (ret == NULL) {
2698
0
      nk = va_arg(ap, const char *);
2699
2700
0
      if (nk == NULL) {
2701
0
        break;
2702
0
      }
2703
0
      else {
2704
0
        ret = ucl_object_lookup_len(obj, nk, strlen(nk));
2705
0
      }
2706
0
    }
2707
2708
0
    va_end(ap);
2709
0
  }
2710
2711
0
  return ret;
2712
0
}
2713
2714
const ucl_object_t *
2715
ucl_object_iterate_with_error(const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values,
2716
                int *ep)
2717
1.28M
{
2718
1.28M
  const ucl_object_t *elt = NULL;
2719
2720
1.28M
  if (obj == NULL || iter == NULL) {
2721
0
    return NULL;
2722
0
  }
2723
2724
1.28M
  if (expand_values) {
2725
1.28M
    switch (obj->type) {
2726
38.9k
    case UCL_OBJECT:
2727
38.9k
      return (const ucl_object_t *) ucl_hash_iterate2(obj->value.ov, iter, ep);
2728
0
      break;
2729
1.24M
    case UCL_ARRAY: {
2730
1.24M
      unsigned int idx;
2731
1.24M
      UCL_ARRAY_GET(vec, obj);
2732
1.24M
      idx = (unsigned int) (uintptr_t) (*iter);
2733
2734
1.24M
      if (vec != NULL) {
2735
1.24M
        while (idx < kv_size(*vec)) {
2736
1.24M
          if ((elt = kv_A(*vec, idx)) != NULL) {
2737
1.24M
            idx++;
2738
1.24M
            break;
2739
1.24M
          }
2740
0
          idx++;
2741
0
        }
2742
1.24M
        *iter = (void *) (uintptr_t) idx;
2743
1.24M
      }
2744
2745
1.24M
      return elt;
2746
0
      break;
2747
0
    }
2748
0
    default:
2749
      /* Go to linear iteration */
2750
0
      break;
2751
1.28M
    }
2752
1.28M
  }
2753
  /* Treat everything as a linear list */
2754
0
  elt = *iter;
2755
0
  if (elt == NULL) {
2756
0
    elt = obj;
2757
0
  }
2758
0
  else if (elt == obj) {
2759
0
    return NULL;
2760
0
  }
2761
0
  *iter = __DECONST(void *, elt->next ? elt->next : obj);
2762
0
  return elt;
2763
2764
  /* Not reached */
2765
0
  return NULL;
2766
0
}
2767
2768
void
2769
ucl_object_iterate_end(const ucl_object_t *obj, ucl_object_iter_t *iter)
2770
0
{
2771
0
  if (iter == NULL || *iter == NULL) {
2772
0
    return;
2773
0
  }
2774
2775
0
  if (obj != NULL && obj->type == UCL_OBJECT) {
2776
0
    ucl_hash_iterate_free(*iter);
2777
0
  }
2778
2779
0
  *iter = NULL;
2780
0
}
2781
2782
enum ucl_safe_iter_flags {
2783
  UCL_ITERATE_FLAG_UNDEFINED = 0,
2784
  UCL_ITERATE_FLAG_INSIDE_ARRAY,
2785
  UCL_ITERATE_FLAG_INSIDE_OBJECT,
2786
  UCL_ITERATE_FLAG_IMPLICIT,
2787
  UCL_ITERATE_FLAG_EXCEPTION
2788
};
2789
2790
static const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
2791
struct ucl_object_safe_iter {
2792
  char magic[4]; /* safety check */
2793
  uint32_t flags;
2794
  const ucl_object_t *impl_it; /* implicit object iteration */
2795
  ucl_object_iter_t expl_it;   /* explicit iteration */
2796
};
2797
2798
560k
#define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *) (ptr)
2799
#define UCL_SAFE_ITER_CHECK(it)                                             \
2800
560k
  do {                                                                    \
2801
560k
    assert(it != NULL);                                                 \
2802
560k
    assert(memcmp(it->magic, safe_iter_magic, sizeof(it->magic)) == 0); \
2803
560k
  } while (0)
2804
2805
ucl_object_iter_t
2806
ucl_object_iterate_new(const ucl_object_t *obj)
2807
6
{
2808
6
  struct ucl_object_safe_iter *it;
2809
2810
6
  it = UCL_ALLOC(sizeof(*it));
2811
6
  if (it != NULL) {
2812
6
    memcpy(it->magic, safe_iter_magic, sizeof(it->magic));
2813
6
    it->flags = UCL_ITERATE_FLAG_UNDEFINED;
2814
6
    it->expl_it = NULL;
2815
6
    it->impl_it = obj;
2816
6
  }
2817
2818
6
  return (ucl_object_iter_t) it;
2819
6
}
2820
2821
bool ucl_object_iter_chk_excpn(ucl_object_iter_t *it)
2822
0
{
2823
0
  struct ucl_object_safe_iter *rit = UCL_SAFE_ITER(it);
2824
2825
0
  UCL_SAFE_ITER_CHECK(rit);
2826
2827
0
  return (rit->flags == UCL_ITERATE_FLAG_EXCEPTION);
2828
0
}
2829
2830
ucl_object_iter_t
2831
ucl_object_iterate_reset(ucl_object_iter_t it, const ucl_object_t *obj)
2832
0
{
2833
0
  struct ucl_object_safe_iter *rit = UCL_SAFE_ITER(it);
2834
2835
0
  UCL_SAFE_ITER_CHECK(rit);
2836
2837
0
  if (rit->expl_it != NULL) {
2838
0
    if (rit->flags == UCL_ITERATE_FLAG_INSIDE_OBJECT) {
2839
0
      UCL_FREE(sizeof(*rit->expl_it), rit->expl_it);
2840
0
    }
2841
0
  }
2842
2843
0
  rit->impl_it = obj;
2844
0
  rit->expl_it = NULL;
2845
0
  rit->flags = UCL_ITERATE_FLAG_UNDEFINED;
2846
2847
0
  return it;
2848
0
}
2849
2850
const ucl_object_t *
2851
ucl_object_iterate_safe(ucl_object_iter_t it, bool expand_values)
2852
560k
{
2853
560k
  return ucl_object_iterate_full(it, expand_values ? UCL_ITERATE_BOTH : UCL_ITERATE_IMPLICIT);
2854
560k
}
2855
2856
const ucl_object_t *
2857
ucl_object_iterate_full(ucl_object_iter_t it, enum ucl_iterate_type type)
2858
560k
{
2859
560k
  struct ucl_object_safe_iter *rit = UCL_SAFE_ITER(it);
2860
560k
  const ucl_object_t *ret = NULL;
2861
560k
  int ern;
2862
2863
560k
  UCL_SAFE_ITER_CHECK(rit);
2864
2865
560k
  if (rit->impl_it == NULL) {
2866
5
    return NULL;
2867
5
  }
2868
2869
560k
  if (rit->impl_it->type == UCL_OBJECT) {
2870
0
    rit->flags = UCL_ITERATE_FLAG_INSIDE_OBJECT;
2871
0
    ret = ucl_object_iterate_with_error(rit->impl_it, &rit->expl_it, true, &ern);
2872
2873
0
    if (ret == NULL && ern != 0) {
2874
0
      rit->flags = UCL_ITERATE_FLAG_EXCEPTION;
2875
0
      return NULL;
2876
0
    }
2877
2878
0
    if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
2879
      /* Need to switch to another implicit object in chain */
2880
0
      rit->impl_it = rit->impl_it->next;
2881
0
      rit->expl_it = NULL;
2882
2883
0
      return ucl_object_iterate_safe(it, type);
2884
0
    }
2885
0
  }
2886
560k
  else if (rit->impl_it->type == UCL_ARRAY) {
2887
560k
    rit->flags = UCL_ITERATE_FLAG_INSIDE_ARRAY;
2888
560k
    ret = ucl_object_iterate(rit->impl_it, &rit->expl_it, true);
2889
2890
560k
    if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
2891
      /* Need to switch to another implicit object in chain */
2892
5
      rit->impl_it = rit->impl_it->next;
2893
5
      rit->expl_it = NULL;
2894
2895
5
      return ucl_object_iterate_safe(it, type);
2896
5
    }
2897
560k
  }
2898
0
  else {
2899
    /* Just iterate over the implicit array */
2900
0
    rit->flags = UCL_ITERATE_FLAG_IMPLICIT;
2901
0
    ret = rit->impl_it;
2902
0
    rit->impl_it = rit->impl_it->next;
2903
2904
0
    if (type & UCL_ITERATE_EXPLICIT) {
2905
      /* We flatten objects if need to expand values */
2906
0
      if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
2907
0
        return ucl_object_iterate_safe(it, type);
2908
0
      }
2909
0
    }
2910
0
  }
2911
2912
560k
  return ret;
2913
560k
}
2914
2915
void ucl_object_iterate_free(ucl_object_iter_t it)
2916
6
{
2917
6
  struct ucl_object_safe_iter *rit = UCL_SAFE_ITER(it);
2918
2919
6
  UCL_SAFE_ITER_CHECK(rit);
2920
2921
6
  if (rit->expl_it != NULL) {
2922
1
    if (rit->flags == UCL_ITERATE_FLAG_INSIDE_OBJECT) {
2923
0
      UCL_FREE(sizeof(*rit->expl_it), rit->expl_it);
2924
0
    }
2925
1
  }
2926
2927
6
  UCL_FREE(sizeof(*rit), it);
2928
6
}
2929
2930
const ucl_object_t *
2931
ucl_object_lookup_path(const ucl_object_t *top, const char *path_in)
2932
0
{
2933
0
  return ucl_object_lookup_path_char(top, path_in, '.');
2934
0
}
2935
2936
2937
const ucl_object_t *
2938
ucl_object_lookup_path_char(const ucl_object_t *top, const char *path_in, const char sep)
2939
0
{
2940
0
  const ucl_object_t *o = NULL, *found;
2941
0
  const char *p, *c;
2942
0
  char *err_str;
2943
0
  unsigned index;
2944
2945
0
  if (path_in == NULL || top == NULL) {
2946
0
    return NULL;
2947
0
  }
2948
2949
0
  found = NULL;
2950
0
  p = path_in;
2951
2952
  /* Skip leading dots */
2953
0
  while (*p == sep) {
2954
0
    p++;
2955
0
  }
2956
2957
0
  c = p;
2958
0
  while (*p != '\0') {
2959
0
    p++;
2960
0
    if (*p == sep || *p == '\0') {
2961
0
      if (p > c) {
2962
0
        switch (top->type) {
2963
0
        case UCL_ARRAY:
2964
          /* Key should be an int */
2965
0
          index = strtoul(c, &err_str, 10);
2966
0
          if (err_str != NULL && (*err_str != sep && *err_str != '\0')) {
2967
0
            return NULL;
2968
0
          }
2969
0
          o = ucl_array_find_index(top, index);
2970
0
          break;
2971
0
        default:
2972
0
          o = ucl_object_lookup_len(top, c, p - c);
2973
0
          break;
2974
0
        }
2975
0
        if (o == NULL) {
2976
0
          return NULL;
2977
0
        }
2978
0
        top = o;
2979
0
      }
2980
0
      if (*p != '\0') {
2981
0
        c = p + 1;
2982
0
      }
2983
0
    }
2984
0
  }
2985
0
  found = o;
2986
2987
0
  return found;
2988
0
}
2989
2990
2991
ucl_object_t *
2992
ucl_object_new(void)
2993
223
{
2994
223
  return ucl_object_typed_new(UCL_NULL);
2995
223
}
2996
2997
ucl_object_t *
2998
ucl_object_typed_new(ucl_type_t type)
2999
223
{
3000
223
  return ucl_object_new_full(type, 0);
3001
223
}
3002
3003
ucl_object_t *
3004
ucl_object_new_full(ucl_type_t type, unsigned priority)
3005
972k
{
3006
972k
  ucl_object_t *new;
3007
3008
972k
  if (type != UCL_USERDATA) {
3009
972k
    new = UCL_ALLOC(sizeof(ucl_object_t));
3010
972k
    if (new != NULL) {
3011
972k
      memset(new, 0, sizeof(ucl_object_t));
3012
972k
      new->ref = 1;
3013
972k
      new->type = (type <= UCL_NULL ? type : UCL_NULL);
3014
972k
      new->next = NULL;
3015
972k
      new->prev = new;
3016
972k
      ucl_object_set_priority(new, priority);
3017
3018
972k
      if (type == UCL_ARRAY) {
3019
2.87k
        new->value.av = UCL_ALLOC(sizeof(ucl_array_t));
3020
2.87k
        if (new->value.av) {
3021
2.87k
          memset(new->value.av, 0, sizeof(ucl_array_t));
3022
2.87k
          UCL_ARRAY_GET(vec, new);
3023
3024
          /* Preallocate some space for arrays */
3025
2.87k
          kv_resize_safe(ucl_object_t *, *vec, 8, enomem);
3026
2.87k
        }
3027
2.87k
      }
3028
972k
    }
3029
972k
  }
3030
0
  else {
3031
0
    new = ucl_object_new_userdata(NULL, NULL, NULL);
3032
0
    ucl_object_set_priority(new, priority);
3033
0
  }
3034
972k
enomem:
3035
972k
  return new;
3036
972k
}
3037
3038
bool ucl_object_reserve(ucl_object_t *obj, size_t reserved)
3039
0
{
3040
0
  if (obj->type == UCL_ARRAY) {
3041
0
    UCL_ARRAY_GET(vec, obj);
3042
3043
0
    if (vec == NULL) {
3044
      /* Allocate array storage if not present (e.g., copied empty array) */
3045
0
      vec = UCL_ALLOC(sizeof(*vec));
3046
0
      if (vec == NULL) {
3047
0
        return false;
3048
0
      }
3049
0
      kv_init(*vec);
3050
0
      obj->value.av = (void *)vec;
3051
0
    }
3052
3053
0
    if (vec->m < reserved) {
3054
      /* Preallocate some space for arrays */
3055
0
      kv_resize_safe(ucl_object_t *, *vec, reserved, e0);
3056
0
    }
3057
0
  }
3058
0
  else if (obj->type == UCL_OBJECT) {
3059
0
    ucl_hash_reserve(obj->value.ov, reserved);
3060
0
  }
3061
0
  return true;
3062
0
e0:
3063
0
  return false;
3064
0
}
3065
3066
ucl_object_t *
3067
ucl_object_new_userdata(ucl_userdata_dtor dtor,
3068
            ucl_userdata_emitter emitter,
3069
            void *ptr)
3070
0
{
3071
0
  struct ucl_object_userdata *new;
3072
0
  size_t nsize = sizeof(*new);
3073
3074
0
  new = UCL_ALLOC(nsize);
3075
0
  if (new != NULL) {
3076
0
    memset(new, 0, nsize);
3077
0
    new->obj.ref = 1;
3078
0
    new->obj.type = UCL_USERDATA;
3079
0
    new->obj.next = NULL;
3080
0
    new->obj.prev = (ucl_object_t *) new;
3081
0
    new->dtor = dtor;
3082
0
    new->emitter = emitter;
3083
0
    new->obj.value.ud = ptr;
3084
0
  }
3085
3086
0
  return (ucl_object_t *) new;
3087
0
}
3088
3089
ucl_type_t
3090
ucl_object_type(const ucl_object_t *obj)
3091
560k
{
3092
560k
  if (obj == NULL) {
3093
0
    return UCL_NULL;
3094
0
  }
3095
3096
560k
  return obj->type;
3097
560k
}
3098
3099
ucl_object_t *
3100
ucl_object_fromstring(const char *str)
3101
0
{
3102
0
  return ucl_object_fromstring_common(str, 0, UCL_STRING_RAW);
3103
0
}
3104
3105
ucl_object_t *
3106
ucl_object_fromlstring(const char *str, size_t len)
3107
0
{
3108
0
  return ucl_object_fromstring_common(str, len, UCL_STRING_RAW);
3109
0
}
3110
3111
ucl_object_t *
3112
ucl_object_fromint(int64_t iv)
3113
0
{
3114
0
  ucl_object_t *obj;
3115
3116
0
  obj = ucl_object_new();
3117
0
  if (obj != NULL) {
3118
0
    obj->type = UCL_INT;
3119
0
    obj->value.iv = iv;
3120
0
  }
3121
3122
0
  return obj;
3123
0
}
3124
3125
ucl_object_t *
3126
ucl_object_fromdouble(double dv)
3127
0
{
3128
0
  ucl_object_t *obj;
3129
3130
0
  obj = ucl_object_new();
3131
0
  if (obj != NULL) {
3132
0
    obj->type = UCL_FLOAT;
3133
0
    obj->value.dv = dv;
3134
0
  }
3135
3136
0
  return obj;
3137
0
}
3138
3139
ucl_object_t *
3140
ucl_object_frombool(bool bv)
3141
0
{
3142
0
  ucl_object_t *obj;
3143
3144
0
  obj = ucl_object_new();
3145
0
  if (obj != NULL) {
3146
0
    obj->type = UCL_BOOLEAN;
3147
0
    obj->value.iv = bv;
3148
0
  }
3149
3150
0
  return obj;
3151
0
}
3152
3153
bool ucl_array_append(ucl_object_t *top, ucl_object_t *elt)
3154
1.48M
{
3155
1.48M
  if (top->type != UCL_ARRAY) {
3156
0
    return false;
3157
0
  }
3158
3159
1.48M
  UCL_ARRAY_GET(vec, top);
3160
3161
1.48M
  if (elt == NULL || top == NULL) {
3162
0
    return false;
3163
0
  }
3164
3165
1.48M
  if (vec == NULL) {
3166
19.1k
    vec = UCL_ALLOC(sizeof(*vec));
3167
3168
19.1k
    if (vec == NULL) {
3169
0
      return false;
3170
0
    }
3171
3172
19.1k
    kv_init(*vec);
3173
19.1k
    top->value.av = (void *) vec;
3174
19.1k
  }
3175
3176
1.48M
  kv_push_safe(ucl_object_t *, *vec, elt, e0);
3177
3178
1.48M
  top->len++;
3179
3180
1.48M
  return true;
3181
0
e0:
3182
0
  return false;
3183
1.48M
}
3184
3185
bool ucl_array_prepend(ucl_object_t *top, ucl_object_t *elt)
3186
0
{
3187
0
  if (top->type != UCL_ARRAY) {
3188
0
    return false;
3189
0
  }
3190
3191
0
  UCL_ARRAY_GET(vec, top);
3192
3193
0
  if (elt == NULL || top == NULL) {
3194
0
    return false;
3195
0
  }
3196
3197
0
  if (vec == NULL) {
3198
0
    vec = UCL_ALLOC(sizeof(*vec));
3199
0
    kv_init(*vec);
3200
0
    top->value.av = (void *) vec;
3201
0
    kv_push_safe(ucl_object_t *, *vec, elt, e0);
3202
0
  }
3203
0
  else {
3204
    /* Slow O(n) algorithm */
3205
0
    kv_prepend_safe(ucl_object_t *, *vec, elt, e0);
3206
0
  }
3207
3208
0
  top->len++;
3209
3210
0
  return true;
3211
0
e0:
3212
0
  return false;
3213
0
}
3214
3215
bool ucl_array_merge(ucl_object_t *top, ucl_object_t *elt, bool copy)
3216
0
{
3217
0
  unsigned i;
3218
0
  ucl_object_t *cp = NULL;
3219
0
  ucl_object_t **obj;
3220
3221
0
  if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
3222
0
    return false;
3223
0
  }
3224
3225
0
  if (copy) {
3226
0
    cp = ucl_object_copy(elt);
3227
0
  }
3228
0
  else {
3229
0
    cp = ucl_object_ref(elt);
3230
0
  }
3231
3232
0
  UCL_ARRAY_GET(v1, top);
3233
0
  UCL_ARRAY_GET(v2, cp);
3234
3235
0
  if (v1 && v2) {
3236
0
    kv_concat_safe(ucl_object_t *, *v1, *v2, e0);
3237
3238
0
    for (i = v2->n; i < v1->n; i++) {
3239
0
      obj = &kv_A(*v1, i);
3240
0
      if (*obj == NULL) {
3241
0
        continue;
3242
0
      }
3243
0
      top->len++;
3244
0
    }
3245
0
  }
3246
3247
0
  return true;
3248
0
e0:
3249
0
  return false;
3250
0
}
3251
3252
ucl_object_t *
3253
ucl_array_delete(ucl_object_t *top, ucl_object_t *elt)
3254
0
{
3255
0
  if (top->type != UCL_ARRAY) {
3256
0
    return NULL;
3257
0
  }
3258
3259
0
  UCL_ARRAY_GET(vec, top);
3260
0
  ucl_object_t *ret = NULL;
3261
0
  unsigned i;
3262
3263
0
  if (vec == NULL) {
3264
0
    return NULL;
3265
0
  }
3266
3267
0
  for (i = 0; i < vec->n; i++) {
3268
0
    if (kv_A(*vec, i) == elt) {
3269
0
      kv_del(ucl_object_t *, *vec, i);
3270
0
      ret = elt;
3271
0
      top->len--;
3272
0
      break;
3273
0
    }
3274
0
  }
3275
3276
0
  return ret;
3277
0
}
3278
3279
const ucl_object_t *
3280
ucl_array_head(const ucl_object_t *top)
3281
0
{
3282
0
  UCL_ARRAY_GET(vec, top);
3283
3284
0
  if (vec == NULL || top == NULL || top->type != UCL_ARRAY ||
3285
0
    top->value.av == NULL) {
3286
0
    return NULL;
3287
0
  }
3288
3289
0
  return (vec->n > 0 ? vec->a[0] : NULL);
3290
0
}
3291
3292
const ucl_object_t *
3293
ucl_array_tail(const ucl_object_t *top)
3294
0
{
3295
0
  UCL_ARRAY_GET(vec, top);
3296
3297
0
  if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
3298
0
    return NULL;
3299
0
  }
3300
3301
0
  return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
3302
0
}
3303
3304
ucl_object_t *
3305
ucl_array_pop_last(ucl_object_t *top)
3306
0
{
3307
0
  if (top->type != UCL_ARRAY) {
3308
0
    return NULL;
3309
0
  }
3310
3311
0
  UCL_ARRAY_GET(vec, top);
3312
0
  ucl_object_t **obj, *ret = NULL;
3313
3314
0
  if (vec != NULL && vec->n > 0) {
3315
0
    obj = &kv_A(*vec, vec->n - 1);
3316
0
    ret = *obj;
3317
0
    kv_del(ucl_object_t *, *vec, vec->n - 1);
3318
0
    top->len--;
3319
0
  }
3320
3321
0
  return ret;
3322
0
}
3323
3324
ucl_object_t *
3325
ucl_array_pop_first(ucl_object_t *top)
3326
0
{
3327
0
  if (top->type != UCL_ARRAY) {
3328
0
    return NULL;
3329
0
  }
3330
3331
0
  UCL_ARRAY_GET(vec, top);
3332
0
  ucl_object_t **obj, *ret = NULL;
3333
3334
0
  if (vec != NULL && vec->n > 0) {
3335
0
    obj = &kv_A(*vec, 0);
3336
0
    ret = *obj;
3337
0
    kv_del(ucl_object_t *, *vec, 0);
3338
0
    top->len--;
3339
0
  }
3340
3341
0
  return ret;
3342
0
}
3343
3344
unsigned int
3345
ucl_array_size(const ucl_object_t *top)
3346
0
{
3347
0
  if (top == NULL || top->type != UCL_ARRAY) {
3348
0
    return 0;
3349
0
  }
3350
3351
0
  UCL_ARRAY_GET(vec, top);
3352
3353
0
  if (vec != NULL) {
3354
0
    return kv_size(*vec);
3355
0
  }
3356
3357
0
  return 0;
3358
0
}
3359
3360
const ucl_object_t *
3361
ucl_array_find_index(const ucl_object_t *top, unsigned int index)
3362
0
{
3363
0
  if (top->type != UCL_ARRAY) {
3364
0
    return NULL;
3365
0
  }
3366
3367
0
  UCL_ARRAY_GET(vec, top);
3368
3369
0
  if (vec != NULL && vec->n > 0 && index < vec->n) {
3370
0
    return kv_A(*vec, index);
3371
0
  }
3372
3373
0
  return NULL;
3374
0
}
3375
3376
unsigned int
3377
ucl_array_index_of(ucl_object_t *top, ucl_object_t *elt)
3378
0
{
3379
0
  if (top->type != UCL_ARRAY) {
3380
0
    return (unsigned int) (-1);
3381
0
  }
3382
3383
0
  UCL_ARRAY_GET(vec, top);
3384
0
  unsigned i;
3385
3386
0
  if (vec == NULL) {
3387
0
    return (unsigned int) (-1);
3388
0
  }
3389
3390
0
  for (i = 0; i < vec->n; i++) {
3391
0
    if (kv_A(*vec, i) == elt) {
3392
0
      return i;
3393
0
    }
3394
0
  }
3395
3396
0
  return (unsigned int) (-1);
3397
0
}
3398
3399
ucl_object_t *
3400
ucl_array_replace_index(ucl_object_t *top, ucl_object_t *elt,
3401
            unsigned int index)
3402
0
{
3403
0
  if (top->type != UCL_ARRAY) {
3404
0
    return NULL;
3405
0
  }
3406
3407
0
  UCL_ARRAY_GET(vec, top);
3408
0
  ucl_object_t *ret = NULL;
3409
3410
0
  if (vec != NULL && vec->n > 0 && index < vec->n) {
3411
0
    ret = kv_A(*vec, index);
3412
0
    kv_A(*vec, index) = elt;
3413
0
  }
3414
3415
0
  return ret;
3416
0
}
3417
3418
ucl_object_t *
3419
ucl_elt_append(ucl_object_t *head, ucl_object_t *elt)
3420
0
{
3421
3422
0
  if (head == NULL) {
3423
0
    elt->next = NULL;
3424
0
    elt->prev = elt;
3425
0
    head = elt;
3426
0
  }
3427
0
  else {
3428
0
    if (head->type == UCL_USERDATA) {
3429
      /* Userdata objects are VERY special! */
3430
0
      struct ucl_object_userdata *ud = (struct ucl_object_userdata *) head;
3431
0
      elt->prev = ud->obj.prev;
3432
0
      ud->obj.prev->next = elt;
3433
0
      ud->obj.prev = elt;
3434
0
      elt->next = NULL;
3435
0
    }
3436
0
    else {
3437
0
      elt->prev = head->prev;
3438
0
      head->prev->next = elt;
3439
0
      head->prev = elt;
3440
0
      elt->next = NULL;
3441
0
    }
3442
0
  }
3443
3444
0
  return head;
3445
0
}
3446
3447
bool ucl_object_todouble_safe(const ucl_object_t *obj, double *target)
3448
0
{
3449
0
  if (obj == NULL || target == NULL) {
3450
0
    return false;
3451
0
  }
3452
0
  switch (obj->type) {
3453
0
  case UCL_INT:
3454
0
    *target = obj->value.iv; /* Probably could cause overflow */
3455
0
    break;
3456
0
  case UCL_FLOAT:
3457
0
  case UCL_TIME:
3458
0
    *target = obj->value.dv;
3459
0
    break;
3460
0
  default:
3461
0
    return false;
3462
0
  }
3463
3464
0
  return true;
3465
0
}
3466
3467
double
3468
ucl_object_todouble(const ucl_object_t *obj)
3469
0
{
3470
0
  double result = 0.;
3471
3472
0
  ucl_object_todouble_safe(obj, &result);
3473
0
  return result;
3474
0
}
3475
3476
bool ucl_object_toint_safe(const ucl_object_t *obj, int64_t *target)
3477
12
{
3478
12
  if (obj == NULL || target == NULL) {
3479
0
    return false;
3480
0
  }
3481
12
  switch (obj->type) {
3482
12
  case UCL_INT:
3483
12
    *target = obj->value.iv;
3484
12
    break;
3485
0
  case UCL_FLOAT:
3486
0
  case UCL_TIME:
3487
0
    *target = obj->value.dv; /* Losing of decimal points */
3488
0
    break;
3489
0
  default:
3490
0
    return false;
3491
12
  }
3492
3493
12
  return true;
3494
12
}
3495
3496
int64_t
3497
ucl_object_toint(const ucl_object_t *obj)
3498
12
{
3499
12
  int64_t result = 0;
3500
3501
12
  ucl_object_toint_safe(obj, &result);
3502
12
  return result;
3503
12
}
3504
3505
bool ucl_object_toboolean_safe(const ucl_object_t *obj, bool *target)
3506
977
{
3507
977
  if (obj == NULL || target == NULL) {
3508
0
    return false;
3509
0
  }
3510
977
  switch (obj->type) {
3511
977
  case UCL_BOOLEAN:
3512
977
    *target = (obj->value.iv == true);
3513
977
    break;
3514
0
  default:
3515
0
    return false;
3516
977
  }
3517
3518
977
  return true;
3519
977
}
3520
3521
bool ucl_object_toboolean(const ucl_object_t *obj)
3522
977
{
3523
977
  bool result = false;
3524
3525
977
  ucl_object_toboolean_safe(obj, &result);
3526
977
  return result;
3527
977
}
3528
3529
bool ucl_object_tostring_safe(const ucl_object_t *obj, const char **target)
3530
572k
{
3531
572k
  if (obj == NULL || target == NULL) {
3532
0
    return false;
3533
0
  }
3534
3535
572k
  switch (obj->type) {
3536
572k
  case UCL_STRING:
3537
572k
    if (!(obj->flags & UCL_OBJECT_BINARY)) {
3538
572k
      *target = ucl_copy_value_trash(obj);
3539
572k
    }
3540
572k
    break;
3541
0
  default:
3542
0
    return false;
3543
572k
  }
3544
3545
572k
  return true;
3546
572k
}
3547
3548
const char *
3549
ucl_object_tostring(const ucl_object_t *obj)
3550
572k
{
3551
572k
  const char *result = NULL;
3552
3553
572k
  ucl_object_tostring_safe(obj, &result);
3554
572k
  return result;
3555
572k
}
3556
3557
const char *
3558
ucl_object_tostring_forced(const ucl_object_t *obj)
3559
0
{
3560
  /* TODO: For binary strings we might encode string here */
3561
0
  if (!(obj->flags & UCL_OBJECT_BINARY)) {
3562
0
    return ucl_copy_value_trash(obj);
3563
0
  }
3564
3565
0
  return NULL;
3566
0
}
3567
3568
bool ucl_object_tolstring_safe(const ucl_object_t *obj, const char **target, size_t *tlen)
3569
0
{
3570
0
  if (obj == NULL || target == NULL) {
3571
0
    return false;
3572
0
  }
3573
0
  switch (obj->type) {
3574
0
  case UCL_STRING:
3575
0
    *target = obj->value.sv;
3576
0
    if (tlen != NULL) {
3577
0
      *tlen = obj->len;
3578
0
    }
3579
0
    break;
3580
0
  default:
3581
0
    return false;
3582
0
  }
3583
3584
0
  return true;
3585
0
}
3586
3587
const char *
3588
ucl_object_tolstring(const ucl_object_t *obj, size_t *tlen)
3589
0
{
3590
0
  const char *result = NULL;
3591
3592
0
  ucl_object_tolstring_safe(obj, &result, tlen);
3593
0
  return result;
3594
0
}
3595
3596
const char *
3597
ucl_object_key(const ucl_object_t *obj)
3598
0
{
3599
0
  return ucl_copy_key_trash(obj);
3600
0
}
3601
3602
const char *
3603
ucl_object_keyl(const ucl_object_t *obj, size_t *len)
3604
0
{
3605
0
  if (len == NULL || obj == NULL) {
3606
0
    return NULL;
3607
0
  }
3608
0
  *len = obj->keylen;
3609
0
  return obj->key;
3610
0
}
3611
3612
ucl_object_t *
3613
ucl_object_ref(const ucl_object_t *obj)
3614
9.79k
{
3615
9.79k
  ucl_object_t *res = NULL;
3616
3617
9.79k
  if (obj != NULL) {
3618
9.79k
    if (obj->flags & UCL_OBJECT_EPHEMERAL) {
3619
      /*
3620
       * Use deep copy for ephemeral objects, note that its refcount
3621
       * is NOT increased, since ephemeral objects does not need refcount
3622
       * at all
3623
       */
3624
0
      res = ucl_object_copy(obj);
3625
0
    }
3626
9.79k
    else {
3627
9.79k
      res = __DECONST(ucl_object_t *, obj);
3628
9.79k
#ifdef HAVE_ATOMIC_BUILTINS
3629
9.79k
      (void) __sync_add_and_fetch(&res->ref, 1);
3630
#else
3631
      res->ref++;
3632
#endif
3633
9.79k
    }
3634
9.79k
  }
3635
9.79k
  return res;
3636
9.79k
}
3637
3638
static ucl_object_t *
3639
ucl_object_copy_internal(const ucl_object_t *other, bool allow_array)
3640
687k
{
3641
3642
687k
  ucl_object_t *new;
3643
687k
  ucl_object_iter_t it = NULL;
3644
687k
  const ucl_object_t *cur;
3645
687k
  size_t sz = sizeof(*new);
3646
3647
687k
  if (other->type == UCL_USERDATA) {
3648
0
    sz = sizeof(struct ucl_object_userdata);
3649
0
  }
3650
687k
  new = UCL_ALLOC(sz);
3651
3652
687k
  if (new != NULL) {
3653
687k
    memcpy(new, other, sz);
3654
687k
    if (other->flags & UCL_OBJECT_EPHEMERAL) {
3655
      /* Copied object is always non ephemeral */
3656
0
      new->flags &= ~UCL_OBJECT_EPHEMERAL;
3657
0
    }
3658
687k
    new->ref = 1;
3659
    /* Unlink from others */
3660
687k
    new->next = NULL;
3661
687k
    new->prev = new;
3662
3663
    /* deep copy of values stored */
3664
687k
    if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
3665
6
      new->trash_stack[UCL_TRASH_KEY] = NULL;
3666
6
      if (other->key == (const char *) other->trash_stack[UCL_TRASH_KEY]) {
3667
6
        new->trash_stack[UCL_TRASH_KEY] = UCL_ALLOC(other->keylen + 1);
3668
6
        memcpy(new->trash_stack[UCL_TRASH_KEY], other->trash_stack[UCL_TRASH_KEY], other->keylen);
3669
6
        new->trash_stack[UCL_TRASH_KEY][other->keylen] = '\0';
3670
6
        new->key = new->trash_stack[UCL_TRASH_KEY];
3671
6
      }
3672
6
    }
3673
687k
    if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
3674
687k
      new->trash_stack[UCL_TRASH_VALUE] =
3675
687k
        UCL_STRDUP(other->trash_stack[UCL_TRASH_VALUE]);
3676
687k
      if (new->type == UCL_STRING) {
3677
687k
        new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
3678
687k
      }
3679
687k
    }
3680
3681
687k
    if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
3682
      /* reset old value and length since we will re-add elements below */
3683
6
      memset(&new->value, 0, sizeof(new->value));
3684
6
      new->len = 0;
3685
3686
687k
      while ((cur = ucl_object_iterate(other, &it, true)) != NULL) {
3687
687k
        if (other->type == UCL_ARRAY) {
3688
687k
          ucl_array_append(new, ucl_object_copy_internal(cur, false));
3689
687k
        }
3690
0
        else {
3691
0
          ucl_object_t *cp = ucl_object_copy_internal(cur, true);
3692
0
          if (cp != NULL) {
3693
0
            ucl_object_insert_key(new, cp, cp->key, cp->keylen,
3694
0
                        false);
3695
0
          }
3696
0
        }
3697
687k
      }
3698
6
    }
3699
687k
    else if (allow_array && other->next != NULL) {
3700
0
      LL_FOREACH(other->next, cur)
3701
0
      {
3702
0
        ucl_object_t *cp = ucl_object_copy_internal(cur, false);
3703
0
        if (cp != NULL) {
3704
0
          DL_APPEND(new, cp);
3705
0
        }
3706
0
      }
3707
0
    }
3708
687k
  }
3709
3710
687k
  return new;
3711
687k
}
3712
3713
ucl_object_t *
3714
ucl_object_copy(const ucl_object_t *other)
3715
6
{
3716
6
  return ucl_object_copy_internal(other, true);
3717
6
}
3718
3719
void ucl_object_unref(ucl_object_t *obj)
3720
38.0k
{
3721
38.0k
  if (obj != NULL) {
3722
38.0k
#ifdef HAVE_ATOMIC_BUILTINS
3723
38.0k
    unsigned int rc = __sync_sub_and_fetch(&obj->ref, 1);
3724
38.0k
    if (rc == 0) {
3725
#else
3726
    if (--obj->ref == 0) {
3727
#endif
3728
28.2k
      ucl_object_free_internal(obj, true, ucl_object_dtor_unref);
3729
28.2k
    }
3730
38.0k
  }
3731
38.0k
}
3732
3733
int ucl_object_compare(const ucl_object_t *o1, const ucl_object_t *o2)
3734
0
{
3735
0
  const ucl_object_t *it1, *it2;
3736
0
  ucl_object_iter_t iter = NULL;
3737
0
  int ret = 0;
3738
3739
0
  if (o1->type != o2->type) {
3740
0
    return (o1->type) - (o2->type);
3741
0
  }
3742
3743
0
  switch (o1->type) {
3744
0
  case UCL_STRING:
3745
0
    if (o1->len == o2->len && o1->len > 0) {
3746
0
      ret = strcmp(ucl_object_tostring(o1), ucl_object_tostring(o2));
3747
0
    }
3748
0
    else {
3749
0
      ret = o1->len - o2->len;
3750
0
    }
3751
0
    break;
3752
0
  case UCL_FLOAT:
3753
0
  case UCL_INT:
3754
0
  case UCL_TIME:
3755
0
    ret = ucl_object_todouble(o1) - ucl_object_todouble(o2);
3756
0
    break;
3757
0
  case UCL_BOOLEAN:
3758
0
    ret = ucl_object_toboolean(o1) - ucl_object_toboolean(o2);
3759
0
    break;
3760
0
  case UCL_ARRAY:
3761
0
    if (o1->len == o2->len && o1->len > 0) {
3762
0
      UCL_ARRAY_GET(vec1, o1);
3763
0
      UCL_ARRAY_GET(vec2, o2);
3764
0
      unsigned i;
3765
3766
      /* Compare all elements in both arrays */
3767
0
      for (i = 0; i < vec1->n; i++) {
3768
0
        it1 = kv_A(*vec1, i);
3769
0
        it2 = kv_A(*vec2, i);
3770
3771
0
        if (it1 == NULL && it2 != NULL) {
3772
0
          return -1;
3773
0
        }
3774
0
        else if (it2 == NULL && it1 != NULL) {
3775
0
          return 1;
3776
0
        }
3777
0
        else if (it1 != NULL && it2 != NULL) {
3778
0
          ret = ucl_object_compare(it1, it2);
3779
0
          if (ret != 0) {
3780
0
            break;
3781
0
          }
3782
0
        }
3783
0
      }
3784
0
    }
3785
0
    else {
3786
0
      ret = o1->len - o2->len;
3787
0
    }
3788
0
    break;
3789
0
  case UCL_OBJECT:
3790
0
    if (o1->len == o2->len && o1->len > 0) {
3791
0
      while ((it1 = ucl_object_iterate(o1, &iter, true)) != NULL) {
3792
0
        it2 = ucl_object_lookup(o2, ucl_object_key(it1));
3793
0
        if (it2 == NULL) {
3794
0
          ret = 1;
3795
0
          break;
3796
0
        }
3797
0
        ret = ucl_object_compare(it1, it2);
3798
0
        if (ret != 0) {
3799
0
          break;
3800
0
        }
3801
0
      }
3802
0
    }
3803
0
    else {
3804
0
      ret = o1->len - o2->len;
3805
0
    }
3806
0
    break;
3807
0
  default:
3808
0
    ret = 0;
3809
0
    break;
3810
0
  }
3811
3812
0
  return ret;
3813
0
}
3814
3815
int ucl_object_compare_qsort(const ucl_object_t **o1,
3816
               const ucl_object_t **o2)
3817
0
{
3818
0
  return ucl_object_compare(*o1, *o2);
3819
0
}
3820
3821
void ucl_object_array_sort(ucl_object_t *ar,
3822
               int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
3823
0
{
3824
0
  UCL_ARRAY_GET(vec, ar);
3825
3826
0
  if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
3827
0
    return;
3828
0
  }
3829
3830
0
  qsort(vec->a, vec->n, sizeof(ucl_object_t *),
3831
0
      (int (*)(const void *, const void *)) cmp);
3832
0
}
3833
3834
void ucl_object_sort_keys(ucl_object_t *obj,
3835
              enum ucl_object_keys_sort_flags how)
3836
0
{
3837
0
  if (obj != NULL && obj->type == UCL_OBJECT) {
3838
0
    ucl_hash_sort(obj->value.ov, how);
3839
0
  }
3840
0
}
3841
3842
2.93M
#define PRIOBITS 4
3843
3844
unsigned int
3845
ucl_object_get_priority(const ucl_object_t *obj)
3846
15.3k
{
3847
15.3k
  if (obj == NULL) {
3848
0
    return 0;
3849
0
  }
3850
3851
15.3k
  return (obj->flags >> ((sizeof(obj->flags) * NBBY) - PRIOBITS));
3852
15.3k
}
3853
3854
void ucl_object_set_priority(ucl_object_t *obj,
3855
               unsigned int priority)
3856
972k
{
3857
972k
  if (obj != NULL) {
3858
972k
    priority &= (0x1 << PRIOBITS) - 1;
3859
972k
    priority <<= ((sizeof(obj->flags) * NBBY) - PRIOBITS);
3860
972k
    priority |= obj->flags & ((1 << ((sizeof(obj->flags) * NBBY) -
3861
972k
                     PRIOBITS)) -
3862
972k
                  1);
3863
972k
    obj->flags = priority;
3864
972k
  }
3865
972k
}
3866
3867
bool ucl_object_string_to_type(const char *input, ucl_type_t *res)
3868
0
{
3869
0
  if (strcasecmp(input, "object") == 0) {
3870
0
    *res = UCL_OBJECT;
3871
0
  }
3872
0
  else if (strcasecmp(input, "array") == 0) {
3873
0
    *res = UCL_ARRAY;
3874
0
  }
3875
0
  else if (strcasecmp(input, "integer") == 0) {
3876
0
    *res = UCL_INT;
3877
0
  }
3878
0
  else if (strcasecmp(input, "number") == 0) {
3879
0
    *res = UCL_FLOAT;
3880
0
  }
3881
0
  else if (strcasecmp(input, "string") == 0) {
3882
0
    *res = UCL_STRING;
3883
0
  }
3884
0
  else if (strcasecmp(input, "boolean") == 0) {
3885
0
    *res = UCL_BOOLEAN;
3886
0
  }
3887
0
  else if (strcasecmp(input, "null") == 0) {
3888
0
    *res = UCL_NULL;
3889
0
  }
3890
0
  else if (strcasecmp(input, "userdata") == 0) {
3891
0
    *res = UCL_USERDATA;
3892
0
  }
3893
0
  else {
3894
0
    return false;
3895
0
  }
3896
3897
0
  return true;
3898
0
}
3899
3900
const char *
3901
ucl_object_type_to_string(ucl_type_t type)
3902
0
{
3903
0
  const char *res = "unknown";
3904
3905
0
  switch (type) {
3906
0
  case UCL_OBJECT:
3907
0
    res = "object";
3908
0
    break;
3909
0
  case UCL_ARRAY:
3910
0
    res = "array";
3911
0
    break;
3912
0
  case UCL_INT:
3913
0
    res = "integer";
3914
0
    break;
3915
0
  case UCL_FLOAT:
3916
0
  case UCL_TIME:
3917
0
    res = "number";
3918
0
    break;
3919
0
  case UCL_STRING:
3920
0
    res = "string";
3921
0
    break;
3922
0
  case UCL_BOOLEAN:
3923
0
    res = "boolean";
3924
0
    break;
3925
0
  case UCL_USERDATA:
3926
0
    res = "userdata";
3927
0
    break;
3928
0
  case UCL_NULL:
3929
0
    res = "null";
3930
0
    break;
3931
0
  }
3932
3933
0
  return res;
3934
0
}
3935
3936
const ucl_object_t *
3937
ucl_parser_get_comments(struct ucl_parser *parser)
3938
0
{
3939
0
  if (parser && parser->comments) {
3940
0
    return parser->comments;
3941
0
  }
3942
3943
0
  return NULL;
3944
0
}
3945
3946
const ucl_object_t *
3947
ucl_comments_find(const ucl_object_t *comments,
3948
          const ucl_object_t *srch)
3949
0
{
3950
0
  if (comments && srch) {
3951
0
    return ucl_object_lookup_len(comments, (const char *) &srch,
3952
0
                   sizeof(void *));
3953
0
  }
3954
3955
0
  return NULL;
3956
0
}
3957
3958
bool ucl_comments_move(ucl_object_t *comments,
3959
             const ucl_object_t *from, const ucl_object_t *to)
3960
0
{
3961
0
  const ucl_object_t *found;
3962
0
  ucl_object_t *obj;
3963
3964
0
  if (comments && from && to) {
3965
0
    found = ucl_object_lookup_len(comments,
3966
0
                    (const char *) &from, sizeof(void *));
3967
3968
0
    if (found) {
3969
      /* Replace key */
3970
0
      obj = ucl_object_ref(found);
3971
0
      ucl_object_delete_keyl(comments, (const char *) &from,
3972
0
                   sizeof(void *));
3973
0
      ucl_object_insert_key(comments, obj, (const char *) &to,
3974
0
                  sizeof(void *), true);
3975
3976
0
      return true;
3977
0
    }
3978
0
  }
3979
3980
0
  return false;
3981
0
}
3982
3983
void ucl_comments_add(ucl_object_t *comments, const ucl_object_t *obj,
3984
            const char *comment)
3985
0
{
3986
0
  if (comments && obj && comment) {
3987
0
    ucl_object_insert_key(comments, ucl_object_fromstring(comment),
3988
0
                (const char *) &obj, sizeof(void *), true);
3989
0
  }
3990
0
}
3991
3992
void ucl_parser_set_include_tracer(struct ucl_parser *parser,
3993
                   ucl_include_trace_func_t func,
3994
                   void *user_data)
3995
0
{
3996
0
  parser->include_trace_func = func;
3997
0
  parser->include_trace_ud = user_data;
3998
0
}
3999
4000
const char *
4001
ucl_parser_get_cur_file(struct ucl_parser *parser)
4002
0
{
4003
0
  return parser->cur_file;
4004
0
}