xref: /freebsd/contrib/libucl/src/ucl_util.c (revision 6525738f)
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"
2939ee7a7aSBaptiste Daroussin #include <stdarg.h>
30d9f0ce31SBaptiste Daroussin #include <stdio.h> /* for snprintf */
31c99fb5f9SBaptiste Daroussin 
328e3b1ab2SBaptiste Daroussin #ifndef _WIN32
334bf54857SBaptiste Daroussin #include <glob.h>
348e3b1ab2SBaptiste Daroussin #endif
354bf54857SBaptiste Daroussin 
3697bd480fSBaptiste Daroussin #ifdef HAVE_LIBGEN_H
37c99fb5f9SBaptiste Daroussin #include <libgen.h> /* For dirname */
3897bd480fSBaptiste Daroussin #endif
39c99fb5f9SBaptiste Daroussin 
408e3b1ab2SBaptiste Daroussin typedef kvec_t(ucl_object_t *) ucl_array_t;
418e3b1ab2SBaptiste Daroussin 
428e3b1ab2SBaptiste Daroussin #define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \
438e3b1ab2SBaptiste Daroussin 	(ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL)
448e3b1ab2SBaptiste Daroussin 
45c99fb5f9SBaptiste Daroussin #ifdef HAVE_OPENSSL
46c99fb5f9SBaptiste Daroussin #include <openssl/err.h>
47c99fb5f9SBaptiste Daroussin #include <openssl/sha.h>
48c99fb5f9SBaptiste Daroussin #include <openssl/rsa.h>
49c99fb5f9SBaptiste Daroussin #include <openssl/ssl.h>
50c99fb5f9SBaptiste Daroussin #include <openssl/evp.h>
51c99fb5f9SBaptiste Daroussin #endif
52c99fb5f9SBaptiste Daroussin 
5397bd480fSBaptiste Daroussin #ifdef CURL_FOUND
54d9f0ce31SBaptiste Daroussin /* Seems to be broken */
55d9f0ce31SBaptiste Daroussin #define CURL_DISABLE_TYPECHECK 1
5697bd480fSBaptiste Daroussin #include <curl/curl.h>
5797bd480fSBaptiste Daroussin #endif
5897bd480fSBaptiste Daroussin #ifdef HAVE_FETCH_H
5997bd480fSBaptiste Daroussin #include <fetch.h>
6097bd480fSBaptiste Daroussin #endif
6197bd480fSBaptiste Daroussin 
6236c53d67SBaptiste Daroussin #ifdef _WIN32
6336c53d67SBaptiste Daroussin #include <windows.h>
6436c53d67SBaptiste Daroussin 
6597bd480fSBaptiste Daroussin #ifndef PROT_READ
6636c53d67SBaptiste Daroussin #define PROT_READ       1
6797bd480fSBaptiste Daroussin #endif
6897bd480fSBaptiste Daroussin #ifndef PROT_WRITE
6936c53d67SBaptiste Daroussin #define PROT_WRITE      2
7097bd480fSBaptiste Daroussin #endif
7197bd480fSBaptiste Daroussin #ifndef PROT_READWRITE
7236c53d67SBaptiste Daroussin #define PROT_READWRITE  3
7397bd480fSBaptiste Daroussin #endif
7497bd480fSBaptiste Daroussin #ifndef MAP_SHARED
7536c53d67SBaptiste Daroussin #define MAP_SHARED      1
7697bd480fSBaptiste Daroussin #endif
7797bd480fSBaptiste Daroussin #ifndef MAP_PRIVATE
7836c53d67SBaptiste Daroussin #define MAP_PRIVATE     2
7997bd480fSBaptiste Daroussin #endif
8097bd480fSBaptiste Daroussin #ifndef MAP_FAILED
8136c53d67SBaptiste Daroussin #define MAP_FAILED      ((void *) -1)
8297bd480fSBaptiste Daroussin #endif
8336c53d67SBaptiste Daroussin 
848e3b1ab2SBaptiste Daroussin #ifdef _WIN32
858e3b1ab2SBaptiste Daroussin #include <limits.h>
868e3b1ab2SBaptiste Daroussin #define NBBY CHAR_BIT
878e3b1ab2SBaptiste Daroussin #endif
888e3b1ab2SBaptiste Daroussin 
8997bd480fSBaptiste Daroussin static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
9036c53d67SBaptiste Daroussin {
9136c53d67SBaptiste Daroussin 	void *map = NULL;
9236c53d67SBaptiste Daroussin 	HANDLE handle = INVALID_HANDLE_VALUE;
9336c53d67SBaptiste Daroussin 
9436c53d67SBaptiste Daroussin 	switch (prot) {
9536c53d67SBaptiste Daroussin 	default:
9636c53d67SBaptiste Daroussin 	case PROT_READ:
9736c53d67SBaptiste Daroussin 		{
9836c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
9936c53d67SBaptiste Daroussin 			if (!handle) break;
10036c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
10136c53d67SBaptiste Daroussin 			CloseHandle(handle);
10236c53d67SBaptiste Daroussin 			break;
10336c53d67SBaptiste Daroussin 		}
10436c53d67SBaptiste Daroussin 	case PROT_WRITE:
10536c53d67SBaptiste Daroussin 		{
10636c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
10736c53d67SBaptiste Daroussin 			if (!handle) break;
10836c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
10936c53d67SBaptiste Daroussin 			CloseHandle(handle);
11036c53d67SBaptiste Daroussin 			break;
11136c53d67SBaptiste Daroussin 		}
11236c53d67SBaptiste Daroussin 	case PROT_READWRITE:
11336c53d67SBaptiste Daroussin 		{
11436c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
11536c53d67SBaptiste Daroussin 			if (!handle) break;
11636c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
11736c53d67SBaptiste Daroussin 			CloseHandle(handle);
11836c53d67SBaptiste Daroussin 			break;
11936c53d67SBaptiste Daroussin 		}
12036c53d67SBaptiste Daroussin 	}
12136c53d67SBaptiste Daroussin 	if (map == (void *) NULL) {
12236c53d67SBaptiste Daroussin 		return (void *) MAP_FAILED;
12336c53d67SBaptiste Daroussin 	}
12436c53d67SBaptiste Daroussin 	return (void *) ((char *) map + offset);
12536c53d67SBaptiste Daroussin }
12636c53d67SBaptiste Daroussin 
12797bd480fSBaptiste Daroussin static int ucl_munmap(void *map,size_t length)
12836c53d67SBaptiste Daroussin {
12936c53d67SBaptiste Daroussin 	if (!UnmapViewOfFile(map)) {
13036c53d67SBaptiste Daroussin 		return(-1);
13136c53d67SBaptiste Daroussin 	}
13236c53d67SBaptiste Daroussin 	return(0);
13336c53d67SBaptiste Daroussin }
13436c53d67SBaptiste Daroussin 
13597bd480fSBaptiste Daroussin static char* ucl_realpath(const char *path, char *resolved_path) {
13636c53d67SBaptiste Daroussin     char *p;
13736c53d67SBaptiste Daroussin     char tmp[MAX_PATH + 1];
13836c53d67SBaptiste Daroussin     strncpy(tmp, path, sizeof(tmp)-1);
13936c53d67SBaptiste Daroussin     p = tmp;
14036c53d67SBaptiste Daroussin     while(*p) {
14136c53d67SBaptiste Daroussin         if (*p == '/') *p = '\\';
14236c53d67SBaptiste Daroussin         p++;
14336c53d67SBaptiste Daroussin     }
14436c53d67SBaptiste Daroussin     return _fullpath(resolved_path, tmp, MAX_PATH);
14536c53d67SBaptiste Daroussin }
14697bd480fSBaptiste Daroussin #else
14797bd480fSBaptiste Daroussin #define ucl_mmap mmap
14897bd480fSBaptiste Daroussin #define ucl_munmap munmap
14997bd480fSBaptiste Daroussin #define ucl_realpath realpath
15036c53d67SBaptiste Daroussin #endif
15136c53d67SBaptiste Daroussin 
152b04a7a0bSBaptiste Daroussin typedef void (*ucl_object_dtor) (ucl_object_t *obj);
153b04a7a0bSBaptiste Daroussin static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
154b04a7a0bSBaptiste Daroussin 		ucl_object_dtor dtor);
155b04a7a0bSBaptiste Daroussin static void ucl_object_dtor_unref (ucl_object_t *obj);
156c99fb5f9SBaptiste Daroussin 
157c99fb5f9SBaptiste Daroussin static void
158b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (ucl_object_t *obj)
159c99fb5f9SBaptiste Daroussin {
160c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
161c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
162c99fb5f9SBaptiste Daroussin 	}
163c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
164c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
165c99fb5f9SBaptiste Daroussin 	}
1664bf54857SBaptiste Daroussin 	/* Do not free ephemeral objects */
1674bf54857SBaptiste Daroussin 	if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
1684bf54857SBaptiste Daroussin 		if (obj->type != UCL_USERDATA) {
169b04a7a0bSBaptiste Daroussin 			UCL_FREE (sizeof (ucl_object_t), obj);
170b04a7a0bSBaptiste Daroussin 		}
1714bf54857SBaptiste Daroussin 		else {
1724bf54857SBaptiste Daroussin 			struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
1734bf54857SBaptiste Daroussin 			if (ud->dtor) {
1744bf54857SBaptiste Daroussin 				ud->dtor (obj->value.ud);
1754bf54857SBaptiste Daroussin 			}
1764bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (*ud), obj);
1774bf54857SBaptiste Daroussin 		}
1784bf54857SBaptiste Daroussin 	}
1794bf54857SBaptiste Daroussin }
180c99fb5f9SBaptiste Daroussin 
181b04a7a0bSBaptiste Daroussin /*
182b04a7a0bSBaptiste Daroussin  * This is a helper function that performs exactly the same as
183b04a7a0bSBaptiste Daroussin  * `ucl_object_unref` but it doesn't iterate over elements allowing
184b04a7a0bSBaptiste Daroussin  * to use it for individual elements of arrays and multiple values
185b04a7a0bSBaptiste Daroussin  */
186b04a7a0bSBaptiste Daroussin static void
187b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (ucl_object_t *obj)
188b04a7a0bSBaptiste Daroussin {
189b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
190b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
191b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
192b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
193b04a7a0bSBaptiste Daroussin #else
194b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
195b04a7a0bSBaptiste Daroussin #endif
196b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, false, ucl_object_dtor_unref);
197b04a7a0bSBaptiste Daroussin 		}
198b04a7a0bSBaptiste Daroussin 	}
199b04a7a0bSBaptiste Daroussin }
200b04a7a0bSBaptiste Daroussin 
201b04a7a0bSBaptiste Daroussin static void
202b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref (ucl_object_t *obj)
203b04a7a0bSBaptiste Daroussin {
204b04a7a0bSBaptiste Daroussin 	if (obj->ref == 0) {
205b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_free (obj);
206b04a7a0bSBaptiste Daroussin 	}
207b04a7a0bSBaptiste Daroussin 	else {
208b04a7a0bSBaptiste Daroussin 		/* This may cause dtor unref being called one more time */
209b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_unref_single (obj);
210b04a7a0bSBaptiste Daroussin 	}
211b04a7a0bSBaptiste Daroussin }
212b04a7a0bSBaptiste Daroussin 
213b04a7a0bSBaptiste Daroussin static void
214b04a7a0bSBaptiste Daroussin ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
215b04a7a0bSBaptiste Daroussin {
2168e3b1ab2SBaptiste Daroussin 	ucl_object_t *tmp, *sub;
217b04a7a0bSBaptiste Daroussin 
218b04a7a0bSBaptiste Daroussin 	while (obj != NULL) {
219c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_ARRAY) {
2208e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
2218e3b1ab2SBaptiste Daroussin 			unsigned int i;
2228e3b1ab2SBaptiste Daroussin 
2238e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
2248e3b1ab2SBaptiste Daroussin 				for (i = 0; i < vec->n; i ++) {
2258e3b1ab2SBaptiste Daroussin 					sub = kv_A (*vec, i);
2268e3b1ab2SBaptiste Daroussin 					if (sub != NULL) {
2278e3b1ab2SBaptiste Daroussin 						tmp = sub;
2288e3b1ab2SBaptiste Daroussin 						while (sub) {
229c99fb5f9SBaptiste Daroussin 							tmp = sub->next;
230b04a7a0bSBaptiste Daroussin 							dtor (sub);
231c99fb5f9SBaptiste Daroussin 							sub = tmp;
232c99fb5f9SBaptiste Daroussin 						}
233c99fb5f9SBaptiste Daroussin 					}
2348e3b1ab2SBaptiste Daroussin 				}
2358e3b1ab2SBaptiste Daroussin 				kv_destroy (*vec);
2368e3b1ab2SBaptiste Daroussin 				UCL_FREE (sizeof (*vec), vec);
2378e3b1ab2SBaptiste Daroussin 			}
23839ee7a7aSBaptiste Daroussin 			obj->value.av = NULL;
2398e3b1ab2SBaptiste Daroussin 		}
240c99fb5f9SBaptiste Daroussin 		else if (obj->type == UCL_OBJECT) {
241c99fb5f9SBaptiste Daroussin 			if (obj->value.ov != NULL) {
242d9f0ce31SBaptiste Daroussin 				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor);
243c99fb5f9SBaptiste Daroussin 			}
24439ee7a7aSBaptiste Daroussin 			obj->value.ov = NULL;
245c99fb5f9SBaptiste Daroussin 		}
246c99fb5f9SBaptiste Daroussin 		tmp = obj->next;
247b04a7a0bSBaptiste Daroussin 		dtor (obj);
248c99fb5f9SBaptiste Daroussin 		obj = tmp;
249c99fb5f9SBaptiste Daroussin 
250c99fb5f9SBaptiste Daroussin 		if (!allow_rec) {
251c99fb5f9SBaptiste Daroussin 			break;
252c99fb5f9SBaptiste Daroussin 		}
253c99fb5f9SBaptiste Daroussin 	}
254c99fb5f9SBaptiste Daroussin }
255c99fb5f9SBaptiste Daroussin 
256c99fb5f9SBaptiste Daroussin void
257c99fb5f9SBaptiste Daroussin ucl_object_free (ucl_object_t *obj)
258c99fb5f9SBaptiste Daroussin {
259b04a7a0bSBaptiste Daroussin 	ucl_object_free_internal (obj, true, ucl_object_dtor_free);
260c99fb5f9SBaptiste Daroussin }
261c99fb5f9SBaptiste Daroussin 
262c99fb5f9SBaptiste Daroussin size_t
263c99fb5f9SBaptiste Daroussin ucl_unescape_json_string (char *str, size_t len)
264c99fb5f9SBaptiste Daroussin {
265c99fb5f9SBaptiste Daroussin 	char *t = str, *h = str;
266c99fb5f9SBaptiste Daroussin 	int i, uval;
267c99fb5f9SBaptiste Daroussin 
26897bd480fSBaptiste Daroussin 	if (len <= 1) {
26997bd480fSBaptiste Daroussin 		return len;
27097bd480fSBaptiste Daroussin 	}
271c99fb5f9SBaptiste Daroussin 	/* t is target (tortoise), h is source (hare) */
272c99fb5f9SBaptiste Daroussin 
273c99fb5f9SBaptiste Daroussin 	while (len) {
274c99fb5f9SBaptiste Daroussin 		if (*h == '\\') {
275c99fb5f9SBaptiste Daroussin 			h ++;
27639ee7a7aSBaptiste Daroussin 
27739ee7a7aSBaptiste Daroussin 			if (len == 1) {
27839ee7a7aSBaptiste Daroussin 				/*
27939ee7a7aSBaptiste Daroussin 				 * If \ is last, then do not try to go further
28039ee7a7aSBaptiste Daroussin 				 * Issue: #74
28139ee7a7aSBaptiste Daroussin 				 */
28239ee7a7aSBaptiste Daroussin 				len --;
28339ee7a7aSBaptiste Daroussin 				*t++ = '\\';
28439ee7a7aSBaptiste Daroussin 				continue;
28539ee7a7aSBaptiste Daroussin 			}
28639ee7a7aSBaptiste Daroussin 
287c99fb5f9SBaptiste Daroussin 			switch (*h) {
288c99fb5f9SBaptiste Daroussin 			case 'n':
289c99fb5f9SBaptiste Daroussin 				*t++ = '\n';
290c99fb5f9SBaptiste Daroussin 				break;
291c99fb5f9SBaptiste Daroussin 			case 'r':
292c99fb5f9SBaptiste Daroussin 				*t++ = '\r';
293c99fb5f9SBaptiste Daroussin 				break;
294c99fb5f9SBaptiste Daroussin 			case 'b':
295c99fb5f9SBaptiste Daroussin 				*t++ = '\b';
296c99fb5f9SBaptiste Daroussin 				break;
297c99fb5f9SBaptiste Daroussin 			case 't':
298c99fb5f9SBaptiste Daroussin 				*t++ = '\t';
299c99fb5f9SBaptiste Daroussin 				break;
300c99fb5f9SBaptiste Daroussin 			case 'f':
301c99fb5f9SBaptiste Daroussin 				*t++ = '\f';
302c99fb5f9SBaptiste Daroussin 				break;
303c99fb5f9SBaptiste Daroussin 			case '\\':
304c99fb5f9SBaptiste Daroussin 				*t++ = '\\';
305c99fb5f9SBaptiste Daroussin 				break;
306c99fb5f9SBaptiste Daroussin 			case '"':
307c99fb5f9SBaptiste Daroussin 				*t++ = '"';
308c99fb5f9SBaptiste Daroussin 				break;
309c99fb5f9SBaptiste Daroussin 			case 'u':
310c99fb5f9SBaptiste Daroussin 				/* Unicode escape */
311c99fb5f9SBaptiste Daroussin 				uval = 0;
312d9f0ce31SBaptiste Daroussin 				h ++; /* u character */
313d9f0ce31SBaptiste Daroussin 				len --;
314d9f0ce31SBaptiste Daroussin 
31597bd480fSBaptiste Daroussin 				if (len > 3) {
316c99fb5f9SBaptiste Daroussin 					for (i = 0; i < 4; i++) {
317c99fb5f9SBaptiste Daroussin 						uval <<= 4;
318c99fb5f9SBaptiste Daroussin 						if (isdigit (h[i])) {
319c99fb5f9SBaptiste Daroussin 							uval += h[i] - '0';
320c99fb5f9SBaptiste Daroussin 						}
321c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'a' && h[i] <= 'f') {
322c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'a' + 10;
323c99fb5f9SBaptiste Daroussin 						}
324c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'A' && h[i] <= 'F') {
325c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'A' + 10;
326c99fb5f9SBaptiste Daroussin 						}
32797bd480fSBaptiste Daroussin 						else {
32897bd480fSBaptiste Daroussin 							break;
32997bd480fSBaptiste Daroussin 						}
330c99fb5f9SBaptiste Daroussin 					}
331d9f0ce31SBaptiste Daroussin 
332c99fb5f9SBaptiste Daroussin 					/* Encode */
333c99fb5f9SBaptiste Daroussin 					if(uval < 0x80) {
334c99fb5f9SBaptiste Daroussin 						t[0] = (char)uval;
335c99fb5f9SBaptiste Daroussin 						t ++;
336c99fb5f9SBaptiste Daroussin 					}
337c99fb5f9SBaptiste Daroussin 					else if(uval < 0x800) {
338c99fb5f9SBaptiste Daroussin 						t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
339c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F));
340c99fb5f9SBaptiste Daroussin 						t += 2;
341c99fb5f9SBaptiste Daroussin 					}
342c99fb5f9SBaptiste Daroussin 					else if(uval < 0x10000) {
343c99fb5f9SBaptiste Daroussin 						t[0] = 0xE0 + ((uval & 0xF000) >> 12);
344c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
345c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x003F));
346c99fb5f9SBaptiste Daroussin 						t += 3;
347c99fb5f9SBaptiste Daroussin 					}
348d9f0ce31SBaptiste Daroussin #if 0
349d9f0ce31SBaptiste Daroussin 					/* It's not actually supported now */
350c99fb5f9SBaptiste Daroussin 					else if(uval <= 0x10FFFF) {
351c99fb5f9SBaptiste Daroussin 						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
352c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
353c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
354c99fb5f9SBaptiste Daroussin 						t[3] = 0x80 + ((uval & 0x00003F));
355c99fb5f9SBaptiste Daroussin 						t += 4;
356c99fb5f9SBaptiste Daroussin 					}
357d9f0ce31SBaptiste Daroussin #endif
358c99fb5f9SBaptiste Daroussin 					else {
359c99fb5f9SBaptiste Daroussin 						*t++ = '?';
360c99fb5f9SBaptiste Daroussin 					}
361d9f0ce31SBaptiste Daroussin 
362d9f0ce31SBaptiste Daroussin 					/* Consume 4 characters of source */
363d9f0ce31SBaptiste Daroussin 					h += 4;
364d9f0ce31SBaptiste Daroussin 					len -= 4;
365d9f0ce31SBaptiste Daroussin 
366d9f0ce31SBaptiste Daroussin 					if (len > 0) {
367d9f0ce31SBaptiste Daroussin 						len --; /* for '\' character */
368d9f0ce31SBaptiste Daroussin 					}
369d9f0ce31SBaptiste Daroussin 					continue;
37097bd480fSBaptiste Daroussin 				}
37197bd480fSBaptiste Daroussin 				else {
37297bd480fSBaptiste Daroussin 					*t++ = 'u';
37397bd480fSBaptiste Daroussin 				}
374c99fb5f9SBaptiste Daroussin 				break;
375c99fb5f9SBaptiste Daroussin 			default:
376c99fb5f9SBaptiste Daroussin 				*t++ = *h;
377c99fb5f9SBaptiste Daroussin 				break;
378c99fb5f9SBaptiste Daroussin 			}
379c99fb5f9SBaptiste Daroussin 			h ++;
380c99fb5f9SBaptiste Daroussin 			len --;
381c99fb5f9SBaptiste Daroussin 		}
382c99fb5f9SBaptiste Daroussin 		else {
383c99fb5f9SBaptiste Daroussin 			*t++ = *h++;
384c99fb5f9SBaptiste Daroussin 		}
38539ee7a7aSBaptiste Daroussin 
38639ee7a7aSBaptiste Daroussin 		if (len > 0) {
387c99fb5f9SBaptiste Daroussin 			len --;
388c99fb5f9SBaptiste Daroussin 		}
38939ee7a7aSBaptiste Daroussin 	}
390c99fb5f9SBaptiste Daroussin 	*t = '\0';
391c99fb5f9SBaptiste Daroussin 
392c99fb5f9SBaptiste Daroussin 	return (t - str);
393c99fb5f9SBaptiste Daroussin }
394c99fb5f9SBaptiste Daroussin 
395b04a7a0bSBaptiste Daroussin char *
396b04a7a0bSBaptiste Daroussin ucl_copy_key_trash (const ucl_object_t *obj)
397c99fb5f9SBaptiste Daroussin {
398b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
399b04a7a0bSBaptiste Daroussin 
40097bd480fSBaptiste Daroussin 	if (obj == NULL) {
40197bd480fSBaptiste Daroussin 		return NULL;
40297bd480fSBaptiste Daroussin 	}
403c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
404b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
405b04a7a0bSBaptiste Daroussin 		deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
406b04a7a0bSBaptiste Daroussin 		if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
407b04a7a0bSBaptiste Daroussin 			memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
408b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
409c99fb5f9SBaptiste Daroussin 		}
410b04a7a0bSBaptiste Daroussin 		deconst->key = obj->trash_stack[UCL_TRASH_KEY];
411b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
412c99fb5f9SBaptiste Daroussin 	}
413c99fb5f9SBaptiste Daroussin 
414c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_KEY];
415c99fb5f9SBaptiste Daroussin }
416c99fb5f9SBaptiste Daroussin 
417b04a7a0bSBaptiste Daroussin char *
418b04a7a0bSBaptiste Daroussin ucl_copy_value_trash (const ucl_object_t *obj)
419c99fb5f9SBaptiste Daroussin {
420b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
421b04a7a0bSBaptiste Daroussin 
42297bd480fSBaptiste Daroussin 	if (obj == NULL) {
42397bd480fSBaptiste Daroussin 		return NULL;
42497bd480fSBaptiste Daroussin 	}
425c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
426b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
427c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_STRING) {
428b04a7a0bSBaptiste Daroussin 
429c99fb5f9SBaptiste Daroussin 			/* Special case for strings */
43039ee7a7aSBaptiste Daroussin 			if (obj->flags & UCL_OBJECT_BINARY) {
43139ee7a7aSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len);
43239ee7a7aSBaptiste Daroussin 				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
43339ee7a7aSBaptiste Daroussin 					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
43439ee7a7aSBaptiste Daroussin 							obj->value.sv,
43539ee7a7aSBaptiste Daroussin 							obj->len);
43639ee7a7aSBaptiste Daroussin 					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
43739ee7a7aSBaptiste Daroussin 				}
43839ee7a7aSBaptiste Daroussin 			}
43939ee7a7aSBaptiste Daroussin 			else {
440b04a7a0bSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
441b04a7a0bSBaptiste Daroussin 				if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
44239ee7a7aSBaptiste Daroussin 					memcpy (deconst->trash_stack[UCL_TRASH_VALUE],
44339ee7a7aSBaptiste Daroussin 							obj->value.sv,
44439ee7a7aSBaptiste Daroussin 							obj->len);
445b04a7a0bSBaptiste Daroussin 					deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
446b04a7a0bSBaptiste Daroussin 					deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
447c99fb5f9SBaptiste Daroussin 				}
448c99fb5f9SBaptiste Daroussin 			}
44939ee7a7aSBaptiste Daroussin 		}
450c99fb5f9SBaptiste Daroussin 		else {
451c99fb5f9SBaptiste Daroussin 			/* Just emit value in json notation */
452b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
453b04a7a0bSBaptiste Daroussin 			deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
454c99fb5f9SBaptiste Daroussin 		}
455b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
456c99fb5f9SBaptiste Daroussin 	}
45739ee7a7aSBaptiste Daroussin 
458c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_VALUE];
459c99fb5f9SBaptiste Daroussin }
460c99fb5f9SBaptiste Daroussin 
46139ee7a7aSBaptiste Daroussin ucl_object_t*
462c99fb5f9SBaptiste Daroussin ucl_parser_get_object (struct ucl_parser *parser)
463c99fb5f9SBaptiste Daroussin {
464c99fb5f9SBaptiste Daroussin 	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
465c99fb5f9SBaptiste Daroussin 		return ucl_object_ref (parser->top_obj);
466c99fb5f9SBaptiste Daroussin 	}
467c99fb5f9SBaptiste Daroussin 
468c99fb5f9SBaptiste Daroussin 	return NULL;
469c99fb5f9SBaptiste Daroussin }
470c99fb5f9SBaptiste Daroussin 
47139ee7a7aSBaptiste Daroussin void
472c99fb5f9SBaptiste Daroussin ucl_parser_free (struct ucl_parser *parser)
473c99fb5f9SBaptiste Daroussin {
474c99fb5f9SBaptiste Daroussin 	struct ucl_stack *stack, *stmp;
475c99fb5f9SBaptiste Daroussin 	struct ucl_macro *macro, *mtmp;
476c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk, *ctmp;
477c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key, *ktmp;
478c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var, *vtmp;
47939ee7a7aSBaptiste Daroussin 	ucl_object_t *tr, *trtmp;
480c99fb5f9SBaptiste Daroussin 
48197bd480fSBaptiste Daroussin 	if (parser == NULL) {
48297bd480fSBaptiste Daroussin 		return;
48397bd480fSBaptiste Daroussin 	}
48497bd480fSBaptiste Daroussin 
485c99fb5f9SBaptiste Daroussin 	if (parser->top_obj != NULL) {
486c99fb5f9SBaptiste Daroussin 		ucl_object_unref (parser->top_obj);
487c99fb5f9SBaptiste Daroussin 	}
488c99fb5f9SBaptiste Daroussin 
48939ee7a7aSBaptiste Daroussin 	if (parser->includepaths != NULL) {
49039ee7a7aSBaptiste Daroussin 		ucl_object_unref (parser->includepaths);
49139ee7a7aSBaptiste Daroussin 	}
49239ee7a7aSBaptiste Daroussin 
493c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
494c99fb5f9SBaptiste Daroussin 		free (stack);
495c99fb5f9SBaptiste Daroussin 	}
496c99fb5f9SBaptiste Daroussin 	HASH_ITER (hh, parser->macroes, macro, mtmp) {
497c99fb5f9SBaptiste Daroussin 		free (macro->name);
498c99fb5f9SBaptiste Daroussin 		HASH_DEL (parser->macroes, macro);
499c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_macro), macro);
500c99fb5f9SBaptiste Daroussin 	}
501c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
502c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_chunk), chunk);
503c99fb5f9SBaptiste Daroussin 	}
504c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
505c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), key);
506c99fb5f9SBaptiste Daroussin 	}
507c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
508c99fb5f9SBaptiste Daroussin 		free (var->value);
509c99fb5f9SBaptiste Daroussin 		free (var->var);
510c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_variable), var);
511c99fb5f9SBaptiste Daroussin 	}
51239ee7a7aSBaptiste Daroussin 	LL_FOREACH_SAFE (parser->trash_objs, tr, trtmp) {
51339ee7a7aSBaptiste Daroussin 		ucl_object_free_internal (tr, false, ucl_object_dtor_free);
51439ee7a7aSBaptiste Daroussin 	}
515c99fb5f9SBaptiste Daroussin 
516c99fb5f9SBaptiste Daroussin 	if (parser->err != NULL) {
517c99fb5f9SBaptiste Daroussin 		utstring_free (parser->err);
518c99fb5f9SBaptiste Daroussin 	}
519c99fb5f9SBaptiste Daroussin 
5204bf54857SBaptiste Daroussin 	if (parser->cur_file) {
5214bf54857SBaptiste Daroussin 		free (parser->cur_file);
5224bf54857SBaptiste Daroussin 	}
5234bf54857SBaptiste Daroussin 
524d9f0ce31SBaptiste Daroussin 	if (parser->comments) {
525d9f0ce31SBaptiste Daroussin 		ucl_object_unref (parser->comments);
526d9f0ce31SBaptiste Daroussin 	}
527d9f0ce31SBaptiste Daroussin 
528c99fb5f9SBaptiste Daroussin 	UCL_FREE (sizeof (struct ucl_parser), parser);
529c99fb5f9SBaptiste Daroussin }
530c99fb5f9SBaptiste Daroussin 
53139ee7a7aSBaptiste Daroussin const char *
532c99fb5f9SBaptiste Daroussin ucl_parser_get_error(struct ucl_parser *parser)
533c99fb5f9SBaptiste Daroussin {
53497bd480fSBaptiste Daroussin 	if (parser == NULL) {
53597bd480fSBaptiste Daroussin 		return NULL;
53697bd480fSBaptiste Daroussin 	}
53797bd480fSBaptiste Daroussin 
53839ee7a7aSBaptiste Daroussin 	if (parser->err == NULL) {
539c99fb5f9SBaptiste Daroussin 		return NULL;
54039ee7a7aSBaptiste Daroussin 	}
541c99fb5f9SBaptiste Daroussin 
542c99fb5f9SBaptiste Daroussin 	return utstring_body (parser->err);
543c99fb5f9SBaptiste Daroussin }
544c99fb5f9SBaptiste Daroussin 
54539ee7a7aSBaptiste Daroussin int
54639ee7a7aSBaptiste Daroussin ucl_parser_get_error_code(struct ucl_parser *parser)
54739ee7a7aSBaptiste Daroussin {
54839ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
54939ee7a7aSBaptiste Daroussin 		return 0;
55039ee7a7aSBaptiste Daroussin 	}
55139ee7a7aSBaptiste Daroussin 
55239ee7a7aSBaptiste Daroussin 	return parser->err_code;
55339ee7a7aSBaptiste Daroussin }
55439ee7a7aSBaptiste Daroussin 
55539ee7a7aSBaptiste Daroussin unsigned
55639ee7a7aSBaptiste Daroussin ucl_parser_get_column(struct ucl_parser *parser)
55739ee7a7aSBaptiste Daroussin {
55839ee7a7aSBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL) {
55939ee7a7aSBaptiste Daroussin 		return 0;
56039ee7a7aSBaptiste Daroussin 	}
56139ee7a7aSBaptiste Daroussin 
56239ee7a7aSBaptiste Daroussin 	return parser->chunks->column;
56339ee7a7aSBaptiste Daroussin }
56439ee7a7aSBaptiste Daroussin 
56539ee7a7aSBaptiste Daroussin unsigned
56639ee7a7aSBaptiste Daroussin ucl_parser_get_linenum(struct ucl_parser *parser)
56739ee7a7aSBaptiste Daroussin {
56839ee7a7aSBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL) {
56939ee7a7aSBaptiste Daroussin 		return 0;
57039ee7a7aSBaptiste Daroussin 	}
57139ee7a7aSBaptiste Daroussin 
57239ee7a7aSBaptiste Daroussin 	return parser->chunks->line;
57339ee7a7aSBaptiste Daroussin }
57439ee7a7aSBaptiste Daroussin 
57539ee7a7aSBaptiste Daroussin void
5768e3b1ab2SBaptiste Daroussin ucl_parser_clear_error(struct ucl_parser *parser)
5778e3b1ab2SBaptiste Daroussin {
5788e3b1ab2SBaptiste Daroussin 	if (parser != NULL && parser->err != NULL) {
5798e3b1ab2SBaptiste Daroussin 		utstring_free(parser->err);
5808e3b1ab2SBaptiste Daroussin 		parser->err = NULL;
58139ee7a7aSBaptiste Daroussin 		parser->err_code = 0;
5828e3b1ab2SBaptiste Daroussin 	}
5838e3b1ab2SBaptiste Daroussin }
5848e3b1ab2SBaptiste Daroussin 
58539ee7a7aSBaptiste Daroussin bool
586c99fb5f9SBaptiste Daroussin ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
587c99fb5f9SBaptiste Daroussin {
588c99fb5f9SBaptiste Daroussin #ifndef HAVE_OPENSSL
589c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures without openssl");
590c99fb5f9SBaptiste Daroussin 	return false;
591c99fb5f9SBaptiste Daroussin #else
592c99fb5f9SBaptiste Daroussin # if (OPENSSL_VERSION_NUMBER < 0x10000000L)
593c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
594c99fb5f9SBaptiste Daroussin 	return EXIT_FAILURE;
595c99fb5f9SBaptiste Daroussin # else
596c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *nkey;
597c99fb5f9SBaptiste Daroussin 	BIO *mem;
598c99fb5f9SBaptiste Daroussin 
599c99fb5f9SBaptiste Daroussin 	mem = BIO_new_mem_buf ((void *)key, len);
600c99fb5f9SBaptiste Daroussin 	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
60197bd480fSBaptiste Daroussin 	if (nkey == NULL) {
60297bd480fSBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot allocate memory for key");
60397bd480fSBaptiste Daroussin 		return false;
60497bd480fSBaptiste Daroussin 	}
605c99fb5f9SBaptiste Daroussin 	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
606c99fb5f9SBaptiste Daroussin 	BIO_free (mem);
607c99fb5f9SBaptiste Daroussin 	if (nkey->key == NULL) {
608c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
609c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "%s",
610c99fb5f9SBaptiste Daroussin 				ERR_error_string (ERR_get_error (), NULL));
611c99fb5f9SBaptiste Daroussin 		return false;
612c99fb5f9SBaptiste Daroussin 	}
613c99fb5f9SBaptiste Daroussin 	LL_PREPEND (parser->keys, nkey);
614c99fb5f9SBaptiste Daroussin # endif
615c99fb5f9SBaptiste Daroussin #endif
616c99fb5f9SBaptiste Daroussin 	return true;
617c99fb5f9SBaptiste Daroussin }
618c99fb5f9SBaptiste Daroussin 
619c99fb5f9SBaptiste Daroussin #ifdef CURL_FOUND
620c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata {
621c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
622c99fb5f9SBaptiste Daroussin 	size_t buflen;
623c99fb5f9SBaptiste Daroussin };
624c99fb5f9SBaptiste Daroussin 
625c99fb5f9SBaptiste Daroussin static size_t
626c99fb5f9SBaptiste Daroussin ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
627c99fb5f9SBaptiste Daroussin {
628c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata *cbdata = ud;
629c99fb5f9SBaptiste Daroussin 	size_t realsize = size * nmemb;
630c99fb5f9SBaptiste Daroussin 
631c99fb5f9SBaptiste Daroussin 	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
632c99fb5f9SBaptiste Daroussin 	if (cbdata->buf == NULL) {
633c99fb5f9SBaptiste Daroussin 		return 0;
634c99fb5f9SBaptiste Daroussin 	}
635c99fb5f9SBaptiste Daroussin 
636c99fb5f9SBaptiste Daroussin 	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
637c99fb5f9SBaptiste Daroussin 	cbdata->buflen += realsize;
638c99fb5f9SBaptiste Daroussin 	cbdata->buf[cbdata->buflen] = 0;
639c99fb5f9SBaptiste Daroussin 
640c99fb5f9SBaptiste Daroussin 	return realsize;
641c99fb5f9SBaptiste Daroussin }
642c99fb5f9SBaptiste Daroussin #endif
643c99fb5f9SBaptiste Daroussin 
644c99fb5f9SBaptiste Daroussin /**
645c99fb5f9SBaptiste Daroussin  * Fetch a url and save results to the memory buffer
646c99fb5f9SBaptiste Daroussin  * @param url url to fetch
647c99fb5f9SBaptiste Daroussin  * @param len length of url
648c99fb5f9SBaptiste Daroussin  * @param buf target buffer
649c99fb5f9SBaptiste Daroussin  * @param buflen target length
650c99fb5f9SBaptiste Daroussin  * @return
651c99fb5f9SBaptiste Daroussin  */
652d9f0ce31SBaptiste Daroussin bool
653c99fb5f9SBaptiste Daroussin ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
654c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
655c99fb5f9SBaptiste Daroussin {
656c99fb5f9SBaptiste Daroussin 
657c99fb5f9SBaptiste Daroussin #ifdef HAVE_FETCH_H
658c99fb5f9SBaptiste Daroussin 	struct url *fetch_url;
659c99fb5f9SBaptiste Daroussin 	struct url_stat us;
660c99fb5f9SBaptiste Daroussin 	FILE *in;
661c99fb5f9SBaptiste Daroussin 
662c99fb5f9SBaptiste Daroussin 	fetch_url = fetchParseURL (url);
663c99fb5f9SBaptiste Daroussin 	if (fetch_url == NULL) {
664c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
665c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
666c99fb5f9SBaptiste Daroussin 		return false;
667c99fb5f9SBaptiste Daroussin 	}
668c99fb5f9SBaptiste Daroussin 	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
669c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
670c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot fetch URL %s: %s",
671c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
672c99fb5f9SBaptiste Daroussin 		}
673c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
674c99fb5f9SBaptiste Daroussin 		return false;
675c99fb5f9SBaptiste Daroussin 	}
676c99fb5f9SBaptiste Daroussin 
677c99fb5f9SBaptiste Daroussin 	*buflen = us.size;
678c99fb5f9SBaptiste Daroussin 	*buf = malloc (*buflen);
679c99fb5f9SBaptiste Daroussin 	if (*buf == NULL) {
680c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
681c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
682c99fb5f9SBaptiste Daroussin 		fclose (in);
683c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
684c99fb5f9SBaptiste Daroussin 		return false;
685c99fb5f9SBaptiste Daroussin 	}
686c99fb5f9SBaptiste Daroussin 
687c99fb5f9SBaptiste Daroussin 	if (fread (*buf, *buflen, 1, in) != 1) {
688c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot read URL %s: %s",
689c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
690c99fb5f9SBaptiste Daroussin 		fclose (in);
691c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
692c99fb5f9SBaptiste Daroussin 		return false;
693c99fb5f9SBaptiste Daroussin 	}
694c99fb5f9SBaptiste Daroussin 
695c99fb5f9SBaptiste Daroussin 	fetchFreeURL (fetch_url);
696c99fb5f9SBaptiste Daroussin 	return true;
697c99fb5f9SBaptiste Daroussin #elif defined(CURL_FOUND)
698c99fb5f9SBaptiste Daroussin 	CURL *curl;
699c99fb5f9SBaptiste Daroussin 	int r;
700c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata cbdata;
701c99fb5f9SBaptiste Daroussin 
702c99fb5f9SBaptiste Daroussin 	curl = curl_easy_init ();
703c99fb5f9SBaptiste Daroussin 	if (curl == NULL) {
704c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "CURL interface is broken");
705c99fb5f9SBaptiste Daroussin 		return false;
706c99fb5f9SBaptiste Daroussin 	}
707c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
708c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
709c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
710c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
711c99fb5f9SBaptiste Daroussin 		return false;
712c99fb5f9SBaptiste Daroussin 	}
713c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
714d9f0ce31SBaptiste Daroussin 	cbdata.buf = NULL;
715d9f0ce31SBaptiste Daroussin 	cbdata.buflen = 0;
716c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
717c99fb5f9SBaptiste Daroussin 
718c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
719c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
720c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "error fetching URL %s: %s",
721c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
722c99fb5f9SBaptiste Daroussin 		}
723c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
724c99fb5f9SBaptiste Daroussin 		if (cbdata.buf) {
725c99fb5f9SBaptiste Daroussin 			free (cbdata.buf);
726c99fb5f9SBaptiste Daroussin 		}
727c99fb5f9SBaptiste Daroussin 		return false;
728c99fb5f9SBaptiste Daroussin 	}
729c99fb5f9SBaptiste Daroussin 	*buf = cbdata.buf;
730c99fb5f9SBaptiste Daroussin 	*buflen = cbdata.buflen;
731c99fb5f9SBaptiste Daroussin 
732c99fb5f9SBaptiste Daroussin 	return true;
733c99fb5f9SBaptiste Daroussin #else
734c99fb5f9SBaptiste Daroussin 	ucl_create_err (err, "URL support is disabled");
735c99fb5f9SBaptiste Daroussin 	return false;
736c99fb5f9SBaptiste Daroussin #endif
737c99fb5f9SBaptiste Daroussin }
738c99fb5f9SBaptiste Daroussin 
739c99fb5f9SBaptiste Daroussin /**
740c99fb5f9SBaptiste Daroussin  * Fetch a file and save results to the memory buffer
741c99fb5f9SBaptiste Daroussin  * @param filename filename to fetch
742c99fb5f9SBaptiste Daroussin  * @param len length of filename
743c99fb5f9SBaptiste Daroussin  * @param buf target buffer
744c99fb5f9SBaptiste Daroussin  * @param buflen target length
745c99fb5f9SBaptiste Daroussin  * @return
746c99fb5f9SBaptiste Daroussin  */
747d9f0ce31SBaptiste Daroussin bool
748c99fb5f9SBaptiste Daroussin ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
749c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
750c99fb5f9SBaptiste Daroussin {
751c99fb5f9SBaptiste Daroussin 	int fd;
752c99fb5f9SBaptiste Daroussin 	struct stat st;
753c99fb5f9SBaptiste Daroussin 
754c99fb5f9SBaptiste Daroussin 	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
755c99fb5f9SBaptiste Daroussin 		if (must_exist) {
756c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot stat file %s: %s",
757c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
758c99fb5f9SBaptiste Daroussin 		}
759c99fb5f9SBaptiste Daroussin 		return false;
760c99fb5f9SBaptiste Daroussin 	}
761c99fb5f9SBaptiste Daroussin 	if (st.st_size == 0) {
762c99fb5f9SBaptiste Daroussin 		/* Do not map empty files */
763d9f0ce31SBaptiste Daroussin 		*buf = NULL;
764c99fb5f9SBaptiste Daroussin 		*buflen = 0;
765c99fb5f9SBaptiste Daroussin 	}
766c99fb5f9SBaptiste Daroussin 	else {
767c99fb5f9SBaptiste Daroussin 		if ((fd = open (filename, O_RDONLY)) == -1) {
768c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot open file %s: %s",
769c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
770c99fb5f9SBaptiste Daroussin 			return false;
771c99fb5f9SBaptiste Daroussin 		}
77297bd480fSBaptiste Daroussin 		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
773c99fb5f9SBaptiste Daroussin 			close (fd);
774c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot mmap file %s: %s",
775c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
776d9f0ce31SBaptiste Daroussin 			*buf = NULL;
777d9f0ce31SBaptiste Daroussin 
778c99fb5f9SBaptiste Daroussin 			return false;
779c99fb5f9SBaptiste Daroussin 		}
780c99fb5f9SBaptiste Daroussin 		*buflen = st.st_size;
781c99fb5f9SBaptiste Daroussin 		close (fd);
782c99fb5f9SBaptiste Daroussin 	}
783c99fb5f9SBaptiste Daroussin 
784c99fb5f9SBaptiste Daroussin 	return true;
785c99fb5f9SBaptiste Daroussin }
786c99fb5f9SBaptiste Daroussin 
787c99fb5f9SBaptiste Daroussin 
788c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
789c99fb5f9SBaptiste Daroussin static inline bool
790c99fb5f9SBaptiste Daroussin ucl_sig_check (const unsigned char *data, size_t datalen,
791c99fb5f9SBaptiste Daroussin 		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
792c99fb5f9SBaptiste Daroussin {
793c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key;
794c99fb5f9SBaptiste Daroussin 	char dig[EVP_MAX_MD_SIZE];
795c99fb5f9SBaptiste Daroussin 	unsigned int diglen;
796c99fb5f9SBaptiste Daroussin 	EVP_PKEY_CTX *key_ctx;
797c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX *sign_ctx = NULL;
798c99fb5f9SBaptiste Daroussin 
799c99fb5f9SBaptiste Daroussin 	sign_ctx = EVP_MD_CTX_create ();
800c99fb5f9SBaptiste Daroussin 
801c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->keys, key) {
802c99fb5f9SBaptiste Daroussin 		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
803c99fb5f9SBaptiste Daroussin 		if (key_ctx != NULL) {
804c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
805c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
806c99fb5f9SBaptiste Daroussin 				continue;
807c99fb5f9SBaptiste Daroussin 			}
808c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
809c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
810c99fb5f9SBaptiste Daroussin 				continue;
811c99fb5f9SBaptiste Daroussin 			}
812c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
813c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
814c99fb5f9SBaptiste Daroussin 				continue;
815c99fb5f9SBaptiste Daroussin 			}
816c99fb5f9SBaptiste Daroussin 			EVP_DigestInit (sign_ctx, EVP_sha256 ());
817c99fb5f9SBaptiste Daroussin 			EVP_DigestUpdate (sign_ctx, data, datalen);
818c99fb5f9SBaptiste Daroussin 			EVP_DigestFinal (sign_ctx, dig, &diglen);
819c99fb5f9SBaptiste Daroussin 
820c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
821c99fb5f9SBaptiste Daroussin 				EVP_MD_CTX_destroy (sign_ctx);
822c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
823c99fb5f9SBaptiste Daroussin 				return true;
824c99fb5f9SBaptiste Daroussin 			}
825c99fb5f9SBaptiste Daroussin 
826c99fb5f9SBaptiste Daroussin 			EVP_PKEY_CTX_free (key_ctx);
827c99fb5f9SBaptiste Daroussin 		}
828c99fb5f9SBaptiste Daroussin 	}
829c99fb5f9SBaptiste Daroussin 
830c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX_destroy (sign_ctx);
831c99fb5f9SBaptiste Daroussin 
832c99fb5f9SBaptiste Daroussin 	return false;
833c99fb5f9SBaptiste Daroussin }
834c99fb5f9SBaptiste Daroussin #endif
835c99fb5f9SBaptiste Daroussin 
83639ee7a7aSBaptiste Daroussin struct ucl_include_params {
83739ee7a7aSBaptiste Daroussin 	bool check_signature;
83839ee7a7aSBaptiste Daroussin 	bool must_exist;
83939ee7a7aSBaptiste Daroussin 	bool use_glob;
84039ee7a7aSBaptiste Daroussin 	bool use_prefix;
84139ee7a7aSBaptiste Daroussin 	bool soft_fail;
84239ee7a7aSBaptiste Daroussin 	bool allow_glob;
84339ee7a7aSBaptiste Daroussin 	unsigned priority;
84439ee7a7aSBaptiste Daroussin 	enum ucl_duplicate_strategy strat;
84539ee7a7aSBaptiste Daroussin 	enum ucl_parse_type parse_type;
84639ee7a7aSBaptiste Daroussin 	const char *prefix;
84739ee7a7aSBaptiste Daroussin 	const char *target;
84839ee7a7aSBaptiste Daroussin };
84939ee7a7aSBaptiste Daroussin 
850c99fb5f9SBaptiste Daroussin /**
851c99fb5f9SBaptiste Daroussin  * Include an url to configuration
852c99fb5f9SBaptiste Daroussin  * @param data
853c99fb5f9SBaptiste Daroussin  * @param len
854c99fb5f9SBaptiste Daroussin  * @param parser
855c99fb5f9SBaptiste Daroussin  * @param err
856c99fb5f9SBaptiste Daroussin  * @return
857c99fb5f9SBaptiste Daroussin  */
858c99fb5f9SBaptiste Daroussin static bool
859c99fb5f9SBaptiste Daroussin ucl_include_url (const unsigned char *data, size_t len,
86039ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser,
86139ee7a7aSBaptiste Daroussin 		struct ucl_include_params *params)
862c99fb5f9SBaptiste Daroussin {
863c99fb5f9SBaptiste Daroussin 
864c99fb5f9SBaptiste Daroussin 	bool res;
865c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
866c99fb5f9SBaptiste Daroussin 	size_t buflen = 0;
867c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
868c99fb5f9SBaptiste Daroussin 	char urlbuf[PATH_MAX];
869c99fb5f9SBaptiste Daroussin 	int prev_state;
870c99fb5f9SBaptiste Daroussin 
871c99fb5f9SBaptiste Daroussin 	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
872c99fb5f9SBaptiste Daroussin 
87339ee7a7aSBaptiste Daroussin 	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
874d9f0ce31SBaptiste Daroussin 		return !params->must_exist;
875c99fb5f9SBaptiste Daroussin 	}
876c99fb5f9SBaptiste Daroussin 
87739ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
878c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
879c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
880c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
881c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
882c99fb5f9SBaptiste Daroussin 		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
883c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
884c99fb5f9SBaptiste Daroussin 			return false;
885c99fb5f9SBaptiste Daroussin 		}
886c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
887c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify url %s: %s",
888c99fb5f9SBaptiste Daroussin 							urlbuf,
889c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
890c99fb5f9SBaptiste Daroussin 			if (siglen > 0) {
89197bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
892c99fb5f9SBaptiste Daroussin 			}
893c99fb5f9SBaptiste Daroussin 			return false;
894c99fb5f9SBaptiste Daroussin 		}
895c99fb5f9SBaptiste Daroussin 		if (siglen > 0) {
89697bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
897c99fb5f9SBaptiste Daroussin 		}
898c99fb5f9SBaptiste Daroussin #endif
899c99fb5f9SBaptiste Daroussin 	}
900c99fb5f9SBaptiste Daroussin 
901c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
902c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
903c99fb5f9SBaptiste Daroussin 
90439ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
90539ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
906c99fb5f9SBaptiste Daroussin 	if (res == true) {
907c99fb5f9SBaptiste Daroussin 		/* Remove chunk from the stack */
908c99fb5f9SBaptiste Daroussin 		chunk = parser->chunks;
909c99fb5f9SBaptiste Daroussin 		if (chunk != NULL) {
910c99fb5f9SBaptiste Daroussin 			parser->chunks = chunk->next;
911c99fb5f9SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_chunk), chunk);
912c99fb5f9SBaptiste Daroussin 		}
913c99fb5f9SBaptiste Daroussin 	}
914c99fb5f9SBaptiste Daroussin 
915c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
916c99fb5f9SBaptiste Daroussin 	free (buf);
917c99fb5f9SBaptiste Daroussin 
918c99fb5f9SBaptiste Daroussin 	return res;
919c99fb5f9SBaptiste Daroussin }
920c99fb5f9SBaptiste Daroussin 
921c99fb5f9SBaptiste Daroussin /**
9224bf54857SBaptiste Daroussin  * Include a single file to the parser
923c99fb5f9SBaptiste Daroussin  * @param data
924c99fb5f9SBaptiste Daroussin  * @param len
925c99fb5f9SBaptiste Daroussin  * @param parser
9264bf54857SBaptiste Daroussin  * @param check_signature
9274bf54857SBaptiste Daroussin  * @param must_exist
9284bf54857SBaptiste Daroussin  * @param allow_glob
9294bf54857SBaptiste Daroussin  * @param priority
930c99fb5f9SBaptiste Daroussin  * @return
931c99fb5f9SBaptiste Daroussin  */
932c99fb5f9SBaptiste Daroussin static bool
9334bf54857SBaptiste Daroussin ucl_include_file_single (const unsigned char *data, size_t len,
93439ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser, struct ucl_include_params *params)
935c99fb5f9SBaptiste Daroussin {
936c99fb5f9SBaptiste Daroussin 	bool res;
937c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
938c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
93939ee7a7aSBaptiste Daroussin 	char *old_curfile, *ext;
94039ee7a7aSBaptiste Daroussin 	size_t buflen = 0;
941c99fb5f9SBaptiste Daroussin 	char filebuf[PATH_MAX], realbuf[PATH_MAX];
942c99fb5f9SBaptiste Daroussin 	int prev_state;
9434bf54857SBaptiste Daroussin 	struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
9444bf54857SBaptiste Daroussin 			*old_filename = NULL;
94539ee7a7aSBaptiste Daroussin 	ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL;
94639ee7a7aSBaptiste Daroussin 	ucl_hash_t *container = NULL;
94739ee7a7aSBaptiste Daroussin 	struct ucl_stack *st = NULL;
948c99fb5f9SBaptiste Daroussin 
949c99fb5f9SBaptiste Daroussin 	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
95097bd480fSBaptiste Daroussin 	if (ucl_realpath (filebuf, realbuf) == NULL) {
95139ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
95239ee7a7aSBaptiste Daroussin 			return false;
95339ee7a7aSBaptiste Daroussin 		}
95439ee7a7aSBaptiste Daroussin 		if (!params->must_exist) {
955c99fb5f9SBaptiste Daroussin 			return true;
956c99fb5f9SBaptiste Daroussin 		}
957c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
958c99fb5f9SBaptiste Daroussin 									filebuf,
959c99fb5f9SBaptiste Daroussin 									strerror (errno));
960c99fb5f9SBaptiste Daroussin 		return false;
961c99fb5f9SBaptiste Daroussin 	}
962c99fb5f9SBaptiste Daroussin 
9634bf54857SBaptiste Daroussin 	if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
9644bf54857SBaptiste Daroussin 		/* We are likely including the file itself */
96539ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
96639ee7a7aSBaptiste Daroussin 			return false;
96739ee7a7aSBaptiste Daroussin 		}
96839ee7a7aSBaptiste Daroussin 
9694bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "trying to include the file %s from itself",
9704bf54857SBaptiste Daroussin 				realbuf);
9714bf54857SBaptiste Daroussin 		return false;
9724bf54857SBaptiste Daroussin 	}
9734bf54857SBaptiste Daroussin 
97439ee7a7aSBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, params->must_exist)) {
97539ee7a7aSBaptiste Daroussin 		if (params->soft_fail) {
97639ee7a7aSBaptiste Daroussin 			return false;
97739ee7a7aSBaptiste Daroussin 		}
978*6525738fSBaptiste Daroussin 
97939ee7a7aSBaptiste Daroussin 		return (!params->must_exist || false);
980c99fb5f9SBaptiste Daroussin 	}
981c99fb5f9SBaptiste Daroussin 
98239ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
983c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
984c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
985c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
986c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
987c99fb5f9SBaptiste Daroussin 		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
988c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
989c99fb5f9SBaptiste Daroussin 			return false;
990c99fb5f9SBaptiste Daroussin 		}
991c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
992c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify file %s: %s",
993c99fb5f9SBaptiste Daroussin 							filebuf,
994c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
995d9f0ce31SBaptiste Daroussin 			if (sigbuf) {
99697bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
997c99fb5f9SBaptiste Daroussin 			}
998c99fb5f9SBaptiste Daroussin 			return false;
999c99fb5f9SBaptiste Daroussin 		}
1000d9f0ce31SBaptiste Daroussin 		if (sigbuf) {
100197bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
1002c99fb5f9SBaptiste Daroussin 		}
1003c99fb5f9SBaptiste Daroussin #endif
1004c99fb5f9SBaptiste Daroussin 	}
1005c99fb5f9SBaptiste Daroussin 
10064bf54857SBaptiste Daroussin 	old_curfile = parser->cur_file;
10074bf54857SBaptiste Daroussin 	parser->cur_file = strdup (realbuf);
10084bf54857SBaptiste Daroussin 
10094bf54857SBaptiste Daroussin 	/* Store old file vars */
10104bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
10114bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0) {
10124bf54857SBaptiste Daroussin 			old_curdir = cur_var;
10134bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
10144bf54857SBaptiste Daroussin 		}
10154bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0) {
10164bf54857SBaptiste Daroussin 			old_filename = cur_var;
10174bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
10184bf54857SBaptiste Daroussin 		}
10194bf54857SBaptiste Daroussin 	}
10204bf54857SBaptiste Daroussin 
1021c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
1022c99fb5f9SBaptiste Daroussin 
1023c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
1024c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
1025c99fb5f9SBaptiste Daroussin 
102639ee7a7aSBaptiste Daroussin 	if (params->use_prefix && params->prefix == NULL) {
102739ee7a7aSBaptiste Daroussin 		/* Auto generate a key name based on the included filename */
102839ee7a7aSBaptiste Daroussin 		params->prefix = basename (realbuf);
102939ee7a7aSBaptiste Daroussin 		ext = strrchr (params->prefix, '.');
103039ee7a7aSBaptiste Daroussin 		if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) {
103139ee7a7aSBaptiste Daroussin 			/* Strip off .conf or .ucl */
103239ee7a7aSBaptiste Daroussin 			*ext = '\0';
103339ee7a7aSBaptiste Daroussin 		}
103439ee7a7aSBaptiste Daroussin 	}
103539ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL) {
103639ee7a7aSBaptiste Daroussin 		/* This is a prefixed include */
103739ee7a7aSBaptiste Daroussin 		container = parser->stack->obj->value.ov;
103839ee7a7aSBaptiste Daroussin 
103939ee7a7aSBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container,
104039ee7a7aSBaptiste Daroussin 				params->prefix, strlen (params->prefix)));
104139ee7a7aSBaptiste Daroussin 
104239ee7a7aSBaptiste Daroussin 		if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) {
104339ee7a7aSBaptiste Daroussin 			/* Create an array with key: prefix */
104439ee7a7aSBaptiste Daroussin 			old_obj = ucl_object_new_full (UCL_ARRAY, params->priority);
104539ee7a7aSBaptiste Daroussin 			old_obj->key = params->prefix;
104639ee7a7aSBaptiste Daroussin 			old_obj->keylen = strlen (params->prefix);
104739ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash(old_obj);
104839ee7a7aSBaptiste Daroussin 			old_obj->prev = old_obj;
104939ee7a7aSBaptiste Daroussin 			old_obj->next = NULL;
105039ee7a7aSBaptiste Daroussin 
105139ee7a7aSBaptiste Daroussin 			container = ucl_hash_insert_object (container, old_obj,
105239ee7a7aSBaptiste Daroussin 					parser->flags & UCL_PARSER_KEY_LOWERCASE);
105339ee7a7aSBaptiste Daroussin 			parser->stack->obj->len ++;
105439ee7a7aSBaptiste Daroussin 
105539ee7a7aSBaptiste Daroussin 			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
105639ee7a7aSBaptiste Daroussin 			nest_obj->prev = nest_obj;
105739ee7a7aSBaptiste Daroussin 			nest_obj->next = NULL;
105839ee7a7aSBaptiste Daroussin 
105939ee7a7aSBaptiste Daroussin 			ucl_array_append (old_obj, nest_obj);
106039ee7a7aSBaptiste Daroussin 		}
106139ee7a7aSBaptiste Daroussin 		else if (old_obj == NULL) {
106239ee7a7aSBaptiste Daroussin 			/* Create an object with key: prefix */
106339ee7a7aSBaptiste Daroussin 			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1064d9f0ce31SBaptiste Daroussin 
1065d9f0ce31SBaptiste Daroussin 			if (nest_obj == NULL) {
1066d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot allocate memory for an object");
1067d9f0ce31SBaptiste Daroussin 				if (buf) {
1068d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
1069d9f0ce31SBaptiste Daroussin 				}
1070d9f0ce31SBaptiste Daroussin 
1071d9f0ce31SBaptiste Daroussin 				return false;
1072d9f0ce31SBaptiste Daroussin 			}
1073d9f0ce31SBaptiste Daroussin 
107439ee7a7aSBaptiste Daroussin 			nest_obj->key = params->prefix;
107539ee7a7aSBaptiste Daroussin 			nest_obj->keylen = strlen (params->prefix);
107639ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash(nest_obj);
107739ee7a7aSBaptiste Daroussin 			nest_obj->prev = nest_obj;
107839ee7a7aSBaptiste Daroussin 			nest_obj->next = NULL;
107939ee7a7aSBaptiste Daroussin 
108039ee7a7aSBaptiste Daroussin 			container = ucl_hash_insert_object (container, nest_obj,
108139ee7a7aSBaptiste Daroussin 					parser->flags & UCL_PARSER_KEY_LOWERCASE);
108239ee7a7aSBaptiste Daroussin 			parser->stack->obj->len ++;
108339ee7a7aSBaptiste Daroussin 		}
108439ee7a7aSBaptiste Daroussin 		else if (strcasecmp (params->target, "array") == 0 ||
108539ee7a7aSBaptiste Daroussin 				ucl_object_type(old_obj) == UCL_ARRAY) {
108639ee7a7aSBaptiste Daroussin 			if (ucl_object_type(old_obj) == UCL_ARRAY) {
108739ee7a7aSBaptiste Daroussin 				/* Append to the existing array */
108839ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1089d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1090d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1091d9f0ce31SBaptiste Daroussin 					if (buf) {
1092d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1093d9f0ce31SBaptiste Daroussin 					}
1094d9f0ce31SBaptiste Daroussin 
1095d9f0ce31SBaptiste Daroussin 					return false;
1096d9f0ce31SBaptiste Daroussin 				}
109739ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
109839ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
109939ee7a7aSBaptiste Daroussin 
110039ee7a7aSBaptiste Daroussin 				ucl_array_append (old_obj, nest_obj);
110139ee7a7aSBaptiste Daroussin 			}
110239ee7a7aSBaptiste Daroussin 			else {
110339ee7a7aSBaptiste Daroussin 				/* Convert the object to an array */
110439ee7a7aSBaptiste Daroussin 				new_obj = ucl_object_typed_new (UCL_ARRAY);
1105d9f0ce31SBaptiste Daroussin 				if (new_obj == NULL) {
1106d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1107d9f0ce31SBaptiste Daroussin 					if (buf) {
1108d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1109d9f0ce31SBaptiste Daroussin 					}
1110d9f0ce31SBaptiste Daroussin 
1111d9f0ce31SBaptiste Daroussin 					return false;
1112d9f0ce31SBaptiste Daroussin 				}
111339ee7a7aSBaptiste Daroussin 				new_obj->key = old_obj->key;
111439ee7a7aSBaptiste Daroussin 				new_obj->keylen = old_obj->keylen;
111539ee7a7aSBaptiste Daroussin 				new_obj->flags |= UCL_OBJECT_MULTIVALUE;
111639ee7a7aSBaptiste Daroussin 				new_obj->prev = new_obj;
111739ee7a7aSBaptiste Daroussin 				new_obj->next = NULL;
111839ee7a7aSBaptiste Daroussin 
111939ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1120d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1121d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1122d9f0ce31SBaptiste Daroussin 					if (buf) {
1123d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1124d9f0ce31SBaptiste Daroussin 					}
1125d9f0ce31SBaptiste Daroussin 
1126d9f0ce31SBaptiste Daroussin 					return false;
1127d9f0ce31SBaptiste Daroussin 				}
112839ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
112939ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
113039ee7a7aSBaptiste Daroussin 
113139ee7a7aSBaptiste Daroussin 				ucl_array_append (new_obj, old_obj);
113239ee7a7aSBaptiste Daroussin 				ucl_array_append (new_obj, nest_obj);
113339ee7a7aSBaptiste Daroussin 				ucl_hash_replace (container, old_obj, new_obj);
113439ee7a7aSBaptiste Daroussin 			}
113539ee7a7aSBaptiste Daroussin 		}
113639ee7a7aSBaptiste Daroussin 		else {
113739ee7a7aSBaptiste Daroussin 			if (ucl_object_type (old_obj) == UCL_OBJECT) {
113839ee7a7aSBaptiste Daroussin 				/* Append to existing Object*/
113939ee7a7aSBaptiste Daroussin 				nest_obj = old_obj;
114039ee7a7aSBaptiste Daroussin 			}
114139ee7a7aSBaptiste Daroussin 			else {
114239ee7a7aSBaptiste Daroussin 				/* The key is not an object */
114339ee7a7aSBaptiste Daroussin 				ucl_create_err (&parser->err,
114439ee7a7aSBaptiste Daroussin 						"Conflicting type for key: %s",
114539ee7a7aSBaptiste Daroussin 						params->prefix);
1146d9f0ce31SBaptiste Daroussin 				if (buf) {
1147d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
1148d9f0ce31SBaptiste Daroussin 				}
1149d9f0ce31SBaptiste Daroussin 
115039ee7a7aSBaptiste Daroussin 				return false;
115139ee7a7aSBaptiste Daroussin 			}
115239ee7a7aSBaptiste Daroussin 		}
115339ee7a7aSBaptiste Daroussin 
115439ee7a7aSBaptiste Daroussin 		 /* Put all of the content of the include inside that object */
115539ee7a7aSBaptiste Daroussin 		parser->stack->obj->value.ov = container;
115639ee7a7aSBaptiste Daroussin 
115739ee7a7aSBaptiste Daroussin 		st = UCL_ALLOC (sizeof (struct ucl_stack));
115839ee7a7aSBaptiste Daroussin 		if (st == NULL) {
115939ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for an object");
116039ee7a7aSBaptiste Daroussin 			ucl_object_unref (nest_obj);
1161d9f0ce31SBaptiste Daroussin 
1162d9f0ce31SBaptiste Daroussin 			if (buf) {
1163d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1164d9f0ce31SBaptiste Daroussin 			}
1165d9f0ce31SBaptiste Daroussin 
1166d9f0ce31SBaptiste Daroussin 			return false;
116739ee7a7aSBaptiste Daroussin 		}
116839ee7a7aSBaptiste Daroussin 		st->obj = nest_obj;
116939ee7a7aSBaptiste Daroussin 		st->level = parser->stack->level;
117039ee7a7aSBaptiste Daroussin 		LL_PREPEND (parser->stack, st);
117139ee7a7aSBaptiste Daroussin 		parser->cur_obj = nest_obj;
117239ee7a7aSBaptiste Daroussin 	}
117339ee7a7aSBaptiste Daroussin 
117439ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
117539ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
1176*6525738fSBaptiste Daroussin 
1177*6525738fSBaptiste Daroussin 	if (!res) {
1178*6525738fSBaptiste Daroussin 		if (!params->must_exist) {
11794bf54857SBaptiste Daroussin 			/* Free error */
11804bf54857SBaptiste Daroussin 			utstring_free (parser->err);
11814bf54857SBaptiste Daroussin 			parser->err = NULL;
1182*6525738fSBaptiste Daroussin 			res = true;
1183*6525738fSBaptiste Daroussin 		}
11844bf54857SBaptiste Daroussin 	}
11854bf54857SBaptiste Daroussin 
118639ee7a7aSBaptiste Daroussin 	/* Stop nesting the include, take 1 level off the stack */
118739ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL && nest_obj != NULL) {
118839ee7a7aSBaptiste Daroussin 		parser->stack = st->next;
118939ee7a7aSBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_stack), st);
119039ee7a7aSBaptiste Daroussin 	}
119139ee7a7aSBaptiste Daroussin 
1192c99fb5f9SBaptiste Daroussin 	/* Remove chunk from the stack */
1193c99fb5f9SBaptiste Daroussin 	chunk = parser->chunks;
1194c99fb5f9SBaptiste Daroussin 	if (chunk != NULL) {
1195c99fb5f9SBaptiste Daroussin 		parser->chunks = chunk->next;
1196c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_chunk), chunk);
11974bf54857SBaptiste Daroussin 		parser->recursion --;
1198c99fb5f9SBaptiste Daroussin 	}
11994bf54857SBaptiste Daroussin 
12004bf54857SBaptiste Daroussin 	/* Restore old file vars */
120139ee7a7aSBaptiste Daroussin 	if (parser->cur_file) {
120239ee7a7aSBaptiste Daroussin 		free (parser->cur_file);
120339ee7a7aSBaptiste Daroussin 	}
120439ee7a7aSBaptiste Daroussin 
12054bf54857SBaptiste Daroussin 	parser->cur_file = old_curfile;
12064bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
12074bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
12084bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
12094bf54857SBaptiste Daroussin 			free (cur_var->var);
12104bf54857SBaptiste Daroussin 			free (cur_var->value);
12114bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), cur_var);
12124bf54857SBaptiste Daroussin 		}
12134bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
12144bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
12154bf54857SBaptiste Daroussin 			free (cur_var->var);
12164bf54857SBaptiste Daroussin 			free (cur_var->value);
12174bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), cur_var);
12184bf54857SBaptiste Daroussin 		}
12194bf54857SBaptiste Daroussin 	}
12204bf54857SBaptiste Daroussin 	if (old_filename) {
12214bf54857SBaptiste Daroussin 		DL_APPEND (parser->variables, old_filename);
12224bf54857SBaptiste Daroussin 	}
12234bf54857SBaptiste Daroussin 	if (old_curdir) {
12244bf54857SBaptiste Daroussin 		DL_APPEND (parser->variables, old_curdir);
12254bf54857SBaptiste Daroussin 	}
1226c99fb5f9SBaptiste Daroussin 
1227c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
1228c99fb5f9SBaptiste Daroussin 
1229c99fb5f9SBaptiste Daroussin 	if (buflen > 0) {
123097bd480fSBaptiste Daroussin 		ucl_munmap (buf, buflen);
1231c99fb5f9SBaptiste Daroussin 	}
1232c99fb5f9SBaptiste Daroussin 
1233c99fb5f9SBaptiste Daroussin 	return res;
1234c99fb5f9SBaptiste Daroussin }
1235c99fb5f9SBaptiste Daroussin 
1236c99fb5f9SBaptiste Daroussin /**
12374bf54857SBaptiste Daroussin  * Include a file to configuration
12384bf54857SBaptiste Daroussin  * @param data
12394bf54857SBaptiste Daroussin  * @param len
12404bf54857SBaptiste Daroussin  * @param parser
12414bf54857SBaptiste Daroussin  * @param err
12424bf54857SBaptiste Daroussin  * @return
12434bf54857SBaptiste Daroussin  */
12444bf54857SBaptiste Daroussin static bool
12454bf54857SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len,
124639ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser, struct ucl_include_params *params)
12474bf54857SBaptiste Daroussin {
12484bf54857SBaptiste Daroussin 	const unsigned char *p = data, *end = data + len;
12494bf54857SBaptiste Daroussin 	bool need_glob = false;
12504bf54857SBaptiste Daroussin 	int cnt = 0;
12514bf54857SBaptiste Daroussin 	char glob_pattern[PATH_MAX];
12524bf54857SBaptiste Daroussin 	size_t i;
12534bf54857SBaptiste Daroussin 
12548e3b1ab2SBaptiste Daroussin #ifndef _WIN32
125539ee7a7aSBaptiste Daroussin 	if (!params->allow_glob) {
125639ee7a7aSBaptiste Daroussin 		return ucl_include_file_single (data, len, parser, params);
12574bf54857SBaptiste Daroussin 	}
12584bf54857SBaptiste Daroussin 	else {
12594bf54857SBaptiste Daroussin 		/* Check for special symbols in a filename */
12604bf54857SBaptiste Daroussin 		while (p != end) {
12614bf54857SBaptiste Daroussin 			if (*p == '*' || *p == '?') {
12624bf54857SBaptiste Daroussin 				need_glob = true;
12634bf54857SBaptiste Daroussin 				break;
12644bf54857SBaptiste Daroussin 			}
12654bf54857SBaptiste Daroussin 			p ++;
12664bf54857SBaptiste Daroussin 		}
12674bf54857SBaptiste Daroussin 		if (need_glob) {
12688e3b1ab2SBaptiste Daroussin 			glob_t globbuf;
12694bf54857SBaptiste Daroussin 			memset (&globbuf, 0, sizeof (globbuf));
127039ee7a7aSBaptiste Daroussin 			ucl_strlcpy (glob_pattern, (const char *)data,
127139ee7a7aSBaptiste Daroussin 				(len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern)));
12724bf54857SBaptiste Daroussin 			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
127339ee7a7aSBaptiste Daroussin 				return (!params->must_exist || false);
12744bf54857SBaptiste Daroussin 			}
12754bf54857SBaptiste Daroussin 			for (i = 0; i < globbuf.gl_pathc; i ++) {
12764bf54857SBaptiste Daroussin 				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
127739ee7a7aSBaptiste Daroussin 						strlen (globbuf.gl_pathv[i]), parser, params)) {
127839ee7a7aSBaptiste Daroussin 					if (params->soft_fail) {
127939ee7a7aSBaptiste Daroussin 						continue;
128039ee7a7aSBaptiste Daroussin 					}
12814bf54857SBaptiste Daroussin 					globfree (&globbuf);
12824bf54857SBaptiste Daroussin 					return false;
12834bf54857SBaptiste Daroussin 				}
12844bf54857SBaptiste Daroussin 				cnt ++;
12854bf54857SBaptiste Daroussin 			}
12864bf54857SBaptiste Daroussin 			globfree (&globbuf);
12874bf54857SBaptiste Daroussin 
128839ee7a7aSBaptiste Daroussin 			if (cnt == 0 && params->must_exist) {
12894bf54857SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
12904bf54857SBaptiste Daroussin 					glob_pattern);
12914bf54857SBaptiste Daroussin 				return false;
12924bf54857SBaptiste Daroussin 			}
12934bf54857SBaptiste Daroussin 		}
12944bf54857SBaptiste Daroussin 		else {
129539ee7a7aSBaptiste Daroussin 			return ucl_include_file_single (data, len, parser, params);
12964bf54857SBaptiste Daroussin 		}
12974bf54857SBaptiste Daroussin 	}
12988e3b1ab2SBaptiste Daroussin #else
12998e3b1ab2SBaptiste Daroussin 	/* Win32 compilers do not support globbing. Therefore, for Win32,
13008e3b1ab2SBaptiste Daroussin 	   treat allow_glob/need_glob as a NOOP and just return */
130139ee7a7aSBaptiste Daroussin 	return ucl_include_file_single (data, len, parser, params);
13028e3b1ab2SBaptiste Daroussin #endif
13034bf54857SBaptiste Daroussin 
13044bf54857SBaptiste Daroussin 	return true;
13054bf54857SBaptiste Daroussin }
13064bf54857SBaptiste Daroussin 
13074bf54857SBaptiste Daroussin /**
13084bf54857SBaptiste Daroussin  * Common function to handle .*include* macros
13094bf54857SBaptiste Daroussin  * @param data
13104bf54857SBaptiste Daroussin  * @param len
13114bf54857SBaptiste Daroussin  * @param args
13124bf54857SBaptiste Daroussin  * @param parser
13134bf54857SBaptiste Daroussin  * @param default_try
13144bf54857SBaptiste Daroussin  * @param default_sign
13154bf54857SBaptiste Daroussin  * @return
13164bf54857SBaptiste Daroussin  */
13174bf54857SBaptiste Daroussin static bool
13184bf54857SBaptiste Daroussin ucl_include_common (const unsigned char *data, size_t len,
13194bf54857SBaptiste Daroussin 		const ucl_object_t *args, struct ucl_parser *parser,
13204bf54857SBaptiste Daroussin 		bool default_try,
13214bf54857SBaptiste Daroussin 		bool default_sign)
13224bf54857SBaptiste Daroussin {
1323d9f0ce31SBaptiste Daroussin 	bool allow_url = false, search = false;
132439ee7a7aSBaptiste Daroussin 	const char *duplicate;
13254bf54857SBaptiste Daroussin 	const ucl_object_t *param;
132639ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL, ip = NULL;
132739ee7a7aSBaptiste Daroussin 	char ipath[PATH_MAX];
132839ee7a7aSBaptiste Daroussin 	struct ucl_include_params params;
13294bf54857SBaptiste Daroussin 
13304bf54857SBaptiste Daroussin 	/* Default values */
133139ee7a7aSBaptiste Daroussin 	params.soft_fail = default_try;
133239ee7a7aSBaptiste Daroussin 	params.allow_glob = false;
133339ee7a7aSBaptiste Daroussin 	params.check_signature = default_sign;
133439ee7a7aSBaptiste Daroussin 	params.use_prefix = false;
133539ee7a7aSBaptiste Daroussin 	params.target = "object";
133639ee7a7aSBaptiste Daroussin 	params.prefix = NULL;
133739ee7a7aSBaptiste Daroussin 	params.priority = 0;
133839ee7a7aSBaptiste Daroussin 	params.parse_type = UCL_PARSE_UCL;
133939ee7a7aSBaptiste Daroussin 	params.strat = UCL_DUPLICATE_APPEND;
134039ee7a7aSBaptiste Daroussin 	params.must_exist = !default_try;
134139ee7a7aSBaptiste Daroussin 
13424bf54857SBaptiste Daroussin 	/* Process arguments */
13434bf54857SBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1344d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
13454bf54857SBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
134639ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
134739ee7a7aSBaptiste Daroussin 					params.must_exist = !ucl_object_toboolean (param);
13484bf54857SBaptiste Daroussin 				}
134939ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "sign", param->keylen) == 0) {
135039ee7a7aSBaptiste Daroussin 					params.check_signature = ucl_object_toboolean (param);
13514bf54857SBaptiste Daroussin 				}
135239ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "glob", param->keylen) == 0) {
135339ee7a7aSBaptiste Daroussin 					params.allow_glob = ucl_object_toboolean (param);
13544bf54857SBaptiste Daroussin 				}
135539ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "url", param->keylen) == 0) {
13564bf54857SBaptiste Daroussin 					allow_url = ucl_object_toboolean (param);
13574bf54857SBaptiste Daroussin 				}
135839ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "prefix", param->keylen) == 0) {
135939ee7a7aSBaptiste Daroussin 					params.use_prefix = ucl_object_toboolean (param);
136039ee7a7aSBaptiste Daroussin 				}
136139ee7a7aSBaptiste Daroussin 			}
136239ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
136339ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
136439ee7a7aSBaptiste Daroussin 					params.prefix = ucl_object_tostring (param);
136539ee7a7aSBaptiste Daroussin 				}
136639ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
136739ee7a7aSBaptiste Daroussin 					params.target = ucl_object_tostring (param);
136839ee7a7aSBaptiste Daroussin 				}
136939ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "duplicate", param->keylen) == 0) {
137039ee7a7aSBaptiste Daroussin 					duplicate = ucl_object_tostring (param);
137139ee7a7aSBaptiste Daroussin 
137239ee7a7aSBaptiste Daroussin 					if (strcmp (duplicate, "append") == 0) {
137339ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_APPEND;
137439ee7a7aSBaptiste Daroussin 					}
137539ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "merge") == 0) {
137639ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_MERGE;
137739ee7a7aSBaptiste Daroussin 					}
137839ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "rewrite") == 0) {
137939ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_REWRITE;
138039ee7a7aSBaptiste Daroussin 					}
138139ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "error") == 0) {
138239ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_ERROR;
138339ee7a7aSBaptiste Daroussin 					}
138439ee7a7aSBaptiste Daroussin 				}
138539ee7a7aSBaptiste Daroussin 			}
138639ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_ARRAY) {
138739ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "path", param->keylen) == 0) {
138839ee7a7aSBaptiste Daroussin 					ucl_set_include_path (parser, __DECONST(ucl_object_t *, param));
138939ee7a7aSBaptiste Daroussin 				}
13904bf54857SBaptiste Daroussin 			}
13914bf54857SBaptiste Daroussin 			else if (param->type == UCL_INT) {
139239ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
139339ee7a7aSBaptiste Daroussin 					params.priority = ucl_object_toint (param);
13944bf54857SBaptiste Daroussin 				}
13954bf54857SBaptiste Daroussin 			}
13964bf54857SBaptiste Daroussin 		}
13974bf54857SBaptiste Daroussin 	}
13984bf54857SBaptiste Daroussin 
139939ee7a7aSBaptiste Daroussin 	if (parser->includepaths == NULL) {
140039ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
14014bf54857SBaptiste Daroussin 			/* Globbing is not used for URL's */
140239ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
140339ee7a7aSBaptiste Daroussin 		}
140439ee7a7aSBaptiste Daroussin 		else if (data != NULL) {
140539ee7a7aSBaptiste Daroussin 			/* Try to load a file */
140639ee7a7aSBaptiste Daroussin 			return ucl_include_file (data, len, parser, &params);
140739ee7a7aSBaptiste Daroussin 		}
140839ee7a7aSBaptiste Daroussin 	}
140939ee7a7aSBaptiste Daroussin 	else {
141039ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
141139ee7a7aSBaptiste Daroussin 			/* Globbing is not used for URL's */
141239ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
141339ee7a7aSBaptiste Daroussin 		}
141439ee7a7aSBaptiste Daroussin 
141539ee7a7aSBaptiste Daroussin 		ip = ucl_object_iterate_new (parser->includepaths);
141639ee7a7aSBaptiste Daroussin 		while ((param = ucl_object_iterate_safe (ip, true)) != NULL) {
141739ee7a7aSBaptiste Daroussin 			if (ucl_object_type(param) == UCL_STRING) {
141839ee7a7aSBaptiste Daroussin 				snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param),
141939ee7a7aSBaptiste Daroussin 						(int)len, data);
142039ee7a7aSBaptiste Daroussin 				if ((search = ucl_include_file (ipath, strlen (ipath),
142139ee7a7aSBaptiste Daroussin 						parser, &params))) {
142239ee7a7aSBaptiste Daroussin 					if (!params.allow_glob) {
142339ee7a7aSBaptiste Daroussin 						break;
142439ee7a7aSBaptiste Daroussin 					}
142539ee7a7aSBaptiste Daroussin 				}
142639ee7a7aSBaptiste Daroussin 			}
142739ee7a7aSBaptiste Daroussin 		}
142839ee7a7aSBaptiste Daroussin 		ucl_object_iterate_free (ip);
142939ee7a7aSBaptiste Daroussin 		if (search == true) {
143039ee7a7aSBaptiste Daroussin 			return true;
143139ee7a7aSBaptiste Daroussin 		}
143239ee7a7aSBaptiste Daroussin 		else {
143339ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err,
143439ee7a7aSBaptiste Daroussin 					"cannot find file: %.*s in search path",
143539ee7a7aSBaptiste Daroussin 					(int)len, data);
143639ee7a7aSBaptiste Daroussin 			return false;
143739ee7a7aSBaptiste Daroussin 		}
14384bf54857SBaptiste Daroussin 	}
14394bf54857SBaptiste Daroussin 
14404bf54857SBaptiste Daroussin 	return false;
14414bf54857SBaptiste Daroussin }
14424bf54857SBaptiste Daroussin 
14434bf54857SBaptiste Daroussin /**
1444c99fb5f9SBaptiste Daroussin  * Handle include macro
1445c99fb5f9SBaptiste Daroussin  * @param data include data
1446c99fb5f9SBaptiste Daroussin  * @param len length of data
144739ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1448c99fb5f9SBaptiste Daroussin  * @param ud user data
1449c99fb5f9SBaptiste Daroussin  * @return
1450c99fb5f9SBaptiste Daroussin  */
145139ee7a7aSBaptiste Daroussin bool
14524bf54857SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len,
14534bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1454c99fb5f9SBaptiste Daroussin {
1455c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1456c99fb5f9SBaptiste Daroussin 
14574bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, false);
1458c99fb5f9SBaptiste Daroussin }
1459c99fb5f9SBaptiste Daroussin 
1460c99fb5f9SBaptiste Daroussin /**
1461c99fb5f9SBaptiste Daroussin  * Handle includes macro
1462c99fb5f9SBaptiste Daroussin  * @param data include data
1463c99fb5f9SBaptiste Daroussin  * @param len length of data
146439ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1465c99fb5f9SBaptiste Daroussin  * @param ud user data
1466c99fb5f9SBaptiste Daroussin  * @return
1467c99fb5f9SBaptiste Daroussin  */
146839ee7a7aSBaptiste Daroussin bool
14694bf54857SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len,
14704bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1471c99fb5f9SBaptiste Daroussin {
1472c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1473c99fb5f9SBaptiste Daroussin 
14744bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, true);
1475c99fb5f9SBaptiste Daroussin }
1476c99fb5f9SBaptiste Daroussin 
147739ee7a7aSBaptiste Daroussin /**
147839ee7a7aSBaptiste Daroussin  * Handle tryinclude macro
147939ee7a7aSBaptiste Daroussin  * @param data include data
148039ee7a7aSBaptiste Daroussin  * @param len length of data
148139ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
148239ee7a7aSBaptiste Daroussin  * @param ud user data
148339ee7a7aSBaptiste Daroussin  * @return
148439ee7a7aSBaptiste Daroussin  */
148539ee7a7aSBaptiste Daroussin bool
14864bf54857SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len,
14874bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1488c99fb5f9SBaptiste Daroussin {
1489c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1490c99fb5f9SBaptiste Daroussin 
14914bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, true, false);
1492c99fb5f9SBaptiste Daroussin }
1493c99fb5f9SBaptiste Daroussin 
149439ee7a7aSBaptiste Daroussin /**
149539ee7a7aSBaptiste Daroussin  * Handle priority macro
149639ee7a7aSBaptiste Daroussin  * @param data include data
149739ee7a7aSBaptiste Daroussin  * @param len length of data
149839ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
149939ee7a7aSBaptiste Daroussin  * @param ud user data
150039ee7a7aSBaptiste Daroussin  * @return
150139ee7a7aSBaptiste Daroussin  */
150239ee7a7aSBaptiste Daroussin bool
150339ee7a7aSBaptiste Daroussin ucl_priority_handler (const unsigned char *data, size_t len,
150439ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
150539ee7a7aSBaptiste Daroussin {
150639ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
150739ee7a7aSBaptiste Daroussin 	unsigned priority = 255;
150839ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
150939ee7a7aSBaptiste Daroussin 	bool found = false;
151039ee7a7aSBaptiste Daroussin 	char *value = NULL, *leftover = NULL;
151139ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
151239ee7a7aSBaptiste Daroussin 
151339ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
151439ee7a7aSBaptiste Daroussin 		return false;
151539ee7a7aSBaptiste Daroussin 	}
151639ee7a7aSBaptiste Daroussin 
151739ee7a7aSBaptiste Daroussin 	/* Process arguments */
151839ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1519d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
152039ee7a7aSBaptiste Daroussin 			if (param->type == UCL_INT) {
152139ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
152239ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
152339ee7a7aSBaptiste Daroussin 					found = true;
152439ee7a7aSBaptiste Daroussin 				}
152539ee7a7aSBaptiste Daroussin 			}
152639ee7a7aSBaptiste Daroussin 		}
152739ee7a7aSBaptiste Daroussin 	}
152839ee7a7aSBaptiste Daroussin 
152939ee7a7aSBaptiste Daroussin 	if (len > 0) {
153039ee7a7aSBaptiste Daroussin 		value = malloc(len + 1);
153139ee7a7aSBaptiste Daroussin 		ucl_strlcpy(value, (const char *)data, len + 1);
153239ee7a7aSBaptiste Daroussin 		priority = strtol(value, &leftover, 10);
153339ee7a7aSBaptiste Daroussin 		if (*leftover != '\0') {
153439ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Invalid priority value in macro: %s",
153539ee7a7aSBaptiste Daroussin 				value);
153639ee7a7aSBaptiste Daroussin 			free(value);
153739ee7a7aSBaptiste Daroussin 			return false;
153839ee7a7aSBaptiste Daroussin 		}
153939ee7a7aSBaptiste Daroussin 		free(value);
154039ee7a7aSBaptiste Daroussin 		found = true;
154139ee7a7aSBaptiste Daroussin 	}
154239ee7a7aSBaptiste Daroussin 
154339ee7a7aSBaptiste Daroussin 	if (found == true) {
154439ee7a7aSBaptiste Daroussin 		parser->chunks->priority = priority;
154539ee7a7aSBaptiste Daroussin 		return true;
154639ee7a7aSBaptiste Daroussin 	}
154739ee7a7aSBaptiste Daroussin 
154839ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse priority macro");
154939ee7a7aSBaptiste Daroussin 	return false;
155039ee7a7aSBaptiste Daroussin }
155139ee7a7aSBaptiste Daroussin 
155239ee7a7aSBaptiste Daroussin /**
155339ee7a7aSBaptiste Daroussin  * Handle load macro
155439ee7a7aSBaptiste Daroussin  * @param data include data
155539ee7a7aSBaptiste Daroussin  * @param len length of data
155639ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
155739ee7a7aSBaptiste Daroussin  * @param ud user data
155839ee7a7aSBaptiste Daroussin  * @return
155939ee7a7aSBaptiste Daroussin  */
156039ee7a7aSBaptiste Daroussin bool
156139ee7a7aSBaptiste Daroussin ucl_load_handler (const unsigned char *data, size_t len,
156239ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
156339ee7a7aSBaptiste Daroussin {
156439ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
156539ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
156639ee7a7aSBaptiste Daroussin 	ucl_object_t *obj, *old_obj;
156739ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
156839ee7a7aSBaptiste Daroussin 	bool try_load, multiline, test;
156939ee7a7aSBaptiste Daroussin 	const char *target, *prefix;
157039ee7a7aSBaptiste Daroussin 	char *load_file, *tmp;
157139ee7a7aSBaptiste Daroussin 	unsigned char *buf;
157239ee7a7aSBaptiste Daroussin 	size_t buflen;
157339ee7a7aSBaptiste Daroussin 	unsigned priority;
157439ee7a7aSBaptiste Daroussin 	int64_t iv;
1575d9f0ce31SBaptiste Daroussin 	ucl_object_t *container = NULL;
157639ee7a7aSBaptiste Daroussin 	enum ucl_string_flags flags;
157739ee7a7aSBaptiste Daroussin 
157839ee7a7aSBaptiste Daroussin 	/* Default values */
157939ee7a7aSBaptiste Daroussin 	try_load = false;
158039ee7a7aSBaptiste Daroussin 	multiline = false;
158139ee7a7aSBaptiste Daroussin 	test = false;
158239ee7a7aSBaptiste Daroussin 	target = "string";
158339ee7a7aSBaptiste Daroussin 	prefix = NULL;
158439ee7a7aSBaptiste Daroussin 	load_file = NULL;
158539ee7a7aSBaptiste Daroussin 	buf = NULL;
158639ee7a7aSBaptiste Daroussin 	buflen = 0;
158739ee7a7aSBaptiste Daroussin 	priority = 0;
158839ee7a7aSBaptiste Daroussin 	obj = NULL;
158939ee7a7aSBaptiste Daroussin 	old_obj = NULL;
159039ee7a7aSBaptiste Daroussin 	flags = 0;
159139ee7a7aSBaptiste Daroussin 
159239ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
159339ee7a7aSBaptiste Daroussin 		return false;
159439ee7a7aSBaptiste Daroussin 	}
159539ee7a7aSBaptiste Daroussin 
159639ee7a7aSBaptiste Daroussin 	/* Process arguments */
159739ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1598d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
159939ee7a7aSBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
160039ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
160139ee7a7aSBaptiste Daroussin 					try_load = ucl_object_toboolean (param);
160239ee7a7aSBaptiste Daroussin 				}
160339ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "multiline", param->keylen) == 0) {
160439ee7a7aSBaptiste Daroussin 					multiline = ucl_object_toboolean (param);
160539ee7a7aSBaptiste Daroussin 				}
160639ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "escape", param->keylen) == 0) {
160739ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
160839ee7a7aSBaptiste Daroussin 					if (test) {
160939ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_ESCAPE;
161039ee7a7aSBaptiste Daroussin 					}
161139ee7a7aSBaptiste Daroussin 				}
161239ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "trim", param->keylen) == 0) {
161339ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
161439ee7a7aSBaptiste Daroussin 					if (test) {
161539ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_TRIM;
161639ee7a7aSBaptiste Daroussin 					}
161739ee7a7aSBaptiste Daroussin 				}
161839ee7a7aSBaptiste Daroussin 			}
161939ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
162039ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
162139ee7a7aSBaptiste Daroussin 					prefix = ucl_object_tostring (param);
162239ee7a7aSBaptiste Daroussin 				}
162339ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
162439ee7a7aSBaptiste Daroussin 					target = ucl_object_tostring (param);
162539ee7a7aSBaptiste Daroussin 				}
162639ee7a7aSBaptiste Daroussin 			}
162739ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_INT) {
162839ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
162939ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
163039ee7a7aSBaptiste Daroussin 				}
163139ee7a7aSBaptiste Daroussin 			}
163239ee7a7aSBaptiste Daroussin 		}
163339ee7a7aSBaptiste Daroussin 	}
163439ee7a7aSBaptiste Daroussin 
163539ee7a7aSBaptiste Daroussin 	if (prefix == NULL || strlen (prefix) == 0) {
163639ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "No Key specified in load macro");
163739ee7a7aSBaptiste Daroussin 		return false;
163839ee7a7aSBaptiste Daroussin 	}
163939ee7a7aSBaptiste Daroussin 
164039ee7a7aSBaptiste Daroussin 	if (len > 0) {
1641d9f0ce31SBaptiste Daroussin 		load_file = malloc (len + 1);
1642d9f0ce31SBaptiste Daroussin 		if (!load_file) {
1643d9f0ce31SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for suffix");
1644d9f0ce31SBaptiste Daroussin 
1645d9f0ce31SBaptiste Daroussin 			return false;
1646d9f0ce31SBaptiste Daroussin 		}
1647d9f0ce31SBaptiste Daroussin 
1648d9f0ce31SBaptiste Daroussin 		snprintf (load_file, len + 1, "%.*s", (int)len, data);
1649d9f0ce31SBaptiste Daroussin 
1650d9f0ce31SBaptiste Daroussin 		if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err,
1651d9f0ce31SBaptiste Daroussin 				!try_load)) {
1652d9f0ce31SBaptiste Daroussin 			free (load_file);
1653d9f0ce31SBaptiste Daroussin 
165439ee7a7aSBaptiste Daroussin 			return (try_load || false);
165539ee7a7aSBaptiste Daroussin 		}
165639ee7a7aSBaptiste Daroussin 
1657d9f0ce31SBaptiste Daroussin 		free (load_file);
1658d9f0ce31SBaptiste Daroussin 		container = parser->stack->obj;
1659d9f0ce31SBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_object_lookup (container,
1660d9f0ce31SBaptiste Daroussin 				prefix));
1661d9f0ce31SBaptiste Daroussin 
166239ee7a7aSBaptiste Daroussin 		if (old_obj != NULL) {
166339ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Key %s already exists", prefix);
1664d9f0ce31SBaptiste Daroussin 			if (buf) {
1665d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1666d9f0ce31SBaptiste Daroussin 			}
1667d9f0ce31SBaptiste Daroussin 
166839ee7a7aSBaptiste Daroussin 			return false;
166939ee7a7aSBaptiste Daroussin 		}
167039ee7a7aSBaptiste Daroussin 
167139ee7a7aSBaptiste Daroussin 		if (strcasecmp (target, "string") == 0) {
167239ee7a7aSBaptiste Daroussin 			obj = ucl_object_fromstring_common (buf, buflen, flags);
167339ee7a7aSBaptiste Daroussin 			ucl_copy_value_trash (obj);
167439ee7a7aSBaptiste Daroussin 			if (multiline) {
167539ee7a7aSBaptiste Daroussin 				obj->flags |= UCL_OBJECT_MULTILINE;
167639ee7a7aSBaptiste Daroussin 			}
167739ee7a7aSBaptiste Daroussin 		}
167839ee7a7aSBaptiste Daroussin 		else if (strcasecmp (target, "int") == 0) {
1679d9f0ce31SBaptiste Daroussin 			tmp = malloc (buflen + 1);
1680d9f0ce31SBaptiste Daroussin 
1681d9f0ce31SBaptiste Daroussin 			if (tmp == NULL) {
1682d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "Memory allocation failed");
1683d9f0ce31SBaptiste Daroussin 				if (buf) {
1684d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
168539ee7a7aSBaptiste Daroussin 				}
168639ee7a7aSBaptiste Daroussin 
1687d9f0ce31SBaptiste Daroussin 				return false;
1688d9f0ce31SBaptiste Daroussin 			}
1689d9f0ce31SBaptiste Daroussin 
1690d9f0ce31SBaptiste Daroussin 			snprintf (tmp, buflen + 1, "%.*s", (int)buflen, buf);
1691d9f0ce31SBaptiste Daroussin 			iv = strtoll (tmp, NULL, 10);
1692d9f0ce31SBaptiste Daroussin 			obj = ucl_object_fromint (iv);
1693d9f0ce31SBaptiste Daroussin 			free (tmp);
1694d9f0ce31SBaptiste Daroussin 		}
1695d9f0ce31SBaptiste Daroussin 
1696d9f0ce31SBaptiste Daroussin 		if (buf) {
169739ee7a7aSBaptiste Daroussin 			ucl_munmap (buf, buflen);
169839ee7a7aSBaptiste Daroussin 		}
169939ee7a7aSBaptiste Daroussin 
170039ee7a7aSBaptiste Daroussin 		if (obj != NULL) {
170139ee7a7aSBaptiste Daroussin 			obj->key = prefix;
170239ee7a7aSBaptiste Daroussin 			obj->keylen = strlen (prefix);
170339ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash (obj);
170439ee7a7aSBaptiste Daroussin 			obj->prev = obj;
170539ee7a7aSBaptiste Daroussin 			obj->next = NULL;
170639ee7a7aSBaptiste Daroussin 			ucl_object_set_priority (obj, priority);
1707d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (container, obj, obj->key, obj->keylen, false);
170839ee7a7aSBaptiste Daroussin 		}
1709d9f0ce31SBaptiste Daroussin 
171039ee7a7aSBaptiste Daroussin 		return true;
171139ee7a7aSBaptiste Daroussin 	}
171239ee7a7aSBaptiste Daroussin 
171339ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse load macro");
171439ee7a7aSBaptiste Daroussin 	return false;
171539ee7a7aSBaptiste Daroussin }
171639ee7a7aSBaptiste Daroussin 
171739ee7a7aSBaptiste Daroussin bool
171839ee7a7aSBaptiste Daroussin ucl_inherit_handler (const unsigned char *data, size_t len,
171939ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, const ucl_object_t *ctx, void* ud)
172039ee7a7aSBaptiste Daroussin {
172139ee7a7aSBaptiste Daroussin 	const ucl_object_t *parent, *cur;
172239ee7a7aSBaptiste Daroussin 	ucl_object_t *target, *copy;
172339ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
172439ee7a7aSBaptiste Daroussin 	bool replace = false;
172539ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
172639ee7a7aSBaptiste Daroussin 
1727d9f0ce31SBaptiste Daroussin 	parent = ucl_object_lookup_len (ctx, data, len);
172839ee7a7aSBaptiste Daroussin 
172939ee7a7aSBaptiste Daroussin 	/* Some sanity checks */
173039ee7a7aSBaptiste Daroussin 	if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) {
173139ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Unable to find inherited object %*.s",
173239ee7a7aSBaptiste Daroussin 				(int)len, data);
173339ee7a7aSBaptiste Daroussin 		return false;
173439ee7a7aSBaptiste Daroussin 	}
173539ee7a7aSBaptiste Daroussin 
173639ee7a7aSBaptiste Daroussin 	if (parser->stack == NULL || parser->stack->obj == NULL ||
173739ee7a7aSBaptiste Daroussin 			ucl_object_type (parser->stack->obj) != UCL_OBJECT) {
173839ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Invalid inherit context");
173939ee7a7aSBaptiste Daroussin 		return false;
174039ee7a7aSBaptiste Daroussin 	}
174139ee7a7aSBaptiste Daroussin 
174239ee7a7aSBaptiste Daroussin 	target = parser->stack->obj;
174339ee7a7aSBaptiste Daroussin 
1744d9f0ce31SBaptiste Daroussin 	if (args && (cur = ucl_object_lookup (args, "replace")) != NULL) {
174539ee7a7aSBaptiste Daroussin 		replace = ucl_object_toboolean (cur);
174639ee7a7aSBaptiste Daroussin 	}
174739ee7a7aSBaptiste Daroussin 
1748d9f0ce31SBaptiste Daroussin 	while ((cur = ucl_object_iterate (parent, &it, true))) {
174939ee7a7aSBaptiste Daroussin 		/* We do not replace existing keys */
1750d9f0ce31SBaptiste Daroussin 		if (!replace && ucl_object_lookup_len (target, cur->key, cur->keylen)) {
175139ee7a7aSBaptiste Daroussin 			continue;
175239ee7a7aSBaptiste Daroussin 		}
175339ee7a7aSBaptiste Daroussin 
175439ee7a7aSBaptiste Daroussin 		copy = ucl_object_copy (cur);
175539ee7a7aSBaptiste Daroussin 
175639ee7a7aSBaptiste Daroussin 		if (!replace) {
175739ee7a7aSBaptiste Daroussin 			copy->flags |= UCL_OBJECT_INHERITED;
175839ee7a7aSBaptiste Daroussin 		}
175939ee7a7aSBaptiste Daroussin 
176039ee7a7aSBaptiste Daroussin 		ucl_object_insert_key (target, copy, copy->key,
176139ee7a7aSBaptiste Daroussin 				copy->keylen, false);
176239ee7a7aSBaptiste Daroussin 	}
176339ee7a7aSBaptiste Daroussin 
176439ee7a7aSBaptiste Daroussin 	return true;
176539ee7a7aSBaptiste Daroussin }
176639ee7a7aSBaptiste Daroussin 
176739ee7a7aSBaptiste Daroussin bool
1768c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
1769c99fb5f9SBaptiste Daroussin {
1770c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX], *curdir;
1771c99fb5f9SBaptiste Daroussin 
1772c99fb5f9SBaptiste Daroussin 	if (filename != NULL) {
1773c99fb5f9SBaptiste Daroussin 		if (need_expand) {
177497bd480fSBaptiste Daroussin 			if (ucl_realpath (filename, realbuf) == NULL) {
1775c99fb5f9SBaptiste Daroussin 				return false;
1776c99fb5f9SBaptiste Daroussin 			}
1777c99fb5f9SBaptiste Daroussin 		}
1778c99fb5f9SBaptiste Daroussin 		else {
1779c99fb5f9SBaptiste Daroussin 			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
1780c99fb5f9SBaptiste Daroussin 		}
1781c99fb5f9SBaptiste Daroussin 
1782c99fb5f9SBaptiste Daroussin 		/* Define variables */
1783c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", realbuf);
1784c99fb5f9SBaptiste Daroussin 		curdir = dirname (realbuf);
1785c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1786c99fb5f9SBaptiste Daroussin 	}
1787c99fb5f9SBaptiste Daroussin 	else {
1788c99fb5f9SBaptiste Daroussin 		/* Set everything from the current dir */
1789c99fb5f9SBaptiste Daroussin 		curdir = getcwd (realbuf, sizeof (realbuf));
1790c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", "undef");
1791c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1792c99fb5f9SBaptiste Daroussin 	}
1793c99fb5f9SBaptiste Daroussin 
1794c99fb5f9SBaptiste Daroussin 	return true;
1795c99fb5f9SBaptiste Daroussin }
1796c99fb5f9SBaptiste Daroussin 
179739ee7a7aSBaptiste Daroussin bool
179839ee7a7aSBaptiste Daroussin ucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename,
179939ee7a7aSBaptiste Daroussin 		unsigned priority)
1800c99fb5f9SBaptiste Daroussin {
1801c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
1802c99fb5f9SBaptiste Daroussin 	size_t len;
1803c99fb5f9SBaptiste Daroussin 	bool ret;
1804c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX];
1805c99fb5f9SBaptiste Daroussin 
180697bd480fSBaptiste Daroussin 	if (ucl_realpath (filename, realbuf) == NULL) {
1807c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
1808c99fb5f9SBaptiste Daroussin 				filename,
1809c99fb5f9SBaptiste Daroussin 				strerror (errno));
1810c99fb5f9SBaptiste Daroussin 		return false;
1811c99fb5f9SBaptiste Daroussin 	}
1812c99fb5f9SBaptiste Daroussin 
1813c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
1814c99fb5f9SBaptiste Daroussin 		return false;
1815c99fb5f9SBaptiste Daroussin 	}
1816c99fb5f9SBaptiste Daroussin 
18174bf54857SBaptiste Daroussin 	if (parser->cur_file) {
18184bf54857SBaptiste Daroussin 		free (parser->cur_file);
18194bf54857SBaptiste Daroussin 	}
18204bf54857SBaptiste Daroussin 	parser->cur_file = strdup (realbuf);
1821c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
182239ee7a7aSBaptiste Daroussin 	ret = ucl_parser_add_chunk_priority (parser, buf, len, priority);
1823c99fb5f9SBaptiste Daroussin 
1824c99fb5f9SBaptiste Daroussin 	if (len > 0) {
182597bd480fSBaptiste Daroussin 		ucl_munmap (buf, len);
1826c99fb5f9SBaptiste Daroussin 	}
1827c99fb5f9SBaptiste Daroussin 
1828c99fb5f9SBaptiste Daroussin 	return ret;
1829c99fb5f9SBaptiste Daroussin }
1830c99fb5f9SBaptiste Daroussin 
183139ee7a7aSBaptiste Daroussin bool
183239ee7a7aSBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
183339ee7a7aSBaptiste Daroussin {
183439ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
183539ee7a7aSBaptiste Daroussin 		return false;
183639ee7a7aSBaptiste Daroussin 	}
183739ee7a7aSBaptiste Daroussin 
183839ee7a7aSBaptiste Daroussin 	return ucl_parser_add_file_priority(parser, filename,
183939ee7a7aSBaptiste Daroussin 			parser->default_priority);
184039ee7a7aSBaptiste Daroussin }
184139ee7a7aSBaptiste Daroussin 
184239ee7a7aSBaptiste Daroussin bool
184339ee7a7aSBaptiste Daroussin ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
184439ee7a7aSBaptiste Daroussin 		unsigned priority)
18454bf54857SBaptiste Daroussin {
18464bf54857SBaptiste Daroussin 	unsigned char *buf;
18474bf54857SBaptiste Daroussin 	size_t len;
18484bf54857SBaptiste Daroussin 	bool ret;
18494bf54857SBaptiste Daroussin 	struct stat st;
18504bf54857SBaptiste Daroussin 
18514bf54857SBaptiste Daroussin 	if (fstat (fd, &st) == -1) {
18524bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot stat fd %d: %s",
18534bf54857SBaptiste Daroussin 			fd, strerror (errno));
18544bf54857SBaptiste Daroussin 		return false;
18554bf54857SBaptiste Daroussin 	}
1856*6525738fSBaptiste Daroussin 	if (st.st_size == 0) {
1857*6525738fSBaptiste Daroussin 		return true;
1858*6525738fSBaptiste Daroussin 	}
18594bf54857SBaptiste Daroussin 	if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
18604bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
18614bf54857SBaptiste Daroussin 			fd, strerror (errno));
18624bf54857SBaptiste Daroussin 		return false;
18634bf54857SBaptiste Daroussin 	}
18644bf54857SBaptiste Daroussin 
18654bf54857SBaptiste Daroussin 	if (parser->cur_file) {
18664bf54857SBaptiste Daroussin 		free (parser->cur_file);
18674bf54857SBaptiste Daroussin 	}
18684bf54857SBaptiste Daroussin 	parser->cur_file = NULL;
18694bf54857SBaptiste Daroussin 	len = st.st_size;
187039ee7a7aSBaptiste Daroussin 	ret = ucl_parser_add_chunk_priority (parser, buf, len, priority);
18714bf54857SBaptiste Daroussin 
18724bf54857SBaptiste Daroussin 	if (len > 0) {
18734bf54857SBaptiste Daroussin 		ucl_munmap (buf, len);
18744bf54857SBaptiste Daroussin 	}
18754bf54857SBaptiste Daroussin 
18764bf54857SBaptiste Daroussin 	return ret;
18774bf54857SBaptiste Daroussin }
18784bf54857SBaptiste Daroussin 
187939ee7a7aSBaptiste Daroussin bool
188039ee7a7aSBaptiste Daroussin ucl_parser_add_fd (struct ucl_parser *parser, int fd)
188139ee7a7aSBaptiste Daroussin {
188239ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
188339ee7a7aSBaptiste Daroussin 		return false;
188439ee7a7aSBaptiste Daroussin 	}
188539ee7a7aSBaptiste Daroussin 
188639ee7a7aSBaptiste Daroussin 	return ucl_parser_add_fd_priority(parser, fd, parser->default_priority);
188739ee7a7aSBaptiste Daroussin }
188839ee7a7aSBaptiste Daroussin 
1889c99fb5f9SBaptiste Daroussin size_t
1890c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz)
1891c99fb5f9SBaptiste Daroussin {
1892c99fb5f9SBaptiste Daroussin 	char *d = dst;
1893c99fb5f9SBaptiste Daroussin 	const char *s = src;
1894c99fb5f9SBaptiste Daroussin 	size_t n = siz;
1895c99fb5f9SBaptiste Daroussin 
1896c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1897c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1898c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1899c99fb5f9SBaptiste Daroussin 			if ((*d++ = *s++) == '\0') {
1900c99fb5f9SBaptiste Daroussin 				break;
1901c99fb5f9SBaptiste Daroussin 			}
1902c99fb5f9SBaptiste Daroussin 		}
1903c99fb5f9SBaptiste Daroussin 	}
1904c99fb5f9SBaptiste Daroussin 
1905c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1906c99fb5f9SBaptiste Daroussin 		*d = '\0';
1907c99fb5f9SBaptiste Daroussin 	}
1908c99fb5f9SBaptiste Daroussin 
1909c99fb5f9SBaptiste Daroussin 	return (s - src - 1);    /* count does not include NUL */
1910c99fb5f9SBaptiste Daroussin }
1911c99fb5f9SBaptiste Daroussin 
1912c99fb5f9SBaptiste Daroussin size_t
1913c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
1914c99fb5f9SBaptiste Daroussin {
1915c99fb5f9SBaptiste Daroussin 	memcpy (dst, src, siz - 1);
1916c99fb5f9SBaptiste Daroussin 	dst[siz - 1] = '\0';
1917c99fb5f9SBaptiste Daroussin 
1918c99fb5f9SBaptiste Daroussin 	return siz - 1;
1919c99fb5f9SBaptiste Daroussin }
1920c99fb5f9SBaptiste Daroussin 
1921c99fb5f9SBaptiste Daroussin size_t
1922c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
1923c99fb5f9SBaptiste Daroussin {
1924c99fb5f9SBaptiste Daroussin 	char *d = dst;
1925c99fb5f9SBaptiste Daroussin 	const char *s = src;
1926c99fb5f9SBaptiste Daroussin 	size_t n = siz;
1927c99fb5f9SBaptiste Daroussin 
1928c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1929c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1930c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1931c99fb5f9SBaptiste Daroussin 			if ((*d++ = tolower (*s++)) == '\0') {
1932c99fb5f9SBaptiste Daroussin 				break;
1933c99fb5f9SBaptiste Daroussin 			}
1934c99fb5f9SBaptiste Daroussin 		}
1935c99fb5f9SBaptiste Daroussin 	}
1936c99fb5f9SBaptiste Daroussin 
1937c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1938c99fb5f9SBaptiste Daroussin 		*d = '\0';
1939c99fb5f9SBaptiste Daroussin 	}
1940c99fb5f9SBaptiste Daroussin 
1941c99fb5f9SBaptiste Daroussin 	return (s - src);    /* count does not include NUL */
1942c99fb5f9SBaptiste Daroussin }
1943c99fb5f9SBaptiste Daroussin 
194439ee7a7aSBaptiste Daroussin /*
194539ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s
194639ee7a7aSBaptiste Daroussin  */
194739ee7a7aSBaptiste Daroussin char *
194839ee7a7aSBaptiste Daroussin ucl_strnstr (const char *s, const char *find, int len)
194939ee7a7aSBaptiste Daroussin {
195039ee7a7aSBaptiste Daroussin 	char c, sc;
195139ee7a7aSBaptiste Daroussin 	int mlen;
195239ee7a7aSBaptiste Daroussin 
195339ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
195439ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
195539ee7a7aSBaptiste Daroussin 		do {
195639ee7a7aSBaptiste Daroussin 			do {
195739ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
195839ee7a7aSBaptiste Daroussin 					return (NULL);
195939ee7a7aSBaptiste Daroussin 			} while (sc != c);
196039ee7a7aSBaptiste Daroussin 		} while (strncmp (s, find, mlen) != 0);
196139ee7a7aSBaptiste Daroussin 		s--;
196239ee7a7aSBaptiste Daroussin 	}
196339ee7a7aSBaptiste Daroussin 	return ((char *)s);
196439ee7a7aSBaptiste Daroussin }
196539ee7a7aSBaptiste Daroussin 
196639ee7a7aSBaptiste Daroussin /*
196739ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s, ignore case.
196839ee7a7aSBaptiste Daroussin  */
196939ee7a7aSBaptiste Daroussin char *
197039ee7a7aSBaptiste Daroussin ucl_strncasestr (const char *s, const char *find, int len)
197139ee7a7aSBaptiste Daroussin {
197239ee7a7aSBaptiste Daroussin 	char c, sc;
197339ee7a7aSBaptiste Daroussin 	int mlen;
197439ee7a7aSBaptiste Daroussin 
197539ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
197639ee7a7aSBaptiste Daroussin 		c = tolower (c);
197739ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
197839ee7a7aSBaptiste Daroussin 		do {
197939ee7a7aSBaptiste Daroussin 			do {
198039ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
198139ee7a7aSBaptiste Daroussin 					return (NULL);
198239ee7a7aSBaptiste Daroussin 			} while (tolower (sc) != c);
198339ee7a7aSBaptiste Daroussin 		} while (strncasecmp (s, find, mlen) != 0);
198439ee7a7aSBaptiste Daroussin 		s--;
198539ee7a7aSBaptiste Daroussin 	}
198639ee7a7aSBaptiste Daroussin 	return ((char *)s);
198739ee7a7aSBaptiste Daroussin }
198839ee7a7aSBaptiste Daroussin 
1989c99fb5f9SBaptiste Daroussin ucl_object_t *
1990c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
1991c99fb5f9SBaptiste Daroussin {
1992c99fb5f9SBaptiste Daroussin 	ucl_object_t *obj;
1993c99fb5f9SBaptiste Daroussin 	const char *start, *end, *p, *pos;
1994c99fb5f9SBaptiste Daroussin 	char *dst, *d;
1995c99fb5f9SBaptiste Daroussin 	size_t escaped_len;
1996c99fb5f9SBaptiste Daroussin 
1997c99fb5f9SBaptiste Daroussin 	if (str == NULL) {
1998c99fb5f9SBaptiste Daroussin 		return NULL;
1999c99fb5f9SBaptiste Daroussin 	}
2000c99fb5f9SBaptiste Daroussin 
2001c99fb5f9SBaptiste Daroussin 	obj = ucl_object_new ();
2002c99fb5f9SBaptiste Daroussin 	if (obj) {
2003c99fb5f9SBaptiste Daroussin 		if (len == 0) {
2004c99fb5f9SBaptiste Daroussin 			len = strlen (str);
2005c99fb5f9SBaptiste Daroussin 		}
2006c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_TRIM) {
2007c99fb5f9SBaptiste Daroussin 			/* Skip leading spaces */
2008c99fb5f9SBaptiste Daroussin 			for (start = str; (size_t)(start - str) < len; start ++) {
2009c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2010c99fb5f9SBaptiste Daroussin 					break;
2011c99fb5f9SBaptiste Daroussin 				}
2012c99fb5f9SBaptiste Daroussin 			}
2013c99fb5f9SBaptiste Daroussin 			/* Skip trailing spaces */
2014c99fb5f9SBaptiste Daroussin 			for (end = str + len - 1; end > start; end --) {
2015c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2016c99fb5f9SBaptiste Daroussin 					break;
2017c99fb5f9SBaptiste Daroussin 				}
2018c99fb5f9SBaptiste Daroussin 			}
2019c99fb5f9SBaptiste Daroussin 			end ++;
2020c99fb5f9SBaptiste Daroussin 		}
2021c99fb5f9SBaptiste Daroussin 		else {
2022c99fb5f9SBaptiste Daroussin 			start = str;
2023c99fb5f9SBaptiste Daroussin 			end = str + len;
2024c99fb5f9SBaptiste Daroussin 		}
2025c99fb5f9SBaptiste Daroussin 
2026c99fb5f9SBaptiste Daroussin 		obj->type = UCL_STRING;
2027c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_ESCAPE) {
2028c99fb5f9SBaptiste Daroussin 			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
2029c99fb5f9SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
2030c99fb5f9SBaptiste Daroussin 					escaped_len ++;
2031c99fb5f9SBaptiste Daroussin 				}
2032c99fb5f9SBaptiste Daroussin 			}
2033c99fb5f9SBaptiste Daroussin 			dst = malloc (escaped_len + 1);
2034c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2035c99fb5f9SBaptiste Daroussin 				for (p = start, d = dst; p < end; p ++, d ++) {
2036c99fb5f9SBaptiste Daroussin 					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
2037c99fb5f9SBaptiste Daroussin 						switch (*p) {
2038c99fb5f9SBaptiste Daroussin 						case '\n':
2039c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2040c99fb5f9SBaptiste Daroussin 							*d = 'n';
2041c99fb5f9SBaptiste Daroussin 							break;
2042c99fb5f9SBaptiste Daroussin 						case '\r':
2043c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2044c99fb5f9SBaptiste Daroussin 							*d = 'r';
2045c99fb5f9SBaptiste Daroussin 							break;
2046c99fb5f9SBaptiste Daroussin 						case '\b':
2047c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2048c99fb5f9SBaptiste Daroussin 							*d = 'b';
2049c99fb5f9SBaptiste Daroussin 							break;
2050c99fb5f9SBaptiste Daroussin 						case '\t':
2051c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2052c99fb5f9SBaptiste Daroussin 							*d = 't';
2053c99fb5f9SBaptiste Daroussin 							break;
2054c99fb5f9SBaptiste Daroussin 						case '\f':
2055c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2056c99fb5f9SBaptiste Daroussin 							*d = 'f';
2057c99fb5f9SBaptiste Daroussin 							break;
2058c99fb5f9SBaptiste Daroussin 						case '\\':
2059c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2060c99fb5f9SBaptiste Daroussin 							*d = '\\';
2061c99fb5f9SBaptiste Daroussin 							break;
2062c99fb5f9SBaptiste Daroussin 						case '"':
2063c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2064c99fb5f9SBaptiste Daroussin 							*d = '"';
2065c99fb5f9SBaptiste Daroussin 							break;
2066c99fb5f9SBaptiste Daroussin 						}
2067c99fb5f9SBaptiste Daroussin 					}
2068c99fb5f9SBaptiste Daroussin 					else {
2069c99fb5f9SBaptiste Daroussin 						*d = *p;
2070c99fb5f9SBaptiste Daroussin 					}
2071c99fb5f9SBaptiste Daroussin 				}
2072c99fb5f9SBaptiste Daroussin 				*d = '\0';
2073c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2074c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2075c99fb5f9SBaptiste Daroussin 				obj->len = escaped_len;
2076c99fb5f9SBaptiste Daroussin 			}
2077c99fb5f9SBaptiste Daroussin 		}
2078c99fb5f9SBaptiste Daroussin 		else {
2079c99fb5f9SBaptiste Daroussin 			dst = malloc (end - start + 1);
2080c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2081c99fb5f9SBaptiste Daroussin 				ucl_strlcpy_unsafe (dst, start, end - start + 1);
2082c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2083c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2084c99fb5f9SBaptiste Daroussin 				obj->len = end - start;
2085c99fb5f9SBaptiste Daroussin 			}
2086c99fb5f9SBaptiste Daroussin 		}
2087c99fb5f9SBaptiste Daroussin 		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
2088c99fb5f9SBaptiste Daroussin 			/* Parse what we have */
2089c99fb5f9SBaptiste Daroussin 			if (flags & UCL_STRING_PARSE_BOOLEAN) {
2090c99fb5f9SBaptiste Daroussin 				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
2091c99fb5f9SBaptiste Daroussin 					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2092c99fb5f9SBaptiste Daroussin 							flags & UCL_STRING_PARSE_DOUBLE,
209397bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_BYTES,
209497bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_TIME);
2095c99fb5f9SBaptiste Daroussin 				}
2096c99fb5f9SBaptiste Daroussin 			}
2097c99fb5f9SBaptiste Daroussin 			else {
2098c99fb5f9SBaptiste Daroussin 				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2099c99fb5f9SBaptiste Daroussin 						flags & UCL_STRING_PARSE_DOUBLE,
210097bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_BYTES,
210197bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_TIME);
2102c99fb5f9SBaptiste Daroussin 			}
2103c99fb5f9SBaptiste Daroussin 		}
2104c99fb5f9SBaptiste Daroussin 	}
2105c99fb5f9SBaptiste Daroussin 
2106c99fb5f9SBaptiste Daroussin 	return obj;
2107c99fb5f9SBaptiste Daroussin }
2108c99fb5f9SBaptiste Daroussin 
2109b04a7a0bSBaptiste Daroussin static bool
2110c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
2111c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
2112c99fb5f9SBaptiste Daroussin {
2113b04a7a0bSBaptiste Daroussin 	ucl_object_t *found, *tmp;
2114b04a7a0bSBaptiste Daroussin 	const ucl_object_t *cur;
2115c99fb5f9SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
2116c99fb5f9SBaptiste Daroussin 	const char *p;
2117b04a7a0bSBaptiste Daroussin 	int ret = true;
2118c99fb5f9SBaptiste Daroussin 
2119c99fb5f9SBaptiste Daroussin 	if (elt == NULL || key == NULL) {
2120b04a7a0bSBaptiste Daroussin 		return false;
2121c99fb5f9SBaptiste Daroussin 	}
2122c99fb5f9SBaptiste Daroussin 
2123c99fb5f9SBaptiste Daroussin 	if (top == NULL) {
2124b04a7a0bSBaptiste Daroussin 		return false;
2125c99fb5f9SBaptiste Daroussin 	}
2126c99fb5f9SBaptiste Daroussin 
2127c99fb5f9SBaptiste Daroussin 	if (top->type != UCL_OBJECT) {
2128c99fb5f9SBaptiste Daroussin 		/* It is possible to convert NULL type to an object */
2129c99fb5f9SBaptiste Daroussin 		if (top->type == UCL_NULL) {
2130c99fb5f9SBaptiste Daroussin 			top->type = UCL_OBJECT;
2131c99fb5f9SBaptiste Daroussin 		}
2132c99fb5f9SBaptiste Daroussin 		else {
2133c99fb5f9SBaptiste Daroussin 			/* Refuse converting of other object types */
2134b04a7a0bSBaptiste Daroussin 			return false;
2135c99fb5f9SBaptiste Daroussin 		}
2136c99fb5f9SBaptiste Daroussin 	}
2137c99fb5f9SBaptiste Daroussin 
2138c99fb5f9SBaptiste Daroussin 	if (top->value.ov == NULL) {
21398e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_create (false);
2140c99fb5f9SBaptiste Daroussin 	}
2141c99fb5f9SBaptiste Daroussin 
2142c99fb5f9SBaptiste Daroussin 	if (keylen == 0) {
2143c99fb5f9SBaptiste Daroussin 		keylen = strlen (key);
2144c99fb5f9SBaptiste Daroussin 	}
2145c99fb5f9SBaptiste Daroussin 
2146c99fb5f9SBaptiste Daroussin 	for (p = key; p < key + keylen; p ++) {
2147c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
2148c99fb5f9SBaptiste Daroussin 			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
2149c99fb5f9SBaptiste Daroussin 			break;
2150c99fb5f9SBaptiste Daroussin 		}
2151c99fb5f9SBaptiste Daroussin 	}
2152c99fb5f9SBaptiste Daroussin 
21534bf54857SBaptiste Daroussin 	/* workaround for some use cases */
21544bf54857SBaptiste Daroussin 	if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
21554bf54857SBaptiste Daroussin 			key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
21564bf54857SBaptiste Daroussin 		/* Remove copied key */
21574bf54857SBaptiste Daroussin 		free (elt->trash_stack[UCL_TRASH_KEY]);
21584bf54857SBaptiste Daroussin 		elt->trash_stack[UCL_TRASH_KEY] = NULL;
21594bf54857SBaptiste Daroussin 		elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
21604bf54857SBaptiste Daroussin 	}
21614bf54857SBaptiste Daroussin 
2162c99fb5f9SBaptiste Daroussin 	elt->key = key;
2163c99fb5f9SBaptiste Daroussin 	elt->keylen = keylen;
2164c99fb5f9SBaptiste Daroussin 
2165c99fb5f9SBaptiste Daroussin 	if (copy_key) {
2166c99fb5f9SBaptiste Daroussin 		ucl_copy_key_trash (elt);
2167c99fb5f9SBaptiste Daroussin 	}
2168c99fb5f9SBaptiste Daroussin 
2169b04a7a0bSBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
2170c99fb5f9SBaptiste Daroussin 
21714bf54857SBaptiste Daroussin 	if (found == NULL) {
21728e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
217397bd480fSBaptiste Daroussin 		top->len ++;
2174b04a7a0bSBaptiste Daroussin 		if (replace) {
2175b04a7a0bSBaptiste Daroussin 			ret = false;
2176b04a7a0bSBaptiste Daroussin 		}
2177c99fb5f9SBaptiste Daroussin 	}
2178c99fb5f9SBaptiste Daroussin 	else {
2179c99fb5f9SBaptiste Daroussin 		if (replace) {
21804bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, elt);
2181c99fb5f9SBaptiste Daroussin 			ucl_object_unref (found);
2182c99fb5f9SBaptiste Daroussin 		}
2183c99fb5f9SBaptiste Daroussin 		else if (merge) {
2184c99fb5f9SBaptiste Daroussin 			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
2185c99fb5f9SBaptiste Daroussin 				/* Insert old elt to new one */
2186b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (elt, found, found->key,
2187b04a7a0bSBaptiste Daroussin 						found->keylen, copy_key, false, false);
2188c99fb5f9SBaptiste Daroussin 				ucl_hash_delete (top->value.ov, found);
21898e3b1ab2SBaptiste Daroussin 				top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
2190c99fb5f9SBaptiste Daroussin 			}
2191c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
2192c99fb5f9SBaptiste Daroussin 				/* Insert new to old */
2193b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (found, elt, elt->key,
2194b04a7a0bSBaptiste Daroussin 						elt->keylen, copy_key, false, false);
2195c99fb5f9SBaptiste Daroussin 			}
2196c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
2197c99fb5f9SBaptiste Daroussin 				/* Mix two hashes */
2198d9f0ce31SBaptiste Daroussin 				while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
2199b04a7a0bSBaptiste Daroussin 					tmp = ucl_object_ref (cur);
2200b04a7a0bSBaptiste Daroussin 					ucl_object_insert_key_common (found, tmp, cur->key,
2201b04a7a0bSBaptiste Daroussin 							cur->keylen, copy_key, false, false);
2202c99fb5f9SBaptiste Daroussin 				}
2203c99fb5f9SBaptiste Daroussin 				ucl_object_unref (elt);
2204c99fb5f9SBaptiste Daroussin 			}
2205c99fb5f9SBaptiste Daroussin 			else {
2206c99fb5f9SBaptiste Daroussin 				/* Just make a list of scalars */
2207c99fb5f9SBaptiste Daroussin 				DL_APPEND (found, elt);
2208c99fb5f9SBaptiste Daroussin 			}
2209c99fb5f9SBaptiste Daroussin 		}
2210c99fb5f9SBaptiste Daroussin 		else {
2211c99fb5f9SBaptiste Daroussin 			DL_APPEND (found, elt);
2212c99fb5f9SBaptiste Daroussin 		}
2213c99fb5f9SBaptiste Daroussin 	}
2214c99fb5f9SBaptiste Daroussin 
2215b04a7a0bSBaptiste Daroussin 	return ret;
2216c99fb5f9SBaptiste Daroussin }
2217c99fb5f9SBaptiste Daroussin 
221836c53d67SBaptiste Daroussin bool
221936c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
222036c53d67SBaptiste Daroussin {
222136c53d67SBaptiste Daroussin 	ucl_object_t *found;
222236c53d67SBaptiste Daroussin 
222397bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
222497bd480fSBaptiste Daroussin 		return false;
222597bd480fSBaptiste Daroussin 	}
222697bd480fSBaptiste Daroussin 
2227d9f0ce31SBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_object_lookup_len (top, key, keylen));
222836c53d67SBaptiste Daroussin 
222997bd480fSBaptiste Daroussin 	if (found == NULL) {
223036c53d67SBaptiste Daroussin 		return false;
223197bd480fSBaptiste Daroussin 	}
223236c53d67SBaptiste Daroussin 
223336c53d67SBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
223436c53d67SBaptiste Daroussin 	ucl_object_unref (found);
223536c53d67SBaptiste Daroussin 	top->len --;
223636c53d67SBaptiste Daroussin 
223736c53d67SBaptiste Daroussin 	return true;
223836c53d67SBaptiste Daroussin }
223936c53d67SBaptiste Daroussin 
224036c53d67SBaptiste Daroussin bool
224136c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key)
224236c53d67SBaptiste Daroussin {
2243b04a7a0bSBaptiste Daroussin 	return ucl_object_delete_keyl (top, key, strlen (key));
224436c53d67SBaptiste Daroussin }
224536c53d67SBaptiste Daroussin 
2246c99fb5f9SBaptiste Daroussin ucl_object_t*
224797bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
224897bd480fSBaptiste Daroussin {
2249b04a7a0bSBaptiste Daroussin 	const ucl_object_t *found;
225097bd480fSBaptiste Daroussin 
225197bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
225297bd480fSBaptiste Daroussin 		return false;
225397bd480fSBaptiste Daroussin 	}
2254d9f0ce31SBaptiste Daroussin 	found = ucl_object_lookup_len (top, key, keylen);
225597bd480fSBaptiste Daroussin 
225697bd480fSBaptiste Daroussin 	if (found == NULL) {
225797bd480fSBaptiste Daroussin 		return NULL;
225897bd480fSBaptiste Daroussin 	}
225997bd480fSBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
226097bd480fSBaptiste Daroussin 	top->len --;
226197bd480fSBaptiste Daroussin 
2262b04a7a0bSBaptiste Daroussin 	return __DECONST (ucl_object_t *, found);
226397bd480fSBaptiste Daroussin }
226497bd480fSBaptiste Daroussin 
226597bd480fSBaptiste Daroussin ucl_object_t*
226697bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key)
226797bd480fSBaptiste Daroussin {
2268b04a7a0bSBaptiste Daroussin 	return ucl_object_pop_keyl (top, key, strlen (key));
226997bd480fSBaptiste Daroussin }
227097bd480fSBaptiste Daroussin 
2271b04a7a0bSBaptiste Daroussin bool
2272c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
2273c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2274c99fb5f9SBaptiste Daroussin {
2275c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
2276c99fb5f9SBaptiste Daroussin }
2277c99fb5f9SBaptiste Daroussin 
2278b04a7a0bSBaptiste Daroussin bool
2279c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
2280c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2281c99fb5f9SBaptiste Daroussin {
2282c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
2283c99fb5f9SBaptiste Daroussin }
2284c99fb5f9SBaptiste Daroussin 
2285b04a7a0bSBaptiste Daroussin bool
2286c99fb5f9SBaptiste Daroussin ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
2287c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2288c99fb5f9SBaptiste Daroussin {
2289c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
2290c99fb5f9SBaptiste Daroussin }
2291c99fb5f9SBaptiste Daroussin 
22924bf54857SBaptiste Daroussin bool
22934bf54857SBaptiste Daroussin ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
22944bf54857SBaptiste Daroussin {
22954bf54857SBaptiste Daroussin 	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
22964bf54857SBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
22974bf54857SBaptiste Daroussin 
22984bf54857SBaptiste Daroussin 	if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
22994bf54857SBaptiste Daroussin 		return false;
23004bf54857SBaptiste Daroussin 	}
23014bf54857SBaptiste Daroussin 
23024bf54857SBaptiste Daroussin 	/* Mix two hashes */
23034bf54857SBaptiste Daroussin 	while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
23044bf54857SBaptiste Daroussin 		if (copy) {
23054bf54857SBaptiste Daroussin 			cp = ucl_object_copy (cur);
23064bf54857SBaptiste Daroussin 		}
23074bf54857SBaptiste Daroussin 		else {
23084bf54857SBaptiste Daroussin 			cp = ucl_object_ref (cur);
23094bf54857SBaptiste Daroussin 		}
23104bf54857SBaptiste Daroussin 		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
23114bf54857SBaptiste Daroussin 		if (found == NULL) {
23124bf54857SBaptiste Daroussin 			/* The key does not exist */
23138e3b1ab2SBaptiste Daroussin 			top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
23144bf54857SBaptiste Daroussin 			top->len ++;
23154bf54857SBaptiste Daroussin 		}
23164bf54857SBaptiste Daroussin 		else {
23174bf54857SBaptiste Daroussin 			/* The key already exists, replace it */
23184bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, cp);
23194bf54857SBaptiste Daroussin 			ucl_object_unref (found);
23204bf54857SBaptiste Daroussin 		}
23214bf54857SBaptiste Daroussin 	}
23224bf54857SBaptiste Daroussin 
23234bf54857SBaptiste Daroussin 	return true;
23244bf54857SBaptiste Daroussin }
23254bf54857SBaptiste Daroussin 
2326b04a7a0bSBaptiste Daroussin const ucl_object_t *
2327d9f0ce31SBaptiste Daroussin ucl_object_lookup_len (const ucl_object_t *obj, const char *key, size_t klen)
2328c99fb5f9SBaptiste Daroussin {
2329b04a7a0bSBaptiste Daroussin 	const ucl_object_t *ret;
2330b04a7a0bSBaptiste Daroussin 	ucl_object_t srch;
2331c99fb5f9SBaptiste Daroussin 
2332c99fb5f9SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
2333c99fb5f9SBaptiste Daroussin 		return NULL;
2334c99fb5f9SBaptiste Daroussin 	}
2335c99fb5f9SBaptiste Daroussin 
2336c99fb5f9SBaptiste Daroussin 	srch.key = key;
2337c99fb5f9SBaptiste Daroussin 	srch.keylen = klen;
2338c99fb5f9SBaptiste Daroussin 	ret = ucl_hash_search_obj (obj->value.ov, &srch);
2339c99fb5f9SBaptiste Daroussin 
2340c99fb5f9SBaptiste Daroussin 	return ret;
2341c99fb5f9SBaptiste Daroussin }
2342c99fb5f9SBaptiste Daroussin 
2343b04a7a0bSBaptiste Daroussin const ucl_object_t *
2344d9f0ce31SBaptiste Daroussin ucl_object_lookup (const ucl_object_t *obj, const char *key)
2345c99fb5f9SBaptiste Daroussin {
234639ee7a7aSBaptiste Daroussin 	if (key == NULL) {
2347c99fb5f9SBaptiste Daroussin 		return NULL;
234839ee7a7aSBaptiste Daroussin 	}
2349c99fb5f9SBaptiste Daroussin 
2350d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_len (obj, key, strlen (key));
2351c99fb5f9SBaptiste Daroussin }
2352c99fb5f9SBaptiste Daroussin 
2353b04a7a0bSBaptiste Daroussin const ucl_object_t*
2354d9f0ce31SBaptiste Daroussin ucl_object_lookup_any (const ucl_object_t *obj,
235539ee7a7aSBaptiste Daroussin 		const char *key, ...)
235639ee7a7aSBaptiste Daroussin {
235739ee7a7aSBaptiste Daroussin 	va_list ap;
235839ee7a7aSBaptiste Daroussin 	const ucl_object_t *ret = NULL;
235939ee7a7aSBaptiste Daroussin 	const char *nk = NULL;
236039ee7a7aSBaptiste Daroussin 
236139ee7a7aSBaptiste Daroussin 	if (obj == NULL || key == NULL) {
236239ee7a7aSBaptiste Daroussin 		return NULL;
236339ee7a7aSBaptiste Daroussin 	}
236439ee7a7aSBaptiste Daroussin 
2365d9f0ce31SBaptiste Daroussin 	ret = ucl_object_lookup_len (obj, key, strlen (key));
236639ee7a7aSBaptiste Daroussin 
236739ee7a7aSBaptiste Daroussin 	if (ret == NULL) {
236839ee7a7aSBaptiste Daroussin 		va_start (ap, key);
236939ee7a7aSBaptiste Daroussin 
237039ee7a7aSBaptiste Daroussin 		while (ret == NULL) {
237139ee7a7aSBaptiste Daroussin 			nk = va_arg (ap, const char *);
237239ee7a7aSBaptiste Daroussin 
237339ee7a7aSBaptiste Daroussin 			if (nk == NULL) {
237439ee7a7aSBaptiste Daroussin 				break;
237539ee7a7aSBaptiste Daroussin 			}
237639ee7a7aSBaptiste Daroussin 			else {
2377d9f0ce31SBaptiste Daroussin 				ret = ucl_object_lookup_len (obj, nk, strlen (nk));
237839ee7a7aSBaptiste Daroussin 			}
237939ee7a7aSBaptiste Daroussin 		}
238039ee7a7aSBaptiste Daroussin 
238139ee7a7aSBaptiste Daroussin 		va_end (ap);
238239ee7a7aSBaptiste Daroussin 	}
238339ee7a7aSBaptiste Daroussin 
238439ee7a7aSBaptiste Daroussin 	return ret;
238539ee7a7aSBaptiste Daroussin }
238639ee7a7aSBaptiste Daroussin 
238739ee7a7aSBaptiste Daroussin const ucl_object_t*
2388d9f0ce31SBaptiste Daroussin ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
2389c99fb5f9SBaptiste Daroussin {
23908e3b1ab2SBaptiste Daroussin 	const ucl_object_t *elt = NULL;
2391c99fb5f9SBaptiste Daroussin 
239297bd480fSBaptiste Daroussin 	if (obj == NULL || iter == NULL) {
239397bd480fSBaptiste Daroussin 		return NULL;
239497bd480fSBaptiste Daroussin 	}
239597bd480fSBaptiste Daroussin 
2396c99fb5f9SBaptiste Daroussin 	if (expand_values) {
2397c99fb5f9SBaptiste Daroussin 		switch (obj->type) {
2398c99fb5f9SBaptiste Daroussin 		case UCL_OBJECT:
2399b04a7a0bSBaptiste Daroussin 			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
2400c99fb5f9SBaptiste Daroussin 			break;
24018e3b1ab2SBaptiste Daroussin 		case UCL_ARRAY: {
24028e3b1ab2SBaptiste Daroussin 			unsigned int idx;
24038e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
24048e3b1ab2SBaptiste Daroussin 			idx = (unsigned int)(uintptr_t)(*iter);
24058e3b1ab2SBaptiste Daroussin 
24068e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
24078e3b1ab2SBaptiste Daroussin 				while (idx < kv_size (*vec)) {
24088e3b1ab2SBaptiste Daroussin 					if ((elt = kv_A (*vec, idx)) != NULL) {
24098e3b1ab2SBaptiste Daroussin 						idx ++;
24108e3b1ab2SBaptiste Daroussin 						break;
2411c99fb5f9SBaptiste Daroussin 					}
24128e3b1ab2SBaptiste Daroussin 					idx ++;
2413c99fb5f9SBaptiste Daroussin 				}
24148e3b1ab2SBaptiste Daroussin 				*iter = (void *)(uintptr_t)idx;
2415c99fb5f9SBaptiste Daroussin 			}
24168e3b1ab2SBaptiste Daroussin 
2417c99fb5f9SBaptiste Daroussin 			return elt;
24188e3b1ab2SBaptiste Daroussin 			break;
24198e3b1ab2SBaptiste Daroussin 		}
2420c99fb5f9SBaptiste Daroussin 		default:
2421c99fb5f9SBaptiste Daroussin 			/* Go to linear iteration */
2422c99fb5f9SBaptiste Daroussin 			break;
2423c99fb5f9SBaptiste Daroussin 		}
2424c99fb5f9SBaptiste Daroussin 	}
2425c99fb5f9SBaptiste Daroussin 	/* Treat everything as a linear list */
2426c99fb5f9SBaptiste Daroussin 	elt = *iter;
2427c99fb5f9SBaptiste Daroussin 	if (elt == NULL) {
2428c99fb5f9SBaptiste Daroussin 		elt = obj;
2429c99fb5f9SBaptiste Daroussin 	}
2430c99fb5f9SBaptiste Daroussin 	else if (elt == obj) {
2431c99fb5f9SBaptiste Daroussin 		return NULL;
2432c99fb5f9SBaptiste Daroussin 	}
2433b04a7a0bSBaptiste Daroussin 	*iter = __DECONST (void *, elt->next ? elt->next : obj);
2434c99fb5f9SBaptiste Daroussin 	return elt;
2435c99fb5f9SBaptiste Daroussin 
2436c99fb5f9SBaptiste Daroussin 	/* Not reached */
2437c99fb5f9SBaptiste Daroussin 	return NULL;
2438c99fb5f9SBaptiste Daroussin }
243997bd480fSBaptiste Daroussin 
24408e3b1ab2SBaptiste Daroussin const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
24418e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter {
24428e3b1ab2SBaptiste Daroussin 	char magic[4]; /* safety check */
24438e3b1ab2SBaptiste Daroussin 	const ucl_object_t *impl_it; /* implicit object iteration */
24448e3b1ab2SBaptiste Daroussin 	ucl_object_iter_t expl_it; /* explicit iteration */
24458e3b1ab2SBaptiste Daroussin };
24468e3b1ab2SBaptiste Daroussin 
24478e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr)
24488e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER_CHECK(it) do { \
24498e3b1ab2SBaptiste Daroussin 	assert (it != NULL); \
24508e3b1ab2SBaptiste Daroussin 	assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \
24518e3b1ab2SBaptiste Daroussin  } while (0)
24528e3b1ab2SBaptiste Daroussin 
24538e3b1ab2SBaptiste Daroussin ucl_object_iter_t
24548e3b1ab2SBaptiste Daroussin ucl_object_iterate_new (const ucl_object_t *obj)
24558e3b1ab2SBaptiste Daroussin {
24568e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *it;
24578e3b1ab2SBaptiste Daroussin 
24588e3b1ab2SBaptiste Daroussin 	it = UCL_ALLOC (sizeof (*it));
24598e3b1ab2SBaptiste Daroussin 	if (it != NULL) {
24608e3b1ab2SBaptiste Daroussin 		memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
24618e3b1ab2SBaptiste Daroussin 		it->expl_it = NULL;
24628e3b1ab2SBaptiste Daroussin 		it->impl_it = obj;
24638e3b1ab2SBaptiste Daroussin 	}
24648e3b1ab2SBaptiste Daroussin 
24658e3b1ab2SBaptiste Daroussin 	return (ucl_object_iter_t)it;
24668e3b1ab2SBaptiste Daroussin }
24678e3b1ab2SBaptiste Daroussin 
24688e3b1ab2SBaptiste Daroussin 
24698e3b1ab2SBaptiste Daroussin ucl_object_iter_t
24708e3b1ab2SBaptiste Daroussin ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
24718e3b1ab2SBaptiste Daroussin {
24728e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
24738e3b1ab2SBaptiste Daroussin 
24748e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
24758e3b1ab2SBaptiste Daroussin 
24768e3b1ab2SBaptiste Daroussin 	rit->impl_it = obj;
24778e3b1ab2SBaptiste Daroussin 	rit->expl_it = NULL;
24788e3b1ab2SBaptiste Daroussin 
24798e3b1ab2SBaptiste Daroussin 	return it;
24808e3b1ab2SBaptiste Daroussin }
24818e3b1ab2SBaptiste Daroussin 
24828e3b1ab2SBaptiste Daroussin const ucl_object_t*
24838e3b1ab2SBaptiste Daroussin ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
24848e3b1ab2SBaptiste Daroussin {
24858e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
24868e3b1ab2SBaptiste Daroussin 	const ucl_object_t *ret = NULL;
24878e3b1ab2SBaptiste Daroussin 
24888e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
24898e3b1ab2SBaptiste Daroussin 
24908e3b1ab2SBaptiste Daroussin 	if (rit->impl_it == NULL) {
24918e3b1ab2SBaptiste Daroussin 		return NULL;
24928e3b1ab2SBaptiste Daroussin 	}
24938e3b1ab2SBaptiste Daroussin 
24948e3b1ab2SBaptiste Daroussin 	if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
2495d9f0ce31SBaptiste Daroussin 		ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
24968e3b1ab2SBaptiste Daroussin 
24978e3b1ab2SBaptiste Daroussin 		if (ret == NULL) {
24988e3b1ab2SBaptiste Daroussin 			/* Need to switch to another implicit object in chain */
24998e3b1ab2SBaptiste Daroussin 			rit->impl_it = rit->impl_it->next;
25008e3b1ab2SBaptiste Daroussin 			rit->expl_it = NULL;
25018e3b1ab2SBaptiste Daroussin 			return ucl_object_iterate_safe (it, expand_values);
25028e3b1ab2SBaptiste Daroussin 		}
25038e3b1ab2SBaptiste Daroussin 	}
25048e3b1ab2SBaptiste Daroussin 	else {
25058e3b1ab2SBaptiste Daroussin 		/* Just iterate over the implicit array */
25068e3b1ab2SBaptiste Daroussin 		ret = rit->impl_it;
25078e3b1ab2SBaptiste Daroussin 		rit->impl_it = rit->impl_it->next;
25088e3b1ab2SBaptiste Daroussin 		if (expand_values) {
25098e3b1ab2SBaptiste Daroussin 			/* We flatten objects if need to expand values */
25108e3b1ab2SBaptiste Daroussin 			if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
25118e3b1ab2SBaptiste Daroussin 				return ucl_object_iterate_safe (it, expand_values);
25128e3b1ab2SBaptiste Daroussin 			}
25138e3b1ab2SBaptiste Daroussin 		}
25148e3b1ab2SBaptiste Daroussin 	}
25158e3b1ab2SBaptiste Daroussin 
25168e3b1ab2SBaptiste Daroussin 	return ret;
25178e3b1ab2SBaptiste Daroussin }
25188e3b1ab2SBaptiste Daroussin 
25198e3b1ab2SBaptiste Daroussin void
25208e3b1ab2SBaptiste Daroussin ucl_object_iterate_free (ucl_object_iter_t it)
25218e3b1ab2SBaptiste Daroussin {
25228e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
25238e3b1ab2SBaptiste Daroussin 
25248e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
25258e3b1ab2SBaptiste Daroussin 
25268e3b1ab2SBaptiste Daroussin 	UCL_FREE (sizeof (*rit), it);
25278e3b1ab2SBaptiste Daroussin }
25288e3b1ab2SBaptiste Daroussin 
25292e8ed2b8SBaptiste Daroussin const ucl_object_t *
2530d9f0ce31SBaptiste Daroussin ucl_object_lookup_path (const ucl_object_t *top, const char *path_in) {
2531d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_path_char (top, path_in, '.');
253239ee7a7aSBaptiste Daroussin }
253339ee7a7aSBaptiste Daroussin 
253439ee7a7aSBaptiste Daroussin 
253539ee7a7aSBaptiste Daroussin const ucl_object_t *
2536d9f0ce31SBaptiste Daroussin ucl_object_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) {
25372e8ed2b8SBaptiste Daroussin 	const ucl_object_t *o = NULL, *found;
25382e8ed2b8SBaptiste Daroussin 	const char *p, *c;
25392e8ed2b8SBaptiste Daroussin 	char *err_str;
25402e8ed2b8SBaptiste Daroussin 	unsigned index;
25412e8ed2b8SBaptiste Daroussin 
25422e8ed2b8SBaptiste Daroussin 	if (path_in == NULL || top == NULL) {
25432e8ed2b8SBaptiste Daroussin 		return NULL;
25442e8ed2b8SBaptiste Daroussin 	}
25452e8ed2b8SBaptiste Daroussin 
25462e8ed2b8SBaptiste Daroussin 	found = NULL;
25472e8ed2b8SBaptiste Daroussin 	p = path_in;
25482e8ed2b8SBaptiste Daroussin 
25492e8ed2b8SBaptiste Daroussin 	/* Skip leading dots */
255039ee7a7aSBaptiste Daroussin 	while (*p == sep) {
25512e8ed2b8SBaptiste Daroussin 		p ++;
25522e8ed2b8SBaptiste Daroussin 	}
25532e8ed2b8SBaptiste Daroussin 
25542e8ed2b8SBaptiste Daroussin 	c = p;
25552e8ed2b8SBaptiste Daroussin 	while (*p != '\0') {
25562e8ed2b8SBaptiste Daroussin 		p ++;
255739ee7a7aSBaptiste Daroussin 		if (*p == sep || *p == '\0') {
25582e8ed2b8SBaptiste Daroussin 			if (p > c) {
25592e8ed2b8SBaptiste Daroussin 				switch (top->type) {
25602e8ed2b8SBaptiste Daroussin 				case UCL_ARRAY:
25612e8ed2b8SBaptiste Daroussin 					/* Key should be an int */
25622e8ed2b8SBaptiste Daroussin 					index = strtoul (c, &err_str, 10);
256339ee7a7aSBaptiste Daroussin 					if (err_str != NULL && (*err_str != sep && *err_str != '\0')) {
25642e8ed2b8SBaptiste Daroussin 						return NULL;
25652e8ed2b8SBaptiste Daroussin 					}
25662e8ed2b8SBaptiste Daroussin 					o = ucl_array_find_index (top, index);
25672e8ed2b8SBaptiste Daroussin 					break;
25682e8ed2b8SBaptiste Daroussin 				default:
2569d9f0ce31SBaptiste Daroussin 					o = ucl_object_lookup_len (top, c, p - c);
25702e8ed2b8SBaptiste Daroussin 					break;
25712e8ed2b8SBaptiste Daroussin 				}
25722e8ed2b8SBaptiste Daroussin 				if (o == NULL) {
25732e8ed2b8SBaptiste Daroussin 					return NULL;
25742e8ed2b8SBaptiste Daroussin 				}
25752e8ed2b8SBaptiste Daroussin 				top = o;
25762e8ed2b8SBaptiste Daroussin 			}
25772e8ed2b8SBaptiste Daroussin 			if (*p != '\0') {
25782e8ed2b8SBaptiste Daroussin 				c = p + 1;
25792e8ed2b8SBaptiste Daroussin 			}
25802e8ed2b8SBaptiste Daroussin 		}
25812e8ed2b8SBaptiste Daroussin 	}
25822e8ed2b8SBaptiste Daroussin 	found = o;
25832e8ed2b8SBaptiste Daroussin 
25842e8ed2b8SBaptiste Daroussin 	return found;
25852e8ed2b8SBaptiste Daroussin }
25862e8ed2b8SBaptiste Daroussin 
258797bd480fSBaptiste Daroussin 
258897bd480fSBaptiste Daroussin ucl_object_t *
258997bd480fSBaptiste Daroussin ucl_object_new (void)
259097bd480fSBaptiste Daroussin {
25914bf54857SBaptiste Daroussin 	return ucl_object_typed_new (UCL_NULL);
259297bd480fSBaptiste Daroussin }
259397bd480fSBaptiste Daroussin 
259497bd480fSBaptiste Daroussin ucl_object_t *
25952e8ed2b8SBaptiste Daroussin ucl_object_typed_new (ucl_type_t type)
259697bd480fSBaptiste Daroussin {
25974bf54857SBaptiste Daroussin 	return ucl_object_new_full (type, 0);
25984bf54857SBaptiste Daroussin }
25994bf54857SBaptiste Daroussin 
26004bf54857SBaptiste Daroussin ucl_object_t *
26014bf54857SBaptiste Daroussin ucl_object_new_full (ucl_type_t type, unsigned priority)
26024bf54857SBaptiste Daroussin {
260397bd480fSBaptiste Daroussin 	ucl_object_t *new;
26044bf54857SBaptiste Daroussin 
26054bf54857SBaptiste Daroussin 	if (type != UCL_USERDATA) {
26064bf54857SBaptiste Daroussin 		new = UCL_ALLOC (sizeof (ucl_object_t));
260797bd480fSBaptiste Daroussin 		if (new != NULL) {
260897bd480fSBaptiste Daroussin 			memset (new, 0, sizeof (ucl_object_t));
260997bd480fSBaptiste Daroussin 			new->ref = 1;
261097bd480fSBaptiste Daroussin 			new->type = (type <= UCL_NULL ? type : UCL_NULL);
26114bf54857SBaptiste Daroussin 			new->next = NULL;
26124bf54857SBaptiste Daroussin 			new->prev = new;
26134bf54857SBaptiste Daroussin 			ucl_object_set_priority (new, priority);
26148e3b1ab2SBaptiste Daroussin 
26158e3b1ab2SBaptiste Daroussin 			if (type == UCL_ARRAY) {
26168e3b1ab2SBaptiste Daroussin 				new->value.av = UCL_ALLOC (sizeof (ucl_array_t));
26178e3b1ab2SBaptiste Daroussin 				if (new->value.av) {
26188e3b1ab2SBaptiste Daroussin 					memset (new->value.av, 0, sizeof (ucl_array_t));
26198e3b1ab2SBaptiste Daroussin 					UCL_ARRAY_GET (vec, new);
26208e3b1ab2SBaptiste Daroussin 
26218e3b1ab2SBaptiste Daroussin 					/* Preallocate some space for arrays */
26228e3b1ab2SBaptiste Daroussin 					kv_resize (ucl_object_t *, *vec, 8);
26238e3b1ab2SBaptiste Daroussin 				}
26248e3b1ab2SBaptiste Daroussin 			}
262597bd480fSBaptiste Daroussin 		}
26264bf54857SBaptiste Daroussin 	}
26274bf54857SBaptiste Daroussin 	else {
2628d9f0ce31SBaptiste Daroussin 		new = ucl_object_new_userdata (NULL, NULL, NULL);
26294bf54857SBaptiste Daroussin 		ucl_object_set_priority (new, priority);
26304bf54857SBaptiste Daroussin 	}
26314bf54857SBaptiste Daroussin 
263297bd480fSBaptiste Daroussin 	return new;
263397bd480fSBaptiste Daroussin }
263497bd480fSBaptiste Daroussin 
26354bf54857SBaptiste Daroussin ucl_object_t*
2636d9f0ce31SBaptiste Daroussin ucl_object_new_userdata (ucl_userdata_dtor dtor,
2637d9f0ce31SBaptiste Daroussin 		ucl_userdata_emitter emitter,
2638d9f0ce31SBaptiste Daroussin 		void *ptr)
26394bf54857SBaptiste Daroussin {
26404bf54857SBaptiste Daroussin 	struct ucl_object_userdata *new;
26414bf54857SBaptiste Daroussin 	size_t nsize = sizeof (*new);
26424bf54857SBaptiste Daroussin 
26434bf54857SBaptiste Daroussin 	new = UCL_ALLOC (nsize);
26444bf54857SBaptiste Daroussin 	if (new != NULL) {
26454bf54857SBaptiste Daroussin 		memset (new, 0, nsize);
26464bf54857SBaptiste Daroussin 		new->obj.ref = 1;
26474bf54857SBaptiste Daroussin 		new->obj.type = UCL_USERDATA;
26484bf54857SBaptiste Daroussin 		new->obj.next = NULL;
26494bf54857SBaptiste Daroussin 		new->obj.prev = (ucl_object_t *)new;
26504bf54857SBaptiste Daroussin 		new->dtor = dtor;
26514bf54857SBaptiste Daroussin 		new->emitter = emitter;
2652d9f0ce31SBaptiste Daroussin 		new->obj.value.ud = ptr;
26534bf54857SBaptiste Daroussin 	}
26544bf54857SBaptiste Daroussin 
26554bf54857SBaptiste Daroussin 	return (ucl_object_t *)new;
26564bf54857SBaptiste Daroussin }
26574bf54857SBaptiste Daroussin 
26582e8ed2b8SBaptiste Daroussin ucl_type_t
26592e8ed2b8SBaptiste Daroussin ucl_object_type (const ucl_object_t *obj)
26602e8ed2b8SBaptiste Daroussin {
266139ee7a7aSBaptiste Daroussin 	if (obj == NULL) {
266239ee7a7aSBaptiste Daroussin 		return UCL_NULL;
266339ee7a7aSBaptiste Daroussin 	}
266439ee7a7aSBaptiste Daroussin 
26652e8ed2b8SBaptiste Daroussin 	return obj->type;
26662e8ed2b8SBaptiste Daroussin }
26672e8ed2b8SBaptiste Daroussin 
266897bd480fSBaptiste Daroussin ucl_object_t*
266997bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str)
267097bd480fSBaptiste Daroussin {
267197bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
267297bd480fSBaptiste Daroussin }
267397bd480fSBaptiste Daroussin 
267497bd480fSBaptiste Daroussin ucl_object_t *
267597bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len)
267697bd480fSBaptiste Daroussin {
267797bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
267897bd480fSBaptiste Daroussin }
267997bd480fSBaptiste Daroussin 
268097bd480fSBaptiste Daroussin ucl_object_t *
268197bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv)
268297bd480fSBaptiste Daroussin {
268397bd480fSBaptiste Daroussin 	ucl_object_t *obj;
268497bd480fSBaptiste Daroussin 
268597bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
268697bd480fSBaptiste Daroussin 	if (obj != NULL) {
268797bd480fSBaptiste Daroussin 		obj->type = UCL_INT;
268897bd480fSBaptiste Daroussin 		obj->value.iv = iv;
268997bd480fSBaptiste Daroussin 	}
269097bd480fSBaptiste Daroussin 
269197bd480fSBaptiste Daroussin 	return obj;
269297bd480fSBaptiste Daroussin }
269397bd480fSBaptiste Daroussin 
269497bd480fSBaptiste Daroussin ucl_object_t *
269597bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv)
269697bd480fSBaptiste Daroussin {
269797bd480fSBaptiste Daroussin 	ucl_object_t *obj;
269897bd480fSBaptiste Daroussin 
269997bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
270097bd480fSBaptiste Daroussin 	if (obj != NULL) {
270197bd480fSBaptiste Daroussin 		obj->type = UCL_FLOAT;
270297bd480fSBaptiste Daroussin 		obj->value.dv = dv;
270397bd480fSBaptiste Daroussin 	}
270497bd480fSBaptiste Daroussin 
270597bd480fSBaptiste Daroussin 	return obj;
270697bd480fSBaptiste Daroussin }
270797bd480fSBaptiste Daroussin 
270897bd480fSBaptiste Daroussin ucl_object_t*
270997bd480fSBaptiste Daroussin ucl_object_frombool (bool bv)
271097bd480fSBaptiste Daroussin {
271197bd480fSBaptiste Daroussin 	ucl_object_t *obj;
271297bd480fSBaptiste Daroussin 
271397bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
271497bd480fSBaptiste Daroussin 	if (obj != NULL) {
271597bd480fSBaptiste Daroussin 		obj->type = UCL_BOOLEAN;
271697bd480fSBaptiste Daroussin 		obj->value.iv = bv;
271797bd480fSBaptiste Daroussin 	}
271897bd480fSBaptiste Daroussin 
271997bd480fSBaptiste Daroussin 	return obj;
272097bd480fSBaptiste Daroussin }
272197bd480fSBaptiste Daroussin 
2722b04a7a0bSBaptiste Daroussin bool
272397bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
272497bd480fSBaptiste Daroussin {
27258e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
272697bd480fSBaptiste Daroussin 
2727b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
2728b04a7a0bSBaptiste Daroussin 		return false;
272997bd480fSBaptiste Daroussin 	}
273097bd480fSBaptiste Daroussin 
27318e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
27328e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
273339ee7a7aSBaptiste Daroussin 
273439ee7a7aSBaptiste Daroussin 		if (vec == NULL) {
273539ee7a7aSBaptiste Daroussin 			return false;
273639ee7a7aSBaptiste Daroussin 		}
273739ee7a7aSBaptiste Daroussin 
27388e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
27398e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
274097bd480fSBaptiste Daroussin 	}
27418e3b1ab2SBaptiste Daroussin 
27428e3b1ab2SBaptiste Daroussin 	kv_push (ucl_object_t *, *vec, elt);
27438e3b1ab2SBaptiste Daroussin 
274497bd480fSBaptiste Daroussin 	top->len ++;
2745b04a7a0bSBaptiste Daroussin 
2746b04a7a0bSBaptiste Daroussin 	return true;
274797bd480fSBaptiste Daroussin }
274897bd480fSBaptiste Daroussin 
2749b04a7a0bSBaptiste Daroussin bool
275097bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
275197bd480fSBaptiste Daroussin {
27528e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
275397bd480fSBaptiste Daroussin 
2754b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
2755b04a7a0bSBaptiste Daroussin 		return false;
275697bd480fSBaptiste Daroussin 	}
275797bd480fSBaptiste Daroussin 
27588e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
27598e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
27608e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
27618e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
27628e3b1ab2SBaptiste Daroussin 		kv_push (ucl_object_t *, *vec, elt);
276397bd480fSBaptiste Daroussin 	}
276497bd480fSBaptiste Daroussin 	else {
27658e3b1ab2SBaptiste Daroussin 		/* Slow O(n) algorithm */
27668e3b1ab2SBaptiste Daroussin 		kv_prepend (ucl_object_t *, *vec, elt);
276797bd480fSBaptiste Daroussin 	}
27688e3b1ab2SBaptiste Daroussin 
276997bd480fSBaptiste Daroussin 	top->len ++;
277097bd480fSBaptiste Daroussin 
2771b04a7a0bSBaptiste Daroussin 	return true;
277297bd480fSBaptiste Daroussin }
277397bd480fSBaptiste Daroussin 
27744bf54857SBaptiste Daroussin bool
27754bf54857SBaptiste Daroussin ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
27764bf54857SBaptiste Daroussin {
27778e3b1ab2SBaptiste Daroussin 	unsigned i;
277839ee7a7aSBaptiste Daroussin 	ucl_object_t *cp = NULL;
27798e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj;
27804bf54857SBaptiste Daroussin 
27814bf54857SBaptiste Daroussin 	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
27824bf54857SBaptiste Daroussin 		return false;
27834bf54857SBaptiste Daroussin 	}
27844bf54857SBaptiste Daroussin 
278539ee7a7aSBaptiste Daroussin 	if (copy) {
278639ee7a7aSBaptiste Daroussin 		cp = ucl_object_copy (elt);
278739ee7a7aSBaptiste Daroussin 	}
278839ee7a7aSBaptiste Daroussin 	else {
278939ee7a7aSBaptiste Daroussin 		cp = ucl_object_ref (elt);
279039ee7a7aSBaptiste Daroussin 	}
279139ee7a7aSBaptiste Daroussin 
279239ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v1, top);
279339ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v2, cp);
279439ee7a7aSBaptiste Daroussin 
2795d9f0ce31SBaptiste Daroussin 	if (v1 && v2) {
27968e3b1ab2SBaptiste Daroussin 		kv_concat (ucl_object_t *, *v1, *v2);
27978e3b1ab2SBaptiste Daroussin 
27988e3b1ab2SBaptiste Daroussin 		for (i = v2->n; i < v1->n; i ++) {
27998e3b1ab2SBaptiste Daroussin 			obj = &kv_A (*v1, i);
28008e3b1ab2SBaptiste Daroussin 			if (*obj == NULL) {
28018e3b1ab2SBaptiste Daroussin 				continue;
28028e3b1ab2SBaptiste Daroussin 			}
28038e3b1ab2SBaptiste Daroussin 			top->len ++;
28044bf54857SBaptiste Daroussin 		}
2805d9f0ce31SBaptiste Daroussin 	}
28064bf54857SBaptiste Daroussin 
28074bf54857SBaptiste Daroussin 	return true;
28084bf54857SBaptiste Daroussin }
28094bf54857SBaptiste Daroussin 
281097bd480fSBaptiste Daroussin ucl_object_t *
281197bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
281297bd480fSBaptiste Daroussin {
28138e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28148e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
28158e3b1ab2SBaptiste Daroussin 	unsigned i;
281697bd480fSBaptiste Daroussin 
281739ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
281839ee7a7aSBaptiste Daroussin 		return NULL;
281939ee7a7aSBaptiste Daroussin 	}
282039ee7a7aSBaptiste Daroussin 
28218e3b1ab2SBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
28228e3b1ab2SBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
28238e3b1ab2SBaptiste Daroussin 			kv_del (ucl_object_t *, *vec, i);
28248e3b1ab2SBaptiste Daroussin 			ret = elt;
282597bd480fSBaptiste Daroussin 			top->len --;
28268e3b1ab2SBaptiste Daroussin 			break;
28278e3b1ab2SBaptiste Daroussin 		}
28288e3b1ab2SBaptiste Daroussin 	}
282997bd480fSBaptiste Daroussin 
28308e3b1ab2SBaptiste Daroussin 	return ret;
283197bd480fSBaptiste Daroussin }
283297bd480fSBaptiste Daroussin 
2833b04a7a0bSBaptiste Daroussin const ucl_object_t *
2834b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top)
283597bd480fSBaptiste Daroussin {
28368e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28378e3b1ab2SBaptiste Daroussin 
283839ee7a7aSBaptiste Daroussin 	if (vec == NULL || top == NULL || top->type != UCL_ARRAY ||
283939ee7a7aSBaptiste Daroussin 			top->value.av == NULL) {
284097bd480fSBaptiste Daroussin 		return NULL;
284197bd480fSBaptiste Daroussin 	}
28428e3b1ab2SBaptiste Daroussin 
28438e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[0] : NULL);
284497bd480fSBaptiste Daroussin }
284597bd480fSBaptiste Daroussin 
2846b04a7a0bSBaptiste Daroussin const ucl_object_t *
2847b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top)
284897bd480fSBaptiste Daroussin {
28498e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28508e3b1ab2SBaptiste Daroussin 
285197bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
285297bd480fSBaptiste Daroussin 		return NULL;
285397bd480fSBaptiste Daroussin 	}
28548e3b1ab2SBaptiste Daroussin 
28558e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
285697bd480fSBaptiste Daroussin }
285797bd480fSBaptiste Daroussin 
285897bd480fSBaptiste Daroussin ucl_object_t *
285997bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top)
286097bd480fSBaptiste Daroussin {
28618e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28628e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
28638e3b1ab2SBaptiste Daroussin 
28648e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
28658e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, vec->n - 1);
28668e3b1ab2SBaptiste Daroussin 		ret = *obj;
28678e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, vec->n - 1);
28688e3b1ab2SBaptiste Daroussin 		top->len --;
28698e3b1ab2SBaptiste Daroussin 	}
28708e3b1ab2SBaptiste Daroussin 
28718e3b1ab2SBaptiste Daroussin 	return ret;
287297bd480fSBaptiste Daroussin }
287397bd480fSBaptiste Daroussin 
287497bd480fSBaptiste Daroussin ucl_object_t *
287597bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top)
287697bd480fSBaptiste Daroussin {
28778e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28788e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
28798e3b1ab2SBaptiste Daroussin 
28808e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
28818e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, 0);
28828e3b1ab2SBaptiste Daroussin 		ret = *obj;
28838e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, 0);
28848e3b1ab2SBaptiste Daroussin 		top->len --;
28858e3b1ab2SBaptiste Daroussin 	}
28868e3b1ab2SBaptiste Daroussin 
28878e3b1ab2SBaptiste Daroussin 	return ret;
288897bd480fSBaptiste Daroussin }
288997bd480fSBaptiste Daroussin 
28902e8ed2b8SBaptiste Daroussin const ucl_object_t *
28912e8ed2b8SBaptiste Daroussin ucl_array_find_index (const ucl_object_t *top, unsigned int index)
28922e8ed2b8SBaptiste Daroussin {
28938e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28942e8ed2b8SBaptiste Daroussin 
28958e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
28968e3b1ab2SBaptiste Daroussin 		return kv_A (*vec, index);
28972e8ed2b8SBaptiste Daroussin 	}
28982e8ed2b8SBaptiste Daroussin 
28992e8ed2b8SBaptiste Daroussin 	return NULL;
29002e8ed2b8SBaptiste Daroussin }
29012e8ed2b8SBaptiste Daroussin 
290239ee7a7aSBaptiste Daroussin unsigned int
290339ee7a7aSBaptiste Daroussin ucl_array_index_of (ucl_object_t *top, ucl_object_t *elt)
290439ee7a7aSBaptiste Daroussin {
290539ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
290639ee7a7aSBaptiste Daroussin 	unsigned i;
290739ee7a7aSBaptiste Daroussin 
290839ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
290939ee7a7aSBaptiste Daroussin 		return (unsigned int)(-1);
291039ee7a7aSBaptiste Daroussin 	}
291139ee7a7aSBaptiste Daroussin 
291239ee7a7aSBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
291339ee7a7aSBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
291439ee7a7aSBaptiste Daroussin 			return i;
291539ee7a7aSBaptiste Daroussin 		}
291639ee7a7aSBaptiste Daroussin 	}
291739ee7a7aSBaptiste Daroussin 
291839ee7a7aSBaptiste Daroussin 	return (unsigned int)(-1);
291939ee7a7aSBaptiste Daroussin }
292039ee7a7aSBaptiste Daroussin 
292197bd480fSBaptiste Daroussin ucl_object_t *
29224bf54857SBaptiste Daroussin ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
29234bf54857SBaptiste Daroussin 	unsigned int index)
29244bf54857SBaptiste Daroussin {
29258e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
29268e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
29274bf54857SBaptiste Daroussin 
29288e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
29298e3b1ab2SBaptiste Daroussin 		ret = kv_A (*vec, index);
29308e3b1ab2SBaptiste Daroussin 		kv_A (*vec, index) = elt;
29314bf54857SBaptiste Daroussin 	}
29324bf54857SBaptiste Daroussin 
29338e3b1ab2SBaptiste Daroussin 	return ret;
29344bf54857SBaptiste Daroussin }
29354bf54857SBaptiste Daroussin 
29364bf54857SBaptiste Daroussin ucl_object_t *
293797bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
293897bd480fSBaptiste Daroussin {
293997bd480fSBaptiste Daroussin 
294097bd480fSBaptiste Daroussin 	if (head == NULL) {
294197bd480fSBaptiste Daroussin 		elt->next = NULL;
294297bd480fSBaptiste Daroussin 		elt->prev = elt;
294397bd480fSBaptiste Daroussin 		head = elt;
294497bd480fSBaptiste Daroussin 	}
294597bd480fSBaptiste Daroussin 	else {
294697bd480fSBaptiste Daroussin 		elt->prev = head->prev;
294797bd480fSBaptiste Daroussin 		head->prev->next = elt;
294897bd480fSBaptiste Daroussin 		head->prev = elt;
294997bd480fSBaptiste Daroussin 		elt->next = NULL;
295097bd480fSBaptiste Daroussin 	}
295197bd480fSBaptiste Daroussin 
295297bd480fSBaptiste Daroussin 	return head;
295397bd480fSBaptiste Daroussin }
295497bd480fSBaptiste Daroussin 
295597bd480fSBaptiste Daroussin bool
2956b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
295797bd480fSBaptiste Daroussin {
295897bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
295997bd480fSBaptiste Daroussin 		return false;
296097bd480fSBaptiste Daroussin 	}
296197bd480fSBaptiste Daroussin 	switch (obj->type) {
296297bd480fSBaptiste Daroussin 	case UCL_INT:
296397bd480fSBaptiste Daroussin 		*target = obj->value.iv; /* Probaly could cause overflow */
296497bd480fSBaptiste Daroussin 		break;
296597bd480fSBaptiste Daroussin 	case UCL_FLOAT:
296697bd480fSBaptiste Daroussin 	case UCL_TIME:
296797bd480fSBaptiste Daroussin 		*target = obj->value.dv;
296897bd480fSBaptiste Daroussin 		break;
296997bd480fSBaptiste Daroussin 	default:
297097bd480fSBaptiste Daroussin 		return false;
297197bd480fSBaptiste Daroussin 	}
297297bd480fSBaptiste Daroussin 
297397bd480fSBaptiste Daroussin 	return true;
297497bd480fSBaptiste Daroussin }
297597bd480fSBaptiste Daroussin 
297697bd480fSBaptiste Daroussin double
2977b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj)
297897bd480fSBaptiste Daroussin {
297997bd480fSBaptiste Daroussin 	double result = 0.;
298097bd480fSBaptiste Daroussin 
298197bd480fSBaptiste Daroussin 	ucl_object_todouble_safe (obj, &result);
298297bd480fSBaptiste Daroussin 	return result;
298397bd480fSBaptiste Daroussin }
298497bd480fSBaptiste Daroussin 
298597bd480fSBaptiste Daroussin bool
2986b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
298797bd480fSBaptiste Daroussin {
298897bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
298997bd480fSBaptiste Daroussin 		return false;
299097bd480fSBaptiste Daroussin 	}
299197bd480fSBaptiste Daroussin 	switch (obj->type) {
299297bd480fSBaptiste Daroussin 	case UCL_INT:
299397bd480fSBaptiste Daroussin 		*target = obj->value.iv;
299497bd480fSBaptiste Daroussin 		break;
299597bd480fSBaptiste Daroussin 	case UCL_FLOAT:
299697bd480fSBaptiste Daroussin 	case UCL_TIME:
299797bd480fSBaptiste Daroussin 		*target = obj->value.dv; /* Loosing of decimal points */
299897bd480fSBaptiste Daroussin 		break;
299997bd480fSBaptiste Daroussin 	default:
300097bd480fSBaptiste Daroussin 		return false;
300197bd480fSBaptiste Daroussin 	}
300297bd480fSBaptiste Daroussin 
300397bd480fSBaptiste Daroussin 	return true;
300497bd480fSBaptiste Daroussin }
300597bd480fSBaptiste Daroussin 
300697bd480fSBaptiste Daroussin int64_t
3007b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj)
300897bd480fSBaptiste Daroussin {
300997bd480fSBaptiste Daroussin 	int64_t result = 0;
301097bd480fSBaptiste Daroussin 
301197bd480fSBaptiste Daroussin 	ucl_object_toint_safe (obj, &result);
301297bd480fSBaptiste Daroussin 	return result;
301397bd480fSBaptiste Daroussin }
301497bd480fSBaptiste Daroussin 
301597bd480fSBaptiste Daroussin bool
3016b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
301797bd480fSBaptiste Daroussin {
301897bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
301997bd480fSBaptiste Daroussin 		return false;
302097bd480fSBaptiste Daroussin 	}
302197bd480fSBaptiste Daroussin 	switch (obj->type) {
302297bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
302397bd480fSBaptiste Daroussin 		*target = (obj->value.iv == true);
302497bd480fSBaptiste Daroussin 		break;
302597bd480fSBaptiste Daroussin 	default:
302697bd480fSBaptiste Daroussin 		return false;
302797bd480fSBaptiste Daroussin 	}
302897bd480fSBaptiste Daroussin 
302997bd480fSBaptiste Daroussin 	return true;
303097bd480fSBaptiste Daroussin }
303197bd480fSBaptiste Daroussin 
303297bd480fSBaptiste Daroussin bool
3033b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj)
303497bd480fSBaptiste Daroussin {
303597bd480fSBaptiste Daroussin 	bool result = false;
303697bd480fSBaptiste Daroussin 
303797bd480fSBaptiste Daroussin 	ucl_object_toboolean_safe (obj, &result);
303897bd480fSBaptiste Daroussin 	return result;
303997bd480fSBaptiste Daroussin }
304097bd480fSBaptiste Daroussin 
304197bd480fSBaptiste Daroussin bool
3042b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
304397bd480fSBaptiste Daroussin {
304497bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
304597bd480fSBaptiste Daroussin 		return false;
304697bd480fSBaptiste Daroussin 	}
304797bd480fSBaptiste Daroussin 
304897bd480fSBaptiste Daroussin 	switch (obj->type) {
304997bd480fSBaptiste Daroussin 	case UCL_STRING:
305039ee7a7aSBaptiste Daroussin 		if (!(obj->flags & UCL_OBJECT_BINARY)) {
305197bd480fSBaptiste Daroussin 			*target = ucl_copy_value_trash (obj);
305239ee7a7aSBaptiste Daroussin 		}
305397bd480fSBaptiste Daroussin 		break;
305497bd480fSBaptiste Daroussin 	default:
305597bd480fSBaptiste Daroussin 		return false;
305697bd480fSBaptiste Daroussin 	}
305797bd480fSBaptiste Daroussin 
305897bd480fSBaptiste Daroussin 	return true;
305997bd480fSBaptiste Daroussin }
306097bd480fSBaptiste Daroussin 
306197bd480fSBaptiste Daroussin const char *
3062b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj)
306397bd480fSBaptiste Daroussin {
306497bd480fSBaptiste Daroussin 	const char *result = NULL;
306597bd480fSBaptiste Daroussin 
306697bd480fSBaptiste Daroussin 	ucl_object_tostring_safe (obj, &result);
306797bd480fSBaptiste Daroussin 	return result;
306897bd480fSBaptiste Daroussin }
306997bd480fSBaptiste Daroussin 
307097bd480fSBaptiste Daroussin const char *
3071b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj)
307297bd480fSBaptiste Daroussin {
307339ee7a7aSBaptiste Daroussin 	/* TODO: For binary strings we might encode string here */
307439ee7a7aSBaptiste Daroussin 	if (!(obj->flags & UCL_OBJECT_BINARY)) {
307597bd480fSBaptiste Daroussin 		return ucl_copy_value_trash (obj);
307697bd480fSBaptiste Daroussin 	}
307797bd480fSBaptiste Daroussin 
307839ee7a7aSBaptiste Daroussin 	return NULL;
307939ee7a7aSBaptiste Daroussin }
308039ee7a7aSBaptiste Daroussin 
308197bd480fSBaptiste Daroussin bool
3082b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
308397bd480fSBaptiste Daroussin {
308497bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
308597bd480fSBaptiste Daroussin 		return false;
308697bd480fSBaptiste Daroussin 	}
308797bd480fSBaptiste Daroussin 	switch (obj->type) {
308897bd480fSBaptiste Daroussin 	case UCL_STRING:
308997bd480fSBaptiste Daroussin 		*target = obj->value.sv;
309097bd480fSBaptiste Daroussin 		if (tlen != NULL) {
309197bd480fSBaptiste Daroussin 			*tlen = obj->len;
309297bd480fSBaptiste Daroussin 		}
309397bd480fSBaptiste Daroussin 		break;
309497bd480fSBaptiste Daroussin 	default:
309597bd480fSBaptiste Daroussin 		return false;
309697bd480fSBaptiste Daroussin 	}
309797bd480fSBaptiste Daroussin 
309897bd480fSBaptiste Daroussin 	return true;
309997bd480fSBaptiste Daroussin }
310097bd480fSBaptiste Daroussin 
310197bd480fSBaptiste Daroussin const char *
3102b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
310397bd480fSBaptiste Daroussin {
310497bd480fSBaptiste Daroussin 	const char *result = NULL;
310597bd480fSBaptiste Daroussin 
310697bd480fSBaptiste Daroussin 	ucl_object_tolstring_safe (obj, &result, tlen);
310797bd480fSBaptiste Daroussin 	return result;
310897bd480fSBaptiste Daroussin }
310997bd480fSBaptiste Daroussin 
311097bd480fSBaptiste Daroussin const char *
3111b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj)
311297bd480fSBaptiste Daroussin {
311397bd480fSBaptiste Daroussin 	return ucl_copy_key_trash (obj);
311497bd480fSBaptiste Daroussin }
311597bd480fSBaptiste Daroussin 
311697bd480fSBaptiste Daroussin const char *
3117b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len)
311897bd480fSBaptiste Daroussin {
311997bd480fSBaptiste Daroussin 	if (len == NULL || obj == NULL) {
312097bd480fSBaptiste Daroussin 		return NULL;
312197bd480fSBaptiste Daroussin 	}
312297bd480fSBaptiste Daroussin 	*len = obj->keylen;
312397bd480fSBaptiste Daroussin 	return obj->key;
312497bd480fSBaptiste Daroussin }
312597bd480fSBaptiste Daroussin 
312697bd480fSBaptiste Daroussin ucl_object_t *
3127b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj)
312897bd480fSBaptiste Daroussin {
3129b04a7a0bSBaptiste Daroussin 	ucl_object_t *res = NULL;
3130b04a7a0bSBaptiste Daroussin 
313197bd480fSBaptiste Daroussin 	if (obj != NULL) {
31324bf54857SBaptiste Daroussin 		if (obj->flags & UCL_OBJECT_EPHEMERAL) {
31334bf54857SBaptiste Daroussin 			/*
31344bf54857SBaptiste Daroussin 			 * Use deep copy for ephemeral objects, note that its refcount
31354bf54857SBaptiste Daroussin 			 * is NOT increased, since ephemeral objects does not need refcount
31364bf54857SBaptiste Daroussin 			 * at all
31374bf54857SBaptiste Daroussin 			 */
31384bf54857SBaptiste Daroussin 			res = ucl_object_copy (obj);
31394bf54857SBaptiste Daroussin 		}
31404bf54857SBaptiste Daroussin 		else {
3141b04a7a0bSBaptiste Daroussin 			res = __DECONST (ucl_object_t *, obj);
3142b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3143b04a7a0bSBaptiste Daroussin 			(void)__sync_add_and_fetch (&res->ref, 1);
3144b04a7a0bSBaptiste Daroussin #else
3145b04a7a0bSBaptiste Daroussin 			res->ref ++;
3146b04a7a0bSBaptiste Daroussin #endif
314797bd480fSBaptiste Daroussin 		}
31484bf54857SBaptiste Daroussin 	}
3149b04a7a0bSBaptiste Daroussin 	return res;
315097bd480fSBaptiste Daroussin }
315197bd480fSBaptiste Daroussin 
31524bf54857SBaptiste Daroussin static ucl_object_t *
31534bf54857SBaptiste Daroussin ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
31544bf54857SBaptiste Daroussin {
31554bf54857SBaptiste Daroussin 
31564bf54857SBaptiste Daroussin 	ucl_object_t *new;
31574bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
31584bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
31594bf54857SBaptiste Daroussin 
31604bf54857SBaptiste Daroussin 	new = malloc (sizeof (*new));
31614bf54857SBaptiste Daroussin 
31624bf54857SBaptiste Daroussin 	if (new != NULL) {
31634bf54857SBaptiste Daroussin 		memcpy (new, other, sizeof (*new));
31644bf54857SBaptiste Daroussin 		if (other->flags & UCL_OBJECT_EPHEMERAL) {
31654bf54857SBaptiste Daroussin 			/* Copied object is always non ephemeral */
31664bf54857SBaptiste Daroussin 			new->flags &= ~UCL_OBJECT_EPHEMERAL;
31674bf54857SBaptiste Daroussin 		}
31684bf54857SBaptiste Daroussin 		new->ref = 1;
31694bf54857SBaptiste Daroussin 		/* Unlink from others */
31704bf54857SBaptiste Daroussin 		new->next = NULL;
31714bf54857SBaptiste Daroussin 		new->prev = new;
31724bf54857SBaptiste Daroussin 
31734bf54857SBaptiste Daroussin 		/* deep copy of values stored */
31744bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
31754bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_KEY] =
31764bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_KEY]);
31774bf54857SBaptiste Daroussin 			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
31784bf54857SBaptiste Daroussin 				new->key = new->trash_stack[UCL_TRASH_KEY];
31794bf54857SBaptiste Daroussin 			}
31804bf54857SBaptiste Daroussin 		}
31814bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
31824bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_VALUE] =
31834bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_VALUE]);
31844bf54857SBaptiste Daroussin 			if (new->type == UCL_STRING) {
31854bf54857SBaptiste Daroussin 				new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
31864bf54857SBaptiste Daroussin 			}
31874bf54857SBaptiste Daroussin 		}
31884bf54857SBaptiste Daroussin 
31894bf54857SBaptiste Daroussin 		if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
31904bf54857SBaptiste Daroussin 			/* reset old value */
31914bf54857SBaptiste Daroussin 			memset (&new->value, 0, sizeof (new->value));
31924bf54857SBaptiste Daroussin 
3193d9f0ce31SBaptiste Daroussin 			while ((cur = ucl_object_iterate (other, &it, true)) != NULL) {
31944bf54857SBaptiste Daroussin 				if (other->type == UCL_ARRAY) {
31954bf54857SBaptiste Daroussin 					ucl_array_append (new, ucl_object_copy_internal (cur, false));
31964bf54857SBaptiste Daroussin 				}
31974bf54857SBaptiste Daroussin 				else {
31984bf54857SBaptiste Daroussin 					ucl_object_t *cp = ucl_object_copy_internal (cur, true);
31994bf54857SBaptiste Daroussin 					if (cp != NULL) {
32004bf54857SBaptiste Daroussin 						ucl_object_insert_key (new, cp, cp->key, cp->keylen,
32014bf54857SBaptiste Daroussin 								false);
32024bf54857SBaptiste Daroussin 					}
32034bf54857SBaptiste Daroussin 				}
32044bf54857SBaptiste Daroussin 			}
32054bf54857SBaptiste Daroussin 		}
32064bf54857SBaptiste Daroussin 		else if (allow_array && other->next != NULL) {
32074bf54857SBaptiste Daroussin 			LL_FOREACH (other->next, cur) {
32084bf54857SBaptiste Daroussin 				ucl_object_t *cp = ucl_object_copy_internal (cur, false);
32094bf54857SBaptiste Daroussin 				if (cp != NULL) {
32104bf54857SBaptiste Daroussin 					DL_APPEND (new, cp);
32114bf54857SBaptiste Daroussin 				}
32124bf54857SBaptiste Daroussin 			}
32134bf54857SBaptiste Daroussin 		}
32144bf54857SBaptiste Daroussin 	}
32154bf54857SBaptiste Daroussin 
32164bf54857SBaptiste Daroussin 	return new;
32174bf54857SBaptiste Daroussin }
32184bf54857SBaptiste Daroussin 
32194bf54857SBaptiste Daroussin ucl_object_t *
32204bf54857SBaptiste Daroussin ucl_object_copy (const ucl_object_t *other)
32214bf54857SBaptiste Daroussin {
32224bf54857SBaptiste Daroussin 	return ucl_object_copy_internal (other, true);
32234bf54857SBaptiste Daroussin }
32244bf54857SBaptiste Daroussin 
322597bd480fSBaptiste Daroussin void
322697bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj)
322797bd480fSBaptiste Daroussin {
3228b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
3229b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3230b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
3231b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
3232b04a7a0bSBaptiste Daroussin #else
3233b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
3234b04a7a0bSBaptiste Daroussin #endif
3235b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
3236b04a7a0bSBaptiste Daroussin 		}
323797bd480fSBaptiste Daroussin 	}
323897bd480fSBaptiste Daroussin }
323997bd480fSBaptiste Daroussin 
324097bd480fSBaptiste Daroussin int
3241b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
324297bd480fSBaptiste Daroussin {
3243b04a7a0bSBaptiste Daroussin 	const ucl_object_t *it1, *it2;
324497bd480fSBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
324597bd480fSBaptiste Daroussin 	int ret = 0;
324697bd480fSBaptiste Daroussin 
324797bd480fSBaptiste Daroussin 	if (o1->type != o2->type) {
324897bd480fSBaptiste Daroussin 		return (o1->type) - (o2->type);
324997bd480fSBaptiste Daroussin 	}
325097bd480fSBaptiste Daroussin 
325197bd480fSBaptiste Daroussin 	switch (o1->type) {
325297bd480fSBaptiste Daroussin 	case UCL_STRING:
32538e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
325497bd480fSBaptiste Daroussin 			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
325597bd480fSBaptiste Daroussin 		}
325697bd480fSBaptiste Daroussin 		else {
325797bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
325897bd480fSBaptiste Daroussin 		}
325997bd480fSBaptiste Daroussin 		break;
326097bd480fSBaptiste Daroussin 	case UCL_FLOAT:
326197bd480fSBaptiste Daroussin 	case UCL_INT:
326297bd480fSBaptiste Daroussin 	case UCL_TIME:
326397bd480fSBaptiste Daroussin 		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
326497bd480fSBaptiste Daroussin 		break;
326597bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
326697bd480fSBaptiste Daroussin 		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
326797bd480fSBaptiste Daroussin 		break;
326897bd480fSBaptiste Daroussin 	case UCL_ARRAY:
32698e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
32708e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec1, o1);
32718e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec2, o2);
32728e3b1ab2SBaptiste Daroussin 			unsigned i;
32738e3b1ab2SBaptiste Daroussin 
327497bd480fSBaptiste Daroussin 			/* Compare all elements in both arrays */
32758e3b1ab2SBaptiste Daroussin 			for (i = 0; i < vec1->n; i ++) {
32768e3b1ab2SBaptiste Daroussin 				it1 = kv_A (*vec1, i);
32778e3b1ab2SBaptiste Daroussin 				it2 = kv_A (*vec2, i);
32788e3b1ab2SBaptiste Daroussin 
32798e3b1ab2SBaptiste Daroussin 				if (it1 == NULL && it2 != NULL) {
32808e3b1ab2SBaptiste Daroussin 					return -1;
32818e3b1ab2SBaptiste Daroussin 				}
32828e3b1ab2SBaptiste Daroussin 				else if (it2 == NULL && it1 != NULL) {
32838e3b1ab2SBaptiste Daroussin 					return 1;
32848e3b1ab2SBaptiste Daroussin 				}
32858e3b1ab2SBaptiste Daroussin 				else if (it1 != NULL && it2 != NULL) {
328697bd480fSBaptiste Daroussin 					ret = ucl_object_compare (it1, it2);
328797bd480fSBaptiste Daroussin 					if (ret != 0) {
328897bd480fSBaptiste Daroussin 						break;
328997bd480fSBaptiste Daroussin 					}
32908e3b1ab2SBaptiste Daroussin 				}
329197bd480fSBaptiste Daroussin 			}
329297bd480fSBaptiste Daroussin 		}
329397bd480fSBaptiste Daroussin 		else {
329497bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
329597bd480fSBaptiste Daroussin 		}
329697bd480fSBaptiste Daroussin 		break;
329797bd480fSBaptiste Daroussin 	case UCL_OBJECT:
32988e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
3299d9f0ce31SBaptiste Daroussin 			while ((it1 = ucl_object_iterate (o1, &iter, true)) != NULL) {
3300d9f0ce31SBaptiste Daroussin 				it2 = ucl_object_lookup (o2, ucl_object_key (it1));
330197bd480fSBaptiste Daroussin 				if (it2 == NULL) {
330297bd480fSBaptiste Daroussin 					ret = 1;
330397bd480fSBaptiste Daroussin 					break;
330497bd480fSBaptiste Daroussin 				}
330597bd480fSBaptiste Daroussin 				ret = ucl_object_compare (it1, it2);
330697bd480fSBaptiste Daroussin 				if (ret != 0) {
330797bd480fSBaptiste Daroussin 					break;
330897bd480fSBaptiste Daroussin 				}
330997bd480fSBaptiste Daroussin 			}
331097bd480fSBaptiste Daroussin 		}
331197bd480fSBaptiste Daroussin 		else {
331297bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
331397bd480fSBaptiste Daroussin 		}
331497bd480fSBaptiste Daroussin 		break;
331597bd480fSBaptiste Daroussin 	default:
331697bd480fSBaptiste Daroussin 		ret = 0;
331797bd480fSBaptiste Daroussin 		break;
331897bd480fSBaptiste Daroussin 	}
331997bd480fSBaptiste Daroussin 
332097bd480fSBaptiste Daroussin 	return ret;
332197bd480fSBaptiste Daroussin }
332297bd480fSBaptiste Daroussin 
3323d9f0ce31SBaptiste Daroussin int
3324d9f0ce31SBaptiste Daroussin ucl_object_compare_qsort (const ucl_object_t **o1,
3325d9f0ce31SBaptiste Daroussin 		const ucl_object_t **o2)
3326d9f0ce31SBaptiste Daroussin {
3327d9f0ce31SBaptiste Daroussin 	return ucl_object_compare (*o1, *o2);
3328d9f0ce31SBaptiste Daroussin }
3329d9f0ce31SBaptiste Daroussin 
333097bd480fSBaptiste Daroussin void
333197bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar,
333239ee7a7aSBaptiste Daroussin 		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
333397bd480fSBaptiste Daroussin {
33348e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, ar);
33358e3b1ab2SBaptiste Daroussin 
333697bd480fSBaptiste Daroussin 	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
333797bd480fSBaptiste Daroussin 		return;
333897bd480fSBaptiste Daroussin 	}
333997bd480fSBaptiste Daroussin 
33408e3b1ab2SBaptiste Daroussin 	qsort (vec->a, vec->n, sizeof (ucl_object_t *),
33418e3b1ab2SBaptiste Daroussin 			(int (*)(const void *, const void *))cmp);
334297bd480fSBaptiste Daroussin }
33434bf54857SBaptiste Daroussin 
33444bf54857SBaptiste Daroussin #define PRIOBITS 4
33454bf54857SBaptiste Daroussin 
33464bf54857SBaptiste Daroussin unsigned int
33474bf54857SBaptiste Daroussin ucl_object_get_priority (const ucl_object_t *obj)
33484bf54857SBaptiste Daroussin {
33494bf54857SBaptiste Daroussin 	if (obj == NULL) {
33504bf54857SBaptiste Daroussin 		return 0;
33514bf54857SBaptiste Daroussin 	}
33524bf54857SBaptiste Daroussin 
33534bf54857SBaptiste Daroussin 	return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
33544bf54857SBaptiste Daroussin }
33554bf54857SBaptiste Daroussin 
33564bf54857SBaptiste Daroussin void
33574bf54857SBaptiste Daroussin ucl_object_set_priority (ucl_object_t *obj,
33584bf54857SBaptiste Daroussin 		unsigned int priority)
33594bf54857SBaptiste Daroussin {
33604bf54857SBaptiste Daroussin 	if (obj != NULL) {
33614bf54857SBaptiste Daroussin 		priority &= (0x1 << PRIOBITS) - 1;
336239ee7a7aSBaptiste Daroussin 		priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS);
336339ee7a7aSBaptiste Daroussin 		priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) -
336439ee7a7aSBaptiste Daroussin 				PRIOBITS)) - 1);
336539ee7a7aSBaptiste Daroussin 		obj->flags = priority;
33664bf54857SBaptiste Daroussin 	}
33674bf54857SBaptiste Daroussin }
3368d9f0ce31SBaptiste Daroussin 
3369d9f0ce31SBaptiste Daroussin bool
3370d9f0ce31SBaptiste Daroussin ucl_object_string_to_type (const char *input, ucl_type_t *res)
3371d9f0ce31SBaptiste Daroussin {
3372d9f0ce31SBaptiste Daroussin 	if (strcasecmp (input, "object") == 0) {
3373d9f0ce31SBaptiste Daroussin 		*res = UCL_OBJECT;
3374d9f0ce31SBaptiste Daroussin 	}
3375d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "array") == 0) {
3376d9f0ce31SBaptiste Daroussin 		*res = UCL_ARRAY;
3377d9f0ce31SBaptiste Daroussin 	}
3378d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "integer") == 0) {
3379d9f0ce31SBaptiste Daroussin 		*res = UCL_INT;
3380d9f0ce31SBaptiste Daroussin 	}
3381d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "number") == 0) {
3382d9f0ce31SBaptiste Daroussin 		*res = UCL_FLOAT;
3383d9f0ce31SBaptiste Daroussin 	}
3384d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "string") == 0) {
3385d9f0ce31SBaptiste Daroussin 		*res = UCL_STRING;
3386d9f0ce31SBaptiste Daroussin 	}
3387d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "boolean") == 0) {
3388d9f0ce31SBaptiste Daroussin 		*res = UCL_BOOLEAN;
3389d9f0ce31SBaptiste Daroussin 	}
3390d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "null") == 0) {
3391d9f0ce31SBaptiste Daroussin 		*res = UCL_NULL;
3392d9f0ce31SBaptiste Daroussin 	}
3393d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "userdata") == 0) {
3394d9f0ce31SBaptiste Daroussin 		*res = UCL_USERDATA;
3395d9f0ce31SBaptiste Daroussin 	}
3396d9f0ce31SBaptiste Daroussin 	else {
3397d9f0ce31SBaptiste Daroussin 		return false;
3398d9f0ce31SBaptiste Daroussin 	}
3399d9f0ce31SBaptiste Daroussin 
3400d9f0ce31SBaptiste Daroussin 	return true;
3401d9f0ce31SBaptiste Daroussin }
3402d9f0ce31SBaptiste Daroussin 
3403d9f0ce31SBaptiste Daroussin const char *
3404d9f0ce31SBaptiste Daroussin ucl_object_type_to_string (ucl_type_t type)
3405d9f0ce31SBaptiste Daroussin {
3406d9f0ce31SBaptiste Daroussin 	const char *res = "unknown";
3407d9f0ce31SBaptiste Daroussin 
3408d9f0ce31SBaptiste Daroussin 	switch (type) {
3409d9f0ce31SBaptiste Daroussin 	case UCL_OBJECT:
3410d9f0ce31SBaptiste Daroussin 		res = "object";
3411d9f0ce31SBaptiste Daroussin 		break;
3412d9f0ce31SBaptiste Daroussin 	case UCL_ARRAY:
3413d9f0ce31SBaptiste Daroussin 		res = "array";
3414d9f0ce31SBaptiste Daroussin 		break;
3415d9f0ce31SBaptiste Daroussin 	case UCL_INT:
3416d9f0ce31SBaptiste Daroussin 		res = "integer";
3417d9f0ce31SBaptiste Daroussin 		break;
3418d9f0ce31SBaptiste Daroussin 	case UCL_FLOAT:
3419d9f0ce31SBaptiste Daroussin 	case UCL_TIME:
3420d9f0ce31SBaptiste Daroussin 		res = "number";
3421d9f0ce31SBaptiste Daroussin 		break;
3422d9f0ce31SBaptiste Daroussin 	case UCL_STRING:
3423d9f0ce31SBaptiste Daroussin 		res = "string";
3424d9f0ce31SBaptiste Daroussin 		break;
3425d9f0ce31SBaptiste Daroussin 	case UCL_BOOLEAN:
3426d9f0ce31SBaptiste Daroussin 		res = "boolean";
3427d9f0ce31SBaptiste Daroussin 		break;
3428d9f0ce31SBaptiste Daroussin 	case UCL_USERDATA:
3429d9f0ce31SBaptiste Daroussin 		res = "userdata";
3430d9f0ce31SBaptiste Daroussin 		break;
3431d9f0ce31SBaptiste Daroussin 	case UCL_NULL:
3432d9f0ce31SBaptiste Daroussin 		res = "null";
3433d9f0ce31SBaptiste Daroussin 		break;
3434d9f0ce31SBaptiste Daroussin 	}
3435d9f0ce31SBaptiste Daroussin 
3436d9f0ce31SBaptiste Daroussin 	return res;
3437d9f0ce31SBaptiste Daroussin }
3438d9f0ce31SBaptiste Daroussin 
3439d9f0ce31SBaptiste Daroussin const ucl_object_t *
3440d9f0ce31SBaptiste Daroussin ucl_parser_get_comments (struct ucl_parser *parser)
3441d9f0ce31SBaptiste Daroussin {
3442d9f0ce31SBaptiste Daroussin 	if (parser && parser->comments) {
3443d9f0ce31SBaptiste Daroussin 		return parser->comments;
3444d9f0ce31SBaptiste Daroussin 	}
3445d9f0ce31SBaptiste Daroussin 
3446d9f0ce31SBaptiste Daroussin 	return NULL;
3447d9f0ce31SBaptiste Daroussin }
3448d9f0ce31SBaptiste Daroussin 
3449d9f0ce31SBaptiste Daroussin const ucl_object_t *
3450d9f0ce31SBaptiste Daroussin ucl_comments_find (const ucl_object_t *comments,
3451d9f0ce31SBaptiste Daroussin 		const ucl_object_t *srch)
3452d9f0ce31SBaptiste Daroussin {
3453d9f0ce31SBaptiste Daroussin 	if (comments && srch) {
3454d9f0ce31SBaptiste Daroussin 		return ucl_object_lookup_len (comments, (const char *)&srch,
3455d9f0ce31SBaptiste Daroussin 				sizeof (void *));
3456d9f0ce31SBaptiste Daroussin 	}
3457d9f0ce31SBaptiste Daroussin 
3458d9f0ce31SBaptiste Daroussin 	return NULL;
3459d9f0ce31SBaptiste Daroussin }
3460d9f0ce31SBaptiste Daroussin 
3461d9f0ce31SBaptiste Daroussin bool
3462d9f0ce31SBaptiste Daroussin ucl_comments_move (ucl_object_t *comments,
3463d9f0ce31SBaptiste Daroussin 		const ucl_object_t *from, const ucl_object_t *to)
3464d9f0ce31SBaptiste Daroussin {
3465d9f0ce31SBaptiste Daroussin 	const ucl_object_t *found;
3466d9f0ce31SBaptiste Daroussin 	ucl_object_t *obj;
3467d9f0ce31SBaptiste Daroussin 
3468d9f0ce31SBaptiste Daroussin 	if (comments && from && to) {
3469d9f0ce31SBaptiste Daroussin 		found = ucl_object_lookup_len (comments,
3470d9f0ce31SBaptiste Daroussin 				(const char *)&from, sizeof (void *));
3471d9f0ce31SBaptiste Daroussin 
3472d9f0ce31SBaptiste Daroussin 		if (found) {
3473d9f0ce31SBaptiste Daroussin 			/* Replace key */
3474d9f0ce31SBaptiste Daroussin 			obj = ucl_object_ref (found);
3475d9f0ce31SBaptiste Daroussin 			ucl_object_delete_keyl (comments, (const char *)&from,
3476d9f0ce31SBaptiste Daroussin 					sizeof (void *));
3477d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (comments, obj, (const char *)&to,
3478d9f0ce31SBaptiste Daroussin 					sizeof (void *), true);
3479d9f0ce31SBaptiste Daroussin 
3480d9f0ce31SBaptiste Daroussin 			return true;
3481d9f0ce31SBaptiste Daroussin 		}
3482d9f0ce31SBaptiste Daroussin 	}
3483d9f0ce31SBaptiste Daroussin 
3484d9f0ce31SBaptiste Daroussin 	return false;
3485d9f0ce31SBaptiste Daroussin }
3486d9f0ce31SBaptiste Daroussin 
3487d9f0ce31SBaptiste Daroussin void
3488d9f0ce31SBaptiste Daroussin ucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj,
3489d9f0ce31SBaptiste Daroussin 		const char *comment)
3490d9f0ce31SBaptiste Daroussin {
3491d9f0ce31SBaptiste Daroussin 	if (comments && obj && comment) {
3492d9f0ce31SBaptiste Daroussin 		ucl_object_insert_key (comments, ucl_object_fromstring (comment),
3493d9f0ce31SBaptiste Daroussin 				(const char *)&obj, sizeof (void *), true);
3494d9f0ce31SBaptiste Daroussin 	}
3495d9f0ce31SBaptiste Daroussin }
3496