ucl_util.c revision 275223
1/* Copyright (c) 2013, Vsevolod Stakhov
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *       * Redistributions of source code must retain the above copyright
7 *         notice, this list of conditions and the following disclaimer.
8 *       * Redistributions in binary form must reproduce the above copyright
9 *         notice, this list of conditions and the following disclaimer in the
10 *         documentation and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23
24#include "ucl.h"
25#include "ucl_internal.h"
26#include "ucl_chartable.h"
27
28#include <glob.h>
29
30#ifdef HAVE_LIBGEN_H
31#include <libgen.h> /* For dirname */
32#endif
33
34#ifdef HAVE_OPENSSL
35#include <openssl/err.h>
36#include <openssl/sha.h>
37#include <openssl/rsa.h>
38#include <openssl/ssl.h>
39#include <openssl/evp.h>
40#endif
41
42#ifdef CURL_FOUND
43#include <curl/curl.h>
44#endif
45#ifdef HAVE_FETCH_H
46#include <fetch.h>
47#endif
48
49#ifdef _WIN32
50#include <windows.h>
51
52#ifndef PROT_READ
53#define PROT_READ       1
54#endif
55#ifndef PROT_WRITE
56#define PROT_WRITE      2
57#endif
58#ifndef PROT_READWRITE
59#define PROT_READWRITE  3
60#endif
61#ifndef MAP_SHARED
62#define MAP_SHARED      1
63#endif
64#ifndef MAP_PRIVATE
65#define MAP_PRIVATE     2
66#endif
67#ifndef MAP_FAILED
68#define MAP_FAILED      ((void *) -1)
69#endif
70
71static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
72{
73	void *map = NULL;
74	HANDLE handle = INVALID_HANDLE_VALUE;
75
76	switch (prot) {
77	default:
78	case PROT_READ:
79		{
80			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
81			if (!handle) break;
82			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
83			CloseHandle(handle);
84			break;
85		}
86	case PROT_WRITE:
87		{
88			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
89			if (!handle) break;
90			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
91			CloseHandle(handle);
92			break;
93		}
94	case PROT_READWRITE:
95		{
96			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
97			if (!handle) break;
98			map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
99			CloseHandle(handle);
100			break;
101		}
102	}
103	if (map == (void *) NULL) {
104		return (void *) MAP_FAILED;
105	}
106	return (void *) ((char *) map + offset);
107}
108
109static int ucl_munmap(void *map,size_t length)
110{
111	if (!UnmapViewOfFile(map)) {
112		return(-1);
113	}
114	return(0);
115}
116
117static char* ucl_realpath(const char *path, char *resolved_path) {
118    char *p;
119    char tmp[MAX_PATH + 1];
120    strncpy(tmp, path, sizeof(tmp)-1);
121    p = tmp;
122    while(*p) {
123        if (*p == '/') *p = '\\';
124        p++;
125    }
126    return _fullpath(resolved_path, tmp, MAX_PATH);
127}
128#else
129#define ucl_mmap mmap
130#define ucl_munmap munmap
131#define ucl_realpath realpath
132#endif
133
134typedef void (*ucl_object_dtor) (ucl_object_t *obj);
135static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
136		ucl_object_dtor dtor);
137static void ucl_object_dtor_unref (ucl_object_t *obj);
138
139static void
140ucl_object_dtor_free (ucl_object_t *obj)
141{
142	if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
143		UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
144	}
145	if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
146		UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
147	}
148	/* Do not free ephemeral objects */
149	if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
150		if (obj->type != UCL_USERDATA) {
151			UCL_FREE (sizeof (ucl_object_t), obj);
152		}
153		else {
154			struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
155			if (ud->dtor) {
156				ud->dtor (obj->value.ud);
157			}
158			UCL_FREE (sizeof (*ud), obj);
159		}
160	}
161}
162
163/*
164 * This is a helper function that performs exactly the same as
165 * `ucl_object_unref` but it doesn't iterate over elements allowing
166 * to use it for individual elements of arrays and multiple values
167 */
168static void
169ucl_object_dtor_unref_single (ucl_object_t *obj)
170{
171	if (obj != NULL) {
172#ifdef HAVE_ATOMIC_BUILTINS
173		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
174		if (rc == 0) {
175#else
176		if (--obj->ref == 0) {
177#endif
178			ucl_object_free_internal (obj, false, ucl_object_dtor_unref);
179		}
180	}
181}
182
183static void
184ucl_object_dtor_unref (ucl_object_t *obj)
185{
186	if (obj->ref == 0) {
187		ucl_object_dtor_free (obj);
188	}
189	else {
190		/* This may cause dtor unref being called one more time */
191		ucl_object_dtor_unref_single (obj);
192	}
193}
194
195static void
196ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
197{
198	ucl_object_t *sub, *tmp;
199
200	while (obj != NULL) {
201		if (obj->type == UCL_ARRAY) {
202			sub = obj->value.av;
203			while (sub != NULL) {
204				tmp = sub->next;
205				dtor (sub);
206				sub = tmp;
207			}
208		}
209		else if (obj->type == UCL_OBJECT) {
210			if (obj->value.ov != NULL) {
211				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor);
212			}
213		}
214		tmp = obj->next;
215		dtor (obj);
216		obj = tmp;
217
218		if (!allow_rec) {
219			break;
220		}
221	}
222}
223
224void
225ucl_object_free (ucl_object_t *obj)
226{
227	ucl_object_free_internal (obj, true, ucl_object_dtor_free);
228}
229
230size_t
231ucl_unescape_json_string (char *str, size_t len)
232{
233	char *t = str, *h = str;
234	int i, uval;
235
236	if (len <= 1) {
237		return len;
238	}
239	/* t is target (tortoise), h is source (hare) */
240
241	while (len) {
242		if (*h == '\\') {
243			h ++;
244			switch (*h) {
245			case 'n':
246				*t++ = '\n';
247				break;
248			case 'r':
249				*t++ = '\r';
250				break;
251			case 'b':
252				*t++ = '\b';
253				break;
254			case 't':
255				*t++ = '\t';
256				break;
257			case 'f':
258				*t++ = '\f';
259				break;
260			case '\\':
261				*t++ = '\\';
262				break;
263			case '"':
264				*t++ = '"';
265				break;
266			case 'u':
267				/* Unicode escape */
268				uval = 0;
269				if (len > 3) {
270					for (i = 0; i < 4; i++) {
271						uval <<= 4;
272						if (isdigit (h[i])) {
273							uval += h[i] - '0';
274						}
275						else if (h[i] >= 'a' && h[i] <= 'f') {
276							uval += h[i] - 'a' + 10;
277						}
278						else if (h[i] >= 'A' && h[i] <= 'F') {
279							uval += h[i] - 'A' + 10;
280						}
281						else {
282							break;
283						}
284					}
285					h += 3;
286					len -= 3;
287					/* Encode */
288					if(uval < 0x80) {
289						t[0] = (char)uval;
290						t ++;
291					}
292					else if(uval < 0x800) {
293						t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
294						t[1] = 0x80 + ((uval & 0x03F));
295						t += 2;
296					}
297					else if(uval < 0x10000) {
298						t[0] = 0xE0 + ((uval & 0xF000) >> 12);
299						t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
300						t[2] = 0x80 + ((uval & 0x003F));
301						t += 3;
302					}
303					else if(uval <= 0x10FFFF) {
304						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
305						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
306						t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
307						t[3] = 0x80 + ((uval & 0x00003F));
308						t += 4;
309					}
310					else {
311						*t++ = '?';
312					}
313				}
314				else {
315					*t++ = 'u';
316				}
317				break;
318			default:
319				*t++ = *h;
320				break;
321			}
322			h ++;
323			len --;
324		}
325		else {
326			*t++ = *h++;
327		}
328		len --;
329	}
330	*t = '\0';
331
332	return (t - str);
333}
334
335char *
336ucl_copy_key_trash (const ucl_object_t *obj)
337{
338	ucl_object_t *deconst;
339
340	if (obj == NULL) {
341		return NULL;
342	}
343	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
344		deconst = __DECONST (ucl_object_t *, obj);
345		deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
346		if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
347			memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
348			deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
349		}
350		deconst->key = obj->trash_stack[UCL_TRASH_KEY];
351		deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
352	}
353
354	return obj->trash_stack[UCL_TRASH_KEY];
355}
356
357char *
358ucl_copy_value_trash (const ucl_object_t *obj)
359{
360	ucl_object_t *deconst;
361
362	if (obj == NULL) {
363		return NULL;
364	}
365	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
366		deconst = __DECONST (ucl_object_t *, obj);
367		if (obj->type == UCL_STRING) {
368
369			/* Special case for strings */
370			deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
371			if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
372				memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
373				deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
374				deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
375			}
376		}
377		else {
378			/* Just emit value in json notation */
379			deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
380			deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
381		}
382		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
383	}
384	return obj->trash_stack[UCL_TRASH_VALUE];
385}
386
387UCL_EXTERN ucl_object_t*
388ucl_parser_get_object (struct ucl_parser *parser)
389{
390	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
391		return ucl_object_ref (parser->top_obj);
392	}
393
394	return NULL;
395}
396
397UCL_EXTERN void
398ucl_parser_free (struct ucl_parser *parser)
399{
400	struct ucl_stack *stack, *stmp;
401	struct ucl_macro *macro, *mtmp;
402	struct ucl_chunk *chunk, *ctmp;
403	struct ucl_pubkey *key, *ktmp;
404	struct ucl_variable *var, *vtmp;
405
406	if (parser == NULL) {
407		return;
408	}
409
410	if (parser->top_obj != NULL) {
411		ucl_object_unref (parser->top_obj);
412	}
413
414	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
415		free (stack);
416	}
417	HASH_ITER (hh, parser->macroes, macro, mtmp) {
418		free (macro->name);
419		HASH_DEL (parser->macroes, macro);
420		UCL_FREE (sizeof (struct ucl_macro), macro);
421	}
422	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
423		UCL_FREE (sizeof (struct ucl_chunk), chunk);
424	}
425	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
426		UCL_FREE (sizeof (struct ucl_pubkey), key);
427	}
428	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
429		free (var->value);
430		free (var->var);
431		UCL_FREE (sizeof (struct ucl_variable), var);
432	}
433
434	if (parser->err != NULL) {
435		utstring_free (parser->err);
436	}
437
438	if (parser->cur_file) {
439		free (parser->cur_file);
440	}
441
442	UCL_FREE (sizeof (struct ucl_parser), parser);
443}
444
445UCL_EXTERN const char *
446ucl_parser_get_error(struct ucl_parser *parser)
447{
448	if (parser == NULL) {
449		return NULL;
450	}
451
452	if (parser->err == NULL)
453		return NULL;
454
455	return utstring_body(parser->err);
456}
457
458UCL_EXTERN bool
459ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
460{
461#ifndef HAVE_OPENSSL
462	ucl_create_err (&parser->err, "cannot check signatures without openssl");
463	return false;
464#else
465# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
466	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
467	return EXIT_FAILURE;
468# else
469	struct ucl_pubkey *nkey;
470	BIO *mem;
471
472	mem = BIO_new_mem_buf ((void *)key, len);
473	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
474	if (nkey == NULL) {
475		ucl_create_err (&parser->err, "cannot allocate memory for key");
476		return false;
477	}
478	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
479	BIO_free (mem);
480	if (nkey->key == NULL) {
481		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
482		ucl_create_err (&parser->err, "%s",
483				ERR_error_string (ERR_get_error (), NULL));
484		return false;
485	}
486	LL_PREPEND (parser->keys, nkey);
487# endif
488#endif
489	return true;
490}
491
492#ifdef CURL_FOUND
493struct ucl_curl_cbdata {
494	unsigned char *buf;
495	size_t buflen;
496};
497
498static size_t
499ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
500{
501	struct ucl_curl_cbdata *cbdata = ud;
502	size_t realsize = size * nmemb;
503
504	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
505	if (cbdata->buf == NULL) {
506		return 0;
507	}
508
509	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
510	cbdata->buflen += realsize;
511	cbdata->buf[cbdata->buflen] = 0;
512
513	return realsize;
514}
515#endif
516
517/**
518 * Fetch a url and save results to the memory buffer
519 * @param url url to fetch
520 * @param len length of url
521 * @param buf target buffer
522 * @param buflen target length
523 * @return
524 */
525static bool
526ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
527		UT_string **err, bool must_exist)
528{
529
530#ifdef HAVE_FETCH_H
531	struct url *fetch_url;
532	struct url_stat us;
533	FILE *in;
534
535	fetch_url = fetchParseURL (url);
536	if (fetch_url == NULL) {
537		ucl_create_err (err, "invalid URL %s: %s",
538				url, strerror (errno));
539		return false;
540	}
541	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
542		if (!must_exist) {
543			ucl_create_err (err, "cannot fetch URL %s: %s",
544				url, strerror (errno));
545		}
546		fetchFreeURL (fetch_url);
547		return false;
548	}
549
550	*buflen = us.size;
551	*buf = malloc (*buflen);
552	if (*buf == NULL) {
553		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
554				url, strerror (errno));
555		fclose (in);
556		fetchFreeURL (fetch_url);
557		return false;
558	}
559
560	if (fread (*buf, *buflen, 1, in) != 1) {
561		ucl_create_err (err, "cannot read URL %s: %s",
562				url, strerror (errno));
563		fclose (in);
564		fetchFreeURL (fetch_url);
565		return false;
566	}
567
568	fetchFreeURL (fetch_url);
569	return true;
570#elif defined(CURL_FOUND)
571	CURL *curl;
572	int r;
573	struct ucl_curl_cbdata cbdata;
574
575	curl = curl_easy_init ();
576	if (curl == NULL) {
577		ucl_create_err (err, "CURL interface is broken");
578		return false;
579	}
580	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
581		ucl_create_err (err, "invalid URL %s: %s",
582				url, curl_easy_strerror (r));
583		curl_easy_cleanup (curl);
584		return false;
585	}
586	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
587	cbdata.buf = *buf;
588	cbdata.buflen = *buflen;
589	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
590
591	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
592		if (!must_exist) {
593			ucl_create_err (err, "error fetching URL %s: %s",
594				url, curl_easy_strerror (r));
595		}
596		curl_easy_cleanup (curl);
597		if (cbdata.buf) {
598			free (cbdata.buf);
599		}
600		return false;
601	}
602	*buf = cbdata.buf;
603	*buflen = cbdata.buflen;
604
605	return true;
606#else
607	ucl_create_err (err, "URL support is disabled");
608	return false;
609#endif
610}
611
612/**
613 * Fetch a file and save results to the memory buffer
614 * @param filename filename to fetch
615 * @param len length of filename
616 * @param buf target buffer
617 * @param buflen target length
618 * @return
619 */
620static bool
621ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
622		UT_string **err, bool must_exist)
623{
624	int fd;
625	struct stat st;
626
627	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
628		if (must_exist) {
629			ucl_create_err (err, "cannot stat file %s: %s",
630					filename, strerror (errno));
631		}
632		return false;
633	}
634	if (st.st_size == 0) {
635		/* Do not map empty files */
636		*buf = "";
637		*buflen = 0;
638	}
639	else {
640		if ((fd = open (filename, O_RDONLY)) == -1) {
641			ucl_create_err (err, "cannot open file %s: %s",
642					filename, strerror (errno));
643			return false;
644		}
645		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
646			close (fd);
647			ucl_create_err (err, "cannot mmap file %s: %s",
648					filename, strerror (errno));
649			return false;
650		}
651		*buflen = st.st_size;
652		close (fd);
653	}
654
655	return true;
656}
657
658
659#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
660static inline bool
661ucl_sig_check (const unsigned char *data, size_t datalen,
662		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
663{
664	struct ucl_pubkey *key;
665	char dig[EVP_MAX_MD_SIZE];
666	unsigned int diglen;
667	EVP_PKEY_CTX *key_ctx;
668	EVP_MD_CTX *sign_ctx = NULL;
669
670	sign_ctx = EVP_MD_CTX_create ();
671
672	LL_FOREACH (parser->keys, key) {
673		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
674		if (key_ctx != NULL) {
675			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
676				EVP_PKEY_CTX_free (key_ctx);
677				continue;
678			}
679			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
680				EVP_PKEY_CTX_free (key_ctx);
681				continue;
682			}
683			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
684				EVP_PKEY_CTX_free (key_ctx);
685				continue;
686			}
687			EVP_DigestInit (sign_ctx, EVP_sha256 ());
688			EVP_DigestUpdate (sign_ctx, data, datalen);
689			EVP_DigestFinal (sign_ctx, dig, &diglen);
690
691			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
692				EVP_MD_CTX_destroy (sign_ctx);
693				EVP_PKEY_CTX_free (key_ctx);
694				return true;
695			}
696
697			EVP_PKEY_CTX_free (key_ctx);
698		}
699	}
700
701	EVP_MD_CTX_destroy (sign_ctx);
702
703	return false;
704}
705#endif
706
707/**
708 * Include an url to configuration
709 * @param data
710 * @param len
711 * @param parser
712 * @param err
713 * @return
714 */
715static bool
716ucl_include_url (const unsigned char *data, size_t len,
717		struct ucl_parser *parser, bool check_signature, bool must_exist,
718		unsigned priority)
719{
720
721	bool res;
722	unsigned char *buf = NULL;
723	size_t buflen = 0;
724	struct ucl_chunk *chunk;
725	char urlbuf[PATH_MAX];
726	int prev_state;
727
728	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
729
730	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) {
731		return (!must_exist || false);
732	}
733
734	if (check_signature) {
735#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
736		unsigned char *sigbuf = NULL;
737		size_t siglen = 0;
738		/* We need to check signature first */
739		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
740		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
741			return false;
742		}
743		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
744			ucl_create_err (&parser->err, "cannot verify url %s: %s",
745							urlbuf,
746							ERR_error_string (ERR_get_error (), NULL));
747			if (siglen > 0) {
748				ucl_munmap (sigbuf, siglen);
749			}
750			return false;
751		}
752		if (siglen > 0) {
753			ucl_munmap (sigbuf, siglen);
754		}
755#endif
756	}
757
758	prev_state = parser->state;
759	parser->state = UCL_STATE_INIT;
760
761	res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
762	if (res == true) {
763		/* Remove chunk from the stack */
764		chunk = parser->chunks;
765		if (chunk != NULL) {
766			parser->chunks = chunk->next;
767			UCL_FREE (sizeof (struct ucl_chunk), chunk);
768		}
769	}
770
771	parser->state = prev_state;
772	free (buf);
773
774	return res;
775}
776
777/**
778 * Include a single file to the parser
779 * @param data
780 * @param len
781 * @param parser
782 * @param check_signature
783 * @param must_exist
784 * @param allow_glob
785 * @param priority
786 * @return
787 */
788static bool
789ucl_include_file_single (const unsigned char *data, size_t len,
790		struct ucl_parser *parser, bool check_signature, bool must_exist,
791		unsigned priority)
792{
793	bool res;
794	struct ucl_chunk *chunk;
795	unsigned char *buf = NULL;
796	char *old_curfile;
797	size_t buflen;
798	char filebuf[PATH_MAX], realbuf[PATH_MAX];
799	int prev_state;
800	struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
801			*old_filename = NULL;
802
803	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
804	if (ucl_realpath (filebuf, realbuf) == NULL) {
805		if (!must_exist) {
806			return true;
807		}
808		ucl_create_err (&parser->err, "cannot open file %s: %s",
809									filebuf,
810									strerror (errno));
811		return false;
812	}
813
814	if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
815		/* We are likely including the file itself */
816		ucl_create_err (&parser->err, "trying to include the file %s from itself",
817				realbuf);
818		return false;
819	}
820
821	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
822		return (!must_exist || false);
823	}
824
825	if (check_signature) {
826#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
827		unsigned char *sigbuf = NULL;
828		size_t siglen = 0;
829		/* We need to check signature first */
830		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
831		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
832			return false;
833		}
834		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
835			ucl_create_err (&parser->err, "cannot verify file %s: %s",
836							filebuf,
837							ERR_error_string (ERR_get_error (), NULL));
838			if (siglen > 0) {
839				ucl_munmap (sigbuf, siglen);
840			}
841			return false;
842		}
843		if (siglen > 0) {
844			ucl_munmap (sigbuf, siglen);
845		}
846#endif
847	}
848
849	old_curfile = parser->cur_file;
850	parser->cur_file = strdup (realbuf);
851
852	/* Store old file vars */
853	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
854		if (strcmp (cur_var->var, "CURDIR") == 0) {
855			old_curdir = cur_var;
856			DL_DELETE (parser->variables, cur_var);
857		}
858		else if (strcmp (cur_var->var, "FILENAME") == 0) {
859			old_filename = cur_var;
860			DL_DELETE (parser->variables, cur_var);
861		}
862	}
863
864	ucl_parser_set_filevars (parser, realbuf, false);
865
866	prev_state = parser->state;
867	parser->state = UCL_STATE_INIT;
868
869	res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
870	if (!res && !must_exist) {
871		/* Free error */
872		utstring_free (parser->err);
873		parser->err = NULL;
874		parser->state = UCL_STATE_AFTER_VALUE;
875	}
876
877	/* Remove chunk from the stack */
878	chunk = parser->chunks;
879	if (chunk != NULL) {
880		parser->chunks = chunk->next;
881		UCL_FREE (sizeof (struct ucl_chunk), chunk);
882		parser->recursion --;
883	}
884
885	/* Restore old file vars */
886	parser->cur_file = old_curfile;
887	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
888		if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
889			DL_DELETE (parser->variables, cur_var);
890			free (cur_var->var);
891			free (cur_var->value);
892			UCL_FREE (sizeof (struct ucl_variable), cur_var);
893		}
894		else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
895			DL_DELETE (parser->variables, cur_var);
896			free (cur_var->var);
897			free (cur_var->value);
898			UCL_FREE (sizeof (struct ucl_variable), cur_var);
899		}
900	}
901	if (old_filename) {
902		DL_APPEND (parser->variables, old_filename);
903	}
904	if (old_curdir) {
905		DL_APPEND (parser->variables, old_curdir);
906	}
907	if (old_curfile) {
908		free (old_curfile);
909	}
910
911	parser->state = prev_state;
912
913	if (buflen > 0) {
914		ucl_munmap (buf, buflen);
915	}
916
917	return res;
918}
919
920/**
921 * Include a file to configuration
922 * @param data
923 * @param len
924 * @param parser
925 * @param err
926 * @return
927 */
928static bool
929ucl_include_file (const unsigned char *data, size_t len,
930		struct ucl_parser *parser, bool check_signature, bool must_exist,
931		bool allow_glob, unsigned priority)
932{
933	const unsigned char *p = data, *end = data + len;
934	bool need_glob = false;
935	int cnt = 0;
936	glob_t globbuf;
937	char glob_pattern[PATH_MAX];
938	size_t i;
939
940	if (!allow_glob) {
941		return ucl_include_file_single (data, len, parser, check_signature,
942			must_exist, priority);
943	}
944	else {
945		/* Check for special symbols in a filename */
946		while (p != end) {
947			if (*p == '*' || *p == '?') {
948				need_glob = true;
949				break;
950			}
951			p ++;
952		}
953		if (need_glob) {
954			memset (&globbuf, 0, sizeof (globbuf));
955			ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern));
956			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
957				return (!must_exist || false);
958			}
959			for (i = 0; i < globbuf.gl_pathc; i ++) {
960				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
961						strlen (globbuf.gl_pathv[i]), parser, check_signature,
962						must_exist, priority)) {
963					globfree (&globbuf);
964					return false;
965				}
966				cnt ++;
967			}
968			globfree (&globbuf);
969
970			if (cnt == 0 && must_exist) {
971				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
972					glob_pattern);
973				return false;
974			}
975		}
976		else {
977			return ucl_include_file_single (data, len, parser, check_signature,
978				must_exist, priority);
979		}
980	}
981
982	return true;
983}
984
985/**
986 * Common function to handle .*include* macros
987 * @param data
988 * @param len
989 * @param args
990 * @param parser
991 * @param default_try
992 * @param default_sign
993 * @return
994 */
995static bool
996ucl_include_common (const unsigned char *data, size_t len,
997		const ucl_object_t *args, struct ucl_parser *parser,
998		bool default_try,
999		bool default_sign)
1000{
1001	bool try_load, allow_glob, allow_url, need_sign;
1002	unsigned priority;
1003	const ucl_object_t *param;
1004	ucl_object_iter_t it = NULL;
1005
1006	/* Default values */
1007	try_load = default_try;
1008	allow_glob = false;
1009	allow_url = true;
1010	need_sign = default_sign;
1011	priority = 0;
1012
1013	/* Process arguments */
1014	if (args != NULL && args->type == UCL_OBJECT) {
1015		while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
1016			if (param->type == UCL_BOOLEAN) {
1017				if (strcmp (param->key, "try") == 0) {
1018					try_load = ucl_object_toboolean (param);
1019				}
1020				else if (strcmp (param->key, "sign") == 0) {
1021					need_sign = ucl_object_toboolean (param);
1022				}
1023				else if (strcmp (param->key, "glob") == 0) {
1024					allow_glob =  ucl_object_toboolean (param);
1025				}
1026				else if (strcmp (param->key, "url") == 0) {
1027					allow_url =  ucl_object_toboolean (param);
1028				}
1029			}
1030			else if (param->type == UCL_INT) {
1031				if (strcmp (param->key, "priority") == 0) {
1032					priority = ucl_object_toint (param);
1033				}
1034			}
1035		}
1036	}
1037
1038	if (*data == '/' || *data == '.') {
1039		/* Try to load a file */
1040		return ucl_include_file (data, len, parser, need_sign, !try_load,
1041				allow_glob, priority);
1042	}
1043	else if (allow_url) {
1044		/* Globbing is not used for URL's */
1045		return ucl_include_url (data, len, parser, need_sign, !try_load,
1046				priority);
1047	}
1048
1049	return false;
1050}
1051
1052/**
1053 * Handle include macro
1054 * @param data include data
1055 * @param len length of data
1056 * @param ud user data
1057 * @param err error ptr
1058 * @return
1059 */
1060UCL_EXTERN bool
1061ucl_include_handler (const unsigned char *data, size_t len,
1062		const ucl_object_t *args, void* ud)
1063{
1064	struct ucl_parser *parser = ud;
1065
1066	return ucl_include_common (data, len, args, parser, false, false);
1067}
1068
1069/**
1070 * Handle includes macro
1071 * @param data include data
1072 * @param len length of data
1073 * @param ud user data
1074 * @param err error ptr
1075 * @return
1076 */
1077UCL_EXTERN bool
1078ucl_includes_handler (const unsigned char *data, size_t len,
1079		const ucl_object_t *args, void* ud)
1080{
1081	struct ucl_parser *parser = ud;
1082
1083	return ucl_include_common (data, len, args, parser, false, true);
1084}
1085
1086
1087UCL_EXTERN bool
1088ucl_try_include_handler (const unsigned char *data, size_t len,
1089		const ucl_object_t *args, void* ud)
1090{
1091	struct ucl_parser *parser = ud;
1092
1093	return ucl_include_common (data, len, args, parser, true, false);
1094}
1095
1096UCL_EXTERN bool
1097ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
1098{
1099	char realbuf[PATH_MAX], *curdir;
1100
1101	if (filename != NULL) {
1102		if (need_expand) {
1103			if (ucl_realpath (filename, realbuf) == NULL) {
1104				return false;
1105			}
1106		}
1107		else {
1108			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
1109		}
1110
1111		/* Define variables */
1112		ucl_parser_register_variable (parser, "FILENAME", realbuf);
1113		curdir = dirname (realbuf);
1114		ucl_parser_register_variable (parser, "CURDIR", curdir);
1115	}
1116	else {
1117		/* Set everything from the current dir */
1118		curdir = getcwd (realbuf, sizeof (realbuf));
1119		ucl_parser_register_variable (parser, "FILENAME", "undef");
1120		ucl_parser_register_variable (parser, "CURDIR", curdir);
1121	}
1122
1123	return true;
1124}
1125
1126UCL_EXTERN bool
1127ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
1128{
1129	unsigned char *buf;
1130	size_t len;
1131	bool ret;
1132	char realbuf[PATH_MAX];
1133
1134	if (ucl_realpath (filename, realbuf) == NULL) {
1135		ucl_create_err (&parser->err, "cannot open file %s: %s",
1136				filename,
1137				strerror (errno));
1138		return false;
1139	}
1140
1141	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
1142		return false;
1143	}
1144
1145	if (parser->cur_file) {
1146		free (parser->cur_file);
1147	}
1148	parser->cur_file = strdup (realbuf);
1149	ucl_parser_set_filevars (parser, realbuf, false);
1150	ret = ucl_parser_add_chunk (parser, buf, len);
1151
1152	if (len > 0) {
1153		ucl_munmap (buf, len);
1154	}
1155
1156	return ret;
1157}
1158
1159UCL_EXTERN bool
1160ucl_parser_add_fd (struct ucl_parser *parser, int fd)
1161{
1162	unsigned char *buf;
1163	size_t len;
1164	bool ret;
1165	struct stat st;
1166
1167	if (fstat (fd, &st) == -1) {
1168		ucl_create_err (&parser->err, "cannot stat fd %d: %s",
1169			fd, strerror (errno));
1170		return false;
1171	}
1172	if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1173		ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
1174			fd, strerror (errno));
1175		return false;
1176	}
1177
1178	if (parser->cur_file) {
1179		free (parser->cur_file);
1180	}
1181	parser->cur_file = NULL;
1182	len = st.st_size;
1183	ret = ucl_parser_add_chunk (parser, buf, len);
1184
1185	if (len > 0) {
1186		ucl_munmap (buf, len);
1187	}
1188
1189	return ret;
1190}
1191
1192size_t
1193ucl_strlcpy (char *dst, const char *src, size_t siz)
1194{
1195	char *d = dst;
1196	const char *s = src;
1197	size_t n = siz;
1198
1199	/* Copy as many bytes as will fit */
1200	if (n != 0) {
1201		while (--n != 0) {
1202			if ((*d++ = *s++) == '\0') {
1203				break;
1204			}
1205		}
1206	}
1207
1208	if (n == 0 && siz != 0) {
1209		*d = '\0';
1210	}
1211
1212	return (s - src - 1);    /* count does not include NUL */
1213}
1214
1215size_t
1216ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
1217{
1218	memcpy (dst, src, siz - 1);
1219	dst[siz - 1] = '\0';
1220
1221	return siz - 1;
1222}
1223
1224size_t
1225ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
1226{
1227	char *d = dst;
1228	const char *s = src;
1229	size_t n = siz;
1230
1231	/* Copy as many bytes as will fit */
1232	if (n != 0) {
1233		while (--n != 0) {
1234			if ((*d++ = tolower (*s++)) == '\0') {
1235				break;
1236			}
1237		}
1238	}
1239
1240	if (n == 0 && siz != 0) {
1241		*d = '\0';
1242	}
1243
1244	return (s - src);    /* count does not include NUL */
1245}
1246
1247ucl_object_t *
1248ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
1249{
1250	ucl_object_t *obj;
1251	const char *start, *end, *p, *pos;
1252	char *dst, *d;
1253	size_t escaped_len;
1254
1255	if (str == NULL) {
1256		return NULL;
1257	}
1258
1259	obj = ucl_object_new ();
1260	if (obj) {
1261		if (len == 0) {
1262			len = strlen (str);
1263		}
1264		if (flags & UCL_STRING_TRIM) {
1265			/* Skip leading spaces */
1266			for (start = str; (size_t)(start - str) < len; start ++) {
1267				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1268					break;
1269				}
1270			}
1271			/* Skip trailing spaces */
1272			for (end = str + len - 1; end > start; end --) {
1273				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1274					break;
1275				}
1276			}
1277			end ++;
1278		}
1279		else {
1280			start = str;
1281			end = str + len;
1282		}
1283
1284		obj->type = UCL_STRING;
1285		if (flags & UCL_STRING_ESCAPE) {
1286			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
1287				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1288					escaped_len ++;
1289				}
1290			}
1291			dst = malloc (escaped_len + 1);
1292			if (dst != NULL) {
1293				for (p = start, d = dst; p < end; p ++, d ++) {
1294					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1295						switch (*p) {
1296						case '\n':
1297							*d++ = '\\';
1298							*d = 'n';
1299							break;
1300						case '\r':
1301							*d++ = '\\';
1302							*d = 'r';
1303							break;
1304						case '\b':
1305							*d++ = '\\';
1306							*d = 'b';
1307							break;
1308						case '\t':
1309							*d++ = '\\';
1310							*d = 't';
1311							break;
1312						case '\f':
1313							*d++ = '\\';
1314							*d = 'f';
1315							break;
1316						case '\\':
1317							*d++ = '\\';
1318							*d = '\\';
1319							break;
1320						case '"':
1321							*d++ = '\\';
1322							*d = '"';
1323							break;
1324						}
1325					}
1326					else {
1327						*d = *p;
1328					}
1329				}
1330				*d = '\0';
1331				obj->value.sv = dst;
1332				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1333				obj->len = escaped_len;
1334			}
1335		}
1336		else {
1337			dst = malloc (end - start + 1);
1338			if (dst != NULL) {
1339				ucl_strlcpy_unsafe (dst, start, end - start + 1);
1340				obj->value.sv = dst;
1341				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1342				obj->len = end - start;
1343			}
1344		}
1345		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
1346			/* Parse what we have */
1347			if (flags & UCL_STRING_PARSE_BOOLEAN) {
1348				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
1349					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1350							flags & UCL_STRING_PARSE_DOUBLE,
1351							flags & UCL_STRING_PARSE_BYTES,
1352							flags & UCL_STRING_PARSE_TIME);
1353				}
1354			}
1355			else {
1356				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1357						flags & UCL_STRING_PARSE_DOUBLE,
1358						flags & UCL_STRING_PARSE_BYTES,
1359						flags & UCL_STRING_PARSE_TIME);
1360			}
1361		}
1362	}
1363
1364	return obj;
1365}
1366
1367static bool
1368ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
1369		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
1370{
1371	ucl_object_t *found, *tmp;
1372	const ucl_object_t *cur;
1373	ucl_object_iter_t it = NULL;
1374	const char *p;
1375	int ret = true;
1376
1377	if (elt == NULL || key == NULL) {
1378		return false;
1379	}
1380
1381	if (top == NULL) {
1382		return false;
1383	}
1384
1385	if (top->type != UCL_OBJECT) {
1386		/* It is possible to convert NULL type to an object */
1387		if (top->type == UCL_NULL) {
1388			top->type = UCL_OBJECT;
1389		}
1390		else {
1391			/* Refuse converting of other object types */
1392			return false;
1393		}
1394	}
1395
1396	if (top->value.ov == NULL) {
1397		top->value.ov = ucl_hash_create ();
1398	}
1399
1400	if (keylen == 0) {
1401		keylen = strlen (key);
1402	}
1403
1404	for (p = key; p < key + keylen; p ++) {
1405		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
1406			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1407			break;
1408		}
1409	}
1410
1411	/* workaround for some use cases */
1412	if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
1413			key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
1414		/* Remove copied key */
1415		free (elt->trash_stack[UCL_TRASH_KEY]);
1416		elt->trash_stack[UCL_TRASH_KEY] = NULL;
1417		elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
1418	}
1419
1420	elt->key = key;
1421	elt->keylen = keylen;
1422
1423	if (copy_key) {
1424		ucl_copy_key_trash (elt);
1425	}
1426
1427	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
1428
1429	if (found == NULL) {
1430		top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1431		top->len ++;
1432		if (replace) {
1433			ret = false;
1434		}
1435	}
1436	else {
1437		if (replace) {
1438			ucl_hash_replace (top->value.ov, found, elt);
1439			ucl_object_unref (found);
1440		}
1441		else if (merge) {
1442			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
1443				/* Insert old elt to new one */
1444				ucl_object_insert_key_common (elt, found, found->key,
1445						found->keylen, copy_key, false, false);
1446				ucl_hash_delete (top->value.ov, found);
1447				top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1448			}
1449			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
1450				/* Insert new to old */
1451				ucl_object_insert_key_common (found, elt, elt->key,
1452						elt->keylen, copy_key, false, false);
1453			}
1454			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
1455				/* Mix two hashes */
1456				while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
1457					tmp = ucl_object_ref (cur);
1458					ucl_object_insert_key_common (found, tmp, cur->key,
1459							cur->keylen, copy_key, false, false);
1460				}
1461				ucl_object_unref (elt);
1462			}
1463			else {
1464				/* Just make a list of scalars */
1465				DL_APPEND (found, elt);
1466			}
1467		}
1468		else {
1469			DL_APPEND (found, elt);
1470		}
1471	}
1472
1473	return ret;
1474}
1475
1476bool
1477ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
1478{
1479	ucl_object_t *found;
1480
1481	if (top == NULL || key == NULL) {
1482		return false;
1483	}
1484
1485	found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen));
1486
1487	if (found == NULL) {
1488		return false;
1489	}
1490
1491	ucl_hash_delete (top->value.ov, found);
1492	ucl_object_unref (found);
1493	top->len --;
1494
1495	return true;
1496}
1497
1498bool
1499ucl_object_delete_key (ucl_object_t *top, const char *key)
1500{
1501	return ucl_object_delete_keyl (top, key, strlen(key));
1502}
1503
1504ucl_object_t*
1505ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
1506{
1507	const ucl_object_t *found;
1508
1509	if (top == NULL || key == NULL) {
1510		return false;
1511	}
1512	found = ucl_object_find_keyl (top, key, keylen);
1513
1514	if (found == NULL) {
1515		return NULL;
1516	}
1517	ucl_hash_delete (top->value.ov, found);
1518	top->len --;
1519
1520	return __DECONST (ucl_object_t *, found);
1521}
1522
1523ucl_object_t*
1524ucl_object_pop_key (ucl_object_t *top, const char *key)
1525{
1526	return ucl_object_pop_keyl (top, key, strlen(key));
1527}
1528
1529bool
1530ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
1531		const char *key, size_t keylen, bool copy_key)
1532{
1533	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
1534}
1535
1536bool
1537ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
1538		const char *key, size_t keylen, bool copy_key)
1539{
1540	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
1541}
1542
1543bool
1544ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
1545		const char *key, size_t keylen, bool copy_key)
1546{
1547	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
1548}
1549
1550bool
1551ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
1552{
1553	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
1554	ucl_object_iter_t iter = NULL;
1555
1556	if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
1557		return false;
1558	}
1559
1560	/* Mix two hashes */
1561	while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
1562		if (copy) {
1563			cp = ucl_object_copy (cur);
1564		}
1565		else {
1566			cp = ucl_object_ref (cur);
1567		}
1568		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
1569		if (found == NULL) {
1570			/* The key does not exist */
1571			top->value.ov = ucl_hash_insert_object (top->value.ov, cp);
1572			top->len ++;
1573		}
1574		else {
1575			/* The key already exists, replace it */
1576			ucl_hash_replace (top->value.ov, found, cp);
1577			ucl_object_unref (found);
1578		}
1579	}
1580
1581	return true;
1582}
1583
1584const ucl_object_t *
1585ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
1586{
1587	const ucl_object_t *ret;
1588	ucl_object_t srch;
1589
1590	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1591		return NULL;
1592	}
1593
1594	srch.key = key;
1595	srch.keylen = klen;
1596	ret = ucl_hash_search_obj (obj->value.ov, &srch);
1597
1598	return ret;
1599}
1600
1601const ucl_object_t *
1602ucl_object_find_key (const ucl_object_t *obj, const char *key)
1603{
1604	if (key == NULL)
1605		return NULL;
1606
1607	return ucl_object_find_keyl (obj, key, strlen(key));
1608}
1609
1610const ucl_object_t*
1611ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
1612{
1613	const ucl_object_t *elt;
1614
1615	if (obj == NULL || iter == NULL) {
1616		return NULL;
1617	}
1618
1619	if (expand_values) {
1620		switch (obj->type) {
1621		case UCL_OBJECT:
1622			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
1623			break;
1624		case UCL_ARRAY:
1625			elt = *iter;
1626			if (elt == NULL) {
1627				elt = obj->value.av;
1628				if (elt == NULL) {
1629					return NULL;
1630				}
1631			}
1632			else if (elt == obj->value.av) {
1633				return NULL;
1634			}
1635			*iter = elt->next ? elt->next : obj->value.av;
1636			return elt;
1637		default:
1638			/* Go to linear iteration */
1639			break;
1640		}
1641	}
1642	/* Treat everything as a linear list */
1643	elt = *iter;
1644	if (elt == NULL) {
1645		elt = obj;
1646	}
1647	else if (elt == obj) {
1648		return NULL;
1649	}
1650	*iter = __DECONST (void *, elt->next ? elt->next : obj);
1651	return elt;
1652
1653	/* Not reached */
1654	return NULL;
1655}
1656
1657const ucl_object_t *
1658ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
1659	const ucl_object_t *o = NULL, *found;
1660	const char *p, *c;
1661	char *err_str;
1662	unsigned index;
1663
1664	if (path_in == NULL || top == NULL) {
1665		return NULL;
1666	}
1667
1668	found = NULL;
1669	p = path_in;
1670
1671	/* Skip leading dots */
1672	while (*p == '.') {
1673		p ++;
1674	}
1675
1676	c = p;
1677	while (*p != '\0') {
1678		p ++;
1679		if (*p == '.' || *p == '\0') {
1680			if (p > c) {
1681				switch (top->type) {
1682				case UCL_ARRAY:
1683					/* Key should be an int */
1684					index = strtoul (c, &err_str, 10);
1685					if (err_str != NULL && (*err_str != '.' && *err_str != '\0')) {
1686						return NULL;
1687					}
1688					o = ucl_array_find_index (top, index);
1689					break;
1690				default:
1691					o = ucl_object_find_keyl (top, c, p - c);
1692					break;
1693				}
1694				if (o == NULL) {
1695					return NULL;
1696				}
1697				top = o;
1698			}
1699			if (*p != '\0') {
1700				c = p + 1;
1701			}
1702		}
1703	}
1704	found = o;
1705
1706	return found;
1707}
1708
1709
1710ucl_object_t *
1711ucl_object_new (void)
1712{
1713	return ucl_object_typed_new (UCL_NULL);
1714}
1715
1716ucl_object_t *
1717ucl_object_typed_new (ucl_type_t type)
1718{
1719	return ucl_object_new_full (type, 0);
1720}
1721
1722ucl_object_t *
1723ucl_object_new_full (ucl_type_t type, unsigned priority)
1724{
1725	ucl_object_t *new;
1726
1727	if (type != UCL_USERDATA) {
1728		new = UCL_ALLOC (sizeof (ucl_object_t));
1729		if (new != NULL) {
1730			memset (new, 0, sizeof (ucl_object_t));
1731			new->ref = 1;
1732			new->type = (type <= UCL_NULL ? type : UCL_NULL);
1733			new->next = NULL;
1734			new->prev = new;
1735			ucl_object_set_priority (new, priority);
1736		}
1737	}
1738	else {
1739		new = ucl_object_new_userdata (NULL, NULL);
1740		ucl_object_set_priority (new, priority);
1741	}
1742
1743	return new;
1744}
1745
1746ucl_object_t*
1747ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
1748{
1749	struct ucl_object_userdata *new;
1750	size_t nsize = sizeof (*new);
1751
1752	new = UCL_ALLOC (nsize);
1753	if (new != NULL) {
1754		memset (new, 0, nsize);
1755		new->obj.ref = 1;
1756		new->obj.type = UCL_USERDATA;
1757		new->obj.next = NULL;
1758		new->obj.prev = (ucl_object_t *)new;
1759		new->dtor = dtor;
1760		new->emitter = emitter;
1761	}
1762
1763	return (ucl_object_t *)new;
1764}
1765
1766ucl_type_t
1767ucl_object_type (const ucl_object_t *obj)
1768{
1769	return obj->type;
1770}
1771
1772ucl_object_t*
1773ucl_object_fromstring (const char *str)
1774{
1775	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
1776}
1777
1778ucl_object_t *
1779ucl_object_fromlstring (const char *str, size_t len)
1780{
1781	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
1782}
1783
1784ucl_object_t *
1785ucl_object_fromint (int64_t iv)
1786{
1787	ucl_object_t *obj;
1788
1789	obj = ucl_object_new ();
1790	if (obj != NULL) {
1791		obj->type = UCL_INT;
1792		obj->value.iv = iv;
1793	}
1794
1795	return obj;
1796}
1797
1798ucl_object_t *
1799ucl_object_fromdouble (double dv)
1800{
1801	ucl_object_t *obj;
1802
1803	obj = ucl_object_new ();
1804	if (obj != NULL) {
1805		obj->type = UCL_FLOAT;
1806		obj->value.dv = dv;
1807	}
1808
1809	return obj;
1810}
1811
1812ucl_object_t*
1813ucl_object_frombool (bool bv)
1814{
1815	ucl_object_t *obj;
1816
1817	obj = ucl_object_new ();
1818	if (obj != NULL) {
1819		obj->type = UCL_BOOLEAN;
1820		obj->value.iv = bv;
1821	}
1822
1823	return obj;
1824}
1825
1826bool
1827ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
1828{
1829	ucl_object_t *head;
1830
1831	if (elt == NULL || top == NULL) {
1832		return false;
1833	}
1834
1835	head = top->value.av;
1836	if (head == NULL) {
1837		top->value.av = elt;
1838		elt->prev = elt;
1839	}
1840	else {
1841		elt->prev = head->prev;
1842		head->prev->next = elt;
1843		head->prev = elt;
1844	}
1845	elt->next = NULL;
1846	top->len ++;
1847
1848	return true;
1849}
1850
1851bool
1852ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
1853{
1854	ucl_object_t *head;
1855
1856	if (elt == NULL || top == NULL) {
1857		return false;
1858	}
1859
1860
1861	head = top->value.av;
1862	if (head == NULL) {
1863		top->value.av = elt;
1864		elt->prev = elt;
1865	}
1866	else {
1867		elt->prev = head->prev;
1868		head->prev = elt;
1869	}
1870	elt->next = head;
1871	top->value.av = elt;
1872	top->len ++;
1873
1874	return true;
1875}
1876
1877bool
1878ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
1879{
1880	ucl_object_t *cur, *tmp, *cp;
1881
1882	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
1883		return false;
1884	}
1885
1886	DL_FOREACH_SAFE (elt->value.av, cur, tmp) {
1887		if (copy) {
1888			cp = ucl_object_copy (cur);
1889		}
1890		else {
1891			cp = ucl_object_ref (cur);
1892		}
1893		if (cp != NULL) {
1894			ucl_array_append (top, cp);
1895		}
1896	}
1897
1898	return true;
1899}
1900
1901ucl_object_t *
1902ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
1903{
1904	ucl_object_t *head;
1905
1906	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1907		return NULL;
1908	}
1909	head = top->value.av;
1910
1911	if (elt->prev == elt) {
1912		top->value.av = NULL;
1913	}
1914	else if (elt == head) {
1915		elt->next->prev = elt->prev;
1916		top->value.av = elt->next;
1917	}
1918	else {
1919		elt->prev->next = elt->next;
1920		if (elt->next) {
1921			elt->next->prev = elt->prev;
1922		}
1923		else {
1924			head->prev = elt->prev;
1925		}
1926	}
1927	elt->next = NULL;
1928	elt->prev = elt;
1929	top->len --;
1930
1931	return elt;
1932}
1933
1934const ucl_object_t *
1935ucl_array_head (const ucl_object_t *top)
1936{
1937	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1938		return NULL;
1939	}
1940	return top->value.av;
1941}
1942
1943const ucl_object_t *
1944ucl_array_tail (const ucl_object_t *top)
1945{
1946	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1947		return NULL;
1948	}
1949	return top->value.av->prev;
1950}
1951
1952ucl_object_t *
1953ucl_array_pop_last (ucl_object_t *top)
1954{
1955	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top)));
1956}
1957
1958ucl_object_t *
1959ucl_array_pop_first (ucl_object_t *top)
1960{
1961	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top)));
1962}
1963
1964const ucl_object_t *
1965ucl_array_find_index (const ucl_object_t *top, unsigned int index)
1966{
1967	ucl_object_iter_t it = NULL;
1968	const ucl_object_t *ret;
1969
1970	if (top == NULL || top->type != UCL_ARRAY || top->len == 0 ||
1971	    (index + 1) > top->len) {
1972		return NULL;
1973	}
1974
1975	while ((ret = ucl_iterate_object (top, &it, true)) != NULL) {
1976		if (index == 0) {
1977			return ret;
1978		}
1979		--index;
1980	}
1981
1982	return NULL;
1983}
1984
1985ucl_object_t *
1986ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
1987	unsigned int index)
1988{
1989	ucl_object_t *cur, *tmp;
1990
1991	if (top == NULL || top->type != UCL_ARRAY || elt == NULL ||
1992			top->len == 0 || (index + 1) > top->len) {
1993		return NULL;
1994	}
1995
1996	DL_FOREACH_SAFE (top->value.av, cur, tmp) {
1997		if (index == 0) {
1998			DL_REPLACE_ELEM (top->value.av, cur, elt);
1999			return cur;
2000		}
2001		--index;
2002	}
2003
2004	return NULL;
2005}
2006
2007ucl_object_t *
2008ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
2009{
2010
2011	if (head == NULL) {
2012		elt->next = NULL;
2013		elt->prev = elt;
2014		head = elt;
2015	}
2016	else {
2017		elt->prev = head->prev;
2018		head->prev->next = elt;
2019		head->prev = elt;
2020		elt->next = NULL;
2021	}
2022
2023	return head;
2024}
2025
2026bool
2027ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
2028{
2029	if (obj == NULL || target == NULL) {
2030		return false;
2031	}
2032	switch (obj->type) {
2033	case UCL_INT:
2034		*target = obj->value.iv; /* Probaly could cause overflow */
2035		break;
2036	case UCL_FLOAT:
2037	case UCL_TIME:
2038		*target = obj->value.dv;
2039		break;
2040	default:
2041		return false;
2042	}
2043
2044	return true;
2045}
2046
2047double
2048ucl_object_todouble (const ucl_object_t *obj)
2049{
2050	double result = 0.;
2051
2052	ucl_object_todouble_safe (obj, &result);
2053	return result;
2054}
2055
2056bool
2057ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
2058{
2059	if (obj == NULL || target == NULL) {
2060		return false;
2061	}
2062	switch (obj->type) {
2063	case UCL_INT:
2064		*target = obj->value.iv;
2065		break;
2066	case UCL_FLOAT:
2067	case UCL_TIME:
2068		*target = obj->value.dv; /* Loosing of decimal points */
2069		break;
2070	default:
2071		return false;
2072	}
2073
2074	return true;
2075}
2076
2077int64_t
2078ucl_object_toint (const ucl_object_t *obj)
2079{
2080	int64_t result = 0;
2081
2082	ucl_object_toint_safe (obj, &result);
2083	return result;
2084}
2085
2086bool
2087ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
2088{
2089	if (obj == NULL || target == NULL) {
2090		return false;
2091	}
2092	switch (obj->type) {
2093	case UCL_BOOLEAN:
2094		*target = (obj->value.iv == true);
2095		break;
2096	default:
2097		return false;
2098	}
2099
2100	return true;
2101}
2102
2103bool
2104ucl_object_toboolean (const ucl_object_t *obj)
2105{
2106	bool result = false;
2107
2108	ucl_object_toboolean_safe (obj, &result);
2109	return result;
2110}
2111
2112bool
2113ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
2114{
2115	if (obj == NULL || target == NULL) {
2116		return false;
2117	}
2118
2119	switch (obj->type) {
2120	case UCL_STRING:
2121		*target = ucl_copy_value_trash (obj);
2122		break;
2123	default:
2124		return false;
2125	}
2126
2127	return true;
2128}
2129
2130const char *
2131ucl_object_tostring (const ucl_object_t *obj)
2132{
2133	const char *result = NULL;
2134
2135	ucl_object_tostring_safe (obj, &result);
2136	return result;
2137}
2138
2139const char *
2140ucl_object_tostring_forced (const ucl_object_t *obj)
2141{
2142	return ucl_copy_value_trash (obj);
2143}
2144
2145bool
2146ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
2147{
2148	if (obj == NULL || target == NULL) {
2149		return false;
2150	}
2151	switch (obj->type) {
2152	case UCL_STRING:
2153		*target = obj->value.sv;
2154		if (tlen != NULL) {
2155			*tlen = obj->len;
2156		}
2157		break;
2158	default:
2159		return false;
2160	}
2161
2162	return true;
2163}
2164
2165const char *
2166ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
2167{
2168	const char *result = NULL;
2169
2170	ucl_object_tolstring_safe (obj, &result, tlen);
2171	return result;
2172}
2173
2174const char *
2175ucl_object_key (const ucl_object_t *obj)
2176{
2177	return ucl_copy_key_trash (obj);
2178}
2179
2180const char *
2181ucl_object_keyl (const ucl_object_t *obj, size_t *len)
2182{
2183	if (len == NULL || obj == NULL) {
2184		return NULL;
2185	}
2186	*len = obj->keylen;
2187	return obj->key;
2188}
2189
2190ucl_object_t *
2191ucl_object_ref (const ucl_object_t *obj)
2192{
2193	ucl_object_t *res = NULL;
2194
2195	if (obj != NULL) {
2196		if (obj->flags & UCL_OBJECT_EPHEMERAL) {
2197			/*
2198			 * Use deep copy for ephemeral objects, note that its refcount
2199			 * is NOT increased, since ephemeral objects does not need refcount
2200			 * at all
2201			 */
2202			res = ucl_object_copy (obj);
2203		}
2204		else {
2205			res = __DECONST (ucl_object_t *, obj);
2206#ifdef HAVE_ATOMIC_BUILTINS
2207			(void)__sync_add_and_fetch (&res->ref, 1);
2208#else
2209			res->ref ++;
2210#endif
2211		}
2212	}
2213	return res;
2214}
2215
2216static ucl_object_t *
2217ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
2218{
2219
2220	ucl_object_t *new;
2221	ucl_object_iter_t it = NULL;
2222	const ucl_object_t *cur;
2223
2224	new = malloc (sizeof (*new));
2225
2226	if (new != NULL) {
2227		memcpy (new, other, sizeof (*new));
2228		if (other->flags & UCL_OBJECT_EPHEMERAL) {
2229			/* Copied object is always non ephemeral */
2230			new->flags &= ~UCL_OBJECT_EPHEMERAL;
2231		}
2232		new->ref = 1;
2233		/* Unlink from others */
2234		new->next = NULL;
2235		new->prev = new;
2236
2237		/* deep copy of values stored */
2238		if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
2239			new->trash_stack[UCL_TRASH_KEY] =
2240					strdup (other->trash_stack[UCL_TRASH_KEY]);
2241			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
2242				new->key = new->trash_stack[UCL_TRASH_KEY];
2243			}
2244		}
2245		if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
2246			new->trash_stack[UCL_TRASH_VALUE] =
2247					strdup (other->trash_stack[UCL_TRASH_VALUE]);
2248			if (new->type == UCL_STRING) {
2249				new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
2250			}
2251		}
2252
2253		if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
2254			/* reset old value */
2255			memset (&new->value, 0, sizeof (new->value));
2256
2257			while ((cur = ucl_iterate_object (other, &it, true)) != NULL) {
2258				if (other->type == UCL_ARRAY) {
2259					ucl_array_append (new, ucl_object_copy_internal (cur, false));
2260				}
2261				else {
2262					ucl_object_t *cp = ucl_object_copy_internal (cur, true);
2263					if (cp != NULL) {
2264						ucl_object_insert_key (new, cp, cp->key, cp->keylen,
2265								false);
2266					}
2267				}
2268			}
2269		}
2270		else if (allow_array && other->next != NULL) {
2271			LL_FOREACH (other->next, cur) {
2272				ucl_object_t *cp = ucl_object_copy_internal (cur, false);
2273				if (cp != NULL) {
2274					DL_APPEND (new, cp);
2275				}
2276			}
2277		}
2278	}
2279
2280	return new;
2281}
2282
2283ucl_object_t *
2284ucl_object_copy (const ucl_object_t *other)
2285{
2286	return ucl_object_copy_internal (other, true);
2287}
2288
2289void
2290ucl_object_unref (ucl_object_t *obj)
2291{
2292	if (obj != NULL) {
2293#ifdef HAVE_ATOMIC_BUILTINS
2294		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
2295		if (rc == 0) {
2296#else
2297		if (--obj->ref == 0) {
2298#endif
2299			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
2300		}
2301	}
2302}
2303
2304int
2305ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
2306{
2307	const ucl_object_t *it1, *it2;
2308	ucl_object_iter_t iter = NULL;
2309	int ret = 0;
2310
2311	if (o1->type != o2->type) {
2312		return (o1->type) - (o2->type);
2313	}
2314
2315	switch (o1->type) {
2316	case UCL_STRING:
2317		if (o1->len == o2->len) {
2318			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
2319		}
2320		else {
2321			ret = o1->len - o2->len;
2322		}
2323		break;
2324	case UCL_FLOAT:
2325	case UCL_INT:
2326	case UCL_TIME:
2327		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
2328		break;
2329	case UCL_BOOLEAN:
2330		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
2331		break;
2332	case UCL_ARRAY:
2333		if (o1->len == o2->len) {
2334			it1 = o1->value.av;
2335			it2 = o2->value.av;
2336			/* Compare all elements in both arrays */
2337			while (it1 != NULL && it2 != NULL) {
2338				ret = ucl_object_compare (it1, it2);
2339				if (ret != 0) {
2340					break;
2341				}
2342				it1 = it1->next;
2343				it2 = it2->next;
2344			}
2345		}
2346		else {
2347			ret = o1->len - o2->len;
2348		}
2349		break;
2350	case UCL_OBJECT:
2351		if (o1->len == o2->len) {
2352			while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) {
2353				it2 = ucl_object_find_key (o2, ucl_object_key (it1));
2354				if (it2 == NULL) {
2355					ret = 1;
2356					break;
2357				}
2358				ret = ucl_object_compare (it1, it2);
2359				if (ret != 0) {
2360					break;
2361				}
2362			}
2363		}
2364		else {
2365			ret = o1->len - o2->len;
2366		}
2367		break;
2368	default:
2369		ret = 0;
2370		break;
2371	}
2372
2373	return ret;
2374}
2375
2376void
2377ucl_object_array_sort (ucl_object_t *ar,
2378		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2))
2379{
2380	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
2381		return;
2382	}
2383
2384	DL_SORT (ar->value.av, cmp);
2385}
2386
2387#define PRIOBITS 4
2388
2389unsigned int
2390ucl_object_get_priority (const ucl_object_t *obj)
2391{
2392	if (obj == NULL) {
2393		return 0;
2394	}
2395
2396	return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
2397}
2398
2399void
2400ucl_object_set_priority (ucl_object_t *obj,
2401		unsigned int priority)
2402{
2403	if (obj != NULL) {
2404		priority &= (0x1 << PRIOBITS) - 1;
2405		obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS);
2406	}
2407}
2408