xref: /freebsd/contrib/libucl/src/ucl_util.c (revision a0409676)
1c99fb5f9SBaptiste Daroussin /* Copyright (c) 2013, Vsevolod Stakhov
239ee7a7aSBaptiste Daroussin  * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org>
3c99fb5f9SBaptiste Daroussin  * All rights reserved.
4c99fb5f9SBaptiste Daroussin  *
5c99fb5f9SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
6c99fb5f9SBaptiste Daroussin  * modification, are permitted provided that the following conditions are met:
7c99fb5f9SBaptiste Daroussin  *       * Redistributions of source code must retain the above copyright
8c99fb5f9SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer.
9c99fb5f9SBaptiste Daroussin  *       * Redistributions in binary form must reproduce the above copyright
10c99fb5f9SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer in the
11c99fb5f9SBaptiste Daroussin  *         documentation and/or other materials provided with the distribution.
12c99fb5f9SBaptiste Daroussin  *
13c99fb5f9SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
14c99fb5f9SBaptiste Daroussin  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15c99fb5f9SBaptiste Daroussin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16c99fb5f9SBaptiste Daroussin  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17c99fb5f9SBaptiste Daroussin  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18c99fb5f9SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19c99fb5f9SBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20c99fb5f9SBaptiste Daroussin  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21c99fb5f9SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22c99fb5f9SBaptiste Daroussin  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23c99fb5f9SBaptiste Daroussin  */
24c99fb5f9SBaptiste Daroussin 
25c99fb5f9SBaptiste Daroussin #include "ucl.h"
26c99fb5f9SBaptiste Daroussin #include "ucl_internal.h"
27c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h"
288e3b1ab2SBaptiste Daroussin #include "kvec.h"
2911dd9ed6SBaptiste Daroussin #include <limits.h>
3039ee7a7aSBaptiste Daroussin #include <stdarg.h>
31d9f0ce31SBaptiste Daroussin #include <stdio.h> /* for snprintf */
32c99fb5f9SBaptiste Daroussin 
338e3b1ab2SBaptiste Daroussin #ifndef _WIN32
344bf54857SBaptiste Daroussin #include <glob.h>
3511dd9ed6SBaptiste Daroussin #include <sys/param.h>
3611dd9ed6SBaptiste Daroussin #else
3711dd9ed6SBaptiste Daroussin #ifndef NBBY
3811dd9ed6SBaptiste Daroussin #define NBBY 8
3911dd9ed6SBaptiste Daroussin #endif
408e3b1ab2SBaptiste Daroussin #endif
414bf54857SBaptiste Daroussin 
4297bd480fSBaptiste Daroussin #ifdef HAVE_LIBGEN_H
43*a0409676SBaptiste Daroussin #ifndef _WIN32
44c99fb5f9SBaptiste Daroussin #  include <libgen.h> /* For dirname */
4597bd480fSBaptiste Daroussin #endif
46*a0409676SBaptiste Daroussin #endif
47c99fb5f9SBaptiste Daroussin 
488e3b1ab2SBaptiste Daroussin typedef kvec_t(ucl_object_t *) ucl_array_t;
498e3b1ab2SBaptiste Daroussin 
508e3b1ab2SBaptiste Daroussin #define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \
518e3b1ab2SBaptiste Daroussin 	(ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL)
528e3b1ab2SBaptiste Daroussin 
53c99fb5f9SBaptiste Daroussin #ifdef HAVE_OPENSSL
54c99fb5f9SBaptiste Daroussin #include <openssl/err.h>
55c99fb5f9SBaptiste Daroussin #include <openssl/sha.h>
56c99fb5f9SBaptiste Daroussin #include <openssl/rsa.h>
57c99fb5f9SBaptiste Daroussin #include <openssl/ssl.h>
58c99fb5f9SBaptiste Daroussin #include <openssl/evp.h>
59c99fb5f9SBaptiste Daroussin #endif
60c99fb5f9SBaptiste Daroussin 
6197bd480fSBaptiste Daroussin #ifdef CURL_FOUND
62d9f0ce31SBaptiste Daroussin /* Seems to be broken */
63d9f0ce31SBaptiste Daroussin #define CURL_DISABLE_TYPECHECK 1
6497bd480fSBaptiste Daroussin #include <curl/curl.h>
6597bd480fSBaptiste Daroussin #endif
6697bd480fSBaptiste Daroussin #ifdef HAVE_FETCH_H
6797bd480fSBaptiste Daroussin #include <fetch.h>
6897bd480fSBaptiste Daroussin #endif
6997bd480fSBaptiste Daroussin 
70*a0409676SBaptiste Daroussin #if defined(_MSC_VER)
7136c53d67SBaptiste Daroussin #include <windows.h>
72*a0409676SBaptiste Daroussin #include <io.h>
73*a0409676SBaptiste Daroussin #include <direct.h>
7436c53d67SBaptiste Daroussin 
7597bd480fSBaptiste Daroussin #ifndef PROT_READ
7636c53d67SBaptiste Daroussin #define PROT_READ       1
7797bd480fSBaptiste Daroussin #endif
7897bd480fSBaptiste Daroussin #ifndef PROT_WRITE
7936c53d67SBaptiste Daroussin #define PROT_WRITE      2
8097bd480fSBaptiste Daroussin #endif
8197bd480fSBaptiste Daroussin #ifndef PROT_READWRITE
8236c53d67SBaptiste Daroussin #define PROT_READWRITE  3
8397bd480fSBaptiste Daroussin #endif
8497bd480fSBaptiste Daroussin #ifndef MAP_SHARED
8536c53d67SBaptiste Daroussin #define MAP_SHARED      1
8697bd480fSBaptiste Daroussin #endif
8797bd480fSBaptiste Daroussin #ifndef MAP_PRIVATE
8836c53d67SBaptiste Daroussin #define MAP_PRIVATE     2
8997bd480fSBaptiste Daroussin #endif
9097bd480fSBaptiste Daroussin #ifndef MAP_FAILED
9136c53d67SBaptiste Daroussin #define MAP_FAILED      ((void *) -1)
9297bd480fSBaptiste Daroussin #endif
9336c53d67SBaptiste Daroussin 
94*a0409676SBaptiste Daroussin #define getcwd _getcwd
95*a0409676SBaptiste Daroussin #define open _open
96*a0409676SBaptiste Daroussin #define close _close
97*a0409676SBaptiste Daroussin 
ucl_mmap(char * addr,size_t length,int prot,int access,int fd,off_t offset)9897bd480fSBaptiste Daroussin static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
9936c53d67SBaptiste Daroussin {
10036c53d67SBaptiste Daroussin 	void *map = NULL;
10136c53d67SBaptiste Daroussin 	HANDLE handle = INVALID_HANDLE_VALUE;
10236c53d67SBaptiste Daroussin 
10336c53d67SBaptiste Daroussin 	switch (prot) {
10436c53d67SBaptiste Daroussin 	default:
10536c53d67SBaptiste Daroussin 	case PROT_READ:
10636c53d67SBaptiste Daroussin 		{
10736c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
10836c53d67SBaptiste Daroussin 			if (!handle) break;
10936c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
11036c53d67SBaptiste Daroussin 			CloseHandle(handle);
11136c53d67SBaptiste Daroussin 			break;
11236c53d67SBaptiste Daroussin 		}
11336c53d67SBaptiste Daroussin 	case PROT_WRITE:
11436c53d67SBaptiste Daroussin 		{
11536c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
11636c53d67SBaptiste Daroussin 			if (!handle) break;
11736c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
11836c53d67SBaptiste Daroussin 			CloseHandle(handle);
11936c53d67SBaptiste Daroussin 			break;
12036c53d67SBaptiste Daroussin 		}
12136c53d67SBaptiste Daroussin 	case PROT_READWRITE:
12236c53d67SBaptiste Daroussin 		{
12336c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
12436c53d67SBaptiste Daroussin 			if (!handle) break;
12536c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
12636c53d67SBaptiste Daroussin 			CloseHandle(handle);
12736c53d67SBaptiste Daroussin 			break;
12836c53d67SBaptiste Daroussin 		}
12936c53d67SBaptiste Daroussin 	}
13036c53d67SBaptiste Daroussin 	if (map == (void *) NULL) {
13136c53d67SBaptiste Daroussin 		return (void *) MAP_FAILED;
13236c53d67SBaptiste Daroussin 	}
13336c53d67SBaptiste Daroussin 	return (void *) ((char *) map + offset);
13436c53d67SBaptiste Daroussin }
13536c53d67SBaptiste Daroussin 
ucl_munmap(void * map,size_t length)13697bd480fSBaptiste Daroussin static int ucl_munmap(void *map,size_t length)
13736c53d67SBaptiste Daroussin {
13836c53d67SBaptiste Daroussin 	if (!UnmapViewOfFile(map)) {
13936c53d67SBaptiste Daroussin 		return(-1);
14036c53d67SBaptiste Daroussin 	}
14136c53d67SBaptiste Daroussin 	return(0);
14236c53d67SBaptiste Daroussin }
14336c53d67SBaptiste Daroussin 
ucl_realpath(const char * path,char * resolved_path)144*a0409676SBaptiste Daroussin static char* ucl_realpath(const char *path, char *resolved_path)
145*a0409676SBaptiste Daroussin {
14636c53d67SBaptiste Daroussin 	char *p;
14736c53d67SBaptiste Daroussin 	char tmp[MAX_PATH + 1];
14836c53d67SBaptiste Daroussin 	strncpy(tmp, path, sizeof(tmp)-1);
14936c53d67SBaptiste Daroussin 	p = tmp;
15036c53d67SBaptiste Daroussin 	while(*p) {
15136c53d67SBaptiste Daroussin 		if (*p == '/') *p = '\\';
15236c53d67SBaptiste Daroussin 		p++;
15336c53d67SBaptiste Daroussin 	}
15436c53d67SBaptiste Daroussin 	return _fullpath(resolved_path, tmp, MAX_PATH);
15536c53d67SBaptiste Daroussin }
156*a0409676SBaptiste Daroussin 
157*a0409676SBaptiste Daroussin 
dirname(char * path)158*a0409676SBaptiste Daroussin char *dirname(char *path)
159*a0409676SBaptiste Daroussin {
160*a0409676SBaptiste Daroussin 	static char path_buffer[_MAX_PATH];
161*a0409676SBaptiste Daroussin 	char drive[_MAX_DRIVE];
162*a0409676SBaptiste Daroussin 	char dir[_MAX_DIR];
163*a0409676SBaptiste Daroussin 	char fname[_MAX_FNAME];
164*a0409676SBaptiste Daroussin 	char ext[_MAX_EXT];
165*a0409676SBaptiste Daroussin 
166*a0409676SBaptiste Daroussin 	_splitpath (path, drive, dir, fname, ext);
167*a0409676SBaptiste Daroussin 	_makepath(path_buffer, drive, dir, NULL, NULL);
168*a0409676SBaptiste Daroussin 
169*a0409676SBaptiste Daroussin 	return path_buffer;
170*a0409676SBaptiste Daroussin }
171*a0409676SBaptiste Daroussin 
basename(char * path)172*a0409676SBaptiste Daroussin char *basename(char *path)
173*a0409676SBaptiste Daroussin {
174*a0409676SBaptiste Daroussin 	static char path_buffer[_MAX_PATH];
175*a0409676SBaptiste Daroussin 	char drive[_MAX_DRIVE];
176*a0409676SBaptiste Daroussin 	char dir[_MAX_DIR];
177*a0409676SBaptiste Daroussin 	char fname[_MAX_FNAME];
178*a0409676SBaptiste Daroussin 	char ext[_MAX_EXT];
179*a0409676SBaptiste Daroussin 
180*a0409676SBaptiste Daroussin 	_splitpath(path, drive, dir, fname, ext);
181*a0409676SBaptiste Daroussin 	_makepath(path_buffer, NULL, NULL, fname, ext);
182*a0409676SBaptiste Daroussin 
183*a0409676SBaptiste Daroussin 	return path_buffer;
184*a0409676SBaptiste Daroussin }
18597bd480fSBaptiste Daroussin #else
18697bd480fSBaptiste Daroussin #define ucl_mmap mmap
18797bd480fSBaptiste Daroussin #define ucl_munmap munmap
18897bd480fSBaptiste Daroussin #define ucl_realpath realpath
18936c53d67SBaptiste Daroussin #endif
19036c53d67SBaptiste Daroussin 
191b04a7a0bSBaptiste Daroussin typedef void (*ucl_object_dtor) (ucl_object_t *obj);
192b04a7a0bSBaptiste Daroussin static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
193b04a7a0bSBaptiste Daroussin 		ucl_object_dtor dtor);
194b04a7a0bSBaptiste Daroussin static void ucl_object_dtor_unref (ucl_object_t *obj);
195c99fb5f9SBaptiste Daroussin 
196c99fb5f9SBaptiste Daroussin static void
ucl_object_dtor_free(ucl_object_t * obj)197b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (ucl_object_t *obj)
198c99fb5f9SBaptiste Daroussin {
199c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
200c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
201c99fb5f9SBaptiste Daroussin 	}
202c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
203c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
204c99fb5f9SBaptiste Daroussin 	}
2054bf54857SBaptiste Daroussin 	/* Do not free ephemeral objects */
2064bf54857SBaptiste Daroussin 	if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
2074bf54857SBaptiste Daroussin 		if (obj->type != UCL_USERDATA) {
208b04a7a0bSBaptiste Daroussin 			UCL_FREE (sizeof (ucl_object_t), obj);
209b04a7a0bSBaptiste Daroussin 		}
2104bf54857SBaptiste Daroussin 		else {
2114bf54857SBaptiste Daroussin 			struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
2124bf54857SBaptiste Daroussin 			if (ud->dtor) {
2134bf54857SBaptiste Daroussin 				ud->dtor (obj->value.ud);
2144bf54857SBaptiste Daroussin 			}
2154bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (*ud), obj);
2164bf54857SBaptiste Daroussin 		}
2174bf54857SBaptiste Daroussin 	}
2184bf54857SBaptiste Daroussin }
219c99fb5f9SBaptiste Daroussin 
220b04a7a0bSBaptiste Daroussin /*
221b04a7a0bSBaptiste Daroussin  * This is a helper function that performs exactly the same as
222b04a7a0bSBaptiste Daroussin  * `ucl_object_unref` but it doesn't iterate over elements allowing
223b04a7a0bSBaptiste Daroussin  * to use it for individual elements of arrays and multiple values
224b04a7a0bSBaptiste Daroussin  */
225b04a7a0bSBaptiste Daroussin static void
ucl_object_dtor_unref_single(ucl_object_t * obj)226b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (ucl_object_t *obj)
227b04a7a0bSBaptiste Daroussin {
228b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
229b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
230b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
231b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
232b04a7a0bSBaptiste Daroussin #else
233b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
234b04a7a0bSBaptiste Daroussin #endif
235b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, false, ucl_object_dtor_unref);
236b04a7a0bSBaptiste Daroussin 		}
237b04a7a0bSBaptiste Daroussin 	}
238b04a7a0bSBaptiste Daroussin }
239b04a7a0bSBaptiste Daroussin 
240b04a7a0bSBaptiste Daroussin static void
241b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref (ucl_object_t *obj)
242b04a7a0bSBaptiste Daroussin {
243b04a7a0bSBaptiste Daroussin 	if (obj->ref == 0) {
244b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_free (obj);
245b04a7a0bSBaptiste Daroussin 	}
246b04a7a0bSBaptiste Daroussin 	else {
247b04a7a0bSBaptiste Daroussin 		/* This may cause dtor unref being called one more time */
248b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_unref_single (obj);
249b04a7a0bSBaptiste Daroussin 	}
250b04a7a0bSBaptiste Daroussin }
251b04a7a0bSBaptiste Daroussin 
252b04a7a0bSBaptiste Daroussin static void
253b04a7a0bSBaptiste Daroussin ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
254b04a7a0bSBaptiste Daroussin {
2558e3b1ab2SBaptiste Daroussin 	ucl_object_t *tmp, *sub;
256b04a7a0bSBaptiste Daroussin 
257b04a7a0bSBaptiste Daroussin 	while (obj != NULL) {
258c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_ARRAY) {
2598e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
2608e3b1ab2SBaptiste Daroussin 			unsigned int i;
2618e3b1ab2SBaptiste Daroussin 
2628e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
2638e3b1ab2SBaptiste Daroussin 				for (i = 0; i < vec->n; i ++) {
2648e3b1ab2SBaptiste Daroussin 					sub = kv_A (*vec, i);
2658e3b1ab2SBaptiste Daroussin 					if (sub != NULL) {
2668e3b1ab2SBaptiste Daroussin 						tmp = sub;
2678e3b1ab2SBaptiste Daroussin 						while (sub) {
268c99fb5f9SBaptiste Daroussin 							tmp = sub->next;
269b04a7a0bSBaptiste Daroussin 							dtor (sub);
270c99fb5f9SBaptiste Daroussin 							sub = tmp;
271c99fb5f9SBaptiste Daroussin 						}
272c99fb5f9SBaptiste Daroussin 					}
2738e3b1ab2SBaptiste Daroussin 				}
2748e3b1ab2SBaptiste Daroussin 				kv_destroy (*vec);
2758e3b1ab2SBaptiste Daroussin 				UCL_FREE (sizeof (*vec), vec);
2768e3b1ab2SBaptiste Daroussin 			}
27739ee7a7aSBaptiste Daroussin 			obj->value.av = NULL;
2788e3b1ab2SBaptiste Daroussin 		}
279c99fb5f9SBaptiste Daroussin 		else if (obj->type == UCL_OBJECT) {
280c99fb5f9SBaptiste Daroussin 			if (obj->value.ov != NULL) {
281d9f0ce31SBaptiste Daroussin 				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor);
282c99fb5f9SBaptiste Daroussin 			}
28339ee7a7aSBaptiste Daroussin 			obj->value.ov = NULL;
284c99fb5f9SBaptiste Daroussin 		}
285c99fb5f9SBaptiste Daroussin 		tmp = obj->next;
286b04a7a0bSBaptiste Daroussin 		dtor (obj);
287c99fb5f9SBaptiste Daroussin 		obj = tmp;
288c99fb5f9SBaptiste Daroussin 
289c99fb5f9SBaptiste Daroussin 		if (!allow_rec) {
290c99fb5f9SBaptiste Daroussin 			break;
291c99fb5f9SBaptiste Daroussin 		}
292c99fb5f9SBaptiste Daroussin 	}
293c99fb5f9SBaptiste Daroussin }
294c99fb5f9SBaptiste Daroussin 
295c99fb5f9SBaptiste Daroussin void
296c99fb5f9SBaptiste Daroussin ucl_object_free (ucl_object_t *obj)
297c99fb5f9SBaptiste Daroussin {
298b04a7a0bSBaptiste Daroussin 	ucl_object_free_internal (obj, true, ucl_object_dtor_free);
299c99fb5f9SBaptiste Daroussin }
300c99fb5f9SBaptiste Daroussin 
301c99fb5f9SBaptiste Daroussin size_t
302c99fb5f9SBaptiste Daroussin ucl_unescape_json_string (char *str, size_t len)
303c99fb5f9SBaptiste Daroussin {
304c99fb5f9SBaptiste Daroussin 	char *t = str, *h = str;
305c99fb5f9SBaptiste Daroussin 	int i, uval;
306c99fb5f9SBaptiste Daroussin 
30797bd480fSBaptiste Daroussin 	if (len <= 1) {
30897bd480fSBaptiste Daroussin 		return len;
30997bd480fSBaptiste Daroussin 	}
310c99fb5f9SBaptiste Daroussin 	/* t is target (tortoise), h is source (hare) */
311c99fb5f9SBaptiste Daroussin 
312c99fb5f9SBaptiste Daroussin 	while (len) {
313c99fb5f9SBaptiste Daroussin 		if (*h == '\\') {
314c99fb5f9SBaptiste Daroussin 			h ++;
31539ee7a7aSBaptiste Daroussin 
31639ee7a7aSBaptiste Daroussin 			if (len == 1) {
31739ee7a7aSBaptiste Daroussin 				/*
31839ee7a7aSBaptiste Daroussin 				 * If \ is last, then do not try to go further
31939ee7a7aSBaptiste Daroussin 				 * Issue: #74
32039ee7a7aSBaptiste Daroussin 				 */
32139ee7a7aSBaptiste Daroussin 				len --;
32239ee7a7aSBaptiste Daroussin 				*t++ = '\\';
32339ee7a7aSBaptiste Daroussin 				continue;
32439ee7a7aSBaptiste Daroussin 			}
32539ee7a7aSBaptiste Daroussin 
326c99fb5f9SBaptiste Daroussin 			switch (*h) {
327c99fb5f9SBaptiste Daroussin 			case 'n':
328c99fb5f9SBaptiste Daroussin 				*t++ = '\n';
329c99fb5f9SBaptiste Daroussin 				break;
330c99fb5f9SBaptiste Daroussin 			case 'r':
331c99fb5f9SBaptiste Daroussin 				*t++ = '\r';
332c99fb5f9SBaptiste Daroussin 				break;
333c99fb5f9SBaptiste Daroussin 			case 'b':
334c99fb5f9SBaptiste Daroussin 				*t++ = '\b';
335c99fb5f9SBaptiste Daroussin 				break;
336c99fb5f9SBaptiste Daroussin 			case 't':
337c99fb5f9SBaptiste Daroussin 				*t++ = '\t';
338c99fb5f9SBaptiste Daroussin 				break;
339c99fb5f9SBaptiste Daroussin 			case 'f':
340c99fb5f9SBaptiste Daroussin 				*t++ = '\f';
341c99fb5f9SBaptiste Daroussin 				break;
342c99fb5f9SBaptiste Daroussin 			case '\\':
343c99fb5f9SBaptiste Daroussin 				*t++ = '\\';
344c99fb5f9SBaptiste Daroussin 				break;
345c99fb5f9SBaptiste Daroussin 			case '"':
346c99fb5f9SBaptiste Daroussin 				*t++ = '"';
347c99fb5f9SBaptiste Daroussin 				break;
348c99fb5f9SBaptiste Daroussin 			case 'u':
349c99fb5f9SBaptiste Daroussin 				/* Unicode escape */
350c99fb5f9SBaptiste Daroussin 				uval = 0;
351d9f0ce31SBaptiste Daroussin 				h ++; /* u character */
352d9f0ce31SBaptiste Daroussin 				len --;
353d9f0ce31SBaptiste Daroussin 
35497bd480fSBaptiste Daroussin 				if (len > 3) {
355c99fb5f9SBaptiste Daroussin 					for (i = 0; i < 4; i++) {
356c99fb5f9SBaptiste Daroussin 						uval <<= 4;
357c99fb5f9SBaptiste Daroussin 						if (isdigit (h[i])) {
358c99fb5f9SBaptiste Daroussin 							uval += h[i] - '0';
359c99fb5f9SBaptiste Daroussin 						}
360c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'a' && h[i] <= 'f') {
361c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'a' + 10;
362c99fb5f9SBaptiste Daroussin 						}
363c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'A' && h[i] <= 'F') {
364c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'A' + 10;
365c99fb5f9SBaptiste Daroussin 						}
36697bd480fSBaptiste Daroussin 						else {
36797bd480fSBaptiste Daroussin 							break;
36897bd480fSBaptiste Daroussin 						}
369c99fb5f9SBaptiste Daroussin 					}
370d9f0ce31SBaptiste Daroussin 
371c99fb5f9SBaptiste Daroussin 					/* Encode */
372c99fb5f9SBaptiste Daroussin 					if(uval < 0x80) {
373c99fb5f9SBaptiste Daroussin 						t[0] = (char)uval;
374c99fb5f9SBaptiste Daroussin 						t ++;
375c99fb5f9SBaptiste Daroussin 					}
376c99fb5f9SBaptiste Daroussin 					else if(uval < 0x800) {
377c99fb5f9SBaptiste Daroussin 						t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
378c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F));
379c99fb5f9SBaptiste Daroussin 						t += 2;
380c99fb5f9SBaptiste Daroussin 					}
381c99fb5f9SBaptiste Daroussin 					else if(uval < 0x10000) {
382c99fb5f9SBaptiste Daroussin 						t[0] = 0xE0 + ((uval & 0xF000) >> 12);
383c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
384c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x003F));
385c99fb5f9SBaptiste Daroussin 						t += 3;
386c99fb5f9SBaptiste Daroussin 					}
387d9f0ce31SBaptiste Daroussin #if 0
388d9f0ce31SBaptiste Daroussin 					/* It's not actually supported now */
389c99fb5f9SBaptiste Daroussin 					else if(uval <= 0x10FFFF) {
390c99fb5f9SBaptiste Daroussin 						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
391c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
392c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
393c99fb5f9SBaptiste Daroussin 						t[3] = 0x80 + ((uval & 0x00003F));
394c99fb5f9SBaptiste Daroussin 						t += 4;
395c99fb5f9SBaptiste Daroussin 					}
396d9f0ce31SBaptiste Daroussin #endif
397c99fb5f9SBaptiste Daroussin 					else {
398c99fb5f9SBaptiste Daroussin 						*t++ = '?';
399c99fb5f9SBaptiste Daroussin 					}
400d9f0ce31SBaptiste Daroussin 
401d9f0ce31SBaptiste Daroussin 					/* Consume 4 characters of source */
402d9f0ce31SBaptiste Daroussin 					h += 4;
403d9f0ce31SBaptiste Daroussin 					len -= 4;
404d9f0ce31SBaptiste Daroussin 
405d9f0ce31SBaptiste Daroussin 					if (len > 0) {
406d9f0ce31SBaptiste Daroussin 						len --; /* for '\' character */
407d9f0ce31SBaptiste Daroussin 					}
408d9f0ce31SBaptiste Daroussin 					continue;
40997bd480fSBaptiste Daroussin 				}
41097bd480fSBaptiste Daroussin 				else {
41197bd480fSBaptiste Daroussin 					*t++ = 'u';
41297bd480fSBaptiste Daroussin 				}
413c99fb5f9SBaptiste Daroussin 				break;
414c99fb5f9SBaptiste Daroussin 			default:
415c99fb5f9SBaptiste Daroussin 				*t++ = *h;
416c99fb5f9SBaptiste Daroussin 				break;
417c99fb5f9SBaptiste Daroussin 			}
418c99fb5f9SBaptiste Daroussin 			h ++;
419c99fb5f9SBaptiste Daroussin 			len --;
420c99fb5f9SBaptiste Daroussin 		}
421c99fb5f9SBaptiste Daroussin 		else {
422c99fb5f9SBaptiste Daroussin 			*t++ = *h++;
423c99fb5f9SBaptiste Daroussin 		}
42439ee7a7aSBaptiste Daroussin 
42539ee7a7aSBaptiste Daroussin 		if (len > 0) {
426c99fb5f9SBaptiste Daroussin 			len --;
427c99fb5f9SBaptiste Daroussin 		}
42839ee7a7aSBaptiste Daroussin 	}
429c99fb5f9SBaptiste Daroussin 	*t = '\0';
430c99fb5f9SBaptiste Daroussin 
431c99fb5f9SBaptiste Daroussin 	return (t - str);
432c99fb5f9SBaptiste Daroussin }
433c99fb5f9SBaptiste Daroussin 
434*a0409676SBaptiste Daroussin size_t
435*a0409676SBaptiste Daroussin ucl_unescape_squoted_string (char *str, size_t len)
436*a0409676SBaptiste Daroussin {
437*a0409676SBaptiste Daroussin 	char *t = str, *h = str;
438*a0409676SBaptiste Daroussin 
439*a0409676SBaptiste Daroussin 	if (len <= 1) {
440*a0409676SBaptiste Daroussin 		return len;
441*a0409676SBaptiste Daroussin 	}
442*a0409676SBaptiste Daroussin 
443*a0409676SBaptiste Daroussin 	/* t is target (tortoise), h is source (hare) */
444*a0409676SBaptiste Daroussin 
445*a0409676SBaptiste Daroussin 	while (len) {
446*a0409676SBaptiste Daroussin 		if (*h == '\\') {
447*a0409676SBaptiste Daroussin 			h ++;
448*a0409676SBaptiste Daroussin 
449*a0409676SBaptiste Daroussin 			if (len == 1) {
450*a0409676SBaptiste Daroussin 				/*
451*a0409676SBaptiste Daroussin 				 * If \ is last, then do not try to go further
452*a0409676SBaptiste Daroussin 				 * Issue: #74
453*a0409676SBaptiste Daroussin 				 */
454*a0409676SBaptiste Daroussin 				len --;
455*a0409676SBaptiste Daroussin 				*t++ = '\\';
456*a0409676SBaptiste Daroussin 				continue;
457*a0409676SBaptiste Daroussin 			}
458*a0409676SBaptiste Daroussin 
459*a0409676SBaptiste Daroussin 			switch (*h) {
460*a0409676SBaptiste Daroussin 			case '\'':
461*a0409676SBaptiste Daroussin 				*t++ = '\'';
462*a0409676SBaptiste Daroussin 				break;
463*a0409676SBaptiste Daroussin 			case '\n':
464*a0409676SBaptiste Daroussin 				/* Ignore \<newline> style stuff */
465*a0409676SBaptiste Daroussin 				break;
466*a0409676SBaptiste Daroussin 			case '\r':
467*a0409676SBaptiste Daroussin 				/* Ignore \r and the following \n if needed */
468*a0409676SBaptiste Daroussin 				if (len > 1 && h[1] == '\n') {
469*a0409676SBaptiste Daroussin 					h ++;
470*a0409676SBaptiste Daroussin 					len --;
471*a0409676SBaptiste Daroussin 				}
472*a0409676SBaptiste Daroussin 				break;
473*a0409676SBaptiste Daroussin 			default:
474*a0409676SBaptiste Daroussin 				/* Ignore \ */
475*a0409676SBaptiste Daroussin 				*t++ = '\\';
476*a0409676SBaptiste Daroussin 				*t++ = *h;
477*a0409676SBaptiste Daroussin 				break;
478*a0409676SBaptiste Daroussin 			}
479*a0409676SBaptiste Daroussin 
480*a0409676SBaptiste Daroussin 			h ++;
481*a0409676SBaptiste Daroussin 			len --;
482*a0409676SBaptiste Daroussin 		}
483*a0409676SBaptiste Daroussin 		else {
484*a0409676SBaptiste Daroussin 			*t++ = *h++;
485*a0409676SBaptiste Daroussin 		}
486*a0409676SBaptiste Daroussin 
487*a0409676SBaptiste Daroussin 		if (len > 0) {
488*a0409676SBaptiste Daroussin 			len --;
489*a0409676SBaptiste Daroussin 		}
490*a0409676SBaptiste Daroussin 	}
491*a0409676SBaptiste Daroussin 
492*a0409676SBaptiste Daroussin 	*t = '\0';
493*a0409676SBaptiste Daroussin 
494*a0409676SBaptiste Daroussin 	return (t - str);
495*a0409676SBaptiste Daroussin }
496*a0409676SBaptiste Daroussin 
497b04a7a0bSBaptiste Daroussin char *
498b04a7a0bSBaptiste Daroussin ucl_copy_key_trash (const ucl_object_t *obj)
499c99fb5f9SBaptiste Daroussin {
500b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
501b04a7a0bSBaptiste Daroussin 
50297bd480fSBaptiste Daroussin 	if (obj == NULL) {
50397bd480fSBaptiste Daroussin 		return NULL;
50497bd480fSBaptiste Daroussin 	}
505c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
506b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
507b04a7a0bSBaptiste Daroussin 		deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
508b04a7a0bSBaptiste Daroussin 		if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
509b04a7a0bSBaptiste Daroussin 			memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
510b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
511c99fb5f9SBaptiste Daroussin 		}
512b04a7a0bSBaptiste Daroussin 		deconst->key = obj->trash_stack[UCL_TRASH_KEY];
513b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
514c99fb5f9SBaptiste Daroussin 	}
515c99fb5f9SBaptiste Daroussin 
516c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_KEY];
517c99fb5f9SBaptiste Daroussin }
518c99fb5f9SBaptiste Daroussin 
519*a0409676SBaptiste Daroussin void
520*a0409676SBaptiste Daroussin ucl_chunk_free (struct ucl_chunk *chunk)
521*a0409676SBaptiste Daroussin {
522*a0409676SBaptiste Daroussin 	if (chunk) {
523*a0409676SBaptiste Daroussin 		struct ucl_parser_special_handler_chain *chain, *tmp;
524*a0409676SBaptiste Daroussin 
525*a0409676SBaptiste Daroussin 		LL_FOREACH_SAFE (chunk->special_handlers, chain, tmp) {
526*a0409676SBaptiste Daroussin 			if (chain->special_handler->free_function) {
527*a0409676SBaptiste Daroussin 				chain->special_handler->free_function (
528*a0409676SBaptiste Daroussin 						chain->begin,
529*a0409676SBaptiste Daroussin 						chain->len,
530*a0409676SBaptiste Daroussin 						chain->special_handler->user_data);
531*a0409676SBaptiste Daroussin 			} else {
532*a0409676SBaptiste Daroussin 				UCL_FREE (chain->len, chain->begin);
533*a0409676SBaptiste Daroussin 			}
534*a0409676SBaptiste Daroussin 
535*a0409676SBaptiste Daroussin 			UCL_FREE (sizeof (*chain), chain);
536*a0409676SBaptiste Daroussin 		}
537*a0409676SBaptiste Daroussin 
538*a0409676SBaptiste Daroussin 		chunk->special_handlers = NULL;
539*a0409676SBaptiste Daroussin 
540*a0409676SBaptiste Daroussin 		if (chunk->fname) {
541*a0409676SBaptiste Daroussin 			free (chunk->fname);
542*a0409676SBaptiste Daroussin 		}
543*a0409676SBaptiste Daroussin 
544*a0409676SBaptiste Daroussin 		UCL_FREE (sizeof (*chunk), chunk);
545*a0409676SBaptiste Daroussin 	}
546*a0409676SBaptiste Daroussin }
547*a0409676SBaptiste Daroussin 
548b04a7a0bSBaptiste Daroussin char *
549b04a7a0bSBaptiste Daroussin ucl_copy_value_trash (const ucl_object_t *obj)
550c99fb5f9SBaptiste Daroussin {
551b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
552b04a7a0bSBaptiste Daroussin 
55397bd480fSBaptiste Daroussin 	if (obj == NULL) {
55497bd480fSBaptiste Daroussin 		return NULL;
55597bd480fSBaptiste Daroussin 	}
556c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
557b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
558c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_STRING) {
559b04a7a0bSBaptiste Daroussin 
560c99fb5f9SBaptiste Daroussin 			/* Special case for strings */
56139ee7a7aSBaptiste Daroussin 			if (obj->flags & UCL_OBJECT_BINARY) {
56239ee7a7aSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len);
56339ee7a7aSBaptiste Daroussin 				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
56439ee7a7aSBaptiste Daroussin 					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
56539ee7a7aSBaptiste Daroussin 							obj->value.sv,
56639ee7a7aSBaptiste Daroussin 							obj->len);
56739ee7a7aSBaptiste Daroussin 					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
56839ee7a7aSBaptiste Daroussin 				}
56939ee7a7aSBaptiste Daroussin 			}
57039ee7a7aSBaptiste Daroussin 			else {
571b04a7a0bSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
572b04a7a0bSBaptiste Daroussin 				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
57339ee7a7aSBaptiste Daroussin 					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
57439ee7a7aSBaptiste Daroussin 							obj->value.sv,
57539ee7a7aSBaptiste Daroussin 							obj->len);
576b04a7a0bSBaptiste Daroussin 					deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
577b04a7a0bSBaptiste Daroussin 					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
578c99fb5f9SBaptiste Daroussin 				}
579c99fb5f9SBaptiste Daroussin 			}
58039ee7a7aSBaptiste Daroussin 		}
581c99fb5f9SBaptiste Daroussin 		else {
582c99fb5f9SBaptiste Daroussin 			/* Just emit value in json notation */
583b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
584b04a7a0bSBaptiste Daroussin 			deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
585c99fb5f9SBaptiste Daroussin 		}
586b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
587c99fb5f9SBaptiste Daroussin 	}
58839ee7a7aSBaptiste Daroussin 
589c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_VALUE];
590c99fb5f9SBaptiste Daroussin }
591c99fb5f9SBaptiste Daroussin 
59239ee7a7aSBaptiste Daroussin ucl_object_t*
593c99fb5f9SBaptiste Daroussin ucl_parser_get_object (struct ucl_parser *parser)
594c99fb5f9SBaptiste Daroussin {
595c99fb5f9SBaptiste Daroussin 	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
596c99fb5f9SBaptiste Daroussin 		return ucl_object_ref (parser->top_obj);
597c99fb5f9SBaptiste Daroussin 	}
598c99fb5f9SBaptiste Daroussin 
599c99fb5f9SBaptiste Daroussin 	return NULL;
600c99fb5f9SBaptiste Daroussin }
601c99fb5f9SBaptiste Daroussin 
60239ee7a7aSBaptiste Daroussin void
603c99fb5f9SBaptiste Daroussin ucl_parser_free (struct ucl_parser *parser)
604c99fb5f9SBaptiste Daroussin {
605c99fb5f9SBaptiste Daroussin 	struct ucl_stack *stack, *stmp;
606c99fb5f9SBaptiste Daroussin 	struct ucl_macro *macro, *mtmp;
607c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk, *ctmp;
608c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key, *ktmp;
609c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var, *vtmp;
61039ee7a7aSBaptiste Daroussin 	ucl_object_t *tr, *trtmp;
611c99fb5f9SBaptiste Daroussin 
61297bd480fSBaptiste Daroussin 	if (parser == NULL) {
61397bd480fSBaptiste Daroussin 		return;
61497bd480fSBaptiste Daroussin 	}
61597bd480fSBaptiste Daroussin 
616c99fb5f9SBaptiste Daroussin 	if (parser->top_obj != NULL) {
617c99fb5f9SBaptiste Daroussin 		ucl_object_unref (parser->top_obj);
618c99fb5f9SBaptiste Daroussin 	}
619c99fb5f9SBaptiste Daroussin 
62039ee7a7aSBaptiste Daroussin 	if (parser->includepaths != NULL) {
62139ee7a7aSBaptiste Daroussin 		ucl_object_unref (parser->includepaths);
62239ee7a7aSBaptiste Daroussin 	}
62339ee7a7aSBaptiste Daroussin 
624c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
625c99fb5f9SBaptiste Daroussin 		free (stack);
626c99fb5f9SBaptiste Daroussin 	}
627c99fb5f9SBaptiste Daroussin 	HASH_ITER (hh, parser->macroes, macro, mtmp) {
628c99fb5f9SBaptiste Daroussin 		free (macro->name);
629c99fb5f9SBaptiste Daroussin 		HASH_DEL (parser->macroes, macro);
630c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_macro), macro);
631c99fb5f9SBaptiste Daroussin 	}
632c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
633*a0409676SBaptiste Daroussin 		ucl_chunk_free (chunk);
634c99fb5f9SBaptiste Daroussin 	}
635c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
636c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), key);
637c99fb5f9SBaptiste Daroussin 	}
638c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
639c99fb5f9SBaptiste Daroussin 		free (var->value);
640c99fb5f9SBaptiste Daroussin 		free (var->var);
641c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_variable), var);
642c99fb5f9SBaptiste Daroussin 	}
64339ee7a7aSBaptiste Daroussin 	LL_FOREACH_SAFE (parser->trash_objs, tr, trtmp) {
64439ee7a7aSBaptiste Daroussin 		ucl_object_free_internal (tr, false, ucl_object_dtor_free);
64539ee7a7aSBaptiste Daroussin 	}
646c99fb5f9SBaptiste Daroussin 
647c99fb5f9SBaptiste Daroussin 	if (parser->err != NULL) {
648c99fb5f9SBaptiste Daroussin 		utstring_free (parser->err);
649c99fb5f9SBaptiste Daroussin 	}
650c99fb5f9SBaptiste Daroussin 
6514bf54857SBaptiste Daroussin 	if (parser->cur_file) {
6524bf54857SBaptiste Daroussin 		free (parser->cur_file);
6534bf54857SBaptiste Daroussin 	}
6544bf54857SBaptiste Daroussin 
655d9f0ce31SBaptiste Daroussin 	if (parser->comments) {
656d9f0ce31SBaptiste Daroussin 		ucl_object_unref (parser->comments);
657d9f0ce31SBaptiste Daroussin 	}
658d9f0ce31SBaptiste Daroussin 
659c99fb5f9SBaptiste Daroussin 	UCL_FREE (sizeof (struct ucl_parser), parser);
660c99fb5f9SBaptiste Daroussin }
661c99fb5f9SBaptiste Daroussin 
66239ee7a7aSBaptiste Daroussin const char *
663c99fb5f9SBaptiste Daroussin ucl_parser_get_error(struct ucl_parser *parser)
664c99fb5f9SBaptiste Daroussin {
66597bd480fSBaptiste Daroussin 	if (parser == NULL) {
66697bd480fSBaptiste Daroussin 		return NULL;
66797bd480fSBaptiste Daroussin 	}
66897bd480fSBaptiste Daroussin 
66939ee7a7aSBaptiste Daroussin 	if (parser->err == NULL) {
670c99fb5f9SBaptiste Daroussin 		return NULL;
67139ee7a7aSBaptiste Daroussin 	}
672c99fb5f9SBaptiste Daroussin 
673c99fb5f9SBaptiste Daroussin 	return utstring_body (parser->err);
674c99fb5f9SBaptiste Daroussin }
675c99fb5f9SBaptiste Daroussin 
67639ee7a7aSBaptiste Daroussin int
67739ee7a7aSBaptiste Daroussin ucl_parser_get_error_code(struct ucl_parser *parser)
67839ee7a7aSBaptiste Daroussin {
67939ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
68039ee7a7aSBaptiste Daroussin 		return 0;
68139ee7a7aSBaptiste Daroussin 	}
68239ee7a7aSBaptiste Daroussin 
68339ee7a7aSBaptiste Daroussin 	return parser->err_code;
68439ee7a7aSBaptiste Daroussin }
68539ee7a7aSBaptiste Daroussin 
68639ee7a7aSBaptiste Daroussin unsigned
68739ee7a7aSBaptiste Daroussin ucl_parser_get_column(struct ucl_parser *parser)
68839ee7a7aSBaptiste Daroussin {
68939ee7a7aSBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL) {
69039ee7a7aSBaptiste Daroussin 		return 0;
69139ee7a7aSBaptiste Daroussin 	}
69239ee7a7aSBaptiste Daroussin 
69339ee7a7aSBaptiste Daroussin 	return parser->chunks->column;
69439ee7a7aSBaptiste Daroussin }
69539ee7a7aSBaptiste Daroussin 
69639ee7a7aSBaptiste Daroussin unsigned
69739ee7a7aSBaptiste Daroussin ucl_parser_get_linenum(struct ucl_parser *parser)
69839ee7a7aSBaptiste Daroussin {
69939ee7a7aSBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL) {
70039ee7a7aSBaptiste Daroussin 		return 0;
70139ee7a7aSBaptiste Daroussin 	}
70239ee7a7aSBaptiste Daroussin 
70339ee7a7aSBaptiste Daroussin 	return parser->chunks->line;
70439ee7a7aSBaptiste Daroussin }
70539ee7a7aSBaptiste Daroussin 
70639ee7a7aSBaptiste Daroussin void
7078e3b1ab2SBaptiste Daroussin ucl_parser_clear_error(struct ucl_parser *parser)
7088e3b1ab2SBaptiste Daroussin {
7098e3b1ab2SBaptiste Daroussin 	if (parser != NULL && parser->err != NULL) {
7108e3b1ab2SBaptiste Daroussin 		utstring_free(parser->err);
7118e3b1ab2SBaptiste Daroussin 		parser->err = NULL;
71239ee7a7aSBaptiste Daroussin 		parser->err_code = 0;
7138e3b1ab2SBaptiste Daroussin 	}
7148e3b1ab2SBaptiste Daroussin }
7158e3b1ab2SBaptiste Daroussin 
71639ee7a7aSBaptiste Daroussin bool
717c99fb5f9SBaptiste Daroussin ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
718c99fb5f9SBaptiste Daroussin {
719c99fb5f9SBaptiste Daroussin #ifndef HAVE_OPENSSL
720c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures without openssl");
721c99fb5f9SBaptiste Daroussin 	return false;
722c99fb5f9SBaptiste Daroussin #else
723c99fb5f9SBaptiste Daroussin # if (OPENSSL_VERSION_NUMBER < 0x10000000L)
724c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
725c99fb5f9SBaptiste Daroussin 	return EXIT_FAILURE;
726c99fb5f9SBaptiste Daroussin # else
727c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *nkey;
728c99fb5f9SBaptiste Daroussin 	BIO *mem;
729c99fb5f9SBaptiste Daroussin 
730c99fb5f9SBaptiste Daroussin 	mem = BIO_new_mem_buf ((void *)key, len);
731c99fb5f9SBaptiste Daroussin 	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
73297bd480fSBaptiste Daroussin 	if (nkey == NULL) {
73397bd480fSBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot allocate memory for key");
73497bd480fSBaptiste Daroussin 		return false;
73597bd480fSBaptiste Daroussin 	}
736c99fb5f9SBaptiste Daroussin 	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
737c99fb5f9SBaptiste Daroussin 	BIO_free (mem);
738c99fb5f9SBaptiste Daroussin 	if (nkey->key == NULL) {
739c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
740c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "%s",
741c99fb5f9SBaptiste Daroussin 				ERR_error_string (ERR_get_error (), NULL));
742c99fb5f9SBaptiste Daroussin 		return false;
743c99fb5f9SBaptiste Daroussin 	}
744c99fb5f9SBaptiste Daroussin 	LL_PREPEND (parser->keys, nkey);
745c99fb5f9SBaptiste Daroussin # endif
746c99fb5f9SBaptiste Daroussin #endif
747c99fb5f9SBaptiste Daroussin 	return true;
748c99fb5f9SBaptiste Daroussin }
749c99fb5f9SBaptiste Daroussin 
750*a0409676SBaptiste Daroussin void ucl_parser_add_special_handler (struct ucl_parser *parser,
751*a0409676SBaptiste Daroussin 		struct ucl_parser_special_handler *handler)
752*a0409676SBaptiste Daroussin {
753*a0409676SBaptiste Daroussin 	LL_APPEND (parser->special_handlers, handler);
754*a0409676SBaptiste Daroussin }
755*a0409676SBaptiste Daroussin 
756c99fb5f9SBaptiste Daroussin #ifdef CURL_FOUND
757c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata {
758c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
759c99fb5f9SBaptiste Daroussin 	size_t buflen;
760c99fb5f9SBaptiste Daroussin };
761c99fb5f9SBaptiste Daroussin 
762c99fb5f9SBaptiste Daroussin static size_t
763c99fb5f9SBaptiste Daroussin ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
764c99fb5f9SBaptiste Daroussin {
765c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata *cbdata = ud;
766c99fb5f9SBaptiste Daroussin 	size_t realsize = size * nmemb;
767c99fb5f9SBaptiste Daroussin 
768c99fb5f9SBaptiste Daroussin 	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
769c99fb5f9SBaptiste Daroussin 	if (cbdata->buf == NULL) {
770c99fb5f9SBaptiste Daroussin 		return 0;
771c99fb5f9SBaptiste Daroussin 	}
772c99fb5f9SBaptiste Daroussin 
773c99fb5f9SBaptiste Daroussin 	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
774c99fb5f9SBaptiste Daroussin 	cbdata->buflen += realsize;
775c99fb5f9SBaptiste Daroussin 	cbdata->buf[cbdata->buflen] = 0;
776c99fb5f9SBaptiste Daroussin 
777c99fb5f9SBaptiste Daroussin 	return realsize;
778c99fb5f9SBaptiste Daroussin }
779c99fb5f9SBaptiste Daroussin #endif
780c99fb5f9SBaptiste Daroussin 
781c99fb5f9SBaptiste Daroussin /**
782c99fb5f9SBaptiste Daroussin  * Fetch a url and save results to the memory buffer
783c99fb5f9SBaptiste Daroussin  * @param url url to fetch
784c99fb5f9SBaptiste Daroussin  * @param len length of url
785c99fb5f9SBaptiste Daroussin  * @param buf target buffer
786c99fb5f9SBaptiste Daroussin  * @param buflen target length
787c99fb5f9SBaptiste Daroussin  * @return
788c99fb5f9SBaptiste Daroussin  */
789d9f0ce31SBaptiste Daroussin bool
790c99fb5f9SBaptiste Daroussin ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
791c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
792c99fb5f9SBaptiste Daroussin {
793c99fb5f9SBaptiste Daroussin 
794c99fb5f9SBaptiste Daroussin #ifdef HAVE_FETCH_H
795c99fb5f9SBaptiste Daroussin 	struct url *fetch_url;
796c99fb5f9SBaptiste Daroussin 	struct url_stat us;
797c99fb5f9SBaptiste Daroussin 	FILE *in;
798c99fb5f9SBaptiste Daroussin 
799c99fb5f9SBaptiste Daroussin 	fetch_url = fetchParseURL (url);
800c99fb5f9SBaptiste Daroussin 	if (fetch_url == NULL) {
801c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
802c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
803c99fb5f9SBaptiste Daroussin 		return false;
804c99fb5f9SBaptiste Daroussin 	}
805c99fb5f9SBaptiste Daroussin 	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
806c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
807c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot fetch URL %s: %s",
808c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
809c99fb5f9SBaptiste Daroussin 		}
810c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
811c99fb5f9SBaptiste Daroussin 		return false;
812c99fb5f9SBaptiste Daroussin 	}
813c99fb5f9SBaptiste Daroussin 
814c99fb5f9SBaptiste Daroussin 	*buflen = us.size;
815c99fb5f9SBaptiste Daroussin 	*buf = malloc (*buflen);
816c99fb5f9SBaptiste Daroussin 	if (*buf == NULL) {
817c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
818c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
819c99fb5f9SBaptiste Daroussin 		fclose (in);
820c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
821c99fb5f9SBaptiste Daroussin 		return false;
822c99fb5f9SBaptiste Daroussin 	}
823c99fb5f9SBaptiste Daroussin 
824c99fb5f9SBaptiste Daroussin 	if (fread (*buf, *buflen, 1, in) != 1) {
825c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot read URL %s: %s",
826c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
827c99fb5f9SBaptiste Daroussin 		fclose (in);
828c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
829c99fb5f9SBaptiste Daroussin 		return false;
830c99fb5f9SBaptiste Daroussin 	}
831c99fb5f9SBaptiste Daroussin 
832c99fb5f9SBaptiste Daroussin 	fetchFreeURL (fetch_url);
833c99fb5f9SBaptiste Daroussin 	return true;
834c99fb5f9SBaptiste Daroussin #elif defined(CURL_FOUND)
835c99fb5f9SBaptiste Daroussin 	CURL *curl;
836c99fb5f9SBaptiste Daroussin 	int r;
837c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata cbdata;
838c99fb5f9SBaptiste Daroussin 
839c99fb5f9SBaptiste Daroussin 	curl = curl_easy_init ();
840c99fb5f9SBaptiste Daroussin 	if (curl == NULL) {
841c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "CURL interface is broken");
842c99fb5f9SBaptiste Daroussin 		return false;
843c99fb5f9SBaptiste Daroussin 	}
844c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
845c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
846c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
847c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
848c99fb5f9SBaptiste Daroussin 		return false;
849c99fb5f9SBaptiste Daroussin 	}
850c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
851d9f0ce31SBaptiste Daroussin 	cbdata.buf = NULL;
852d9f0ce31SBaptiste Daroussin 	cbdata.buflen = 0;
853c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
854c99fb5f9SBaptiste Daroussin 
855c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
856c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
857c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "error fetching URL %s: %s",
858c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
859c99fb5f9SBaptiste Daroussin 		}
860c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
861c99fb5f9SBaptiste Daroussin 		if (cbdata.buf) {
862c99fb5f9SBaptiste Daroussin 			free (cbdata.buf);
863c99fb5f9SBaptiste Daroussin 		}
864c99fb5f9SBaptiste Daroussin 		return false;
865c99fb5f9SBaptiste Daroussin 	}
866c99fb5f9SBaptiste Daroussin 	*buf = cbdata.buf;
867c99fb5f9SBaptiste Daroussin 	*buflen = cbdata.buflen;
868c99fb5f9SBaptiste Daroussin 
869*a0409676SBaptiste Daroussin 	curl_easy_cleanup (curl);
870*a0409676SBaptiste Daroussin 
871c99fb5f9SBaptiste Daroussin 	return true;
872c99fb5f9SBaptiste Daroussin #else
873c99fb5f9SBaptiste Daroussin 	ucl_create_err (err, "URL support is disabled");
874c99fb5f9SBaptiste Daroussin 	return false;
875c99fb5f9SBaptiste Daroussin #endif
876c99fb5f9SBaptiste Daroussin }
877c99fb5f9SBaptiste Daroussin 
878c99fb5f9SBaptiste Daroussin /**
879c99fb5f9SBaptiste Daroussin  * Fetch a file and save results to the memory buffer
880c99fb5f9SBaptiste Daroussin  * @param filename filename to fetch
881c99fb5f9SBaptiste Daroussin  * @param len length of filename
882c99fb5f9SBaptiste Daroussin  * @param buf target buffer
883c99fb5f9SBaptiste Daroussin  * @param buflen target length
884c99fb5f9SBaptiste Daroussin  * @return
885c99fb5f9SBaptiste Daroussin  */
886d9f0ce31SBaptiste Daroussin bool
887c99fb5f9SBaptiste Daroussin ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
888c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
889c99fb5f9SBaptiste Daroussin {
890c99fb5f9SBaptiste Daroussin 	int fd;
891c99fb5f9SBaptiste Daroussin 	struct stat st;
892c99fb5f9SBaptiste Daroussin 
893*a0409676SBaptiste Daroussin 	if (stat (filename, &st) == -1) {
894*a0409676SBaptiste Daroussin 		if (must_exist || errno == EPERM) {
895c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot stat file %s: %s",
896c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
897c99fb5f9SBaptiste Daroussin 		}
898c99fb5f9SBaptiste Daroussin 		return false;
899c99fb5f9SBaptiste Daroussin 	}
900*a0409676SBaptiste Daroussin 	if (!S_ISREG (st.st_mode)) {
901*a0409676SBaptiste Daroussin 		if (must_exist) {
902*a0409676SBaptiste Daroussin 			ucl_create_err (err, "file %s is not a regular file", filename);
903*a0409676SBaptiste Daroussin 		}
904*a0409676SBaptiste Daroussin 
905*a0409676SBaptiste Daroussin 		return false;
906*a0409676SBaptiste Daroussin 	}
907c99fb5f9SBaptiste Daroussin 	if (st.st_size == 0) {
908c99fb5f9SBaptiste Daroussin 		/* Do not map empty files */
909d9f0ce31SBaptiste Daroussin 		*buf = NULL;
910c99fb5f9SBaptiste Daroussin 		*buflen = 0;
911c99fb5f9SBaptiste Daroussin 	}
912c99fb5f9SBaptiste Daroussin 	else {
913c99fb5f9SBaptiste Daroussin 		if ((fd = open (filename, O_RDONLY)) == -1) {
914c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot open file %s: %s",
915c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
916c99fb5f9SBaptiste Daroussin 			return false;
917c99fb5f9SBaptiste Daroussin 		}
91897bd480fSBaptiste Daroussin 		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
919c99fb5f9SBaptiste Daroussin 			close (fd);
920c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot mmap file %s: %s",
921c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
922d9f0ce31SBaptiste Daroussin 			*buf = NULL;
923d9f0ce31SBaptiste Daroussin 
924c99fb5f9SBaptiste Daroussin 			return false;
925c99fb5f9SBaptiste Daroussin 		}
926c99fb5f9SBaptiste Daroussin 		*buflen = st.st_size;
927c99fb5f9SBaptiste Daroussin 		close (fd);
928c99fb5f9SBaptiste Daroussin 	}
929c99fb5f9SBaptiste Daroussin 
930c99fb5f9SBaptiste Daroussin 	return true;
931c99fb5f9SBaptiste Daroussin }
932c99fb5f9SBaptiste Daroussin 
933c99fb5f9SBaptiste Daroussin 
934c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
935c99fb5f9SBaptiste Daroussin static inline bool
936c99fb5f9SBaptiste Daroussin ucl_sig_check (const unsigned char *data, size_t datalen,
937c99fb5f9SBaptiste Daroussin 		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
938c99fb5f9SBaptiste Daroussin {
939c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key;
940c99fb5f9SBaptiste Daroussin 	char dig[EVP_MAX_MD_SIZE];
941c99fb5f9SBaptiste Daroussin 	unsigned int diglen;
942c99fb5f9SBaptiste Daroussin 	EVP_PKEY_CTX *key_ctx;
943c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX *sign_ctx = NULL;
944c99fb5f9SBaptiste Daroussin 
945c99fb5f9SBaptiste Daroussin 	sign_ctx = EVP_MD_CTX_create ();
946c99fb5f9SBaptiste Daroussin 
947c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->keys, key) {
948c99fb5f9SBaptiste Daroussin 		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
949c99fb5f9SBaptiste Daroussin 		if (key_ctx != NULL) {
950c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
951c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
952c99fb5f9SBaptiste Daroussin 				continue;
953c99fb5f9SBaptiste Daroussin 			}
954c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
955c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
956c99fb5f9SBaptiste Daroussin 				continue;
957c99fb5f9SBaptiste Daroussin 			}
958c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
959c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
960c99fb5f9SBaptiste Daroussin 				continue;
961c99fb5f9SBaptiste Daroussin 			}
962c99fb5f9SBaptiste Daroussin 			EVP_DigestInit (sign_ctx, EVP_sha256 ());
963c99fb5f9SBaptiste Daroussin 			EVP_DigestUpdate (sign_ctx, data, datalen);
964c99fb5f9SBaptiste Daroussin 			EVP_DigestFinal (sign_ctx, dig, &diglen);
965c99fb5f9SBaptiste Daroussin 
966c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
967c99fb5f9SBaptiste Daroussin 				EVP_MD_CTX_destroy (sign_ctx);
968c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
969c99fb5f9SBaptiste Daroussin 				return true;
970c99fb5f9SBaptiste Daroussin 			}
971c99fb5f9SBaptiste Daroussin 
972c99fb5f9SBaptiste Daroussin 			EVP_PKEY_CTX_free (key_ctx);
973c99fb5f9SBaptiste Daroussin 		}
974c99fb5f9SBaptiste Daroussin 	}
975c99fb5f9SBaptiste Daroussin 
976c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX_destroy (sign_ctx);
977c99fb5f9SBaptiste Daroussin 
978c99fb5f9SBaptiste Daroussin 	return false;
979c99fb5f9SBaptiste Daroussin }
980c99fb5f9SBaptiste Daroussin #endif
981c99fb5f9SBaptiste Daroussin 
98239ee7a7aSBaptiste Daroussin struct ucl_include_params {
98339ee7a7aSBaptiste Daroussin 	bool check_signature;
98439ee7a7aSBaptiste Daroussin 	bool must_exist;
98539ee7a7aSBaptiste Daroussin 	bool use_glob;
98639ee7a7aSBaptiste Daroussin 	bool use_prefix;
98739ee7a7aSBaptiste Daroussin 	bool soft_fail;
98839ee7a7aSBaptiste Daroussin 	bool allow_glob;
98939ee7a7aSBaptiste Daroussin 	unsigned priority;
99039ee7a7aSBaptiste Daroussin 	enum ucl_duplicate_strategy strat;
99139ee7a7aSBaptiste Daroussin 	enum ucl_parse_type parse_type;
99239ee7a7aSBaptiste Daroussin 	const char *prefix;
99339ee7a7aSBaptiste Daroussin 	const char *target;
99439ee7a7aSBaptiste Daroussin };
99539ee7a7aSBaptiste Daroussin 
996c99fb5f9SBaptiste Daroussin /**
997c99fb5f9SBaptiste Daroussin  * Include an url to configuration
998c99fb5f9SBaptiste Daroussin  * @param data
999c99fb5f9SBaptiste Daroussin  * @param len
1000c99fb5f9SBaptiste Daroussin  * @param parser
1001c99fb5f9SBaptiste Daroussin  * @param err
1002c99fb5f9SBaptiste Daroussin  * @return
1003c99fb5f9SBaptiste Daroussin  */
1004c99fb5f9SBaptiste Daroussin static bool
1005c99fb5f9SBaptiste Daroussin ucl_include_url (const unsigned char *data, size_t len,
100639ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser,
100739ee7a7aSBaptiste Daroussin 		struct ucl_include_params *params)
1008c99fb5f9SBaptiste Daroussin {
1009c99fb5f9SBaptiste Daroussin 
1010c99fb5f9SBaptiste Daroussin 	bool res;
1011c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
1012c99fb5f9SBaptiste Daroussin 	size_t buflen = 0;
1013c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
1014c99fb5f9SBaptiste Daroussin 	char urlbuf[PATH_MAX];
1015c99fb5f9SBaptiste Daroussin 	int prev_state;
1016c99fb5f9SBaptiste Daroussin 
1017c99fb5f9SBaptiste Daroussin 	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
1018c99fb5f9SBaptiste Daroussin 
101939ee7a7aSBaptiste Daroussin 	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
1020d9f0ce31SBaptiste Daroussin 		return !params->must_exist;
1021c99fb5f9SBaptiste Daroussin 	}
1022c99fb5f9SBaptiste Daroussin 
102339ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
1024c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
1025c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
1026c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
1027c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
1028c99fb5f9SBaptiste Daroussin 		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
1029c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
1030c99fb5f9SBaptiste Daroussin 			return false;
1031c99fb5f9SBaptiste Daroussin 		}
1032c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
1033c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify url %s: %s",
1034c99fb5f9SBaptiste Daroussin 							urlbuf,
1035c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
1036c99fb5f9SBaptiste Daroussin 			if (siglen > 0) {
103797bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
1038c99fb5f9SBaptiste Daroussin 			}
1039c99fb5f9SBaptiste Daroussin 			return false;
1040c99fb5f9SBaptiste Daroussin 		}
1041c99fb5f9SBaptiste Daroussin 		if (siglen > 0) {
104297bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
1043c99fb5f9SBaptiste Daroussin 		}
1044c99fb5f9SBaptiste Daroussin #endif
1045c99fb5f9SBaptiste Daroussin 	}
1046c99fb5f9SBaptiste Daroussin 
1047c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
1048c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
1049c99fb5f9SBaptiste Daroussin 
105039ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
105139ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
1052c99fb5f9SBaptiste Daroussin 	if (res == true) {
1053c99fb5f9SBaptiste Daroussin 		/* Remove chunk from the stack */
1054c99fb5f9SBaptiste Daroussin 		chunk = parser->chunks;
1055c99fb5f9SBaptiste Daroussin 		if (chunk != NULL) {
1056c99fb5f9SBaptiste Daroussin 			parser->chunks = chunk->next;
1057*a0409676SBaptiste Daroussin 			ucl_chunk_free (chunk);
1058c99fb5f9SBaptiste Daroussin 		}
1059c99fb5f9SBaptiste Daroussin 	}
1060c99fb5f9SBaptiste Daroussin 
1061c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
1062c99fb5f9SBaptiste Daroussin 	free (buf);
1063c99fb5f9SBaptiste Daroussin 
1064c99fb5f9SBaptiste Daroussin 	return res;
1065c99fb5f9SBaptiste Daroussin }
1066c99fb5f9SBaptiste Daroussin 
1067c99fb5f9SBaptiste Daroussin /**
10684bf54857SBaptiste Daroussin  * Include a single file to the parser
1069c99fb5f9SBaptiste Daroussin  * @param data
1070c99fb5f9SBaptiste Daroussin  * @param len
1071c99fb5f9SBaptiste Daroussin  * @param parser
10724bf54857SBaptiste Daroussin  * @param check_signature
10734bf54857SBaptiste Daroussin  * @param must_exist
10744bf54857SBaptiste Daroussin  * @param allow_glob
10754bf54857SBaptiste Daroussin  * @param priority
1076c99fb5f9SBaptiste Daroussin  * @return
1077c99fb5f9SBaptiste Daroussin  */
1078c99fb5f9SBaptiste Daroussin static bool
10794bf54857SBaptiste Daroussin ucl_include_file_single (const unsigned char *data, size_t len,
108039ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser, struct ucl_include_params *params)
1081c99fb5f9SBaptiste Daroussin {
1082c99fb5f9SBaptiste Daroussin 	bool res;
1083c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
1084c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
108539ee7a7aSBaptiste Daroussin 	char *old_curfile, *ext;
108639ee7a7aSBaptiste Daroussin 	size_t buflen = 0;
1087c99fb5f9SBaptiste Daroussin 	char filebuf[PATH_MAX], realbuf[PATH_MAX];
1088c99fb5f9SBaptiste Daroussin 	int prev_state;
10894bf54857SBaptiste Daroussin 	struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
10904bf54857SBaptiste Daroussin 			*old_filename = NULL;
109139ee7a7aSBaptiste Daroussin 	ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL;
109239ee7a7aSBaptiste Daroussin 	ucl_hash_t *container = NULL;
109339ee7a7aSBaptiste Daroussin 	struct ucl_stack *st = NULL;
1094c99fb5f9SBaptiste Daroussin 
1095c99fb5f9SBaptiste Daroussin 	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
109697bd480fSBaptiste Daroussin 	if (ucl_realpath (filebuf, realbuf) == NULL) {
109739ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
109839ee7a7aSBaptiste Daroussin 			return false;
109939ee7a7aSBaptiste Daroussin 		}
1100*a0409676SBaptiste Daroussin 		if (!params->must_exist && errno != EPERM) {
1101c99fb5f9SBaptiste Daroussin 			return true;
1102c99fb5f9SBaptiste Daroussin 		}
1103*a0409676SBaptiste Daroussin 
1104c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
1105c99fb5f9SBaptiste Daroussin 									filebuf,
1106c99fb5f9SBaptiste Daroussin 									strerror (errno));
1107c99fb5f9SBaptiste Daroussin 		return false;
1108c99fb5f9SBaptiste Daroussin 	}
1109c99fb5f9SBaptiste Daroussin 
11104bf54857SBaptiste Daroussin 	if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
11114bf54857SBaptiste Daroussin 		/* We are likely including the file itself */
111239ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
111339ee7a7aSBaptiste Daroussin 			return false;
111439ee7a7aSBaptiste Daroussin 		}
111539ee7a7aSBaptiste Daroussin 
11164bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "trying to include the file %s from itself",
11174bf54857SBaptiste Daroussin 				realbuf);
11184bf54857SBaptiste Daroussin 		return false;
11194bf54857SBaptiste Daroussin 	}
11204bf54857SBaptiste Daroussin 
112139ee7a7aSBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, params->must_exist)) {
112239ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
112339ee7a7aSBaptiste Daroussin 			return false;
112439ee7a7aSBaptiste Daroussin 		}
11256525738fSBaptiste Daroussin 
1126*a0409676SBaptiste Daroussin 		if (params->must_exist || parser->err != NULL) {
1127*a0409676SBaptiste Daroussin 			/* The case of fatal errors */
1128*a0409676SBaptiste Daroussin 			return false;
1129*a0409676SBaptiste Daroussin 		}
1130*a0409676SBaptiste Daroussin 
1131*a0409676SBaptiste Daroussin 		return true;
1132c99fb5f9SBaptiste Daroussin 	}
1133c99fb5f9SBaptiste Daroussin 
113439ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
1135c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
1136c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
1137c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
1138c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
1139c99fb5f9SBaptiste Daroussin 		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
1140c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
1141c99fb5f9SBaptiste Daroussin 			return false;
1142c99fb5f9SBaptiste Daroussin 		}
1143c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
1144c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify file %s: %s",
1145c99fb5f9SBaptiste Daroussin 							filebuf,
1146c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
1147d9f0ce31SBaptiste Daroussin 			if (sigbuf) {
114897bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
1149c99fb5f9SBaptiste Daroussin 			}
1150c99fb5f9SBaptiste Daroussin 			return false;
1151c99fb5f9SBaptiste Daroussin 		}
1152d9f0ce31SBaptiste Daroussin 		if (sigbuf) {
115397bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
1154c99fb5f9SBaptiste Daroussin 		}
1155c99fb5f9SBaptiste Daroussin #endif
1156c99fb5f9SBaptiste Daroussin 	}
1157c99fb5f9SBaptiste Daroussin 
11584bf54857SBaptiste Daroussin 	old_curfile = parser->cur_file;
1159*a0409676SBaptiste Daroussin 	parser->cur_file = NULL;
11604bf54857SBaptiste Daroussin 
11614bf54857SBaptiste Daroussin 	/* Store old file vars */
11624bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
11634bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0) {
11644bf54857SBaptiste Daroussin 			old_curdir = cur_var;
11654bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
11664bf54857SBaptiste Daroussin 		}
11674bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0) {
11684bf54857SBaptiste Daroussin 			old_filename = cur_var;
11694bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
11704bf54857SBaptiste Daroussin 		}
11714bf54857SBaptiste Daroussin 	}
11724bf54857SBaptiste Daroussin 
1173c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
1174c99fb5f9SBaptiste Daroussin 
1175c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
1176c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
1177c99fb5f9SBaptiste Daroussin 
117839ee7a7aSBaptiste Daroussin 	if (params->use_prefix && params->prefix == NULL) {
117939ee7a7aSBaptiste Daroussin 		/* Auto generate a key name based on the included filename */
118039ee7a7aSBaptiste Daroussin 		params->prefix = basename (realbuf);
118139ee7a7aSBaptiste Daroussin 		ext = strrchr (params->prefix, '.');
118239ee7a7aSBaptiste Daroussin 		if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) {
118339ee7a7aSBaptiste Daroussin 			/* Strip off .conf or .ucl */
118439ee7a7aSBaptiste Daroussin 			*ext = '\0';
118539ee7a7aSBaptiste Daroussin 		}
118639ee7a7aSBaptiste Daroussin 	}
118739ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL) {
118839ee7a7aSBaptiste Daroussin 		/* This is a prefixed include */
118939ee7a7aSBaptiste Daroussin 		container = parser->stack->obj->value.ov;
119039ee7a7aSBaptiste Daroussin 
119139ee7a7aSBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container,
119239ee7a7aSBaptiste Daroussin 				params->prefix, strlen (params->prefix)));
119339ee7a7aSBaptiste Daroussin 
1194*a0409676SBaptiste Daroussin 		if (strcasecmp (params->target, "array") == 0) {
1195*a0409676SBaptiste Daroussin 			if (old_obj == NULL) {
119639ee7a7aSBaptiste Daroussin 				/* Create an array with key: prefix */
119739ee7a7aSBaptiste Daroussin 				old_obj = ucl_object_new_full (UCL_ARRAY, params->priority);
119839ee7a7aSBaptiste Daroussin 				old_obj->key = params->prefix;
119939ee7a7aSBaptiste Daroussin 				old_obj->keylen = strlen (params->prefix);
120039ee7a7aSBaptiste Daroussin 				ucl_copy_key_trash (old_obj);
120139ee7a7aSBaptiste Daroussin 				old_obj->prev = old_obj;
120239ee7a7aSBaptiste Daroussin 				old_obj->next = NULL;
120339ee7a7aSBaptiste Daroussin 
120439ee7a7aSBaptiste Daroussin 				container = ucl_hash_insert_object (container, old_obj,
120539ee7a7aSBaptiste Daroussin 						parser->flags & UCL_PARSER_KEY_LOWERCASE);
120639ee7a7aSBaptiste Daroussin 				parser->stack->obj->len++;
120739ee7a7aSBaptiste Daroussin 
120839ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
120939ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
121039ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
121139ee7a7aSBaptiste Daroussin 
121239ee7a7aSBaptiste Daroussin 				ucl_array_append (old_obj, nest_obj);
121339ee7a7aSBaptiste Daroussin 			}
1214*a0409676SBaptiste Daroussin 			else {
1215*a0409676SBaptiste Daroussin 				if (ucl_object_type (old_obj) == UCL_ARRAY) {
1216*a0409676SBaptiste Daroussin 					/* Append to the existing array */
1217*a0409676SBaptiste Daroussin 					nest_obj = ucl_object_new_full (UCL_OBJECT,
1218*a0409676SBaptiste Daroussin 							params->priority);
1219*a0409676SBaptiste Daroussin 					if (nest_obj == NULL) {
1220*a0409676SBaptiste Daroussin 						ucl_create_err (&parser->err,
1221*a0409676SBaptiste Daroussin 								"cannot allocate memory for an object");
1222*a0409676SBaptiste Daroussin 						if (buf) {
1223*a0409676SBaptiste Daroussin 							ucl_munmap (buf, buflen);
1224*a0409676SBaptiste Daroussin 						}
1225*a0409676SBaptiste Daroussin 
1226*a0409676SBaptiste Daroussin 						return false;
1227*a0409676SBaptiste Daroussin 					}
1228*a0409676SBaptiste Daroussin 					nest_obj->prev = nest_obj;
1229*a0409676SBaptiste Daroussin 					nest_obj->next = NULL;
1230*a0409676SBaptiste Daroussin 
1231*a0409676SBaptiste Daroussin 					ucl_array_append (old_obj, nest_obj);
1232*a0409676SBaptiste Daroussin 				}
1233*a0409676SBaptiste Daroussin 				else {
1234*a0409676SBaptiste Daroussin 					/* Convert the object to an array */
1235*a0409676SBaptiste Daroussin 					new_obj = ucl_object_typed_new (UCL_ARRAY);
1236*a0409676SBaptiste Daroussin 					if (new_obj == NULL) {
1237*a0409676SBaptiste Daroussin 						ucl_create_err (&parser->err,
1238*a0409676SBaptiste Daroussin 								"cannot allocate memory for an object");
1239*a0409676SBaptiste Daroussin 						if (buf) {
1240*a0409676SBaptiste Daroussin 							ucl_munmap (buf, buflen);
1241*a0409676SBaptiste Daroussin 						}
1242*a0409676SBaptiste Daroussin 
1243*a0409676SBaptiste Daroussin 						return false;
1244*a0409676SBaptiste Daroussin 					}
1245*a0409676SBaptiste Daroussin 					new_obj->key = old_obj->key;
1246*a0409676SBaptiste Daroussin 					new_obj->keylen = old_obj->keylen;
1247*a0409676SBaptiste Daroussin 					new_obj->flags |= UCL_OBJECT_MULTIVALUE;
1248*a0409676SBaptiste Daroussin 					new_obj->prev = new_obj;
1249*a0409676SBaptiste Daroussin 					new_obj->next = NULL;
1250*a0409676SBaptiste Daroussin 
1251*a0409676SBaptiste Daroussin 					nest_obj = ucl_object_new_full (UCL_OBJECT,
1252*a0409676SBaptiste Daroussin 							params->priority);
1253*a0409676SBaptiste Daroussin 					if (nest_obj == NULL) {
1254*a0409676SBaptiste Daroussin 						ucl_create_err (&parser->err,
1255*a0409676SBaptiste Daroussin 								"cannot allocate memory for an object");
1256*a0409676SBaptiste Daroussin 						if (buf) {
1257*a0409676SBaptiste Daroussin 							ucl_munmap (buf, buflen);
1258*a0409676SBaptiste Daroussin 						}
1259*a0409676SBaptiste Daroussin 
1260*a0409676SBaptiste Daroussin 						return false;
1261*a0409676SBaptiste Daroussin 					}
1262*a0409676SBaptiste Daroussin 					nest_obj->prev = nest_obj;
1263*a0409676SBaptiste Daroussin 					nest_obj->next = NULL;
1264*a0409676SBaptiste Daroussin 
1265*a0409676SBaptiste Daroussin 					ucl_array_append (new_obj, old_obj);
1266*a0409676SBaptiste Daroussin 					ucl_array_append (new_obj, nest_obj);
1267*a0409676SBaptiste Daroussin 					ucl_hash_replace (container, old_obj, new_obj);
1268*a0409676SBaptiste Daroussin 				}
1269*a0409676SBaptiste Daroussin 			}
1270*a0409676SBaptiste Daroussin 		}
1271*a0409676SBaptiste Daroussin 		else {
1272*a0409676SBaptiste Daroussin 			/* Case of object */
1273*a0409676SBaptiste Daroussin 			if (old_obj == NULL) {
127439ee7a7aSBaptiste Daroussin 				/* Create an object with key: prefix */
127539ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1276d9f0ce31SBaptiste Daroussin 
1277d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1278d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1279d9f0ce31SBaptiste Daroussin 					if (buf) {
1280d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1281d9f0ce31SBaptiste Daroussin 					}
1282d9f0ce31SBaptiste Daroussin 
1283d9f0ce31SBaptiste Daroussin 					return false;
1284d9f0ce31SBaptiste Daroussin 				}
1285d9f0ce31SBaptiste Daroussin 
128639ee7a7aSBaptiste Daroussin 				nest_obj->key = params->prefix;
128739ee7a7aSBaptiste Daroussin 				nest_obj->keylen = strlen (params->prefix);
128839ee7a7aSBaptiste Daroussin 				ucl_copy_key_trash(nest_obj);
128939ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
129039ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
129139ee7a7aSBaptiste Daroussin 
129239ee7a7aSBaptiste Daroussin 				container = ucl_hash_insert_object (container, nest_obj,
129339ee7a7aSBaptiste Daroussin 						parser->flags & UCL_PARSER_KEY_LOWERCASE);
129439ee7a7aSBaptiste Daroussin 				parser->stack->obj->len ++;
129539ee7a7aSBaptiste Daroussin 			}
129639ee7a7aSBaptiste Daroussin 			else {
129739ee7a7aSBaptiste Daroussin 				if (ucl_object_type (old_obj) == UCL_OBJECT) {
129839ee7a7aSBaptiste Daroussin 					/* Append to existing Object*/
129939ee7a7aSBaptiste Daroussin 					nest_obj = old_obj;
130039ee7a7aSBaptiste Daroussin 				}
130139ee7a7aSBaptiste Daroussin 				else {
130239ee7a7aSBaptiste Daroussin 					/* The key is not an object */
130339ee7a7aSBaptiste Daroussin 					ucl_create_err (&parser->err,
1304*a0409676SBaptiste Daroussin 							"Conflicting type for key: %s, asked %s, has %s",
1305*a0409676SBaptiste Daroussin 							params->prefix, params->target,
1306*a0409676SBaptiste Daroussin 							ucl_object_type_to_string (ucl_object_type (old_obj)));
1307d9f0ce31SBaptiste Daroussin 					if (buf) {
1308d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1309d9f0ce31SBaptiste Daroussin 					}
1310d9f0ce31SBaptiste Daroussin 
131139ee7a7aSBaptiste Daroussin 					return false;
131239ee7a7aSBaptiste Daroussin 				}
131339ee7a7aSBaptiste Daroussin 			}
1314*a0409676SBaptiste Daroussin 		}
1315*a0409676SBaptiste Daroussin 
131639ee7a7aSBaptiste Daroussin 
131739ee7a7aSBaptiste Daroussin 		/* Put all of the content of the include inside that object */
131839ee7a7aSBaptiste Daroussin 		parser->stack->obj->value.ov = container;
131939ee7a7aSBaptiste Daroussin 
132039ee7a7aSBaptiste Daroussin 		st = UCL_ALLOC (sizeof (struct ucl_stack));
132139ee7a7aSBaptiste Daroussin 		if (st == NULL) {
132239ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for an object");
132339ee7a7aSBaptiste Daroussin 			ucl_object_unref (nest_obj);
1324d9f0ce31SBaptiste Daroussin 
1325d9f0ce31SBaptiste Daroussin 			if (buf) {
1326d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1327d9f0ce31SBaptiste Daroussin 			}
1328d9f0ce31SBaptiste Daroussin 
1329d9f0ce31SBaptiste Daroussin 			return false;
133039ee7a7aSBaptiste Daroussin 		}
133139ee7a7aSBaptiste Daroussin 		st->obj = nest_obj;
1332*a0409676SBaptiste Daroussin 		st->e.params.level = parser->stack->e.params.level;
1333*a0409676SBaptiste Daroussin 		st->e.params.flags = parser->stack->e.params.flags;
1334*a0409676SBaptiste Daroussin 		st->e.params.line = parser->stack->e.params.line;
1335*a0409676SBaptiste Daroussin 		st->chunk = parser->chunks;
133639ee7a7aSBaptiste Daroussin 		LL_PREPEND (parser->stack, st);
133739ee7a7aSBaptiste Daroussin 		parser->cur_obj = nest_obj;
133839ee7a7aSBaptiste Daroussin 	}
133939ee7a7aSBaptiste Daroussin 
134039ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
134139ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
13426525738fSBaptiste Daroussin 
1343*a0409676SBaptiste Daroussin 	if (res) {
134439ee7a7aSBaptiste Daroussin 		/* Stop nesting the include, take 1 level off the stack */
134539ee7a7aSBaptiste Daroussin 		if (params->prefix != NULL && nest_obj != NULL) {
134639ee7a7aSBaptiste Daroussin 			parser->stack = st->next;
134739ee7a7aSBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_stack), st);
134839ee7a7aSBaptiste Daroussin 		}
134939ee7a7aSBaptiste Daroussin 
1350c99fb5f9SBaptiste Daroussin 		/* Remove chunk from the stack */
1351c99fb5f9SBaptiste Daroussin 		chunk = parser->chunks;
1352c99fb5f9SBaptiste Daroussin 		if (chunk != NULL) {
1353c99fb5f9SBaptiste Daroussin 			parser->chunks = chunk->next;
1354*a0409676SBaptiste Daroussin 			ucl_chunk_free (chunk);
13554bf54857SBaptiste Daroussin 			parser->recursion--;
1356c99fb5f9SBaptiste Daroussin 		}
13574bf54857SBaptiste Daroussin 
13584bf54857SBaptiste Daroussin 		/* Restore old file vars */
135939ee7a7aSBaptiste Daroussin 		if (parser->cur_file) {
136039ee7a7aSBaptiste Daroussin 			free (parser->cur_file);
136139ee7a7aSBaptiste Daroussin 		}
136239ee7a7aSBaptiste Daroussin 
13634bf54857SBaptiste Daroussin 		parser->cur_file = old_curfile;
13644bf54857SBaptiste Daroussin 		DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
13654bf54857SBaptiste Daroussin 			if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
13664bf54857SBaptiste Daroussin 				DL_DELETE (parser->variables, cur_var);
13674bf54857SBaptiste Daroussin 				free (cur_var->var);
13684bf54857SBaptiste Daroussin 				free (cur_var->value);
13694bf54857SBaptiste Daroussin 				UCL_FREE (sizeof (struct ucl_variable), cur_var);
1370*a0409676SBaptiste Daroussin 			} else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
13714bf54857SBaptiste Daroussin 				DL_DELETE (parser->variables, cur_var);
13724bf54857SBaptiste Daroussin 				free (cur_var->var);
13734bf54857SBaptiste Daroussin 				free (cur_var->value);
13744bf54857SBaptiste Daroussin 				UCL_FREE (sizeof (struct ucl_variable), cur_var);
13754bf54857SBaptiste Daroussin 			}
13764bf54857SBaptiste Daroussin 		}
13774bf54857SBaptiste Daroussin 		if (old_filename) {
13784bf54857SBaptiste Daroussin 			DL_APPEND (parser->variables, old_filename);
13794bf54857SBaptiste Daroussin 		}
13804bf54857SBaptiste Daroussin 		if (old_curdir) {
13814bf54857SBaptiste Daroussin 			DL_APPEND (parser->variables, old_curdir);
13824bf54857SBaptiste Daroussin 		}
1383c99fb5f9SBaptiste Daroussin 
1384c99fb5f9SBaptiste Daroussin 		parser->state = prev_state;
1385*a0409676SBaptiste Daroussin 	}
1386c99fb5f9SBaptiste Daroussin 
1387c99fb5f9SBaptiste Daroussin 	if (buflen > 0) {
138897bd480fSBaptiste Daroussin 		ucl_munmap (buf, buflen);
1389c99fb5f9SBaptiste Daroussin 	}
1390c99fb5f9SBaptiste Daroussin 
1391c99fb5f9SBaptiste Daroussin 	return res;
1392c99fb5f9SBaptiste Daroussin }
1393c99fb5f9SBaptiste Daroussin 
1394c99fb5f9SBaptiste Daroussin /**
13954bf54857SBaptiste Daroussin  * Include a file to configuration
13964bf54857SBaptiste Daroussin  * @param data
13974bf54857SBaptiste Daroussin  * @param len
13984bf54857SBaptiste Daroussin  * @param parser
13994bf54857SBaptiste Daroussin  * @param err
14004bf54857SBaptiste Daroussin  * @return
14014bf54857SBaptiste Daroussin  */
14024bf54857SBaptiste Daroussin static bool
14034bf54857SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len,
1404*a0409676SBaptiste Daroussin 				  struct ucl_parser *parser,
1405*a0409676SBaptiste Daroussin 				  struct ucl_include_params *params,
1406*a0409676SBaptiste Daroussin 				  const ucl_object_t *args)
14074bf54857SBaptiste Daroussin {
14084bf54857SBaptiste Daroussin 	const unsigned char *p = data, *end = data + len;
14094bf54857SBaptiste Daroussin 	bool need_glob = false;
14104bf54857SBaptiste Daroussin 	int cnt = 0;
14114bf54857SBaptiste Daroussin 	char glob_pattern[PATH_MAX];
14124bf54857SBaptiste Daroussin 	size_t i;
14134bf54857SBaptiste Daroussin 
14148e3b1ab2SBaptiste Daroussin #ifndef _WIN32
141539ee7a7aSBaptiste Daroussin 	if (!params->allow_glob) {
141639ee7a7aSBaptiste Daroussin 		return ucl_include_file_single (data, len, parser, params);
14174bf54857SBaptiste Daroussin 	}
14184bf54857SBaptiste Daroussin 	else {
14194bf54857SBaptiste Daroussin 		/* Check for special symbols in a filename */
14204bf54857SBaptiste Daroussin 		while (p != end) {
14214bf54857SBaptiste Daroussin 			if (*p == '*' || *p == '?') {
14224bf54857SBaptiste Daroussin 				need_glob = true;
14234bf54857SBaptiste Daroussin 				break;
14244bf54857SBaptiste Daroussin 			}
14254bf54857SBaptiste Daroussin 			p ++;
14264bf54857SBaptiste Daroussin 		}
14274bf54857SBaptiste Daroussin 		if (need_glob) {
14288e3b1ab2SBaptiste Daroussin 			glob_t globbuf;
14294bf54857SBaptiste Daroussin 			memset (&globbuf, 0, sizeof (globbuf));
143039ee7a7aSBaptiste Daroussin 			ucl_strlcpy (glob_pattern, (const char *)data,
143139ee7a7aSBaptiste Daroussin 				(len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern)));
14324bf54857SBaptiste Daroussin 			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
143339ee7a7aSBaptiste Daroussin 				return (!params->must_exist || false);
14344bf54857SBaptiste Daroussin 			}
14354bf54857SBaptiste Daroussin 			for (i = 0; i < globbuf.gl_pathc; i ++) {
1436*a0409676SBaptiste Daroussin 
1437*a0409676SBaptiste Daroussin 				if (parser->include_trace_func) {
1438*a0409676SBaptiste Daroussin 					const ucl_object_t *parent = NULL;
1439*a0409676SBaptiste Daroussin 
1440*a0409676SBaptiste Daroussin 					if (parser->stack) {
1441*a0409676SBaptiste Daroussin 						parent = parser->stack->obj;
1442*a0409676SBaptiste Daroussin 					}
1443*a0409676SBaptiste Daroussin 
1444*a0409676SBaptiste Daroussin 					parser->include_trace_func (parser, parent, NULL,
1445*a0409676SBaptiste Daroussin 							globbuf.gl_pathv[i],
1446*a0409676SBaptiste Daroussin 							strlen (globbuf.gl_pathv[i]),
1447*a0409676SBaptiste Daroussin 							parser->include_trace_ud);
1448*a0409676SBaptiste Daroussin 				}
1449*a0409676SBaptiste Daroussin 
14504bf54857SBaptiste Daroussin 				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
145139ee7a7aSBaptiste Daroussin 						strlen (globbuf.gl_pathv[i]), parser, params)) {
145239ee7a7aSBaptiste Daroussin 					if (params->soft_fail) {
145339ee7a7aSBaptiste Daroussin 						continue;
145439ee7a7aSBaptiste Daroussin 					}
14554bf54857SBaptiste Daroussin 					globfree (&globbuf);
14564bf54857SBaptiste Daroussin 					return false;
14574bf54857SBaptiste Daroussin 				}
14584bf54857SBaptiste Daroussin 				cnt ++;
14594bf54857SBaptiste Daroussin 			}
14604bf54857SBaptiste Daroussin 			globfree (&globbuf);
14614bf54857SBaptiste Daroussin 
146239ee7a7aSBaptiste Daroussin 			if (cnt == 0 && params->must_exist) {
14634bf54857SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
14644bf54857SBaptiste Daroussin 					glob_pattern);
14654bf54857SBaptiste Daroussin 				return false;
14664bf54857SBaptiste Daroussin 			}
14674bf54857SBaptiste Daroussin 		}
14684bf54857SBaptiste Daroussin 		else {
146939ee7a7aSBaptiste Daroussin 			return ucl_include_file_single (data, len, parser, params);
14704bf54857SBaptiste Daroussin 		}
14714bf54857SBaptiste Daroussin 	}
14728e3b1ab2SBaptiste Daroussin #else
14738e3b1ab2SBaptiste Daroussin 	/* Win32 compilers do not support globbing. Therefore, for Win32,
14748e3b1ab2SBaptiste Daroussin 	   treat allow_glob/need_glob as a NOOP and just return */
147539ee7a7aSBaptiste Daroussin 	return ucl_include_file_single (data, len, parser, params);
14768e3b1ab2SBaptiste Daroussin #endif
14774bf54857SBaptiste Daroussin 
14784bf54857SBaptiste Daroussin 	return true;
14794bf54857SBaptiste Daroussin }
14804bf54857SBaptiste Daroussin 
14814bf54857SBaptiste Daroussin /**
14824bf54857SBaptiste Daroussin  * Common function to handle .*include* macros
14834bf54857SBaptiste Daroussin  * @param data
14844bf54857SBaptiste Daroussin  * @param len
14854bf54857SBaptiste Daroussin  * @param args
14864bf54857SBaptiste Daroussin  * @param parser
14874bf54857SBaptiste Daroussin  * @param default_try
14884bf54857SBaptiste Daroussin  * @param default_sign
14894bf54857SBaptiste Daroussin  * @return
14904bf54857SBaptiste Daroussin  */
14914bf54857SBaptiste Daroussin static bool
14924bf54857SBaptiste Daroussin ucl_include_common (const unsigned char *data, size_t len,
14934bf54857SBaptiste Daroussin 		const ucl_object_t *args, struct ucl_parser *parser,
14944bf54857SBaptiste Daroussin 		bool default_try,
14954bf54857SBaptiste Daroussin 		bool default_sign)
14964bf54857SBaptiste Daroussin {
1497d9f0ce31SBaptiste Daroussin 	bool allow_url = false, search = false;
149839ee7a7aSBaptiste Daroussin 	const char *duplicate;
14994bf54857SBaptiste Daroussin 	const ucl_object_t *param;
150039ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL, ip = NULL;
150139ee7a7aSBaptiste Daroussin 	char ipath[PATH_MAX];
150239ee7a7aSBaptiste Daroussin 	struct ucl_include_params params;
15034bf54857SBaptiste Daroussin 
15044bf54857SBaptiste Daroussin 	/* Default values */
150539ee7a7aSBaptiste Daroussin 	params.soft_fail = default_try;
150639ee7a7aSBaptiste Daroussin 	params.allow_glob = false;
150739ee7a7aSBaptiste Daroussin 	params.check_signature = default_sign;
150839ee7a7aSBaptiste Daroussin 	params.use_prefix = false;
150939ee7a7aSBaptiste Daroussin 	params.target = "object";
151039ee7a7aSBaptiste Daroussin 	params.prefix = NULL;
151139ee7a7aSBaptiste Daroussin 	params.priority = 0;
151239ee7a7aSBaptiste Daroussin 	params.parse_type = UCL_PARSE_UCL;
151339ee7a7aSBaptiste Daroussin 	params.strat = UCL_DUPLICATE_APPEND;
151439ee7a7aSBaptiste Daroussin 	params.must_exist = !default_try;
151539ee7a7aSBaptiste Daroussin 
1516*a0409676SBaptiste Daroussin 	if (parser->include_trace_func) {
1517*a0409676SBaptiste Daroussin 		const ucl_object_t *parent = NULL;
1518*a0409676SBaptiste Daroussin 
1519*a0409676SBaptiste Daroussin 		if (parser->stack) {
1520*a0409676SBaptiste Daroussin 			parent = parser->stack->obj;
1521*a0409676SBaptiste Daroussin 		}
1522*a0409676SBaptiste Daroussin 
1523*a0409676SBaptiste Daroussin 		parser->include_trace_func (parser, parent, args,
1524*a0409676SBaptiste Daroussin 				data, len, parser->include_trace_ud);
1525*a0409676SBaptiste Daroussin 	}
1526*a0409676SBaptiste Daroussin 
15274bf54857SBaptiste Daroussin 	/* Process arguments */
15284bf54857SBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1529d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
15304bf54857SBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
153139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
153239ee7a7aSBaptiste Daroussin 					params.must_exist = !ucl_object_toboolean (param);
15334bf54857SBaptiste Daroussin 				}
153439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "sign", param->keylen) == 0) {
153539ee7a7aSBaptiste Daroussin 					params.check_signature = ucl_object_toboolean (param);
15364bf54857SBaptiste Daroussin 				}
153739ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "glob", param->keylen) == 0) {
153839ee7a7aSBaptiste Daroussin 					params.allow_glob = ucl_object_toboolean (param);
15394bf54857SBaptiste Daroussin 				}
154039ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "url", param->keylen) == 0) {
15414bf54857SBaptiste Daroussin 					allow_url = ucl_object_toboolean (param);
15424bf54857SBaptiste Daroussin 				}
154339ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "prefix", param->keylen) == 0) {
154439ee7a7aSBaptiste Daroussin 					params.use_prefix = ucl_object_toboolean (param);
154539ee7a7aSBaptiste Daroussin 				}
154639ee7a7aSBaptiste Daroussin 			}
154739ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
154839ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
154939ee7a7aSBaptiste Daroussin 					params.prefix = ucl_object_tostring (param);
155039ee7a7aSBaptiste Daroussin 				}
155139ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
155239ee7a7aSBaptiste Daroussin 					params.target = ucl_object_tostring (param);
155339ee7a7aSBaptiste Daroussin 				}
155439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "duplicate", param->keylen) == 0) {
155539ee7a7aSBaptiste Daroussin 					duplicate = ucl_object_tostring (param);
155639ee7a7aSBaptiste Daroussin 
155739ee7a7aSBaptiste Daroussin 					if (strcmp (duplicate, "append") == 0) {
155839ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_APPEND;
155939ee7a7aSBaptiste Daroussin 					}
156039ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "merge") == 0) {
156139ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_MERGE;
156239ee7a7aSBaptiste Daroussin 					}
156339ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "rewrite") == 0) {
156439ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_REWRITE;
156539ee7a7aSBaptiste Daroussin 					}
156639ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "error") == 0) {
156739ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_ERROR;
156839ee7a7aSBaptiste Daroussin 					}
156939ee7a7aSBaptiste Daroussin 				}
157039ee7a7aSBaptiste Daroussin 			}
157139ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_ARRAY) {
157239ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "path", param->keylen) == 0) {
157339ee7a7aSBaptiste Daroussin 					ucl_set_include_path (parser, __DECONST(ucl_object_t *, param));
157439ee7a7aSBaptiste Daroussin 				}
15754bf54857SBaptiste Daroussin 			}
15764bf54857SBaptiste Daroussin 			else if (param->type == UCL_INT) {
157739ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
157839ee7a7aSBaptiste Daroussin 					params.priority = ucl_object_toint (param);
1579*a0409676SBaptiste Daroussin 					if (params.priority > UCL_PRIORITY_MAX) {
1580*a0409676SBaptiste Daroussin 						ucl_create_err (&parser->err, "Invalid priority value in macro: %d",
1581*a0409676SBaptiste Daroussin 							params.priority);
1582*a0409676SBaptiste Daroussin 						return false;
1583*a0409676SBaptiste Daroussin 					}
15844bf54857SBaptiste Daroussin 				}
15854bf54857SBaptiste Daroussin 			}
15864bf54857SBaptiste Daroussin 		}
15874bf54857SBaptiste Daroussin 	}
15884bf54857SBaptiste Daroussin 
158939ee7a7aSBaptiste Daroussin 	if (parser->includepaths == NULL) {
159039ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
15914bf54857SBaptiste Daroussin 			/* Globbing is not used for URL's */
159239ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
159339ee7a7aSBaptiste Daroussin 		}
159439ee7a7aSBaptiste Daroussin 		else if (data != NULL) {
159539ee7a7aSBaptiste Daroussin 			/* Try to load a file */
1596*a0409676SBaptiste Daroussin 			return ucl_include_file (data, len, parser, &params, args);
159739ee7a7aSBaptiste Daroussin 		}
159839ee7a7aSBaptiste Daroussin 	}
159939ee7a7aSBaptiste Daroussin 	else {
160039ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
160139ee7a7aSBaptiste Daroussin 			/* Globbing is not used for URL's */
160239ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
160339ee7a7aSBaptiste Daroussin 		}
160439ee7a7aSBaptiste Daroussin 
160539ee7a7aSBaptiste Daroussin 		ip = ucl_object_iterate_new (parser->includepaths);
160639ee7a7aSBaptiste Daroussin 		while ((param = ucl_object_iterate_safe (ip, true)) != NULL) {
160739ee7a7aSBaptiste Daroussin 			if (ucl_object_type(param) == UCL_STRING) {
160839ee7a7aSBaptiste Daroussin 				snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param),
160939ee7a7aSBaptiste Daroussin 						(int)len, data);
161039ee7a7aSBaptiste Daroussin 				if ((search = ucl_include_file (ipath, strlen (ipath),
1611*a0409676SBaptiste Daroussin 						parser, &params, args))) {
161239ee7a7aSBaptiste Daroussin 					if (!params.allow_glob) {
161339ee7a7aSBaptiste Daroussin 						break;
161439ee7a7aSBaptiste Daroussin 					}
161539ee7a7aSBaptiste Daroussin 				}
161639ee7a7aSBaptiste Daroussin 			}
161739ee7a7aSBaptiste Daroussin 		}
161839ee7a7aSBaptiste Daroussin 		ucl_object_iterate_free (ip);
161939ee7a7aSBaptiste Daroussin 		if (search == true) {
162039ee7a7aSBaptiste Daroussin 			return true;
162139ee7a7aSBaptiste Daroussin 		}
162239ee7a7aSBaptiste Daroussin 		else {
162339ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err,
162439ee7a7aSBaptiste Daroussin 					"cannot find file: %.*s in search path",
162539ee7a7aSBaptiste Daroussin 					(int)len, data);
162639ee7a7aSBaptiste Daroussin 			return false;
162739ee7a7aSBaptiste Daroussin 		}
16284bf54857SBaptiste Daroussin 	}
16294bf54857SBaptiste Daroussin 
16304bf54857SBaptiste Daroussin 	return false;
16314bf54857SBaptiste Daroussin }
16324bf54857SBaptiste Daroussin 
16334bf54857SBaptiste Daroussin /**
1634c99fb5f9SBaptiste Daroussin  * Handle include macro
1635c99fb5f9SBaptiste Daroussin  * @param data include data
1636c99fb5f9SBaptiste Daroussin  * @param len length of data
163739ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1638c99fb5f9SBaptiste Daroussin  * @param ud user data
1639c99fb5f9SBaptiste Daroussin  * @return
1640c99fb5f9SBaptiste Daroussin  */
164139ee7a7aSBaptiste Daroussin bool
16424bf54857SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len,
16434bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1644c99fb5f9SBaptiste Daroussin {
1645c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1646c99fb5f9SBaptiste Daroussin 
16474bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, false);
1648c99fb5f9SBaptiste Daroussin }
1649c99fb5f9SBaptiste Daroussin 
1650c99fb5f9SBaptiste Daroussin /**
1651c99fb5f9SBaptiste Daroussin  * Handle includes macro
1652c99fb5f9SBaptiste Daroussin  * @param data include data
1653c99fb5f9SBaptiste Daroussin  * @param len length of data
165439ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1655c99fb5f9SBaptiste Daroussin  * @param ud user data
1656c99fb5f9SBaptiste Daroussin  * @return
1657c99fb5f9SBaptiste Daroussin  */
165839ee7a7aSBaptiste Daroussin bool
16594bf54857SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len,
16604bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1661c99fb5f9SBaptiste Daroussin {
1662c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1663c99fb5f9SBaptiste Daroussin 
16644bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, true);
1665c99fb5f9SBaptiste Daroussin }
1666c99fb5f9SBaptiste Daroussin 
166739ee7a7aSBaptiste Daroussin /**
166839ee7a7aSBaptiste Daroussin  * Handle tryinclude macro
166939ee7a7aSBaptiste Daroussin  * @param data include data
167039ee7a7aSBaptiste Daroussin  * @param len length of data
167139ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
167239ee7a7aSBaptiste Daroussin  * @param ud user data
167339ee7a7aSBaptiste Daroussin  * @return
167439ee7a7aSBaptiste Daroussin  */
167539ee7a7aSBaptiste Daroussin bool
16764bf54857SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len,
16774bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1678c99fb5f9SBaptiste Daroussin {
1679c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1680c99fb5f9SBaptiste Daroussin 
16814bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, true, false);
1682c99fb5f9SBaptiste Daroussin }
1683c99fb5f9SBaptiste Daroussin 
168439ee7a7aSBaptiste Daroussin /**
168539ee7a7aSBaptiste Daroussin  * Handle priority macro
168639ee7a7aSBaptiste Daroussin  * @param data include data
168739ee7a7aSBaptiste Daroussin  * @param len length of data
168839ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
168939ee7a7aSBaptiste Daroussin  * @param ud user data
169039ee7a7aSBaptiste Daroussin  * @return
169139ee7a7aSBaptiste Daroussin  */
169239ee7a7aSBaptiste Daroussin bool
169339ee7a7aSBaptiste Daroussin ucl_priority_handler (const unsigned char *data, size_t len,
169439ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
169539ee7a7aSBaptiste Daroussin {
169639ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
169739ee7a7aSBaptiste Daroussin 	unsigned priority = 255;
169839ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
169939ee7a7aSBaptiste Daroussin 	bool found = false;
170039ee7a7aSBaptiste Daroussin 	char *value = NULL, *leftover = NULL;
170139ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
170239ee7a7aSBaptiste Daroussin 
170339ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
170439ee7a7aSBaptiste Daroussin 		return false;
170539ee7a7aSBaptiste Daroussin 	}
170639ee7a7aSBaptiste Daroussin 
170739ee7a7aSBaptiste Daroussin 	/* Process arguments */
170839ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1709d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
171039ee7a7aSBaptiste Daroussin 			if (param->type == UCL_INT) {
171139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
171239ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
171339ee7a7aSBaptiste Daroussin 					found = true;
171439ee7a7aSBaptiste Daroussin 				}
171539ee7a7aSBaptiste Daroussin 			}
171639ee7a7aSBaptiste Daroussin 		}
171739ee7a7aSBaptiste Daroussin 	}
171839ee7a7aSBaptiste Daroussin 
171939ee7a7aSBaptiste Daroussin 	if (len > 0) {
172039ee7a7aSBaptiste Daroussin 		value = malloc(len + 1);
172139ee7a7aSBaptiste Daroussin 		ucl_strlcpy(value, (const char *)data, len + 1);
1722*a0409676SBaptiste Daroussin 		errno = 0;
1723*a0409676SBaptiste Daroussin 		priority = strtoul(value, &leftover, 10);
1724*a0409676SBaptiste Daroussin 		if (errno != 0 || *leftover != '\0' || priority > UCL_PRIORITY_MAX) {
172539ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Invalid priority value in macro: %s",
172639ee7a7aSBaptiste Daroussin 				value);
172739ee7a7aSBaptiste Daroussin 			free(value);
172839ee7a7aSBaptiste Daroussin 			return false;
172939ee7a7aSBaptiste Daroussin 		}
173039ee7a7aSBaptiste Daroussin 		free(value);
173139ee7a7aSBaptiste Daroussin 		found = true;
173239ee7a7aSBaptiste Daroussin 	}
173339ee7a7aSBaptiste Daroussin 
173439ee7a7aSBaptiste Daroussin 	if (found == true) {
173539ee7a7aSBaptiste Daroussin 		parser->chunks->priority = priority;
173639ee7a7aSBaptiste Daroussin 		return true;
173739ee7a7aSBaptiste Daroussin 	}
173839ee7a7aSBaptiste Daroussin 
173939ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse priority macro");
174039ee7a7aSBaptiste Daroussin 	return false;
174139ee7a7aSBaptiste Daroussin }
174239ee7a7aSBaptiste Daroussin 
174339ee7a7aSBaptiste Daroussin /**
174439ee7a7aSBaptiste Daroussin  * Handle load macro
174539ee7a7aSBaptiste Daroussin  * @param data include data
174639ee7a7aSBaptiste Daroussin  * @param len length of data
174739ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
174839ee7a7aSBaptiste Daroussin  * @param ud user data
174939ee7a7aSBaptiste Daroussin  * @return
175039ee7a7aSBaptiste Daroussin  */
175139ee7a7aSBaptiste Daroussin bool
175239ee7a7aSBaptiste Daroussin ucl_load_handler (const unsigned char *data, size_t len,
175339ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
175439ee7a7aSBaptiste Daroussin {
175539ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
175639ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
175739ee7a7aSBaptiste Daroussin 	ucl_object_t *obj, *old_obj;
175839ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
175939ee7a7aSBaptiste Daroussin 	bool try_load, multiline, test;
176039ee7a7aSBaptiste Daroussin 	const char *target, *prefix;
176139ee7a7aSBaptiste Daroussin 	char *load_file, *tmp;
176239ee7a7aSBaptiste Daroussin 	unsigned char *buf;
176339ee7a7aSBaptiste Daroussin 	size_t buflen;
176439ee7a7aSBaptiste Daroussin 	unsigned priority;
176539ee7a7aSBaptiste Daroussin 	int64_t iv;
1766d9f0ce31SBaptiste Daroussin 	ucl_object_t *container = NULL;
176739ee7a7aSBaptiste Daroussin 	enum ucl_string_flags flags;
176839ee7a7aSBaptiste Daroussin 
176939ee7a7aSBaptiste Daroussin 	/* Default values */
177039ee7a7aSBaptiste Daroussin 	try_load = false;
177139ee7a7aSBaptiste Daroussin 	multiline = false;
177239ee7a7aSBaptiste Daroussin 	test = false;
177339ee7a7aSBaptiste Daroussin 	target = "string";
177439ee7a7aSBaptiste Daroussin 	prefix = NULL;
177539ee7a7aSBaptiste Daroussin 	load_file = NULL;
177639ee7a7aSBaptiste Daroussin 	buf = NULL;
177739ee7a7aSBaptiste Daroussin 	buflen = 0;
177839ee7a7aSBaptiste Daroussin 	priority = 0;
177939ee7a7aSBaptiste Daroussin 	obj = NULL;
178039ee7a7aSBaptiste Daroussin 	old_obj = NULL;
178139ee7a7aSBaptiste Daroussin 	flags = 0;
178239ee7a7aSBaptiste Daroussin 
178339ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
178439ee7a7aSBaptiste Daroussin 		return false;
178539ee7a7aSBaptiste Daroussin 	}
178639ee7a7aSBaptiste Daroussin 
178739ee7a7aSBaptiste Daroussin 	/* Process arguments */
178839ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1789d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
179039ee7a7aSBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
179139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
179239ee7a7aSBaptiste Daroussin 					try_load = ucl_object_toboolean (param);
179339ee7a7aSBaptiste Daroussin 				}
179439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "multiline", param->keylen) == 0) {
179539ee7a7aSBaptiste Daroussin 					multiline = ucl_object_toboolean (param);
179639ee7a7aSBaptiste Daroussin 				}
179739ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "escape", param->keylen) == 0) {
179839ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
179939ee7a7aSBaptiste Daroussin 					if (test) {
180039ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_ESCAPE;
180139ee7a7aSBaptiste Daroussin 					}
180239ee7a7aSBaptiste Daroussin 				}
180339ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "trim", param->keylen) == 0) {
180439ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
180539ee7a7aSBaptiste Daroussin 					if (test) {
180639ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_TRIM;
180739ee7a7aSBaptiste Daroussin 					}
180839ee7a7aSBaptiste Daroussin 				}
180939ee7a7aSBaptiste Daroussin 			}
181039ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
181139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
181239ee7a7aSBaptiste Daroussin 					prefix = ucl_object_tostring (param);
181339ee7a7aSBaptiste Daroussin 				}
181439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
181539ee7a7aSBaptiste Daroussin 					target = ucl_object_tostring (param);
181639ee7a7aSBaptiste Daroussin 				}
181739ee7a7aSBaptiste Daroussin 			}
181839ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_INT) {
181939ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
182039ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
182139ee7a7aSBaptiste Daroussin 				}
182239ee7a7aSBaptiste Daroussin 			}
182339ee7a7aSBaptiste Daroussin 		}
182439ee7a7aSBaptiste Daroussin 	}
182539ee7a7aSBaptiste Daroussin 
182639ee7a7aSBaptiste Daroussin 	if (prefix == NULL || strlen (prefix) == 0) {
182739ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "No Key specified in load macro");
182839ee7a7aSBaptiste Daroussin 		return false;
182939ee7a7aSBaptiste Daroussin 	}
183039ee7a7aSBaptiste Daroussin 
183139ee7a7aSBaptiste Daroussin 	if (len > 0) {
1832d9f0ce31SBaptiste Daroussin 		load_file = malloc (len + 1);
1833d9f0ce31SBaptiste Daroussin 		if (!load_file) {
1834d9f0ce31SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for suffix");
1835d9f0ce31SBaptiste Daroussin 
1836d9f0ce31SBaptiste Daroussin 			return false;
1837d9f0ce31SBaptiste Daroussin 		}
1838d9f0ce31SBaptiste Daroussin 
1839d9f0ce31SBaptiste Daroussin 		snprintf (load_file, len + 1, "%.*s", (int)len, data);
1840d9f0ce31SBaptiste Daroussin 
1841d9f0ce31SBaptiste Daroussin 		if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err,
1842d9f0ce31SBaptiste Daroussin 				!try_load)) {
1843d9f0ce31SBaptiste Daroussin 			free (load_file);
1844d9f0ce31SBaptiste Daroussin 
184539ee7a7aSBaptiste Daroussin 			return (try_load || false);
184639ee7a7aSBaptiste Daroussin 		}
184739ee7a7aSBaptiste Daroussin 
1848d9f0ce31SBaptiste Daroussin 		free (load_file);
1849d9f0ce31SBaptiste Daroussin 		container = parser->stack->obj;
1850d9f0ce31SBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_object_lookup (container,
1851d9f0ce31SBaptiste Daroussin 				prefix));
1852d9f0ce31SBaptiste Daroussin 
185339ee7a7aSBaptiste Daroussin 		if (old_obj != NULL) {
185439ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Key %s already exists", prefix);
1855d9f0ce31SBaptiste Daroussin 			if (buf) {
1856d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1857d9f0ce31SBaptiste Daroussin 			}
1858d9f0ce31SBaptiste Daroussin 
185939ee7a7aSBaptiste Daroussin 			return false;
186039ee7a7aSBaptiste Daroussin 		}
186139ee7a7aSBaptiste Daroussin 
186239ee7a7aSBaptiste Daroussin 		if (strcasecmp (target, "string") == 0) {
186339ee7a7aSBaptiste Daroussin 			obj = ucl_object_fromstring_common (buf, buflen, flags);
186439ee7a7aSBaptiste Daroussin 			ucl_copy_value_trash (obj);
186539ee7a7aSBaptiste Daroussin 			if (multiline) {
186639ee7a7aSBaptiste Daroussin 				obj->flags |= UCL_OBJECT_MULTILINE;
186739ee7a7aSBaptiste Daroussin 			}
186839ee7a7aSBaptiste Daroussin 		}
186939ee7a7aSBaptiste Daroussin 		else if (strcasecmp (target, "int") == 0) {
1870d9f0ce31SBaptiste Daroussin 			tmp = malloc (buflen + 1);
1871d9f0ce31SBaptiste Daroussin 
1872d9f0ce31SBaptiste Daroussin 			if (tmp == NULL) {
1873d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "Memory allocation failed");
1874d9f0ce31SBaptiste Daroussin 				if (buf) {
1875d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
187639ee7a7aSBaptiste Daroussin 				}
187739ee7a7aSBaptiste Daroussin 
1878d9f0ce31SBaptiste Daroussin 				return false;
1879d9f0ce31SBaptiste Daroussin 			}
1880d9f0ce31SBaptiste Daroussin 
1881d9f0ce31SBaptiste Daroussin 			snprintf (tmp, buflen + 1, "%.*s", (int)buflen, buf);
1882d9f0ce31SBaptiste Daroussin 			iv = strtoll (tmp, NULL, 10);
1883d9f0ce31SBaptiste Daroussin 			obj = ucl_object_fromint (iv);
1884d9f0ce31SBaptiste Daroussin 			free (tmp);
1885d9f0ce31SBaptiste Daroussin 		}
1886d9f0ce31SBaptiste Daroussin 
1887d9f0ce31SBaptiste Daroussin 		if (buf) {
188839ee7a7aSBaptiste Daroussin 			ucl_munmap (buf, buflen);
188939ee7a7aSBaptiste Daroussin 		}
189039ee7a7aSBaptiste Daroussin 
189139ee7a7aSBaptiste Daroussin 		if (obj != NULL) {
189239ee7a7aSBaptiste Daroussin 			obj->key = prefix;
189339ee7a7aSBaptiste Daroussin 			obj->keylen = strlen (prefix);
189439ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash (obj);
189539ee7a7aSBaptiste Daroussin 			obj->prev = obj;
189639ee7a7aSBaptiste Daroussin 			obj->next = NULL;
189739ee7a7aSBaptiste Daroussin 			ucl_object_set_priority (obj, priority);
1898d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (container, obj, obj->key, obj->keylen, false);
189939ee7a7aSBaptiste Daroussin 		}
1900d9f0ce31SBaptiste Daroussin 
190139ee7a7aSBaptiste Daroussin 		return true;
190239ee7a7aSBaptiste Daroussin 	}
190339ee7a7aSBaptiste Daroussin 
190439ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse load macro");
190539ee7a7aSBaptiste Daroussin 	return false;
190639ee7a7aSBaptiste Daroussin }
190739ee7a7aSBaptiste Daroussin 
190839ee7a7aSBaptiste Daroussin bool
190939ee7a7aSBaptiste Daroussin ucl_inherit_handler (const unsigned char *data, size_t len,
191039ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, const ucl_object_t *ctx, void* ud)
191139ee7a7aSBaptiste Daroussin {
191239ee7a7aSBaptiste Daroussin 	const ucl_object_t *parent, *cur;
191339ee7a7aSBaptiste Daroussin 	ucl_object_t *target, *copy;
191439ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
191539ee7a7aSBaptiste Daroussin 	bool replace = false;
191639ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
191739ee7a7aSBaptiste Daroussin 
1918d9f0ce31SBaptiste Daroussin 	parent = ucl_object_lookup_len (ctx, data, len);
191939ee7a7aSBaptiste Daroussin 
192039ee7a7aSBaptiste Daroussin 	/* Some sanity checks */
192139ee7a7aSBaptiste Daroussin 	if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) {
192239ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Unable to find inherited object %*.s",
192339ee7a7aSBaptiste Daroussin 				(int)len, data);
192439ee7a7aSBaptiste Daroussin 		return false;
192539ee7a7aSBaptiste Daroussin 	}
192639ee7a7aSBaptiste Daroussin 
192739ee7a7aSBaptiste Daroussin 	if (parser->stack == NULL || parser->stack->obj == NULL ||
192839ee7a7aSBaptiste Daroussin 			ucl_object_type (parser->stack->obj) != UCL_OBJECT) {
192939ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Invalid inherit context");
193039ee7a7aSBaptiste Daroussin 		return false;
193139ee7a7aSBaptiste Daroussin 	}
193239ee7a7aSBaptiste Daroussin 
193339ee7a7aSBaptiste Daroussin 	target = parser->stack->obj;
193439ee7a7aSBaptiste Daroussin 
1935d9f0ce31SBaptiste Daroussin 	if (args && (cur = ucl_object_lookup (args, "replace")) != NULL) {
193639ee7a7aSBaptiste Daroussin 		replace = ucl_object_toboolean (cur);
193739ee7a7aSBaptiste Daroussin 	}
193839ee7a7aSBaptiste Daroussin 
1939d9f0ce31SBaptiste Daroussin 	while ((cur = ucl_object_iterate (parent, &it, true))) {
194039ee7a7aSBaptiste Daroussin 		/* We do not replace existing keys */
1941d9f0ce31SBaptiste Daroussin 		if (!replace && ucl_object_lookup_len (target, cur->key, cur->keylen)) {
194239ee7a7aSBaptiste Daroussin 			continue;
194339ee7a7aSBaptiste Daroussin 		}
194439ee7a7aSBaptiste Daroussin 
194539ee7a7aSBaptiste Daroussin 		copy = ucl_object_copy (cur);
194639ee7a7aSBaptiste Daroussin 
194739ee7a7aSBaptiste Daroussin 		if (!replace) {
194839ee7a7aSBaptiste Daroussin 			copy->flags |= UCL_OBJECT_INHERITED;
194939ee7a7aSBaptiste Daroussin 		}
195039ee7a7aSBaptiste Daroussin 
195139ee7a7aSBaptiste Daroussin 		ucl_object_insert_key (target, copy, copy->key,
195239ee7a7aSBaptiste Daroussin 				copy->keylen, false);
195339ee7a7aSBaptiste Daroussin 	}
195439ee7a7aSBaptiste Daroussin 
195539ee7a7aSBaptiste Daroussin 	return true;
195639ee7a7aSBaptiste Daroussin }
195739ee7a7aSBaptiste Daroussin 
195839ee7a7aSBaptiste Daroussin bool
1959c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
1960c99fb5f9SBaptiste Daroussin {
1961c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX], *curdir;
1962c99fb5f9SBaptiste Daroussin 
1963c99fb5f9SBaptiste Daroussin 	if (filename != NULL) {
1964c99fb5f9SBaptiste Daroussin 		if (need_expand) {
196597bd480fSBaptiste Daroussin 			if (ucl_realpath (filename, realbuf) == NULL) {
1966c99fb5f9SBaptiste Daroussin 				return false;
1967c99fb5f9SBaptiste Daroussin 			}
1968c99fb5f9SBaptiste Daroussin 		}
1969c99fb5f9SBaptiste Daroussin 		else {
1970c99fb5f9SBaptiste Daroussin 			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
1971c99fb5f9SBaptiste Daroussin 		}
1972c99fb5f9SBaptiste Daroussin 
1973*a0409676SBaptiste Daroussin 		if (parser->cur_file) {
1974*a0409676SBaptiste Daroussin 			free (parser->cur_file);
1975*a0409676SBaptiste Daroussin 		}
1976*a0409676SBaptiste Daroussin 
1977*a0409676SBaptiste Daroussin 		parser->cur_file = strdup (realbuf);
1978*a0409676SBaptiste Daroussin 
1979c99fb5f9SBaptiste Daroussin 		/* Define variables */
1980c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", realbuf);
1981c99fb5f9SBaptiste Daroussin 		curdir = dirname (realbuf);
1982c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1983c99fb5f9SBaptiste Daroussin 	}
1984c99fb5f9SBaptiste Daroussin 	else {
1985c99fb5f9SBaptiste Daroussin 		/* Set everything from the current dir */
1986c99fb5f9SBaptiste Daroussin 		curdir = getcwd (realbuf, sizeof (realbuf));
1987c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", "undef");
1988c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1989c99fb5f9SBaptiste Daroussin 	}
1990c99fb5f9SBaptiste Daroussin 
1991c99fb5f9SBaptiste Daroussin 	return true;
1992c99fb5f9SBaptiste Daroussin }
1993c99fb5f9SBaptiste Daroussin 
199439ee7a7aSBaptiste Daroussin bool
1995273c26a3SBaptiste Daroussin ucl_parser_add_file_full (struct ucl_parser *parser, const char *filename,
1996273c26a3SBaptiste Daroussin 		unsigned priority, enum ucl_duplicate_strategy strat,
1997273c26a3SBaptiste Daroussin 		enum ucl_parse_type parse_type)
1998c99fb5f9SBaptiste Daroussin {
1999c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
2000c99fb5f9SBaptiste Daroussin 	size_t len;
2001c99fb5f9SBaptiste Daroussin 	bool ret;
2002c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX];
2003c99fb5f9SBaptiste Daroussin 
200497bd480fSBaptiste Daroussin 	if (ucl_realpath (filename, realbuf) == NULL) {
2005c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
2006c99fb5f9SBaptiste Daroussin 				filename,
2007c99fb5f9SBaptiste Daroussin 				strerror (errno));
2008c99fb5f9SBaptiste Daroussin 		return false;
2009c99fb5f9SBaptiste Daroussin 	}
2010c99fb5f9SBaptiste Daroussin 
2011c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
2012c99fb5f9SBaptiste Daroussin 		return false;
2013c99fb5f9SBaptiste Daroussin 	}
2014c99fb5f9SBaptiste Daroussin 
2015c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
2016273c26a3SBaptiste Daroussin 	ret = ucl_parser_add_chunk_full (parser, buf, len, priority, strat,
2017273c26a3SBaptiste Daroussin 			parse_type);
2018c99fb5f9SBaptiste Daroussin 
2019c99fb5f9SBaptiste Daroussin 	if (len > 0) {
202097bd480fSBaptiste Daroussin 		ucl_munmap (buf, len);
2021c99fb5f9SBaptiste Daroussin 	}
2022c99fb5f9SBaptiste Daroussin 
2023c99fb5f9SBaptiste Daroussin 	return ret;
2024c99fb5f9SBaptiste Daroussin }
2025c99fb5f9SBaptiste Daroussin 
202639ee7a7aSBaptiste Daroussin bool
2027273c26a3SBaptiste Daroussin ucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename,
2028273c26a3SBaptiste Daroussin 		unsigned priority)
2029273c26a3SBaptiste Daroussin {
2030273c26a3SBaptiste Daroussin 	if (parser == NULL) {
2031273c26a3SBaptiste Daroussin 		return false;
2032273c26a3SBaptiste Daroussin 	}
2033273c26a3SBaptiste Daroussin 
2034273c26a3SBaptiste Daroussin 	return ucl_parser_add_file_full(parser, filename, priority,
2035273c26a3SBaptiste Daroussin 			UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2036273c26a3SBaptiste Daroussin }
2037273c26a3SBaptiste Daroussin 
2038273c26a3SBaptiste Daroussin bool
203939ee7a7aSBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
204039ee7a7aSBaptiste Daroussin {
204139ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
204239ee7a7aSBaptiste Daroussin 		return false;
204339ee7a7aSBaptiste Daroussin 	}
204439ee7a7aSBaptiste Daroussin 
2045273c26a3SBaptiste Daroussin 	return ucl_parser_add_file_full(parser, filename,
2046273c26a3SBaptiste Daroussin 			parser->default_priority, UCL_DUPLICATE_APPEND,
2047273c26a3SBaptiste Daroussin 			UCL_PARSE_UCL);
204839ee7a7aSBaptiste Daroussin }
204939ee7a7aSBaptiste Daroussin 
205011dd9ed6SBaptiste Daroussin 
205139ee7a7aSBaptiste Daroussin bool
205211dd9ed6SBaptiste Daroussin ucl_parser_add_fd_full (struct ucl_parser *parser, int fd,
205311dd9ed6SBaptiste Daroussin 		unsigned priority, enum ucl_duplicate_strategy strat,
205411dd9ed6SBaptiste Daroussin 		enum ucl_parse_type parse_type)
20554bf54857SBaptiste Daroussin {
20564bf54857SBaptiste Daroussin 	unsigned char *buf;
20574bf54857SBaptiste Daroussin 	size_t len;
20584bf54857SBaptiste Daroussin 	bool ret;
20594bf54857SBaptiste Daroussin 	struct stat st;
20604bf54857SBaptiste Daroussin 
20614bf54857SBaptiste Daroussin 	if (fstat (fd, &st) == -1) {
20624bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot stat fd %d: %s",
20634bf54857SBaptiste Daroussin 			fd, strerror (errno));
20644bf54857SBaptiste Daroussin 		return false;
20654bf54857SBaptiste Daroussin 	}
20666525738fSBaptiste Daroussin 	if (st.st_size == 0) {
20676525738fSBaptiste Daroussin 		return true;
20686525738fSBaptiste Daroussin 	}
20694bf54857SBaptiste Daroussin 	if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
20704bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
20714bf54857SBaptiste Daroussin 			fd, strerror (errno));
20724bf54857SBaptiste Daroussin 		return false;
20734bf54857SBaptiste Daroussin 	}
20744bf54857SBaptiste Daroussin 
20754bf54857SBaptiste Daroussin 	if (parser->cur_file) {
20764bf54857SBaptiste Daroussin 		free (parser->cur_file);
20774bf54857SBaptiste Daroussin 	}
20784bf54857SBaptiste Daroussin 	parser->cur_file = NULL;
20794bf54857SBaptiste Daroussin 	len = st.st_size;
208011dd9ed6SBaptiste Daroussin 	ret = ucl_parser_add_chunk_full (parser, buf, len, priority, strat,
208111dd9ed6SBaptiste Daroussin 			parse_type);
20824bf54857SBaptiste Daroussin 
20834bf54857SBaptiste Daroussin 	if (len > 0) {
20844bf54857SBaptiste Daroussin 		ucl_munmap (buf, len);
20854bf54857SBaptiste Daroussin 	}
20864bf54857SBaptiste Daroussin 
20874bf54857SBaptiste Daroussin 	return ret;
20884bf54857SBaptiste Daroussin }
20894bf54857SBaptiste Daroussin 
209039ee7a7aSBaptiste Daroussin bool
209111dd9ed6SBaptiste Daroussin ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
209211dd9ed6SBaptiste Daroussin 		unsigned priority)
209311dd9ed6SBaptiste Daroussin {
209411dd9ed6SBaptiste Daroussin 	if (parser == NULL) {
209511dd9ed6SBaptiste Daroussin 		return false;
209611dd9ed6SBaptiste Daroussin 	}
209711dd9ed6SBaptiste Daroussin 
209811dd9ed6SBaptiste Daroussin 	return ucl_parser_add_fd_full(parser, fd, parser->default_priority,
209911dd9ed6SBaptiste Daroussin 			UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
210011dd9ed6SBaptiste Daroussin }
210111dd9ed6SBaptiste Daroussin 
210211dd9ed6SBaptiste Daroussin bool
210339ee7a7aSBaptiste Daroussin ucl_parser_add_fd (struct ucl_parser *parser, int fd)
210439ee7a7aSBaptiste Daroussin {
210539ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
210639ee7a7aSBaptiste Daroussin 		return false;
210739ee7a7aSBaptiste Daroussin 	}
210839ee7a7aSBaptiste Daroussin 
210939ee7a7aSBaptiste Daroussin 	return ucl_parser_add_fd_priority(parser, fd, parser->default_priority);
211039ee7a7aSBaptiste Daroussin }
211139ee7a7aSBaptiste Daroussin 
2112c99fb5f9SBaptiste Daroussin size_t
2113c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz)
2114c99fb5f9SBaptiste Daroussin {
2115c99fb5f9SBaptiste Daroussin 	char *d = dst;
2116c99fb5f9SBaptiste Daroussin 	const char *s = src;
2117c99fb5f9SBaptiste Daroussin 	size_t n = siz;
2118c99fb5f9SBaptiste Daroussin 
2119c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
2120c99fb5f9SBaptiste Daroussin 	if (n != 0) {
2121c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
2122c99fb5f9SBaptiste Daroussin 			if ((*d++ = *s++) == '\0') {
2123c99fb5f9SBaptiste Daroussin 				break;
2124c99fb5f9SBaptiste Daroussin 			}
2125c99fb5f9SBaptiste Daroussin 		}
2126c99fb5f9SBaptiste Daroussin 	}
2127c99fb5f9SBaptiste Daroussin 
2128c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
2129c99fb5f9SBaptiste Daroussin 		*d = '\0';
2130c99fb5f9SBaptiste Daroussin 	}
2131c99fb5f9SBaptiste Daroussin 
2132c99fb5f9SBaptiste Daroussin 	return (s - src - 1);    /* count does not include NUL */
2133c99fb5f9SBaptiste Daroussin }
2134c99fb5f9SBaptiste Daroussin 
2135c99fb5f9SBaptiste Daroussin size_t
2136c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
2137c99fb5f9SBaptiste Daroussin {
2138c99fb5f9SBaptiste Daroussin 	memcpy (dst, src, siz - 1);
2139c99fb5f9SBaptiste Daroussin 	dst[siz - 1] = '\0';
2140c99fb5f9SBaptiste Daroussin 
2141c99fb5f9SBaptiste Daroussin 	return siz - 1;
2142c99fb5f9SBaptiste Daroussin }
2143c99fb5f9SBaptiste Daroussin 
2144c99fb5f9SBaptiste Daroussin size_t
2145c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
2146c99fb5f9SBaptiste Daroussin {
2147c99fb5f9SBaptiste Daroussin 	char *d = dst;
2148c99fb5f9SBaptiste Daroussin 	const char *s = src;
2149c99fb5f9SBaptiste Daroussin 	size_t n = siz;
2150c99fb5f9SBaptiste Daroussin 
2151c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
2152c99fb5f9SBaptiste Daroussin 	if (n != 0) {
2153c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
2154c99fb5f9SBaptiste Daroussin 			if ((*d++ = tolower (*s++)) == '\0') {
2155c99fb5f9SBaptiste Daroussin 				break;
2156c99fb5f9SBaptiste Daroussin 			}
2157c99fb5f9SBaptiste Daroussin 		}
2158c99fb5f9SBaptiste Daroussin 	}
2159c99fb5f9SBaptiste Daroussin 
2160c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
2161c99fb5f9SBaptiste Daroussin 		*d = '\0';
2162c99fb5f9SBaptiste Daroussin 	}
2163c99fb5f9SBaptiste Daroussin 
2164c99fb5f9SBaptiste Daroussin 	return (s - src);    /* count does not include NUL */
2165c99fb5f9SBaptiste Daroussin }
2166c99fb5f9SBaptiste Daroussin 
216739ee7a7aSBaptiste Daroussin /*
216839ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s
216939ee7a7aSBaptiste Daroussin  */
217039ee7a7aSBaptiste Daroussin char *
217139ee7a7aSBaptiste Daroussin ucl_strnstr (const char *s, const char *find, int len)
217239ee7a7aSBaptiste Daroussin {
217339ee7a7aSBaptiste Daroussin 	char c, sc;
217439ee7a7aSBaptiste Daroussin 	int mlen;
217539ee7a7aSBaptiste Daroussin 
217639ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
217739ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
217839ee7a7aSBaptiste Daroussin 		do {
217939ee7a7aSBaptiste Daroussin 			do {
218039ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
218139ee7a7aSBaptiste Daroussin 					return (NULL);
218239ee7a7aSBaptiste Daroussin 			} while (sc != c);
218339ee7a7aSBaptiste Daroussin 		} while (strncmp (s, find, mlen) != 0);
218439ee7a7aSBaptiste Daroussin 		s--;
218539ee7a7aSBaptiste Daroussin 	}
218639ee7a7aSBaptiste Daroussin 	return ((char *)s);
218739ee7a7aSBaptiste Daroussin }
218839ee7a7aSBaptiste Daroussin 
218939ee7a7aSBaptiste Daroussin /*
219039ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s, ignore case.
219139ee7a7aSBaptiste Daroussin  */
219239ee7a7aSBaptiste Daroussin char *
219339ee7a7aSBaptiste Daroussin ucl_strncasestr (const char *s, const char *find, int len)
219439ee7a7aSBaptiste Daroussin {
219539ee7a7aSBaptiste Daroussin 	char c, sc;
219639ee7a7aSBaptiste Daroussin 	int mlen;
219739ee7a7aSBaptiste Daroussin 
219839ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
219939ee7a7aSBaptiste Daroussin 		c = tolower (c);
220039ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
220139ee7a7aSBaptiste Daroussin 		do {
220239ee7a7aSBaptiste Daroussin 			do {
220339ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
220439ee7a7aSBaptiste Daroussin 					return (NULL);
220539ee7a7aSBaptiste Daroussin 			} while (tolower (sc) != c);
220639ee7a7aSBaptiste Daroussin 		} while (strncasecmp (s, find, mlen) != 0);
220739ee7a7aSBaptiste Daroussin 		s--;
220839ee7a7aSBaptiste Daroussin 	}
220939ee7a7aSBaptiste Daroussin 	return ((char *)s);
221039ee7a7aSBaptiste Daroussin }
221139ee7a7aSBaptiste Daroussin 
2212c99fb5f9SBaptiste Daroussin ucl_object_t *
2213c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
2214c99fb5f9SBaptiste Daroussin {
2215c99fb5f9SBaptiste Daroussin 	ucl_object_t *obj;
2216c99fb5f9SBaptiste Daroussin 	const char *start, *end, *p, *pos;
2217c99fb5f9SBaptiste Daroussin 	char *dst, *d;
2218c99fb5f9SBaptiste Daroussin 	size_t escaped_len;
2219c99fb5f9SBaptiste Daroussin 
2220c99fb5f9SBaptiste Daroussin 	if (str == NULL) {
2221c99fb5f9SBaptiste Daroussin 		return NULL;
2222c99fb5f9SBaptiste Daroussin 	}
2223c99fb5f9SBaptiste Daroussin 
2224c99fb5f9SBaptiste Daroussin 	obj = ucl_object_new ();
2225c99fb5f9SBaptiste Daroussin 	if (obj) {
2226c99fb5f9SBaptiste Daroussin 		if (len == 0) {
2227c99fb5f9SBaptiste Daroussin 			len = strlen (str);
2228c99fb5f9SBaptiste Daroussin 		}
2229c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_TRIM) {
2230c99fb5f9SBaptiste Daroussin 			/* Skip leading spaces */
2231c99fb5f9SBaptiste Daroussin 			for (start = str; (size_t)(start - str) < len; start ++) {
2232c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2233c99fb5f9SBaptiste Daroussin 					break;
2234c99fb5f9SBaptiste Daroussin 				}
2235c99fb5f9SBaptiste Daroussin 			}
2236c99fb5f9SBaptiste Daroussin 			/* Skip trailing spaces */
2237c99fb5f9SBaptiste Daroussin 			for (end = str + len - 1; end > start; end --) {
2238c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2239c99fb5f9SBaptiste Daroussin 					break;
2240c99fb5f9SBaptiste Daroussin 				}
2241c99fb5f9SBaptiste Daroussin 			}
2242c99fb5f9SBaptiste Daroussin 			end ++;
2243c99fb5f9SBaptiste Daroussin 		}
2244c99fb5f9SBaptiste Daroussin 		else {
2245c99fb5f9SBaptiste Daroussin 			start = str;
2246c99fb5f9SBaptiste Daroussin 			end = str + len;
2247c99fb5f9SBaptiste Daroussin 		}
2248c99fb5f9SBaptiste Daroussin 
2249c99fb5f9SBaptiste Daroussin 		obj->type = UCL_STRING;
2250c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_ESCAPE) {
2251c99fb5f9SBaptiste Daroussin 			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
2252*a0409676SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE | UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2253*a0409676SBaptiste Daroussin 					switch (*p) {
2254*a0409676SBaptiste Daroussin 					case '\v':
2255*a0409676SBaptiste Daroussin 					case '\0':
2256*a0409676SBaptiste Daroussin 						escaped_len += 5;
2257*a0409676SBaptiste Daroussin 						break;
2258*a0409676SBaptiste Daroussin 					case ' ':
2259*a0409676SBaptiste Daroussin 						break;
2260*a0409676SBaptiste Daroussin 					default:
2261c99fb5f9SBaptiste Daroussin 						escaped_len ++;
2262*a0409676SBaptiste Daroussin 						break;
2263*a0409676SBaptiste Daroussin 					}
2264c99fb5f9SBaptiste Daroussin 				}
2265c99fb5f9SBaptiste Daroussin 			}
2266c99fb5f9SBaptiste Daroussin 			dst = malloc (escaped_len + 1);
2267c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2268c99fb5f9SBaptiste Daroussin 				for (p = start, d = dst; p < end; p ++, d ++) {
2269*a0409676SBaptiste Daroussin 					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE | UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2270c99fb5f9SBaptiste Daroussin 						switch (*p) {
2271c99fb5f9SBaptiste Daroussin 						case '\n':
2272c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2273c99fb5f9SBaptiste Daroussin 							*d = 'n';
2274c99fb5f9SBaptiste Daroussin 							break;
2275c99fb5f9SBaptiste Daroussin 						case '\r':
2276c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2277c99fb5f9SBaptiste Daroussin 							*d = 'r';
2278c99fb5f9SBaptiste Daroussin 							break;
2279c99fb5f9SBaptiste Daroussin 						case '\b':
2280c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2281c99fb5f9SBaptiste Daroussin 							*d = 'b';
2282c99fb5f9SBaptiste Daroussin 							break;
2283c99fb5f9SBaptiste Daroussin 						case '\t':
2284c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2285c99fb5f9SBaptiste Daroussin 							*d = 't';
2286c99fb5f9SBaptiste Daroussin 							break;
2287c99fb5f9SBaptiste Daroussin 						case '\f':
2288c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2289c99fb5f9SBaptiste Daroussin 							*d = 'f';
2290c99fb5f9SBaptiste Daroussin 							break;
2291*a0409676SBaptiste Daroussin 						case '\0':
2292*a0409676SBaptiste Daroussin 							*d++ = '\\';
2293*a0409676SBaptiste Daroussin 							*d++ = 'u';
2294*a0409676SBaptiste Daroussin 							*d++ = '0';
2295*a0409676SBaptiste Daroussin 							*d++ = '0';
2296*a0409676SBaptiste Daroussin 							*d++ = '0';
2297*a0409676SBaptiste Daroussin 							*d   = '0';
2298*a0409676SBaptiste Daroussin 							break;
2299*a0409676SBaptiste Daroussin 						case '\v':
2300*a0409676SBaptiste Daroussin 							*d++ = '\\';
2301*a0409676SBaptiste Daroussin 							*d++ = 'u';
2302*a0409676SBaptiste Daroussin 							*d++ = '0';
2303*a0409676SBaptiste Daroussin 							*d++ = '0';
2304*a0409676SBaptiste Daroussin 							*d++ = '0';
2305*a0409676SBaptiste Daroussin 							*d   = 'B';
2306*a0409676SBaptiste Daroussin 							break;
2307c99fb5f9SBaptiste Daroussin 						case '\\':
2308c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2309c99fb5f9SBaptiste Daroussin 							*d = '\\';
2310c99fb5f9SBaptiste Daroussin 							break;
2311*a0409676SBaptiste Daroussin 						case ' ':
2312*a0409676SBaptiste Daroussin 							*d = ' ';
2313*a0409676SBaptiste Daroussin 							break;
2314c99fb5f9SBaptiste Daroussin 						case '"':
2315c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2316c99fb5f9SBaptiste Daroussin 							*d = '"';
2317c99fb5f9SBaptiste Daroussin 							break;
2318c99fb5f9SBaptiste Daroussin 						}
2319c99fb5f9SBaptiste Daroussin 					}
2320c99fb5f9SBaptiste Daroussin 					else {
2321c99fb5f9SBaptiste Daroussin 						*d = *p;
2322c99fb5f9SBaptiste Daroussin 					}
2323c99fb5f9SBaptiste Daroussin 				}
2324c99fb5f9SBaptiste Daroussin 				*d = '\0';
2325c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2326c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2327c99fb5f9SBaptiste Daroussin 				obj->len = escaped_len;
2328c99fb5f9SBaptiste Daroussin 			}
2329c99fb5f9SBaptiste Daroussin 		}
2330c99fb5f9SBaptiste Daroussin 		else {
2331c99fb5f9SBaptiste Daroussin 			dst = malloc (end - start + 1);
2332c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2333c99fb5f9SBaptiste Daroussin 				ucl_strlcpy_unsafe (dst, start, end - start + 1);
2334c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2335c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2336c99fb5f9SBaptiste Daroussin 				obj->len = end - start;
2337c99fb5f9SBaptiste Daroussin 			}
2338c99fb5f9SBaptiste Daroussin 		}
2339c99fb5f9SBaptiste Daroussin 		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
2340c99fb5f9SBaptiste Daroussin 			/* Parse what we have */
2341c99fb5f9SBaptiste Daroussin 			if (flags & UCL_STRING_PARSE_BOOLEAN) {
2342c99fb5f9SBaptiste Daroussin 				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
2343c99fb5f9SBaptiste Daroussin 					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2344c99fb5f9SBaptiste Daroussin 							flags & UCL_STRING_PARSE_DOUBLE,
234597bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_BYTES,
234697bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_TIME);
2347c99fb5f9SBaptiste Daroussin 				}
2348c99fb5f9SBaptiste Daroussin 			}
2349c99fb5f9SBaptiste Daroussin 			else {
2350c99fb5f9SBaptiste Daroussin 				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2351c99fb5f9SBaptiste Daroussin 						flags & UCL_STRING_PARSE_DOUBLE,
235297bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_BYTES,
235397bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_TIME);
2354c99fb5f9SBaptiste Daroussin 			}
2355c99fb5f9SBaptiste Daroussin 		}
2356c99fb5f9SBaptiste Daroussin 	}
2357c99fb5f9SBaptiste Daroussin 
2358c99fb5f9SBaptiste Daroussin 	return obj;
2359c99fb5f9SBaptiste Daroussin }
2360c99fb5f9SBaptiste Daroussin 
2361b04a7a0bSBaptiste Daroussin static bool
2362c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
2363c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
2364c99fb5f9SBaptiste Daroussin {
2365b04a7a0bSBaptiste Daroussin 	ucl_object_t *found, *tmp;
2366b04a7a0bSBaptiste Daroussin 	const ucl_object_t *cur;
2367c99fb5f9SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
2368c99fb5f9SBaptiste Daroussin 	const char *p;
2369b04a7a0bSBaptiste Daroussin 	int ret = true;
2370c99fb5f9SBaptiste Daroussin 
2371c99fb5f9SBaptiste Daroussin 	if (elt == NULL || key == NULL) {
2372b04a7a0bSBaptiste Daroussin 		return false;
2373c99fb5f9SBaptiste Daroussin 	}
2374c99fb5f9SBaptiste Daroussin 
2375c99fb5f9SBaptiste Daroussin 	if (top == NULL) {
2376b04a7a0bSBaptiste Daroussin 		return false;
2377c99fb5f9SBaptiste Daroussin 	}
2378c99fb5f9SBaptiste Daroussin 
2379c99fb5f9SBaptiste Daroussin 	if (top->type != UCL_OBJECT) {
2380c99fb5f9SBaptiste Daroussin 		/* It is possible to convert NULL type to an object */
2381c99fb5f9SBaptiste Daroussin 		if (top->type == UCL_NULL) {
2382c99fb5f9SBaptiste Daroussin 			top->type = UCL_OBJECT;
2383c99fb5f9SBaptiste Daroussin 		}
2384c99fb5f9SBaptiste Daroussin 		else {
2385c99fb5f9SBaptiste Daroussin 			/* Refuse converting of other object types */
2386b04a7a0bSBaptiste Daroussin 			return false;
2387c99fb5f9SBaptiste Daroussin 		}
2388c99fb5f9SBaptiste Daroussin 	}
2389c99fb5f9SBaptiste Daroussin 
2390c99fb5f9SBaptiste Daroussin 	if (top->value.ov == NULL) {
23918e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_create (false);
2392c99fb5f9SBaptiste Daroussin 	}
2393c99fb5f9SBaptiste Daroussin 
2394c99fb5f9SBaptiste Daroussin 	if (keylen == 0) {
2395c99fb5f9SBaptiste Daroussin 		keylen = strlen (key);
2396c99fb5f9SBaptiste Daroussin 	}
2397c99fb5f9SBaptiste Daroussin 
2398c99fb5f9SBaptiste Daroussin 	for (p = key; p < key + keylen; p ++) {
2399c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
2400c99fb5f9SBaptiste Daroussin 			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
2401c99fb5f9SBaptiste Daroussin 			break;
2402c99fb5f9SBaptiste Daroussin 		}
2403c99fb5f9SBaptiste Daroussin 	}
2404c99fb5f9SBaptiste Daroussin 
24054bf54857SBaptiste Daroussin 	/* workaround for some use cases */
24064bf54857SBaptiste Daroussin 	if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
24074bf54857SBaptiste Daroussin 			key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
24084bf54857SBaptiste Daroussin 		/* Remove copied key */
24094bf54857SBaptiste Daroussin 		free (elt->trash_stack[UCL_TRASH_KEY]);
24104bf54857SBaptiste Daroussin 		elt->trash_stack[UCL_TRASH_KEY] = NULL;
24114bf54857SBaptiste Daroussin 		elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
24124bf54857SBaptiste Daroussin 	}
24134bf54857SBaptiste Daroussin 
2414c99fb5f9SBaptiste Daroussin 	elt->key = key;
2415c99fb5f9SBaptiste Daroussin 	elt->keylen = keylen;
2416c99fb5f9SBaptiste Daroussin 
2417c99fb5f9SBaptiste Daroussin 	if (copy_key) {
2418c99fb5f9SBaptiste Daroussin 		ucl_copy_key_trash (elt);
2419c99fb5f9SBaptiste Daroussin 	}
2420c99fb5f9SBaptiste Daroussin 
2421b04a7a0bSBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
2422c99fb5f9SBaptiste Daroussin 
24234bf54857SBaptiste Daroussin 	if (found == NULL) {
24248e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
242597bd480fSBaptiste Daroussin 		top->len ++;
2426b04a7a0bSBaptiste Daroussin 		if (replace) {
2427b04a7a0bSBaptiste Daroussin 			ret = false;
2428b04a7a0bSBaptiste Daroussin 		}
2429c99fb5f9SBaptiste Daroussin 	}
2430c99fb5f9SBaptiste Daroussin 	else {
2431c99fb5f9SBaptiste Daroussin 		if (replace) {
24324bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, elt);
2433c99fb5f9SBaptiste Daroussin 			ucl_object_unref (found);
2434c99fb5f9SBaptiste Daroussin 		}
2435c99fb5f9SBaptiste Daroussin 		else if (merge) {
2436c99fb5f9SBaptiste Daroussin 			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
2437c99fb5f9SBaptiste Daroussin 				/* Insert old elt to new one */
2438b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (elt, found, found->key,
2439b04a7a0bSBaptiste Daroussin 						found->keylen, copy_key, false, false);
2440c99fb5f9SBaptiste Daroussin 				ucl_hash_delete (top->value.ov, found);
24418e3b1ab2SBaptiste Daroussin 				top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
2442c99fb5f9SBaptiste Daroussin 			}
2443c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
2444c99fb5f9SBaptiste Daroussin 				/* Insert new to old */
2445b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (found, elt, elt->key,
2446b04a7a0bSBaptiste Daroussin 						elt->keylen, copy_key, false, false);
2447c99fb5f9SBaptiste Daroussin 			}
2448c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
2449c99fb5f9SBaptiste Daroussin 				/* Mix two hashes */
2450d9f0ce31SBaptiste Daroussin 				while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
2451b04a7a0bSBaptiste Daroussin 					tmp = ucl_object_ref (cur);
2452b04a7a0bSBaptiste Daroussin 					ucl_object_insert_key_common (found, tmp, cur->key,
2453*a0409676SBaptiste Daroussin 							cur->keylen, copy_key, true, false);
2454c99fb5f9SBaptiste Daroussin 				}
2455c99fb5f9SBaptiste Daroussin 				ucl_object_unref (elt);
2456c99fb5f9SBaptiste Daroussin 			}
2457c99fb5f9SBaptiste Daroussin 			else {
2458c99fb5f9SBaptiste Daroussin 				/* Just make a list of scalars */
2459*a0409676SBaptiste Daroussin 				DL_CONCAT (found, elt);
2460c99fb5f9SBaptiste Daroussin 			}
2461c99fb5f9SBaptiste Daroussin 		}
2462c99fb5f9SBaptiste Daroussin 		else {
2463*a0409676SBaptiste Daroussin 			DL_CONCAT (found, elt);
2464c99fb5f9SBaptiste Daroussin 		}
2465c99fb5f9SBaptiste Daroussin 	}
2466c99fb5f9SBaptiste Daroussin 
2467b04a7a0bSBaptiste Daroussin 	return ret;
2468c99fb5f9SBaptiste Daroussin }
2469c99fb5f9SBaptiste Daroussin 
247036c53d67SBaptiste Daroussin bool
247136c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
247236c53d67SBaptiste Daroussin {
247336c53d67SBaptiste Daroussin 	ucl_object_t *found;
247436c53d67SBaptiste Daroussin 
247597bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
247697bd480fSBaptiste Daroussin 		return false;
247797bd480fSBaptiste Daroussin 	}
247897bd480fSBaptiste Daroussin 
2479d9f0ce31SBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_object_lookup_len (top, key, keylen));
248036c53d67SBaptiste Daroussin 
248197bd480fSBaptiste Daroussin 	if (found == NULL) {
248236c53d67SBaptiste Daroussin 		return false;
248397bd480fSBaptiste Daroussin 	}
248436c53d67SBaptiste Daroussin 
248536c53d67SBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
248636c53d67SBaptiste Daroussin 	ucl_object_unref (found);
248736c53d67SBaptiste Daroussin 	top->len --;
248836c53d67SBaptiste Daroussin 
248936c53d67SBaptiste Daroussin 	return true;
249036c53d67SBaptiste Daroussin }
249136c53d67SBaptiste Daroussin 
249236c53d67SBaptiste Daroussin bool
249336c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key)
249436c53d67SBaptiste Daroussin {
2495b04a7a0bSBaptiste Daroussin 	return ucl_object_delete_keyl (top, key, strlen (key));
249636c53d67SBaptiste Daroussin }
249736c53d67SBaptiste Daroussin 
2498c99fb5f9SBaptiste Daroussin ucl_object_t*
249997bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
250097bd480fSBaptiste Daroussin {
2501b04a7a0bSBaptiste Daroussin 	const ucl_object_t *found;
250297bd480fSBaptiste Daroussin 
250397bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
250497bd480fSBaptiste Daroussin 		return false;
250597bd480fSBaptiste Daroussin 	}
2506d9f0ce31SBaptiste Daroussin 	found = ucl_object_lookup_len (top, key, keylen);
250797bd480fSBaptiste Daroussin 
250897bd480fSBaptiste Daroussin 	if (found == NULL) {
250997bd480fSBaptiste Daroussin 		return NULL;
251097bd480fSBaptiste Daroussin 	}
251197bd480fSBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
251297bd480fSBaptiste Daroussin 	top->len --;
251397bd480fSBaptiste Daroussin 
2514b04a7a0bSBaptiste Daroussin 	return __DECONST (ucl_object_t *, found);
251597bd480fSBaptiste Daroussin }
251697bd480fSBaptiste Daroussin 
251797bd480fSBaptiste Daroussin ucl_object_t*
251897bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key)
251997bd480fSBaptiste Daroussin {
2520b04a7a0bSBaptiste Daroussin 	return ucl_object_pop_keyl (top, key, strlen (key));
252197bd480fSBaptiste Daroussin }
252297bd480fSBaptiste Daroussin 
2523b04a7a0bSBaptiste Daroussin bool
2524c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
2525c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2526c99fb5f9SBaptiste Daroussin {
2527c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
2528c99fb5f9SBaptiste Daroussin }
2529c99fb5f9SBaptiste Daroussin 
2530b04a7a0bSBaptiste Daroussin bool
2531c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
2532c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2533c99fb5f9SBaptiste Daroussin {
2534c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
2535c99fb5f9SBaptiste Daroussin }
2536c99fb5f9SBaptiste Daroussin 
2537b04a7a0bSBaptiste Daroussin bool
2538c99fb5f9SBaptiste Daroussin ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
2539c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2540c99fb5f9SBaptiste Daroussin {
2541c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
2542c99fb5f9SBaptiste Daroussin }
2543c99fb5f9SBaptiste Daroussin 
25444bf54857SBaptiste Daroussin bool
25454bf54857SBaptiste Daroussin ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
25464bf54857SBaptiste Daroussin {
25474bf54857SBaptiste Daroussin 	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
25484bf54857SBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
25494bf54857SBaptiste Daroussin 
2550*a0409676SBaptiste Daroussin 	if (top == NULL || elt == NULL) {
25514bf54857SBaptiste Daroussin 		return false;
25524bf54857SBaptiste Daroussin 	}
25534bf54857SBaptiste Daroussin 
2554*a0409676SBaptiste Daroussin 	if (top->type == UCL_ARRAY) {
2555*a0409676SBaptiste Daroussin 		if (elt->type == UCL_ARRAY) {
2556*a0409676SBaptiste Daroussin 			/* Merge two arrays */
2557*a0409676SBaptiste Daroussin 			return ucl_array_merge (top, elt, copy);
25584bf54857SBaptiste Daroussin 		}
25594bf54857SBaptiste Daroussin 		else {
2560*a0409676SBaptiste Daroussin 			if (copy) {
2561*a0409676SBaptiste Daroussin 				ucl_array_append (top, ucl_object_copy (elt));
2562*a0409676SBaptiste Daroussin 
2563*a0409676SBaptiste Daroussin 				return true;
2564*a0409676SBaptiste Daroussin 			}
2565*a0409676SBaptiste Daroussin 			else {
2566*a0409676SBaptiste Daroussin 				ucl_array_append (top, ucl_object_ref (elt));
2567*a0409676SBaptiste Daroussin 
2568*a0409676SBaptiste Daroussin 				return true;
2569*a0409676SBaptiste Daroussin 			}
2570*a0409676SBaptiste Daroussin 		}
2571*a0409676SBaptiste Daroussin 	}
2572*a0409676SBaptiste Daroussin 	else if (top->type == UCL_OBJECT) {
2573*a0409676SBaptiste Daroussin 		if (elt->type == UCL_OBJECT) {
2574*a0409676SBaptiste Daroussin 			/* Mix two hashes */
2575*a0409676SBaptiste Daroussin 			while ((cur = (ucl_object_t *) ucl_hash_iterate (elt->value.ov,
2576*a0409676SBaptiste Daroussin 					&iter))) {
2577*a0409676SBaptiste Daroussin 
2578*a0409676SBaptiste Daroussin 				if (copy) {
2579*a0409676SBaptiste Daroussin 					cp = ucl_object_copy (cur);
2580*a0409676SBaptiste Daroussin 				} else {
25814bf54857SBaptiste Daroussin 					cp = ucl_object_ref (cur);
25824bf54857SBaptiste Daroussin 				}
2583*a0409676SBaptiste Daroussin 
2584*a0409676SBaptiste Daroussin 				found = __DECONST(ucl_object_t *,
2585*a0409676SBaptiste Daroussin 						ucl_hash_search (top->value.ov, cp->key, cp->keylen));
2586*a0409676SBaptiste Daroussin 
25874bf54857SBaptiste Daroussin 				if (found == NULL) {
25884bf54857SBaptiste Daroussin 					/* The key does not exist */
2589*a0409676SBaptiste Daroussin 					top->value.ov = ucl_hash_insert_object (top->value.ov, cp,
2590*a0409676SBaptiste Daroussin 							false);
25914bf54857SBaptiste Daroussin 					top->len++;
25924bf54857SBaptiste Daroussin 				}
25934bf54857SBaptiste Daroussin 				else {
2594*a0409676SBaptiste Daroussin 					/* The key already exists, merge it recursively */
2595*a0409676SBaptiste Daroussin 					if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
2596*a0409676SBaptiste Daroussin 						if (!ucl_object_merge (found, cp, copy)) {
2597*a0409676SBaptiste Daroussin 							return false;
2598*a0409676SBaptiste Daroussin 						}
2599*a0409676SBaptiste Daroussin 					}
2600*a0409676SBaptiste Daroussin 					else {
26014bf54857SBaptiste Daroussin 						ucl_hash_replace (top->value.ov, found, cp);
26024bf54857SBaptiste Daroussin 						ucl_object_unref (found);
26034bf54857SBaptiste Daroussin 					}
26044bf54857SBaptiste Daroussin 				}
2605*a0409676SBaptiste Daroussin 			}
2606*a0409676SBaptiste Daroussin 		}
2607*a0409676SBaptiste Daroussin 		else {
2608*a0409676SBaptiste Daroussin 			if (copy) {
2609*a0409676SBaptiste Daroussin 				cp = ucl_object_copy (elt);
2610*a0409676SBaptiste Daroussin 			}
2611*a0409676SBaptiste Daroussin 			else {
2612*a0409676SBaptiste Daroussin 				cp = ucl_object_ref (elt);
2613*a0409676SBaptiste Daroussin 			}
2614*a0409676SBaptiste Daroussin 
2615*a0409676SBaptiste Daroussin 			found = __DECONST(ucl_object_t *,
2616*a0409676SBaptiste Daroussin 					ucl_hash_search (top->value.ov, cp->key, cp->keylen));
2617*a0409676SBaptiste Daroussin 
2618*a0409676SBaptiste Daroussin 			if (found == NULL) {
2619*a0409676SBaptiste Daroussin 				/* The key does not exist */
2620*a0409676SBaptiste Daroussin 				top->value.ov = ucl_hash_insert_object (top->value.ov, cp,
2621*a0409676SBaptiste Daroussin 						false);
2622*a0409676SBaptiste Daroussin 				top->len++;
2623*a0409676SBaptiste Daroussin 			}
2624*a0409676SBaptiste Daroussin 			else {
2625*a0409676SBaptiste Daroussin 				/* The key already exists, merge it recursively */
2626*a0409676SBaptiste Daroussin 				if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
2627*a0409676SBaptiste Daroussin 					if (!ucl_object_merge (found, cp, copy)) {
2628*a0409676SBaptiste Daroussin 						return false;
2629*a0409676SBaptiste Daroussin 					}
2630*a0409676SBaptiste Daroussin 				}
2631*a0409676SBaptiste Daroussin 				else {
2632*a0409676SBaptiste Daroussin 					ucl_hash_replace (top->value.ov, found, cp);
2633*a0409676SBaptiste Daroussin 					ucl_object_unref (found);
2634*a0409676SBaptiste Daroussin 				}
2635*a0409676SBaptiste Daroussin 			}
2636*a0409676SBaptiste Daroussin 		}
2637*a0409676SBaptiste Daroussin 	}
2638*a0409676SBaptiste Daroussin 	else {
2639*a0409676SBaptiste Daroussin 		/* Cannot merge trivial objects */
2640*a0409676SBaptiste Daroussin 		return false;
2641*a0409676SBaptiste Daroussin 	}
26424bf54857SBaptiste Daroussin 
26434bf54857SBaptiste Daroussin 	return true;
26444bf54857SBaptiste Daroussin }
26454bf54857SBaptiste Daroussin 
2646b04a7a0bSBaptiste Daroussin const ucl_object_t *
2647d9f0ce31SBaptiste Daroussin ucl_object_lookup_len (const ucl_object_t *obj, const char *key, size_t klen)
2648c99fb5f9SBaptiste Daroussin {
2649b04a7a0bSBaptiste Daroussin 	const ucl_object_t *ret;
2650b04a7a0bSBaptiste Daroussin 	ucl_object_t srch;
2651c99fb5f9SBaptiste Daroussin 
2652c99fb5f9SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
2653c99fb5f9SBaptiste Daroussin 		return NULL;
2654c99fb5f9SBaptiste Daroussin 	}
2655c99fb5f9SBaptiste Daroussin 
2656c99fb5f9SBaptiste Daroussin 	srch.key = key;
2657c99fb5f9SBaptiste Daroussin 	srch.keylen = klen;
2658c99fb5f9SBaptiste Daroussin 	ret = ucl_hash_search_obj (obj->value.ov, &srch);
2659c99fb5f9SBaptiste Daroussin 
2660c99fb5f9SBaptiste Daroussin 	return ret;
2661c99fb5f9SBaptiste Daroussin }
2662c99fb5f9SBaptiste Daroussin 
2663b04a7a0bSBaptiste Daroussin const ucl_object_t *
2664d9f0ce31SBaptiste Daroussin ucl_object_lookup (const ucl_object_t *obj, const char *key)
2665c99fb5f9SBaptiste Daroussin {
266639ee7a7aSBaptiste Daroussin 	if (key == NULL) {
2667c99fb5f9SBaptiste Daroussin 		return NULL;
266839ee7a7aSBaptiste Daroussin 	}
2669c99fb5f9SBaptiste Daroussin 
2670d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_len (obj, key, strlen (key));
2671c99fb5f9SBaptiste Daroussin }
2672c99fb5f9SBaptiste Daroussin 
2673b04a7a0bSBaptiste Daroussin const ucl_object_t*
2674d9f0ce31SBaptiste Daroussin ucl_object_lookup_any (const ucl_object_t *obj,
267539ee7a7aSBaptiste Daroussin 		const char *key, ...)
267639ee7a7aSBaptiste Daroussin {
267739ee7a7aSBaptiste Daroussin 	va_list ap;
267839ee7a7aSBaptiste Daroussin 	const ucl_object_t *ret = NULL;
267939ee7a7aSBaptiste Daroussin 	const char *nk = NULL;
268039ee7a7aSBaptiste Daroussin 
268139ee7a7aSBaptiste Daroussin 	if (obj == NULL || key == NULL) {
268239ee7a7aSBaptiste Daroussin 		return NULL;
268339ee7a7aSBaptiste Daroussin 	}
268439ee7a7aSBaptiste Daroussin 
2685d9f0ce31SBaptiste Daroussin 	ret = ucl_object_lookup_len (obj, key, strlen (key));
268639ee7a7aSBaptiste Daroussin 
268739ee7a7aSBaptiste Daroussin 	if (ret == NULL) {
268839ee7a7aSBaptiste Daroussin 		va_start (ap, key);
268939ee7a7aSBaptiste Daroussin 
269039ee7a7aSBaptiste Daroussin 		while (ret == NULL) {
269139ee7a7aSBaptiste Daroussin 			nk = va_arg (ap, const char *);
269239ee7a7aSBaptiste Daroussin 
269339ee7a7aSBaptiste Daroussin 			if (nk == NULL) {
269439ee7a7aSBaptiste Daroussin 				break;
269539ee7a7aSBaptiste Daroussin 			}
269639ee7a7aSBaptiste Daroussin 			else {
2697d9f0ce31SBaptiste Daroussin 				ret = ucl_object_lookup_len (obj, nk, strlen (nk));
269839ee7a7aSBaptiste Daroussin 			}
269939ee7a7aSBaptiste Daroussin 		}
270039ee7a7aSBaptiste Daroussin 
270139ee7a7aSBaptiste Daroussin 		va_end (ap);
270239ee7a7aSBaptiste Daroussin 	}
270339ee7a7aSBaptiste Daroussin 
270439ee7a7aSBaptiste Daroussin 	return ret;
270539ee7a7aSBaptiste Daroussin }
270639ee7a7aSBaptiste Daroussin 
270739ee7a7aSBaptiste Daroussin const ucl_object_t*
2708*a0409676SBaptiste Daroussin ucl_object_iterate_with_error (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values,
2709*a0409676SBaptiste Daroussin     int *ep)
2710c99fb5f9SBaptiste Daroussin {
27118e3b1ab2SBaptiste Daroussin 	const ucl_object_t *elt = NULL;
2712c99fb5f9SBaptiste Daroussin 
271397bd480fSBaptiste Daroussin 	if (obj == NULL || iter == NULL) {
271497bd480fSBaptiste Daroussin 		return NULL;
271597bd480fSBaptiste Daroussin 	}
271697bd480fSBaptiste Daroussin 
2717c99fb5f9SBaptiste Daroussin 	if (expand_values) {
2718c99fb5f9SBaptiste Daroussin 		switch (obj->type) {
2719c99fb5f9SBaptiste Daroussin 		case UCL_OBJECT:
2720*a0409676SBaptiste Daroussin 			return (const ucl_object_t*)ucl_hash_iterate2 (obj->value.ov, iter, ep);
2721c99fb5f9SBaptiste Daroussin 			break;
27228e3b1ab2SBaptiste Daroussin 		case UCL_ARRAY: {
27238e3b1ab2SBaptiste Daroussin 			unsigned int idx;
27248e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
27258e3b1ab2SBaptiste Daroussin 			idx = (unsigned int)(uintptr_t)(*iter);
27268e3b1ab2SBaptiste Daroussin 
27278e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
27288e3b1ab2SBaptiste Daroussin 				while (idx < kv_size (*vec)) {
27298e3b1ab2SBaptiste Daroussin 					if ((elt = kv_A (*vec, idx)) != NULL) {
27308e3b1ab2SBaptiste Daroussin 						idx ++;
27318e3b1ab2SBaptiste Daroussin 						break;
2732c99fb5f9SBaptiste Daroussin 					}
27338e3b1ab2SBaptiste Daroussin 					idx ++;
2734c99fb5f9SBaptiste Daroussin 				}
27358e3b1ab2SBaptiste Daroussin 				*iter = (void *)(uintptr_t)idx;
2736c99fb5f9SBaptiste Daroussin 			}
27378e3b1ab2SBaptiste Daroussin 
2738c99fb5f9SBaptiste Daroussin 			return elt;
27398e3b1ab2SBaptiste Daroussin 			break;
27408e3b1ab2SBaptiste Daroussin 		}
2741c99fb5f9SBaptiste Daroussin 		default:
2742c99fb5f9SBaptiste Daroussin 			/* Go to linear iteration */
2743c99fb5f9SBaptiste Daroussin 			break;
2744c99fb5f9SBaptiste Daroussin 		}
2745c99fb5f9SBaptiste Daroussin 	}
2746c99fb5f9SBaptiste Daroussin 	/* Treat everything as a linear list */
2747c99fb5f9SBaptiste Daroussin 	elt = *iter;
2748c99fb5f9SBaptiste Daroussin 	if (elt == NULL) {
2749c99fb5f9SBaptiste Daroussin 		elt = obj;
2750c99fb5f9SBaptiste Daroussin 	}
2751c99fb5f9SBaptiste Daroussin 	else if (elt == obj) {
2752c99fb5f9SBaptiste Daroussin 		return NULL;
2753c99fb5f9SBaptiste Daroussin 	}
2754b04a7a0bSBaptiste Daroussin 	*iter = __DECONST (void *, elt->next ? elt->next : obj);
2755c99fb5f9SBaptiste Daroussin 	return elt;
2756c99fb5f9SBaptiste Daroussin 
2757c99fb5f9SBaptiste Daroussin 	/* Not reached */
2758c99fb5f9SBaptiste Daroussin 	return NULL;
2759c99fb5f9SBaptiste Daroussin }
276097bd480fSBaptiste Daroussin 
2761*a0409676SBaptiste Daroussin enum ucl_safe_iter_flags {
2762*a0409676SBaptiste Daroussin 	UCL_ITERATE_FLAG_UNDEFINED = 0,
2763*a0409676SBaptiste Daroussin 	UCL_ITERATE_FLAG_INSIDE_ARRAY,
2764*a0409676SBaptiste Daroussin 	UCL_ITERATE_FLAG_INSIDE_OBJECT,
2765*a0409676SBaptiste Daroussin 	UCL_ITERATE_FLAG_IMPLICIT,
2766*a0409676SBaptiste Daroussin 	UCL_ITERATE_FLAG_EXCEPTION
2767*a0409676SBaptiste Daroussin };
2768*a0409676SBaptiste Daroussin 
2769*a0409676SBaptiste Daroussin static const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
27708e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter {
27718e3b1ab2SBaptiste Daroussin 	char magic[4]; /* safety check */
2772*a0409676SBaptiste Daroussin 	uint32_t flags;
27738e3b1ab2SBaptiste Daroussin 	const ucl_object_t *impl_it; /* implicit object iteration */
27748e3b1ab2SBaptiste Daroussin 	ucl_object_iter_t expl_it; /* explicit iteration */
27758e3b1ab2SBaptiste Daroussin };
27768e3b1ab2SBaptiste Daroussin 
27778e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr)
27788e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER_CHECK(it) do { \
27798e3b1ab2SBaptiste Daroussin 	assert (it != NULL); \
27808e3b1ab2SBaptiste Daroussin 	assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \
27818e3b1ab2SBaptiste Daroussin  } while (0)
27828e3b1ab2SBaptiste Daroussin 
27838e3b1ab2SBaptiste Daroussin ucl_object_iter_t
27848e3b1ab2SBaptiste Daroussin ucl_object_iterate_new (const ucl_object_t *obj)
27858e3b1ab2SBaptiste Daroussin {
27868e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *it;
27878e3b1ab2SBaptiste Daroussin 
27888e3b1ab2SBaptiste Daroussin 	it = UCL_ALLOC (sizeof (*it));
27898e3b1ab2SBaptiste Daroussin 	if (it != NULL) {
27908e3b1ab2SBaptiste Daroussin 		memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
2791*a0409676SBaptiste Daroussin 		it->flags = UCL_ITERATE_FLAG_UNDEFINED;
27928e3b1ab2SBaptiste Daroussin 		it->expl_it = NULL;
27938e3b1ab2SBaptiste Daroussin 		it->impl_it = obj;
27948e3b1ab2SBaptiste Daroussin 	}
27958e3b1ab2SBaptiste Daroussin 
27968e3b1ab2SBaptiste Daroussin 	return (ucl_object_iter_t)it;
27978e3b1ab2SBaptiste Daroussin }
27988e3b1ab2SBaptiste Daroussin 
2799*a0409676SBaptiste Daroussin bool
2800*a0409676SBaptiste Daroussin ucl_object_iter_chk_excpn(ucl_object_iter_t *it)
2801*a0409676SBaptiste Daroussin {
2802*a0409676SBaptiste Daroussin         struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
2803*a0409676SBaptiste Daroussin 
2804*a0409676SBaptiste Daroussin         UCL_SAFE_ITER_CHECK (rit);
2805*a0409676SBaptiste Daroussin 
2806*a0409676SBaptiste Daroussin 	return (rit->flags == UCL_ITERATE_FLAG_EXCEPTION);
2807*a0409676SBaptiste Daroussin }
28088e3b1ab2SBaptiste Daroussin 
28098e3b1ab2SBaptiste Daroussin ucl_object_iter_t
28108e3b1ab2SBaptiste Daroussin ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
28118e3b1ab2SBaptiste Daroussin {
28128e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
28138e3b1ab2SBaptiste Daroussin 
28148e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
28158e3b1ab2SBaptiste Daroussin 
281611dd9ed6SBaptiste Daroussin 	if (rit->expl_it != NULL) {
2817*a0409676SBaptiste Daroussin 		if (rit->flags == UCL_ITERATE_FLAG_INSIDE_OBJECT) {
281811dd9ed6SBaptiste Daroussin 			UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
281911dd9ed6SBaptiste Daroussin 		}
2820*a0409676SBaptiste Daroussin 	}
282111dd9ed6SBaptiste Daroussin 
28228e3b1ab2SBaptiste Daroussin 	rit->impl_it = obj;
28238e3b1ab2SBaptiste Daroussin 	rit->expl_it = NULL;
2824*a0409676SBaptiste Daroussin 	rit->flags = UCL_ITERATE_FLAG_UNDEFINED;
28258e3b1ab2SBaptiste Daroussin 
28268e3b1ab2SBaptiste Daroussin 	return it;
28278e3b1ab2SBaptiste Daroussin }
28288e3b1ab2SBaptiste Daroussin 
28298e3b1ab2SBaptiste Daroussin const ucl_object_t*
28308e3b1ab2SBaptiste Daroussin ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
28318e3b1ab2SBaptiste Daroussin {
283211dd9ed6SBaptiste Daroussin 	return ucl_object_iterate_full (it, expand_values ? UCL_ITERATE_BOTH :
283311dd9ed6SBaptiste Daroussin 			UCL_ITERATE_IMPLICIT);
283411dd9ed6SBaptiste Daroussin }
283511dd9ed6SBaptiste Daroussin 
283611dd9ed6SBaptiste Daroussin const ucl_object_t*
283711dd9ed6SBaptiste Daroussin ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)
283811dd9ed6SBaptiste Daroussin {
28398e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
28408e3b1ab2SBaptiste Daroussin 	const ucl_object_t *ret = NULL;
2841*a0409676SBaptiste Daroussin 	int ern;
28428e3b1ab2SBaptiste Daroussin 
28438e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
28448e3b1ab2SBaptiste Daroussin 
28458e3b1ab2SBaptiste Daroussin 	if (rit->impl_it == NULL) {
28468e3b1ab2SBaptiste Daroussin 		return NULL;
28478e3b1ab2SBaptiste Daroussin 	}
28488e3b1ab2SBaptiste Daroussin 
2849*a0409676SBaptiste Daroussin 	if (rit->impl_it->type == UCL_OBJECT) {
2850*a0409676SBaptiste Daroussin 		rit->flags = UCL_ITERATE_FLAG_INSIDE_OBJECT;
2851*a0409676SBaptiste Daroussin 		ret = ucl_object_iterate_with_error (rit->impl_it, &rit->expl_it, true, &ern);
2852*a0409676SBaptiste Daroussin 
2853*a0409676SBaptiste Daroussin 		if (ret == NULL && ern != 0) {
2854*a0409676SBaptiste Daroussin 			rit->flags = UCL_ITERATE_FLAG_EXCEPTION;
2855*a0409676SBaptiste Daroussin 			return NULL;
2856*a0409676SBaptiste Daroussin 		}
2857*a0409676SBaptiste Daroussin 
2858*a0409676SBaptiste Daroussin 		if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
2859*a0409676SBaptiste Daroussin 			/* Need to switch to another implicit object in chain */
2860*a0409676SBaptiste Daroussin 			rit->impl_it = rit->impl_it->next;
2861*a0409676SBaptiste Daroussin 			rit->expl_it = NULL;
2862*a0409676SBaptiste Daroussin 
2863*a0409676SBaptiste Daroussin 			return ucl_object_iterate_safe (it, type);
2864*a0409676SBaptiste Daroussin 		}
2865*a0409676SBaptiste Daroussin 	}
2866*a0409676SBaptiste Daroussin 	else if (rit->impl_it->type == UCL_ARRAY) {
2867*a0409676SBaptiste Daroussin 		rit->flags = UCL_ITERATE_FLAG_INSIDE_ARRAY;
2868d9f0ce31SBaptiste Daroussin 		ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
28698e3b1ab2SBaptiste Daroussin 
287011dd9ed6SBaptiste Daroussin 		if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
28718e3b1ab2SBaptiste Daroussin 			/* Need to switch to another implicit object in chain */
28728e3b1ab2SBaptiste Daroussin 			rit->impl_it = rit->impl_it->next;
28738e3b1ab2SBaptiste Daroussin 			rit->expl_it = NULL;
287411dd9ed6SBaptiste Daroussin 
287511dd9ed6SBaptiste Daroussin 			return ucl_object_iterate_safe (it, type);
28768e3b1ab2SBaptiste Daroussin 		}
28778e3b1ab2SBaptiste Daroussin 	}
28788e3b1ab2SBaptiste Daroussin 	else {
28798e3b1ab2SBaptiste Daroussin 		/* Just iterate over the implicit array */
2880*a0409676SBaptiste Daroussin 		rit->flags = UCL_ITERATE_FLAG_IMPLICIT;
28818e3b1ab2SBaptiste Daroussin 		ret = rit->impl_it;
28828e3b1ab2SBaptiste Daroussin 		rit->impl_it = rit->impl_it->next;
288311dd9ed6SBaptiste Daroussin 
288411dd9ed6SBaptiste Daroussin 		if (type & UCL_ITERATE_EXPLICIT) {
28858e3b1ab2SBaptiste Daroussin 			/* We flatten objects if need to expand values */
28868e3b1ab2SBaptiste Daroussin 			if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
288711dd9ed6SBaptiste Daroussin 				return ucl_object_iterate_safe (it, type);
28888e3b1ab2SBaptiste Daroussin 			}
28898e3b1ab2SBaptiste Daroussin 		}
28908e3b1ab2SBaptiste Daroussin 	}
28918e3b1ab2SBaptiste Daroussin 
28928e3b1ab2SBaptiste Daroussin 	return ret;
28938e3b1ab2SBaptiste Daroussin }
28948e3b1ab2SBaptiste Daroussin 
28958e3b1ab2SBaptiste Daroussin void
28968e3b1ab2SBaptiste Daroussin ucl_object_iterate_free (ucl_object_iter_t it)
28978e3b1ab2SBaptiste Daroussin {
28988e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
28998e3b1ab2SBaptiste Daroussin 
29008e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
29018e3b1ab2SBaptiste Daroussin 
290211dd9ed6SBaptiste Daroussin 	if (rit->expl_it != NULL) {
2903*a0409676SBaptiste Daroussin 		if (rit->flags == UCL_ITERATE_FLAG_INSIDE_OBJECT) {
290411dd9ed6SBaptiste Daroussin 			UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
290511dd9ed6SBaptiste Daroussin 		}
2906*a0409676SBaptiste Daroussin 	}
290711dd9ed6SBaptiste Daroussin 
29088e3b1ab2SBaptiste Daroussin 	UCL_FREE (sizeof (*rit), it);
29098e3b1ab2SBaptiste Daroussin }
29108e3b1ab2SBaptiste Daroussin 
29112e8ed2b8SBaptiste Daroussin const ucl_object_t *
2912d9f0ce31SBaptiste Daroussin ucl_object_lookup_path (const ucl_object_t *top, const char *path_in) {
2913d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_path_char (top, path_in, '.');
291439ee7a7aSBaptiste Daroussin }
291539ee7a7aSBaptiste Daroussin 
291639ee7a7aSBaptiste Daroussin 
291739ee7a7aSBaptiste Daroussin const ucl_object_t *
2918d9f0ce31SBaptiste Daroussin ucl_object_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) {
29192e8ed2b8SBaptiste Daroussin 	const ucl_object_t *o = NULL, *found;
29202e8ed2b8SBaptiste Daroussin 	const char *p, *c;
29212e8ed2b8SBaptiste Daroussin 	char *err_str;
29222e8ed2b8SBaptiste Daroussin 	unsigned index;
29232e8ed2b8SBaptiste Daroussin 
29242e8ed2b8SBaptiste Daroussin 	if (path_in == NULL || top == NULL) {
29252e8ed2b8SBaptiste Daroussin 		return NULL;
29262e8ed2b8SBaptiste Daroussin 	}
29272e8ed2b8SBaptiste Daroussin 
29282e8ed2b8SBaptiste Daroussin 	found = NULL;
29292e8ed2b8SBaptiste Daroussin 	p = path_in;
29302e8ed2b8SBaptiste Daroussin 
29312e8ed2b8SBaptiste Daroussin 	/* Skip leading dots */
293239ee7a7aSBaptiste Daroussin 	while (*p == sep) {
29332e8ed2b8SBaptiste Daroussin 		p ++;
29342e8ed2b8SBaptiste Daroussin 	}
29352e8ed2b8SBaptiste Daroussin 
29362e8ed2b8SBaptiste Daroussin 	c = p;
29372e8ed2b8SBaptiste Daroussin 	while (*p != '\0') {
29382e8ed2b8SBaptiste Daroussin 		p ++;
293939ee7a7aSBaptiste Daroussin 		if (*p == sep || *p == '\0') {
29402e8ed2b8SBaptiste Daroussin 			if (p > c) {
29412e8ed2b8SBaptiste Daroussin 				switch (top->type) {
29422e8ed2b8SBaptiste Daroussin 				case UCL_ARRAY:
29432e8ed2b8SBaptiste Daroussin 					/* Key should be an int */
29442e8ed2b8SBaptiste Daroussin 					index = strtoul (c, &err_str, 10);
294539ee7a7aSBaptiste Daroussin 					if (err_str != NULL && (*err_str != sep && *err_str != '\0')) {
29462e8ed2b8SBaptiste Daroussin 						return NULL;
29472e8ed2b8SBaptiste Daroussin 					}
29482e8ed2b8SBaptiste Daroussin 					o = ucl_array_find_index (top, index);
29492e8ed2b8SBaptiste Daroussin 					break;
29502e8ed2b8SBaptiste Daroussin 				default:
2951d9f0ce31SBaptiste Daroussin 					o = ucl_object_lookup_len (top, c, p - c);
29522e8ed2b8SBaptiste Daroussin 					break;
29532e8ed2b8SBaptiste Daroussin 				}
29542e8ed2b8SBaptiste Daroussin 				if (o == NULL) {
29552e8ed2b8SBaptiste Daroussin 					return NULL;
29562e8ed2b8SBaptiste Daroussin 				}
29572e8ed2b8SBaptiste Daroussin 				top = o;
29582e8ed2b8SBaptiste Daroussin 			}
29592e8ed2b8SBaptiste Daroussin 			if (*p != '\0') {
29602e8ed2b8SBaptiste Daroussin 				c = p + 1;
29612e8ed2b8SBaptiste Daroussin 			}
29622e8ed2b8SBaptiste Daroussin 		}
29632e8ed2b8SBaptiste Daroussin 	}
29642e8ed2b8SBaptiste Daroussin 	found = o;
29652e8ed2b8SBaptiste Daroussin 
29662e8ed2b8SBaptiste Daroussin 	return found;
29672e8ed2b8SBaptiste Daroussin }
29682e8ed2b8SBaptiste Daroussin 
296997bd480fSBaptiste Daroussin 
297097bd480fSBaptiste Daroussin ucl_object_t *
297197bd480fSBaptiste Daroussin ucl_object_new (void)
297297bd480fSBaptiste Daroussin {
29734bf54857SBaptiste Daroussin 	return ucl_object_typed_new (UCL_NULL);
297497bd480fSBaptiste Daroussin }
297597bd480fSBaptiste Daroussin 
297697bd480fSBaptiste Daroussin ucl_object_t *
29772e8ed2b8SBaptiste Daroussin ucl_object_typed_new (ucl_type_t type)
297897bd480fSBaptiste Daroussin {
29794bf54857SBaptiste Daroussin 	return ucl_object_new_full (type, 0);
29804bf54857SBaptiste Daroussin }
29814bf54857SBaptiste Daroussin 
29824bf54857SBaptiste Daroussin ucl_object_t *
29834bf54857SBaptiste Daroussin ucl_object_new_full (ucl_type_t type, unsigned priority)
29844bf54857SBaptiste Daroussin {
298597bd480fSBaptiste Daroussin 	ucl_object_t *new;
29864bf54857SBaptiste Daroussin 
29874bf54857SBaptiste Daroussin 	if (type != UCL_USERDATA) {
29884bf54857SBaptiste Daroussin 		new = UCL_ALLOC (sizeof (ucl_object_t));
298997bd480fSBaptiste Daroussin 		if (new != NULL) {
299097bd480fSBaptiste Daroussin 			memset (new, 0, sizeof (ucl_object_t));
299197bd480fSBaptiste Daroussin 			new->ref = 1;
299297bd480fSBaptiste Daroussin 			new->type = (type <= UCL_NULL ? type : UCL_NULL);
29934bf54857SBaptiste Daroussin 			new->next = NULL;
29944bf54857SBaptiste Daroussin 			new->prev = new;
29954bf54857SBaptiste Daroussin 			ucl_object_set_priority (new, priority);
29968e3b1ab2SBaptiste Daroussin 
29978e3b1ab2SBaptiste Daroussin 			if (type == UCL_ARRAY) {
29988e3b1ab2SBaptiste Daroussin 				new->value.av = UCL_ALLOC (sizeof (ucl_array_t));
29998e3b1ab2SBaptiste Daroussin 				if (new->value.av) {
30008e3b1ab2SBaptiste Daroussin 					memset (new->value.av, 0, sizeof (ucl_array_t));
30018e3b1ab2SBaptiste Daroussin 					UCL_ARRAY_GET (vec, new);
30028e3b1ab2SBaptiste Daroussin 
30038e3b1ab2SBaptiste Daroussin 					/* Preallocate some space for arrays */
3004*a0409676SBaptiste Daroussin 					kv_resize_safe (ucl_object_t *, *vec, 8, enomem);
30058e3b1ab2SBaptiste Daroussin 				}
30068e3b1ab2SBaptiste Daroussin 			}
300797bd480fSBaptiste Daroussin 		}
30084bf54857SBaptiste Daroussin 	}
30094bf54857SBaptiste Daroussin 	else {
3010d9f0ce31SBaptiste Daroussin 		new = ucl_object_new_userdata (NULL, NULL, NULL);
30114bf54857SBaptiste Daroussin 		ucl_object_set_priority (new, priority);
30124bf54857SBaptiste Daroussin 	}
3013*a0409676SBaptiste Daroussin enomem:
301497bd480fSBaptiste Daroussin 	return new;
301597bd480fSBaptiste Daroussin }
301697bd480fSBaptiste Daroussin 
3017*a0409676SBaptiste Daroussin bool ucl_object_reserve (ucl_object_t *obj, size_t reserved)
3018*a0409676SBaptiste Daroussin {
3019*a0409676SBaptiste Daroussin 	if (obj->type == UCL_ARRAY) {
3020*a0409676SBaptiste Daroussin 		UCL_ARRAY_GET (vec, obj);
3021*a0409676SBaptiste Daroussin 
3022*a0409676SBaptiste Daroussin 		if (vec->m < reserved) {
3023*a0409676SBaptiste Daroussin 			/* Preallocate some space for arrays */
3024*a0409676SBaptiste Daroussin 			kv_resize_safe (ucl_object_t *, *vec, reserved, e0);
3025*a0409676SBaptiste Daroussin 		}
3026*a0409676SBaptiste Daroussin 	}
3027*a0409676SBaptiste Daroussin 	else if (obj->type == UCL_OBJECT) {
3028*a0409676SBaptiste Daroussin 		ucl_hash_reserve (obj->value.ov, reserved);
3029*a0409676SBaptiste Daroussin 	}
3030*a0409676SBaptiste Daroussin 	return true;
3031*a0409676SBaptiste Daroussin e0:
3032*a0409676SBaptiste Daroussin 	return false;
3033*a0409676SBaptiste Daroussin }
3034*a0409676SBaptiste Daroussin 
30354bf54857SBaptiste Daroussin ucl_object_t*
3036d9f0ce31SBaptiste Daroussin ucl_object_new_userdata (ucl_userdata_dtor dtor,
3037d9f0ce31SBaptiste Daroussin 		ucl_userdata_emitter emitter,
3038d9f0ce31SBaptiste Daroussin 		void *ptr)
30394bf54857SBaptiste Daroussin {
30404bf54857SBaptiste Daroussin 	struct ucl_object_userdata *new;
30414bf54857SBaptiste Daroussin 	size_t nsize = sizeof (*new);
30424bf54857SBaptiste Daroussin 
30434bf54857SBaptiste Daroussin 	new = UCL_ALLOC (nsize);
30444bf54857SBaptiste Daroussin 	if (new != NULL) {
30454bf54857SBaptiste Daroussin 		memset (new, 0, nsize);
30464bf54857SBaptiste Daroussin 		new->obj.ref = 1;
30474bf54857SBaptiste Daroussin 		new->obj.type = UCL_USERDATA;
30484bf54857SBaptiste Daroussin 		new->obj.next = NULL;
30494bf54857SBaptiste Daroussin 		new->obj.prev = (ucl_object_t *)new;
30504bf54857SBaptiste Daroussin 		new->dtor = dtor;
30514bf54857SBaptiste Daroussin 		new->emitter = emitter;
3052d9f0ce31SBaptiste Daroussin 		new->obj.value.ud = ptr;
30534bf54857SBaptiste Daroussin 	}
30544bf54857SBaptiste Daroussin 
30554bf54857SBaptiste Daroussin 	return (ucl_object_t *)new;
30564bf54857SBaptiste Daroussin }
30574bf54857SBaptiste Daroussin 
30582e8ed2b8SBaptiste Daroussin ucl_type_t
30592e8ed2b8SBaptiste Daroussin ucl_object_type (const ucl_object_t *obj)
30602e8ed2b8SBaptiste Daroussin {
306139ee7a7aSBaptiste Daroussin 	if (obj == NULL) {
306239ee7a7aSBaptiste Daroussin 		return UCL_NULL;
306339ee7a7aSBaptiste Daroussin 	}
306439ee7a7aSBaptiste Daroussin 
30652e8ed2b8SBaptiste Daroussin 	return obj->type;
30662e8ed2b8SBaptiste Daroussin }
30672e8ed2b8SBaptiste Daroussin 
306897bd480fSBaptiste Daroussin ucl_object_t*
306997bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str)
307097bd480fSBaptiste Daroussin {
307197bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
307297bd480fSBaptiste Daroussin }
307397bd480fSBaptiste Daroussin 
307497bd480fSBaptiste Daroussin ucl_object_t *
307597bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len)
307697bd480fSBaptiste Daroussin {
307797bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
307897bd480fSBaptiste Daroussin }
307997bd480fSBaptiste Daroussin 
308097bd480fSBaptiste Daroussin ucl_object_t *
308197bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv)
308297bd480fSBaptiste Daroussin {
308397bd480fSBaptiste Daroussin 	ucl_object_t *obj;
308497bd480fSBaptiste Daroussin 
308597bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
308697bd480fSBaptiste Daroussin 	if (obj != NULL) {
308797bd480fSBaptiste Daroussin 		obj->type = UCL_INT;
308897bd480fSBaptiste Daroussin 		obj->value.iv = iv;
308997bd480fSBaptiste Daroussin 	}
309097bd480fSBaptiste Daroussin 
309197bd480fSBaptiste Daroussin 	return obj;
309297bd480fSBaptiste Daroussin }
309397bd480fSBaptiste Daroussin 
309497bd480fSBaptiste Daroussin ucl_object_t *
309597bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv)
309697bd480fSBaptiste Daroussin {
309797bd480fSBaptiste Daroussin 	ucl_object_t *obj;
309897bd480fSBaptiste Daroussin 
309997bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
310097bd480fSBaptiste Daroussin 	if (obj != NULL) {
310197bd480fSBaptiste Daroussin 		obj->type = UCL_FLOAT;
310297bd480fSBaptiste Daroussin 		obj->value.dv = dv;
310397bd480fSBaptiste Daroussin 	}
310497bd480fSBaptiste Daroussin 
310597bd480fSBaptiste Daroussin 	return obj;
310697bd480fSBaptiste Daroussin }
310797bd480fSBaptiste Daroussin 
310897bd480fSBaptiste Daroussin ucl_object_t*
310997bd480fSBaptiste Daroussin ucl_object_frombool (bool bv)
311097bd480fSBaptiste Daroussin {
311197bd480fSBaptiste Daroussin 	ucl_object_t *obj;
311297bd480fSBaptiste Daroussin 
311397bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
311497bd480fSBaptiste Daroussin 	if (obj != NULL) {
311597bd480fSBaptiste Daroussin 		obj->type = UCL_BOOLEAN;
311697bd480fSBaptiste Daroussin 		obj->value.iv = bv;
311797bd480fSBaptiste Daroussin 	}
311897bd480fSBaptiste Daroussin 
311997bd480fSBaptiste Daroussin 	return obj;
312097bd480fSBaptiste Daroussin }
312197bd480fSBaptiste Daroussin 
3122b04a7a0bSBaptiste Daroussin bool
312397bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
312497bd480fSBaptiste Daroussin {
31258e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
312697bd480fSBaptiste Daroussin 
3127b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
3128b04a7a0bSBaptiste Daroussin 		return false;
312997bd480fSBaptiste Daroussin 	}
313097bd480fSBaptiste Daroussin 
31318e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
31328e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
313339ee7a7aSBaptiste Daroussin 
313439ee7a7aSBaptiste Daroussin 		if (vec == NULL) {
313539ee7a7aSBaptiste Daroussin 			return false;
313639ee7a7aSBaptiste Daroussin 		}
313739ee7a7aSBaptiste Daroussin 
31388e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
31398e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
314097bd480fSBaptiste Daroussin 	}
31418e3b1ab2SBaptiste Daroussin 
3142*a0409676SBaptiste Daroussin 	kv_push_safe (ucl_object_t *, *vec, elt, e0);
31438e3b1ab2SBaptiste Daroussin 
314497bd480fSBaptiste Daroussin 	top->len ++;
3145b04a7a0bSBaptiste Daroussin 
3146b04a7a0bSBaptiste Daroussin 	return true;
3147*a0409676SBaptiste Daroussin e0:
3148*a0409676SBaptiste Daroussin 	return false;
314997bd480fSBaptiste Daroussin }
315097bd480fSBaptiste Daroussin 
3151b04a7a0bSBaptiste Daroussin bool
315297bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
315397bd480fSBaptiste Daroussin {
31548e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
315597bd480fSBaptiste Daroussin 
3156b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
3157b04a7a0bSBaptiste Daroussin 		return false;
315897bd480fSBaptiste Daroussin 	}
315997bd480fSBaptiste Daroussin 
31608e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
31618e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
31628e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
31638e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
3164*a0409676SBaptiste Daroussin 		kv_push_safe (ucl_object_t *, *vec, elt, e0);
316597bd480fSBaptiste Daroussin 	}
316697bd480fSBaptiste Daroussin 	else {
31678e3b1ab2SBaptiste Daroussin 		/* Slow O(n) algorithm */
3168*a0409676SBaptiste Daroussin 		kv_prepend_safe (ucl_object_t *, *vec, elt, e0);
316997bd480fSBaptiste Daroussin 	}
31708e3b1ab2SBaptiste Daroussin 
317197bd480fSBaptiste Daroussin 	top->len ++;
317297bd480fSBaptiste Daroussin 
3173b04a7a0bSBaptiste Daroussin 	return true;
3174*a0409676SBaptiste Daroussin e0:
3175*a0409676SBaptiste Daroussin 	return false;
317697bd480fSBaptiste Daroussin }
317797bd480fSBaptiste Daroussin 
31784bf54857SBaptiste Daroussin bool
31794bf54857SBaptiste Daroussin ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
31804bf54857SBaptiste Daroussin {
31818e3b1ab2SBaptiste Daroussin 	unsigned i;
318239ee7a7aSBaptiste Daroussin 	ucl_object_t *cp = NULL;
31838e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj;
31844bf54857SBaptiste Daroussin 
31854bf54857SBaptiste Daroussin 	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
31864bf54857SBaptiste Daroussin 		return false;
31874bf54857SBaptiste Daroussin 	}
31884bf54857SBaptiste Daroussin 
318939ee7a7aSBaptiste Daroussin 	if (copy) {
319039ee7a7aSBaptiste Daroussin 		cp = ucl_object_copy (elt);
319139ee7a7aSBaptiste Daroussin 	}
319239ee7a7aSBaptiste Daroussin 	else {
319339ee7a7aSBaptiste Daroussin 		cp = ucl_object_ref (elt);
319439ee7a7aSBaptiste Daroussin 	}
319539ee7a7aSBaptiste Daroussin 
319639ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v1, top);
319739ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v2, cp);
319839ee7a7aSBaptiste Daroussin 
3199d9f0ce31SBaptiste Daroussin 	if (v1 && v2) {
3200*a0409676SBaptiste Daroussin 		kv_concat_safe (ucl_object_t *, *v1, *v2, e0);
32018e3b1ab2SBaptiste Daroussin 
32028e3b1ab2SBaptiste Daroussin 		for (i = v2->n; i < v1->n; i ++) {
32038e3b1ab2SBaptiste Daroussin 			obj = &kv_A (*v1, i);
32048e3b1ab2SBaptiste Daroussin 			if (*obj == NULL) {
32058e3b1ab2SBaptiste Daroussin 				continue;
32068e3b1ab2SBaptiste Daroussin 			}
32078e3b1ab2SBaptiste Daroussin 			top->len ++;
32084bf54857SBaptiste Daroussin 		}
3209d9f0ce31SBaptiste Daroussin 	}
32104bf54857SBaptiste Daroussin 
32114bf54857SBaptiste Daroussin 	return true;
3212*a0409676SBaptiste Daroussin e0:
3213*a0409676SBaptiste Daroussin 	return false;
32144bf54857SBaptiste Daroussin }
32154bf54857SBaptiste Daroussin 
321697bd480fSBaptiste Daroussin ucl_object_t *
321797bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
321897bd480fSBaptiste Daroussin {
32198e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
32208e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
32218e3b1ab2SBaptiste Daroussin 	unsigned i;
322297bd480fSBaptiste Daroussin 
322339ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
322439ee7a7aSBaptiste Daroussin 		return NULL;
322539ee7a7aSBaptiste Daroussin 	}
322639ee7a7aSBaptiste Daroussin 
32278e3b1ab2SBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
32288e3b1ab2SBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
32298e3b1ab2SBaptiste Daroussin 			kv_del (ucl_object_t *, *vec, i);
32308e3b1ab2SBaptiste Daroussin 			ret = elt;
323197bd480fSBaptiste Daroussin 			top->len --;
32328e3b1ab2SBaptiste Daroussin 			break;
32338e3b1ab2SBaptiste Daroussin 		}
32348e3b1ab2SBaptiste Daroussin 	}
323597bd480fSBaptiste Daroussin 
32368e3b1ab2SBaptiste Daroussin 	return ret;
323797bd480fSBaptiste Daroussin }
323897bd480fSBaptiste Daroussin 
3239b04a7a0bSBaptiste Daroussin const ucl_object_t *
3240b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top)
324197bd480fSBaptiste Daroussin {
32428e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
32438e3b1ab2SBaptiste Daroussin 
324439ee7a7aSBaptiste Daroussin 	if (vec == NULL || top == NULL || top->type != UCL_ARRAY ||
324539ee7a7aSBaptiste Daroussin 			top->value.av == NULL) {
324697bd480fSBaptiste Daroussin 		return NULL;
324797bd480fSBaptiste Daroussin 	}
32488e3b1ab2SBaptiste Daroussin 
32498e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[0] : NULL);
325097bd480fSBaptiste Daroussin }
325197bd480fSBaptiste Daroussin 
3252b04a7a0bSBaptiste Daroussin const ucl_object_t *
3253b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top)
325497bd480fSBaptiste Daroussin {
32558e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
32568e3b1ab2SBaptiste Daroussin 
325797bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
325897bd480fSBaptiste Daroussin 		return NULL;
325997bd480fSBaptiste Daroussin 	}
32608e3b1ab2SBaptiste Daroussin 
32618e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
326297bd480fSBaptiste Daroussin }
326397bd480fSBaptiste Daroussin 
326497bd480fSBaptiste Daroussin ucl_object_t *
326597bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top)
326697bd480fSBaptiste Daroussin {
32678e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
32688e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
32698e3b1ab2SBaptiste Daroussin 
32708e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
32718e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, vec->n - 1);
32728e3b1ab2SBaptiste Daroussin 		ret = *obj;
32738e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, vec->n - 1);
32748e3b1ab2SBaptiste Daroussin 		top->len --;
32758e3b1ab2SBaptiste Daroussin 	}
32768e3b1ab2SBaptiste Daroussin 
32778e3b1ab2SBaptiste Daroussin 	return ret;
327897bd480fSBaptiste Daroussin }
327997bd480fSBaptiste Daroussin 
328097bd480fSBaptiste Daroussin ucl_object_t *
328197bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top)
328297bd480fSBaptiste Daroussin {
32838e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
32848e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
32858e3b1ab2SBaptiste Daroussin 
32868e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
32878e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, 0);
32888e3b1ab2SBaptiste Daroussin 		ret = *obj;
32898e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, 0);
32908e3b1ab2SBaptiste Daroussin 		top->len --;
32918e3b1ab2SBaptiste Daroussin 	}
32928e3b1ab2SBaptiste Daroussin 
32938e3b1ab2SBaptiste Daroussin 	return ret;
329497bd480fSBaptiste Daroussin }
329597bd480fSBaptiste Daroussin 
3296*a0409676SBaptiste Daroussin unsigned int
3297*a0409676SBaptiste Daroussin ucl_array_size (const ucl_object_t *top)
3298*a0409676SBaptiste Daroussin {
3299*a0409676SBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY) {
3300*a0409676SBaptiste Daroussin 		return 0;
3301*a0409676SBaptiste Daroussin 	}
3302*a0409676SBaptiste Daroussin 
3303*a0409676SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
3304*a0409676SBaptiste Daroussin 
3305*a0409676SBaptiste Daroussin 	if (vec != NULL) {
3306*a0409676SBaptiste Daroussin 		return kv_size(*vec);
3307*a0409676SBaptiste Daroussin 	}
3308*a0409676SBaptiste Daroussin 
3309*a0409676SBaptiste Daroussin 	return 0;
3310*a0409676SBaptiste Daroussin }
3311*a0409676SBaptiste Daroussin 
33122e8ed2b8SBaptiste Daroussin const ucl_object_t *
33132e8ed2b8SBaptiste Daroussin ucl_array_find_index (const ucl_object_t *top, unsigned int index)
33142e8ed2b8SBaptiste Daroussin {
33158e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
33162e8ed2b8SBaptiste Daroussin 
33178e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
33188e3b1ab2SBaptiste Daroussin 		return kv_A (*vec, index);
33192e8ed2b8SBaptiste Daroussin 	}
33202e8ed2b8SBaptiste Daroussin 
33212e8ed2b8SBaptiste Daroussin 	return NULL;
33222e8ed2b8SBaptiste Daroussin }
33232e8ed2b8SBaptiste Daroussin 
332439ee7a7aSBaptiste Daroussin unsigned int
332539ee7a7aSBaptiste Daroussin ucl_array_index_of (ucl_object_t *top, ucl_object_t *elt)
332639ee7a7aSBaptiste Daroussin {
332739ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
332839ee7a7aSBaptiste Daroussin 	unsigned i;
332939ee7a7aSBaptiste Daroussin 
333039ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
333139ee7a7aSBaptiste Daroussin 		return (unsigned int)(-1);
333239ee7a7aSBaptiste Daroussin 	}
333339ee7a7aSBaptiste Daroussin 
333439ee7a7aSBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
333539ee7a7aSBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
333639ee7a7aSBaptiste Daroussin 			return i;
333739ee7a7aSBaptiste Daroussin 		}
333839ee7a7aSBaptiste Daroussin 	}
333939ee7a7aSBaptiste Daroussin 
334039ee7a7aSBaptiste Daroussin 	return (unsigned int)(-1);
334139ee7a7aSBaptiste Daroussin }
334239ee7a7aSBaptiste Daroussin 
334397bd480fSBaptiste Daroussin ucl_object_t *
33444bf54857SBaptiste Daroussin ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
33454bf54857SBaptiste Daroussin 	unsigned int index)
33464bf54857SBaptiste Daroussin {
33478e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
33488e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
33494bf54857SBaptiste Daroussin 
33508e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
33518e3b1ab2SBaptiste Daroussin 		ret = kv_A (*vec, index);
33528e3b1ab2SBaptiste Daroussin 		kv_A (*vec, index) = elt;
33534bf54857SBaptiste Daroussin 	}
33544bf54857SBaptiste Daroussin 
33558e3b1ab2SBaptiste Daroussin 	return ret;
33564bf54857SBaptiste Daroussin }
33574bf54857SBaptiste Daroussin 
33584bf54857SBaptiste Daroussin ucl_object_t *
335997bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
336097bd480fSBaptiste Daroussin {
336197bd480fSBaptiste Daroussin 
336297bd480fSBaptiste Daroussin 	if (head == NULL) {
336397bd480fSBaptiste Daroussin 		elt->next = NULL;
336497bd480fSBaptiste Daroussin 		elt->prev = elt;
336597bd480fSBaptiste Daroussin 		head = elt;
336697bd480fSBaptiste Daroussin 	}
336797bd480fSBaptiste Daroussin 	else {
336897bd480fSBaptiste Daroussin 		elt->prev = head->prev;
336997bd480fSBaptiste Daroussin 		head->prev->next = elt;
337097bd480fSBaptiste Daroussin 		head->prev = elt;
337197bd480fSBaptiste Daroussin 		elt->next = NULL;
337297bd480fSBaptiste Daroussin 	}
337397bd480fSBaptiste Daroussin 
337497bd480fSBaptiste Daroussin 	return head;
337597bd480fSBaptiste Daroussin }
337697bd480fSBaptiste Daroussin 
337797bd480fSBaptiste Daroussin bool
3378b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
337997bd480fSBaptiste Daroussin {
338097bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
338197bd480fSBaptiste Daroussin 		return false;
338297bd480fSBaptiste Daroussin 	}
338397bd480fSBaptiste Daroussin 	switch (obj->type) {
338497bd480fSBaptiste Daroussin 	case UCL_INT:
3385*a0409676SBaptiste Daroussin 		*target = obj->value.iv; /* Probably could cause overflow */
338697bd480fSBaptiste Daroussin 		break;
338797bd480fSBaptiste Daroussin 	case UCL_FLOAT:
338897bd480fSBaptiste Daroussin 	case UCL_TIME:
338997bd480fSBaptiste Daroussin 		*target = obj->value.dv;
339097bd480fSBaptiste Daroussin 		break;
339197bd480fSBaptiste Daroussin 	default:
339297bd480fSBaptiste Daroussin 		return false;
339397bd480fSBaptiste Daroussin 	}
339497bd480fSBaptiste Daroussin 
339597bd480fSBaptiste Daroussin 	return true;
339697bd480fSBaptiste Daroussin }
339797bd480fSBaptiste Daroussin 
339897bd480fSBaptiste Daroussin double
3399b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj)
340097bd480fSBaptiste Daroussin {
340197bd480fSBaptiste Daroussin 	double result = 0.;
340297bd480fSBaptiste Daroussin 
340397bd480fSBaptiste Daroussin 	ucl_object_todouble_safe (obj, &result);
340497bd480fSBaptiste Daroussin 	return result;
340597bd480fSBaptiste Daroussin }
340697bd480fSBaptiste Daroussin 
340797bd480fSBaptiste Daroussin bool
3408b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
340997bd480fSBaptiste Daroussin {
341097bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
341197bd480fSBaptiste Daroussin 		return false;
341297bd480fSBaptiste Daroussin 	}
341397bd480fSBaptiste Daroussin 	switch (obj->type) {
341497bd480fSBaptiste Daroussin 	case UCL_INT:
341597bd480fSBaptiste Daroussin 		*target = obj->value.iv;
341697bd480fSBaptiste Daroussin 		break;
341797bd480fSBaptiste Daroussin 	case UCL_FLOAT:
341897bd480fSBaptiste Daroussin 	case UCL_TIME:
3419*a0409676SBaptiste Daroussin 		*target = obj->value.dv; /* Losing of decimal points */
342097bd480fSBaptiste Daroussin 		break;
342197bd480fSBaptiste Daroussin 	default:
342297bd480fSBaptiste Daroussin 		return false;
342397bd480fSBaptiste Daroussin 	}
342497bd480fSBaptiste Daroussin 
342597bd480fSBaptiste Daroussin 	return true;
342697bd480fSBaptiste Daroussin }
342797bd480fSBaptiste Daroussin 
342897bd480fSBaptiste Daroussin int64_t
3429b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj)
343097bd480fSBaptiste Daroussin {
343197bd480fSBaptiste Daroussin 	int64_t result = 0;
343297bd480fSBaptiste Daroussin 
343397bd480fSBaptiste Daroussin 	ucl_object_toint_safe (obj, &result);
343497bd480fSBaptiste Daroussin 	return result;
343597bd480fSBaptiste Daroussin }
343697bd480fSBaptiste Daroussin 
343797bd480fSBaptiste Daroussin bool
3438b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
343997bd480fSBaptiste Daroussin {
344097bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
344197bd480fSBaptiste Daroussin 		return false;
344297bd480fSBaptiste Daroussin 	}
344397bd480fSBaptiste Daroussin 	switch (obj->type) {
344497bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
344597bd480fSBaptiste Daroussin 		*target = (obj->value.iv == true);
344697bd480fSBaptiste Daroussin 		break;
344797bd480fSBaptiste Daroussin 	default:
344897bd480fSBaptiste Daroussin 		return false;
344997bd480fSBaptiste Daroussin 	}
345097bd480fSBaptiste Daroussin 
345197bd480fSBaptiste Daroussin 	return true;
345297bd480fSBaptiste Daroussin }
345397bd480fSBaptiste Daroussin 
345497bd480fSBaptiste Daroussin bool
3455b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj)
345697bd480fSBaptiste Daroussin {
345797bd480fSBaptiste Daroussin 	bool result = false;
345897bd480fSBaptiste Daroussin 
345997bd480fSBaptiste Daroussin 	ucl_object_toboolean_safe (obj, &result);
346097bd480fSBaptiste Daroussin 	return result;
346197bd480fSBaptiste Daroussin }
346297bd480fSBaptiste Daroussin 
346397bd480fSBaptiste Daroussin bool
3464b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
346597bd480fSBaptiste Daroussin {
346697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
346797bd480fSBaptiste Daroussin 		return false;
346897bd480fSBaptiste Daroussin 	}
346997bd480fSBaptiste Daroussin 
347097bd480fSBaptiste Daroussin 	switch (obj->type) {
347197bd480fSBaptiste Daroussin 	case UCL_STRING:
347239ee7a7aSBaptiste Daroussin 		if (!(obj->flags & UCL_OBJECT_BINARY)) {
347397bd480fSBaptiste Daroussin 			*target = ucl_copy_value_trash (obj);
347439ee7a7aSBaptiste Daroussin 		}
347597bd480fSBaptiste Daroussin 		break;
347697bd480fSBaptiste Daroussin 	default:
347797bd480fSBaptiste Daroussin 		return false;
347897bd480fSBaptiste Daroussin 	}
347997bd480fSBaptiste Daroussin 
348097bd480fSBaptiste Daroussin 	return true;
348197bd480fSBaptiste Daroussin }
348297bd480fSBaptiste Daroussin 
348397bd480fSBaptiste Daroussin const char *
3484b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj)
348597bd480fSBaptiste Daroussin {
348697bd480fSBaptiste Daroussin 	const char *result = NULL;
348797bd480fSBaptiste Daroussin 
348897bd480fSBaptiste Daroussin 	ucl_object_tostring_safe (obj, &result);
348997bd480fSBaptiste Daroussin 	return result;
349097bd480fSBaptiste Daroussin }
349197bd480fSBaptiste Daroussin 
349297bd480fSBaptiste Daroussin const char *
3493b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj)
349497bd480fSBaptiste Daroussin {
349539ee7a7aSBaptiste Daroussin 	/* TODO: For binary strings we might encode string here */
349639ee7a7aSBaptiste Daroussin 	if (!(obj->flags & UCL_OBJECT_BINARY)) {
349797bd480fSBaptiste Daroussin 		return ucl_copy_value_trash (obj);
349897bd480fSBaptiste Daroussin 	}
349997bd480fSBaptiste Daroussin 
350039ee7a7aSBaptiste Daroussin 	return NULL;
350139ee7a7aSBaptiste Daroussin }
350239ee7a7aSBaptiste Daroussin 
350397bd480fSBaptiste Daroussin bool
3504b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
350597bd480fSBaptiste Daroussin {
350697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
350797bd480fSBaptiste Daroussin 		return false;
350897bd480fSBaptiste Daroussin 	}
350997bd480fSBaptiste Daroussin 	switch (obj->type) {
351097bd480fSBaptiste Daroussin 	case UCL_STRING:
351197bd480fSBaptiste Daroussin 		*target = obj->value.sv;
351297bd480fSBaptiste Daroussin 		if (tlen != NULL) {
351397bd480fSBaptiste Daroussin 			*tlen = obj->len;
351497bd480fSBaptiste Daroussin 		}
351597bd480fSBaptiste Daroussin 		break;
351697bd480fSBaptiste Daroussin 	default:
351797bd480fSBaptiste Daroussin 		return false;
351897bd480fSBaptiste Daroussin 	}
351997bd480fSBaptiste Daroussin 
352097bd480fSBaptiste Daroussin 	return true;
352197bd480fSBaptiste Daroussin }
352297bd480fSBaptiste Daroussin 
352397bd480fSBaptiste Daroussin const char *
3524b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
352597bd480fSBaptiste Daroussin {
352697bd480fSBaptiste Daroussin 	const char *result = NULL;
352797bd480fSBaptiste Daroussin 
352897bd480fSBaptiste Daroussin 	ucl_object_tolstring_safe (obj, &result, tlen);
352997bd480fSBaptiste Daroussin 	return result;
353097bd480fSBaptiste Daroussin }
353197bd480fSBaptiste Daroussin 
353297bd480fSBaptiste Daroussin const char *
3533b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj)
353497bd480fSBaptiste Daroussin {
353597bd480fSBaptiste Daroussin 	return ucl_copy_key_trash (obj);
353697bd480fSBaptiste Daroussin }
353797bd480fSBaptiste Daroussin 
353897bd480fSBaptiste Daroussin const char *
3539b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len)
354097bd480fSBaptiste Daroussin {
354197bd480fSBaptiste Daroussin 	if (len == NULL || obj == NULL) {
354297bd480fSBaptiste Daroussin 		return NULL;
354397bd480fSBaptiste Daroussin 	}
354497bd480fSBaptiste Daroussin 	*len = obj->keylen;
354597bd480fSBaptiste Daroussin 	return obj->key;
354697bd480fSBaptiste Daroussin }
354797bd480fSBaptiste Daroussin 
354897bd480fSBaptiste Daroussin ucl_object_t *
3549b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj)
355097bd480fSBaptiste Daroussin {
3551b04a7a0bSBaptiste Daroussin 	ucl_object_t *res = NULL;
3552b04a7a0bSBaptiste Daroussin 
355397bd480fSBaptiste Daroussin 	if (obj != NULL) {
35544bf54857SBaptiste Daroussin 		if (obj->flags & UCL_OBJECT_EPHEMERAL) {
35554bf54857SBaptiste Daroussin 			/*
35564bf54857SBaptiste Daroussin 			 * Use deep copy for ephemeral objects, note that its refcount
35574bf54857SBaptiste Daroussin 			 * is NOT increased, since ephemeral objects does not need refcount
35584bf54857SBaptiste Daroussin 			 * at all
35594bf54857SBaptiste Daroussin 			 */
35604bf54857SBaptiste Daroussin 			res = ucl_object_copy (obj);
35614bf54857SBaptiste Daroussin 		}
35624bf54857SBaptiste Daroussin 		else {
3563b04a7a0bSBaptiste Daroussin 			res = __DECONST (ucl_object_t *, obj);
3564b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3565b04a7a0bSBaptiste Daroussin 			(void)__sync_add_and_fetch (&res->ref, 1);
3566b04a7a0bSBaptiste Daroussin #else
3567b04a7a0bSBaptiste Daroussin 			res->ref ++;
3568b04a7a0bSBaptiste Daroussin #endif
356997bd480fSBaptiste Daroussin 		}
35704bf54857SBaptiste Daroussin 	}
3571b04a7a0bSBaptiste Daroussin 	return res;
357297bd480fSBaptiste Daroussin }
357397bd480fSBaptiste Daroussin 
35744bf54857SBaptiste Daroussin static ucl_object_t *
35754bf54857SBaptiste Daroussin ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
35764bf54857SBaptiste Daroussin {
35774bf54857SBaptiste Daroussin 
35784bf54857SBaptiste Daroussin 	ucl_object_t *new;
35794bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
35804bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
35814bf54857SBaptiste Daroussin 
35824bf54857SBaptiste Daroussin 	new = malloc (sizeof (*new));
35834bf54857SBaptiste Daroussin 
35844bf54857SBaptiste Daroussin 	if (new != NULL) {
35854bf54857SBaptiste Daroussin 		memcpy (new, other, sizeof (*new));
35864bf54857SBaptiste Daroussin 		if (other->flags & UCL_OBJECT_EPHEMERAL) {
35874bf54857SBaptiste Daroussin 			/* Copied object is always non ephemeral */
35884bf54857SBaptiste Daroussin 			new->flags &= ~UCL_OBJECT_EPHEMERAL;
35894bf54857SBaptiste Daroussin 		}
35904bf54857SBaptiste Daroussin 		new->ref = 1;
35914bf54857SBaptiste Daroussin 		/* Unlink from others */
35924bf54857SBaptiste Daroussin 		new->next = NULL;
35934bf54857SBaptiste Daroussin 		new->prev = new;
35944bf54857SBaptiste Daroussin 
35954bf54857SBaptiste Daroussin 		/* deep copy of values stored */
35964bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
35974bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_KEY] =
35984bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_KEY]);
35994bf54857SBaptiste Daroussin 			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
36004bf54857SBaptiste Daroussin 				new->key = new->trash_stack[UCL_TRASH_KEY];
36014bf54857SBaptiste Daroussin 			}
36024bf54857SBaptiste Daroussin 		}
36034bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
36044bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_VALUE] =
36054bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_VALUE]);
36064bf54857SBaptiste Daroussin 			if (new->type == UCL_STRING) {
36074bf54857SBaptiste Daroussin 				new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
36084bf54857SBaptiste Daroussin 			}
36094bf54857SBaptiste Daroussin 		}
36104bf54857SBaptiste Daroussin 
36114bf54857SBaptiste Daroussin 		if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
36124bf54857SBaptiste Daroussin 			/* reset old value */
36134bf54857SBaptiste Daroussin 			memset (&new->value, 0, sizeof (new->value));
36144bf54857SBaptiste Daroussin 
3615d9f0ce31SBaptiste Daroussin 			while ((cur = ucl_object_iterate (other, &it, true)) != NULL) {
36164bf54857SBaptiste Daroussin 				if (other->type == UCL_ARRAY) {
36174bf54857SBaptiste Daroussin 					ucl_array_append (new, ucl_object_copy_internal (cur, false));
36184bf54857SBaptiste Daroussin 				}
36194bf54857SBaptiste Daroussin 				else {
36204bf54857SBaptiste Daroussin 					ucl_object_t *cp = ucl_object_copy_internal (cur, true);
36214bf54857SBaptiste Daroussin 					if (cp != NULL) {
36224bf54857SBaptiste Daroussin 						ucl_object_insert_key (new, cp, cp->key, cp->keylen,
36234bf54857SBaptiste Daroussin 								false);
36244bf54857SBaptiste Daroussin 					}
36254bf54857SBaptiste Daroussin 				}
36264bf54857SBaptiste Daroussin 			}
36274bf54857SBaptiste Daroussin 		}
36284bf54857SBaptiste Daroussin 		else if (allow_array && other->next != NULL) {
36294bf54857SBaptiste Daroussin 			LL_FOREACH (other->next, cur) {
36304bf54857SBaptiste Daroussin 				ucl_object_t *cp = ucl_object_copy_internal (cur, false);
36314bf54857SBaptiste Daroussin 				if (cp != NULL) {
36324bf54857SBaptiste Daroussin 					DL_APPEND (new, cp);
36334bf54857SBaptiste Daroussin 				}
36344bf54857SBaptiste Daroussin 			}
36354bf54857SBaptiste Daroussin 		}
36364bf54857SBaptiste Daroussin 	}
36374bf54857SBaptiste Daroussin 
36384bf54857SBaptiste Daroussin 	return new;
36394bf54857SBaptiste Daroussin }
36404bf54857SBaptiste Daroussin 
36414bf54857SBaptiste Daroussin ucl_object_t *
36424bf54857SBaptiste Daroussin ucl_object_copy (const ucl_object_t *other)
36434bf54857SBaptiste Daroussin {
36444bf54857SBaptiste Daroussin 	return ucl_object_copy_internal (other, true);
36454bf54857SBaptiste Daroussin }
36464bf54857SBaptiste Daroussin 
364797bd480fSBaptiste Daroussin void
364897bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj)
364997bd480fSBaptiste Daroussin {
3650b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
3651b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3652b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
3653b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
3654b04a7a0bSBaptiste Daroussin #else
3655b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
3656b04a7a0bSBaptiste Daroussin #endif
3657b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
3658b04a7a0bSBaptiste Daroussin 		}
365997bd480fSBaptiste Daroussin 	}
366097bd480fSBaptiste Daroussin }
366197bd480fSBaptiste Daroussin 
366297bd480fSBaptiste Daroussin int
3663b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
366497bd480fSBaptiste Daroussin {
3665b04a7a0bSBaptiste Daroussin 	const ucl_object_t *it1, *it2;
366697bd480fSBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
366797bd480fSBaptiste Daroussin 	int ret = 0;
366897bd480fSBaptiste Daroussin 
3669*a0409676SBaptiste Daroussin     // Must check for NULL or code will segfault
3670*a0409676SBaptiste Daroussin     if ((o1 == NULL) || (o2 == NULL))
3671*a0409676SBaptiste Daroussin     {
3672*a0409676SBaptiste Daroussin         // The only way this could be true is of both are NULL
3673*a0409676SBaptiste Daroussin         return (o1 == NULL) && (o2 == NULL);
3674*a0409676SBaptiste Daroussin     }
3675*a0409676SBaptiste Daroussin 
367697bd480fSBaptiste Daroussin 	if (o1->type != o2->type) {
367797bd480fSBaptiste Daroussin 		return (o1->type) - (o2->type);
367897bd480fSBaptiste Daroussin 	}
367997bd480fSBaptiste Daroussin 
368097bd480fSBaptiste Daroussin 	switch (o1->type) {
368197bd480fSBaptiste Daroussin 	case UCL_STRING:
36828e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
368397bd480fSBaptiste Daroussin 			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
368497bd480fSBaptiste Daroussin 		}
368597bd480fSBaptiste Daroussin 		else {
368697bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
368797bd480fSBaptiste Daroussin 		}
368897bd480fSBaptiste Daroussin 		break;
368997bd480fSBaptiste Daroussin 	case UCL_FLOAT:
369097bd480fSBaptiste Daroussin 	case UCL_INT:
369197bd480fSBaptiste Daroussin 	case UCL_TIME:
369297bd480fSBaptiste Daroussin 		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
369397bd480fSBaptiste Daroussin 		break;
369497bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
369597bd480fSBaptiste Daroussin 		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
369697bd480fSBaptiste Daroussin 		break;
369797bd480fSBaptiste Daroussin 	case UCL_ARRAY:
36988e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
36998e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec1, o1);
37008e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec2, o2);
37018e3b1ab2SBaptiste Daroussin 			unsigned i;
37028e3b1ab2SBaptiste Daroussin 
370397bd480fSBaptiste Daroussin 			/* Compare all elements in both arrays */
37048e3b1ab2SBaptiste Daroussin 			for (i = 0; i < vec1->n; i ++) {
37058e3b1ab2SBaptiste Daroussin 				it1 = kv_A (*vec1, i);
37068e3b1ab2SBaptiste Daroussin 				it2 = kv_A (*vec2, i);
37078e3b1ab2SBaptiste Daroussin 
37088e3b1ab2SBaptiste Daroussin 				if (it1 == NULL && it2 != NULL) {
37098e3b1ab2SBaptiste Daroussin 					return -1;
37108e3b1ab2SBaptiste Daroussin 				}
37118e3b1ab2SBaptiste Daroussin 				else if (it2 == NULL && it1 != NULL) {
37128e3b1ab2SBaptiste Daroussin 					return 1;
37138e3b1ab2SBaptiste Daroussin 				}
37148e3b1ab2SBaptiste Daroussin 				else if (it1 != NULL && it2 != NULL) {
371597bd480fSBaptiste Daroussin 					ret = ucl_object_compare (it1, it2);
371697bd480fSBaptiste Daroussin 					if (ret != 0) {
371797bd480fSBaptiste Daroussin 						break;
371897bd480fSBaptiste Daroussin 					}
37198e3b1ab2SBaptiste Daroussin 				}
372097bd480fSBaptiste Daroussin 			}
372197bd480fSBaptiste Daroussin 		}
372297bd480fSBaptiste Daroussin 		else {
372397bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
372497bd480fSBaptiste Daroussin 		}
372597bd480fSBaptiste Daroussin 		break;
372697bd480fSBaptiste Daroussin 	case UCL_OBJECT:
37278e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
3728d9f0ce31SBaptiste Daroussin 			while ((it1 = ucl_object_iterate (o1, &iter, true)) != NULL) {
3729d9f0ce31SBaptiste Daroussin 				it2 = ucl_object_lookup (o2, ucl_object_key (it1));
373097bd480fSBaptiste Daroussin 				if (it2 == NULL) {
373197bd480fSBaptiste Daroussin 					ret = 1;
373297bd480fSBaptiste Daroussin 					break;
373397bd480fSBaptiste Daroussin 				}
373497bd480fSBaptiste Daroussin 				ret = ucl_object_compare (it1, it2);
373597bd480fSBaptiste Daroussin 				if (ret != 0) {
373697bd480fSBaptiste Daroussin 					break;
373797bd480fSBaptiste Daroussin 				}
373897bd480fSBaptiste Daroussin 			}
373997bd480fSBaptiste Daroussin 		}
374097bd480fSBaptiste Daroussin 		else {
374197bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
374297bd480fSBaptiste Daroussin 		}
374397bd480fSBaptiste Daroussin 		break;
374497bd480fSBaptiste Daroussin 	default:
374597bd480fSBaptiste Daroussin 		ret = 0;
374697bd480fSBaptiste Daroussin 		break;
374797bd480fSBaptiste Daroussin 	}
374897bd480fSBaptiste Daroussin 
374997bd480fSBaptiste Daroussin 	return ret;
375097bd480fSBaptiste Daroussin }
375197bd480fSBaptiste Daroussin 
3752d9f0ce31SBaptiste Daroussin int
3753d9f0ce31SBaptiste Daroussin ucl_object_compare_qsort (const ucl_object_t **o1,
3754d9f0ce31SBaptiste Daroussin 		const ucl_object_t **o2)
3755d9f0ce31SBaptiste Daroussin {
3756d9f0ce31SBaptiste Daroussin 	return ucl_object_compare (*o1, *o2);
3757d9f0ce31SBaptiste Daroussin }
3758d9f0ce31SBaptiste Daroussin 
375997bd480fSBaptiste Daroussin void
376097bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar,
376139ee7a7aSBaptiste Daroussin 		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
376297bd480fSBaptiste Daroussin {
37638e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, ar);
37648e3b1ab2SBaptiste Daroussin 
376597bd480fSBaptiste Daroussin 	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
376697bd480fSBaptiste Daroussin 		return;
376797bd480fSBaptiste Daroussin 	}
376897bd480fSBaptiste Daroussin 
37698e3b1ab2SBaptiste Daroussin 	qsort (vec->a, vec->n, sizeof (ucl_object_t *),
37708e3b1ab2SBaptiste Daroussin 			(int (*)(const void *, const void *))cmp);
377197bd480fSBaptiste Daroussin }
37724bf54857SBaptiste Daroussin 
3773*a0409676SBaptiste Daroussin void ucl_object_sort_keys (ucl_object_t *obj,
3774*a0409676SBaptiste Daroussin 		enum ucl_object_keys_sort_flags how)
3775*a0409676SBaptiste Daroussin {
3776*a0409676SBaptiste Daroussin 	if (obj != NULL && obj->type == UCL_OBJECT) {
3777*a0409676SBaptiste Daroussin 		ucl_hash_sort (obj->value.ov, how);
3778*a0409676SBaptiste Daroussin 	}
3779*a0409676SBaptiste Daroussin }
3780*a0409676SBaptiste Daroussin 
37814bf54857SBaptiste Daroussin #define PRIOBITS 4
37824bf54857SBaptiste Daroussin 
37834bf54857SBaptiste Daroussin unsigned int
37844bf54857SBaptiste Daroussin ucl_object_get_priority (const ucl_object_t *obj)
37854bf54857SBaptiste Daroussin {
37864bf54857SBaptiste Daroussin 	if (obj == NULL) {
37874bf54857SBaptiste Daroussin 		return 0;
37884bf54857SBaptiste Daroussin 	}
37894bf54857SBaptiste Daroussin 
37904bf54857SBaptiste Daroussin 	return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
37914bf54857SBaptiste Daroussin }
37924bf54857SBaptiste Daroussin 
37934bf54857SBaptiste Daroussin void
37944bf54857SBaptiste Daroussin ucl_object_set_priority (ucl_object_t *obj,
37954bf54857SBaptiste Daroussin 		unsigned int priority)
37964bf54857SBaptiste Daroussin {
37974bf54857SBaptiste Daroussin 	if (obj != NULL) {
37984bf54857SBaptiste Daroussin 		priority &= (0x1 << PRIOBITS) - 1;
379939ee7a7aSBaptiste Daroussin 		priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS);
380039ee7a7aSBaptiste Daroussin 		priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) -
380139ee7a7aSBaptiste Daroussin 				PRIOBITS)) - 1);
380239ee7a7aSBaptiste Daroussin 		obj->flags = priority;
38034bf54857SBaptiste Daroussin 	}
38044bf54857SBaptiste Daroussin }
3805d9f0ce31SBaptiste Daroussin 
3806d9f0ce31SBaptiste Daroussin bool
3807d9f0ce31SBaptiste Daroussin ucl_object_string_to_type (const char *input, ucl_type_t *res)
3808d9f0ce31SBaptiste Daroussin {
3809d9f0ce31SBaptiste Daroussin 	if (strcasecmp (input, "object") == 0) {
3810d9f0ce31SBaptiste Daroussin 		*res = UCL_OBJECT;
3811d9f0ce31SBaptiste Daroussin 	}
3812d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "array") == 0) {
3813d9f0ce31SBaptiste Daroussin 		*res = UCL_ARRAY;
3814d9f0ce31SBaptiste Daroussin 	}
3815d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "integer") == 0) {
3816d9f0ce31SBaptiste Daroussin 		*res = UCL_INT;
3817d9f0ce31SBaptiste Daroussin 	}
3818d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "number") == 0) {
3819d9f0ce31SBaptiste Daroussin 		*res = UCL_FLOAT;
3820d9f0ce31SBaptiste Daroussin 	}
3821d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "string") == 0) {
3822d9f0ce31SBaptiste Daroussin 		*res = UCL_STRING;
3823d9f0ce31SBaptiste Daroussin 	}
3824d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "boolean") == 0) {
3825d9f0ce31SBaptiste Daroussin 		*res = UCL_BOOLEAN;
3826d9f0ce31SBaptiste Daroussin 	}
3827d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "null") == 0) {
3828d9f0ce31SBaptiste Daroussin 		*res = UCL_NULL;
3829d9f0ce31SBaptiste Daroussin 	}
3830d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "userdata") == 0) {
3831d9f0ce31SBaptiste Daroussin 		*res = UCL_USERDATA;
3832d9f0ce31SBaptiste Daroussin 	}
3833d9f0ce31SBaptiste Daroussin 	else {
3834d9f0ce31SBaptiste Daroussin 		return false;
3835d9f0ce31SBaptiste Daroussin 	}
3836d9f0ce31SBaptiste Daroussin 
3837d9f0ce31SBaptiste Daroussin 	return true;
3838d9f0ce31SBaptiste Daroussin }
3839d9f0ce31SBaptiste Daroussin 
3840d9f0ce31SBaptiste Daroussin const char *
3841d9f0ce31SBaptiste Daroussin ucl_object_type_to_string (ucl_type_t type)
3842d9f0ce31SBaptiste Daroussin {
3843d9f0ce31SBaptiste Daroussin 	const char *res = "unknown";
3844d9f0ce31SBaptiste Daroussin 
3845d9f0ce31SBaptiste Daroussin 	switch (type) {
3846d9f0ce31SBaptiste Daroussin 	case UCL_OBJECT:
3847d9f0ce31SBaptiste Daroussin 		res = "object";
3848d9f0ce31SBaptiste Daroussin 		break;
3849d9f0ce31SBaptiste Daroussin 	case UCL_ARRAY:
3850d9f0ce31SBaptiste Daroussin 		res = "array";
3851d9f0ce31SBaptiste Daroussin 		break;
3852d9f0ce31SBaptiste Daroussin 	case UCL_INT:
3853d9f0ce31SBaptiste Daroussin 		res = "integer";
3854d9f0ce31SBaptiste Daroussin 		break;
3855d9f0ce31SBaptiste Daroussin 	case UCL_FLOAT:
3856d9f0ce31SBaptiste Daroussin 	case UCL_TIME:
3857d9f0ce31SBaptiste Daroussin 		res = "number";
3858d9f0ce31SBaptiste Daroussin 		break;
3859d9f0ce31SBaptiste Daroussin 	case UCL_STRING:
3860d9f0ce31SBaptiste Daroussin 		res = "string";
3861d9f0ce31SBaptiste Daroussin 		break;
3862d9f0ce31SBaptiste Daroussin 	case UCL_BOOLEAN:
3863d9f0ce31SBaptiste Daroussin 		res = "boolean";
3864d9f0ce31SBaptiste Daroussin 		break;
3865d9f0ce31SBaptiste Daroussin 	case UCL_USERDATA:
3866d9f0ce31SBaptiste Daroussin 		res = "userdata";
3867d9f0ce31SBaptiste Daroussin 		break;
3868d9f0ce31SBaptiste Daroussin 	case UCL_NULL:
3869d9f0ce31SBaptiste Daroussin 		res = "null";
3870d9f0ce31SBaptiste Daroussin 		break;
3871d9f0ce31SBaptiste Daroussin 	}
3872d9f0ce31SBaptiste Daroussin 
3873d9f0ce31SBaptiste Daroussin 	return res;
3874d9f0ce31SBaptiste Daroussin }
3875d9f0ce31SBaptiste Daroussin 
3876d9f0ce31SBaptiste Daroussin const ucl_object_t *
3877d9f0ce31SBaptiste Daroussin ucl_parser_get_comments (struct ucl_parser *parser)
3878d9f0ce31SBaptiste Daroussin {
3879d9f0ce31SBaptiste Daroussin 	if (parser && parser->comments) {
3880d9f0ce31SBaptiste Daroussin 		return parser->comments;
3881d9f0ce31SBaptiste Daroussin 	}
3882d9f0ce31SBaptiste Daroussin 
3883d9f0ce31SBaptiste Daroussin 	return NULL;
3884d9f0ce31SBaptiste Daroussin }
3885d9f0ce31SBaptiste Daroussin 
3886d9f0ce31SBaptiste Daroussin const ucl_object_t *
3887d9f0ce31SBaptiste Daroussin ucl_comments_find (const ucl_object_t *comments,
3888d9f0ce31SBaptiste Daroussin 		const ucl_object_t *srch)
3889d9f0ce31SBaptiste Daroussin {
3890d9f0ce31SBaptiste Daroussin 	if (comments && srch) {
3891d9f0ce31SBaptiste Daroussin 		return ucl_object_lookup_len (comments, (const char *)&srch,
3892d9f0ce31SBaptiste Daroussin 				sizeof (void *));
3893d9f0ce31SBaptiste Daroussin 	}
3894d9f0ce31SBaptiste Daroussin 
3895d9f0ce31SBaptiste Daroussin 	return NULL;
3896d9f0ce31SBaptiste Daroussin }
3897d9f0ce31SBaptiste Daroussin 
3898d9f0ce31SBaptiste Daroussin bool
3899d9f0ce31SBaptiste Daroussin ucl_comments_move (ucl_object_t *comments,
3900d9f0ce31SBaptiste Daroussin 		const ucl_object_t *from, const ucl_object_t *to)
3901d9f0ce31SBaptiste Daroussin {
3902d9f0ce31SBaptiste Daroussin 	const ucl_object_t *found;
3903d9f0ce31SBaptiste Daroussin 	ucl_object_t *obj;
3904d9f0ce31SBaptiste Daroussin 
3905d9f0ce31SBaptiste Daroussin 	if (comments && from && to) {
3906d9f0ce31SBaptiste Daroussin 		found = ucl_object_lookup_len (comments,
3907d9f0ce31SBaptiste Daroussin 				(const char *)&from, sizeof (void *));
3908d9f0ce31SBaptiste Daroussin 
3909d9f0ce31SBaptiste Daroussin 		if (found) {
3910d9f0ce31SBaptiste Daroussin 			/* Replace key */
3911d9f0ce31SBaptiste Daroussin 			obj = ucl_object_ref (found);
3912d9f0ce31SBaptiste Daroussin 			ucl_object_delete_keyl (comments, (const char *)&from,
3913d9f0ce31SBaptiste Daroussin 					sizeof (void *));
3914d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (comments, obj, (const char *)&to,
3915d9f0ce31SBaptiste Daroussin 					sizeof (void *), true);
3916d9f0ce31SBaptiste Daroussin 
3917d9f0ce31SBaptiste Daroussin 			return true;
3918d9f0ce31SBaptiste Daroussin 		}
3919d9f0ce31SBaptiste Daroussin 	}
3920d9f0ce31SBaptiste Daroussin 
3921d9f0ce31SBaptiste Daroussin 	return false;
3922d9f0ce31SBaptiste Daroussin }
3923d9f0ce31SBaptiste Daroussin 
3924d9f0ce31SBaptiste Daroussin void
3925d9f0ce31SBaptiste Daroussin ucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj,
3926d9f0ce31SBaptiste Daroussin 		const char *comment)
3927d9f0ce31SBaptiste Daroussin {
3928d9f0ce31SBaptiste Daroussin 	if (comments && obj && comment) {
3929d9f0ce31SBaptiste Daroussin 		ucl_object_insert_key (comments, ucl_object_fromstring (comment),
3930d9f0ce31SBaptiste Daroussin 				(const char *)&obj, sizeof (void *), true);
3931d9f0ce31SBaptiste Daroussin 	}
3932d9f0ce31SBaptiste Daroussin }
3933*a0409676SBaptiste Daroussin 
3934*a0409676SBaptiste Daroussin void
3935*a0409676SBaptiste Daroussin ucl_parser_set_include_tracer (struct ucl_parser *parser,
3936*a0409676SBaptiste Daroussin 							   ucl_include_trace_func_t func,
3937*a0409676SBaptiste Daroussin 							   void *user_data)
3938*a0409676SBaptiste Daroussin {
3939*a0409676SBaptiste Daroussin 	parser->include_trace_func = func;
3940*a0409676SBaptiste Daroussin 	parser->include_trace_ud = user_data;
3941*a0409676SBaptiste Daroussin }
3942*a0409676SBaptiste Daroussin 
3943*a0409676SBaptiste Daroussin const char *
3944*a0409676SBaptiste Daroussin ucl_parser_get_cur_file (struct ucl_parser *parser)
3945*a0409676SBaptiste Daroussin {
3946*a0409676SBaptiste Daroussin 	return parser->cur_file;
3947*a0409676SBaptiste Daroussin }
3948