ucl 0.1.3.2 → 0.2.0

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