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