ucl_util.c revision 275223
1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov
2262395Sbapt * All rights reserved.
3262395Sbapt *
4262395Sbapt * Redistribution and use in source and binary forms, with or without
5262395Sbapt * modification, are permitted provided that the following conditions are met:
6262395Sbapt *       * Redistributions of source code must retain the above copyright
7262395Sbapt *         notice, this list of conditions and the following disclaimer.
8262395Sbapt *       * Redistributions in binary form must reproduce the above copyright
9262395Sbapt *         notice, this list of conditions and the following disclaimer in the
10262395Sbapt *         documentation and/or other materials provided with the distribution.
11262395Sbapt *
12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22262395Sbapt */
23262395Sbapt
24262395Sbapt#include "ucl.h"
25262395Sbapt#include "ucl_internal.h"
26262395Sbapt#include "ucl_chartable.h"
27262395Sbapt
28275223Sbapt#include <glob.h>
29275223Sbapt
30263648Sbapt#ifdef HAVE_LIBGEN_H
31262395Sbapt#include <libgen.h> /* For dirname */
32263648Sbapt#endif
33262395Sbapt
34262395Sbapt#ifdef HAVE_OPENSSL
35262395Sbapt#include <openssl/err.h>
36262395Sbapt#include <openssl/sha.h>
37262395Sbapt#include <openssl/rsa.h>
38262395Sbapt#include <openssl/ssl.h>
39262395Sbapt#include <openssl/evp.h>
40262395Sbapt#endif
41262395Sbapt
42263648Sbapt#ifdef CURL_FOUND
43263648Sbapt#include <curl/curl.h>
44263648Sbapt#endif
45263648Sbapt#ifdef HAVE_FETCH_H
46263648Sbapt#include <fetch.h>
47263648Sbapt#endif
48263648Sbapt
49262975Sbapt#ifdef _WIN32
50262975Sbapt#include <windows.h>
51262975Sbapt
52263648Sbapt#ifndef PROT_READ
53262975Sbapt#define PROT_READ       1
54263648Sbapt#endif
55263648Sbapt#ifndef PROT_WRITE
56262975Sbapt#define PROT_WRITE      2
57263648Sbapt#endif
58263648Sbapt#ifndef PROT_READWRITE
59262975Sbapt#define PROT_READWRITE  3
60263648Sbapt#endif
61263648Sbapt#ifndef MAP_SHARED
62262975Sbapt#define MAP_SHARED      1
63263648Sbapt#endif
64263648Sbapt#ifndef MAP_PRIVATE
65262975Sbapt#define MAP_PRIVATE     2
66263648Sbapt#endif
67263648Sbapt#ifndef MAP_FAILED
68262975Sbapt#define MAP_FAILED      ((void *) -1)
69263648Sbapt#endif
70262975Sbapt
71263648Sbaptstatic void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
72262975Sbapt{
73262975Sbapt	void *map = NULL;
74262975Sbapt	HANDLE handle = INVALID_HANDLE_VALUE;
75262975Sbapt
76262975Sbapt	switch (prot) {
77262975Sbapt	default:
78262975Sbapt	case PROT_READ:
79262975Sbapt		{
80262975Sbapt			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
81262975Sbapt			if (!handle) break;
82262975Sbapt			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
83262975Sbapt			CloseHandle(handle);
84262975Sbapt			break;
85262975Sbapt		}
86262975Sbapt	case PROT_WRITE:
87262975Sbapt		{
88262975Sbapt			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
89262975Sbapt			if (!handle) break;
90262975Sbapt			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
91262975Sbapt			CloseHandle(handle);
92262975Sbapt			break;
93262975Sbapt		}
94262975Sbapt	case PROT_READWRITE:
95262975Sbapt		{
96262975Sbapt			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
97262975Sbapt			if (!handle) break;
98262975Sbapt			map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
99262975Sbapt			CloseHandle(handle);
100262975Sbapt			break;
101262975Sbapt		}
102262975Sbapt	}
103262975Sbapt	if (map == (void *) NULL) {
104262975Sbapt		return (void *) MAP_FAILED;
105262975Sbapt	}
106262975Sbapt	return (void *) ((char *) map + offset);
107262975Sbapt}
108262975Sbapt
109263648Sbaptstatic int ucl_munmap(void *map,size_t length)
110262975Sbapt{
111262975Sbapt	if (!UnmapViewOfFile(map)) {
112262975Sbapt		return(-1);
113262975Sbapt	}
114262975Sbapt	return(0);
115262975Sbapt}
116262975Sbapt
117263648Sbaptstatic char* ucl_realpath(const char *path, char *resolved_path) {
118262975Sbapt    char *p;
119262975Sbapt    char tmp[MAX_PATH + 1];
120262975Sbapt    strncpy(tmp, path, sizeof(tmp)-1);
121262975Sbapt    p = tmp;
122262975Sbapt    while(*p) {
123262975Sbapt        if (*p == '/') *p = '\\';
124262975Sbapt        p++;
125262975Sbapt    }
126262975Sbapt    return _fullpath(resolved_path, tmp, MAX_PATH);
127262975Sbapt}
128263648Sbapt#else
129263648Sbapt#define ucl_mmap mmap
130263648Sbapt#define ucl_munmap munmap
131263648Sbapt#define ucl_realpath realpath
132262975Sbapt#endif
133262975Sbapt
134264789Sbapttypedef void (*ucl_object_dtor) (ucl_object_t *obj);
135264789Sbaptstatic void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
136264789Sbapt		ucl_object_dtor dtor);
137264789Sbaptstatic void ucl_object_dtor_unref (ucl_object_t *obj);
138262395Sbapt
139262395Sbaptstatic void
140264789Sbaptucl_object_dtor_free (ucl_object_t *obj)
141262395Sbapt{
142264789Sbapt	if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
143264789Sbapt		UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
144264789Sbapt	}
145264789Sbapt	if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
146264789Sbapt		UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
147264789Sbapt	}
148275223Sbapt	/* Do not free ephemeral objects */
149275223Sbapt	if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
150275223Sbapt		if (obj->type != UCL_USERDATA) {
151275223Sbapt			UCL_FREE (sizeof (ucl_object_t), obj);
152275223Sbapt		}
153275223Sbapt		else {
154275223Sbapt			struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
155275223Sbapt			if (ud->dtor) {
156275223Sbapt				ud->dtor (obj->value.ud);
157275223Sbapt			}
158275223Sbapt			UCL_FREE (sizeof (*ud), obj);
159275223Sbapt		}
160275223Sbapt	}
161264789Sbapt}
162264789Sbapt
163264789Sbapt/*
164264789Sbapt * This is a helper function that performs exactly the same as
165264789Sbapt * `ucl_object_unref` but it doesn't iterate over elements allowing
166264789Sbapt * to use it for individual elements of arrays and multiple values
167264789Sbapt */
168264789Sbaptstatic void
169264789Sbaptucl_object_dtor_unref_single (ucl_object_t *obj)
170264789Sbapt{
171264789Sbapt	if (obj != NULL) {
172264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS
173264789Sbapt		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
174264789Sbapt		if (rc == 0) {
175264789Sbapt#else
176264789Sbapt		if (--obj->ref == 0) {
177264789Sbapt#endif
178264789Sbapt			ucl_object_free_internal (obj, false, ucl_object_dtor_unref);
179264789Sbapt		}
180264789Sbapt	}
181264789Sbapt}
182264789Sbapt
183264789Sbaptstatic void
184264789Sbaptucl_object_dtor_unref (ucl_object_t *obj)
185264789Sbapt{
186264789Sbapt	if (obj->ref == 0) {
187264789Sbapt		ucl_object_dtor_free (obj);
188264789Sbapt	}
189264789Sbapt	else {
190264789Sbapt		/* This may cause dtor unref being called one more time */
191264789Sbapt		ucl_object_dtor_unref_single (obj);
192264789Sbapt	}
193264789Sbapt}
194264789Sbapt
195264789Sbaptstatic void
196264789Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
197264789Sbapt{
198262395Sbapt	ucl_object_t *sub, *tmp;
199262395Sbapt
200262395Sbapt	while (obj != NULL) {
201262395Sbapt		if (obj->type == UCL_ARRAY) {
202262395Sbapt			sub = obj->value.av;
203262395Sbapt			while (sub != NULL) {
204262395Sbapt				tmp = sub->next;
205264789Sbapt				dtor (sub);
206262395Sbapt				sub = tmp;
207262395Sbapt			}
208262395Sbapt		}
209262395Sbapt		else if (obj->type == UCL_OBJECT) {
210262395Sbapt			if (obj->value.ov != NULL) {
211264789Sbapt				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor);
212262395Sbapt			}
213262395Sbapt		}
214262395Sbapt		tmp = obj->next;
215264789Sbapt		dtor (obj);
216262395Sbapt		obj = tmp;
217262395Sbapt
218262395Sbapt		if (!allow_rec) {
219262395Sbapt			break;
220262395Sbapt		}
221262395Sbapt	}
222262395Sbapt}
223262395Sbapt
224262395Sbaptvoid
225262395Sbaptucl_object_free (ucl_object_t *obj)
226262395Sbapt{
227264789Sbapt	ucl_object_free_internal (obj, true, ucl_object_dtor_free);
228262395Sbapt}
229262395Sbapt
230262395Sbaptsize_t
231262395Sbaptucl_unescape_json_string (char *str, size_t len)
232262395Sbapt{
233262395Sbapt	char *t = str, *h = str;
234262395Sbapt	int i, uval;
235262395Sbapt
236263648Sbapt	if (len <= 1) {
237263648Sbapt		return len;
238263648Sbapt	}
239262395Sbapt	/* t is target (tortoise), h is source (hare) */
240262395Sbapt
241262395Sbapt	while (len) {
242262395Sbapt		if (*h == '\\') {
243262395Sbapt			h ++;
244262395Sbapt			switch (*h) {
245262395Sbapt			case 'n':
246262395Sbapt				*t++ = '\n';
247262395Sbapt				break;
248262395Sbapt			case 'r':
249262395Sbapt				*t++ = '\r';
250262395Sbapt				break;
251262395Sbapt			case 'b':
252262395Sbapt				*t++ = '\b';
253262395Sbapt				break;
254262395Sbapt			case 't':
255262395Sbapt				*t++ = '\t';
256262395Sbapt				break;
257262395Sbapt			case 'f':
258262395Sbapt				*t++ = '\f';
259262395Sbapt				break;
260262395Sbapt			case '\\':
261262395Sbapt				*t++ = '\\';
262262395Sbapt				break;
263262395Sbapt			case '"':
264262395Sbapt				*t++ = '"';
265262395Sbapt				break;
266262395Sbapt			case 'u':
267262395Sbapt				/* Unicode escape */
268262395Sbapt				uval = 0;
269263648Sbapt				if (len > 3) {
270263648Sbapt					for (i = 0; i < 4; i++) {
271263648Sbapt						uval <<= 4;
272263648Sbapt						if (isdigit (h[i])) {
273263648Sbapt							uval += h[i] - '0';
274263648Sbapt						}
275263648Sbapt						else if (h[i] >= 'a' && h[i] <= 'f') {
276263648Sbapt							uval += h[i] - 'a' + 10;
277263648Sbapt						}
278263648Sbapt						else if (h[i] >= 'A' && h[i] <= 'F') {
279263648Sbapt							uval += h[i] - 'A' + 10;
280263648Sbapt						}
281263648Sbapt						else {
282263648Sbapt							break;
283263648Sbapt						}
284262395Sbapt					}
285263648Sbapt					h += 3;
286263648Sbapt					len -= 3;
287263648Sbapt					/* Encode */
288263648Sbapt					if(uval < 0x80) {
289263648Sbapt						t[0] = (char)uval;
290263648Sbapt						t ++;
291262395Sbapt					}
292263648Sbapt					else if(uval < 0x800) {
293263648Sbapt						t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
294263648Sbapt						t[1] = 0x80 + ((uval & 0x03F));
295263648Sbapt						t += 2;
296262395Sbapt					}
297263648Sbapt					else if(uval < 0x10000) {
298263648Sbapt						t[0] = 0xE0 + ((uval & 0xF000) >> 12);
299263648Sbapt						t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
300263648Sbapt						t[2] = 0x80 + ((uval & 0x003F));
301263648Sbapt						t += 3;
302263648Sbapt					}
303263648Sbapt					else if(uval <= 0x10FFFF) {
304263648Sbapt						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
305263648Sbapt						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
306263648Sbapt						t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
307263648Sbapt						t[3] = 0x80 + ((uval & 0x00003F));
308263648Sbapt						t += 4;
309263648Sbapt					}
310263648Sbapt					else {
311263648Sbapt						*t++ = '?';
312263648Sbapt					}
313262395Sbapt				}
314262395Sbapt				else {
315263648Sbapt					*t++ = 'u';
316262395Sbapt				}
317262395Sbapt				break;
318262395Sbapt			default:
319262395Sbapt				*t++ = *h;
320262395Sbapt				break;
321262395Sbapt			}
322262395Sbapt			h ++;
323262395Sbapt			len --;
324262395Sbapt		}
325262395Sbapt		else {
326262395Sbapt			*t++ = *h++;
327262395Sbapt		}
328262395Sbapt		len --;
329262395Sbapt	}
330262395Sbapt	*t = '\0';
331262395Sbapt
332262395Sbapt	return (t - str);
333262395Sbapt}
334262395Sbapt
335264789Sbaptchar *
336264789Sbaptucl_copy_key_trash (const ucl_object_t *obj)
337262395Sbapt{
338264789Sbapt	ucl_object_t *deconst;
339264789Sbapt
340263648Sbapt	if (obj == NULL) {
341263648Sbapt		return NULL;
342263648Sbapt	}
343262395Sbapt	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
344264789Sbapt		deconst = __DECONST (ucl_object_t *, obj);
345264789Sbapt		deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
346264789Sbapt		if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
347264789Sbapt			memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
348264789Sbapt			deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
349262395Sbapt		}
350264789Sbapt		deconst->key = obj->trash_stack[UCL_TRASH_KEY];
351264789Sbapt		deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
352262395Sbapt	}
353262395Sbapt
354262395Sbapt	return obj->trash_stack[UCL_TRASH_KEY];
355262395Sbapt}
356262395Sbapt
357264789Sbaptchar *
358264789Sbaptucl_copy_value_trash (const ucl_object_t *obj)
359262395Sbapt{
360264789Sbapt	ucl_object_t *deconst;
361264789Sbapt
362263648Sbapt	if (obj == NULL) {
363263648Sbapt		return NULL;
364263648Sbapt	}
365262395Sbapt	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
366264789Sbapt		deconst = __DECONST (ucl_object_t *, obj);
367262395Sbapt		if (obj->type == UCL_STRING) {
368264789Sbapt
369262395Sbapt			/* Special case for strings */
370264789Sbapt			deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
371264789Sbapt			if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
372264789Sbapt				memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
373264789Sbapt				deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
374264789Sbapt				deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
375262395Sbapt			}
376262395Sbapt		}
377262395Sbapt		else {
378262395Sbapt			/* Just emit value in json notation */
379264789Sbapt			deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
380264789Sbapt			deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
381262395Sbapt		}
382264789Sbapt		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
383262395Sbapt	}
384262395Sbapt	return obj->trash_stack[UCL_TRASH_VALUE];
385262395Sbapt}
386262395Sbapt
387262975SbaptUCL_EXTERN ucl_object_t*
388262395Sbaptucl_parser_get_object (struct ucl_parser *parser)
389262395Sbapt{
390262395Sbapt	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
391262395Sbapt		return ucl_object_ref (parser->top_obj);
392262395Sbapt	}
393262395Sbapt
394262395Sbapt	return NULL;
395262395Sbapt}
396262395Sbapt
397262975SbaptUCL_EXTERN void
398262395Sbaptucl_parser_free (struct ucl_parser *parser)
399262395Sbapt{
400262395Sbapt	struct ucl_stack *stack, *stmp;
401262395Sbapt	struct ucl_macro *macro, *mtmp;
402262395Sbapt	struct ucl_chunk *chunk, *ctmp;
403262395Sbapt	struct ucl_pubkey *key, *ktmp;
404262395Sbapt	struct ucl_variable *var, *vtmp;
405262395Sbapt
406263648Sbapt	if (parser == NULL) {
407263648Sbapt		return;
408263648Sbapt	}
409263648Sbapt
410262395Sbapt	if (parser->top_obj != NULL) {
411262395Sbapt		ucl_object_unref (parser->top_obj);
412262395Sbapt	}
413262395Sbapt
414262395Sbapt	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
415262395Sbapt		free (stack);
416262395Sbapt	}
417262395Sbapt	HASH_ITER (hh, parser->macroes, macro, mtmp) {
418262395Sbapt		free (macro->name);
419262395Sbapt		HASH_DEL (parser->macroes, macro);
420262395Sbapt		UCL_FREE (sizeof (struct ucl_macro), macro);
421262395Sbapt	}
422262395Sbapt	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
423262395Sbapt		UCL_FREE (sizeof (struct ucl_chunk), chunk);
424262395Sbapt	}
425262395Sbapt	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
426262395Sbapt		UCL_FREE (sizeof (struct ucl_pubkey), key);
427262395Sbapt	}
428262395Sbapt	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
429262395Sbapt		free (var->value);
430262395Sbapt		free (var->var);
431262395Sbapt		UCL_FREE (sizeof (struct ucl_variable), var);
432262395Sbapt	}
433262395Sbapt
434262395Sbapt	if (parser->err != NULL) {
435275223Sbapt		utstring_free (parser->err);
436262395Sbapt	}
437262395Sbapt
438275223Sbapt	if (parser->cur_file) {
439275223Sbapt		free (parser->cur_file);
440275223Sbapt	}
441275223Sbapt
442262395Sbapt	UCL_FREE (sizeof (struct ucl_parser), parser);
443262395Sbapt}
444262395Sbapt
445262975SbaptUCL_EXTERN const char *
446262395Sbaptucl_parser_get_error(struct ucl_parser *parser)
447262395Sbapt{
448263648Sbapt	if (parser == NULL) {
449263648Sbapt		return NULL;
450263648Sbapt	}
451263648Sbapt
452262395Sbapt	if (parser->err == NULL)
453262395Sbapt		return NULL;
454262395Sbapt
455262395Sbapt	return utstring_body(parser->err);
456262395Sbapt}
457262395Sbapt
458262975SbaptUCL_EXTERN bool
459262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
460262395Sbapt{
461262395Sbapt#ifndef HAVE_OPENSSL
462262395Sbapt	ucl_create_err (&parser->err, "cannot check signatures without openssl");
463262395Sbapt	return false;
464262395Sbapt#else
465262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
466262395Sbapt	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
467262395Sbapt	return EXIT_FAILURE;
468262395Sbapt# else
469262395Sbapt	struct ucl_pubkey *nkey;
470262395Sbapt	BIO *mem;
471262395Sbapt
472262395Sbapt	mem = BIO_new_mem_buf ((void *)key, len);
473262395Sbapt	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
474263648Sbapt	if (nkey == NULL) {
475263648Sbapt		ucl_create_err (&parser->err, "cannot allocate memory for key");
476263648Sbapt		return false;
477263648Sbapt	}
478262395Sbapt	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
479262395Sbapt	BIO_free (mem);
480262395Sbapt	if (nkey->key == NULL) {
481262395Sbapt		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
482262395Sbapt		ucl_create_err (&parser->err, "%s",
483262395Sbapt				ERR_error_string (ERR_get_error (), NULL));
484262395Sbapt		return false;
485262395Sbapt	}
486262395Sbapt	LL_PREPEND (parser->keys, nkey);
487262395Sbapt# endif
488262395Sbapt#endif
489262395Sbapt	return true;
490262395Sbapt}
491262395Sbapt
492262395Sbapt#ifdef CURL_FOUND
493262395Sbaptstruct ucl_curl_cbdata {
494262395Sbapt	unsigned char *buf;
495262395Sbapt	size_t buflen;
496262395Sbapt};
497262395Sbapt
498262395Sbaptstatic size_t
499262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
500262395Sbapt{
501262395Sbapt	struct ucl_curl_cbdata *cbdata = ud;
502262395Sbapt	size_t realsize = size * nmemb;
503262395Sbapt
504262395Sbapt	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
505262395Sbapt	if (cbdata->buf == NULL) {
506262395Sbapt		return 0;
507262395Sbapt	}
508262395Sbapt
509262395Sbapt	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
510262395Sbapt	cbdata->buflen += realsize;
511262395Sbapt	cbdata->buf[cbdata->buflen] = 0;
512262395Sbapt
513262395Sbapt	return realsize;
514262395Sbapt}
515262395Sbapt#endif
516262395Sbapt
517262395Sbapt/**
518262395Sbapt * Fetch a url and save results to the memory buffer
519262395Sbapt * @param url url to fetch
520262395Sbapt * @param len length of url
521262395Sbapt * @param buf target buffer
522262395Sbapt * @param buflen target length
523262395Sbapt * @return
524262395Sbapt */
525262395Sbaptstatic bool
526262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
527262395Sbapt		UT_string **err, bool must_exist)
528262395Sbapt{
529262395Sbapt
530262395Sbapt#ifdef HAVE_FETCH_H
531262395Sbapt	struct url *fetch_url;
532262395Sbapt	struct url_stat us;
533262395Sbapt	FILE *in;
534262395Sbapt
535262395Sbapt	fetch_url = fetchParseURL (url);
536262395Sbapt	if (fetch_url == NULL) {
537262395Sbapt		ucl_create_err (err, "invalid URL %s: %s",
538262395Sbapt				url, strerror (errno));
539262395Sbapt		return false;
540262395Sbapt	}
541262395Sbapt	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
542262395Sbapt		if (!must_exist) {
543262395Sbapt			ucl_create_err (err, "cannot fetch URL %s: %s",
544262395Sbapt				url, strerror (errno));
545262395Sbapt		}
546262395Sbapt		fetchFreeURL (fetch_url);
547262395Sbapt		return false;
548262395Sbapt	}
549262395Sbapt
550262395Sbapt	*buflen = us.size;
551262395Sbapt	*buf = malloc (*buflen);
552262395Sbapt	if (*buf == NULL) {
553262395Sbapt		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
554262395Sbapt				url, strerror (errno));
555262395Sbapt		fclose (in);
556262395Sbapt		fetchFreeURL (fetch_url);
557262395Sbapt		return false;
558262395Sbapt	}
559262395Sbapt
560262395Sbapt	if (fread (*buf, *buflen, 1, in) != 1) {
561262395Sbapt		ucl_create_err (err, "cannot read URL %s: %s",
562262395Sbapt				url, strerror (errno));
563262395Sbapt		fclose (in);
564262395Sbapt		fetchFreeURL (fetch_url);
565262395Sbapt		return false;
566262395Sbapt	}
567262395Sbapt
568262395Sbapt	fetchFreeURL (fetch_url);
569262395Sbapt	return true;
570262395Sbapt#elif defined(CURL_FOUND)
571262395Sbapt	CURL *curl;
572262395Sbapt	int r;
573262395Sbapt	struct ucl_curl_cbdata cbdata;
574262395Sbapt
575262395Sbapt	curl = curl_easy_init ();
576262395Sbapt	if (curl == NULL) {
577262395Sbapt		ucl_create_err (err, "CURL interface is broken");
578262395Sbapt		return false;
579262395Sbapt	}
580262395Sbapt	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
581262395Sbapt		ucl_create_err (err, "invalid URL %s: %s",
582262395Sbapt				url, curl_easy_strerror (r));
583262395Sbapt		curl_easy_cleanup (curl);
584262395Sbapt		return false;
585262395Sbapt	}
586262395Sbapt	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
587262395Sbapt	cbdata.buf = *buf;
588262395Sbapt	cbdata.buflen = *buflen;
589262395Sbapt	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
590262395Sbapt
591262395Sbapt	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
592262395Sbapt		if (!must_exist) {
593262395Sbapt			ucl_create_err (err, "error fetching URL %s: %s",
594262395Sbapt				url, curl_easy_strerror (r));
595262395Sbapt		}
596262395Sbapt		curl_easy_cleanup (curl);
597262395Sbapt		if (cbdata.buf) {
598262395Sbapt			free (cbdata.buf);
599262395Sbapt		}
600262395Sbapt		return false;
601262395Sbapt	}
602262395Sbapt	*buf = cbdata.buf;
603262395Sbapt	*buflen = cbdata.buflen;
604262395Sbapt
605262395Sbapt	return true;
606262395Sbapt#else
607262395Sbapt	ucl_create_err (err, "URL support is disabled");
608262395Sbapt	return false;
609262395Sbapt#endif
610262395Sbapt}
611262395Sbapt
612262395Sbapt/**
613262395Sbapt * Fetch a file and save results to the memory buffer
614262395Sbapt * @param filename filename to fetch
615262395Sbapt * @param len length of filename
616262395Sbapt * @param buf target buffer
617262395Sbapt * @param buflen target length
618262395Sbapt * @return
619262395Sbapt */
620262395Sbaptstatic bool
621262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
622262395Sbapt		UT_string **err, bool must_exist)
623262395Sbapt{
624262395Sbapt	int fd;
625262395Sbapt	struct stat st;
626262395Sbapt
627262395Sbapt	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
628262395Sbapt		if (must_exist) {
629262395Sbapt			ucl_create_err (err, "cannot stat file %s: %s",
630262395Sbapt					filename, strerror (errno));
631262395Sbapt		}
632262395Sbapt		return false;
633262395Sbapt	}
634262395Sbapt	if (st.st_size == 0) {
635262395Sbapt		/* Do not map empty files */
636262395Sbapt		*buf = "";
637262395Sbapt		*buflen = 0;
638262395Sbapt	}
639262395Sbapt	else {
640262395Sbapt		if ((fd = open (filename, O_RDONLY)) == -1) {
641262395Sbapt			ucl_create_err (err, "cannot open file %s: %s",
642262395Sbapt					filename, strerror (errno));
643262395Sbapt			return false;
644262395Sbapt		}
645263648Sbapt		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
646262395Sbapt			close (fd);
647262395Sbapt			ucl_create_err (err, "cannot mmap file %s: %s",
648262395Sbapt					filename, strerror (errno));
649262395Sbapt			return false;
650262395Sbapt		}
651262395Sbapt		*buflen = st.st_size;
652262395Sbapt		close (fd);
653262395Sbapt	}
654262395Sbapt
655262395Sbapt	return true;
656262395Sbapt}
657262395Sbapt
658262395Sbapt
659262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
660262395Sbaptstatic inline bool
661262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen,
662262395Sbapt		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
663262395Sbapt{
664262395Sbapt	struct ucl_pubkey *key;
665262395Sbapt	char dig[EVP_MAX_MD_SIZE];
666262395Sbapt	unsigned int diglen;
667262395Sbapt	EVP_PKEY_CTX *key_ctx;
668262395Sbapt	EVP_MD_CTX *sign_ctx = NULL;
669262395Sbapt
670262395Sbapt	sign_ctx = EVP_MD_CTX_create ();
671262395Sbapt
672262395Sbapt	LL_FOREACH (parser->keys, key) {
673262395Sbapt		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
674262395Sbapt		if (key_ctx != NULL) {
675262395Sbapt			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
676262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
677262395Sbapt				continue;
678262395Sbapt			}
679262395Sbapt			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
680262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
681262395Sbapt				continue;
682262395Sbapt			}
683262395Sbapt			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
684262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
685262395Sbapt				continue;
686262395Sbapt			}
687262395Sbapt			EVP_DigestInit (sign_ctx, EVP_sha256 ());
688262395Sbapt			EVP_DigestUpdate (sign_ctx, data, datalen);
689262395Sbapt			EVP_DigestFinal (sign_ctx, dig, &diglen);
690262395Sbapt
691262395Sbapt			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
692262395Sbapt				EVP_MD_CTX_destroy (sign_ctx);
693262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
694262395Sbapt				return true;
695262395Sbapt			}
696262395Sbapt
697262395Sbapt			EVP_PKEY_CTX_free (key_ctx);
698262395Sbapt		}
699262395Sbapt	}
700262395Sbapt
701262395Sbapt	EVP_MD_CTX_destroy (sign_ctx);
702262395Sbapt
703262395Sbapt	return false;
704262395Sbapt}
705262395Sbapt#endif
706262395Sbapt
707262395Sbapt/**
708262395Sbapt * Include an url to configuration
709262395Sbapt * @param data
710262395Sbapt * @param len
711262395Sbapt * @param parser
712262395Sbapt * @param err
713262395Sbapt * @return
714262395Sbapt */
715262395Sbaptstatic bool
716262395Sbaptucl_include_url (const unsigned char *data, size_t len,
717275223Sbapt		struct ucl_parser *parser, bool check_signature, bool must_exist,
718275223Sbapt		unsigned priority)
719262395Sbapt{
720262395Sbapt
721262395Sbapt	bool res;
722262395Sbapt	unsigned char *buf = NULL;
723262395Sbapt	size_t buflen = 0;
724262395Sbapt	struct ucl_chunk *chunk;
725262395Sbapt	char urlbuf[PATH_MAX];
726262395Sbapt	int prev_state;
727262395Sbapt
728262395Sbapt	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
729262395Sbapt
730262395Sbapt	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) {
731262395Sbapt		return (!must_exist || false);
732262395Sbapt	}
733262395Sbapt
734262395Sbapt	if (check_signature) {
735262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
736262395Sbapt		unsigned char *sigbuf = NULL;
737262395Sbapt		size_t siglen = 0;
738262395Sbapt		/* We need to check signature first */
739262395Sbapt		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
740262395Sbapt		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
741262395Sbapt			return false;
742262395Sbapt		}
743262395Sbapt		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
744262395Sbapt			ucl_create_err (&parser->err, "cannot verify url %s: %s",
745262395Sbapt							urlbuf,
746262395Sbapt							ERR_error_string (ERR_get_error (), NULL));
747262395Sbapt			if (siglen > 0) {
748263648Sbapt				ucl_munmap (sigbuf, siglen);
749262395Sbapt			}
750262395Sbapt			return false;
751262395Sbapt		}
752262395Sbapt		if (siglen > 0) {
753263648Sbapt			ucl_munmap (sigbuf, siglen);
754262395Sbapt		}
755262395Sbapt#endif
756262395Sbapt	}
757262395Sbapt
758262395Sbapt	prev_state = parser->state;
759262395Sbapt	parser->state = UCL_STATE_INIT;
760262395Sbapt
761275223Sbapt	res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
762262395Sbapt	if (res == true) {
763262395Sbapt		/* Remove chunk from the stack */
764262395Sbapt		chunk = parser->chunks;
765262395Sbapt		if (chunk != NULL) {
766262395Sbapt			parser->chunks = chunk->next;
767262395Sbapt			UCL_FREE (sizeof (struct ucl_chunk), chunk);
768262395Sbapt		}
769262395Sbapt	}
770262395Sbapt
771262395Sbapt	parser->state = prev_state;
772262395Sbapt	free (buf);
773262395Sbapt
774262395Sbapt	return res;
775262395Sbapt}
776262395Sbapt
777262395Sbapt/**
778275223Sbapt * Include a single file to the parser
779262395Sbapt * @param data
780262395Sbapt * @param len
781262395Sbapt * @param parser
782275223Sbapt * @param check_signature
783275223Sbapt * @param must_exist
784275223Sbapt * @param allow_glob
785275223Sbapt * @param priority
786262395Sbapt * @return
787262395Sbapt */
788262395Sbaptstatic bool
789275223Sbaptucl_include_file_single (const unsigned char *data, size_t len,
790275223Sbapt		struct ucl_parser *parser, bool check_signature, bool must_exist,
791275223Sbapt		unsigned priority)
792262395Sbapt{
793262395Sbapt	bool res;
794262395Sbapt	struct ucl_chunk *chunk;
795262395Sbapt	unsigned char *buf = NULL;
796275223Sbapt	char *old_curfile;
797262395Sbapt	size_t buflen;
798262395Sbapt	char filebuf[PATH_MAX], realbuf[PATH_MAX];
799262395Sbapt	int prev_state;
800275223Sbapt	struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
801275223Sbapt			*old_filename = NULL;
802262395Sbapt
803262395Sbapt	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
804263648Sbapt	if (ucl_realpath (filebuf, realbuf) == NULL) {
805262395Sbapt		if (!must_exist) {
806262395Sbapt			return true;
807262395Sbapt		}
808262395Sbapt		ucl_create_err (&parser->err, "cannot open file %s: %s",
809262395Sbapt									filebuf,
810262395Sbapt									strerror (errno));
811262395Sbapt		return false;
812262395Sbapt	}
813262395Sbapt
814275223Sbapt	if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
815275223Sbapt		/* We are likely including the file itself */
816275223Sbapt		ucl_create_err (&parser->err, "trying to include the file %s from itself",
817275223Sbapt				realbuf);
818275223Sbapt		return false;
819275223Sbapt	}
820275223Sbapt
821262395Sbapt	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
822262395Sbapt		return (!must_exist || false);
823262395Sbapt	}
824262395Sbapt
825262395Sbapt	if (check_signature) {
826262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
827262395Sbapt		unsigned char *sigbuf = NULL;
828262395Sbapt		size_t siglen = 0;
829262395Sbapt		/* We need to check signature first */
830262395Sbapt		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
831262395Sbapt		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
832262395Sbapt			return false;
833262395Sbapt		}
834262395Sbapt		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
835262395Sbapt			ucl_create_err (&parser->err, "cannot verify file %s: %s",
836262395Sbapt							filebuf,
837262395Sbapt							ERR_error_string (ERR_get_error (), NULL));
838262395Sbapt			if (siglen > 0) {
839263648Sbapt				ucl_munmap (sigbuf, siglen);
840262395Sbapt			}
841262395Sbapt			return false;
842262395Sbapt		}
843262395Sbapt		if (siglen > 0) {
844263648Sbapt			ucl_munmap (sigbuf, siglen);
845262395Sbapt		}
846262395Sbapt#endif
847262395Sbapt	}
848262395Sbapt
849275223Sbapt	old_curfile = parser->cur_file;
850275223Sbapt	parser->cur_file = strdup (realbuf);
851275223Sbapt
852275223Sbapt	/* Store old file vars */
853275223Sbapt	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
854275223Sbapt		if (strcmp (cur_var->var, "CURDIR") == 0) {
855275223Sbapt			old_curdir = cur_var;
856275223Sbapt			DL_DELETE (parser->variables, cur_var);
857275223Sbapt		}
858275223Sbapt		else if (strcmp (cur_var->var, "FILENAME") == 0) {
859275223Sbapt			old_filename = cur_var;
860275223Sbapt			DL_DELETE (parser->variables, cur_var);
861275223Sbapt		}
862275223Sbapt	}
863275223Sbapt
864262395Sbapt	ucl_parser_set_filevars (parser, realbuf, false);
865262395Sbapt
866262395Sbapt	prev_state = parser->state;
867262395Sbapt	parser->state = UCL_STATE_INIT;
868262395Sbapt
869275223Sbapt	res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
870275223Sbapt	if (!res && !must_exist) {
871275223Sbapt		/* Free error */
872275223Sbapt		utstring_free (parser->err);
873275223Sbapt		parser->err = NULL;
874275223Sbapt		parser->state = UCL_STATE_AFTER_VALUE;
875275223Sbapt	}
876275223Sbapt
877275223Sbapt	/* Remove chunk from the stack */
878275223Sbapt	chunk = parser->chunks;
879275223Sbapt	if (chunk != NULL) {
880275223Sbapt		parser->chunks = chunk->next;
881275223Sbapt		UCL_FREE (sizeof (struct ucl_chunk), chunk);
882275223Sbapt		parser->recursion --;
883275223Sbapt	}
884275223Sbapt
885275223Sbapt	/* Restore old file vars */
886275223Sbapt	parser->cur_file = old_curfile;
887275223Sbapt	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
888275223Sbapt		if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
889275223Sbapt			DL_DELETE (parser->variables, cur_var);
890275223Sbapt			free (cur_var->var);
891275223Sbapt			free (cur_var->value);
892275223Sbapt			UCL_FREE (sizeof (struct ucl_variable), cur_var);
893262395Sbapt		}
894275223Sbapt		else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
895275223Sbapt			DL_DELETE (parser->variables, cur_var);
896275223Sbapt			free (cur_var->var);
897275223Sbapt			free (cur_var->value);
898275223Sbapt			UCL_FREE (sizeof (struct ucl_variable), cur_var);
899275223Sbapt		}
900262395Sbapt	}
901275223Sbapt	if (old_filename) {
902275223Sbapt		DL_APPEND (parser->variables, old_filename);
903275223Sbapt	}
904275223Sbapt	if (old_curdir) {
905275223Sbapt		DL_APPEND (parser->variables, old_curdir);
906275223Sbapt	}
907275223Sbapt	if (old_curfile) {
908275223Sbapt		free (old_curfile);
909275223Sbapt	}
910262395Sbapt
911262395Sbapt	parser->state = prev_state;
912262395Sbapt
913262395Sbapt	if (buflen > 0) {
914263648Sbapt		ucl_munmap (buf, buflen);
915262395Sbapt	}
916262395Sbapt
917262395Sbapt	return res;
918262395Sbapt}
919262395Sbapt
920262395Sbapt/**
921275223Sbapt * Include a file to configuration
922275223Sbapt * @param data
923275223Sbapt * @param len
924275223Sbapt * @param parser
925275223Sbapt * @param err
926275223Sbapt * @return
927275223Sbapt */
928275223Sbaptstatic bool
929275223Sbaptucl_include_file (const unsigned char *data, size_t len,
930275223Sbapt		struct ucl_parser *parser, bool check_signature, bool must_exist,
931275223Sbapt		bool allow_glob, unsigned priority)
932275223Sbapt{
933275223Sbapt	const unsigned char *p = data, *end = data + len;
934275223Sbapt	bool need_glob = false;
935275223Sbapt	int cnt = 0;
936275223Sbapt	glob_t globbuf;
937275223Sbapt	char glob_pattern[PATH_MAX];
938275223Sbapt	size_t i;
939275223Sbapt
940275223Sbapt	if (!allow_glob) {
941275223Sbapt		return ucl_include_file_single (data, len, parser, check_signature,
942275223Sbapt			must_exist, priority);
943275223Sbapt	}
944275223Sbapt	else {
945275223Sbapt		/* Check for special symbols in a filename */
946275223Sbapt		while (p != end) {
947275223Sbapt			if (*p == '*' || *p == '?') {
948275223Sbapt				need_glob = true;
949275223Sbapt				break;
950275223Sbapt			}
951275223Sbapt			p ++;
952275223Sbapt		}
953275223Sbapt		if (need_glob) {
954275223Sbapt			memset (&globbuf, 0, sizeof (globbuf));
955275223Sbapt			ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern));
956275223Sbapt			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
957275223Sbapt				return (!must_exist || false);
958275223Sbapt			}
959275223Sbapt			for (i = 0; i < globbuf.gl_pathc; i ++) {
960275223Sbapt				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
961275223Sbapt						strlen (globbuf.gl_pathv[i]), parser, check_signature,
962275223Sbapt						must_exist, priority)) {
963275223Sbapt					globfree (&globbuf);
964275223Sbapt					return false;
965275223Sbapt				}
966275223Sbapt				cnt ++;
967275223Sbapt			}
968275223Sbapt			globfree (&globbuf);
969275223Sbapt
970275223Sbapt			if (cnt == 0 && must_exist) {
971275223Sbapt				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
972275223Sbapt					glob_pattern);
973275223Sbapt				return false;
974275223Sbapt			}
975275223Sbapt		}
976275223Sbapt		else {
977275223Sbapt			return ucl_include_file_single (data, len, parser, check_signature,
978275223Sbapt				must_exist, priority);
979275223Sbapt		}
980275223Sbapt	}
981275223Sbapt
982275223Sbapt	return true;
983275223Sbapt}
984275223Sbapt
985275223Sbapt/**
986275223Sbapt * Common function to handle .*include* macros
987275223Sbapt * @param data
988275223Sbapt * @param len
989275223Sbapt * @param args
990275223Sbapt * @param parser
991275223Sbapt * @param default_try
992275223Sbapt * @param default_sign
993275223Sbapt * @return
994275223Sbapt */
995275223Sbaptstatic bool
996275223Sbaptucl_include_common (const unsigned char *data, size_t len,
997275223Sbapt		const ucl_object_t *args, struct ucl_parser *parser,
998275223Sbapt		bool default_try,
999275223Sbapt		bool default_sign)
1000275223Sbapt{
1001275223Sbapt	bool try_load, allow_glob, allow_url, need_sign;
1002275223Sbapt	unsigned priority;
1003275223Sbapt	const ucl_object_t *param;
1004275223Sbapt	ucl_object_iter_t it = NULL;
1005275223Sbapt
1006275223Sbapt	/* Default values */
1007275223Sbapt	try_load = default_try;
1008275223Sbapt	allow_glob = false;
1009275223Sbapt	allow_url = true;
1010275223Sbapt	need_sign = default_sign;
1011275223Sbapt	priority = 0;
1012275223Sbapt
1013275223Sbapt	/* Process arguments */
1014275223Sbapt	if (args != NULL && args->type == UCL_OBJECT) {
1015275223Sbapt		while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
1016275223Sbapt			if (param->type == UCL_BOOLEAN) {
1017275223Sbapt				if (strcmp (param->key, "try") == 0) {
1018275223Sbapt					try_load = ucl_object_toboolean (param);
1019275223Sbapt				}
1020275223Sbapt				else if (strcmp (param->key, "sign") == 0) {
1021275223Sbapt					need_sign = ucl_object_toboolean (param);
1022275223Sbapt				}
1023275223Sbapt				else if (strcmp (param->key, "glob") == 0) {
1024275223Sbapt					allow_glob =  ucl_object_toboolean (param);
1025275223Sbapt				}
1026275223Sbapt				else if (strcmp (param->key, "url") == 0) {
1027275223Sbapt					allow_url =  ucl_object_toboolean (param);
1028275223Sbapt				}
1029275223Sbapt			}
1030275223Sbapt			else if (param->type == UCL_INT) {
1031275223Sbapt				if (strcmp (param->key, "priority") == 0) {
1032275223Sbapt					priority = ucl_object_toint (param);
1033275223Sbapt				}
1034275223Sbapt			}
1035275223Sbapt		}
1036275223Sbapt	}
1037275223Sbapt
1038275223Sbapt	if (*data == '/' || *data == '.') {
1039275223Sbapt		/* Try to load a file */
1040275223Sbapt		return ucl_include_file (data, len, parser, need_sign, !try_load,
1041275223Sbapt				allow_glob, priority);
1042275223Sbapt	}
1043275223Sbapt	else if (allow_url) {
1044275223Sbapt		/* Globbing is not used for URL's */
1045275223Sbapt		return ucl_include_url (data, len, parser, need_sign, !try_load,
1046275223Sbapt				priority);
1047275223Sbapt	}
1048275223Sbapt
1049275223Sbapt	return false;
1050275223Sbapt}
1051275223Sbapt
1052275223Sbapt/**
1053262395Sbapt * Handle include macro
1054262395Sbapt * @param data include data
1055262395Sbapt * @param len length of data
1056262395Sbapt * @param ud user data
1057262395Sbapt * @param err error ptr
1058262395Sbapt * @return
1059262395Sbapt */
1060262975SbaptUCL_EXTERN bool
1061275223Sbaptucl_include_handler (const unsigned char *data, size_t len,
1062275223Sbapt		const ucl_object_t *args, void* ud)
1063262395Sbapt{
1064262395Sbapt	struct ucl_parser *parser = ud;
1065262395Sbapt
1066275223Sbapt	return ucl_include_common (data, len, args, parser, false, false);
1067262395Sbapt}
1068262395Sbapt
1069262395Sbapt/**
1070262395Sbapt * Handle includes macro
1071262395Sbapt * @param data include data
1072262395Sbapt * @param len length of data
1073262395Sbapt * @param ud user data
1074262395Sbapt * @param err error ptr
1075262395Sbapt * @return
1076262395Sbapt */
1077262975SbaptUCL_EXTERN bool
1078275223Sbaptucl_includes_handler (const unsigned char *data, size_t len,
1079275223Sbapt		const ucl_object_t *args, void* ud)
1080262395Sbapt{
1081262395Sbapt	struct ucl_parser *parser = ud;
1082262395Sbapt
1083275223Sbapt	return ucl_include_common (data, len, args, parser, false, true);
1084262395Sbapt}
1085262395Sbapt
1086262395Sbapt
1087262975SbaptUCL_EXTERN bool
1088275223Sbaptucl_try_include_handler (const unsigned char *data, size_t len,
1089275223Sbapt		const ucl_object_t *args, void* ud)
1090262395Sbapt{
1091262395Sbapt	struct ucl_parser *parser = ud;
1092262395Sbapt
1093275223Sbapt	return ucl_include_common (data, len, args, parser, true, false);
1094262395Sbapt}
1095262395Sbapt
1096262975SbaptUCL_EXTERN bool
1097262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
1098262395Sbapt{
1099262395Sbapt	char realbuf[PATH_MAX], *curdir;
1100262395Sbapt
1101262395Sbapt	if (filename != NULL) {
1102262395Sbapt		if (need_expand) {
1103263648Sbapt			if (ucl_realpath (filename, realbuf) == NULL) {
1104262395Sbapt				return false;
1105262395Sbapt			}
1106262395Sbapt		}
1107262395Sbapt		else {
1108262395Sbapt			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
1109262395Sbapt		}
1110262395Sbapt
1111262395Sbapt		/* Define variables */
1112262395Sbapt		ucl_parser_register_variable (parser, "FILENAME", realbuf);
1113262395Sbapt		curdir = dirname (realbuf);
1114262395Sbapt		ucl_parser_register_variable (parser, "CURDIR", curdir);
1115262395Sbapt	}
1116262395Sbapt	else {
1117262395Sbapt		/* Set everything from the current dir */
1118262395Sbapt		curdir = getcwd (realbuf, sizeof (realbuf));
1119262395Sbapt		ucl_parser_register_variable (parser, "FILENAME", "undef");
1120262395Sbapt		ucl_parser_register_variable (parser, "CURDIR", curdir);
1121262395Sbapt	}
1122262395Sbapt
1123262395Sbapt	return true;
1124262395Sbapt}
1125262395Sbapt
1126262975SbaptUCL_EXTERN bool
1127262395Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename)
1128262395Sbapt{
1129262395Sbapt	unsigned char *buf;
1130262395Sbapt	size_t len;
1131262395Sbapt	bool ret;
1132262395Sbapt	char realbuf[PATH_MAX];
1133262395Sbapt
1134263648Sbapt	if (ucl_realpath (filename, realbuf) == NULL) {
1135262395Sbapt		ucl_create_err (&parser->err, "cannot open file %s: %s",
1136262395Sbapt				filename,
1137262395Sbapt				strerror (errno));
1138262395Sbapt		return false;
1139262395Sbapt	}
1140262395Sbapt
1141262395Sbapt	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
1142262395Sbapt		return false;
1143262395Sbapt	}
1144262395Sbapt
1145275223Sbapt	if (parser->cur_file) {
1146275223Sbapt		free (parser->cur_file);
1147275223Sbapt	}
1148275223Sbapt	parser->cur_file = strdup (realbuf);
1149262395Sbapt	ucl_parser_set_filevars (parser, realbuf, false);
1150262395Sbapt	ret = ucl_parser_add_chunk (parser, buf, len);
1151262395Sbapt
1152262395Sbapt	if (len > 0) {
1153263648Sbapt		ucl_munmap (buf, len);
1154262395Sbapt	}
1155262395Sbapt
1156262395Sbapt	return ret;
1157262395Sbapt}
1158262395Sbapt
1159275223SbaptUCL_EXTERN bool
1160275223Sbaptucl_parser_add_fd (struct ucl_parser *parser, int fd)
1161275223Sbapt{
1162275223Sbapt	unsigned char *buf;
1163275223Sbapt	size_t len;
1164275223Sbapt	bool ret;
1165275223Sbapt	struct stat st;
1166275223Sbapt
1167275223Sbapt	if (fstat (fd, &st) == -1) {
1168275223Sbapt		ucl_create_err (&parser->err, "cannot stat fd %d: %s",
1169275223Sbapt			fd, strerror (errno));
1170275223Sbapt		return false;
1171275223Sbapt	}
1172275223Sbapt	if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1173275223Sbapt		ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
1174275223Sbapt			fd, strerror (errno));
1175275223Sbapt		return false;
1176275223Sbapt	}
1177275223Sbapt
1178275223Sbapt	if (parser->cur_file) {
1179275223Sbapt		free (parser->cur_file);
1180275223Sbapt	}
1181275223Sbapt	parser->cur_file = NULL;
1182275223Sbapt	len = st.st_size;
1183275223Sbapt	ret = ucl_parser_add_chunk (parser, buf, len);
1184275223Sbapt
1185275223Sbapt	if (len > 0) {
1186275223Sbapt		ucl_munmap (buf, len);
1187275223Sbapt	}
1188275223Sbapt
1189275223Sbapt	return ret;
1190275223Sbapt}
1191275223Sbapt
1192262395Sbaptsize_t
1193262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz)
1194262395Sbapt{
1195262395Sbapt	char *d = dst;
1196262395Sbapt	const char *s = src;
1197262395Sbapt	size_t n = siz;
1198262395Sbapt
1199262395Sbapt	/* Copy as many bytes as will fit */
1200262395Sbapt	if (n != 0) {
1201262395Sbapt		while (--n != 0) {
1202262395Sbapt			if ((*d++ = *s++) == '\0') {
1203262395Sbapt				break;
1204262395Sbapt			}
1205262395Sbapt		}
1206262395Sbapt	}
1207262395Sbapt
1208262395Sbapt	if (n == 0 && siz != 0) {
1209262395Sbapt		*d = '\0';
1210262395Sbapt	}
1211262395Sbapt
1212262395Sbapt	return (s - src - 1);    /* count does not include NUL */
1213262395Sbapt}
1214262395Sbapt
1215262395Sbaptsize_t
1216262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
1217262395Sbapt{
1218262395Sbapt	memcpy (dst, src, siz - 1);
1219262395Sbapt	dst[siz - 1] = '\0';
1220262395Sbapt
1221262395Sbapt	return siz - 1;
1222262395Sbapt}
1223262395Sbapt
1224262395Sbaptsize_t
1225262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
1226262395Sbapt{
1227262395Sbapt	char *d = dst;
1228262395Sbapt	const char *s = src;
1229262395Sbapt	size_t n = siz;
1230262395Sbapt
1231262395Sbapt	/* Copy as many bytes as will fit */
1232262395Sbapt	if (n != 0) {
1233262395Sbapt		while (--n != 0) {
1234262395Sbapt			if ((*d++ = tolower (*s++)) == '\0') {
1235262395Sbapt				break;
1236262395Sbapt			}
1237262395Sbapt		}
1238262395Sbapt	}
1239262395Sbapt
1240262395Sbapt	if (n == 0 && siz != 0) {
1241262395Sbapt		*d = '\0';
1242262395Sbapt	}
1243262395Sbapt
1244262395Sbapt	return (s - src);    /* count does not include NUL */
1245262395Sbapt}
1246262395Sbapt
1247262395Sbaptucl_object_t *
1248262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
1249262395Sbapt{
1250262395Sbapt	ucl_object_t *obj;
1251262395Sbapt	const char *start, *end, *p, *pos;
1252262395Sbapt	char *dst, *d;
1253262395Sbapt	size_t escaped_len;
1254262395Sbapt
1255262395Sbapt	if (str == NULL) {
1256262395Sbapt		return NULL;
1257262395Sbapt	}
1258262395Sbapt
1259262395Sbapt	obj = ucl_object_new ();
1260262395Sbapt	if (obj) {
1261262395Sbapt		if (len == 0) {
1262262395Sbapt			len = strlen (str);
1263262395Sbapt		}
1264262395Sbapt		if (flags & UCL_STRING_TRIM) {
1265262395Sbapt			/* Skip leading spaces */
1266262395Sbapt			for (start = str; (size_t)(start - str) < len; start ++) {
1267262395Sbapt				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1268262395Sbapt					break;
1269262395Sbapt				}
1270262395Sbapt			}
1271262395Sbapt			/* Skip trailing spaces */
1272262395Sbapt			for (end = str + len - 1; end > start; end --) {
1273262395Sbapt				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1274262395Sbapt					break;
1275262395Sbapt				}
1276262395Sbapt			}
1277262395Sbapt			end ++;
1278262395Sbapt		}
1279262395Sbapt		else {
1280262395Sbapt			start = str;
1281262395Sbapt			end = str + len;
1282262395Sbapt		}
1283262395Sbapt
1284262395Sbapt		obj->type = UCL_STRING;
1285262395Sbapt		if (flags & UCL_STRING_ESCAPE) {
1286262395Sbapt			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
1287262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1288262395Sbapt					escaped_len ++;
1289262395Sbapt				}
1290262395Sbapt			}
1291262395Sbapt			dst = malloc (escaped_len + 1);
1292262395Sbapt			if (dst != NULL) {
1293262395Sbapt				for (p = start, d = dst; p < end; p ++, d ++) {
1294262395Sbapt					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1295262395Sbapt						switch (*p) {
1296262395Sbapt						case '\n':
1297262395Sbapt							*d++ = '\\';
1298262395Sbapt							*d = 'n';
1299262395Sbapt							break;
1300262395Sbapt						case '\r':
1301262395Sbapt							*d++ = '\\';
1302262395Sbapt							*d = 'r';
1303262395Sbapt							break;
1304262395Sbapt						case '\b':
1305262395Sbapt							*d++ = '\\';
1306262395Sbapt							*d = 'b';
1307262395Sbapt							break;
1308262395Sbapt						case '\t':
1309262395Sbapt							*d++ = '\\';
1310262395Sbapt							*d = 't';
1311262395Sbapt							break;
1312262395Sbapt						case '\f':
1313262395Sbapt							*d++ = '\\';
1314262395Sbapt							*d = 'f';
1315262395Sbapt							break;
1316262395Sbapt						case '\\':
1317262395Sbapt							*d++ = '\\';
1318262395Sbapt							*d = '\\';
1319262395Sbapt							break;
1320262395Sbapt						case '"':
1321262395Sbapt							*d++ = '\\';
1322262395Sbapt							*d = '"';
1323262395Sbapt							break;
1324262395Sbapt						}
1325262395Sbapt					}
1326262395Sbapt					else {
1327262395Sbapt						*d = *p;
1328262395Sbapt					}
1329262395Sbapt				}
1330262395Sbapt				*d = '\0';
1331262395Sbapt				obj->value.sv = dst;
1332262395Sbapt				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1333262395Sbapt				obj->len = escaped_len;
1334262395Sbapt			}
1335262395Sbapt		}
1336262395Sbapt		else {
1337262395Sbapt			dst = malloc (end - start + 1);
1338262395Sbapt			if (dst != NULL) {
1339262395Sbapt				ucl_strlcpy_unsafe (dst, start, end - start + 1);
1340262395Sbapt				obj->value.sv = dst;
1341262395Sbapt				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1342262395Sbapt				obj->len = end - start;
1343262395Sbapt			}
1344262395Sbapt		}
1345262395Sbapt		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
1346262395Sbapt			/* Parse what we have */
1347262395Sbapt			if (flags & UCL_STRING_PARSE_BOOLEAN) {
1348262395Sbapt				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
1349262395Sbapt					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1350262395Sbapt							flags & UCL_STRING_PARSE_DOUBLE,
1351263648Sbapt							flags & UCL_STRING_PARSE_BYTES,
1352263648Sbapt							flags & UCL_STRING_PARSE_TIME);
1353262395Sbapt				}
1354262395Sbapt			}
1355262395Sbapt			else {
1356262395Sbapt				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1357262395Sbapt						flags & UCL_STRING_PARSE_DOUBLE,
1358263648Sbapt						flags & UCL_STRING_PARSE_BYTES,
1359263648Sbapt						flags & UCL_STRING_PARSE_TIME);
1360262395Sbapt			}
1361262395Sbapt		}
1362262395Sbapt	}
1363262395Sbapt
1364262395Sbapt	return obj;
1365262395Sbapt}
1366262395Sbapt
1367264789Sbaptstatic bool
1368262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
1369262395Sbapt		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
1370262395Sbapt{
1371264789Sbapt	ucl_object_t *found, *tmp;
1372264789Sbapt	const ucl_object_t *cur;
1373262395Sbapt	ucl_object_iter_t it = NULL;
1374262395Sbapt	const char *p;
1375264789Sbapt	int ret = true;
1376262395Sbapt
1377262395Sbapt	if (elt == NULL || key == NULL) {
1378264789Sbapt		return false;
1379262395Sbapt	}
1380262395Sbapt
1381262395Sbapt	if (top == NULL) {
1382264789Sbapt		return false;
1383262395Sbapt	}
1384262395Sbapt
1385262395Sbapt	if (top->type != UCL_OBJECT) {
1386262395Sbapt		/* It is possible to convert NULL type to an object */
1387262395Sbapt		if (top->type == UCL_NULL) {
1388262395Sbapt			top->type = UCL_OBJECT;
1389262395Sbapt		}
1390262395Sbapt		else {
1391262395Sbapt			/* Refuse converting of other object types */
1392264789Sbapt			return false;
1393262395Sbapt		}
1394262395Sbapt	}
1395262395Sbapt
1396262395Sbapt	if (top->value.ov == NULL) {
1397262395Sbapt		top->value.ov = ucl_hash_create ();
1398262395Sbapt	}
1399262395Sbapt
1400262395Sbapt	if (keylen == 0) {
1401262395Sbapt		keylen = strlen (key);
1402262395Sbapt	}
1403262395Sbapt
1404262395Sbapt	for (p = key; p < key + keylen; p ++) {
1405262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
1406262395Sbapt			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1407262395Sbapt			break;
1408262395Sbapt		}
1409262395Sbapt	}
1410262395Sbapt
1411275223Sbapt	/* workaround for some use cases */
1412275223Sbapt	if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
1413275223Sbapt			key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
1414275223Sbapt		/* Remove copied key */
1415275223Sbapt		free (elt->trash_stack[UCL_TRASH_KEY]);
1416275223Sbapt		elt->trash_stack[UCL_TRASH_KEY] = NULL;
1417275223Sbapt		elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
1418275223Sbapt	}
1419275223Sbapt
1420262395Sbapt	elt->key = key;
1421262395Sbapt	elt->keylen = keylen;
1422262395Sbapt
1423262395Sbapt	if (copy_key) {
1424262395Sbapt		ucl_copy_key_trash (elt);
1425262395Sbapt	}
1426262395Sbapt
1427264789Sbapt	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
1428262395Sbapt
1429275223Sbapt	if (found == NULL) {
1430262395Sbapt		top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1431263648Sbapt		top->len ++;
1432264789Sbapt		if (replace) {
1433264789Sbapt			ret = false;
1434264789Sbapt		}
1435262395Sbapt	}
1436262395Sbapt	else {
1437262395Sbapt		if (replace) {
1438275223Sbapt			ucl_hash_replace (top->value.ov, found, elt);
1439262395Sbapt			ucl_object_unref (found);
1440262395Sbapt		}
1441262395Sbapt		else if (merge) {
1442262395Sbapt			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
1443262395Sbapt				/* Insert old elt to new one */
1444264789Sbapt				ucl_object_insert_key_common (elt, found, found->key,
1445264789Sbapt						found->keylen, copy_key, false, false);
1446262395Sbapt				ucl_hash_delete (top->value.ov, found);
1447262395Sbapt				top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1448262395Sbapt			}
1449262395Sbapt			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
1450262395Sbapt				/* Insert new to old */
1451264789Sbapt				ucl_object_insert_key_common (found, elt, elt->key,
1452264789Sbapt						elt->keylen, copy_key, false, false);
1453262395Sbapt			}
1454262395Sbapt			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
1455262395Sbapt				/* Mix two hashes */
1456262395Sbapt				while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
1457264789Sbapt					tmp = ucl_object_ref (cur);
1458264789Sbapt					ucl_object_insert_key_common (found, tmp, cur->key,
1459264789Sbapt							cur->keylen, copy_key, false, false);
1460262395Sbapt				}
1461262395Sbapt				ucl_object_unref (elt);
1462262395Sbapt			}
1463262395Sbapt			else {
1464262395Sbapt				/* Just make a list of scalars */
1465262395Sbapt				DL_APPEND (found, elt);
1466262395Sbapt			}
1467262395Sbapt		}
1468262395Sbapt		else {
1469262395Sbapt			DL_APPEND (found, elt);
1470262395Sbapt		}
1471262395Sbapt	}
1472262395Sbapt
1473264789Sbapt	return ret;
1474262395Sbapt}
1475262395Sbapt
1476262975Sbaptbool
1477264789Sbaptucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
1478262975Sbapt{
1479262975Sbapt	ucl_object_t *found;
1480262975Sbapt
1481263648Sbapt	if (top == NULL || key == NULL) {
1482263648Sbapt		return false;
1483263648Sbapt	}
1484263648Sbapt
1485264789Sbapt	found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen));
1486262975Sbapt
1487263648Sbapt	if (found == NULL) {
1488262975Sbapt		return false;
1489263648Sbapt	}
1490262975Sbapt
1491264789Sbapt	ucl_hash_delete (top->value.ov, found);
1492262975Sbapt	ucl_object_unref (found);
1493262975Sbapt	top->len --;
1494262975Sbapt
1495262975Sbapt	return true;
1496262975Sbapt}
1497262975Sbapt
1498262975Sbaptbool
1499264789Sbaptucl_object_delete_key (ucl_object_t *top, const char *key)
1500262975Sbapt{
1501264789Sbapt	return ucl_object_delete_keyl (top, key, strlen(key));
1502262975Sbapt}
1503262975Sbapt
1504263648Sbaptucl_object_t*
1505263648Sbaptucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
1506263648Sbapt{
1507264789Sbapt	const ucl_object_t *found;
1508263648Sbapt
1509263648Sbapt	if (top == NULL || key == NULL) {
1510263648Sbapt		return false;
1511263648Sbapt	}
1512264789Sbapt	found = ucl_object_find_keyl (top, key, keylen);
1513263648Sbapt
1514263648Sbapt	if (found == NULL) {
1515263648Sbapt		return NULL;
1516263648Sbapt	}
1517264789Sbapt	ucl_hash_delete (top->value.ov, found);
1518263648Sbapt	top->len --;
1519263648Sbapt
1520264789Sbapt	return __DECONST (ucl_object_t *, found);
1521263648Sbapt}
1522263648Sbapt
1523263648Sbaptucl_object_t*
1524263648Sbaptucl_object_pop_key (ucl_object_t *top, const char *key)
1525263648Sbapt{
1526264789Sbapt	return ucl_object_pop_keyl (top, key, strlen(key));
1527263648Sbapt}
1528263648Sbapt
1529264789Sbaptbool
1530262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
1531262395Sbapt		const char *key, size_t keylen, bool copy_key)
1532262395Sbapt{
1533262395Sbapt	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
1534262395Sbapt}
1535262395Sbapt
1536264789Sbaptbool
1537262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
1538262395Sbapt		const char *key, size_t keylen, bool copy_key)
1539262395Sbapt{
1540262395Sbapt	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
1541262395Sbapt}
1542262395Sbapt
1543264789Sbaptbool
1544262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
1545262395Sbapt		const char *key, size_t keylen, bool copy_key)
1546262395Sbapt{
1547262395Sbapt	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
1548262395Sbapt}
1549262395Sbapt
1550275223Sbaptbool
1551275223Sbaptucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
1552275223Sbapt{
1553275223Sbapt	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
1554275223Sbapt	ucl_object_iter_t iter = NULL;
1555275223Sbapt
1556275223Sbapt	if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
1557275223Sbapt		return false;
1558275223Sbapt	}
1559275223Sbapt
1560275223Sbapt	/* Mix two hashes */
1561275223Sbapt	while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
1562275223Sbapt		if (copy) {
1563275223Sbapt			cp = ucl_object_copy (cur);
1564275223Sbapt		}
1565275223Sbapt		else {
1566275223Sbapt			cp = ucl_object_ref (cur);
1567275223Sbapt		}
1568275223Sbapt		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
1569275223Sbapt		if (found == NULL) {
1570275223Sbapt			/* The key does not exist */
1571275223Sbapt			top->value.ov = ucl_hash_insert_object (top->value.ov, cp);
1572275223Sbapt			top->len ++;
1573275223Sbapt		}
1574275223Sbapt		else {
1575275223Sbapt			/* The key already exists, replace it */
1576275223Sbapt			ucl_hash_replace (top->value.ov, found, cp);
1577275223Sbapt			ucl_object_unref (found);
1578275223Sbapt		}
1579275223Sbapt	}
1580275223Sbapt
1581275223Sbapt	return true;
1582275223Sbapt}
1583275223Sbapt
1584264789Sbaptconst ucl_object_t *
1585264789Sbaptucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
1586262395Sbapt{
1587264789Sbapt	const ucl_object_t *ret;
1588264789Sbapt	ucl_object_t srch;
1589262395Sbapt
1590262395Sbapt	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1591262395Sbapt		return NULL;
1592262395Sbapt	}
1593262395Sbapt
1594262395Sbapt	srch.key = key;
1595262395Sbapt	srch.keylen = klen;
1596262395Sbapt	ret = ucl_hash_search_obj (obj->value.ov, &srch);
1597262395Sbapt
1598262395Sbapt	return ret;
1599262395Sbapt}
1600262395Sbapt
1601264789Sbaptconst ucl_object_t *
1602264789Sbaptucl_object_find_key (const ucl_object_t *obj, const char *key)
1603262395Sbapt{
1604266636Sbapt	if (key == NULL)
1605262395Sbapt		return NULL;
1606262395Sbapt
1607266636Sbapt	return ucl_object_find_keyl (obj, key, strlen(key));
1608262395Sbapt}
1609262395Sbapt
1610264789Sbaptconst ucl_object_t*
1611264789Sbaptucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
1612262395Sbapt{
1613264789Sbapt	const ucl_object_t *elt;
1614262395Sbapt
1615263648Sbapt	if (obj == NULL || iter == NULL) {
1616263648Sbapt		return NULL;
1617263648Sbapt	}
1618263648Sbapt
1619262395Sbapt	if (expand_values) {
1620262395Sbapt		switch (obj->type) {
1621262395Sbapt		case UCL_OBJECT:
1622264789Sbapt			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
1623262395Sbapt			break;
1624262395Sbapt		case UCL_ARRAY:
1625262395Sbapt			elt = *iter;
1626262395Sbapt			if (elt == NULL) {
1627262395Sbapt				elt = obj->value.av;
1628262395Sbapt				if (elt == NULL) {
1629262395Sbapt					return NULL;
1630262395Sbapt				}
1631262395Sbapt			}
1632262395Sbapt			else if (elt == obj->value.av) {
1633262395Sbapt				return NULL;
1634262395Sbapt			}
1635262395Sbapt			*iter = elt->next ? elt->next : obj->value.av;
1636262395Sbapt			return elt;
1637262395Sbapt		default:
1638262395Sbapt			/* Go to linear iteration */
1639262395Sbapt			break;
1640262395Sbapt		}
1641262395Sbapt	}
1642262395Sbapt	/* Treat everything as a linear list */
1643262395Sbapt	elt = *iter;
1644262395Sbapt	if (elt == NULL) {
1645262395Sbapt		elt = obj;
1646262395Sbapt	}
1647262395Sbapt	else if (elt == obj) {
1648262395Sbapt		return NULL;
1649262395Sbapt	}
1650264789Sbapt	*iter = __DECONST (void *, elt->next ? elt->next : obj);
1651262395Sbapt	return elt;
1652262395Sbapt
1653262395Sbapt	/* Not reached */
1654262395Sbapt	return NULL;
1655262395Sbapt}
1656263648Sbapt
1657266636Sbaptconst ucl_object_t *
1658266636Sbaptucl_lookup_path (const ucl_object_t *top, const char *path_in) {
1659266636Sbapt	const ucl_object_t *o = NULL, *found;
1660266636Sbapt	const char *p, *c;
1661266636Sbapt	char *err_str;
1662266636Sbapt	unsigned index;
1663263648Sbapt
1664266636Sbapt	if (path_in == NULL || top == NULL) {
1665266636Sbapt		return NULL;
1666266636Sbapt	}
1667266636Sbapt
1668266636Sbapt	found = NULL;
1669266636Sbapt	p = path_in;
1670266636Sbapt
1671266636Sbapt	/* Skip leading dots */
1672266636Sbapt	while (*p == '.') {
1673266636Sbapt		p ++;
1674266636Sbapt	}
1675266636Sbapt
1676266636Sbapt	c = p;
1677266636Sbapt	while (*p != '\0') {
1678266636Sbapt		p ++;
1679266636Sbapt		if (*p == '.' || *p == '\0') {
1680266636Sbapt			if (p > c) {
1681266636Sbapt				switch (top->type) {
1682266636Sbapt				case UCL_ARRAY:
1683266636Sbapt					/* Key should be an int */
1684266636Sbapt					index = strtoul (c, &err_str, 10);
1685266636Sbapt					if (err_str != NULL && (*err_str != '.' && *err_str != '\0')) {
1686266636Sbapt						return NULL;
1687266636Sbapt					}
1688266636Sbapt					o = ucl_array_find_index (top, index);
1689266636Sbapt					break;
1690266636Sbapt				default:
1691266636Sbapt					o = ucl_object_find_keyl (top, c, p - c);
1692266636Sbapt					break;
1693266636Sbapt				}
1694266636Sbapt				if (o == NULL) {
1695266636Sbapt					return NULL;
1696266636Sbapt				}
1697266636Sbapt				top = o;
1698266636Sbapt			}
1699266636Sbapt			if (*p != '\0') {
1700266636Sbapt				c = p + 1;
1701266636Sbapt			}
1702266636Sbapt		}
1703266636Sbapt	}
1704266636Sbapt	found = o;
1705266636Sbapt
1706266636Sbapt	return found;
1707266636Sbapt}
1708266636Sbapt
1709266636Sbapt
1710263648Sbaptucl_object_t *
1711263648Sbaptucl_object_new (void)
1712263648Sbapt{
1713275223Sbapt	return ucl_object_typed_new (UCL_NULL);
1714263648Sbapt}
1715263648Sbapt
1716263648Sbaptucl_object_t *
1717266636Sbaptucl_object_typed_new (ucl_type_t type)
1718263648Sbapt{
1719275223Sbapt	return ucl_object_new_full (type, 0);
1720275223Sbapt}
1721275223Sbapt
1722275223Sbaptucl_object_t *
1723275223Sbaptucl_object_new_full (ucl_type_t type, unsigned priority)
1724275223Sbapt{
1725263648Sbapt	ucl_object_t *new;
1726275223Sbapt
1727275223Sbapt	if (type != UCL_USERDATA) {
1728275223Sbapt		new = UCL_ALLOC (sizeof (ucl_object_t));
1729275223Sbapt		if (new != NULL) {
1730275223Sbapt			memset (new, 0, sizeof (ucl_object_t));
1731275223Sbapt			new->ref = 1;
1732275223Sbapt			new->type = (type <= UCL_NULL ? type : UCL_NULL);
1733275223Sbapt			new->next = NULL;
1734275223Sbapt			new->prev = new;
1735275223Sbapt			ucl_object_set_priority (new, priority);
1736275223Sbapt		}
1737263648Sbapt	}
1738275223Sbapt	else {
1739275223Sbapt		new = ucl_object_new_userdata (NULL, NULL);
1740275223Sbapt		ucl_object_set_priority (new, priority);
1741275223Sbapt	}
1742275223Sbapt
1743263648Sbapt	return new;
1744263648Sbapt}
1745263648Sbapt
1746275223Sbaptucl_object_t*
1747275223Sbaptucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
1748275223Sbapt{
1749275223Sbapt	struct ucl_object_userdata *new;
1750275223Sbapt	size_t nsize = sizeof (*new);
1751275223Sbapt
1752275223Sbapt	new = UCL_ALLOC (nsize);
1753275223Sbapt	if (new != NULL) {
1754275223Sbapt		memset (new, 0, nsize);
1755275223Sbapt		new->obj.ref = 1;
1756275223Sbapt		new->obj.type = UCL_USERDATA;
1757275223Sbapt		new->obj.next = NULL;
1758275223Sbapt		new->obj.prev = (ucl_object_t *)new;
1759275223Sbapt		new->dtor = dtor;
1760275223Sbapt		new->emitter = emitter;
1761275223Sbapt	}
1762275223Sbapt
1763275223Sbapt	return (ucl_object_t *)new;
1764275223Sbapt}
1765275223Sbapt
1766266636Sbaptucl_type_t
1767266636Sbaptucl_object_type (const ucl_object_t *obj)
1768266636Sbapt{
1769266636Sbapt	return obj->type;
1770266636Sbapt}
1771266636Sbapt
1772263648Sbaptucl_object_t*
1773263648Sbaptucl_object_fromstring (const char *str)
1774263648Sbapt{
1775263648Sbapt	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
1776263648Sbapt}
1777263648Sbapt
1778263648Sbaptucl_object_t *
1779263648Sbaptucl_object_fromlstring (const char *str, size_t len)
1780263648Sbapt{
1781263648Sbapt	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
1782263648Sbapt}
1783263648Sbapt
1784263648Sbaptucl_object_t *
1785263648Sbaptucl_object_fromint (int64_t iv)
1786263648Sbapt{
1787263648Sbapt	ucl_object_t *obj;
1788263648Sbapt
1789263648Sbapt	obj = ucl_object_new ();
1790263648Sbapt	if (obj != NULL) {
1791263648Sbapt		obj->type = UCL_INT;
1792263648Sbapt		obj->value.iv = iv;
1793263648Sbapt	}
1794263648Sbapt
1795263648Sbapt	return obj;
1796263648Sbapt}
1797263648Sbapt
1798263648Sbaptucl_object_t *
1799263648Sbaptucl_object_fromdouble (double dv)
1800263648Sbapt{
1801263648Sbapt	ucl_object_t *obj;
1802263648Sbapt
1803263648Sbapt	obj = ucl_object_new ();
1804263648Sbapt	if (obj != NULL) {
1805263648Sbapt		obj->type = UCL_FLOAT;
1806263648Sbapt		obj->value.dv = dv;
1807263648Sbapt	}
1808263648Sbapt
1809263648Sbapt	return obj;
1810263648Sbapt}
1811263648Sbapt
1812263648Sbaptucl_object_t*
1813263648Sbaptucl_object_frombool (bool bv)
1814263648Sbapt{
1815263648Sbapt	ucl_object_t *obj;
1816263648Sbapt
1817263648Sbapt	obj = ucl_object_new ();
1818263648Sbapt	if (obj != NULL) {
1819263648Sbapt		obj->type = UCL_BOOLEAN;
1820263648Sbapt		obj->value.iv = bv;
1821263648Sbapt	}
1822263648Sbapt
1823263648Sbapt	return obj;
1824263648Sbapt}
1825263648Sbapt
1826264789Sbaptbool
1827263648Sbaptucl_array_append (ucl_object_t *top, ucl_object_t *elt)
1828263648Sbapt{
1829263648Sbapt	ucl_object_t *head;
1830263648Sbapt
1831264789Sbapt	if (elt == NULL || top == NULL) {
1832264789Sbapt		return false;
1833263648Sbapt	}
1834263648Sbapt
1835264789Sbapt	head = top->value.av;
1836264789Sbapt	if (head == NULL) {
1837263648Sbapt		top->value.av = elt;
1838263648Sbapt		elt->prev = elt;
1839263648Sbapt	}
1840263648Sbapt	else {
1841264789Sbapt		elt->prev = head->prev;
1842264789Sbapt		head->prev->next = elt;
1843264789Sbapt		head->prev = elt;
1844263648Sbapt	}
1845264789Sbapt	elt->next = NULL;
1846264789Sbapt	top->len ++;
1847263648Sbapt
1848264789Sbapt	return true;
1849263648Sbapt}
1850263648Sbapt
1851264789Sbaptbool
1852263648Sbaptucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
1853263648Sbapt{
1854263648Sbapt	ucl_object_t *head;
1855263648Sbapt
1856264789Sbapt	if (elt == NULL || top == NULL) {
1857264789Sbapt		return false;
1858263648Sbapt	}
1859263648Sbapt
1860264789Sbapt
1861264789Sbapt	head = top->value.av;
1862264789Sbapt	if (head == NULL) {
1863263648Sbapt		top->value.av = elt;
1864263648Sbapt		elt->prev = elt;
1865263648Sbapt	}
1866263648Sbapt	else {
1867264789Sbapt		elt->prev = head->prev;
1868264789Sbapt		head->prev = elt;
1869263648Sbapt	}
1870264789Sbapt	elt->next = head;
1871264789Sbapt	top->value.av = elt;
1872264789Sbapt	top->len ++;
1873263648Sbapt
1874264789Sbapt	return true;
1875263648Sbapt}
1876263648Sbapt
1877275223Sbaptbool
1878275223Sbaptucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
1879275223Sbapt{
1880275223Sbapt	ucl_object_t *cur, *tmp, *cp;
1881275223Sbapt
1882275223Sbapt	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
1883275223Sbapt		return false;
1884275223Sbapt	}
1885275223Sbapt
1886275223Sbapt	DL_FOREACH_SAFE (elt->value.av, cur, tmp) {
1887275223Sbapt		if (copy) {
1888275223Sbapt			cp = ucl_object_copy (cur);
1889275223Sbapt		}
1890275223Sbapt		else {
1891275223Sbapt			cp = ucl_object_ref (cur);
1892275223Sbapt		}
1893275223Sbapt		if (cp != NULL) {
1894275223Sbapt			ucl_array_append (top, cp);
1895275223Sbapt		}
1896275223Sbapt	}
1897275223Sbapt
1898275223Sbapt	return true;
1899275223Sbapt}
1900275223Sbapt
1901263648Sbaptucl_object_t *
1902263648Sbaptucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
1903263648Sbapt{
1904263648Sbapt	ucl_object_t *head;
1905263648Sbapt
1906263648Sbapt	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1907263648Sbapt		return NULL;
1908263648Sbapt	}
1909263648Sbapt	head = top->value.av;
1910263648Sbapt
1911263648Sbapt	if (elt->prev == elt) {
1912263648Sbapt		top->value.av = NULL;
1913263648Sbapt	}
1914263648Sbapt	else if (elt == head) {
1915263648Sbapt		elt->next->prev = elt->prev;
1916263648Sbapt		top->value.av = elt->next;
1917263648Sbapt	}
1918263648Sbapt	else {
1919263648Sbapt		elt->prev->next = elt->next;
1920263648Sbapt		if (elt->next) {
1921263648Sbapt			elt->next->prev = elt->prev;
1922263648Sbapt		}
1923263648Sbapt		else {
1924263648Sbapt			head->prev = elt->prev;
1925263648Sbapt		}
1926263648Sbapt	}
1927263648Sbapt	elt->next = NULL;
1928263648Sbapt	elt->prev = elt;
1929263648Sbapt	top->len --;
1930263648Sbapt
1931263648Sbapt	return elt;
1932263648Sbapt}
1933263648Sbapt
1934264789Sbaptconst ucl_object_t *
1935264789Sbaptucl_array_head (const ucl_object_t *top)
1936263648Sbapt{
1937263648Sbapt	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1938263648Sbapt		return NULL;
1939263648Sbapt	}
1940263648Sbapt	return top->value.av;
1941263648Sbapt}
1942263648Sbapt
1943264789Sbaptconst ucl_object_t *
1944264789Sbaptucl_array_tail (const ucl_object_t *top)
1945263648Sbapt{
1946263648Sbapt	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1947263648Sbapt		return NULL;
1948263648Sbapt	}
1949263648Sbapt	return top->value.av->prev;
1950263648Sbapt}
1951263648Sbapt
1952263648Sbaptucl_object_t *
1953263648Sbaptucl_array_pop_last (ucl_object_t *top)
1954263648Sbapt{
1955264789Sbapt	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top)));
1956263648Sbapt}
1957263648Sbapt
1958263648Sbaptucl_object_t *
1959263648Sbaptucl_array_pop_first (ucl_object_t *top)
1960263648Sbapt{
1961264789Sbapt	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top)));
1962263648Sbapt}
1963263648Sbapt
1964266636Sbaptconst ucl_object_t *
1965266636Sbaptucl_array_find_index (const ucl_object_t *top, unsigned int index)
1966266636Sbapt{
1967266636Sbapt	ucl_object_iter_t it = NULL;
1968266636Sbapt	const ucl_object_t *ret;
1969266636Sbapt
1970266636Sbapt	if (top == NULL || top->type != UCL_ARRAY || top->len == 0 ||
1971266636Sbapt	    (index + 1) > top->len) {
1972266636Sbapt		return NULL;
1973266636Sbapt	}
1974266636Sbapt
1975266636Sbapt	while ((ret = ucl_iterate_object (top, &it, true)) != NULL) {
1976266636Sbapt		if (index == 0) {
1977266636Sbapt			return ret;
1978266636Sbapt		}
1979266636Sbapt		--index;
1980266636Sbapt	}
1981266636Sbapt
1982266636Sbapt	return NULL;
1983266636Sbapt}
1984266636Sbapt
1985263648Sbaptucl_object_t *
1986275223Sbaptucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
1987275223Sbapt	unsigned int index)
1988275223Sbapt{
1989275223Sbapt	ucl_object_t *cur, *tmp;
1990275223Sbapt
1991275223Sbapt	if (top == NULL || top->type != UCL_ARRAY || elt == NULL ||
1992275223Sbapt			top->len == 0 || (index + 1) > top->len) {
1993275223Sbapt		return NULL;
1994275223Sbapt	}
1995275223Sbapt
1996275223Sbapt	DL_FOREACH_SAFE (top->value.av, cur, tmp) {
1997275223Sbapt		if (index == 0) {
1998275223Sbapt			DL_REPLACE_ELEM (top->value.av, cur, elt);
1999275223Sbapt			return cur;
2000275223Sbapt		}
2001275223Sbapt		--index;
2002275223Sbapt	}
2003275223Sbapt
2004275223Sbapt	return NULL;
2005275223Sbapt}
2006275223Sbapt
2007275223Sbaptucl_object_t *
2008263648Sbaptucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
2009263648Sbapt{
2010263648Sbapt
2011263648Sbapt	if (head == NULL) {
2012263648Sbapt		elt->next = NULL;
2013263648Sbapt		elt->prev = elt;
2014263648Sbapt		head = elt;
2015263648Sbapt	}
2016263648Sbapt	else {
2017263648Sbapt		elt->prev = head->prev;
2018263648Sbapt		head->prev->next = elt;
2019263648Sbapt		head->prev = elt;
2020263648Sbapt		elt->next = NULL;
2021263648Sbapt	}
2022263648Sbapt
2023263648Sbapt	return head;
2024263648Sbapt}
2025263648Sbapt
2026263648Sbaptbool
2027264789Sbaptucl_object_todouble_safe (const ucl_object_t *obj, double *target)
2028263648Sbapt{
2029263648Sbapt	if (obj == NULL || target == NULL) {
2030263648Sbapt		return false;
2031263648Sbapt	}
2032263648Sbapt	switch (obj->type) {
2033263648Sbapt	case UCL_INT:
2034263648Sbapt		*target = obj->value.iv; /* Probaly could cause overflow */
2035263648Sbapt		break;
2036263648Sbapt	case UCL_FLOAT:
2037263648Sbapt	case UCL_TIME:
2038263648Sbapt		*target = obj->value.dv;
2039263648Sbapt		break;
2040263648Sbapt	default:
2041263648Sbapt		return false;
2042263648Sbapt	}
2043263648Sbapt
2044263648Sbapt	return true;
2045263648Sbapt}
2046263648Sbapt
2047263648Sbaptdouble
2048264789Sbaptucl_object_todouble (const ucl_object_t *obj)
2049263648Sbapt{
2050263648Sbapt	double result = 0.;
2051263648Sbapt
2052263648Sbapt	ucl_object_todouble_safe (obj, &result);
2053263648Sbapt	return result;
2054263648Sbapt}
2055263648Sbapt
2056263648Sbaptbool
2057264789Sbaptucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
2058263648Sbapt{
2059263648Sbapt	if (obj == NULL || target == NULL) {
2060263648Sbapt		return false;
2061263648Sbapt	}
2062263648Sbapt	switch (obj->type) {
2063263648Sbapt	case UCL_INT:
2064263648Sbapt		*target = obj->value.iv;
2065263648Sbapt		break;
2066263648Sbapt	case UCL_FLOAT:
2067263648Sbapt	case UCL_TIME:
2068263648Sbapt		*target = obj->value.dv; /* Loosing of decimal points */
2069263648Sbapt		break;
2070263648Sbapt	default:
2071263648Sbapt		return false;
2072263648Sbapt	}
2073263648Sbapt
2074263648Sbapt	return true;
2075263648Sbapt}
2076263648Sbapt
2077263648Sbaptint64_t
2078264789Sbaptucl_object_toint (const ucl_object_t *obj)
2079263648Sbapt{
2080263648Sbapt	int64_t result = 0;
2081263648Sbapt
2082263648Sbapt	ucl_object_toint_safe (obj, &result);
2083263648Sbapt	return result;
2084263648Sbapt}
2085263648Sbapt
2086263648Sbaptbool
2087264789Sbaptucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
2088263648Sbapt{
2089263648Sbapt	if (obj == NULL || target == NULL) {
2090263648Sbapt		return false;
2091263648Sbapt	}
2092263648Sbapt	switch (obj->type) {
2093263648Sbapt	case UCL_BOOLEAN:
2094263648Sbapt		*target = (obj->value.iv == true);
2095263648Sbapt		break;
2096263648Sbapt	default:
2097263648Sbapt		return false;
2098263648Sbapt	}
2099263648Sbapt
2100263648Sbapt	return true;
2101263648Sbapt}
2102263648Sbapt
2103263648Sbaptbool
2104264789Sbaptucl_object_toboolean (const ucl_object_t *obj)
2105263648Sbapt{
2106263648Sbapt	bool result = false;
2107263648Sbapt
2108263648Sbapt	ucl_object_toboolean_safe (obj, &result);
2109263648Sbapt	return result;
2110263648Sbapt}
2111263648Sbapt
2112263648Sbaptbool
2113264789Sbaptucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
2114263648Sbapt{
2115263648Sbapt	if (obj == NULL || target == NULL) {
2116263648Sbapt		return false;
2117263648Sbapt	}
2118263648Sbapt
2119263648Sbapt	switch (obj->type) {
2120263648Sbapt	case UCL_STRING:
2121263648Sbapt		*target = ucl_copy_value_trash (obj);
2122263648Sbapt		break;
2123263648Sbapt	default:
2124263648Sbapt		return false;
2125263648Sbapt	}
2126263648Sbapt
2127263648Sbapt	return true;
2128263648Sbapt}
2129263648Sbapt
2130263648Sbaptconst char *
2131264789Sbaptucl_object_tostring (const ucl_object_t *obj)
2132263648Sbapt{
2133263648Sbapt	const char *result = NULL;
2134263648Sbapt
2135263648Sbapt	ucl_object_tostring_safe (obj, &result);
2136263648Sbapt	return result;
2137263648Sbapt}
2138263648Sbapt
2139263648Sbaptconst char *
2140264789Sbaptucl_object_tostring_forced (const ucl_object_t *obj)
2141263648Sbapt{
2142263648Sbapt	return ucl_copy_value_trash (obj);
2143263648Sbapt}
2144263648Sbapt
2145263648Sbaptbool
2146264789Sbaptucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
2147263648Sbapt{
2148263648Sbapt	if (obj == NULL || target == NULL) {
2149263648Sbapt		return false;
2150263648Sbapt	}
2151263648Sbapt	switch (obj->type) {
2152263648Sbapt	case UCL_STRING:
2153263648Sbapt		*target = obj->value.sv;
2154263648Sbapt		if (tlen != NULL) {
2155263648Sbapt			*tlen = obj->len;
2156263648Sbapt		}
2157263648Sbapt		break;
2158263648Sbapt	default:
2159263648Sbapt		return false;
2160263648Sbapt	}
2161263648Sbapt
2162263648Sbapt	return true;
2163263648Sbapt}
2164263648Sbapt
2165263648Sbaptconst char *
2166264789Sbaptucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
2167263648Sbapt{
2168263648Sbapt	const char *result = NULL;
2169263648Sbapt
2170263648Sbapt	ucl_object_tolstring_safe (obj, &result, tlen);
2171263648Sbapt	return result;
2172263648Sbapt}
2173263648Sbapt
2174263648Sbaptconst char *
2175264789Sbaptucl_object_key (const ucl_object_t *obj)
2176263648Sbapt{
2177263648Sbapt	return ucl_copy_key_trash (obj);
2178263648Sbapt}
2179263648Sbapt
2180263648Sbaptconst char *
2181264789Sbaptucl_object_keyl (const ucl_object_t *obj, size_t *len)
2182263648Sbapt{
2183263648Sbapt	if (len == NULL || obj == NULL) {
2184263648Sbapt		return NULL;
2185263648Sbapt	}
2186263648Sbapt	*len = obj->keylen;
2187263648Sbapt	return obj->key;
2188263648Sbapt}
2189263648Sbapt
2190263648Sbaptucl_object_t *
2191264789Sbaptucl_object_ref (const ucl_object_t *obj)
2192263648Sbapt{
2193264789Sbapt	ucl_object_t *res = NULL;
2194264789Sbapt
2195263648Sbapt	if (obj != NULL) {
2196275223Sbapt		if (obj->flags & UCL_OBJECT_EPHEMERAL) {
2197275223Sbapt			/*
2198275223Sbapt			 * Use deep copy for ephemeral objects, note that its refcount
2199275223Sbapt			 * is NOT increased, since ephemeral objects does not need refcount
2200275223Sbapt			 * at all
2201275223Sbapt			 */
2202275223Sbapt			res = ucl_object_copy (obj);
2203275223Sbapt		}
2204275223Sbapt		else {
2205275223Sbapt			res = __DECONST (ucl_object_t *, obj);
2206264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS
2207275223Sbapt			(void)__sync_add_and_fetch (&res->ref, 1);
2208264789Sbapt#else
2209275223Sbapt			res->ref ++;
2210264789Sbapt#endif
2211275223Sbapt		}
2212263648Sbapt	}
2213264789Sbapt	return res;
2214263648Sbapt}
2215263648Sbapt
2216275223Sbaptstatic ucl_object_t *
2217275223Sbaptucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
2218275223Sbapt{
2219275223Sbapt
2220275223Sbapt	ucl_object_t *new;
2221275223Sbapt	ucl_object_iter_t it = NULL;
2222275223Sbapt	const ucl_object_t *cur;
2223275223Sbapt
2224275223Sbapt	new = malloc (sizeof (*new));
2225275223Sbapt
2226275223Sbapt	if (new != NULL) {
2227275223Sbapt		memcpy (new, other, sizeof (*new));
2228275223Sbapt		if (other->flags & UCL_OBJECT_EPHEMERAL) {
2229275223Sbapt			/* Copied object is always non ephemeral */
2230275223Sbapt			new->flags &= ~UCL_OBJECT_EPHEMERAL;
2231275223Sbapt		}
2232275223Sbapt		new->ref = 1;
2233275223Sbapt		/* Unlink from others */
2234275223Sbapt		new->next = NULL;
2235275223Sbapt		new->prev = new;
2236275223Sbapt
2237275223Sbapt		/* deep copy of values stored */
2238275223Sbapt		if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
2239275223Sbapt			new->trash_stack[UCL_TRASH_KEY] =
2240275223Sbapt					strdup (other->trash_stack[UCL_TRASH_KEY]);
2241275223Sbapt			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
2242275223Sbapt				new->key = new->trash_stack[UCL_TRASH_KEY];
2243275223Sbapt			}
2244275223Sbapt		}
2245275223Sbapt		if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
2246275223Sbapt			new->trash_stack[UCL_TRASH_VALUE] =
2247275223Sbapt					strdup (other->trash_stack[UCL_TRASH_VALUE]);
2248275223Sbapt			if (new->type == UCL_STRING) {
2249275223Sbapt				new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
2250275223Sbapt			}
2251275223Sbapt		}
2252275223Sbapt
2253275223Sbapt		if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
2254275223Sbapt			/* reset old value */
2255275223Sbapt			memset (&new->value, 0, sizeof (new->value));
2256275223Sbapt
2257275223Sbapt			while ((cur = ucl_iterate_object (other, &it, true)) != NULL) {
2258275223Sbapt				if (other->type == UCL_ARRAY) {
2259275223Sbapt					ucl_array_append (new, ucl_object_copy_internal (cur, false));
2260275223Sbapt				}
2261275223Sbapt				else {
2262275223Sbapt					ucl_object_t *cp = ucl_object_copy_internal (cur, true);
2263275223Sbapt					if (cp != NULL) {
2264275223Sbapt						ucl_object_insert_key (new, cp, cp->key, cp->keylen,
2265275223Sbapt								false);
2266275223Sbapt					}
2267275223Sbapt				}
2268275223Sbapt			}
2269275223Sbapt		}
2270275223Sbapt		else if (allow_array && other->next != NULL) {
2271275223Sbapt			LL_FOREACH (other->next, cur) {
2272275223Sbapt				ucl_object_t *cp = ucl_object_copy_internal (cur, false);
2273275223Sbapt				if (cp != NULL) {
2274275223Sbapt					DL_APPEND (new, cp);
2275275223Sbapt				}
2276275223Sbapt			}
2277275223Sbapt		}
2278275223Sbapt	}
2279275223Sbapt
2280275223Sbapt	return new;
2281275223Sbapt}
2282275223Sbapt
2283275223Sbaptucl_object_t *
2284275223Sbaptucl_object_copy (const ucl_object_t *other)
2285275223Sbapt{
2286275223Sbapt	return ucl_object_copy_internal (other, true);
2287275223Sbapt}
2288275223Sbapt
2289263648Sbaptvoid
2290263648Sbaptucl_object_unref (ucl_object_t *obj)
2291263648Sbapt{
2292264789Sbapt	if (obj != NULL) {
2293264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS
2294264789Sbapt		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
2295264789Sbapt		if (rc == 0) {
2296264789Sbapt#else
2297264789Sbapt		if (--obj->ref == 0) {
2298264789Sbapt#endif
2299264789Sbapt			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
2300264789Sbapt		}
2301263648Sbapt	}
2302263648Sbapt}
2303263648Sbapt
2304263648Sbaptint
2305264789Sbaptucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
2306263648Sbapt{
2307264789Sbapt	const ucl_object_t *it1, *it2;
2308263648Sbapt	ucl_object_iter_t iter = NULL;
2309263648Sbapt	int ret = 0;
2310263648Sbapt
2311263648Sbapt	if (o1->type != o2->type) {
2312263648Sbapt		return (o1->type) - (o2->type);
2313263648Sbapt	}
2314263648Sbapt
2315263648Sbapt	switch (o1->type) {
2316263648Sbapt	case UCL_STRING:
2317263648Sbapt		if (o1->len == o2->len) {
2318263648Sbapt			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
2319263648Sbapt		}
2320263648Sbapt		else {
2321263648Sbapt			ret = o1->len - o2->len;
2322263648Sbapt		}
2323263648Sbapt		break;
2324263648Sbapt	case UCL_FLOAT:
2325263648Sbapt	case UCL_INT:
2326263648Sbapt	case UCL_TIME:
2327263648Sbapt		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
2328263648Sbapt		break;
2329263648Sbapt	case UCL_BOOLEAN:
2330263648Sbapt		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
2331263648Sbapt		break;
2332263648Sbapt	case UCL_ARRAY:
2333263648Sbapt		if (o1->len == o2->len) {
2334263648Sbapt			it1 = o1->value.av;
2335263648Sbapt			it2 = o2->value.av;
2336263648Sbapt			/* Compare all elements in both arrays */
2337263648Sbapt			while (it1 != NULL && it2 != NULL) {
2338263648Sbapt				ret = ucl_object_compare (it1, it2);
2339263648Sbapt				if (ret != 0) {
2340263648Sbapt					break;
2341263648Sbapt				}
2342263648Sbapt				it1 = it1->next;
2343263648Sbapt				it2 = it2->next;
2344263648Sbapt			}
2345263648Sbapt		}
2346263648Sbapt		else {
2347263648Sbapt			ret = o1->len - o2->len;
2348263648Sbapt		}
2349263648Sbapt		break;
2350263648Sbapt	case UCL_OBJECT:
2351263648Sbapt		if (o1->len == o2->len) {
2352263648Sbapt			while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) {
2353263648Sbapt				it2 = ucl_object_find_key (o2, ucl_object_key (it1));
2354263648Sbapt				if (it2 == NULL) {
2355263648Sbapt					ret = 1;
2356263648Sbapt					break;
2357263648Sbapt				}
2358263648Sbapt				ret = ucl_object_compare (it1, it2);
2359263648Sbapt				if (ret != 0) {
2360263648Sbapt					break;
2361263648Sbapt				}
2362263648Sbapt			}
2363263648Sbapt		}
2364263648Sbapt		else {
2365263648Sbapt			ret = o1->len - o2->len;
2366263648Sbapt		}
2367263648Sbapt		break;
2368263648Sbapt	default:
2369263648Sbapt		ret = 0;
2370263648Sbapt		break;
2371263648Sbapt	}
2372263648Sbapt
2373263648Sbapt	return ret;
2374263648Sbapt}
2375263648Sbapt
2376263648Sbaptvoid
2377263648Sbaptucl_object_array_sort (ucl_object_t *ar,
2378264789Sbapt		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2))
2379263648Sbapt{
2380263648Sbapt	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
2381263648Sbapt		return;
2382263648Sbapt	}
2383263648Sbapt
2384263648Sbapt	DL_SORT (ar->value.av, cmp);
2385263648Sbapt}
2386275223Sbapt
2387275223Sbapt#define PRIOBITS 4
2388275223Sbapt
2389275223Sbaptunsigned int
2390275223Sbaptucl_object_get_priority (const ucl_object_t *obj)
2391275223Sbapt{
2392275223Sbapt	if (obj == NULL) {
2393275223Sbapt		return 0;
2394275223Sbapt	}
2395275223Sbapt
2396275223Sbapt	return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
2397275223Sbapt}
2398275223Sbapt
2399275223Sbaptvoid
2400275223Sbaptucl_object_set_priority (ucl_object_t *obj,
2401275223Sbapt		unsigned int priority)
2402275223Sbapt{
2403275223Sbapt	if (obj != NULL) {
2404275223Sbapt		priority &= (0x1 << PRIOBITS) - 1;
2405275223Sbapt		obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS);
2406275223Sbapt	}
2407275223Sbapt}
2408