xref: /freebsd/contrib/libucl/src/ucl_util.c (revision 11dd9ed6)
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"
29*11dd9ed6SBaptiste 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>
35*11dd9ed6SBaptiste Daroussin #include <sys/param.h>
36*11dd9ed6SBaptiste Daroussin #else
37*11dd9ed6SBaptiste Daroussin #ifndef NBBY
38*11dd9ed6SBaptiste Daroussin #define NBBY 8
39*11dd9ed6SBaptiste Daroussin #endif
408e3b1ab2SBaptiste Daroussin #endif
414bf54857SBaptiste Daroussin 
4297bd480fSBaptiste Daroussin #ifdef HAVE_LIBGEN_H
43c99fb5f9SBaptiste Daroussin #include <libgen.h> /* For dirname */
4497bd480fSBaptiste Daroussin #endif
45c99fb5f9SBaptiste Daroussin 
468e3b1ab2SBaptiste Daroussin typedef kvec_t(ucl_object_t *) ucl_array_t;
478e3b1ab2SBaptiste Daroussin 
488e3b1ab2SBaptiste Daroussin #define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \
498e3b1ab2SBaptiste Daroussin 	(ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL)
508e3b1ab2SBaptiste Daroussin 
51c99fb5f9SBaptiste Daroussin #ifdef HAVE_OPENSSL
52c99fb5f9SBaptiste Daroussin #include <openssl/err.h>
53c99fb5f9SBaptiste Daroussin #include <openssl/sha.h>
54c99fb5f9SBaptiste Daroussin #include <openssl/rsa.h>
55c99fb5f9SBaptiste Daroussin #include <openssl/ssl.h>
56c99fb5f9SBaptiste Daroussin #include <openssl/evp.h>
57c99fb5f9SBaptiste Daroussin #endif
58c99fb5f9SBaptiste Daroussin 
5997bd480fSBaptiste Daroussin #ifdef CURL_FOUND
60d9f0ce31SBaptiste Daroussin /* Seems to be broken */
61d9f0ce31SBaptiste Daroussin #define CURL_DISABLE_TYPECHECK 1
6297bd480fSBaptiste Daroussin #include <curl/curl.h>
6397bd480fSBaptiste Daroussin #endif
6497bd480fSBaptiste Daroussin #ifdef HAVE_FETCH_H
6597bd480fSBaptiste Daroussin #include <fetch.h>
6697bd480fSBaptiste Daroussin #endif
6797bd480fSBaptiste Daroussin 
6836c53d67SBaptiste Daroussin #ifdef _WIN32
6936c53d67SBaptiste Daroussin #include <windows.h>
7036c53d67SBaptiste Daroussin 
7197bd480fSBaptiste Daroussin #ifndef PROT_READ
7236c53d67SBaptiste Daroussin #define PROT_READ       1
7397bd480fSBaptiste Daroussin #endif
7497bd480fSBaptiste Daroussin #ifndef PROT_WRITE
7536c53d67SBaptiste Daroussin #define PROT_WRITE      2
7697bd480fSBaptiste Daroussin #endif
7797bd480fSBaptiste Daroussin #ifndef PROT_READWRITE
7836c53d67SBaptiste Daroussin #define PROT_READWRITE  3
7997bd480fSBaptiste Daroussin #endif
8097bd480fSBaptiste Daroussin #ifndef MAP_SHARED
8136c53d67SBaptiste Daroussin #define MAP_SHARED      1
8297bd480fSBaptiste Daroussin #endif
8397bd480fSBaptiste Daroussin #ifndef MAP_PRIVATE
8436c53d67SBaptiste Daroussin #define MAP_PRIVATE     2
8597bd480fSBaptiste Daroussin #endif
8697bd480fSBaptiste Daroussin #ifndef MAP_FAILED
8736c53d67SBaptiste Daroussin #define MAP_FAILED      ((void *) -1)
8897bd480fSBaptiste Daroussin #endif
8936c53d67SBaptiste Daroussin 
9097bd480fSBaptiste Daroussin static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
9136c53d67SBaptiste Daroussin {
9236c53d67SBaptiste Daroussin 	void *map = NULL;
9336c53d67SBaptiste Daroussin 	HANDLE handle = INVALID_HANDLE_VALUE;
9436c53d67SBaptiste Daroussin 
9536c53d67SBaptiste Daroussin 	switch (prot) {
9636c53d67SBaptiste Daroussin 	default:
9736c53d67SBaptiste Daroussin 	case PROT_READ:
9836c53d67SBaptiste Daroussin 		{
9936c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
10036c53d67SBaptiste Daroussin 			if (!handle) break;
10136c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
10236c53d67SBaptiste Daroussin 			CloseHandle(handle);
10336c53d67SBaptiste Daroussin 			break;
10436c53d67SBaptiste Daroussin 		}
10536c53d67SBaptiste Daroussin 	case PROT_WRITE:
10636c53d67SBaptiste Daroussin 		{
10736c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
10836c53d67SBaptiste Daroussin 			if (!handle) break;
10936c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
11036c53d67SBaptiste Daroussin 			CloseHandle(handle);
11136c53d67SBaptiste Daroussin 			break;
11236c53d67SBaptiste Daroussin 		}
11336c53d67SBaptiste Daroussin 	case PROT_READWRITE:
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_ALL_ACCESS, 0, 0, length);
11836c53d67SBaptiste Daroussin 			CloseHandle(handle);
11936c53d67SBaptiste Daroussin 			break;
12036c53d67SBaptiste Daroussin 		}
12136c53d67SBaptiste Daroussin 	}
12236c53d67SBaptiste Daroussin 	if (map == (void *) NULL) {
12336c53d67SBaptiste Daroussin 		return (void *) MAP_FAILED;
12436c53d67SBaptiste Daroussin 	}
12536c53d67SBaptiste Daroussin 	return (void *) ((char *) map + offset);
12636c53d67SBaptiste Daroussin }
12736c53d67SBaptiste Daroussin 
12897bd480fSBaptiste Daroussin static int ucl_munmap(void *map,size_t length)
12936c53d67SBaptiste Daroussin {
13036c53d67SBaptiste Daroussin 	if (!UnmapViewOfFile(map)) {
13136c53d67SBaptiste Daroussin 		return(-1);
13236c53d67SBaptiste Daroussin 	}
13336c53d67SBaptiste Daroussin 	return(0);
13436c53d67SBaptiste Daroussin }
13536c53d67SBaptiste Daroussin 
13697bd480fSBaptiste Daroussin static char* ucl_realpath(const char *path, char *resolved_path) {
13736c53d67SBaptiste Daroussin     char *p;
13836c53d67SBaptiste Daroussin     char tmp[MAX_PATH + 1];
13936c53d67SBaptiste Daroussin     strncpy(tmp, path, sizeof(tmp)-1);
14036c53d67SBaptiste Daroussin     p = tmp;
14136c53d67SBaptiste Daroussin     while(*p) {
14236c53d67SBaptiste Daroussin         if (*p == '/') *p = '\\';
14336c53d67SBaptiste Daroussin         p++;
14436c53d67SBaptiste Daroussin     }
14536c53d67SBaptiste Daroussin     return _fullpath(resolved_path, tmp, MAX_PATH);
14636c53d67SBaptiste Daroussin }
14797bd480fSBaptiste Daroussin #else
14897bd480fSBaptiste Daroussin #define ucl_mmap mmap
14997bd480fSBaptiste Daroussin #define ucl_munmap munmap
15097bd480fSBaptiste Daroussin #define ucl_realpath realpath
15136c53d67SBaptiste Daroussin #endif
15236c53d67SBaptiste Daroussin 
153b04a7a0bSBaptiste Daroussin typedef void (*ucl_object_dtor) (ucl_object_t *obj);
154b04a7a0bSBaptiste Daroussin static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
155b04a7a0bSBaptiste Daroussin 		ucl_object_dtor dtor);
156b04a7a0bSBaptiste Daroussin static void ucl_object_dtor_unref (ucl_object_t *obj);
157c99fb5f9SBaptiste Daroussin 
158c99fb5f9SBaptiste Daroussin static void
159b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (ucl_object_t *obj)
160c99fb5f9SBaptiste Daroussin {
161c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
162c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
163c99fb5f9SBaptiste Daroussin 	}
164c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
165c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
166c99fb5f9SBaptiste Daroussin 	}
1674bf54857SBaptiste Daroussin 	/* Do not free ephemeral objects */
1684bf54857SBaptiste Daroussin 	if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
1694bf54857SBaptiste Daroussin 		if (obj->type != UCL_USERDATA) {
170b04a7a0bSBaptiste Daroussin 			UCL_FREE (sizeof (ucl_object_t), obj);
171b04a7a0bSBaptiste Daroussin 		}
1724bf54857SBaptiste Daroussin 		else {
1734bf54857SBaptiste Daroussin 			struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
1744bf54857SBaptiste Daroussin 			if (ud->dtor) {
1754bf54857SBaptiste Daroussin 				ud->dtor (obj->value.ud);
1764bf54857SBaptiste Daroussin 			}
1774bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (*ud), obj);
1784bf54857SBaptiste Daroussin 		}
1794bf54857SBaptiste Daroussin 	}
1804bf54857SBaptiste Daroussin }
181c99fb5f9SBaptiste Daroussin 
182b04a7a0bSBaptiste Daroussin /*
183b04a7a0bSBaptiste Daroussin  * This is a helper function that performs exactly the same as
184b04a7a0bSBaptiste Daroussin  * `ucl_object_unref` but it doesn't iterate over elements allowing
185b04a7a0bSBaptiste Daroussin  * to use it for individual elements of arrays and multiple values
186b04a7a0bSBaptiste Daroussin  */
187b04a7a0bSBaptiste Daroussin static void
188b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (ucl_object_t *obj)
189b04a7a0bSBaptiste Daroussin {
190b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
191b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
192b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
193b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
194b04a7a0bSBaptiste Daroussin #else
195b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
196b04a7a0bSBaptiste Daroussin #endif
197b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, false, ucl_object_dtor_unref);
198b04a7a0bSBaptiste Daroussin 		}
199b04a7a0bSBaptiste Daroussin 	}
200b04a7a0bSBaptiste Daroussin }
201b04a7a0bSBaptiste Daroussin 
202b04a7a0bSBaptiste Daroussin static void
203b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref (ucl_object_t *obj)
204b04a7a0bSBaptiste Daroussin {
205b04a7a0bSBaptiste Daroussin 	if (obj->ref == 0) {
206b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_free (obj);
207b04a7a0bSBaptiste Daroussin 	}
208b04a7a0bSBaptiste Daroussin 	else {
209b04a7a0bSBaptiste Daroussin 		/* This may cause dtor unref being called one more time */
210b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_unref_single (obj);
211b04a7a0bSBaptiste Daroussin 	}
212b04a7a0bSBaptiste Daroussin }
213b04a7a0bSBaptiste Daroussin 
214b04a7a0bSBaptiste Daroussin static void
215b04a7a0bSBaptiste Daroussin ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
216b04a7a0bSBaptiste Daroussin {
2178e3b1ab2SBaptiste Daroussin 	ucl_object_t *tmp, *sub;
218b04a7a0bSBaptiste Daroussin 
219b04a7a0bSBaptiste Daroussin 	while (obj != NULL) {
220c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_ARRAY) {
2218e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
2228e3b1ab2SBaptiste Daroussin 			unsigned int i;
2238e3b1ab2SBaptiste Daroussin 
2248e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
2258e3b1ab2SBaptiste Daroussin 				for (i = 0; i < vec->n; i ++) {
2268e3b1ab2SBaptiste Daroussin 					sub = kv_A (*vec, i);
2278e3b1ab2SBaptiste Daroussin 					if (sub != NULL) {
2288e3b1ab2SBaptiste Daroussin 						tmp = sub;
2298e3b1ab2SBaptiste Daroussin 						while (sub) {
230c99fb5f9SBaptiste Daroussin 							tmp = sub->next;
231b04a7a0bSBaptiste Daroussin 							dtor (sub);
232c99fb5f9SBaptiste Daroussin 							sub = tmp;
233c99fb5f9SBaptiste Daroussin 						}
234c99fb5f9SBaptiste Daroussin 					}
2358e3b1ab2SBaptiste Daroussin 				}
2368e3b1ab2SBaptiste Daroussin 				kv_destroy (*vec);
2378e3b1ab2SBaptiste Daroussin 				UCL_FREE (sizeof (*vec), vec);
2388e3b1ab2SBaptiste Daroussin 			}
23939ee7a7aSBaptiste Daroussin 			obj->value.av = NULL;
2408e3b1ab2SBaptiste Daroussin 		}
241c99fb5f9SBaptiste Daroussin 		else if (obj->type == UCL_OBJECT) {
242c99fb5f9SBaptiste Daroussin 			if (obj->value.ov != NULL) {
243d9f0ce31SBaptiste Daroussin 				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor);
244c99fb5f9SBaptiste Daroussin 			}
24539ee7a7aSBaptiste Daroussin 			obj->value.ov = NULL;
246c99fb5f9SBaptiste Daroussin 		}
247c99fb5f9SBaptiste Daroussin 		tmp = obj->next;
248b04a7a0bSBaptiste Daroussin 		dtor (obj);
249c99fb5f9SBaptiste Daroussin 		obj = tmp;
250c99fb5f9SBaptiste Daroussin 
251c99fb5f9SBaptiste Daroussin 		if (!allow_rec) {
252c99fb5f9SBaptiste Daroussin 			break;
253c99fb5f9SBaptiste Daroussin 		}
254c99fb5f9SBaptiste Daroussin 	}
255c99fb5f9SBaptiste Daroussin }
256c99fb5f9SBaptiste Daroussin 
257c99fb5f9SBaptiste Daroussin void
258c99fb5f9SBaptiste Daroussin ucl_object_free (ucl_object_t *obj)
259c99fb5f9SBaptiste Daroussin {
260b04a7a0bSBaptiste Daroussin 	ucl_object_free_internal (obj, true, ucl_object_dtor_free);
261c99fb5f9SBaptiste Daroussin }
262c99fb5f9SBaptiste Daroussin 
263c99fb5f9SBaptiste Daroussin size_t
264c99fb5f9SBaptiste Daroussin ucl_unescape_json_string (char *str, size_t len)
265c99fb5f9SBaptiste Daroussin {
266c99fb5f9SBaptiste Daroussin 	char *t = str, *h = str;
267c99fb5f9SBaptiste Daroussin 	int i, uval;
268c99fb5f9SBaptiste Daroussin 
26997bd480fSBaptiste Daroussin 	if (len <= 1) {
27097bd480fSBaptiste Daroussin 		return len;
27197bd480fSBaptiste Daroussin 	}
272c99fb5f9SBaptiste Daroussin 	/* t is target (tortoise), h is source (hare) */
273c99fb5f9SBaptiste Daroussin 
274c99fb5f9SBaptiste Daroussin 	while (len) {
275c99fb5f9SBaptiste Daroussin 		if (*h == '\\') {
276c99fb5f9SBaptiste Daroussin 			h ++;
27739ee7a7aSBaptiste Daroussin 
27839ee7a7aSBaptiste Daroussin 			if (len == 1) {
27939ee7a7aSBaptiste Daroussin 				/*
28039ee7a7aSBaptiste Daroussin 				 * If \ is last, then do not try to go further
28139ee7a7aSBaptiste Daroussin 				 * Issue: #74
28239ee7a7aSBaptiste Daroussin 				 */
28339ee7a7aSBaptiste Daroussin 				len --;
28439ee7a7aSBaptiste Daroussin 				*t++ = '\\';
28539ee7a7aSBaptiste Daroussin 				continue;
28639ee7a7aSBaptiste Daroussin 			}
28739ee7a7aSBaptiste Daroussin 
288c99fb5f9SBaptiste Daroussin 			switch (*h) {
289c99fb5f9SBaptiste Daroussin 			case 'n':
290c99fb5f9SBaptiste Daroussin 				*t++ = '\n';
291c99fb5f9SBaptiste Daroussin 				break;
292c99fb5f9SBaptiste Daroussin 			case 'r':
293c99fb5f9SBaptiste Daroussin 				*t++ = '\r';
294c99fb5f9SBaptiste Daroussin 				break;
295c99fb5f9SBaptiste Daroussin 			case 'b':
296c99fb5f9SBaptiste Daroussin 				*t++ = '\b';
297c99fb5f9SBaptiste Daroussin 				break;
298c99fb5f9SBaptiste Daroussin 			case 't':
299c99fb5f9SBaptiste Daroussin 				*t++ = '\t';
300c99fb5f9SBaptiste Daroussin 				break;
301c99fb5f9SBaptiste Daroussin 			case 'f':
302c99fb5f9SBaptiste Daroussin 				*t++ = '\f';
303c99fb5f9SBaptiste Daroussin 				break;
304c99fb5f9SBaptiste Daroussin 			case '\\':
305c99fb5f9SBaptiste Daroussin 				*t++ = '\\';
306c99fb5f9SBaptiste Daroussin 				break;
307c99fb5f9SBaptiste Daroussin 			case '"':
308c99fb5f9SBaptiste Daroussin 				*t++ = '"';
309c99fb5f9SBaptiste Daroussin 				break;
310c99fb5f9SBaptiste Daroussin 			case 'u':
311c99fb5f9SBaptiste Daroussin 				/* Unicode escape */
312c99fb5f9SBaptiste Daroussin 				uval = 0;
313d9f0ce31SBaptiste Daroussin 				h ++; /* u character */
314d9f0ce31SBaptiste Daroussin 				len --;
315d9f0ce31SBaptiste Daroussin 
31697bd480fSBaptiste Daroussin 				if (len > 3) {
317c99fb5f9SBaptiste Daroussin 					for (i = 0; i < 4; i++) {
318c99fb5f9SBaptiste Daroussin 						uval <<= 4;
319c99fb5f9SBaptiste Daroussin 						if (isdigit (h[i])) {
320c99fb5f9SBaptiste Daroussin 							uval += h[i] - '0';
321c99fb5f9SBaptiste Daroussin 						}
322c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'a' && h[i] <= 'f') {
323c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'a' + 10;
324c99fb5f9SBaptiste Daroussin 						}
325c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'A' && h[i] <= 'F') {
326c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'A' + 10;
327c99fb5f9SBaptiste Daroussin 						}
32897bd480fSBaptiste Daroussin 						else {
32997bd480fSBaptiste Daroussin 							break;
33097bd480fSBaptiste Daroussin 						}
331c99fb5f9SBaptiste Daroussin 					}
332d9f0ce31SBaptiste Daroussin 
333c99fb5f9SBaptiste Daroussin 					/* Encode */
334c99fb5f9SBaptiste Daroussin 					if(uval < 0x80) {
335c99fb5f9SBaptiste Daroussin 						t[0] = (char)uval;
336c99fb5f9SBaptiste Daroussin 						t ++;
337c99fb5f9SBaptiste Daroussin 					}
338c99fb5f9SBaptiste Daroussin 					else if(uval < 0x800) {
339c99fb5f9SBaptiste Daroussin 						t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
340c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F));
341c99fb5f9SBaptiste Daroussin 						t += 2;
342c99fb5f9SBaptiste Daroussin 					}
343c99fb5f9SBaptiste Daroussin 					else if(uval < 0x10000) {
344c99fb5f9SBaptiste Daroussin 						t[0] = 0xE0 + ((uval & 0xF000) >> 12);
345c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
346c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x003F));
347c99fb5f9SBaptiste Daroussin 						t += 3;
348c99fb5f9SBaptiste Daroussin 					}
349d9f0ce31SBaptiste Daroussin #if 0
350d9f0ce31SBaptiste Daroussin 					/* It's not actually supported now */
351c99fb5f9SBaptiste Daroussin 					else if(uval <= 0x10FFFF) {
352c99fb5f9SBaptiste Daroussin 						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
353c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
354c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
355c99fb5f9SBaptiste Daroussin 						t[3] = 0x80 + ((uval & 0x00003F));
356c99fb5f9SBaptiste Daroussin 						t += 4;
357c99fb5f9SBaptiste Daroussin 					}
358d9f0ce31SBaptiste Daroussin #endif
359c99fb5f9SBaptiste Daroussin 					else {
360c99fb5f9SBaptiste Daroussin 						*t++ = '?';
361c99fb5f9SBaptiste Daroussin 					}
362d9f0ce31SBaptiste Daroussin 
363d9f0ce31SBaptiste Daroussin 					/* Consume 4 characters of source */
364d9f0ce31SBaptiste Daroussin 					h += 4;
365d9f0ce31SBaptiste Daroussin 					len -= 4;
366d9f0ce31SBaptiste Daroussin 
367d9f0ce31SBaptiste Daroussin 					if (len > 0) {
368d9f0ce31SBaptiste Daroussin 						len --; /* for '\' character */
369d9f0ce31SBaptiste Daroussin 					}
370d9f0ce31SBaptiste Daroussin 					continue;
37197bd480fSBaptiste Daroussin 				}
37297bd480fSBaptiste Daroussin 				else {
37397bd480fSBaptiste Daroussin 					*t++ = 'u';
37497bd480fSBaptiste Daroussin 				}
375c99fb5f9SBaptiste Daroussin 				break;
376c99fb5f9SBaptiste Daroussin 			default:
377c99fb5f9SBaptiste Daroussin 				*t++ = *h;
378c99fb5f9SBaptiste Daroussin 				break;
379c99fb5f9SBaptiste Daroussin 			}
380c99fb5f9SBaptiste Daroussin 			h ++;
381c99fb5f9SBaptiste Daroussin 			len --;
382c99fb5f9SBaptiste Daroussin 		}
383c99fb5f9SBaptiste Daroussin 		else {
384c99fb5f9SBaptiste Daroussin 			*t++ = *h++;
385c99fb5f9SBaptiste Daroussin 		}
38639ee7a7aSBaptiste Daroussin 
38739ee7a7aSBaptiste Daroussin 		if (len > 0) {
388c99fb5f9SBaptiste Daroussin 			len --;
389c99fb5f9SBaptiste Daroussin 		}
39039ee7a7aSBaptiste Daroussin 	}
391c99fb5f9SBaptiste Daroussin 	*t = '\0';
392c99fb5f9SBaptiste Daroussin 
393c99fb5f9SBaptiste Daroussin 	return (t - str);
394c99fb5f9SBaptiste Daroussin }
395c99fb5f9SBaptiste Daroussin 
396b04a7a0bSBaptiste Daroussin char *
397b04a7a0bSBaptiste Daroussin ucl_copy_key_trash (const ucl_object_t *obj)
398c99fb5f9SBaptiste Daroussin {
399b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
400b04a7a0bSBaptiste Daroussin 
40197bd480fSBaptiste Daroussin 	if (obj == NULL) {
40297bd480fSBaptiste Daroussin 		return NULL;
40397bd480fSBaptiste Daroussin 	}
404c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
405b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
406b04a7a0bSBaptiste Daroussin 		deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
407b04a7a0bSBaptiste Daroussin 		if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
408b04a7a0bSBaptiste Daroussin 			memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
409b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
410c99fb5f9SBaptiste Daroussin 		}
411b04a7a0bSBaptiste Daroussin 		deconst->key = obj->trash_stack[UCL_TRASH_KEY];
412b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
413c99fb5f9SBaptiste Daroussin 	}
414c99fb5f9SBaptiste Daroussin 
415c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_KEY];
416c99fb5f9SBaptiste Daroussin }
417c99fb5f9SBaptiste Daroussin 
418b04a7a0bSBaptiste Daroussin char *
419b04a7a0bSBaptiste Daroussin ucl_copy_value_trash (const ucl_object_t *obj)
420c99fb5f9SBaptiste Daroussin {
421b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
422b04a7a0bSBaptiste Daroussin 
42397bd480fSBaptiste Daroussin 	if (obj == NULL) {
42497bd480fSBaptiste Daroussin 		return NULL;
42597bd480fSBaptiste Daroussin 	}
426c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
427b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
428c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_STRING) {
429b04a7a0bSBaptiste Daroussin 
430c99fb5f9SBaptiste Daroussin 			/* Special case for strings */
43139ee7a7aSBaptiste Daroussin 			if (obj->flags & UCL_OBJECT_BINARY) {
43239ee7a7aSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len);
43339ee7a7aSBaptiste Daroussin 				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
43439ee7a7aSBaptiste Daroussin 					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
43539ee7a7aSBaptiste Daroussin 							obj->value.sv,
43639ee7a7aSBaptiste Daroussin 							obj->len);
43739ee7a7aSBaptiste Daroussin 					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
43839ee7a7aSBaptiste Daroussin 				}
43939ee7a7aSBaptiste Daroussin 			}
44039ee7a7aSBaptiste Daroussin 			else {
441b04a7a0bSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
442b04a7a0bSBaptiste Daroussin 				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
44339ee7a7aSBaptiste Daroussin 					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
44439ee7a7aSBaptiste Daroussin 							obj->value.sv,
44539ee7a7aSBaptiste Daroussin 							obj->len);
446b04a7a0bSBaptiste Daroussin 					deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
447b04a7a0bSBaptiste Daroussin 					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
448c99fb5f9SBaptiste Daroussin 				}
449c99fb5f9SBaptiste Daroussin 			}
45039ee7a7aSBaptiste Daroussin 		}
451c99fb5f9SBaptiste Daroussin 		else {
452c99fb5f9SBaptiste Daroussin 			/* Just emit value in json notation */
453b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
454b04a7a0bSBaptiste Daroussin 			deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
455c99fb5f9SBaptiste Daroussin 		}
456b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
457c99fb5f9SBaptiste Daroussin 	}
45839ee7a7aSBaptiste Daroussin 
459c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_VALUE];
460c99fb5f9SBaptiste Daroussin }
461c99fb5f9SBaptiste Daroussin 
46239ee7a7aSBaptiste Daroussin ucl_object_t*
463c99fb5f9SBaptiste Daroussin ucl_parser_get_object (struct ucl_parser *parser)
464c99fb5f9SBaptiste Daroussin {
465c99fb5f9SBaptiste Daroussin 	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
466c99fb5f9SBaptiste Daroussin 		return ucl_object_ref (parser->top_obj);
467c99fb5f9SBaptiste Daroussin 	}
468c99fb5f9SBaptiste Daroussin 
469c99fb5f9SBaptiste Daroussin 	return NULL;
470c99fb5f9SBaptiste Daroussin }
471c99fb5f9SBaptiste Daroussin 
47239ee7a7aSBaptiste Daroussin void
473c99fb5f9SBaptiste Daroussin ucl_parser_free (struct ucl_parser *parser)
474c99fb5f9SBaptiste Daroussin {
475c99fb5f9SBaptiste Daroussin 	struct ucl_stack *stack, *stmp;
476c99fb5f9SBaptiste Daroussin 	struct ucl_macro *macro, *mtmp;
477c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk, *ctmp;
478c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key, *ktmp;
479c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var, *vtmp;
48039ee7a7aSBaptiste Daroussin 	ucl_object_t *tr, *trtmp;
481c99fb5f9SBaptiste Daroussin 
48297bd480fSBaptiste Daroussin 	if (parser == NULL) {
48397bd480fSBaptiste Daroussin 		return;
48497bd480fSBaptiste Daroussin 	}
48597bd480fSBaptiste Daroussin 
486c99fb5f9SBaptiste Daroussin 	if (parser->top_obj != NULL) {
487c99fb5f9SBaptiste Daroussin 		ucl_object_unref (parser->top_obj);
488c99fb5f9SBaptiste Daroussin 	}
489c99fb5f9SBaptiste Daroussin 
49039ee7a7aSBaptiste Daroussin 	if (parser->includepaths != NULL) {
49139ee7a7aSBaptiste Daroussin 		ucl_object_unref (parser->includepaths);
49239ee7a7aSBaptiste Daroussin 	}
49339ee7a7aSBaptiste Daroussin 
494c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
495c99fb5f9SBaptiste Daroussin 		free (stack);
496c99fb5f9SBaptiste Daroussin 	}
497c99fb5f9SBaptiste Daroussin 	HASH_ITER (hh, parser->macroes, macro, mtmp) {
498c99fb5f9SBaptiste Daroussin 		free (macro->name);
499c99fb5f9SBaptiste Daroussin 		HASH_DEL (parser->macroes, macro);
500c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_macro), macro);
501c99fb5f9SBaptiste Daroussin 	}
502c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
503c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_chunk), chunk);
504c99fb5f9SBaptiste Daroussin 	}
505c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
506c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), key);
507c99fb5f9SBaptiste Daroussin 	}
508c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
509c99fb5f9SBaptiste Daroussin 		free (var->value);
510c99fb5f9SBaptiste Daroussin 		free (var->var);
511c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_variable), var);
512c99fb5f9SBaptiste Daroussin 	}
51339ee7a7aSBaptiste Daroussin 	LL_FOREACH_SAFE (parser->trash_objs, tr, trtmp) {
51439ee7a7aSBaptiste Daroussin 		ucl_object_free_internal (tr, false, ucl_object_dtor_free);
51539ee7a7aSBaptiste Daroussin 	}
516c99fb5f9SBaptiste Daroussin 
517c99fb5f9SBaptiste Daroussin 	if (parser->err != NULL) {
518c99fb5f9SBaptiste Daroussin 		utstring_free (parser->err);
519c99fb5f9SBaptiste Daroussin 	}
520c99fb5f9SBaptiste Daroussin 
5214bf54857SBaptiste Daroussin 	if (parser->cur_file) {
5224bf54857SBaptiste Daroussin 		free (parser->cur_file);
5234bf54857SBaptiste Daroussin 	}
5244bf54857SBaptiste Daroussin 
525d9f0ce31SBaptiste Daroussin 	if (parser->comments) {
526d9f0ce31SBaptiste Daroussin 		ucl_object_unref (parser->comments);
527d9f0ce31SBaptiste Daroussin 	}
528d9f0ce31SBaptiste Daroussin 
529c99fb5f9SBaptiste Daroussin 	UCL_FREE (sizeof (struct ucl_parser), parser);
530c99fb5f9SBaptiste Daroussin }
531c99fb5f9SBaptiste Daroussin 
53239ee7a7aSBaptiste Daroussin const char *
533c99fb5f9SBaptiste Daroussin ucl_parser_get_error(struct ucl_parser *parser)
534c99fb5f9SBaptiste Daroussin {
53597bd480fSBaptiste Daroussin 	if (parser == NULL) {
53697bd480fSBaptiste Daroussin 		return NULL;
53797bd480fSBaptiste Daroussin 	}
53897bd480fSBaptiste Daroussin 
53939ee7a7aSBaptiste Daroussin 	if (parser->err == NULL) {
540c99fb5f9SBaptiste Daroussin 		return NULL;
54139ee7a7aSBaptiste Daroussin 	}
542c99fb5f9SBaptiste Daroussin 
543c99fb5f9SBaptiste Daroussin 	return utstring_body (parser->err);
544c99fb5f9SBaptiste Daroussin }
545c99fb5f9SBaptiste Daroussin 
54639ee7a7aSBaptiste Daroussin int
54739ee7a7aSBaptiste Daroussin ucl_parser_get_error_code(struct ucl_parser *parser)
54839ee7a7aSBaptiste Daroussin {
54939ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
55039ee7a7aSBaptiste Daroussin 		return 0;
55139ee7a7aSBaptiste Daroussin 	}
55239ee7a7aSBaptiste Daroussin 
55339ee7a7aSBaptiste Daroussin 	return parser->err_code;
55439ee7a7aSBaptiste Daroussin }
55539ee7a7aSBaptiste Daroussin 
55639ee7a7aSBaptiste Daroussin unsigned
55739ee7a7aSBaptiste Daroussin ucl_parser_get_column(struct ucl_parser *parser)
55839ee7a7aSBaptiste Daroussin {
55939ee7a7aSBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL) {
56039ee7a7aSBaptiste Daroussin 		return 0;
56139ee7a7aSBaptiste Daroussin 	}
56239ee7a7aSBaptiste Daroussin 
56339ee7a7aSBaptiste Daroussin 	return parser->chunks->column;
56439ee7a7aSBaptiste Daroussin }
56539ee7a7aSBaptiste Daroussin 
56639ee7a7aSBaptiste Daroussin unsigned
56739ee7a7aSBaptiste Daroussin ucl_parser_get_linenum(struct ucl_parser *parser)
56839ee7a7aSBaptiste Daroussin {
56939ee7a7aSBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL) {
57039ee7a7aSBaptiste Daroussin 		return 0;
57139ee7a7aSBaptiste Daroussin 	}
57239ee7a7aSBaptiste Daroussin 
57339ee7a7aSBaptiste Daroussin 	return parser->chunks->line;
57439ee7a7aSBaptiste Daroussin }
57539ee7a7aSBaptiste Daroussin 
57639ee7a7aSBaptiste Daroussin void
5778e3b1ab2SBaptiste Daroussin ucl_parser_clear_error(struct ucl_parser *parser)
5788e3b1ab2SBaptiste Daroussin {
5798e3b1ab2SBaptiste Daroussin 	if (parser != NULL && parser->err != NULL) {
5808e3b1ab2SBaptiste Daroussin 		utstring_free(parser->err);
5818e3b1ab2SBaptiste Daroussin 		parser->err = NULL;
58239ee7a7aSBaptiste Daroussin 		parser->err_code = 0;
5838e3b1ab2SBaptiste Daroussin 	}
5848e3b1ab2SBaptiste Daroussin }
5858e3b1ab2SBaptiste Daroussin 
58639ee7a7aSBaptiste Daroussin bool
587c99fb5f9SBaptiste Daroussin ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
588c99fb5f9SBaptiste Daroussin {
589c99fb5f9SBaptiste Daroussin #ifndef HAVE_OPENSSL
590c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures without openssl");
591c99fb5f9SBaptiste Daroussin 	return false;
592c99fb5f9SBaptiste Daroussin #else
593c99fb5f9SBaptiste Daroussin # if (OPENSSL_VERSION_NUMBER < 0x10000000L)
594c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
595c99fb5f9SBaptiste Daroussin 	return EXIT_FAILURE;
596c99fb5f9SBaptiste Daroussin # else
597c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *nkey;
598c99fb5f9SBaptiste Daroussin 	BIO *mem;
599c99fb5f9SBaptiste Daroussin 
600c99fb5f9SBaptiste Daroussin 	mem = BIO_new_mem_buf ((void *)key, len);
601c99fb5f9SBaptiste Daroussin 	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
60297bd480fSBaptiste Daroussin 	if (nkey == NULL) {
60397bd480fSBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot allocate memory for key");
60497bd480fSBaptiste Daroussin 		return false;
60597bd480fSBaptiste Daroussin 	}
606c99fb5f9SBaptiste Daroussin 	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
607c99fb5f9SBaptiste Daroussin 	BIO_free (mem);
608c99fb5f9SBaptiste Daroussin 	if (nkey->key == NULL) {
609c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
610c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "%s",
611c99fb5f9SBaptiste Daroussin 				ERR_error_string (ERR_get_error (), NULL));
612c99fb5f9SBaptiste Daroussin 		return false;
613c99fb5f9SBaptiste Daroussin 	}
614c99fb5f9SBaptiste Daroussin 	LL_PREPEND (parser->keys, nkey);
615c99fb5f9SBaptiste Daroussin # endif
616c99fb5f9SBaptiste Daroussin #endif
617c99fb5f9SBaptiste Daroussin 	return true;
618c99fb5f9SBaptiste Daroussin }
619c99fb5f9SBaptiste Daroussin 
620c99fb5f9SBaptiste Daroussin #ifdef CURL_FOUND
621c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata {
622c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
623c99fb5f9SBaptiste Daroussin 	size_t buflen;
624c99fb5f9SBaptiste Daroussin };
625c99fb5f9SBaptiste Daroussin 
626c99fb5f9SBaptiste Daroussin static size_t
627c99fb5f9SBaptiste Daroussin ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
628c99fb5f9SBaptiste Daroussin {
629c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata *cbdata = ud;
630c99fb5f9SBaptiste Daroussin 	size_t realsize = size * nmemb;
631c99fb5f9SBaptiste Daroussin 
632c99fb5f9SBaptiste Daroussin 	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
633c99fb5f9SBaptiste Daroussin 	if (cbdata->buf == NULL) {
634c99fb5f9SBaptiste Daroussin 		return 0;
635c99fb5f9SBaptiste Daroussin 	}
636c99fb5f9SBaptiste Daroussin 
637c99fb5f9SBaptiste Daroussin 	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
638c99fb5f9SBaptiste Daroussin 	cbdata->buflen += realsize;
639c99fb5f9SBaptiste Daroussin 	cbdata->buf[cbdata->buflen] = 0;
640c99fb5f9SBaptiste Daroussin 
641c99fb5f9SBaptiste Daroussin 	return realsize;
642c99fb5f9SBaptiste Daroussin }
643c99fb5f9SBaptiste Daroussin #endif
644c99fb5f9SBaptiste Daroussin 
645c99fb5f9SBaptiste Daroussin /**
646c99fb5f9SBaptiste Daroussin  * Fetch a url and save results to the memory buffer
647c99fb5f9SBaptiste Daroussin  * @param url url to fetch
648c99fb5f9SBaptiste Daroussin  * @param len length of url
649c99fb5f9SBaptiste Daroussin  * @param buf target buffer
650c99fb5f9SBaptiste Daroussin  * @param buflen target length
651c99fb5f9SBaptiste Daroussin  * @return
652c99fb5f9SBaptiste Daroussin  */
653d9f0ce31SBaptiste Daroussin bool
654c99fb5f9SBaptiste Daroussin ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
655c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
656c99fb5f9SBaptiste Daroussin {
657c99fb5f9SBaptiste Daroussin 
658c99fb5f9SBaptiste Daroussin #ifdef HAVE_FETCH_H
659c99fb5f9SBaptiste Daroussin 	struct url *fetch_url;
660c99fb5f9SBaptiste Daroussin 	struct url_stat us;
661c99fb5f9SBaptiste Daroussin 	FILE *in;
662c99fb5f9SBaptiste Daroussin 
663c99fb5f9SBaptiste Daroussin 	fetch_url = fetchParseURL (url);
664c99fb5f9SBaptiste Daroussin 	if (fetch_url == NULL) {
665c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
666c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
667c99fb5f9SBaptiste Daroussin 		return false;
668c99fb5f9SBaptiste Daroussin 	}
669c99fb5f9SBaptiste Daroussin 	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
670c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
671c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot fetch URL %s: %s",
672c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
673c99fb5f9SBaptiste Daroussin 		}
674c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
675c99fb5f9SBaptiste Daroussin 		return false;
676c99fb5f9SBaptiste Daroussin 	}
677c99fb5f9SBaptiste Daroussin 
678c99fb5f9SBaptiste Daroussin 	*buflen = us.size;
679c99fb5f9SBaptiste Daroussin 	*buf = malloc (*buflen);
680c99fb5f9SBaptiste Daroussin 	if (*buf == NULL) {
681c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
682c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
683c99fb5f9SBaptiste Daroussin 		fclose (in);
684c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
685c99fb5f9SBaptiste Daroussin 		return false;
686c99fb5f9SBaptiste Daroussin 	}
687c99fb5f9SBaptiste Daroussin 
688c99fb5f9SBaptiste Daroussin 	if (fread (*buf, *buflen, 1, in) != 1) {
689c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot read URL %s: %s",
690c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
691c99fb5f9SBaptiste Daroussin 		fclose (in);
692c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
693c99fb5f9SBaptiste Daroussin 		return false;
694c99fb5f9SBaptiste Daroussin 	}
695c99fb5f9SBaptiste Daroussin 
696c99fb5f9SBaptiste Daroussin 	fetchFreeURL (fetch_url);
697c99fb5f9SBaptiste Daroussin 	return true;
698c99fb5f9SBaptiste Daroussin #elif defined(CURL_FOUND)
699c99fb5f9SBaptiste Daroussin 	CURL *curl;
700c99fb5f9SBaptiste Daroussin 	int r;
701c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata cbdata;
702c99fb5f9SBaptiste Daroussin 
703c99fb5f9SBaptiste Daroussin 	curl = curl_easy_init ();
704c99fb5f9SBaptiste Daroussin 	if (curl == NULL) {
705c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "CURL interface is broken");
706c99fb5f9SBaptiste Daroussin 		return false;
707c99fb5f9SBaptiste Daroussin 	}
708c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
709c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
710c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
711c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
712c99fb5f9SBaptiste Daroussin 		return false;
713c99fb5f9SBaptiste Daroussin 	}
714c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
715d9f0ce31SBaptiste Daroussin 	cbdata.buf = NULL;
716d9f0ce31SBaptiste Daroussin 	cbdata.buflen = 0;
717c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
718c99fb5f9SBaptiste Daroussin 
719c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
720c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
721c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "error fetching URL %s: %s",
722c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
723c99fb5f9SBaptiste Daroussin 		}
724c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
725c99fb5f9SBaptiste Daroussin 		if (cbdata.buf) {
726c99fb5f9SBaptiste Daroussin 			free (cbdata.buf);
727c99fb5f9SBaptiste Daroussin 		}
728c99fb5f9SBaptiste Daroussin 		return false;
729c99fb5f9SBaptiste Daroussin 	}
730c99fb5f9SBaptiste Daroussin 	*buf = cbdata.buf;
731c99fb5f9SBaptiste Daroussin 	*buflen = cbdata.buflen;
732c99fb5f9SBaptiste Daroussin 
733c99fb5f9SBaptiste Daroussin 	return true;
734c99fb5f9SBaptiste Daroussin #else
735c99fb5f9SBaptiste Daroussin 	ucl_create_err (err, "URL support is disabled");
736c99fb5f9SBaptiste Daroussin 	return false;
737c99fb5f9SBaptiste Daroussin #endif
738c99fb5f9SBaptiste Daroussin }
739c99fb5f9SBaptiste Daroussin 
740c99fb5f9SBaptiste Daroussin /**
741c99fb5f9SBaptiste Daroussin  * Fetch a file and save results to the memory buffer
742c99fb5f9SBaptiste Daroussin  * @param filename filename to fetch
743c99fb5f9SBaptiste Daroussin  * @param len length of filename
744c99fb5f9SBaptiste Daroussin  * @param buf target buffer
745c99fb5f9SBaptiste Daroussin  * @param buflen target length
746c99fb5f9SBaptiste Daroussin  * @return
747c99fb5f9SBaptiste Daroussin  */
748d9f0ce31SBaptiste Daroussin bool
749c99fb5f9SBaptiste Daroussin ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
750c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
751c99fb5f9SBaptiste Daroussin {
752c99fb5f9SBaptiste Daroussin 	int fd;
753c99fb5f9SBaptiste Daroussin 	struct stat st;
754c99fb5f9SBaptiste Daroussin 
755c99fb5f9SBaptiste Daroussin 	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
756c99fb5f9SBaptiste Daroussin 		if (must_exist) {
757c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot stat file %s: %s",
758c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
759c99fb5f9SBaptiste Daroussin 		}
760c99fb5f9SBaptiste Daroussin 		return false;
761c99fb5f9SBaptiste Daroussin 	}
762c99fb5f9SBaptiste Daroussin 	if (st.st_size == 0) {
763c99fb5f9SBaptiste Daroussin 		/* Do not map empty files */
764d9f0ce31SBaptiste Daroussin 		*buf = NULL;
765c99fb5f9SBaptiste Daroussin 		*buflen = 0;
766c99fb5f9SBaptiste Daroussin 	}
767c99fb5f9SBaptiste Daroussin 	else {
768c99fb5f9SBaptiste Daroussin 		if ((fd = open (filename, O_RDONLY)) == -1) {
769c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot open file %s: %s",
770c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
771c99fb5f9SBaptiste Daroussin 			return false;
772c99fb5f9SBaptiste Daroussin 		}
77397bd480fSBaptiste Daroussin 		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
774c99fb5f9SBaptiste Daroussin 			close (fd);
775c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot mmap file %s: %s",
776c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
777d9f0ce31SBaptiste Daroussin 			*buf = NULL;
778d9f0ce31SBaptiste Daroussin 
779c99fb5f9SBaptiste Daroussin 			return false;
780c99fb5f9SBaptiste Daroussin 		}
781c99fb5f9SBaptiste Daroussin 		*buflen = st.st_size;
782c99fb5f9SBaptiste Daroussin 		close (fd);
783c99fb5f9SBaptiste Daroussin 	}
784c99fb5f9SBaptiste Daroussin 
785c99fb5f9SBaptiste Daroussin 	return true;
786c99fb5f9SBaptiste Daroussin }
787c99fb5f9SBaptiste Daroussin 
788c99fb5f9SBaptiste Daroussin 
789c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
790c99fb5f9SBaptiste Daroussin static inline bool
791c99fb5f9SBaptiste Daroussin ucl_sig_check (const unsigned char *data, size_t datalen,
792c99fb5f9SBaptiste Daroussin 		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
793c99fb5f9SBaptiste Daroussin {
794c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key;
795c99fb5f9SBaptiste Daroussin 	char dig[EVP_MAX_MD_SIZE];
796c99fb5f9SBaptiste Daroussin 	unsigned int diglen;
797c99fb5f9SBaptiste Daroussin 	EVP_PKEY_CTX *key_ctx;
798c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX *sign_ctx = NULL;
799c99fb5f9SBaptiste Daroussin 
800c99fb5f9SBaptiste Daroussin 	sign_ctx = EVP_MD_CTX_create ();
801c99fb5f9SBaptiste Daroussin 
802c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->keys, key) {
803c99fb5f9SBaptiste Daroussin 		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
804c99fb5f9SBaptiste Daroussin 		if (key_ctx != NULL) {
805c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
806c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
807c99fb5f9SBaptiste Daroussin 				continue;
808c99fb5f9SBaptiste Daroussin 			}
809c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
810c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
811c99fb5f9SBaptiste Daroussin 				continue;
812c99fb5f9SBaptiste Daroussin 			}
813c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
814c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
815c99fb5f9SBaptiste Daroussin 				continue;
816c99fb5f9SBaptiste Daroussin 			}
817c99fb5f9SBaptiste Daroussin 			EVP_DigestInit (sign_ctx, EVP_sha256 ());
818c99fb5f9SBaptiste Daroussin 			EVP_DigestUpdate (sign_ctx, data, datalen);
819c99fb5f9SBaptiste Daroussin 			EVP_DigestFinal (sign_ctx, dig, &diglen);
820c99fb5f9SBaptiste Daroussin 
821c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
822c99fb5f9SBaptiste Daroussin 				EVP_MD_CTX_destroy (sign_ctx);
823c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
824c99fb5f9SBaptiste Daroussin 				return true;
825c99fb5f9SBaptiste Daroussin 			}
826c99fb5f9SBaptiste Daroussin 
827c99fb5f9SBaptiste Daroussin 			EVP_PKEY_CTX_free (key_ctx);
828c99fb5f9SBaptiste Daroussin 		}
829c99fb5f9SBaptiste Daroussin 	}
830c99fb5f9SBaptiste Daroussin 
831c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX_destroy (sign_ctx);
832c99fb5f9SBaptiste Daroussin 
833c99fb5f9SBaptiste Daroussin 	return false;
834c99fb5f9SBaptiste Daroussin }
835c99fb5f9SBaptiste Daroussin #endif
836c99fb5f9SBaptiste Daroussin 
83739ee7a7aSBaptiste Daroussin struct ucl_include_params {
83839ee7a7aSBaptiste Daroussin 	bool check_signature;
83939ee7a7aSBaptiste Daroussin 	bool must_exist;
84039ee7a7aSBaptiste Daroussin 	bool use_glob;
84139ee7a7aSBaptiste Daroussin 	bool use_prefix;
84239ee7a7aSBaptiste Daroussin 	bool soft_fail;
84339ee7a7aSBaptiste Daroussin 	bool allow_glob;
84439ee7a7aSBaptiste Daroussin 	unsigned priority;
84539ee7a7aSBaptiste Daroussin 	enum ucl_duplicate_strategy strat;
84639ee7a7aSBaptiste Daroussin 	enum ucl_parse_type parse_type;
84739ee7a7aSBaptiste Daroussin 	const char *prefix;
84839ee7a7aSBaptiste Daroussin 	const char *target;
84939ee7a7aSBaptiste Daroussin };
85039ee7a7aSBaptiste Daroussin 
851c99fb5f9SBaptiste Daroussin /**
852c99fb5f9SBaptiste Daroussin  * Include an url to configuration
853c99fb5f9SBaptiste Daroussin  * @param data
854c99fb5f9SBaptiste Daroussin  * @param len
855c99fb5f9SBaptiste Daroussin  * @param parser
856c99fb5f9SBaptiste Daroussin  * @param err
857c99fb5f9SBaptiste Daroussin  * @return
858c99fb5f9SBaptiste Daroussin  */
859c99fb5f9SBaptiste Daroussin static bool
860c99fb5f9SBaptiste Daroussin ucl_include_url (const unsigned char *data, size_t len,
86139ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser,
86239ee7a7aSBaptiste Daroussin 		struct ucl_include_params *params)
863c99fb5f9SBaptiste Daroussin {
864c99fb5f9SBaptiste Daroussin 
865c99fb5f9SBaptiste Daroussin 	bool res;
866c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
867c99fb5f9SBaptiste Daroussin 	size_t buflen = 0;
868c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
869c99fb5f9SBaptiste Daroussin 	char urlbuf[PATH_MAX];
870c99fb5f9SBaptiste Daroussin 	int prev_state;
871c99fb5f9SBaptiste Daroussin 
872c99fb5f9SBaptiste Daroussin 	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
873c99fb5f9SBaptiste Daroussin 
87439ee7a7aSBaptiste Daroussin 	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
875d9f0ce31SBaptiste Daroussin 		return !params->must_exist;
876c99fb5f9SBaptiste Daroussin 	}
877c99fb5f9SBaptiste Daroussin 
87839ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
879c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
880c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
881c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
882c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
883c99fb5f9SBaptiste Daroussin 		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
884c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
885c99fb5f9SBaptiste Daroussin 			return false;
886c99fb5f9SBaptiste Daroussin 		}
887c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
888c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify url %s: %s",
889c99fb5f9SBaptiste Daroussin 							urlbuf,
890c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
891c99fb5f9SBaptiste Daroussin 			if (siglen > 0) {
89297bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
893c99fb5f9SBaptiste Daroussin 			}
894c99fb5f9SBaptiste Daroussin 			return false;
895c99fb5f9SBaptiste Daroussin 		}
896c99fb5f9SBaptiste Daroussin 		if (siglen > 0) {
89797bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
898c99fb5f9SBaptiste Daroussin 		}
899c99fb5f9SBaptiste Daroussin #endif
900c99fb5f9SBaptiste Daroussin 	}
901c99fb5f9SBaptiste Daroussin 
902c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
903c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
904c99fb5f9SBaptiste Daroussin 
90539ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
90639ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
907c99fb5f9SBaptiste Daroussin 	if (res == true) {
908c99fb5f9SBaptiste Daroussin 		/* Remove chunk from the stack */
909c99fb5f9SBaptiste Daroussin 		chunk = parser->chunks;
910c99fb5f9SBaptiste Daroussin 		if (chunk != NULL) {
911c99fb5f9SBaptiste Daroussin 			parser->chunks = chunk->next;
912c99fb5f9SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_chunk), chunk);
913c99fb5f9SBaptiste Daroussin 		}
914c99fb5f9SBaptiste Daroussin 	}
915c99fb5f9SBaptiste Daroussin 
916c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
917c99fb5f9SBaptiste Daroussin 	free (buf);
918c99fb5f9SBaptiste Daroussin 
919c99fb5f9SBaptiste Daroussin 	return res;
920c99fb5f9SBaptiste Daroussin }
921c99fb5f9SBaptiste Daroussin 
922c99fb5f9SBaptiste Daroussin /**
9234bf54857SBaptiste Daroussin  * Include a single file to the parser
924c99fb5f9SBaptiste Daroussin  * @param data
925c99fb5f9SBaptiste Daroussin  * @param len
926c99fb5f9SBaptiste Daroussin  * @param parser
9274bf54857SBaptiste Daroussin  * @param check_signature
9284bf54857SBaptiste Daroussin  * @param must_exist
9294bf54857SBaptiste Daroussin  * @param allow_glob
9304bf54857SBaptiste Daroussin  * @param priority
931c99fb5f9SBaptiste Daroussin  * @return
932c99fb5f9SBaptiste Daroussin  */
933c99fb5f9SBaptiste Daroussin static bool
9344bf54857SBaptiste Daroussin ucl_include_file_single (const unsigned char *data, size_t len,
93539ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser, struct ucl_include_params *params)
936c99fb5f9SBaptiste Daroussin {
937c99fb5f9SBaptiste Daroussin 	bool res;
938c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
939c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
94039ee7a7aSBaptiste Daroussin 	char *old_curfile, *ext;
94139ee7a7aSBaptiste Daroussin 	size_t buflen = 0;
942c99fb5f9SBaptiste Daroussin 	char filebuf[PATH_MAX], realbuf[PATH_MAX];
943c99fb5f9SBaptiste Daroussin 	int prev_state;
9444bf54857SBaptiste Daroussin 	struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
9454bf54857SBaptiste Daroussin 			*old_filename = NULL;
94639ee7a7aSBaptiste Daroussin 	ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL;
94739ee7a7aSBaptiste Daroussin 	ucl_hash_t *container = NULL;
94839ee7a7aSBaptiste Daroussin 	struct ucl_stack *st = NULL;
949c99fb5f9SBaptiste Daroussin 
950c99fb5f9SBaptiste Daroussin 	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
95197bd480fSBaptiste Daroussin 	if (ucl_realpath (filebuf, realbuf) == NULL) {
95239ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
95339ee7a7aSBaptiste Daroussin 			return false;
95439ee7a7aSBaptiste Daroussin 		}
95539ee7a7aSBaptiste Daroussin 		if (!params->must_exist) {
956c99fb5f9SBaptiste Daroussin 			return true;
957c99fb5f9SBaptiste Daroussin 		}
958c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
959c99fb5f9SBaptiste Daroussin 									filebuf,
960c99fb5f9SBaptiste Daroussin 									strerror (errno));
961c99fb5f9SBaptiste Daroussin 		return false;
962c99fb5f9SBaptiste Daroussin 	}
963c99fb5f9SBaptiste Daroussin 
9644bf54857SBaptiste Daroussin 	if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
9654bf54857SBaptiste Daroussin 		/* We are likely including the file itself */
96639ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
96739ee7a7aSBaptiste Daroussin 			return false;
96839ee7a7aSBaptiste Daroussin 		}
96939ee7a7aSBaptiste Daroussin 
9704bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "trying to include the file %s from itself",
9714bf54857SBaptiste Daroussin 				realbuf);
9724bf54857SBaptiste Daroussin 		return false;
9734bf54857SBaptiste Daroussin 	}
9744bf54857SBaptiste Daroussin 
97539ee7a7aSBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, params->must_exist)) {
97639ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
97739ee7a7aSBaptiste Daroussin 			return false;
97839ee7a7aSBaptiste Daroussin 		}
9796525738fSBaptiste Daroussin 
98039ee7a7aSBaptiste Daroussin 		return (!params->must_exist || false);
981c99fb5f9SBaptiste Daroussin 	}
982c99fb5f9SBaptiste Daroussin 
98339ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
984c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
985c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
986c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
987c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
988c99fb5f9SBaptiste Daroussin 		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
989c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
990c99fb5f9SBaptiste Daroussin 			return false;
991c99fb5f9SBaptiste Daroussin 		}
992c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
993c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify file %s: %s",
994c99fb5f9SBaptiste Daroussin 							filebuf,
995c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
996d9f0ce31SBaptiste Daroussin 			if (sigbuf) {
99797bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
998c99fb5f9SBaptiste Daroussin 			}
999c99fb5f9SBaptiste Daroussin 			return false;
1000c99fb5f9SBaptiste Daroussin 		}
1001d9f0ce31SBaptiste Daroussin 		if (sigbuf) {
100297bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
1003c99fb5f9SBaptiste Daroussin 		}
1004c99fb5f9SBaptiste Daroussin #endif
1005c99fb5f9SBaptiste Daroussin 	}
1006c99fb5f9SBaptiste Daroussin 
10074bf54857SBaptiste Daroussin 	old_curfile = parser->cur_file;
10084bf54857SBaptiste Daroussin 	parser->cur_file = strdup (realbuf);
10094bf54857SBaptiste Daroussin 
10104bf54857SBaptiste Daroussin 	/* Store old file vars */
10114bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
10124bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0) {
10134bf54857SBaptiste Daroussin 			old_curdir = cur_var;
10144bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
10154bf54857SBaptiste Daroussin 		}
10164bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0) {
10174bf54857SBaptiste Daroussin 			old_filename = cur_var;
10184bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
10194bf54857SBaptiste Daroussin 		}
10204bf54857SBaptiste Daroussin 	}
10214bf54857SBaptiste Daroussin 
1022c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
1023c99fb5f9SBaptiste Daroussin 
1024c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
1025c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
1026c99fb5f9SBaptiste Daroussin 
102739ee7a7aSBaptiste Daroussin 	if (params->use_prefix && params->prefix == NULL) {
102839ee7a7aSBaptiste Daroussin 		/* Auto generate a key name based on the included filename */
102939ee7a7aSBaptiste Daroussin 		params->prefix = basename (realbuf);
103039ee7a7aSBaptiste Daroussin 		ext = strrchr (params->prefix, '.');
103139ee7a7aSBaptiste Daroussin 		if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) {
103239ee7a7aSBaptiste Daroussin 			/* Strip off .conf or .ucl */
103339ee7a7aSBaptiste Daroussin 			*ext = '\0';
103439ee7a7aSBaptiste Daroussin 		}
103539ee7a7aSBaptiste Daroussin 	}
103639ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL) {
103739ee7a7aSBaptiste Daroussin 		/* This is a prefixed include */
103839ee7a7aSBaptiste Daroussin 		container = parser->stack->obj->value.ov;
103939ee7a7aSBaptiste Daroussin 
104039ee7a7aSBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container,
104139ee7a7aSBaptiste Daroussin 				params->prefix, strlen (params->prefix)));
104239ee7a7aSBaptiste Daroussin 
104339ee7a7aSBaptiste Daroussin 		if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) {
104439ee7a7aSBaptiste Daroussin 			/* Create an array with key: prefix */
104539ee7a7aSBaptiste Daroussin 			old_obj = ucl_object_new_full (UCL_ARRAY, params->priority);
104639ee7a7aSBaptiste Daroussin 			old_obj->key = params->prefix;
104739ee7a7aSBaptiste Daroussin 			old_obj->keylen = strlen (params->prefix);
104839ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash(old_obj);
104939ee7a7aSBaptiste Daroussin 			old_obj->prev = old_obj;
105039ee7a7aSBaptiste Daroussin 			old_obj->next = NULL;
105139ee7a7aSBaptiste Daroussin 
105239ee7a7aSBaptiste Daroussin 			container = ucl_hash_insert_object (container, old_obj,
105339ee7a7aSBaptiste Daroussin 					parser->flags & UCL_PARSER_KEY_LOWERCASE);
105439ee7a7aSBaptiste Daroussin 			parser->stack->obj->len ++;
105539ee7a7aSBaptiste Daroussin 
105639ee7a7aSBaptiste Daroussin 			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
105739ee7a7aSBaptiste Daroussin 			nest_obj->prev = nest_obj;
105839ee7a7aSBaptiste Daroussin 			nest_obj->next = NULL;
105939ee7a7aSBaptiste Daroussin 
106039ee7a7aSBaptiste Daroussin 			ucl_array_append (old_obj, nest_obj);
106139ee7a7aSBaptiste Daroussin 		}
106239ee7a7aSBaptiste Daroussin 		else if (old_obj == NULL) {
106339ee7a7aSBaptiste Daroussin 			/* Create an object with key: prefix */
106439ee7a7aSBaptiste Daroussin 			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1065d9f0ce31SBaptiste Daroussin 
1066d9f0ce31SBaptiste Daroussin 			if (nest_obj == NULL) {
1067d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot allocate memory for an object");
1068d9f0ce31SBaptiste Daroussin 				if (buf) {
1069d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
1070d9f0ce31SBaptiste Daroussin 				}
1071d9f0ce31SBaptiste Daroussin 
1072d9f0ce31SBaptiste Daroussin 				return false;
1073d9f0ce31SBaptiste Daroussin 			}
1074d9f0ce31SBaptiste Daroussin 
107539ee7a7aSBaptiste Daroussin 			nest_obj->key = params->prefix;
107639ee7a7aSBaptiste Daroussin 			nest_obj->keylen = strlen (params->prefix);
107739ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash(nest_obj);
107839ee7a7aSBaptiste Daroussin 			nest_obj->prev = nest_obj;
107939ee7a7aSBaptiste Daroussin 			nest_obj->next = NULL;
108039ee7a7aSBaptiste Daroussin 
108139ee7a7aSBaptiste Daroussin 			container = ucl_hash_insert_object (container, nest_obj,
108239ee7a7aSBaptiste Daroussin 					parser->flags & UCL_PARSER_KEY_LOWERCASE);
108339ee7a7aSBaptiste Daroussin 			parser->stack->obj->len ++;
108439ee7a7aSBaptiste Daroussin 		}
108539ee7a7aSBaptiste Daroussin 		else if (strcasecmp (params->target, "array") == 0 ||
108639ee7a7aSBaptiste Daroussin 				ucl_object_type(old_obj) == UCL_ARRAY) {
108739ee7a7aSBaptiste Daroussin 			if (ucl_object_type(old_obj) == UCL_ARRAY) {
108839ee7a7aSBaptiste Daroussin 				/* Append to the existing array */
108939ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1090d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1091d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1092d9f0ce31SBaptiste Daroussin 					if (buf) {
1093d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1094d9f0ce31SBaptiste Daroussin 					}
1095d9f0ce31SBaptiste Daroussin 
1096d9f0ce31SBaptiste Daroussin 					return false;
1097d9f0ce31SBaptiste Daroussin 				}
109839ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
109939ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
110039ee7a7aSBaptiste Daroussin 
110139ee7a7aSBaptiste Daroussin 				ucl_array_append (old_obj, nest_obj);
110239ee7a7aSBaptiste Daroussin 			}
110339ee7a7aSBaptiste Daroussin 			else {
110439ee7a7aSBaptiste Daroussin 				/* Convert the object to an array */
110539ee7a7aSBaptiste Daroussin 				new_obj = ucl_object_typed_new (UCL_ARRAY);
1106d9f0ce31SBaptiste Daroussin 				if (new_obj == NULL) {
1107d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1108d9f0ce31SBaptiste Daroussin 					if (buf) {
1109d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1110d9f0ce31SBaptiste Daroussin 					}
1111d9f0ce31SBaptiste Daroussin 
1112d9f0ce31SBaptiste Daroussin 					return false;
1113d9f0ce31SBaptiste Daroussin 				}
111439ee7a7aSBaptiste Daroussin 				new_obj->key = old_obj->key;
111539ee7a7aSBaptiste Daroussin 				new_obj->keylen = old_obj->keylen;
111639ee7a7aSBaptiste Daroussin 				new_obj->flags |= UCL_OBJECT_MULTIVALUE;
111739ee7a7aSBaptiste Daroussin 				new_obj->prev = new_obj;
111839ee7a7aSBaptiste Daroussin 				new_obj->next = NULL;
111939ee7a7aSBaptiste Daroussin 
112039ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1121d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1122d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1123d9f0ce31SBaptiste Daroussin 					if (buf) {
1124d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1125d9f0ce31SBaptiste Daroussin 					}
1126d9f0ce31SBaptiste Daroussin 
1127d9f0ce31SBaptiste Daroussin 					return false;
1128d9f0ce31SBaptiste Daroussin 				}
112939ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
113039ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
113139ee7a7aSBaptiste Daroussin 
113239ee7a7aSBaptiste Daroussin 				ucl_array_append (new_obj, old_obj);
113339ee7a7aSBaptiste Daroussin 				ucl_array_append (new_obj, nest_obj);
113439ee7a7aSBaptiste Daroussin 				ucl_hash_replace (container, old_obj, new_obj);
113539ee7a7aSBaptiste Daroussin 			}
113639ee7a7aSBaptiste Daroussin 		}
113739ee7a7aSBaptiste Daroussin 		else {
113839ee7a7aSBaptiste Daroussin 			if (ucl_object_type (old_obj) == UCL_OBJECT) {
113939ee7a7aSBaptiste Daroussin 				/* Append to existing Object*/
114039ee7a7aSBaptiste Daroussin 				nest_obj = old_obj;
114139ee7a7aSBaptiste Daroussin 			}
114239ee7a7aSBaptiste Daroussin 			else {
114339ee7a7aSBaptiste Daroussin 				/* The key is not an object */
114439ee7a7aSBaptiste Daroussin 				ucl_create_err (&parser->err,
114539ee7a7aSBaptiste Daroussin 						"Conflicting type for key: %s",
114639ee7a7aSBaptiste Daroussin 						params->prefix);
1147d9f0ce31SBaptiste Daroussin 				if (buf) {
1148d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
1149d9f0ce31SBaptiste Daroussin 				}
1150d9f0ce31SBaptiste Daroussin 
115139ee7a7aSBaptiste Daroussin 				return false;
115239ee7a7aSBaptiste Daroussin 			}
115339ee7a7aSBaptiste Daroussin 		}
115439ee7a7aSBaptiste Daroussin 
115539ee7a7aSBaptiste Daroussin 		 /* Put all of the content of the include inside that object */
115639ee7a7aSBaptiste Daroussin 		parser->stack->obj->value.ov = container;
115739ee7a7aSBaptiste Daroussin 
115839ee7a7aSBaptiste Daroussin 		st = UCL_ALLOC (sizeof (struct ucl_stack));
115939ee7a7aSBaptiste Daroussin 		if (st == NULL) {
116039ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for an object");
116139ee7a7aSBaptiste Daroussin 			ucl_object_unref (nest_obj);
1162d9f0ce31SBaptiste Daroussin 
1163d9f0ce31SBaptiste Daroussin 			if (buf) {
1164d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1165d9f0ce31SBaptiste Daroussin 			}
1166d9f0ce31SBaptiste Daroussin 
1167d9f0ce31SBaptiste Daroussin 			return false;
116839ee7a7aSBaptiste Daroussin 		}
116939ee7a7aSBaptiste Daroussin 		st->obj = nest_obj;
117039ee7a7aSBaptiste Daroussin 		st->level = parser->stack->level;
117139ee7a7aSBaptiste Daroussin 		LL_PREPEND (parser->stack, st);
117239ee7a7aSBaptiste Daroussin 		parser->cur_obj = nest_obj;
117339ee7a7aSBaptiste Daroussin 	}
117439ee7a7aSBaptiste Daroussin 
117539ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
117639ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
11776525738fSBaptiste Daroussin 
11786525738fSBaptiste Daroussin 	if (!res) {
11796525738fSBaptiste Daroussin 		if (!params->must_exist) {
11804bf54857SBaptiste Daroussin 			/* Free error */
11814bf54857SBaptiste Daroussin 			utstring_free (parser->err);
11824bf54857SBaptiste Daroussin 			parser->err = NULL;
11836525738fSBaptiste Daroussin 			res = true;
11846525738fSBaptiste Daroussin 		}
11854bf54857SBaptiste Daroussin 	}
11864bf54857SBaptiste Daroussin 
118739ee7a7aSBaptiste Daroussin 	/* Stop nesting the include, take 1 level off the stack */
118839ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL && nest_obj != NULL) {
118939ee7a7aSBaptiste Daroussin 		parser->stack = st->next;
119039ee7a7aSBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_stack), st);
119139ee7a7aSBaptiste Daroussin 	}
119239ee7a7aSBaptiste Daroussin 
1193c99fb5f9SBaptiste Daroussin 	/* Remove chunk from the stack */
1194c99fb5f9SBaptiste Daroussin 	chunk = parser->chunks;
1195c99fb5f9SBaptiste Daroussin 	if (chunk != NULL) {
1196c99fb5f9SBaptiste Daroussin 		parser->chunks = chunk->next;
1197c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_chunk), chunk);
11984bf54857SBaptiste Daroussin 		parser->recursion --;
1199c99fb5f9SBaptiste Daroussin 	}
12004bf54857SBaptiste Daroussin 
12014bf54857SBaptiste Daroussin 	/* Restore old file vars */
120239ee7a7aSBaptiste Daroussin 	if (parser->cur_file) {
120339ee7a7aSBaptiste Daroussin 		free (parser->cur_file);
120439ee7a7aSBaptiste Daroussin 	}
120539ee7a7aSBaptiste Daroussin 
12064bf54857SBaptiste Daroussin 	parser->cur_file = old_curfile;
12074bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
12084bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
12094bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
12104bf54857SBaptiste Daroussin 			free (cur_var->var);
12114bf54857SBaptiste Daroussin 			free (cur_var->value);
12124bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), cur_var);
12134bf54857SBaptiste Daroussin 		}
12144bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
12154bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
12164bf54857SBaptiste Daroussin 			free (cur_var->var);
12174bf54857SBaptiste Daroussin 			free (cur_var->value);
12184bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), cur_var);
12194bf54857SBaptiste Daroussin 		}
12204bf54857SBaptiste Daroussin 	}
12214bf54857SBaptiste Daroussin 	if (old_filename) {
12224bf54857SBaptiste Daroussin 		DL_APPEND (parser->variables, old_filename);
12234bf54857SBaptiste Daroussin 	}
12244bf54857SBaptiste Daroussin 	if (old_curdir) {
12254bf54857SBaptiste Daroussin 		DL_APPEND (parser->variables, old_curdir);
12264bf54857SBaptiste Daroussin 	}
1227c99fb5f9SBaptiste Daroussin 
1228c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
1229c99fb5f9SBaptiste Daroussin 
1230c99fb5f9SBaptiste Daroussin 	if (buflen > 0) {
123197bd480fSBaptiste Daroussin 		ucl_munmap (buf, buflen);
1232c99fb5f9SBaptiste Daroussin 	}
1233c99fb5f9SBaptiste Daroussin 
1234c99fb5f9SBaptiste Daroussin 	return res;
1235c99fb5f9SBaptiste Daroussin }
1236c99fb5f9SBaptiste Daroussin 
1237c99fb5f9SBaptiste Daroussin /**
12384bf54857SBaptiste Daroussin  * Include a file to configuration
12394bf54857SBaptiste Daroussin  * @param data
12404bf54857SBaptiste Daroussin  * @param len
12414bf54857SBaptiste Daroussin  * @param parser
12424bf54857SBaptiste Daroussin  * @param err
12434bf54857SBaptiste Daroussin  * @return
12444bf54857SBaptiste Daroussin  */
12454bf54857SBaptiste Daroussin static bool
12464bf54857SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len,
124739ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser, struct ucl_include_params *params)
12484bf54857SBaptiste Daroussin {
12494bf54857SBaptiste Daroussin 	const unsigned char *p = data, *end = data + len;
12504bf54857SBaptiste Daroussin 	bool need_glob = false;
12514bf54857SBaptiste Daroussin 	int cnt = 0;
12524bf54857SBaptiste Daroussin 	char glob_pattern[PATH_MAX];
12534bf54857SBaptiste Daroussin 	size_t i;
12544bf54857SBaptiste Daroussin 
12558e3b1ab2SBaptiste Daroussin #ifndef _WIN32
125639ee7a7aSBaptiste Daroussin 	if (!params->allow_glob) {
125739ee7a7aSBaptiste Daroussin 		return ucl_include_file_single (data, len, parser, params);
12584bf54857SBaptiste Daroussin 	}
12594bf54857SBaptiste Daroussin 	else {
12604bf54857SBaptiste Daroussin 		/* Check for special symbols in a filename */
12614bf54857SBaptiste Daroussin 		while (p != end) {
12624bf54857SBaptiste Daroussin 			if (*p == '*' || *p == '?') {
12634bf54857SBaptiste Daroussin 				need_glob = true;
12644bf54857SBaptiste Daroussin 				break;
12654bf54857SBaptiste Daroussin 			}
12664bf54857SBaptiste Daroussin 			p ++;
12674bf54857SBaptiste Daroussin 		}
12684bf54857SBaptiste Daroussin 		if (need_glob) {
12698e3b1ab2SBaptiste Daroussin 			glob_t globbuf;
12704bf54857SBaptiste Daroussin 			memset (&globbuf, 0, sizeof (globbuf));
127139ee7a7aSBaptiste Daroussin 			ucl_strlcpy (glob_pattern, (const char *)data,
127239ee7a7aSBaptiste Daroussin 				(len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern)));
12734bf54857SBaptiste Daroussin 			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
127439ee7a7aSBaptiste Daroussin 				return (!params->must_exist || false);
12754bf54857SBaptiste Daroussin 			}
12764bf54857SBaptiste Daroussin 			for (i = 0; i < globbuf.gl_pathc; i ++) {
12774bf54857SBaptiste Daroussin 				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
127839ee7a7aSBaptiste Daroussin 						strlen (globbuf.gl_pathv[i]), parser, params)) {
127939ee7a7aSBaptiste Daroussin 					if (params->soft_fail) {
128039ee7a7aSBaptiste Daroussin 						continue;
128139ee7a7aSBaptiste Daroussin 					}
12824bf54857SBaptiste Daroussin 					globfree (&globbuf);
12834bf54857SBaptiste Daroussin 					return false;
12844bf54857SBaptiste Daroussin 				}
12854bf54857SBaptiste Daroussin 				cnt ++;
12864bf54857SBaptiste Daroussin 			}
12874bf54857SBaptiste Daroussin 			globfree (&globbuf);
12884bf54857SBaptiste Daroussin 
128939ee7a7aSBaptiste Daroussin 			if (cnt == 0 && params->must_exist) {
12904bf54857SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
12914bf54857SBaptiste Daroussin 					glob_pattern);
12924bf54857SBaptiste Daroussin 				return false;
12934bf54857SBaptiste Daroussin 			}
12944bf54857SBaptiste Daroussin 		}
12954bf54857SBaptiste Daroussin 		else {
129639ee7a7aSBaptiste Daroussin 			return ucl_include_file_single (data, len, parser, params);
12974bf54857SBaptiste Daroussin 		}
12984bf54857SBaptiste Daroussin 	}
12998e3b1ab2SBaptiste Daroussin #else
13008e3b1ab2SBaptiste Daroussin 	/* Win32 compilers do not support globbing. Therefore, for Win32,
13018e3b1ab2SBaptiste Daroussin 	   treat allow_glob/need_glob as a NOOP and just return */
130239ee7a7aSBaptiste Daroussin 	return ucl_include_file_single (data, len, parser, params);
13038e3b1ab2SBaptiste Daroussin #endif
13044bf54857SBaptiste Daroussin 
13054bf54857SBaptiste Daroussin 	return true;
13064bf54857SBaptiste Daroussin }
13074bf54857SBaptiste Daroussin 
13084bf54857SBaptiste Daroussin /**
13094bf54857SBaptiste Daroussin  * Common function to handle .*include* macros
13104bf54857SBaptiste Daroussin  * @param data
13114bf54857SBaptiste Daroussin  * @param len
13124bf54857SBaptiste Daroussin  * @param args
13134bf54857SBaptiste Daroussin  * @param parser
13144bf54857SBaptiste Daroussin  * @param default_try
13154bf54857SBaptiste Daroussin  * @param default_sign
13164bf54857SBaptiste Daroussin  * @return
13174bf54857SBaptiste Daroussin  */
13184bf54857SBaptiste Daroussin static bool
13194bf54857SBaptiste Daroussin ucl_include_common (const unsigned char *data, size_t len,
13204bf54857SBaptiste Daroussin 		const ucl_object_t *args, struct ucl_parser *parser,
13214bf54857SBaptiste Daroussin 		bool default_try,
13224bf54857SBaptiste Daroussin 		bool default_sign)
13234bf54857SBaptiste Daroussin {
1324d9f0ce31SBaptiste Daroussin 	bool allow_url = false, search = false;
132539ee7a7aSBaptiste Daroussin 	const char *duplicate;
13264bf54857SBaptiste Daroussin 	const ucl_object_t *param;
132739ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL, ip = NULL;
132839ee7a7aSBaptiste Daroussin 	char ipath[PATH_MAX];
132939ee7a7aSBaptiste Daroussin 	struct ucl_include_params params;
13304bf54857SBaptiste Daroussin 
13314bf54857SBaptiste Daroussin 	/* Default values */
133239ee7a7aSBaptiste Daroussin 	params.soft_fail = default_try;
133339ee7a7aSBaptiste Daroussin 	params.allow_glob = false;
133439ee7a7aSBaptiste Daroussin 	params.check_signature = default_sign;
133539ee7a7aSBaptiste Daroussin 	params.use_prefix = false;
133639ee7a7aSBaptiste Daroussin 	params.target = "object";
133739ee7a7aSBaptiste Daroussin 	params.prefix = NULL;
133839ee7a7aSBaptiste Daroussin 	params.priority = 0;
133939ee7a7aSBaptiste Daroussin 	params.parse_type = UCL_PARSE_UCL;
134039ee7a7aSBaptiste Daroussin 	params.strat = UCL_DUPLICATE_APPEND;
134139ee7a7aSBaptiste Daroussin 	params.must_exist = !default_try;
134239ee7a7aSBaptiste Daroussin 
13434bf54857SBaptiste Daroussin 	/* Process arguments */
13444bf54857SBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1345d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
13464bf54857SBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
134739ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
134839ee7a7aSBaptiste Daroussin 					params.must_exist = !ucl_object_toboolean (param);
13494bf54857SBaptiste Daroussin 				}
135039ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "sign", param->keylen) == 0) {
135139ee7a7aSBaptiste Daroussin 					params.check_signature = ucl_object_toboolean (param);
13524bf54857SBaptiste Daroussin 				}
135339ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "glob", param->keylen) == 0) {
135439ee7a7aSBaptiste Daroussin 					params.allow_glob = ucl_object_toboolean (param);
13554bf54857SBaptiste Daroussin 				}
135639ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "url", param->keylen) == 0) {
13574bf54857SBaptiste Daroussin 					allow_url = ucl_object_toboolean (param);
13584bf54857SBaptiste Daroussin 				}
135939ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "prefix", param->keylen) == 0) {
136039ee7a7aSBaptiste Daroussin 					params.use_prefix = ucl_object_toboolean (param);
136139ee7a7aSBaptiste Daroussin 				}
136239ee7a7aSBaptiste Daroussin 			}
136339ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
136439ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
136539ee7a7aSBaptiste Daroussin 					params.prefix = ucl_object_tostring (param);
136639ee7a7aSBaptiste Daroussin 				}
136739ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
136839ee7a7aSBaptiste Daroussin 					params.target = ucl_object_tostring (param);
136939ee7a7aSBaptiste Daroussin 				}
137039ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "duplicate", param->keylen) == 0) {
137139ee7a7aSBaptiste Daroussin 					duplicate = ucl_object_tostring (param);
137239ee7a7aSBaptiste Daroussin 
137339ee7a7aSBaptiste Daroussin 					if (strcmp (duplicate, "append") == 0) {
137439ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_APPEND;
137539ee7a7aSBaptiste Daroussin 					}
137639ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "merge") == 0) {
137739ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_MERGE;
137839ee7a7aSBaptiste Daroussin 					}
137939ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "rewrite") == 0) {
138039ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_REWRITE;
138139ee7a7aSBaptiste Daroussin 					}
138239ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "error") == 0) {
138339ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_ERROR;
138439ee7a7aSBaptiste Daroussin 					}
138539ee7a7aSBaptiste Daroussin 				}
138639ee7a7aSBaptiste Daroussin 			}
138739ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_ARRAY) {
138839ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "path", param->keylen) == 0) {
138939ee7a7aSBaptiste Daroussin 					ucl_set_include_path (parser, __DECONST(ucl_object_t *, param));
139039ee7a7aSBaptiste Daroussin 				}
13914bf54857SBaptiste Daroussin 			}
13924bf54857SBaptiste Daroussin 			else if (param->type == UCL_INT) {
139339ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
139439ee7a7aSBaptiste Daroussin 					params.priority = ucl_object_toint (param);
13954bf54857SBaptiste Daroussin 				}
13964bf54857SBaptiste Daroussin 			}
13974bf54857SBaptiste Daroussin 		}
13984bf54857SBaptiste Daroussin 	}
13994bf54857SBaptiste Daroussin 
140039ee7a7aSBaptiste Daroussin 	if (parser->includepaths == NULL) {
140139ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
14024bf54857SBaptiste Daroussin 			/* Globbing is not used for URL's */
140339ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
140439ee7a7aSBaptiste Daroussin 		}
140539ee7a7aSBaptiste Daroussin 		else if (data != NULL) {
140639ee7a7aSBaptiste Daroussin 			/* Try to load a file */
140739ee7a7aSBaptiste Daroussin 			return ucl_include_file (data, len, parser, &params);
140839ee7a7aSBaptiste Daroussin 		}
140939ee7a7aSBaptiste Daroussin 	}
141039ee7a7aSBaptiste Daroussin 	else {
141139ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
141239ee7a7aSBaptiste Daroussin 			/* Globbing is not used for URL's */
141339ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
141439ee7a7aSBaptiste Daroussin 		}
141539ee7a7aSBaptiste Daroussin 
141639ee7a7aSBaptiste Daroussin 		ip = ucl_object_iterate_new (parser->includepaths);
141739ee7a7aSBaptiste Daroussin 		while ((param = ucl_object_iterate_safe (ip, true)) != NULL) {
141839ee7a7aSBaptiste Daroussin 			if (ucl_object_type(param) == UCL_STRING) {
141939ee7a7aSBaptiste Daroussin 				snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param),
142039ee7a7aSBaptiste Daroussin 						(int)len, data);
142139ee7a7aSBaptiste Daroussin 				if ((search = ucl_include_file (ipath, strlen (ipath),
142239ee7a7aSBaptiste Daroussin 						parser, &params))) {
142339ee7a7aSBaptiste Daroussin 					if (!params.allow_glob) {
142439ee7a7aSBaptiste Daroussin 						break;
142539ee7a7aSBaptiste Daroussin 					}
142639ee7a7aSBaptiste Daroussin 				}
142739ee7a7aSBaptiste Daroussin 			}
142839ee7a7aSBaptiste Daroussin 		}
142939ee7a7aSBaptiste Daroussin 		ucl_object_iterate_free (ip);
143039ee7a7aSBaptiste Daroussin 		if (search == true) {
143139ee7a7aSBaptiste Daroussin 			return true;
143239ee7a7aSBaptiste Daroussin 		}
143339ee7a7aSBaptiste Daroussin 		else {
143439ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err,
143539ee7a7aSBaptiste Daroussin 					"cannot find file: %.*s in search path",
143639ee7a7aSBaptiste Daroussin 					(int)len, data);
143739ee7a7aSBaptiste Daroussin 			return false;
143839ee7a7aSBaptiste Daroussin 		}
14394bf54857SBaptiste Daroussin 	}
14404bf54857SBaptiste Daroussin 
14414bf54857SBaptiste Daroussin 	return false;
14424bf54857SBaptiste Daroussin }
14434bf54857SBaptiste Daroussin 
14444bf54857SBaptiste Daroussin /**
1445c99fb5f9SBaptiste Daroussin  * Handle include macro
1446c99fb5f9SBaptiste Daroussin  * @param data include data
1447c99fb5f9SBaptiste Daroussin  * @param len length of data
144839ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1449c99fb5f9SBaptiste Daroussin  * @param ud user data
1450c99fb5f9SBaptiste Daroussin  * @return
1451c99fb5f9SBaptiste Daroussin  */
145239ee7a7aSBaptiste Daroussin bool
14534bf54857SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len,
14544bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1455c99fb5f9SBaptiste Daroussin {
1456c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1457c99fb5f9SBaptiste Daroussin 
14584bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, false);
1459c99fb5f9SBaptiste Daroussin }
1460c99fb5f9SBaptiste Daroussin 
1461c99fb5f9SBaptiste Daroussin /**
1462c99fb5f9SBaptiste Daroussin  * Handle includes macro
1463c99fb5f9SBaptiste Daroussin  * @param data include data
1464c99fb5f9SBaptiste Daroussin  * @param len length of data
146539ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1466c99fb5f9SBaptiste Daroussin  * @param ud user data
1467c99fb5f9SBaptiste Daroussin  * @return
1468c99fb5f9SBaptiste Daroussin  */
146939ee7a7aSBaptiste Daroussin bool
14704bf54857SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len,
14714bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1472c99fb5f9SBaptiste Daroussin {
1473c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1474c99fb5f9SBaptiste Daroussin 
14754bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, true);
1476c99fb5f9SBaptiste Daroussin }
1477c99fb5f9SBaptiste Daroussin 
147839ee7a7aSBaptiste Daroussin /**
147939ee7a7aSBaptiste Daroussin  * Handle tryinclude macro
148039ee7a7aSBaptiste Daroussin  * @param data include data
148139ee7a7aSBaptiste Daroussin  * @param len length of data
148239ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
148339ee7a7aSBaptiste Daroussin  * @param ud user data
148439ee7a7aSBaptiste Daroussin  * @return
148539ee7a7aSBaptiste Daroussin  */
148639ee7a7aSBaptiste Daroussin bool
14874bf54857SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len,
14884bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1489c99fb5f9SBaptiste Daroussin {
1490c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1491c99fb5f9SBaptiste Daroussin 
14924bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, true, false);
1493c99fb5f9SBaptiste Daroussin }
1494c99fb5f9SBaptiste Daroussin 
149539ee7a7aSBaptiste Daroussin /**
149639ee7a7aSBaptiste Daroussin  * Handle priority macro
149739ee7a7aSBaptiste Daroussin  * @param data include data
149839ee7a7aSBaptiste Daroussin  * @param len length of data
149939ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
150039ee7a7aSBaptiste Daroussin  * @param ud user data
150139ee7a7aSBaptiste Daroussin  * @return
150239ee7a7aSBaptiste Daroussin  */
150339ee7a7aSBaptiste Daroussin bool
150439ee7a7aSBaptiste Daroussin ucl_priority_handler (const unsigned char *data, size_t len,
150539ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
150639ee7a7aSBaptiste Daroussin {
150739ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
150839ee7a7aSBaptiste Daroussin 	unsigned priority = 255;
150939ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
151039ee7a7aSBaptiste Daroussin 	bool found = false;
151139ee7a7aSBaptiste Daroussin 	char *value = NULL, *leftover = NULL;
151239ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
151339ee7a7aSBaptiste Daroussin 
151439ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
151539ee7a7aSBaptiste Daroussin 		return false;
151639ee7a7aSBaptiste Daroussin 	}
151739ee7a7aSBaptiste Daroussin 
151839ee7a7aSBaptiste Daroussin 	/* Process arguments */
151939ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1520d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
152139ee7a7aSBaptiste Daroussin 			if (param->type == UCL_INT) {
152239ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
152339ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
152439ee7a7aSBaptiste Daroussin 					found = true;
152539ee7a7aSBaptiste Daroussin 				}
152639ee7a7aSBaptiste Daroussin 			}
152739ee7a7aSBaptiste Daroussin 		}
152839ee7a7aSBaptiste Daroussin 	}
152939ee7a7aSBaptiste Daroussin 
153039ee7a7aSBaptiste Daroussin 	if (len > 0) {
153139ee7a7aSBaptiste Daroussin 		value = malloc(len + 1);
153239ee7a7aSBaptiste Daroussin 		ucl_strlcpy(value, (const char *)data, len + 1);
153339ee7a7aSBaptiste Daroussin 		priority = strtol(value, &leftover, 10);
153439ee7a7aSBaptiste Daroussin 		if (*leftover != '\0') {
153539ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Invalid priority value in macro: %s",
153639ee7a7aSBaptiste Daroussin 				value);
153739ee7a7aSBaptiste Daroussin 			free(value);
153839ee7a7aSBaptiste Daroussin 			return false;
153939ee7a7aSBaptiste Daroussin 		}
154039ee7a7aSBaptiste Daroussin 		free(value);
154139ee7a7aSBaptiste Daroussin 		found = true;
154239ee7a7aSBaptiste Daroussin 	}
154339ee7a7aSBaptiste Daroussin 
154439ee7a7aSBaptiste Daroussin 	if (found == true) {
154539ee7a7aSBaptiste Daroussin 		parser->chunks->priority = priority;
154639ee7a7aSBaptiste Daroussin 		return true;
154739ee7a7aSBaptiste Daroussin 	}
154839ee7a7aSBaptiste Daroussin 
154939ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse priority macro");
155039ee7a7aSBaptiste Daroussin 	return false;
155139ee7a7aSBaptiste Daroussin }
155239ee7a7aSBaptiste Daroussin 
155339ee7a7aSBaptiste Daroussin /**
155439ee7a7aSBaptiste Daroussin  * Handle load macro
155539ee7a7aSBaptiste Daroussin  * @param data include data
155639ee7a7aSBaptiste Daroussin  * @param len length of data
155739ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
155839ee7a7aSBaptiste Daroussin  * @param ud user data
155939ee7a7aSBaptiste Daroussin  * @return
156039ee7a7aSBaptiste Daroussin  */
156139ee7a7aSBaptiste Daroussin bool
156239ee7a7aSBaptiste Daroussin ucl_load_handler (const unsigned char *data, size_t len,
156339ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
156439ee7a7aSBaptiste Daroussin {
156539ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
156639ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
156739ee7a7aSBaptiste Daroussin 	ucl_object_t *obj, *old_obj;
156839ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
156939ee7a7aSBaptiste Daroussin 	bool try_load, multiline, test;
157039ee7a7aSBaptiste Daroussin 	const char *target, *prefix;
157139ee7a7aSBaptiste Daroussin 	char *load_file, *tmp;
157239ee7a7aSBaptiste Daroussin 	unsigned char *buf;
157339ee7a7aSBaptiste Daroussin 	size_t buflen;
157439ee7a7aSBaptiste Daroussin 	unsigned priority;
157539ee7a7aSBaptiste Daroussin 	int64_t iv;
1576d9f0ce31SBaptiste Daroussin 	ucl_object_t *container = NULL;
157739ee7a7aSBaptiste Daroussin 	enum ucl_string_flags flags;
157839ee7a7aSBaptiste Daroussin 
157939ee7a7aSBaptiste Daroussin 	/* Default values */
158039ee7a7aSBaptiste Daroussin 	try_load = false;
158139ee7a7aSBaptiste Daroussin 	multiline = false;
158239ee7a7aSBaptiste Daroussin 	test = false;
158339ee7a7aSBaptiste Daroussin 	target = "string";
158439ee7a7aSBaptiste Daroussin 	prefix = NULL;
158539ee7a7aSBaptiste Daroussin 	load_file = NULL;
158639ee7a7aSBaptiste Daroussin 	buf = NULL;
158739ee7a7aSBaptiste Daroussin 	buflen = 0;
158839ee7a7aSBaptiste Daroussin 	priority = 0;
158939ee7a7aSBaptiste Daroussin 	obj = NULL;
159039ee7a7aSBaptiste Daroussin 	old_obj = NULL;
159139ee7a7aSBaptiste Daroussin 	flags = 0;
159239ee7a7aSBaptiste Daroussin 
159339ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
159439ee7a7aSBaptiste Daroussin 		return false;
159539ee7a7aSBaptiste Daroussin 	}
159639ee7a7aSBaptiste Daroussin 
159739ee7a7aSBaptiste Daroussin 	/* Process arguments */
159839ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1599d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
160039ee7a7aSBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
160139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
160239ee7a7aSBaptiste Daroussin 					try_load = ucl_object_toboolean (param);
160339ee7a7aSBaptiste Daroussin 				}
160439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "multiline", param->keylen) == 0) {
160539ee7a7aSBaptiste Daroussin 					multiline = ucl_object_toboolean (param);
160639ee7a7aSBaptiste Daroussin 				}
160739ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "escape", param->keylen) == 0) {
160839ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
160939ee7a7aSBaptiste Daroussin 					if (test) {
161039ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_ESCAPE;
161139ee7a7aSBaptiste Daroussin 					}
161239ee7a7aSBaptiste Daroussin 				}
161339ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "trim", param->keylen) == 0) {
161439ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
161539ee7a7aSBaptiste Daroussin 					if (test) {
161639ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_TRIM;
161739ee7a7aSBaptiste Daroussin 					}
161839ee7a7aSBaptiste Daroussin 				}
161939ee7a7aSBaptiste Daroussin 			}
162039ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
162139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
162239ee7a7aSBaptiste Daroussin 					prefix = ucl_object_tostring (param);
162339ee7a7aSBaptiste Daroussin 				}
162439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
162539ee7a7aSBaptiste Daroussin 					target = ucl_object_tostring (param);
162639ee7a7aSBaptiste Daroussin 				}
162739ee7a7aSBaptiste Daroussin 			}
162839ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_INT) {
162939ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
163039ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
163139ee7a7aSBaptiste Daroussin 				}
163239ee7a7aSBaptiste Daroussin 			}
163339ee7a7aSBaptiste Daroussin 		}
163439ee7a7aSBaptiste Daroussin 	}
163539ee7a7aSBaptiste Daroussin 
163639ee7a7aSBaptiste Daroussin 	if (prefix == NULL || strlen (prefix) == 0) {
163739ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "No Key specified in load macro");
163839ee7a7aSBaptiste Daroussin 		return false;
163939ee7a7aSBaptiste Daroussin 	}
164039ee7a7aSBaptiste Daroussin 
164139ee7a7aSBaptiste Daroussin 	if (len > 0) {
1642d9f0ce31SBaptiste Daroussin 		load_file = malloc (len + 1);
1643d9f0ce31SBaptiste Daroussin 		if (!load_file) {
1644d9f0ce31SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for suffix");
1645d9f0ce31SBaptiste Daroussin 
1646d9f0ce31SBaptiste Daroussin 			return false;
1647d9f0ce31SBaptiste Daroussin 		}
1648d9f0ce31SBaptiste Daroussin 
1649d9f0ce31SBaptiste Daroussin 		snprintf (load_file, len + 1, "%.*s", (int)len, data);
1650d9f0ce31SBaptiste Daroussin 
1651d9f0ce31SBaptiste Daroussin 		if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err,
1652d9f0ce31SBaptiste Daroussin 				!try_load)) {
1653d9f0ce31SBaptiste Daroussin 			free (load_file);
1654d9f0ce31SBaptiste Daroussin 
165539ee7a7aSBaptiste Daroussin 			return (try_load || false);
165639ee7a7aSBaptiste Daroussin 		}
165739ee7a7aSBaptiste Daroussin 
1658d9f0ce31SBaptiste Daroussin 		free (load_file);
1659d9f0ce31SBaptiste Daroussin 		container = parser->stack->obj;
1660d9f0ce31SBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_object_lookup (container,
1661d9f0ce31SBaptiste Daroussin 				prefix));
1662d9f0ce31SBaptiste Daroussin 
166339ee7a7aSBaptiste Daroussin 		if (old_obj != NULL) {
166439ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Key %s already exists", prefix);
1665d9f0ce31SBaptiste Daroussin 			if (buf) {
1666d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1667d9f0ce31SBaptiste Daroussin 			}
1668d9f0ce31SBaptiste Daroussin 
166939ee7a7aSBaptiste Daroussin 			return false;
167039ee7a7aSBaptiste Daroussin 		}
167139ee7a7aSBaptiste Daroussin 
167239ee7a7aSBaptiste Daroussin 		if (strcasecmp (target, "string") == 0) {
167339ee7a7aSBaptiste Daroussin 			obj = ucl_object_fromstring_common (buf, buflen, flags);
167439ee7a7aSBaptiste Daroussin 			ucl_copy_value_trash (obj);
167539ee7a7aSBaptiste Daroussin 			if (multiline) {
167639ee7a7aSBaptiste Daroussin 				obj->flags |= UCL_OBJECT_MULTILINE;
167739ee7a7aSBaptiste Daroussin 			}
167839ee7a7aSBaptiste Daroussin 		}
167939ee7a7aSBaptiste Daroussin 		else if (strcasecmp (target, "int") == 0) {
1680d9f0ce31SBaptiste Daroussin 			tmp = malloc (buflen + 1);
1681d9f0ce31SBaptiste Daroussin 
1682d9f0ce31SBaptiste Daroussin 			if (tmp == NULL) {
1683d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "Memory allocation failed");
1684d9f0ce31SBaptiste Daroussin 				if (buf) {
1685d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
168639ee7a7aSBaptiste Daroussin 				}
168739ee7a7aSBaptiste Daroussin 
1688d9f0ce31SBaptiste Daroussin 				return false;
1689d9f0ce31SBaptiste Daroussin 			}
1690d9f0ce31SBaptiste Daroussin 
1691d9f0ce31SBaptiste Daroussin 			snprintf (tmp, buflen + 1, "%.*s", (int)buflen, buf);
1692d9f0ce31SBaptiste Daroussin 			iv = strtoll (tmp, NULL, 10);
1693d9f0ce31SBaptiste Daroussin 			obj = ucl_object_fromint (iv);
1694d9f0ce31SBaptiste Daroussin 			free (tmp);
1695d9f0ce31SBaptiste Daroussin 		}
1696d9f0ce31SBaptiste Daroussin 
1697d9f0ce31SBaptiste Daroussin 		if (buf) {
169839ee7a7aSBaptiste Daroussin 			ucl_munmap (buf, buflen);
169939ee7a7aSBaptiste Daroussin 		}
170039ee7a7aSBaptiste Daroussin 
170139ee7a7aSBaptiste Daroussin 		if (obj != NULL) {
170239ee7a7aSBaptiste Daroussin 			obj->key = prefix;
170339ee7a7aSBaptiste Daroussin 			obj->keylen = strlen (prefix);
170439ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash (obj);
170539ee7a7aSBaptiste Daroussin 			obj->prev = obj;
170639ee7a7aSBaptiste Daroussin 			obj->next = NULL;
170739ee7a7aSBaptiste Daroussin 			ucl_object_set_priority (obj, priority);
1708d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (container, obj, obj->key, obj->keylen, false);
170939ee7a7aSBaptiste Daroussin 		}
1710d9f0ce31SBaptiste Daroussin 
171139ee7a7aSBaptiste Daroussin 		return true;
171239ee7a7aSBaptiste Daroussin 	}
171339ee7a7aSBaptiste Daroussin 
171439ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse load macro");
171539ee7a7aSBaptiste Daroussin 	return false;
171639ee7a7aSBaptiste Daroussin }
171739ee7a7aSBaptiste Daroussin 
171839ee7a7aSBaptiste Daroussin bool
171939ee7a7aSBaptiste Daroussin ucl_inherit_handler (const unsigned char *data, size_t len,
172039ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, const ucl_object_t *ctx, void* ud)
172139ee7a7aSBaptiste Daroussin {
172239ee7a7aSBaptiste Daroussin 	const ucl_object_t *parent, *cur;
172339ee7a7aSBaptiste Daroussin 	ucl_object_t *target, *copy;
172439ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
172539ee7a7aSBaptiste Daroussin 	bool replace = false;
172639ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
172739ee7a7aSBaptiste Daroussin 
1728d9f0ce31SBaptiste Daroussin 	parent = ucl_object_lookup_len (ctx, data, len);
172939ee7a7aSBaptiste Daroussin 
173039ee7a7aSBaptiste Daroussin 	/* Some sanity checks */
173139ee7a7aSBaptiste Daroussin 	if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) {
173239ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Unable to find inherited object %*.s",
173339ee7a7aSBaptiste Daroussin 				(int)len, data);
173439ee7a7aSBaptiste Daroussin 		return false;
173539ee7a7aSBaptiste Daroussin 	}
173639ee7a7aSBaptiste Daroussin 
173739ee7a7aSBaptiste Daroussin 	if (parser->stack == NULL || parser->stack->obj == NULL ||
173839ee7a7aSBaptiste Daroussin 			ucl_object_type (parser->stack->obj) != UCL_OBJECT) {
173939ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Invalid inherit context");
174039ee7a7aSBaptiste Daroussin 		return false;
174139ee7a7aSBaptiste Daroussin 	}
174239ee7a7aSBaptiste Daroussin 
174339ee7a7aSBaptiste Daroussin 	target = parser->stack->obj;
174439ee7a7aSBaptiste Daroussin 
1745d9f0ce31SBaptiste Daroussin 	if (args && (cur = ucl_object_lookup (args, "replace")) != NULL) {
174639ee7a7aSBaptiste Daroussin 		replace = ucl_object_toboolean (cur);
174739ee7a7aSBaptiste Daroussin 	}
174839ee7a7aSBaptiste Daroussin 
1749d9f0ce31SBaptiste Daroussin 	while ((cur = ucl_object_iterate (parent, &it, true))) {
175039ee7a7aSBaptiste Daroussin 		/* We do not replace existing keys */
1751d9f0ce31SBaptiste Daroussin 		if (!replace && ucl_object_lookup_len (target, cur->key, cur->keylen)) {
175239ee7a7aSBaptiste Daroussin 			continue;
175339ee7a7aSBaptiste Daroussin 		}
175439ee7a7aSBaptiste Daroussin 
175539ee7a7aSBaptiste Daroussin 		copy = ucl_object_copy (cur);
175639ee7a7aSBaptiste Daroussin 
175739ee7a7aSBaptiste Daroussin 		if (!replace) {
175839ee7a7aSBaptiste Daroussin 			copy->flags |= UCL_OBJECT_INHERITED;
175939ee7a7aSBaptiste Daroussin 		}
176039ee7a7aSBaptiste Daroussin 
176139ee7a7aSBaptiste Daroussin 		ucl_object_insert_key (target, copy, copy->key,
176239ee7a7aSBaptiste Daroussin 				copy->keylen, false);
176339ee7a7aSBaptiste Daroussin 	}
176439ee7a7aSBaptiste Daroussin 
176539ee7a7aSBaptiste Daroussin 	return true;
176639ee7a7aSBaptiste Daroussin }
176739ee7a7aSBaptiste Daroussin 
176839ee7a7aSBaptiste Daroussin bool
1769c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
1770c99fb5f9SBaptiste Daroussin {
1771c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX], *curdir;
1772c99fb5f9SBaptiste Daroussin 
1773c99fb5f9SBaptiste Daroussin 	if (filename != NULL) {
1774c99fb5f9SBaptiste Daroussin 		if (need_expand) {
177597bd480fSBaptiste Daroussin 			if (ucl_realpath (filename, realbuf) == NULL) {
1776c99fb5f9SBaptiste Daroussin 				return false;
1777c99fb5f9SBaptiste Daroussin 			}
1778c99fb5f9SBaptiste Daroussin 		}
1779c99fb5f9SBaptiste Daroussin 		else {
1780c99fb5f9SBaptiste Daroussin 			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
1781c99fb5f9SBaptiste Daroussin 		}
1782c99fb5f9SBaptiste Daroussin 
1783c99fb5f9SBaptiste Daroussin 		/* Define variables */
1784c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", realbuf);
1785c99fb5f9SBaptiste Daroussin 		curdir = dirname (realbuf);
1786c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1787c99fb5f9SBaptiste Daroussin 	}
1788c99fb5f9SBaptiste Daroussin 	else {
1789c99fb5f9SBaptiste Daroussin 		/* Set everything from the current dir */
1790c99fb5f9SBaptiste Daroussin 		curdir = getcwd (realbuf, sizeof (realbuf));
1791c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", "undef");
1792c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1793c99fb5f9SBaptiste Daroussin 	}
1794c99fb5f9SBaptiste Daroussin 
1795c99fb5f9SBaptiste Daroussin 	return true;
1796c99fb5f9SBaptiste Daroussin }
1797c99fb5f9SBaptiste Daroussin 
179839ee7a7aSBaptiste Daroussin bool
1799273c26a3SBaptiste Daroussin ucl_parser_add_file_full (struct ucl_parser *parser, const char *filename,
1800273c26a3SBaptiste Daroussin 		unsigned priority, enum ucl_duplicate_strategy strat,
1801273c26a3SBaptiste Daroussin 		enum ucl_parse_type parse_type)
1802c99fb5f9SBaptiste Daroussin {
1803c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
1804c99fb5f9SBaptiste Daroussin 	size_t len;
1805c99fb5f9SBaptiste Daroussin 	bool ret;
1806c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX];
1807c99fb5f9SBaptiste Daroussin 
180897bd480fSBaptiste Daroussin 	if (ucl_realpath (filename, realbuf) == NULL) {
1809c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
1810c99fb5f9SBaptiste Daroussin 				filename,
1811c99fb5f9SBaptiste Daroussin 				strerror (errno));
1812c99fb5f9SBaptiste Daroussin 		return false;
1813c99fb5f9SBaptiste Daroussin 	}
1814c99fb5f9SBaptiste Daroussin 
1815c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
1816c99fb5f9SBaptiste Daroussin 		return false;
1817c99fb5f9SBaptiste Daroussin 	}
1818c99fb5f9SBaptiste Daroussin 
18194bf54857SBaptiste Daroussin 	if (parser->cur_file) {
18204bf54857SBaptiste Daroussin 		free (parser->cur_file);
18214bf54857SBaptiste Daroussin 	}
18224bf54857SBaptiste Daroussin 	parser->cur_file = strdup (realbuf);
1823c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
1824273c26a3SBaptiste Daroussin 	ret = ucl_parser_add_chunk_full (parser, buf, len, priority, strat,
1825273c26a3SBaptiste Daroussin 			parse_type);
1826c99fb5f9SBaptiste Daroussin 
1827c99fb5f9SBaptiste Daroussin 	if (len > 0) {
182897bd480fSBaptiste Daroussin 		ucl_munmap (buf, len);
1829c99fb5f9SBaptiste Daroussin 	}
1830c99fb5f9SBaptiste Daroussin 
1831c99fb5f9SBaptiste Daroussin 	return ret;
1832c99fb5f9SBaptiste Daroussin }
1833c99fb5f9SBaptiste Daroussin 
183439ee7a7aSBaptiste Daroussin bool
1835273c26a3SBaptiste Daroussin ucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename,
1836273c26a3SBaptiste Daroussin 		unsigned priority)
1837273c26a3SBaptiste Daroussin {
1838273c26a3SBaptiste Daroussin 	if (parser == NULL) {
1839273c26a3SBaptiste Daroussin 		return false;
1840273c26a3SBaptiste Daroussin 	}
1841273c26a3SBaptiste Daroussin 
1842273c26a3SBaptiste Daroussin 	return ucl_parser_add_file_full(parser, filename, priority,
1843273c26a3SBaptiste Daroussin 			UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
1844273c26a3SBaptiste Daroussin }
1845273c26a3SBaptiste Daroussin 
1846273c26a3SBaptiste Daroussin bool
184739ee7a7aSBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
184839ee7a7aSBaptiste Daroussin {
184939ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
185039ee7a7aSBaptiste Daroussin 		return false;
185139ee7a7aSBaptiste Daroussin 	}
185239ee7a7aSBaptiste Daroussin 
1853273c26a3SBaptiste Daroussin 	return ucl_parser_add_file_full(parser, filename,
1854273c26a3SBaptiste Daroussin 			parser->default_priority, UCL_DUPLICATE_APPEND,
1855273c26a3SBaptiste Daroussin 			UCL_PARSE_UCL);
185639ee7a7aSBaptiste Daroussin }
185739ee7a7aSBaptiste Daroussin 
1858*11dd9ed6SBaptiste Daroussin 
185939ee7a7aSBaptiste Daroussin bool
1860*11dd9ed6SBaptiste Daroussin ucl_parser_add_fd_full (struct ucl_parser *parser, int fd,
1861*11dd9ed6SBaptiste Daroussin 		unsigned priority, enum ucl_duplicate_strategy strat,
1862*11dd9ed6SBaptiste Daroussin 		enum ucl_parse_type parse_type)
18634bf54857SBaptiste Daroussin {
18644bf54857SBaptiste Daroussin 	unsigned char *buf;
18654bf54857SBaptiste Daroussin 	size_t len;
18664bf54857SBaptiste Daroussin 	bool ret;
18674bf54857SBaptiste Daroussin 	struct stat st;
18684bf54857SBaptiste Daroussin 
18694bf54857SBaptiste Daroussin 	if (fstat (fd, &st) == -1) {
18704bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot stat fd %d: %s",
18714bf54857SBaptiste Daroussin 			fd, strerror (errno));
18724bf54857SBaptiste Daroussin 		return false;
18734bf54857SBaptiste Daroussin 	}
18746525738fSBaptiste Daroussin 	if (st.st_size == 0) {
18756525738fSBaptiste Daroussin 		return true;
18766525738fSBaptiste Daroussin 	}
18774bf54857SBaptiste Daroussin 	if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
18784bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
18794bf54857SBaptiste Daroussin 			fd, strerror (errno));
18804bf54857SBaptiste Daroussin 		return false;
18814bf54857SBaptiste Daroussin 	}
18824bf54857SBaptiste Daroussin 
18834bf54857SBaptiste Daroussin 	if (parser->cur_file) {
18844bf54857SBaptiste Daroussin 		free (parser->cur_file);
18854bf54857SBaptiste Daroussin 	}
18864bf54857SBaptiste Daroussin 	parser->cur_file = NULL;
18874bf54857SBaptiste Daroussin 	len = st.st_size;
1888*11dd9ed6SBaptiste Daroussin 	ret = ucl_parser_add_chunk_full (parser, buf, len, priority, strat,
1889*11dd9ed6SBaptiste Daroussin 			parse_type);
18904bf54857SBaptiste Daroussin 
18914bf54857SBaptiste Daroussin 	if (len > 0) {
18924bf54857SBaptiste Daroussin 		ucl_munmap (buf, len);
18934bf54857SBaptiste Daroussin 	}
18944bf54857SBaptiste Daroussin 
18954bf54857SBaptiste Daroussin 	return ret;
18964bf54857SBaptiste Daroussin }
18974bf54857SBaptiste Daroussin 
189839ee7a7aSBaptiste Daroussin bool
1899*11dd9ed6SBaptiste Daroussin ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
1900*11dd9ed6SBaptiste Daroussin 		unsigned priority)
1901*11dd9ed6SBaptiste Daroussin {
1902*11dd9ed6SBaptiste Daroussin 	if (parser == NULL) {
1903*11dd9ed6SBaptiste Daroussin 		return false;
1904*11dd9ed6SBaptiste Daroussin 	}
1905*11dd9ed6SBaptiste Daroussin 
1906*11dd9ed6SBaptiste Daroussin 	return ucl_parser_add_fd_full(parser, fd, parser->default_priority,
1907*11dd9ed6SBaptiste Daroussin 			UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
1908*11dd9ed6SBaptiste Daroussin }
1909*11dd9ed6SBaptiste Daroussin 
1910*11dd9ed6SBaptiste Daroussin bool
191139ee7a7aSBaptiste Daroussin ucl_parser_add_fd (struct ucl_parser *parser, int fd)
191239ee7a7aSBaptiste Daroussin {
191339ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
191439ee7a7aSBaptiste Daroussin 		return false;
191539ee7a7aSBaptiste Daroussin 	}
191639ee7a7aSBaptiste Daroussin 
191739ee7a7aSBaptiste Daroussin 	return ucl_parser_add_fd_priority(parser, fd, parser->default_priority);
191839ee7a7aSBaptiste Daroussin }
191939ee7a7aSBaptiste Daroussin 
1920c99fb5f9SBaptiste Daroussin size_t
1921c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz)
1922c99fb5f9SBaptiste Daroussin {
1923c99fb5f9SBaptiste Daroussin 	char *d = dst;
1924c99fb5f9SBaptiste Daroussin 	const char *s = src;
1925c99fb5f9SBaptiste Daroussin 	size_t n = siz;
1926c99fb5f9SBaptiste Daroussin 
1927c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1928c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1929c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1930c99fb5f9SBaptiste Daroussin 			if ((*d++ = *s++) == '\0') {
1931c99fb5f9SBaptiste Daroussin 				break;
1932c99fb5f9SBaptiste Daroussin 			}
1933c99fb5f9SBaptiste Daroussin 		}
1934c99fb5f9SBaptiste Daroussin 	}
1935c99fb5f9SBaptiste Daroussin 
1936c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1937c99fb5f9SBaptiste Daroussin 		*d = '\0';
1938c99fb5f9SBaptiste Daroussin 	}
1939c99fb5f9SBaptiste Daroussin 
1940c99fb5f9SBaptiste Daroussin 	return (s - src - 1);    /* count does not include NUL */
1941c99fb5f9SBaptiste Daroussin }
1942c99fb5f9SBaptiste Daroussin 
1943c99fb5f9SBaptiste Daroussin size_t
1944c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
1945c99fb5f9SBaptiste Daroussin {
1946c99fb5f9SBaptiste Daroussin 	memcpy (dst, src, siz - 1);
1947c99fb5f9SBaptiste Daroussin 	dst[siz - 1] = '\0';
1948c99fb5f9SBaptiste Daroussin 
1949c99fb5f9SBaptiste Daroussin 	return siz - 1;
1950c99fb5f9SBaptiste Daroussin }
1951c99fb5f9SBaptiste Daroussin 
1952c99fb5f9SBaptiste Daroussin size_t
1953c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
1954c99fb5f9SBaptiste Daroussin {
1955c99fb5f9SBaptiste Daroussin 	char *d = dst;
1956c99fb5f9SBaptiste Daroussin 	const char *s = src;
1957c99fb5f9SBaptiste Daroussin 	size_t n = siz;
1958c99fb5f9SBaptiste Daroussin 
1959c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1960c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1961c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1962c99fb5f9SBaptiste Daroussin 			if ((*d++ = tolower (*s++)) == '\0') {
1963c99fb5f9SBaptiste Daroussin 				break;
1964c99fb5f9SBaptiste Daroussin 			}
1965c99fb5f9SBaptiste Daroussin 		}
1966c99fb5f9SBaptiste Daroussin 	}
1967c99fb5f9SBaptiste Daroussin 
1968c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1969c99fb5f9SBaptiste Daroussin 		*d = '\0';
1970c99fb5f9SBaptiste Daroussin 	}
1971c99fb5f9SBaptiste Daroussin 
1972c99fb5f9SBaptiste Daroussin 	return (s - src);    /* count does not include NUL */
1973c99fb5f9SBaptiste Daroussin }
1974c99fb5f9SBaptiste Daroussin 
197539ee7a7aSBaptiste Daroussin /*
197639ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s
197739ee7a7aSBaptiste Daroussin  */
197839ee7a7aSBaptiste Daroussin char *
197939ee7a7aSBaptiste Daroussin ucl_strnstr (const char *s, const char *find, int len)
198039ee7a7aSBaptiste Daroussin {
198139ee7a7aSBaptiste Daroussin 	char c, sc;
198239ee7a7aSBaptiste Daroussin 	int mlen;
198339ee7a7aSBaptiste Daroussin 
198439ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
198539ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
198639ee7a7aSBaptiste Daroussin 		do {
198739ee7a7aSBaptiste Daroussin 			do {
198839ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
198939ee7a7aSBaptiste Daroussin 					return (NULL);
199039ee7a7aSBaptiste Daroussin 			} while (sc != c);
199139ee7a7aSBaptiste Daroussin 		} while (strncmp (s, find, mlen) != 0);
199239ee7a7aSBaptiste Daroussin 		s--;
199339ee7a7aSBaptiste Daroussin 	}
199439ee7a7aSBaptiste Daroussin 	return ((char *)s);
199539ee7a7aSBaptiste Daroussin }
199639ee7a7aSBaptiste Daroussin 
199739ee7a7aSBaptiste Daroussin /*
199839ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s, ignore case.
199939ee7a7aSBaptiste Daroussin  */
200039ee7a7aSBaptiste Daroussin char *
200139ee7a7aSBaptiste Daroussin ucl_strncasestr (const char *s, const char *find, int len)
200239ee7a7aSBaptiste Daroussin {
200339ee7a7aSBaptiste Daroussin 	char c, sc;
200439ee7a7aSBaptiste Daroussin 	int mlen;
200539ee7a7aSBaptiste Daroussin 
200639ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
200739ee7a7aSBaptiste Daroussin 		c = tolower (c);
200839ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
200939ee7a7aSBaptiste Daroussin 		do {
201039ee7a7aSBaptiste Daroussin 			do {
201139ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
201239ee7a7aSBaptiste Daroussin 					return (NULL);
201339ee7a7aSBaptiste Daroussin 			} while (tolower (sc) != c);
201439ee7a7aSBaptiste Daroussin 		} while (strncasecmp (s, find, mlen) != 0);
201539ee7a7aSBaptiste Daroussin 		s--;
201639ee7a7aSBaptiste Daroussin 	}
201739ee7a7aSBaptiste Daroussin 	return ((char *)s);
201839ee7a7aSBaptiste Daroussin }
201939ee7a7aSBaptiste Daroussin 
2020c99fb5f9SBaptiste Daroussin ucl_object_t *
2021c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
2022c99fb5f9SBaptiste Daroussin {
2023c99fb5f9SBaptiste Daroussin 	ucl_object_t *obj;
2024c99fb5f9SBaptiste Daroussin 	const char *start, *end, *p, *pos;
2025c99fb5f9SBaptiste Daroussin 	char *dst, *d;
2026c99fb5f9SBaptiste Daroussin 	size_t escaped_len;
2027c99fb5f9SBaptiste Daroussin 
2028c99fb5f9SBaptiste Daroussin 	if (str == NULL) {
2029c99fb5f9SBaptiste Daroussin 		return NULL;
2030c99fb5f9SBaptiste Daroussin 	}
2031c99fb5f9SBaptiste Daroussin 
2032c99fb5f9SBaptiste Daroussin 	obj = ucl_object_new ();
2033c99fb5f9SBaptiste Daroussin 	if (obj) {
2034c99fb5f9SBaptiste Daroussin 		if (len == 0) {
2035c99fb5f9SBaptiste Daroussin 			len = strlen (str);
2036c99fb5f9SBaptiste Daroussin 		}
2037c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_TRIM) {
2038c99fb5f9SBaptiste Daroussin 			/* Skip leading spaces */
2039c99fb5f9SBaptiste Daroussin 			for (start = str; (size_t)(start - str) < len; start ++) {
2040c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2041c99fb5f9SBaptiste Daroussin 					break;
2042c99fb5f9SBaptiste Daroussin 				}
2043c99fb5f9SBaptiste Daroussin 			}
2044c99fb5f9SBaptiste Daroussin 			/* Skip trailing spaces */
2045c99fb5f9SBaptiste Daroussin 			for (end = str + len - 1; end > start; end --) {
2046c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2047c99fb5f9SBaptiste Daroussin 					break;
2048c99fb5f9SBaptiste Daroussin 				}
2049c99fb5f9SBaptiste Daroussin 			}
2050c99fb5f9SBaptiste Daroussin 			end ++;
2051c99fb5f9SBaptiste Daroussin 		}
2052c99fb5f9SBaptiste Daroussin 		else {
2053c99fb5f9SBaptiste Daroussin 			start = str;
2054c99fb5f9SBaptiste Daroussin 			end = str + len;
2055c99fb5f9SBaptiste Daroussin 		}
2056c99fb5f9SBaptiste Daroussin 
2057c99fb5f9SBaptiste Daroussin 		obj->type = UCL_STRING;
2058c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_ESCAPE) {
2059c99fb5f9SBaptiste Daroussin 			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
2060c99fb5f9SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
2061c99fb5f9SBaptiste Daroussin 					escaped_len ++;
2062c99fb5f9SBaptiste Daroussin 				}
2063c99fb5f9SBaptiste Daroussin 			}
2064c99fb5f9SBaptiste Daroussin 			dst = malloc (escaped_len + 1);
2065c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2066c99fb5f9SBaptiste Daroussin 				for (p = start, d = dst; p < end; p ++, d ++) {
2067c99fb5f9SBaptiste Daroussin 					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
2068c99fb5f9SBaptiste Daroussin 						switch (*p) {
2069c99fb5f9SBaptiste Daroussin 						case '\n':
2070c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2071c99fb5f9SBaptiste Daroussin 							*d = 'n';
2072c99fb5f9SBaptiste Daroussin 							break;
2073c99fb5f9SBaptiste Daroussin 						case '\r':
2074c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2075c99fb5f9SBaptiste Daroussin 							*d = 'r';
2076c99fb5f9SBaptiste Daroussin 							break;
2077c99fb5f9SBaptiste Daroussin 						case '\b':
2078c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2079c99fb5f9SBaptiste Daroussin 							*d = 'b';
2080c99fb5f9SBaptiste Daroussin 							break;
2081c99fb5f9SBaptiste Daroussin 						case '\t':
2082c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2083c99fb5f9SBaptiste Daroussin 							*d = 't';
2084c99fb5f9SBaptiste Daroussin 							break;
2085c99fb5f9SBaptiste Daroussin 						case '\f':
2086c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2087c99fb5f9SBaptiste Daroussin 							*d = 'f';
2088c99fb5f9SBaptiste Daroussin 							break;
2089c99fb5f9SBaptiste Daroussin 						case '\\':
2090c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2091c99fb5f9SBaptiste Daroussin 							*d = '\\';
2092c99fb5f9SBaptiste Daroussin 							break;
2093c99fb5f9SBaptiste Daroussin 						case '"':
2094c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2095c99fb5f9SBaptiste Daroussin 							*d = '"';
2096c99fb5f9SBaptiste Daroussin 							break;
2097c99fb5f9SBaptiste Daroussin 						}
2098c99fb5f9SBaptiste Daroussin 					}
2099c99fb5f9SBaptiste Daroussin 					else {
2100c99fb5f9SBaptiste Daroussin 						*d = *p;
2101c99fb5f9SBaptiste Daroussin 					}
2102c99fb5f9SBaptiste Daroussin 				}
2103c99fb5f9SBaptiste Daroussin 				*d = '\0';
2104c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2105c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2106c99fb5f9SBaptiste Daroussin 				obj->len = escaped_len;
2107c99fb5f9SBaptiste Daroussin 			}
2108c99fb5f9SBaptiste Daroussin 		}
2109c99fb5f9SBaptiste Daroussin 		else {
2110c99fb5f9SBaptiste Daroussin 			dst = malloc (end - start + 1);
2111c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2112c99fb5f9SBaptiste Daroussin 				ucl_strlcpy_unsafe (dst, start, end - start + 1);
2113c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2114c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2115c99fb5f9SBaptiste Daroussin 				obj->len = end - start;
2116c99fb5f9SBaptiste Daroussin 			}
2117c99fb5f9SBaptiste Daroussin 		}
2118c99fb5f9SBaptiste Daroussin 		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
2119c99fb5f9SBaptiste Daroussin 			/* Parse what we have */
2120c99fb5f9SBaptiste Daroussin 			if (flags & UCL_STRING_PARSE_BOOLEAN) {
2121c99fb5f9SBaptiste Daroussin 				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
2122c99fb5f9SBaptiste Daroussin 					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2123c99fb5f9SBaptiste Daroussin 							flags & UCL_STRING_PARSE_DOUBLE,
212497bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_BYTES,
212597bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_TIME);
2126c99fb5f9SBaptiste Daroussin 				}
2127c99fb5f9SBaptiste Daroussin 			}
2128c99fb5f9SBaptiste Daroussin 			else {
2129c99fb5f9SBaptiste Daroussin 				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2130c99fb5f9SBaptiste Daroussin 						flags & UCL_STRING_PARSE_DOUBLE,
213197bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_BYTES,
213297bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_TIME);
2133c99fb5f9SBaptiste Daroussin 			}
2134c99fb5f9SBaptiste Daroussin 		}
2135c99fb5f9SBaptiste Daroussin 	}
2136c99fb5f9SBaptiste Daroussin 
2137c99fb5f9SBaptiste Daroussin 	return obj;
2138c99fb5f9SBaptiste Daroussin }
2139c99fb5f9SBaptiste Daroussin 
2140b04a7a0bSBaptiste Daroussin static bool
2141c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
2142c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
2143c99fb5f9SBaptiste Daroussin {
2144b04a7a0bSBaptiste Daroussin 	ucl_object_t *found, *tmp;
2145b04a7a0bSBaptiste Daroussin 	const ucl_object_t *cur;
2146c99fb5f9SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
2147c99fb5f9SBaptiste Daroussin 	const char *p;
2148b04a7a0bSBaptiste Daroussin 	int ret = true;
2149c99fb5f9SBaptiste Daroussin 
2150c99fb5f9SBaptiste Daroussin 	if (elt == NULL || key == NULL) {
2151b04a7a0bSBaptiste Daroussin 		return false;
2152c99fb5f9SBaptiste Daroussin 	}
2153c99fb5f9SBaptiste Daroussin 
2154c99fb5f9SBaptiste Daroussin 	if (top == NULL) {
2155b04a7a0bSBaptiste Daroussin 		return false;
2156c99fb5f9SBaptiste Daroussin 	}
2157c99fb5f9SBaptiste Daroussin 
2158c99fb5f9SBaptiste Daroussin 	if (top->type != UCL_OBJECT) {
2159c99fb5f9SBaptiste Daroussin 		/* It is possible to convert NULL type to an object */
2160c99fb5f9SBaptiste Daroussin 		if (top->type == UCL_NULL) {
2161c99fb5f9SBaptiste Daroussin 			top->type = UCL_OBJECT;
2162c99fb5f9SBaptiste Daroussin 		}
2163c99fb5f9SBaptiste Daroussin 		else {
2164c99fb5f9SBaptiste Daroussin 			/* Refuse converting of other object types */
2165b04a7a0bSBaptiste Daroussin 			return false;
2166c99fb5f9SBaptiste Daroussin 		}
2167c99fb5f9SBaptiste Daroussin 	}
2168c99fb5f9SBaptiste Daroussin 
2169c99fb5f9SBaptiste Daroussin 	if (top->value.ov == NULL) {
21708e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_create (false);
2171c99fb5f9SBaptiste Daroussin 	}
2172c99fb5f9SBaptiste Daroussin 
2173c99fb5f9SBaptiste Daroussin 	if (keylen == 0) {
2174c99fb5f9SBaptiste Daroussin 		keylen = strlen (key);
2175c99fb5f9SBaptiste Daroussin 	}
2176c99fb5f9SBaptiste Daroussin 
2177c99fb5f9SBaptiste Daroussin 	for (p = key; p < key + keylen; p ++) {
2178c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
2179c99fb5f9SBaptiste Daroussin 			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
2180c99fb5f9SBaptiste Daroussin 			break;
2181c99fb5f9SBaptiste Daroussin 		}
2182c99fb5f9SBaptiste Daroussin 	}
2183c99fb5f9SBaptiste Daroussin 
21844bf54857SBaptiste Daroussin 	/* workaround for some use cases */
21854bf54857SBaptiste Daroussin 	if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
21864bf54857SBaptiste Daroussin 			key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
21874bf54857SBaptiste Daroussin 		/* Remove copied key */
21884bf54857SBaptiste Daroussin 		free (elt->trash_stack[UCL_TRASH_KEY]);
21894bf54857SBaptiste Daroussin 		elt->trash_stack[UCL_TRASH_KEY] = NULL;
21904bf54857SBaptiste Daroussin 		elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
21914bf54857SBaptiste Daroussin 	}
21924bf54857SBaptiste Daroussin 
2193c99fb5f9SBaptiste Daroussin 	elt->key = key;
2194c99fb5f9SBaptiste Daroussin 	elt->keylen = keylen;
2195c99fb5f9SBaptiste Daroussin 
2196c99fb5f9SBaptiste Daroussin 	if (copy_key) {
2197c99fb5f9SBaptiste Daroussin 		ucl_copy_key_trash (elt);
2198c99fb5f9SBaptiste Daroussin 	}
2199c99fb5f9SBaptiste Daroussin 
2200b04a7a0bSBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
2201c99fb5f9SBaptiste Daroussin 
22024bf54857SBaptiste Daroussin 	if (found == NULL) {
22038e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
220497bd480fSBaptiste Daroussin 		top->len ++;
2205b04a7a0bSBaptiste Daroussin 		if (replace) {
2206b04a7a0bSBaptiste Daroussin 			ret = false;
2207b04a7a0bSBaptiste Daroussin 		}
2208c99fb5f9SBaptiste Daroussin 	}
2209c99fb5f9SBaptiste Daroussin 	else {
2210c99fb5f9SBaptiste Daroussin 		if (replace) {
22114bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, elt);
2212c99fb5f9SBaptiste Daroussin 			ucl_object_unref (found);
2213c99fb5f9SBaptiste Daroussin 		}
2214c99fb5f9SBaptiste Daroussin 		else if (merge) {
2215c99fb5f9SBaptiste Daroussin 			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
2216c99fb5f9SBaptiste Daroussin 				/* Insert old elt to new one */
2217b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (elt, found, found->key,
2218b04a7a0bSBaptiste Daroussin 						found->keylen, copy_key, false, false);
2219c99fb5f9SBaptiste Daroussin 				ucl_hash_delete (top->value.ov, found);
22208e3b1ab2SBaptiste Daroussin 				top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
2221c99fb5f9SBaptiste Daroussin 			}
2222c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
2223c99fb5f9SBaptiste Daroussin 				/* Insert new to old */
2224b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (found, elt, elt->key,
2225b04a7a0bSBaptiste Daroussin 						elt->keylen, copy_key, false, false);
2226c99fb5f9SBaptiste Daroussin 			}
2227c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
2228c99fb5f9SBaptiste Daroussin 				/* Mix two hashes */
2229d9f0ce31SBaptiste Daroussin 				while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
2230b04a7a0bSBaptiste Daroussin 					tmp = ucl_object_ref (cur);
2231b04a7a0bSBaptiste Daroussin 					ucl_object_insert_key_common (found, tmp, cur->key,
2232b04a7a0bSBaptiste Daroussin 							cur->keylen, copy_key, false, false);
2233c99fb5f9SBaptiste Daroussin 				}
2234c99fb5f9SBaptiste Daroussin 				ucl_object_unref (elt);
2235c99fb5f9SBaptiste Daroussin 			}
2236c99fb5f9SBaptiste Daroussin 			else {
2237c99fb5f9SBaptiste Daroussin 				/* Just make a list of scalars */
2238c99fb5f9SBaptiste Daroussin 				DL_APPEND (found, elt);
2239c99fb5f9SBaptiste Daroussin 			}
2240c99fb5f9SBaptiste Daroussin 		}
2241c99fb5f9SBaptiste Daroussin 		else {
2242c99fb5f9SBaptiste Daroussin 			DL_APPEND (found, elt);
2243c99fb5f9SBaptiste Daroussin 		}
2244c99fb5f9SBaptiste Daroussin 	}
2245c99fb5f9SBaptiste Daroussin 
2246b04a7a0bSBaptiste Daroussin 	return ret;
2247c99fb5f9SBaptiste Daroussin }
2248c99fb5f9SBaptiste Daroussin 
224936c53d67SBaptiste Daroussin bool
225036c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
225136c53d67SBaptiste Daroussin {
225236c53d67SBaptiste Daroussin 	ucl_object_t *found;
225336c53d67SBaptiste Daroussin 
225497bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
225597bd480fSBaptiste Daroussin 		return false;
225697bd480fSBaptiste Daroussin 	}
225797bd480fSBaptiste Daroussin 
2258d9f0ce31SBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_object_lookup_len (top, key, keylen));
225936c53d67SBaptiste Daroussin 
226097bd480fSBaptiste Daroussin 	if (found == NULL) {
226136c53d67SBaptiste Daroussin 		return false;
226297bd480fSBaptiste Daroussin 	}
226336c53d67SBaptiste Daroussin 
226436c53d67SBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
226536c53d67SBaptiste Daroussin 	ucl_object_unref (found);
226636c53d67SBaptiste Daroussin 	top->len --;
226736c53d67SBaptiste Daroussin 
226836c53d67SBaptiste Daroussin 	return true;
226936c53d67SBaptiste Daroussin }
227036c53d67SBaptiste Daroussin 
227136c53d67SBaptiste Daroussin bool
227236c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key)
227336c53d67SBaptiste Daroussin {
2274b04a7a0bSBaptiste Daroussin 	return ucl_object_delete_keyl (top, key, strlen (key));
227536c53d67SBaptiste Daroussin }
227636c53d67SBaptiste Daroussin 
2277c99fb5f9SBaptiste Daroussin ucl_object_t*
227897bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
227997bd480fSBaptiste Daroussin {
2280b04a7a0bSBaptiste Daroussin 	const ucl_object_t *found;
228197bd480fSBaptiste Daroussin 
228297bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
228397bd480fSBaptiste Daroussin 		return false;
228497bd480fSBaptiste Daroussin 	}
2285d9f0ce31SBaptiste Daroussin 	found = ucl_object_lookup_len (top, key, keylen);
228697bd480fSBaptiste Daroussin 
228797bd480fSBaptiste Daroussin 	if (found == NULL) {
228897bd480fSBaptiste Daroussin 		return NULL;
228997bd480fSBaptiste Daroussin 	}
229097bd480fSBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
229197bd480fSBaptiste Daroussin 	top->len --;
229297bd480fSBaptiste Daroussin 
2293b04a7a0bSBaptiste Daroussin 	return __DECONST (ucl_object_t *, found);
229497bd480fSBaptiste Daroussin }
229597bd480fSBaptiste Daroussin 
229697bd480fSBaptiste Daroussin ucl_object_t*
229797bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key)
229897bd480fSBaptiste Daroussin {
2299b04a7a0bSBaptiste Daroussin 	return ucl_object_pop_keyl (top, key, strlen (key));
230097bd480fSBaptiste Daroussin }
230197bd480fSBaptiste Daroussin 
2302b04a7a0bSBaptiste Daroussin bool
2303c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
2304c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2305c99fb5f9SBaptiste Daroussin {
2306c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
2307c99fb5f9SBaptiste Daroussin }
2308c99fb5f9SBaptiste Daroussin 
2309b04a7a0bSBaptiste Daroussin bool
2310c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
2311c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2312c99fb5f9SBaptiste Daroussin {
2313c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
2314c99fb5f9SBaptiste Daroussin }
2315c99fb5f9SBaptiste Daroussin 
2316b04a7a0bSBaptiste Daroussin bool
2317c99fb5f9SBaptiste Daroussin ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
2318c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2319c99fb5f9SBaptiste Daroussin {
2320c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
2321c99fb5f9SBaptiste Daroussin }
2322c99fb5f9SBaptiste Daroussin 
23234bf54857SBaptiste Daroussin bool
23244bf54857SBaptiste Daroussin ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
23254bf54857SBaptiste Daroussin {
23264bf54857SBaptiste Daroussin 	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
23274bf54857SBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
23284bf54857SBaptiste Daroussin 
23294bf54857SBaptiste Daroussin 	if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
23304bf54857SBaptiste Daroussin 		return false;
23314bf54857SBaptiste Daroussin 	}
23324bf54857SBaptiste Daroussin 
23334bf54857SBaptiste Daroussin 	/* Mix two hashes */
23344bf54857SBaptiste Daroussin 	while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
23354bf54857SBaptiste Daroussin 		if (copy) {
23364bf54857SBaptiste Daroussin 			cp = ucl_object_copy (cur);
23374bf54857SBaptiste Daroussin 		}
23384bf54857SBaptiste Daroussin 		else {
23394bf54857SBaptiste Daroussin 			cp = ucl_object_ref (cur);
23404bf54857SBaptiste Daroussin 		}
23414bf54857SBaptiste Daroussin 		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
23424bf54857SBaptiste Daroussin 		if (found == NULL) {
23434bf54857SBaptiste Daroussin 			/* The key does not exist */
23448e3b1ab2SBaptiste Daroussin 			top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
23454bf54857SBaptiste Daroussin 			top->len ++;
23464bf54857SBaptiste Daroussin 		}
23474bf54857SBaptiste Daroussin 		else {
23484bf54857SBaptiste Daroussin 			/* The key already exists, replace it */
23494bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, cp);
23504bf54857SBaptiste Daroussin 			ucl_object_unref (found);
23514bf54857SBaptiste Daroussin 		}
23524bf54857SBaptiste Daroussin 	}
23534bf54857SBaptiste Daroussin 
23544bf54857SBaptiste Daroussin 	return true;
23554bf54857SBaptiste Daroussin }
23564bf54857SBaptiste Daroussin 
2357b04a7a0bSBaptiste Daroussin const ucl_object_t *
2358d9f0ce31SBaptiste Daroussin ucl_object_lookup_len (const ucl_object_t *obj, const char *key, size_t klen)
2359c99fb5f9SBaptiste Daroussin {
2360b04a7a0bSBaptiste Daroussin 	const ucl_object_t *ret;
2361b04a7a0bSBaptiste Daroussin 	ucl_object_t srch;
2362c99fb5f9SBaptiste Daroussin 
2363c99fb5f9SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
2364c99fb5f9SBaptiste Daroussin 		return NULL;
2365c99fb5f9SBaptiste Daroussin 	}
2366c99fb5f9SBaptiste Daroussin 
2367c99fb5f9SBaptiste Daroussin 	srch.key = key;
2368c99fb5f9SBaptiste Daroussin 	srch.keylen = klen;
2369c99fb5f9SBaptiste Daroussin 	ret = ucl_hash_search_obj (obj->value.ov, &srch);
2370c99fb5f9SBaptiste Daroussin 
2371c99fb5f9SBaptiste Daroussin 	return ret;
2372c99fb5f9SBaptiste Daroussin }
2373c99fb5f9SBaptiste Daroussin 
2374b04a7a0bSBaptiste Daroussin const ucl_object_t *
2375d9f0ce31SBaptiste Daroussin ucl_object_lookup (const ucl_object_t *obj, const char *key)
2376c99fb5f9SBaptiste Daroussin {
237739ee7a7aSBaptiste Daroussin 	if (key == NULL) {
2378c99fb5f9SBaptiste Daroussin 		return NULL;
237939ee7a7aSBaptiste Daroussin 	}
2380c99fb5f9SBaptiste Daroussin 
2381d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_len (obj, key, strlen (key));
2382c99fb5f9SBaptiste Daroussin }
2383c99fb5f9SBaptiste Daroussin 
2384b04a7a0bSBaptiste Daroussin const ucl_object_t*
2385d9f0ce31SBaptiste Daroussin ucl_object_lookup_any (const ucl_object_t *obj,
238639ee7a7aSBaptiste Daroussin 		const char *key, ...)
238739ee7a7aSBaptiste Daroussin {
238839ee7a7aSBaptiste Daroussin 	va_list ap;
238939ee7a7aSBaptiste Daroussin 	const ucl_object_t *ret = NULL;
239039ee7a7aSBaptiste Daroussin 	const char *nk = NULL;
239139ee7a7aSBaptiste Daroussin 
239239ee7a7aSBaptiste Daroussin 	if (obj == NULL || key == NULL) {
239339ee7a7aSBaptiste Daroussin 		return NULL;
239439ee7a7aSBaptiste Daroussin 	}
239539ee7a7aSBaptiste Daroussin 
2396d9f0ce31SBaptiste Daroussin 	ret = ucl_object_lookup_len (obj, key, strlen (key));
239739ee7a7aSBaptiste Daroussin 
239839ee7a7aSBaptiste Daroussin 	if (ret == NULL) {
239939ee7a7aSBaptiste Daroussin 		va_start (ap, key);
240039ee7a7aSBaptiste Daroussin 
240139ee7a7aSBaptiste Daroussin 		while (ret == NULL) {
240239ee7a7aSBaptiste Daroussin 			nk = va_arg (ap, const char *);
240339ee7a7aSBaptiste Daroussin 
240439ee7a7aSBaptiste Daroussin 			if (nk == NULL) {
240539ee7a7aSBaptiste Daroussin 				break;
240639ee7a7aSBaptiste Daroussin 			}
240739ee7a7aSBaptiste Daroussin 			else {
2408d9f0ce31SBaptiste Daroussin 				ret = ucl_object_lookup_len (obj, nk, strlen (nk));
240939ee7a7aSBaptiste Daroussin 			}
241039ee7a7aSBaptiste Daroussin 		}
241139ee7a7aSBaptiste Daroussin 
241239ee7a7aSBaptiste Daroussin 		va_end (ap);
241339ee7a7aSBaptiste Daroussin 	}
241439ee7a7aSBaptiste Daroussin 
241539ee7a7aSBaptiste Daroussin 	return ret;
241639ee7a7aSBaptiste Daroussin }
241739ee7a7aSBaptiste Daroussin 
241839ee7a7aSBaptiste Daroussin const ucl_object_t*
2419d9f0ce31SBaptiste Daroussin ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
2420c99fb5f9SBaptiste Daroussin {
24218e3b1ab2SBaptiste Daroussin 	const ucl_object_t *elt = NULL;
2422c99fb5f9SBaptiste Daroussin 
242397bd480fSBaptiste Daroussin 	if (obj == NULL || iter == NULL) {
242497bd480fSBaptiste Daroussin 		return NULL;
242597bd480fSBaptiste Daroussin 	}
242697bd480fSBaptiste Daroussin 
2427c99fb5f9SBaptiste Daroussin 	if (expand_values) {
2428c99fb5f9SBaptiste Daroussin 		switch (obj->type) {
2429c99fb5f9SBaptiste Daroussin 		case UCL_OBJECT:
2430b04a7a0bSBaptiste Daroussin 			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
2431c99fb5f9SBaptiste Daroussin 			break;
24328e3b1ab2SBaptiste Daroussin 		case UCL_ARRAY: {
24338e3b1ab2SBaptiste Daroussin 			unsigned int idx;
24348e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
24358e3b1ab2SBaptiste Daroussin 			idx = (unsigned int)(uintptr_t)(*iter);
24368e3b1ab2SBaptiste Daroussin 
24378e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
24388e3b1ab2SBaptiste Daroussin 				while (idx < kv_size (*vec)) {
24398e3b1ab2SBaptiste Daroussin 					if ((elt = kv_A (*vec, idx)) != NULL) {
24408e3b1ab2SBaptiste Daroussin 						idx ++;
24418e3b1ab2SBaptiste Daroussin 						break;
2442c99fb5f9SBaptiste Daroussin 					}
24438e3b1ab2SBaptiste Daroussin 					idx ++;
2444c99fb5f9SBaptiste Daroussin 				}
24458e3b1ab2SBaptiste Daroussin 				*iter = (void *)(uintptr_t)idx;
2446c99fb5f9SBaptiste Daroussin 			}
24478e3b1ab2SBaptiste Daroussin 
2448c99fb5f9SBaptiste Daroussin 			return elt;
24498e3b1ab2SBaptiste Daroussin 			break;
24508e3b1ab2SBaptiste Daroussin 		}
2451c99fb5f9SBaptiste Daroussin 		default:
2452c99fb5f9SBaptiste Daroussin 			/* Go to linear iteration */
2453c99fb5f9SBaptiste Daroussin 			break;
2454c99fb5f9SBaptiste Daroussin 		}
2455c99fb5f9SBaptiste Daroussin 	}
2456c99fb5f9SBaptiste Daroussin 	/* Treat everything as a linear list */
2457c99fb5f9SBaptiste Daroussin 	elt = *iter;
2458c99fb5f9SBaptiste Daroussin 	if (elt == NULL) {
2459c99fb5f9SBaptiste Daroussin 		elt = obj;
2460c99fb5f9SBaptiste Daroussin 	}
2461c99fb5f9SBaptiste Daroussin 	else if (elt == obj) {
2462c99fb5f9SBaptiste Daroussin 		return NULL;
2463c99fb5f9SBaptiste Daroussin 	}
2464b04a7a0bSBaptiste Daroussin 	*iter = __DECONST (void *, elt->next ? elt->next : obj);
2465c99fb5f9SBaptiste Daroussin 	return elt;
2466c99fb5f9SBaptiste Daroussin 
2467c99fb5f9SBaptiste Daroussin 	/* Not reached */
2468c99fb5f9SBaptiste Daroussin 	return NULL;
2469c99fb5f9SBaptiste Daroussin }
247097bd480fSBaptiste Daroussin 
24718e3b1ab2SBaptiste Daroussin const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
24728e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter {
24738e3b1ab2SBaptiste Daroussin 	char magic[4]; /* safety check */
24748e3b1ab2SBaptiste Daroussin 	const ucl_object_t *impl_it; /* implicit object iteration */
24758e3b1ab2SBaptiste Daroussin 	ucl_object_iter_t expl_it; /* explicit iteration */
24768e3b1ab2SBaptiste Daroussin };
24778e3b1ab2SBaptiste Daroussin 
24788e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr)
24798e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER_CHECK(it) do { \
24808e3b1ab2SBaptiste Daroussin 	assert (it != NULL); \
24818e3b1ab2SBaptiste Daroussin 	assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \
24828e3b1ab2SBaptiste Daroussin  } while (0)
24838e3b1ab2SBaptiste Daroussin 
24848e3b1ab2SBaptiste Daroussin ucl_object_iter_t
24858e3b1ab2SBaptiste Daroussin ucl_object_iterate_new (const ucl_object_t *obj)
24868e3b1ab2SBaptiste Daroussin {
24878e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *it;
24888e3b1ab2SBaptiste Daroussin 
24898e3b1ab2SBaptiste Daroussin 	it = UCL_ALLOC (sizeof (*it));
24908e3b1ab2SBaptiste Daroussin 	if (it != NULL) {
24918e3b1ab2SBaptiste Daroussin 		memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
24928e3b1ab2SBaptiste Daroussin 		it->expl_it = NULL;
24938e3b1ab2SBaptiste Daroussin 		it->impl_it = obj;
24948e3b1ab2SBaptiste Daroussin 	}
24958e3b1ab2SBaptiste Daroussin 
24968e3b1ab2SBaptiste Daroussin 	return (ucl_object_iter_t)it;
24978e3b1ab2SBaptiste Daroussin }
24988e3b1ab2SBaptiste Daroussin 
24998e3b1ab2SBaptiste Daroussin 
25008e3b1ab2SBaptiste Daroussin ucl_object_iter_t
25018e3b1ab2SBaptiste Daroussin ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
25028e3b1ab2SBaptiste Daroussin {
25038e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
25048e3b1ab2SBaptiste Daroussin 
25058e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
25068e3b1ab2SBaptiste Daroussin 
2507*11dd9ed6SBaptiste Daroussin 	if (rit->expl_it != NULL) {
2508*11dd9ed6SBaptiste Daroussin 		UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
2509*11dd9ed6SBaptiste Daroussin 	}
2510*11dd9ed6SBaptiste Daroussin 
25118e3b1ab2SBaptiste Daroussin 	rit->impl_it = obj;
25128e3b1ab2SBaptiste Daroussin 	rit->expl_it = NULL;
25138e3b1ab2SBaptiste Daroussin 
25148e3b1ab2SBaptiste Daroussin 	return it;
25158e3b1ab2SBaptiste Daroussin }
25168e3b1ab2SBaptiste Daroussin 
25178e3b1ab2SBaptiste Daroussin const ucl_object_t*
25188e3b1ab2SBaptiste Daroussin ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
25198e3b1ab2SBaptiste Daroussin {
2520*11dd9ed6SBaptiste Daroussin 	return ucl_object_iterate_full (it, expand_values ? UCL_ITERATE_BOTH :
2521*11dd9ed6SBaptiste Daroussin 			UCL_ITERATE_IMPLICIT);
2522*11dd9ed6SBaptiste Daroussin }
2523*11dd9ed6SBaptiste Daroussin 
2524*11dd9ed6SBaptiste Daroussin const ucl_object_t*
2525*11dd9ed6SBaptiste Daroussin ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)
2526*11dd9ed6SBaptiste Daroussin {
25278e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
25288e3b1ab2SBaptiste Daroussin 	const ucl_object_t *ret = NULL;
25298e3b1ab2SBaptiste Daroussin 
25308e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
25318e3b1ab2SBaptiste Daroussin 
25328e3b1ab2SBaptiste Daroussin 	if (rit->impl_it == NULL) {
25338e3b1ab2SBaptiste Daroussin 		return NULL;
25348e3b1ab2SBaptiste Daroussin 	}
25358e3b1ab2SBaptiste Daroussin 
25368e3b1ab2SBaptiste Daroussin 	if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
2537d9f0ce31SBaptiste Daroussin 		ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
25388e3b1ab2SBaptiste Daroussin 
2539*11dd9ed6SBaptiste Daroussin 		if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
25408e3b1ab2SBaptiste Daroussin 			/* Need to switch to another implicit object in chain */
25418e3b1ab2SBaptiste Daroussin 			rit->impl_it = rit->impl_it->next;
25428e3b1ab2SBaptiste Daroussin 			rit->expl_it = NULL;
2543*11dd9ed6SBaptiste Daroussin 
2544*11dd9ed6SBaptiste Daroussin 			return ucl_object_iterate_safe (it, type);
25458e3b1ab2SBaptiste Daroussin 		}
25468e3b1ab2SBaptiste Daroussin 	}
25478e3b1ab2SBaptiste Daroussin 	else {
25488e3b1ab2SBaptiste Daroussin 		/* Just iterate over the implicit array */
25498e3b1ab2SBaptiste Daroussin 		ret = rit->impl_it;
25508e3b1ab2SBaptiste Daroussin 		rit->impl_it = rit->impl_it->next;
2551*11dd9ed6SBaptiste Daroussin 
2552*11dd9ed6SBaptiste Daroussin 		if (type & UCL_ITERATE_EXPLICIT) {
25538e3b1ab2SBaptiste Daroussin 			/* We flatten objects if need to expand values */
25548e3b1ab2SBaptiste Daroussin 			if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
2555*11dd9ed6SBaptiste Daroussin 				return ucl_object_iterate_safe (it, type);
25568e3b1ab2SBaptiste Daroussin 			}
25578e3b1ab2SBaptiste Daroussin 		}
25588e3b1ab2SBaptiste Daroussin 	}
25598e3b1ab2SBaptiste Daroussin 
25608e3b1ab2SBaptiste Daroussin 	return ret;
25618e3b1ab2SBaptiste Daroussin }
25628e3b1ab2SBaptiste Daroussin 
25638e3b1ab2SBaptiste Daroussin void
25648e3b1ab2SBaptiste Daroussin ucl_object_iterate_free (ucl_object_iter_t it)
25658e3b1ab2SBaptiste Daroussin {
25668e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
25678e3b1ab2SBaptiste Daroussin 
25688e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
25698e3b1ab2SBaptiste Daroussin 
2570*11dd9ed6SBaptiste Daroussin 	if (rit->expl_it != NULL) {
2571*11dd9ed6SBaptiste Daroussin 		UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
2572*11dd9ed6SBaptiste Daroussin 	}
2573*11dd9ed6SBaptiste Daroussin 
25748e3b1ab2SBaptiste Daroussin 	UCL_FREE (sizeof (*rit), it);
25758e3b1ab2SBaptiste Daroussin }
25768e3b1ab2SBaptiste Daroussin 
25772e8ed2b8SBaptiste Daroussin const ucl_object_t *
2578d9f0ce31SBaptiste Daroussin ucl_object_lookup_path (const ucl_object_t *top, const char *path_in) {
2579d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_path_char (top, path_in, '.');
258039ee7a7aSBaptiste Daroussin }
258139ee7a7aSBaptiste Daroussin 
258239ee7a7aSBaptiste Daroussin 
258339ee7a7aSBaptiste Daroussin const ucl_object_t *
2584d9f0ce31SBaptiste Daroussin ucl_object_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) {
25852e8ed2b8SBaptiste Daroussin 	const ucl_object_t *o = NULL, *found;
25862e8ed2b8SBaptiste Daroussin 	const char *p, *c;
25872e8ed2b8SBaptiste Daroussin 	char *err_str;
25882e8ed2b8SBaptiste Daroussin 	unsigned index;
25892e8ed2b8SBaptiste Daroussin 
25902e8ed2b8SBaptiste Daroussin 	if (path_in == NULL || top == NULL) {
25912e8ed2b8SBaptiste Daroussin 		return NULL;
25922e8ed2b8SBaptiste Daroussin 	}
25932e8ed2b8SBaptiste Daroussin 
25942e8ed2b8SBaptiste Daroussin 	found = NULL;
25952e8ed2b8SBaptiste Daroussin 	p = path_in;
25962e8ed2b8SBaptiste Daroussin 
25972e8ed2b8SBaptiste Daroussin 	/* Skip leading dots */
259839ee7a7aSBaptiste Daroussin 	while (*p == sep) {
25992e8ed2b8SBaptiste Daroussin 		p ++;
26002e8ed2b8SBaptiste Daroussin 	}
26012e8ed2b8SBaptiste Daroussin 
26022e8ed2b8SBaptiste Daroussin 	c = p;
26032e8ed2b8SBaptiste Daroussin 	while (*p != '\0') {
26042e8ed2b8SBaptiste Daroussin 		p ++;
260539ee7a7aSBaptiste Daroussin 		if (*p == sep || *p == '\0') {
26062e8ed2b8SBaptiste Daroussin 			if (p > c) {
26072e8ed2b8SBaptiste Daroussin 				switch (top->type) {
26082e8ed2b8SBaptiste Daroussin 				case UCL_ARRAY:
26092e8ed2b8SBaptiste Daroussin 					/* Key should be an int */
26102e8ed2b8SBaptiste Daroussin 					index = strtoul (c, &err_str, 10);
261139ee7a7aSBaptiste Daroussin 					if (err_str != NULL && (*err_str != sep && *err_str != '\0')) {
26122e8ed2b8SBaptiste Daroussin 						return NULL;
26132e8ed2b8SBaptiste Daroussin 					}
26142e8ed2b8SBaptiste Daroussin 					o = ucl_array_find_index (top, index);
26152e8ed2b8SBaptiste Daroussin 					break;
26162e8ed2b8SBaptiste Daroussin 				default:
2617d9f0ce31SBaptiste Daroussin 					o = ucl_object_lookup_len (top, c, p - c);
26182e8ed2b8SBaptiste Daroussin 					break;
26192e8ed2b8SBaptiste Daroussin 				}
26202e8ed2b8SBaptiste Daroussin 				if (o == NULL) {
26212e8ed2b8SBaptiste Daroussin 					return NULL;
26222e8ed2b8SBaptiste Daroussin 				}
26232e8ed2b8SBaptiste Daroussin 				top = o;
26242e8ed2b8SBaptiste Daroussin 			}
26252e8ed2b8SBaptiste Daroussin 			if (*p != '\0') {
26262e8ed2b8SBaptiste Daroussin 				c = p + 1;
26272e8ed2b8SBaptiste Daroussin 			}
26282e8ed2b8SBaptiste Daroussin 		}
26292e8ed2b8SBaptiste Daroussin 	}
26302e8ed2b8SBaptiste Daroussin 	found = o;
26312e8ed2b8SBaptiste Daroussin 
26322e8ed2b8SBaptiste Daroussin 	return found;
26332e8ed2b8SBaptiste Daroussin }
26342e8ed2b8SBaptiste Daroussin 
263597bd480fSBaptiste Daroussin 
263697bd480fSBaptiste Daroussin ucl_object_t *
263797bd480fSBaptiste Daroussin ucl_object_new (void)
263897bd480fSBaptiste Daroussin {
26394bf54857SBaptiste Daroussin 	return ucl_object_typed_new (UCL_NULL);
264097bd480fSBaptiste Daroussin }
264197bd480fSBaptiste Daroussin 
264297bd480fSBaptiste Daroussin ucl_object_t *
26432e8ed2b8SBaptiste Daroussin ucl_object_typed_new (ucl_type_t type)
264497bd480fSBaptiste Daroussin {
26454bf54857SBaptiste Daroussin 	return ucl_object_new_full (type, 0);
26464bf54857SBaptiste Daroussin }
26474bf54857SBaptiste Daroussin 
26484bf54857SBaptiste Daroussin ucl_object_t *
26494bf54857SBaptiste Daroussin ucl_object_new_full (ucl_type_t type, unsigned priority)
26504bf54857SBaptiste Daroussin {
265197bd480fSBaptiste Daroussin 	ucl_object_t *new;
26524bf54857SBaptiste Daroussin 
26534bf54857SBaptiste Daroussin 	if (type != UCL_USERDATA) {
26544bf54857SBaptiste Daroussin 		new = UCL_ALLOC (sizeof (ucl_object_t));
265597bd480fSBaptiste Daroussin 		if (new != NULL) {
265697bd480fSBaptiste Daroussin 			memset (new, 0, sizeof (ucl_object_t));
265797bd480fSBaptiste Daroussin 			new->ref = 1;
265897bd480fSBaptiste Daroussin 			new->type = (type <= UCL_NULL ? type : UCL_NULL);
26594bf54857SBaptiste Daroussin 			new->next = NULL;
26604bf54857SBaptiste Daroussin 			new->prev = new;
26614bf54857SBaptiste Daroussin 			ucl_object_set_priority (new, priority);
26628e3b1ab2SBaptiste Daroussin 
26638e3b1ab2SBaptiste Daroussin 			if (type == UCL_ARRAY) {
26648e3b1ab2SBaptiste Daroussin 				new->value.av = UCL_ALLOC (sizeof (ucl_array_t));
26658e3b1ab2SBaptiste Daroussin 				if (new->value.av) {
26668e3b1ab2SBaptiste Daroussin 					memset (new->value.av, 0, sizeof (ucl_array_t));
26678e3b1ab2SBaptiste Daroussin 					UCL_ARRAY_GET (vec, new);
26688e3b1ab2SBaptiste Daroussin 
26698e3b1ab2SBaptiste Daroussin 					/* Preallocate some space for arrays */
26708e3b1ab2SBaptiste Daroussin 					kv_resize (ucl_object_t *, *vec, 8);
26718e3b1ab2SBaptiste Daroussin 				}
26728e3b1ab2SBaptiste Daroussin 			}
267397bd480fSBaptiste Daroussin 		}
26744bf54857SBaptiste Daroussin 	}
26754bf54857SBaptiste Daroussin 	else {
2676d9f0ce31SBaptiste Daroussin 		new = ucl_object_new_userdata (NULL, NULL, NULL);
26774bf54857SBaptiste Daroussin 		ucl_object_set_priority (new, priority);
26784bf54857SBaptiste Daroussin 	}
26794bf54857SBaptiste Daroussin 
268097bd480fSBaptiste Daroussin 	return new;
268197bd480fSBaptiste Daroussin }
268297bd480fSBaptiste Daroussin 
26834bf54857SBaptiste Daroussin ucl_object_t*
2684d9f0ce31SBaptiste Daroussin ucl_object_new_userdata (ucl_userdata_dtor dtor,
2685d9f0ce31SBaptiste Daroussin 		ucl_userdata_emitter emitter,
2686d9f0ce31SBaptiste Daroussin 		void *ptr)
26874bf54857SBaptiste Daroussin {
26884bf54857SBaptiste Daroussin 	struct ucl_object_userdata *new;
26894bf54857SBaptiste Daroussin 	size_t nsize = sizeof (*new);
26904bf54857SBaptiste Daroussin 
26914bf54857SBaptiste Daroussin 	new = UCL_ALLOC (nsize);
26924bf54857SBaptiste Daroussin 	if (new != NULL) {
26934bf54857SBaptiste Daroussin 		memset (new, 0, nsize);
26944bf54857SBaptiste Daroussin 		new->obj.ref = 1;
26954bf54857SBaptiste Daroussin 		new->obj.type = UCL_USERDATA;
26964bf54857SBaptiste Daroussin 		new->obj.next = NULL;
26974bf54857SBaptiste Daroussin 		new->obj.prev = (ucl_object_t *)new;
26984bf54857SBaptiste Daroussin 		new->dtor = dtor;
26994bf54857SBaptiste Daroussin 		new->emitter = emitter;
2700d9f0ce31SBaptiste Daroussin 		new->obj.value.ud = ptr;
27014bf54857SBaptiste Daroussin 	}
27024bf54857SBaptiste Daroussin 
27034bf54857SBaptiste Daroussin 	return (ucl_object_t *)new;
27044bf54857SBaptiste Daroussin }
27054bf54857SBaptiste Daroussin 
27062e8ed2b8SBaptiste Daroussin ucl_type_t
27072e8ed2b8SBaptiste Daroussin ucl_object_type (const ucl_object_t *obj)
27082e8ed2b8SBaptiste Daroussin {
270939ee7a7aSBaptiste Daroussin 	if (obj == NULL) {
271039ee7a7aSBaptiste Daroussin 		return UCL_NULL;
271139ee7a7aSBaptiste Daroussin 	}
271239ee7a7aSBaptiste Daroussin 
27132e8ed2b8SBaptiste Daroussin 	return obj->type;
27142e8ed2b8SBaptiste Daroussin }
27152e8ed2b8SBaptiste Daroussin 
271697bd480fSBaptiste Daroussin ucl_object_t*
271797bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str)
271897bd480fSBaptiste Daroussin {
271997bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
272097bd480fSBaptiste Daroussin }
272197bd480fSBaptiste Daroussin 
272297bd480fSBaptiste Daroussin ucl_object_t *
272397bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len)
272497bd480fSBaptiste Daroussin {
272597bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
272697bd480fSBaptiste Daroussin }
272797bd480fSBaptiste Daroussin 
272897bd480fSBaptiste Daroussin ucl_object_t *
272997bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv)
273097bd480fSBaptiste Daroussin {
273197bd480fSBaptiste Daroussin 	ucl_object_t *obj;
273297bd480fSBaptiste Daroussin 
273397bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
273497bd480fSBaptiste Daroussin 	if (obj != NULL) {
273597bd480fSBaptiste Daroussin 		obj->type = UCL_INT;
273697bd480fSBaptiste Daroussin 		obj->value.iv = iv;
273797bd480fSBaptiste Daroussin 	}
273897bd480fSBaptiste Daroussin 
273997bd480fSBaptiste Daroussin 	return obj;
274097bd480fSBaptiste Daroussin }
274197bd480fSBaptiste Daroussin 
274297bd480fSBaptiste Daroussin ucl_object_t *
274397bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv)
274497bd480fSBaptiste Daroussin {
274597bd480fSBaptiste Daroussin 	ucl_object_t *obj;
274697bd480fSBaptiste Daroussin 
274797bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
274897bd480fSBaptiste Daroussin 	if (obj != NULL) {
274997bd480fSBaptiste Daroussin 		obj->type = UCL_FLOAT;
275097bd480fSBaptiste Daroussin 		obj->value.dv = dv;
275197bd480fSBaptiste Daroussin 	}
275297bd480fSBaptiste Daroussin 
275397bd480fSBaptiste Daroussin 	return obj;
275497bd480fSBaptiste Daroussin }
275597bd480fSBaptiste Daroussin 
275697bd480fSBaptiste Daroussin ucl_object_t*
275797bd480fSBaptiste Daroussin ucl_object_frombool (bool bv)
275897bd480fSBaptiste Daroussin {
275997bd480fSBaptiste Daroussin 	ucl_object_t *obj;
276097bd480fSBaptiste Daroussin 
276197bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
276297bd480fSBaptiste Daroussin 	if (obj != NULL) {
276397bd480fSBaptiste Daroussin 		obj->type = UCL_BOOLEAN;
276497bd480fSBaptiste Daroussin 		obj->value.iv = bv;
276597bd480fSBaptiste Daroussin 	}
276697bd480fSBaptiste Daroussin 
276797bd480fSBaptiste Daroussin 	return obj;
276897bd480fSBaptiste Daroussin }
276997bd480fSBaptiste Daroussin 
2770b04a7a0bSBaptiste Daroussin bool
277197bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
277297bd480fSBaptiste Daroussin {
27738e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
277497bd480fSBaptiste Daroussin 
2775b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
2776b04a7a0bSBaptiste Daroussin 		return false;
277797bd480fSBaptiste Daroussin 	}
277897bd480fSBaptiste Daroussin 
27798e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
27808e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
278139ee7a7aSBaptiste Daroussin 
278239ee7a7aSBaptiste Daroussin 		if (vec == NULL) {
278339ee7a7aSBaptiste Daroussin 			return false;
278439ee7a7aSBaptiste Daroussin 		}
278539ee7a7aSBaptiste Daroussin 
27868e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
27878e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
278897bd480fSBaptiste Daroussin 	}
27898e3b1ab2SBaptiste Daroussin 
27908e3b1ab2SBaptiste Daroussin 	kv_push (ucl_object_t *, *vec, elt);
27918e3b1ab2SBaptiste Daroussin 
279297bd480fSBaptiste Daroussin 	top->len ++;
2793b04a7a0bSBaptiste Daroussin 
2794b04a7a0bSBaptiste Daroussin 	return true;
279597bd480fSBaptiste Daroussin }
279697bd480fSBaptiste Daroussin 
2797b04a7a0bSBaptiste Daroussin bool
279897bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
279997bd480fSBaptiste Daroussin {
28008e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
280197bd480fSBaptiste Daroussin 
2802b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
2803b04a7a0bSBaptiste Daroussin 		return false;
280497bd480fSBaptiste Daroussin 	}
280597bd480fSBaptiste Daroussin 
28068e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
28078e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
28088e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
28098e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
28108e3b1ab2SBaptiste Daroussin 		kv_push (ucl_object_t *, *vec, elt);
281197bd480fSBaptiste Daroussin 	}
281297bd480fSBaptiste Daroussin 	else {
28138e3b1ab2SBaptiste Daroussin 		/* Slow O(n) algorithm */
28148e3b1ab2SBaptiste Daroussin 		kv_prepend (ucl_object_t *, *vec, elt);
281597bd480fSBaptiste Daroussin 	}
28168e3b1ab2SBaptiste Daroussin 
281797bd480fSBaptiste Daroussin 	top->len ++;
281897bd480fSBaptiste Daroussin 
2819b04a7a0bSBaptiste Daroussin 	return true;
282097bd480fSBaptiste Daroussin }
282197bd480fSBaptiste Daroussin 
28224bf54857SBaptiste Daroussin bool
28234bf54857SBaptiste Daroussin ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
28244bf54857SBaptiste Daroussin {
28258e3b1ab2SBaptiste Daroussin 	unsigned i;
282639ee7a7aSBaptiste Daroussin 	ucl_object_t *cp = NULL;
28278e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj;
28284bf54857SBaptiste Daroussin 
28294bf54857SBaptiste Daroussin 	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
28304bf54857SBaptiste Daroussin 		return false;
28314bf54857SBaptiste Daroussin 	}
28324bf54857SBaptiste Daroussin 
283339ee7a7aSBaptiste Daroussin 	if (copy) {
283439ee7a7aSBaptiste Daroussin 		cp = ucl_object_copy (elt);
283539ee7a7aSBaptiste Daroussin 	}
283639ee7a7aSBaptiste Daroussin 	else {
283739ee7a7aSBaptiste Daroussin 		cp = ucl_object_ref (elt);
283839ee7a7aSBaptiste Daroussin 	}
283939ee7a7aSBaptiste Daroussin 
284039ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v1, top);
284139ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v2, cp);
284239ee7a7aSBaptiste Daroussin 
2843d9f0ce31SBaptiste Daroussin 	if (v1 && v2) {
28448e3b1ab2SBaptiste Daroussin 		kv_concat (ucl_object_t *, *v1, *v2);
28458e3b1ab2SBaptiste Daroussin 
28468e3b1ab2SBaptiste Daroussin 		for (i = v2->n; i < v1->n; i ++) {
28478e3b1ab2SBaptiste Daroussin 			obj = &kv_A (*v1, i);
28488e3b1ab2SBaptiste Daroussin 			if (*obj == NULL) {
28498e3b1ab2SBaptiste Daroussin 				continue;
28508e3b1ab2SBaptiste Daroussin 			}
28518e3b1ab2SBaptiste Daroussin 			top->len ++;
28524bf54857SBaptiste Daroussin 		}
2853d9f0ce31SBaptiste Daroussin 	}
28544bf54857SBaptiste Daroussin 
28554bf54857SBaptiste Daroussin 	return true;
28564bf54857SBaptiste Daroussin }
28574bf54857SBaptiste Daroussin 
285897bd480fSBaptiste Daroussin ucl_object_t *
285997bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
286097bd480fSBaptiste Daroussin {
28618e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28628e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
28638e3b1ab2SBaptiste Daroussin 	unsigned i;
286497bd480fSBaptiste Daroussin 
286539ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
286639ee7a7aSBaptiste Daroussin 		return NULL;
286739ee7a7aSBaptiste Daroussin 	}
286839ee7a7aSBaptiste Daroussin 
28698e3b1ab2SBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
28708e3b1ab2SBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
28718e3b1ab2SBaptiste Daroussin 			kv_del (ucl_object_t *, *vec, i);
28728e3b1ab2SBaptiste Daroussin 			ret = elt;
287397bd480fSBaptiste Daroussin 			top->len --;
28748e3b1ab2SBaptiste Daroussin 			break;
28758e3b1ab2SBaptiste Daroussin 		}
28768e3b1ab2SBaptiste Daroussin 	}
287797bd480fSBaptiste Daroussin 
28788e3b1ab2SBaptiste Daroussin 	return ret;
287997bd480fSBaptiste Daroussin }
288097bd480fSBaptiste Daroussin 
2881b04a7a0bSBaptiste Daroussin const ucl_object_t *
2882b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top)
288397bd480fSBaptiste Daroussin {
28848e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28858e3b1ab2SBaptiste Daroussin 
288639ee7a7aSBaptiste Daroussin 	if (vec == NULL || top == NULL || top->type != UCL_ARRAY ||
288739ee7a7aSBaptiste Daroussin 			top->value.av == NULL) {
288897bd480fSBaptiste Daroussin 		return NULL;
288997bd480fSBaptiste Daroussin 	}
28908e3b1ab2SBaptiste Daroussin 
28918e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[0] : NULL);
289297bd480fSBaptiste Daroussin }
289397bd480fSBaptiste Daroussin 
2894b04a7a0bSBaptiste Daroussin const ucl_object_t *
2895b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top)
289697bd480fSBaptiste Daroussin {
28978e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28988e3b1ab2SBaptiste Daroussin 
289997bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
290097bd480fSBaptiste Daroussin 		return NULL;
290197bd480fSBaptiste Daroussin 	}
29028e3b1ab2SBaptiste Daroussin 
29038e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
290497bd480fSBaptiste Daroussin }
290597bd480fSBaptiste Daroussin 
290697bd480fSBaptiste Daroussin ucl_object_t *
290797bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top)
290897bd480fSBaptiste Daroussin {
29098e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
29108e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
29118e3b1ab2SBaptiste Daroussin 
29128e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
29138e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, vec->n - 1);
29148e3b1ab2SBaptiste Daroussin 		ret = *obj;
29158e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, vec->n - 1);
29168e3b1ab2SBaptiste Daroussin 		top->len --;
29178e3b1ab2SBaptiste Daroussin 	}
29188e3b1ab2SBaptiste Daroussin 
29198e3b1ab2SBaptiste Daroussin 	return ret;
292097bd480fSBaptiste Daroussin }
292197bd480fSBaptiste Daroussin 
292297bd480fSBaptiste Daroussin ucl_object_t *
292397bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top)
292497bd480fSBaptiste Daroussin {
29258e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
29268e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
29278e3b1ab2SBaptiste Daroussin 
29288e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
29298e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, 0);
29308e3b1ab2SBaptiste Daroussin 		ret = *obj;
29318e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, 0);
29328e3b1ab2SBaptiste Daroussin 		top->len --;
29338e3b1ab2SBaptiste Daroussin 	}
29348e3b1ab2SBaptiste Daroussin 
29358e3b1ab2SBaptiste Daroussin 	return ret;
293697bd480fSBaptiste Daroussin }
293797bd480fSBaptiste Daroussin 
29382e8ed2b8SBaptiste Daroussin const ucl_object_t *
29392e8ed2b8SBaptiste Daroussin ucl_array_find_index (const ucl_object_t *top, unsigned int index)
29402e8ed2b8SBaptiste Daroussin {
29418e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
29422e8ed2b8SBaptiste Daroussin 
29438e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
29448e3b1ab2SBaptiste Daroussin 		return kv_A (*vec, index);
29452e8ed2b8SBaptiste Daroussin 	}
29462e8ed2b8SBaptiste Daroussin 
29472e8ed2b8SBaptiste Daroussin 	return NULL;
29482e8ed2b8SBaptiste Daroussin }
29492e8ed2b8SBaptiste Daroussin 
295039ee7a7aSBaptiste Daroussin unsigned int
295139ee7a7aSBaptiste Daroussin ucl_array_index_of (ucl_object_t *top, ucl_object_t *elt)
295239ee7a7aSBaptiste Daroussin {
295339ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
295439ee7a7aSBaptiste Daroussin 	unsigned i;
295539ee7a7aSBaptiste Daroussin 
295639ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
295739ee7a7aSBaptiste Daroussin 		return (unsigned int)(-1);
295839ee7a7aSBaptiste Daroussin 	}
295939ee7a7aSBaptiste Daroussin 
296039ee7a7aSBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
296139ee7a7aSBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
296239ee7a7aSBaptiste Daroussin 			return i;
296339ee7a7aSBaptiste Daroussin 		}
296439ee7a7aSBaptiste Daroussin 	}
296539ee7a7aSBaptiste Daroussin 
296639ee7a7aSBaptiste Daroussin 	return (unsigned int)(-1);
296739ee7a7aSBaptiste Daroussin }
296839ee7a7aSBaptiste Daroussin 
296997bd480fSBaptiste Daroussin ucl_object_t *
29704bf54857SBaptiste Daroussin ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
29714bf54857SBaptiste Daroussin 	unsigned int index)
29724bf54857SBaptiste Daroussin {
29738e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
29748e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
29754bf54857SBaptiste Daroussin 
29768e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
29778e3b1ab2SBaptiste Daroussin 		ret = kv_A (*vec, index);
29788e3b1ab2SBaptiste Daroussin 		kv_A (*vec, index) = elt;
29794bf54857SBaptiste Daroussin 	}
29804bf54857SBaptiste Daroussin 
29818e3b1ab2SBaptiste Daroussin 	return ret;
29824bf54857SBaptiste Daroussin }
29834bf54857SBaptiste Daroussin 
29844bf54857SBaptiste Daroussin ucl_object_t *
298597bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
298697bd480fSBaptiste Daroussin {
298797bd480fSBaptiste Daroussin 
298897bd480fSBaptiste Daroussin 	if (head == NULL) {
298997bd480fSBaptiste Daroussin 		elt->next = NULL;
299097bd480fSBaptiste Daroussin 		elt->prev = elt;
299197bd480fSBaptiste Daroussin 		head = elt;
299297bd480fSBaptiste Daroussin 	}
299397bd480fSBaptiste Daroussin 	else {
299497bd480fSBaptiste Daroussin 		elt->prev = head->prev;
299597bd480fSBaptiste Daroussin 		head->prev->next = elt;
299697bd480fSBaptiste Daroussin 		head->prev = elt;
299797bd480fSBaptiste Daroussin 		elt->next = NULL;
299897bd480fSBaptiste Daroussin 	}
299997bd480fSBaptiste Daroussin 
300097bd480fSBaptiste Daroussin 	return head;
300197bd480fSBaptiste Daroussin }
300297bd480fSBaptiste Daroussin 
300397bd480fSBaptiste Daroussin bool
3004b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
300597bd480fSBaptiste Daroussin {
300697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
300797bd480fSBaptiste Daroussin 		return false;
300897bd480fSBaptiste Daroussin 	}
300997bd480fSBaptiste Daroussin 	switch (obj->type) {
301097bd480fSBaptiste Daroussin 	case UCL_INT:
301197bd480fSBaptiste Daroussin 		*target = obj->value.iv; /* Probaly could cause overflow */
301297bd480fSBaptiste Daroussin 		break;
301397bd480fSBaptiste Daroussin 	case UCL_FLOAT:
301497bd480fSBaptiste Daroussin 	case UCL_TIME:
301597bd480fSBaptiste Daroussin 		*target = obj->value.dv;
301697bd480fSBaptiste Daroussin 		break;
301797bd480fSBaptiste Daroussin 	default:
301897bd480fSBaptiste Daroussin 		return false;
301997bd480fSBaptiste Daroussin 	}
302097bd480fSBaptiste Daroussin 
302197bd480fSBaptiste Daroussin 	return true;
302297bd480fSBaptiste Daroussin }
302397bd480fSBaptiste Daroussin 
302497bd480fSBaptiste Daroussin double
3025b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj)
302697bd480fSBaptiste Daroussin {
302797bd480fSBaptiste Daroussin 	double result = 0.;
302897bd480fSBaptiste Daroussin 
302997bd480fSBaptiste Daroussin 	ucl_object_todouble_safe (obj, &result);
303097bd480fSBaptiste Daroussin 	return result;
303197bd480fSBaptiste Daroussin }
303297bd480fSBaptiste Daroussin 
303397bd480fSBaptiste Daroussin bool
3034b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
303597bd480fSBaptiste Daroussin {
303697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
303797bd480fSBaptiste Daroussin 		return false;
303897bd480fSBaptiste Daroussin 	}
303997bd480fSBaptiste Daroussin 	switch (obj->type) {
304097bd480fSBaptiste Daroussin 	case UCL_INT:
304197bd480fSBaptiste Daroussin 		*target = obj->value.iv;
304297bd480fSBaptiste Daroussin 		break;
304397bd480fSBaptiste Daroussin 	case UCL_FLOAT:
304497bd480fSBaptiste Daroussin 	case UCL_TIME:
304597bd480fSBaptiste Daroussin 		*target = obj->value.dv; /* Loosing of decimal points */
304697bd480fSBaptiste Daroussin 		break;
304797bd480fSBaptiste Daroussin 	default:
304897bd480fSBaptiste Daroussin 		return false;
304997bd480fSBaptiste Daroussin 	}
305097bd480fSBaptiste Daroussin 
305197bd480fSBaptiste Daroussin 	return true;
305297bd480fSBaptiste Daroussin }
305397bd480fSBaptiste Daroussin 
305497bd480fSBaptiste Daroussin int64_t
3055b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj)
305697bd480fSBaptiste Daroussin {
305797bd480fSBaptiste Daroussin 	int64_t result = 0;
305897bd480fSBaptiste Daroussin 
305997bd480fSBaptiste Daroussin 	ucl_object_toint_safe (obj, &result);
306097bd480fSBaptiste Daroussin 	return result;
306197bd480fSBaptiste Daroussin }
306297bd480fSBaptiste Daroussin 
306397bd480fSBaptiste Daroussin bool
3064b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
306597bd480fSBaptiste Daroussin {
306697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
306797bd480fSBaptiste Daroussin 		return false;
306897bd480fSBaptiste Daroussin 	}
306997bd480fSBaptiste Daroussin 	switch (obj->type) {
307097bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
307197bd480fSBaptiste Daroussin 		*target = (obj->value.iv == true);
307297bd480fSBaptiste Daroussin 		break;
307397bd480fSBaptiste Daroussin 	default:
307497bd480fSBaptiste Daroussin 		return false;
307597bd480fSBaptiste Daroussin 	}
307697bd480fSBaptiste Daroussin 
307797bd480fSBaptiste Daroussin 	return true;
307897bd480fSBaptiste Daroussin }
307997bd480fSBaptiste Daroussin 
308097bd480fSBaptiste Daroussin bool
3081b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj)
308297bd480fSBaptiste Daroussin {
308397bd480fSBaptiste Daroussin 	bool result = false;
308497bd480fSBaptiste Daroussin 
308597bd480fSBaptiste Daroussin 	ucl_object_toboolean_safe (obj, &result);
308697bd480fSBaptiste Daroussin 	return result;
308797bd480fSBaptiste Daroussin }
308897bd480fSBaptiste Daroussin 
308997bd480fSBaptiste Daroussin bool
3090b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
309197bd480fSBaptiste Daroussin {
309297bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
309397bd480fSBaptiste Daroussin 		return false;
309497bd480fSBaptiste Daroussin 	}
309597bd480fSBaptiste Daroussin 
309697bd480fSBaptiste Daroussin 	switch (obj->type) {
309797bd480fSBaptiste Daroussin 	case UCL_STRING:
309839ee7a7aSBaptiste Daroussin 		if (!(obj->flags & UCL_OBJECT_BINARY)) {
309997bd480fSBaptiste Daroussin 			*target = ucl_copy_value_trash (obj);
310039ee7a7aSBaptiste Daroussin 		}
310197bd480fSBaptiste Daroussin 		break;
310297bd480fSBaptiste Daroussin 	default:
310397bd480fSBaptiste Daroussin 		return false;
310497bd480fSBaptiste Daroussin 	}
310597bd480fSBaptiste Daroussin 
310697bd480fSBaptiste Daroussin 	return true;
310797bd480fSBaptiste Daroussin }
310897bd480fSBaptiste Daroussin 
310997bd480fSBaptiste Daroussin const char *
3110b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj)
311197bd480fSBaptiste Daroussin {
311297bd480fSBaptiste Daroussin 	const char *result = NULL;
311397bd480fSBaptiste Daroussin 
311497bd480fSBaptiste Daroussin 	ucl_object_tostring_safe (obj, &result);
311597bd480fSBaptiste Daroussin 	return result;
311697bd480fSBaptiste Daroussin }
311797bd480fSBaptiste Daroussin 
311897bd480fSBaptiste Daroussin const char *
3119b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj)
312097bd480fSBaptiste Daroussin {
312139ee7a7aSBaptiste Daroussin 	/* TODO: For binary strings we might encode string here */
312239ee7a7aSBaptiste Daroussin 	if (!(obj->flags & UCL_OBJECT_BINARY)) {
312397bd480fSBaptiste Daroussin 		return ucl_copy_value_trash (obj);
312497bd480fSBaptiste Daroussin 	}
312597bd480fSBaptiste Daroussin 
312639ee7a7aSBaptiste Daroussin 	return NULL;
312739ee7a7aSBaptiste Daroussin }
312839ee7a7aSBaptiste Daroussin 
312997bd480fSBaptiste Daroussin bool
3130b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
313197bd480fSBaptiste Daroussin {
313297bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
313397bd480fSBaptiste Daroussin 		return false;
313497bd480fSBaptiste Daroussin 	}
313597bd480fSBaptiste Daroussin 	switch (obj->type) {
313697bd480fSBaptiste Daroussin 	case UCL_STRING:
313797bd480fSBaptiste Daroussin 		*target = obj->value.sv;
313897bd480fSBaptiste Daroussin 		if (tlen != NULL) {
313997bd480fSBaptiste Daroussin 			*tlen = obj->len;
314097bd480fSBaptiste Daroussin 		}
314197bd480fSBaptiste Daroussin 		break;
314297bd480fSBaptiste Daroussin 	default:
314397bd480fSBaptiste Daroussin 		return false;
314497bd480fSBaptiste Daroussin 	}
314597bd480fSBaptiste Daroussin 
314697bd480fSBaptiste Daroussin 	return true;
314797bd480fSBaptiste Daroussin }
314897bd480fSBaptiste Daroussin 
314997bd480fSBaptiste Daroussin const char *
3150b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
315197bd480fSBaptiste Daroussin {
315297bd480fSBaptiste Daroussin 	const char *result = NULL;
315397bd480fSBaptiste Daroussin 
315497bd480fSBaptiste Daroussin 	ucl_object_tolstring_safe (obj, &result, tlen);
315597bd480fSBaptiste Daroussin 	return result;
315697bd480fSBaptiste Daroussin }
315797bd480fSBaptiste Daroussin 
315897bd480fSBaptiste Daroussin const char *
3159b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj)
316097bd480fSBaptiste Daroussin {
316197bd480fSBaptiste Daroussin 	return ucl_copy_key_trash (obj);
316297bd480fSBaptiste Daroussin }
316397bd480fSBaptiste Daroussin 
316497bd480fSBaptiste Daroussin const char *
3165b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len)
316697bd480fSBaptiste Daroussin {
316797bd480fSBaptiste Daroussin 	if (len == NULL || obj == NULL) {
316897bd480fSBaptiste Daroussin 		return NULL;
316997bd480fSBaptiste Daroussin 	}
317097bd480fSBaptiste Daroussin 	*len = obj->keylen;
317197bd480fSBaptiste Daroussin 	return obj->key;
317297bd480fSBaptiste Daroussin }
317397bd480fSBaptiste Daroussin 
317497bd480fSBaptiste Daroussin ucl_object_t *
3175b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj)
317697bd480fSBaptiste Daroussin {
3177b04a7a0bSBaptiste Daroussin 	ucl_object_t *res = NULL;
3178b04a7a0bSBaptiste Daroussin 
317997bd480fSBaptiste Daroussin 	if (obj != NULL) {
31804bf54857SBaptiste Daroussin 		if (obj->flags & UCL_OBJECT_EPHEMERAL) {
31814bf54857SBaptiste Daroussin 			/*
31824bf54857SBaptiste Daroussin 			 * Use deep copy for ephemeral objects, note that its refcount
31834bf54857SBaptiste Daroussin 			 * is NOT increased, since ephemeral objects does not need refcount
31844bf54857SBaptiste Daroussin 			 * at all
31854bf54857SBaptiste Daroussin 			 */
31864bf54857SBaptiste Daroussin 			res = ucl_object_copy (obj);
31874bf54857SBaptiste Daroussin 		}
31884bf54857SBaptiste Daroussin 		else {
3189b04a7a0bSBaptiste Daroussin 			res = __DECONST (ucl_object_t *, obj);
3190b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3191b04a7a0bSBaptiste Daroussin 			(void)__sync_add_and_fetch (&res->ref, 1);
3192b04a7a0bSBaptiste Daroussin #else
3193b04a7a0bSBaptiste Daroussin 			res->ref ++;
3194b04a7a0bSBaptiste Daroussin #endif
319597bd480fSBaptiste Daroussin 		}
31964bf54857SBaptiste Daroussin 	}
3197b04a7a0bSBaptiste Daroussin 	return res;
319897bd480fSBaptiste Daroussin }
319997bd480fSBaptiste Daroussin 
32004bf54857SBaptiste Daroussin static ucl_object_t *
32014bf54857SBaptiste Daroussin ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
32024bf54857SBaptiste Daroussin {
32034bf54857SBaptiste Daroussin 
32044bf54857SBaptiste Daroussin 	ucl_object_t *new;
32054bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
32064bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
32074bf54857SBaptiste Daroussin 
32084bf54857SBaptiste Daroussin 	new = malloc (sizeof (*new));
32094bf54857SBaptiste Daroussin 
32104bf54857SBaptiste Daroussin 	if (new != NULL) {
32114bf54857SBaptiste Daroussin 		memcpy (new, other, sizeof (*new));
32124bf54857SBaptiste Daroussin 		if (other->flags & UCL_OBJECT_EPHEMERAL) {
32134bf54857SBaptiste Daroussin 			/* Copied object is always non ephemeral */
32144bf54857SBaptiste Daroussin 			new->flags &= ~UCL_OBJECT_EPHEMERAL;
32154bf54857SBaptiste Daroussin 		}
32164bf54857SBaptiste Daroussin 		new->ref = 1;
32174bf54857SBaptiste Daroussin 		/* Unlink from others */
32184bf54857SBaptiste Daroussin 		new->next = NULL;
32194bf54857SBaptiste Daroussin 		new->prev = new;
32204bf54857SBaptiste Daroussin 
32214bf54857SBaptiste Daroussin 		/* deep copy of values stored */
32224bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
32234bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_KEY] =
32244bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_KEY]);
32254bf54857SBaptiste Daroussin 			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
32264bf54857SBaptiste Daroussin 				new->key = new->trash_stack[UCL_TRASH_KEY];
32274bf54857SBaptiste Daroussin 			}
32284bf54857SBaptiste Daroussin 		}
32294bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
32304bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_VALUE] =
32314bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_VALUE]);
32324bf54857SBaptiste Daroussin 			if (new->type == UCL_STRING) {
32334bf54857SBaptiste Daroussin 				new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
32344bf54857SBaptiste Daroussin 			}
32354bf54857SBaptiste Daroussin 		}
32364bf54857SBaptiste Daroussin 
32374bf54857SBaptiste Daroussin 		if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
32384bf54857SBaptiste Daroussin 			/* reset old value */
32394bf54857SBaptiste Daroussin 			memset (&new->value, 0, sizeof (new->value));
32404bf54857SBaptiste Daroussin 
3241d9f0ce31SBaptiste Daroussin 			while ((cur = ucl_object_iterate (other, &it, true)) != NULL) {
32424bf54857SBaptiste Daroussin 				if (other->type == UCL_ARRAY) {
32434bf54857SBaptiste Daroussin 					ucl_array_append (new, ucl_object_copy_internal (cur, false));
32444bf54857SBaptiste Daroussin 				}
32454bf54857SBaptiste Daroussin 				else {
32464bf54857SBaptiste Daroussin 					ucl_object_t *cp = ucl_object_copy_internal (cur, true);
32474bf54857SBaptiste Daroussin 					if (cp != NULL) {
32484bf54857SBaptiste Daroussin 						ucl_object_insert_key (new, cp, cp->key, cp->keylen,
32494bf54857SBaptiste Daroussin 								false);
32504bf54857SBaptiste Daroussin 					}
32514bf54857SBaptiste Daroussin 				}
32524bf54857SBaptiste Daroussin 			}
32534bf54857SBaptiste Daroussin 		}
32544bf54857SBaptiste Daroussin 		else if (allow_array && other->next != NULL) {
32554bf54857SBaptiste Daroussin 			LL_FOREACH (other->next, cur) {
32564bf54857SBaptiste Daroussin 				ucl_object_t *cp = ucl_object_copy_internal (cur, false);
32574bf54857SBaptiste Daroussin 				if (cp != NULL) {
32584bf54857SBaptiste Daroussin 					DL_APPEND (new, cp);
32594bf54857SBaptiste Daroussin 				}
32604bf54857SBaptiste Daroussin 			}
32614bf54857SBaptiste Daroussin 		}
32624bf54857SBaptiste Daroussin 	}
32634bf54857SBaptiste Daroussin 
32644bf54857SBaptiste Daroussin 	return new;
32654bf54857SBaptiste Daroussin }
32664bf54857SBaptiste Daroussin 
32674bf54857SBaptiste Daroussin ucl_object_t *
32684bf54857SBaptiste Daroussin ucl_object_copy (const ucl_object_t *other)
32694bf54857SBaptiste Daroussin {
32704bf54857SBaptiste Daroussin 	return ucl_object_copy_internal (other, true);
32714bf54857SBaptiste Daroussin }
32724bf54857SBaptiste Daroussin 
327397bd480fSBaptiste Daroussin void
327497bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj)
327597bd480fSBaptiste Daroussin {
3276b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
3277b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3278b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
3279b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
3280b04a7a0bSBaptiste Daroussin #else
3281b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
3282b04a7a0bSBaptiste Daroussin #endif
3283b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
3284b04a7a0bSBaptiste Daroussin 		}
328597bd480fSBaptiste Daroussin 	}
328697bd480fSBaptiste Daroussin }
328797bd480fSBaptiste Daroussin 
328897bd480fSBaptiste Daroussin int
3289b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
329097bd480fSBaptiste Daroussin {
3291b04a7a0bSBaptiste Daroussin 	const ucl_object_t *it1, *it2;
329297bd480fSBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
329397bd480fSBaptiste Daroussin 	int ret = 0;
329497bd480fSBaptiste Daroussin 
329597bd480fSBaptiste Daroussin 	if (o1->type != o2->type) {
329697bd480fSBaptiste Daroussin 		return (o1->type) - (o2->type);
329797bd480fSBaptiste Daroussin 	}
329897bd480fSBaptiste Daroussin 
329997bd480fSBaptiste Daroussin 	switch (o1->type) {
330097bd480fSBaptiste Daroussin 	case UCL_STRING:
33018e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
330297bd480fSBaptiste Daroussin 			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
330397bd480fSBaptiste Daroussin 		}
330497bd480fSBaptiste Daroussin 		else {
330597bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
330697bd480fSBaptiste Daroussin 		}
330797bd480fSBaptiste Daroussin 		break;
330897bd480fSBaptiste Daroussin 	case UCL_FLOAT:
330997bd480fSBaptiste Daroussin 	case UCL_INT:
331097bd480fSBaptiste Daroussin 	case UCL_TIME:
331197bd480fSBaptiste Daroussin 		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
331297bd480fSBaptiste Daroussin 		break;
331397bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
331497bd480fSBaptiste Daroussin 		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
331597bd480fSBaptiste Daroussin 		break;
331697bd480fSBaptiste Daroussin 	case UCL_ARRAY:
33178e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
33188e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec1, o1);
33198e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec2, o2);
33208e3b1ab2SBaptiste Daroussin 			unsigned i;
33218e3b1ab2SBaptiste Daroussin 
332297bd480fSBaptiste Daroussin 			/* Compare all elements in both arrays */
33238e3b1ab2SBaptiste Daroussin 			for (i = 0; i < vec1->n; i ++) {
33248e3b1ab2SBaptiste Daroussin 				it1 = kv_A (*vec1, i);
33258e3b1ab2SBaptiste Daroussin 				it2 = kv_A (*vec2, i);
33268e3b1ab2SBaptiste Daroussin 
33278e3b1ab2SBaptiste Daroussin 				if (it1 == NULL && it2 != NULL) {
33288e3b1ab2SBaptiste Daroussin 					return -1;
33298e3b1ab2SBaptiste Daroussin 				}
33308e3b1ab2SBaptiste Daroussin 				else if (it2 == NULL && it1 != NULL) {
33318e3b1ab2SBaptiste Daroussin 					return 1;
33328e3b1ab2SBaptiste Daroussin 				}
33338e3b1ab2SBaptiste Daroussin 				else if (it1 != NULL && it2 != NULL) {
333497bd480fSBaptiste Daroussin 					ret = ucl_object_compare (it1, it2);
333597bd480fSBaptiste Daroussin 					if (ret != 0) {
333697bd480fSBaptiste Daroussin 						break;
333797bd480fSBaptiste Daroussin 					}
33388e3b1ab2SBaptiste Daroussin 				}
333997bd480fSBaptiste Daroussin 			}
334097bd480fSBaptiste Daroussin 		}
334197bd480fSBaptiste Daroussin 		else {
334297bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
334397bd480fSBaptiste Daroussin 		}
334497bd480fSBaptiste Daroussin 		break;
334597bd480fSBaptiste Daroussin 	case UCL_OBJECT:
33468e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
3347d9f0ce31SBaptiste Daroussin 			while ((it1 = ucl_object_iterate (o1, &iter, true)) != NULL) {
3348d9f0ce31SBaptiste Daroussin 				it2 = ucl_object_lookup (o2, ucl_object_key (it1));
334997bd480fSBaptiste Daroussin 				if (it2 == NULL) {
335097bd480fSBaptiste Daroussin 					ret = 1;
335197bd480fSBaptiste Daroussin 					break;
335297bd480fSBaptiste Daroussin 				}
335397bd480fSBaptiste Daroussin 				ret = ucl_object_compare (it1, it2);
335497bd480fSBaptiste Daroussin 				if (ret != 0) {
335597bd480fSBaptiste Daroussin 					break;
335697bd480fSBaptiste Daroussin 				}
335797bd480fSBaptiste Daroussin 			}
335897bd480fSBaptiste Daroussin 		}
335997bd480fSBaptiste Daroussin 		else {
336097bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
336197bd480fSBaptiste Daroussin 		}
336297bd480fSBaptiste Daroussin 		break;
336397bd480fSBaptiste Daroussin 	default:
336497bd480fSBaptiste Daroussin 		ret = 0;
336597bd480fSBaptiste Daroussin 		break;
336697bd480fSBaptiste Daroussin 	}
336797bd480fSBaptiste Daroussin 
336897bd480fSBaptiste Daroussin 	return ret;
336997bd480fSBaptiste Daroussin }
337097bd480fSBaptiste Daroussin 
3371d9f0ce31SBaptiste Daroussin int
3372d9f0ce31SBaptiste Daroussin ucl_object_compare_qsort (const ucl_object_t **o1,
3373d9f0ce31SBaptiste Daroussin 		const ucl_object_t **o2)
3374d9f0ce31SBaptiste Daroussin {
3375d9f0ce31SBaptiste Daroussin 	return ucl_object_compare (*o1, *o2);
3376d9f0ce31SBaptiste Daroussin }
3377d9f0ce31SBaptiste Daroussin 
337897bd480fSBaptiste Daroussin void
337997bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar,
338039ee7a7aSBaptiste Daroussin 		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
338197bd480fSBaptiste Daroussin {
33828e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, ar);
33838e3b1ab2SBaptiste Daroussin 
338497bd480fSBaptiste Daroussin 	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
338597bd480fSBaptiste Daroussin 		return;
338697bd480fSBaptiste Daroussin 	}
338797bd480fSBaptiste Daroussin 
33888e3b1ab2SBaptiste Daroussin 	qsort (vec->a, vec->n, sizeof (ucl_object_t *),
33898e3b1ab2SBaptiste Daroussin 			(int (*)(const void *, const void *))cmp);
339097bd480fSBaptiste Daroussin }
33914bf54857SBaptiste Daroussin 
33924bf54857SBaptiste Daroussin #define PRIOBITS 4
33934bf54857SBaptiste Daroussin 
33944bf54857SBaptiste Daroussin unsigned int
33954bf54857SBaptiste Daroussin ucl_object_get_priority (const ucl_object_t *obj)
33964bf54857SBaptiste Daroussin {
33974bf54857SBaptiste Daroussin 	if (obj == NULL) {
33984bf54857SBaptiste Daroussin 		return 0;
33994bf54857SBaptiste Daroussin 	}
34004bf54857SBaptiste Daroussin 
34014bf54857SBaptiste Daroussin 	return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
34024bf54857SBaptiste Daroussin }
34034bf54857SBaptiste Daroussin 
34044bf54857SBaptiste Daroussin void
34054bf54857SBaptiste Daroussin ucl_object_set_priority (ucl_object_t *obj,
34064bf54857SBaptiste Daroussin 		unsigned int priority)
34074bf54857SBaptiste Daroussin {
34084bf54857SBaptiste Daroussin 	if (obj != NULL) {
34094bf54857SBaptiste Daroussin 		priority &= (0x1 << PRIOBITS) - 1;
341039ee7a7aSBaptiste Daroussin 		priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS);
341139ee7a7aSBaptiste Daroussin 		priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) -
341239ee7a7aSBaptiste Daroussin 				PRIOBITS)) - 1);
341339ee7a7aSBaptiste Daroussin 		obj->flags = priority;
34144bf54857SBaptiste Daroussin 	}
34154bf54857SBaptiste Daroussin }
3416d9f0ce31SBaptiste Daroussin 
3417d9f0ce31SBaptiste Daroussin bool
3418d9f0ce31SBaptiste Daroussin ucl_object_string_to_type (const char *input, ucl_type_t *res)
3419d9f0ce31SBaptiste Daroussin {
3420d9f0ce31SBaptiste Daroussin 	if (strcasecmp (input, "object") == 0) {
3421d9f0ce31SBaptiste Daroussin 		*res = UCL_OBJECT;
3422d9f0ce31SBaptiste Daroussin 	}
3423d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "array") == 0) {
3424d9f0ce31SBaptiste Daroussin 		*res = UCL_ARRAY;
3425d9f0ce31SBaptiste Daroussin 	}
3426d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "integer") == 0) {
3427d9f0ce31SBaptiste Daroussin 		*res = UCL_INT;
3428d9f0ce31SBaptiste Daroussin 	}
3429d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "number") == 0) {
3430d9f0ce31SBaptiste Daroussin 		*res = UCL_FLOAT;
3431d9f0ce31SBaptiste Daroussin 	}
3432d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "string") == 0) {
3433d9f0ce31SBaptiste Daroussin 		*res = UCL_STRING;
3434d9f0ce31SBaptiste Daroussin 	}
3435d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "boolean") == 0) {
3436d9f0ce31SBaptiste Daroussin 		*res = UCL_BOOLEAN;
3437d9f0ce31SBaptiste Daroussin 	}
3438d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "null") == 0) {
3439d9f0ce31SBaptiste Daroussin 		*res = UCL_NULL;
3440d9f0ce31SBaptiste Daroussin 	}
3441d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "userdata") == 0) {
3442d9f0ce31SBaptiste Daroussin 		*res = UCL_USERDATA;
3443d9f0ce31SBaptiste Daroussin 	}
3444d9f0ce31SBaptiste Daroussin 	else {
3445d9f0ce31SBaptiste Daroussin 		return false;
3446d9f0ce31SBaptiste Daroussin 	}
3447d9f0ce31SBaptiste Daroussin 
3448d9f0ce31SBaptiste Daroussin 	return true;
3449d9f0ce31SBaptiste Daroussin }
3450d9f0ce31SBaptiste Daroussin 
3451d9f0ce31SBaptiste Daroussin const char *
3452d9f0ce31SBaptiste Daroussin ucl_object_type_to_string (ucl_type_t type)
3453d9f0ce31SBaptiste Daroussin {
3454d9f0ce31SBaptiste Daroussin 	const char *res = "unknown";
3455d9f0ce31SBaptiste Daroussin 
3456d9f0ce31SBaptiste Daroussin 	switch (type) {
3457d9f0ce31SBaptiste Daroussin 	case UCL_OBJECT:
3458d9f0ce31SBaptiste Daroussin 		res = "object";
3459d9f0ce31SBaptiste Daroussin 		break;
3460d9f0ce31SBaptiste Daroussin 	case UCL_ARRAY:
3461d9f0ce31SBaptiste Daroussin 		res = "array";
3462d9f0ce31SBaptiste Daroussin 		break;
3463d9f0ce31SBaptiste Daroussin 	case UCL_INT:
3464d9f0ce31SBaptiste Daroussin 		res = "integer";
3465d9f0ce31SBaptiste Daroussin 		break;
3466d9f0ce31SBaptiste Daroussin 	case UCL_FLOAT:
3467d9f0ce31SBaptiste Daroussin 	case UCL_TIME:
3468d9f0ce31SBaptiste Daroussin 		res = "number";
3469d9f0ce31SBaptiste Daroussin 		break;
3470d9f0ce31SBaptiste Daroussin 	case UCL_STRING:
3471d9f0ce31SBaptiste Daroussin 		res = "string";
3472d9f0ce31SBaptiste Daroussin 		break;
3473d9f0ce31SBaptiste Daroussin 	case UCL_BOOLEAN:
3474d9f0ce31SBaptiste Daroussin 		res = "boolean";
3475d9f0ce31SBaptiste Daroussin 		break;
3476d9f0ce31SBaptiste Daroussin 	case UCL_USERDATA:
3477d9f0ce31SBaptiste Daroussin 		res = "userdata";
3478d9f0ce31SBaptiste Daroussin 		break;
3479d9f0ce31SBaptiste Daroussin 	case UCL_NULL:
3480d9f0ce31SBaptiste Daroussin 		res = "null";
3481d9f0ce31SBaptiste Daroussin 		break;
3482d9f0ce31SBaptiste Daroussin 	}
3483d9f0ce31SBaptiste Daroussin 
3484d9f0ce31SBaptiste Daroussin 	return res;
3485d9f0ce31SBaptiste Daroussin }
3486d9f0ce31SBaptiste Daroussin 
3487d9f0ce31SBaptiste Daroussin const ucl_object_t *
3488d9f0ce31SBaptiste Daroussin ucl_parser_get_comments (struct ucl_parser *parser)
3489d9f0ce31SBaptiste Daroussin {
3490d9f0ce31SBaptiste Daroussin 	if (parser && parser->comments) {
3491d9f0ce31SBaptiste Daroussin 		return parser->comments;
3492d9f0ce31SBaptiste Daroussin 	}
3493d9f0ce31SBaptiste Daroussin 
3494d9f0ce31SBaptiste Daroussin 	return NULL;
3495d9f0ce31SBaptiste Daroussin }
3496d9f0ce31SBaptiste Daroussin 
3497d9f0ce31SBaptiste Daroussin const ucl_object_t *
3498d9f0ce31SBaptiste Daroussin ucl_comments_find (const ucl_object_t *comments,
3499d9f0ce31SBaptiste Daroussin 		const ucl_object_t *srch)
3500d9f0ce31SBaptiste Daroussin {
3501d9f0ce31SBaptiste Daroussin 	if (comments && srch) {
3502d9f0ce31SBaptiste Daroussin 		return ucl_object_lookup_len (comments, (const char *)&srch,
3503d9f0ce31SBaptiste Daroussin 				sizeof (void *));
3504d9f0ce31SBaptiste Daroussin 	}
3505d9f0ce31SBaptiste Daroussin 
3506d9f0ce31SBaptiste Daroussin 	return NULL;
3507d9f0ce31SBaptiste Daroussin }
3508d9f0ce31SBaptiste Daroussin 
3509d9f0ce31SBaptiste Daroussin bool
3510d9f0ce31SBaptiste Daroussin ucl_comments_move (ucl_object_t *comments,
3511d9f0ce31SBaptiste Daroussin 		const ucl_object_t *from, const ucl_object_t *to)
3512d9f0ce31SBaptiste Daroussin {
3513d9f0ce31SBaptiste Daroussin 	const ucl_object_t *found;
3514d9f0ce31SBaptiste Daroussin 	ucl_object_t *obj;
3515d9f0ce31SBaptiste Daroussin 
3516d9f0ce31SBaptiste Daroussin 	if (comments && from && to) {
3517d9f0ce31SBaptiste Daroussin 		found = ucl_object_lookup_len (comments,
3518d9f0ce31SBaptiste Daroussin 				(const char *)&from, sizeof (void *));
3519d9f0ce31SBaptiste Daroussin 
3520d9f0ce31SBaptiste Daroussin 		if (found) {
3521d9f0ce31SBaptiste Daroussin 			/* Replace key */
3522d9f0ce31SBaptiste Daroussin 			obj = ucl_object_ref (found);
3523d9f0ce31SBaptiste Daroussin 			ucl_object_delete_keyl (comments, (const char *)&from,
3524d9f0ce31SBaptiste Daroussin 					sizeof (void *));
3525d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (comments, obj, (const char *)&to,
3526d9f0ce31SBaptiste Daroussin 					sizeof (void *), true);
3527d9f0ce31SBaptiste Daroussin 
3528d9f0ce31SBaptiste Daroussin 			return true;
3529d9f0ce31SBaptiste Daroussin 		}
3530d9f0ce31SBaptiste Daroussin 	}
3531d9f0ce31SBaptiste Daroussin 
3532d9f0ce31SBaptiste Daroussin 	return false;
3533d9f0ce31SBaptiste Daroussin }
3534d9f0ce31SBaptiste Daroussin 
3535d9f0ce31SBaptiste Daroussin void
3536d9f0ce31SBaptiste Daroussin ucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj,
3537d9f0ce31SBaptiste Daroussin 		const char *comment)
3538d9f0ce31SBaptiste Daroussin {
3539d9f0ce31SBaptiste Daroussin 	if (comments && obj && comment) {
3540d9f0ce31SBaptiste Daroussin 		ucl_object_insert_key (comments, ucl_object_fromstring (comment),
3541d9f0ce31SBaptiste Daroussin 				(const char *)&obj, sizeof (void *), true);
3542d9f0ce31SBaptiste Daroussin 	}
3543d9f0ce31SBaptiste Daroussin }
3544