Coverage Report

Created: 2024-02-11 06:32

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