xref: /freebsd/contrib/libucl/src/ucl_util.c (revision d9f0ce31)
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>
30*d9f0ce31SBaptiste 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
54*d9f0ce31SBaptiste Daroussin /* Seems to be broken */
55*d9f0ce31SBaptiste 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) {
242*d9f0ce31SBaptiste 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;
312*d9f0ce31SBaptiste Daroussin 				h ++; /* u character */
313*d9f0ce31SBaptiste Daroussin 				len --;
314*d9f0ce31SBaptiste 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 					}
331*d9f0ce31SBaptiste 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 					}
348*d9f0ce31SBaptiste Daroussin #if 0
349*d9f0ce31SBaptiste 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 					}
357*d9f0ce31SBaptiste Daroussin #endif
358c99fb5f9SBaptiste Daroussin 					else {
359c99fb5f9SBaptiste Daroussin 						*t++ = '?';
360c99fb5f9SBaptiste Daroussin 					}
361*d9f0ce31SBaptiste Daroussin 
362*d9f0ce31SBaptiste Daroussin 					/* Consume 4 characters of source */
363*d9f0ce31SBaptiste Daroussin 					h += 4;
364*d9f0ce31SBaptiste Daroussin 					len -= 4;
365*d9f0ce31SBaptiste Daroussin 
366*d9f0ce31SBaptiste Daroussin 					if (len > 0) {
367*d9f0ce31SBaptiste Daroussin 						len --; /* for '\' character */
368*d9f0ce31SBaptiste Daroussin 					}
369*d9f0ce31SBaptiste 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 
524*d9f0ce31SBaptiste Daroussin 	if (parser->comments) {
525*d9f0ce31SBaptiste Daroussin 		ucl_object_unref (parser->comments);
526*d9f0ce31SBaptiste Daroussin 	}
527*d9f0ce31SBaptiste 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  */
652*d9f0ce31SBaptiste 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);
714*d9f0ce31SBaptiste Daroussin 	cbdata.buf = NULL;
715*d9f0ce31SBaptiste 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  */
747*d9f0ce31SBaptiste 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 */
763*d9f0ce31SBaptiste 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));
776*d9f0ce31SBaptiste Daroussin 			*buf = NULL;
777*d9f0ce31SBaptiste 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)) {
874*d9f0ce31SBaptiste 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 		}
97839ee7a7aSBaptiste Daroussin 		return (!params->must_exist || false);
979c99fb5f9SBaptiste Daroussin 	}
980c99fb5f9SBaptiste Daroussin 
98139ee7a7aSBaptiste Daroussin 	if (params->check_signature) {
982c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
983c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
984c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
985c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
986c99fb5f9SBaptiste Daroussin 		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
987c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
988c99fb5f9SBaptiste Daroussin 			return false;
989c99fb5f9SBaptiste Daroussin 		}
990c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
991c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify file %s: %s",
992c99fb5f9SBaptiste Daroussin 							filebuf,
993c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
994*d9f0ce31SBaptiste Daroussin 			if (sigbuf) {
99597bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
996c99fb5f9SBaptiste Daroussin 			}
997c99fb5f9SBaptiste Daroussin 			return false;
998c99fb5f9SBaptiste Daroussin 		}
999*d9f0ce31SBaptiste Daroussin 		if (sigbuf) {
100097bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
1001c99fb5f9SBaptiste Daroussin 		}
1002c99fb5f9SBaptiste Daroussin #endif
1003c99fb5f9SBaptiste Daroussin 	}
1004c99fb5f9SBaptiste Daroussin 
10054bf54857SBaptiste Daroussin 	old_curfile = parser->cur_file;
10064bf54857SBaptiste Daroussin 	parser->cur_file = strdup (realbuf);
10074bf54857SBaptiste Daroussin 
10084bf54857SBaptiste Daroussin 	/* Store old file vars */
10094bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
10104bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0) {
10114bf54857SBaptiste Daroussin 			old_curdir = cur_var;
10124bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
10134bf54857SBaptiste Daroussin 		}
10144bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0) {
10154bf54857SBaptiste Daroussin 			old_filename = cur_var;
10164bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
10174bf54857SBaptiste Daroussin 		}
10184bf54857SBaptiste Daroussin 	}
10194bf54857SBaptiste Daroussin 
1020c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
1021c99fb5f9SBaptiste Daroussin 
1022c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
1023c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
1024c99fb5f9SBaptiste Daroussin 
102539ee7a7aSBaptiste Daroussin 	if (params->use_prefix && params->prefix == NULL) {
102639ee7a7aSBaptiste Daroussin 		/* Auto generate a key name based on the included filename */
102739ee7a7aSBaptiste Daroussin 		params->prefix = basename (realbuf);
102839ee7a7aSBaptiste Daroussin 		ext = strrchr (params->prefix, '.');
102939ee7a7aSBaptiste Daroussin 		if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) {
103039ee7a7aSBaptiste Daroussin 			/* Strip off .conf or .ucl */
103139ee7a7aSBaptiste Daroussin 			*ext = '\0';
103239ee7a7aSBaptiste Daroussin 		}
103339ee7a7aSBaptiste Daroussin 	}
103439ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL) {
103539ee7a7aSBaptiste Daroussin 		/* This is a prefixed include */
103639ee7a7aSBaptiste Daroussin 		container = parser->stack->obj->value.ov;
103739ee7a7aSBaptiste Daroussin 
103839ee7a7aSBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container,
103939ee7a7aSBaptiste Daroussin 				params->prefix, strlen (params->prefix)));
104039ee7a7aSBaptiste Daroussin 
104139ee7a7aSBaptiste Daroussin 		if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) {
104239ee7a7aSBaptiste Daroussin 			/* Create an array with key: prefix */
104339ee7a7aSBaptiste Daroussin 			old_obj = ucl_object_new_full (UCL_ARRAY, params->priority);
104439ee7a7aSBaptiste Daroussin 			old_obj->key = params->prefix;
104539ee7a7aSBaptiste Daroussin 			old_obj->keylen = strlen (params->prefix);
104639ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash(old_obj);
104739ee7a7aSBaptiste Daroussin 			old_obj->prev = old_obj;
104839ee7a7aSBaptiste Daroussin 			old_obj->next = NULL;
104939ee7a7aSBaptiste Daroussin 
105039ee7a7aSBaptiste Daroussin 			container = ucl_hash_insert_object (container, old_obj,
105139ee7a7aSBaptiste Daroussin 					parser->flags & UCL_PARSER_KEY_LOWERCASE);
105239ee7a7aSBaptiste Daroussin 			parser->stack->obj->len ++;
105339ee7a7aSBaptiste Daroussin 
105439ee7a7aSBaptiste Daroussin 			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
105539ee7a7aSBaptiste Daroussin 			nest_obj->prev = nest_obj;
105639ee7a7aSBaptiste Daroussin 			nest_obj->next = NULL;
105739ee7a7aSBaptiste Daroussin 
105839ee7a7aSBaptiste Daroussin 			ucl_array_append (old_obj, nest_obj);
105939ee7a7aSBaptiste Daroussin 		}
106039ee7a7aSBaptiste Daroussin 		else if (old_obj == NULL) {
106139ee7a7aSBaptiste Daroussin 			/* Create an object with key: prefix */
106239ee7a7aSBaptiste Daroussin 			nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1063*d9f0ce31SBaptiste Daroussin 
1064*d9f0ce31SBaptiste Daroussin 			if (nest_obj == NULL) {
1065*d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot allocate memory for an object");
1066*d9f0ce31SBaptiste Daroussin 				if (buf) {
1067*d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
1068*d9f0ce31SBaptiste Daroussin 				}
1069*d9f0ce31SBaptiste Daroussin 
1070*d9f0ce31SBaptiste Daroussin 				return false;
1071*d9f0ce31SBaptiste Daroussin 			}
1072*d9f0ce31SBaptiste Daroussin 
107339ee7a7aSBaptiste Daroussin 			nest_obj->key = params->prefix;
107439ee7a7aSBaptiste Daroussin 			nest_obj->keylen = strlen (params->prefix);
107539ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash(nest_obj);
107639ee7a7aSBaptiste Daroussin 			nest_obj->prev = nest_obj;
107739ee7a7aSBaptiste Daroussin 			nest_obj->next = NULL;
107839ee7a7aSBaptiste Daroussin 
107939ee7a7aSBaptiste Daroussin 			container = ucl_hash_insert_object (container, nest_obj,
108039ee7a7aSBaptiste Daroussin 					parser->flags & UCL_PARSER_KEY_LOWERCASE);
108139ee7a7aSBaptiste Daroussin 			parser->stack->obj->len ++;
108239ee7a7aSBaptiste Daroussin 		}
108339ee7a7aSBaptiste Daroussin 		else if (strcasecmp (params->target, "array") == 0 ||
108439ee7a7aSBaptiste Daroussin 				ucl_object_type(old_obj) == UCL_ARRAY) {
108539ee7a7aSBaptiste Daroussin 			if (ucl_object_type(old_obj) == UCL_ARRAY) {
108639ee7a7aSBaptiste Daroussin 				/* Append to the existing array */
108739ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1088*d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1089*d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1090*d9f0ce31SBaptiste Daroussin 					if (buf) {
1091*d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1092*d9f0ce31SBaptiste Daroussin 					}
1093*d9f0ce31SBaptiste Daroussin 
1094*d9f0ce31SBaptiste Daroussin 					return false;
1095*d9f0ce31SBaptiste Daroussin 				}
109639ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
109739ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
109839ee7a7aSBaptiste Daroussin 
109939ee7a7aSBaptiste Daroussin 				ucl_array_append (old_obj, nest_obj);
110039ee7a7aSBaptiste Daroussin 			}
110139ee7a7aSBaptiste Daroussin 			else {
110239ee7a7aSBaptiste Daroussin 				/* Convert the object to an array */
110339ee7a7aSBaptiste Daroussin 				new_obj = ucl_object_typed_new (UCL_ARRAY);
1104*d9f0ce31SBaptiste Daroussin 				if (new_obj == NULL) {
1105*d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1106*d9f0ce31SBaptiste Daroussin 					if (buf) {
1107*d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1108*d9f0ce31SBaptiste Daroussin 					}
1109*d9f0ce31SBaptiste Daroussin 
1110*d9f0ce31SBaptiste Daroussin 					return false;
1111*d9f0ce31SBaptiste Daroussin 				}
111239ee7a7aSBaptiste Daroussin 				new_obj->key = old_obj->key;
111339ee7a7aSBaptiste Daroussin 				new_obj->keylen = old_obj->keylen;
111439ee7a7aSBaptiste Daroussin 				new_obj->flags |= UCL_OBJECT_MULTIVALUE;
111539ee7a7aSBaptiste Daroussin 				new_obj->prev = new_obj;
111639ee7a7aSBaptiste Daroussin 				new_obj->next = NULL;
111739ee7a7aSBaptiste Daroussin 
111839ee7a7aSBaptiste Daroussin 				nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
1119*d9f0ce31SBaptiste Daroussin 				if (nest_obj == NULL) {
1120*d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err, "cannot allocate memory for an object");
1121*d9f0ce31SBaptiste Daroussin 					if (buf) {
1122*d9f0ce31SBaptiste Daroussin 						ucl_munmap (buf, buflen);
1123*d9f0ce31SBaptiste Daroussin 					}
1124*d9f0ce31SBaptiste Daroussin 
1125*d9f0ce31SBaptiste Daroussin 					return false;
1126*d9f0ce31SBaptiste Daroussin 				}
112739ee7a7aSBaptiste Daroussin 				nest_obj->prev = nest_obj;
112839ee7a7aSBaptiste Daroussin 				nest_obj->next = NULL;
112939ee7a7aSBaptiste Daroussin 
113039ee7a7aSBaptiste Daroussin 				ucl_array_append (new_obj, old_obj);
113139ee7a7aSBaptiste Daroussin 				ucl_array_append (new_obj, nest_obj);
113239ee7a7aSBaptiste Daroussin 				ucl_hash_replace (container, old_obj, new_obj);
113339ee7a7aSBaptiste Daroussin 			}
113439ee7a7aSBaptiste Daroussin 		}
113539ee7a7aSBaptiste Daroussin 		else {
113639ee7a7aSBaptiste Daroussin 			if (ucl_object_type (old_obj) == UCL_OBJECT) {
113739ee7a7aSBaptiste Daroussin 				/* Append to existing Object*/
113839ee7a7aSBaptiste Daroussin 				nest_obj = old_obj;
113939ee7a7aSBaptiste Daroussin 			}
114039ee7a7aSBaptiste Daroussin 			else {
114139ee7a7aSBaptiste Daroussin 				/* The key is not an object */
114239ee7a7aSBaptiste Daroussin 				ucl_create_err (&parser->err,
114339ee7a7aSBaptiste Daroussin 						"Conflicting type for key: %s",
114439ee7a7aSBaptiste Daroussin 						params->prefix);
1145*d9f0ce31SBaptiste Daroussin 				if (buf) {
1146*d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
1147*d9f0ce31SBaptiste Daroussin 				}
1148*d9f0ce31SBaptiste Daroussin 
114939ee7a7aSBaptiste Daroussin 				return false;
115039ee7a7aSBaptiste Daroussin 			}
115139ee7a7aSBaptiste Daroussin 		}
115239ee7a7aSBaptiste Daroussin 
115339ee7a7aSBaptiste Daroussin 		 /* Put all of the content of the include inside that object */
115439ee7a7aSBaptiste Daroussin 		parser->stack->obj->value.ov = container;
115539ee7a7aSBaptiste Daroussin 
115639ee7a7aSBaptiste Daroussin 		st = UCL_ALLOC (sizeof (struct ucl_stack));
115739ee7a7aSBaptiste Daroussin 		if (st == NULL) {
115839ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for an object");
115939ee7a7aSBaptiste Daroussin 			ucl_object_unref (nest_obj);
1160*d9f0ce31SBaptiste Daroussin 
1161*d9f0ce31SBaptiste Daroussin 			if (buf) {
1162*d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1163*d9f0ce31SBaptiste Daroussin 			}
1164*d9f0ce31SBaptiste Daroussin 
1165*d9f0ce31SBaptiste Daroussin 			return false;
116639ee7a7aSBaptiste Daroussin 		}
116739ee7a7aSBaptiste Daroussin 		st->obj = nest_obj;
116839ee7a7aSBaptiste Daroussin 		st->level = parser->stack->level;
116939ee7a7aSBaptiste Daroussin 		LL_PREPEND (parser->stack, st);
117039ee7a7aSBaptiste Daroussin 		parser->cur_obj = nest_obj;
117139ee7a7aSBaptiste Daroussin 	}
117239ee7a7aSBaptiste Daroussin 
117339ee7a7aSBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority,
117439ee7a7aSBaptiste Daroussin 			params->strat, params->parse_type);
117539ee7a7aSBaptiste Daroussin 	if (!res && !params->must_exist) {
11764bf54857SBaptiste Daroussin 		/* Free error */
11774bf54857SBaptiste Daroussin 		utstring_free (parser->err);
11784bf54857SBaptiste Daroussin 		parser->err = NULL;
11794bf54857SBaptiste Daroussin 		parser->state = UCL_STATE_AFTER_VALUE;
11804bf54857SBaptiste Daroussin 	}
11814bf54857SBaptiste Daroussin 
118239ee7a7aSBaptiste Daroussin 	/* Stop nesting the include, take 1 level off the stack */
118339ee7a7aSBaptiste Daroussin 	if (params->prefix != NULL && nest_obj != NULL) {
118439ee7a7aSBaptiste Daroussin 		parser->stack = st->next;
118539ee7a7aSBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_stack), st);
118639ee7a7aSBaptiste Daroussin 	}
118739ee7a7aSBaptiste Daroussin 
1188c99fb5f9SBaptiste Daroussin 	/* Remove chunk from the stack */
1189c99fb5f9SBaptiste Daroussin 	chunk = parser->chunks;
1190c99fb5f9SBaptiste Daroussin 	if (chunk != NULL) {
1191c99fb5f9SBaptiste Daroussin 		parser->chunks = chunk->next;
1192c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_chunk), chunk);
11934bf54857SBaptiste Daroussin 		parser->recursion --;
1194c99fb5f9SBaptiste Daroussin 	}
11954bf54857SBaptiste Daroussin 
11964bf54857SBaptiste Daroussin 	/* Restore old file vars */
119739ee7a7aSBaptiste Daroussin 	if (parser->cur_file) {
119839ee7a7aSBaptiste Daroussin 		free (parser->cur_file);
119939ee7a7aSBaptiste Daroussin 	}
120039ee7a7aSBaptiste Daroussin 
12014bf54857SBaptiste Daroussin 	parser->cur_file = old_curfile;
12024bf54857SBaptiste Daroussin 	DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
12034bf54857SBaptiste Daroussin 		if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
12044bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
12054bf54857SBaptiste Daroussin 			free (cur_var->var);
12064bf54857SBaptiste Daroussin 			free (cur_var->value);
12074bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), cur_var);
12084bf54857SBaptiste Daroussin 		}
12094bf54857SBaptiste Daroussin 		else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
12104bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, cur_var);
12114bf54857SBaptiste Daroussin 			free (cur_var->var);
12124bf54857SBaptiste Daroussin 			free (cur_var->value);
12134bf54857SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), cur_var);
12144bf54857SBaptiste Daroussin 		}
12154bf54857SBaptiste Daroussin 	}
12164bf54857SBaptiste Daroussin 	if (old_filename) {
12174bf54857SBaptiste Daroussin 		DL_APPEND (parser->variables, old_filename);
12184bf54857SBaptiste Daroussin 	}
12194bf54857SBaptiste Daroussin 	if (old_curdir) {
12204bf54857SBaptiste Daroussin 		DL_APPEND (parser->variables, old_curdir);
12214bf54857SBaptiste Daroussin 	}
1222c99fb5f9SBaptiste Daroussin 
1223c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
1224c99fb5f9SBaptiste Daroussin 
1225c99fb5f9SBaptiste Daroussin 	if (buflen > 0) {
122697bd480fSBaptiste Daroussin 		ucl_munmap (buf, buflen);
1227c99fb5f9SBaptiste Daroussin 	}
1228c99fb5f9SBaptiste Daroussin 
1229c99fb5f9SBaptiste Daroussin 	return res;
1230c99fb5f9SBaptiste Daroussin }
1231c99fb5f9SBaptiste Daroussin 
1232c99fb5f9SBaptiste Daroussin /**
12334bf54857SBaptiste Daroussin  * Include a file to configuration
12344bf54857SBaptiste Daroussin  * @param data
12354bf54857SBaptiste Daroussin  * @param len
12364bf54857SBaptiste Daroussin  * @param parser
12374bf54857SBaptiste Daroussin  * @param err
12384bf54857SBaptiste Daroussin  * @return
12394bf54857SBaptiste Daroussin  */
12404bf54857SBaptiste Daroussin static bool
12414bf54857SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len,
124239ee7a7aSBaptiste Daroussin 		struct ucl_parser *parser, struct ucl_include_params *params)
12434bf54857SBaptiste Daroussin {
12444bf54857SBaptiste Daroussin 	const unsigned char *p = data, *end = data + len;
12454bf54857SBaptiste Daroussin 	bool need_glob = false;
12464bf54857SBaptiste Daroussin 	int cnt = 0;
12474bf54857SBaptiste Daroussin 	char glob_pattern[PATH_MAX];
12484bf54857SBaptiste Daroussin 	size_t i;
12494bf54857SBaptiste Daroussin 
12508e3b1ab2SBaptiste Daroussin #ifndef _WIN32
125139ee7a7aSBaptiste Daroussin 	if (!params->allow_glob) {
125239ee7a7aSBaptiste Daroussin 		return ucl_include_file_single (data, len, parser, params);
12534bf54857SBaptiste Daroussin 	}
12544bf54857SBaptiste Daroussin 	else {
12554bf54857SBaptiste Daroussin 		/* Check for special symbols in a filename */
12564bf54857SBaptiste Daroussin 		while (p != end) {
12574bf54857SBaptiste Daroussin 			if (*p == '*' || *p == '?') {
12584bf54857SBaptiste Daroussin 				need_glob = true;
12594bf54857SBaptiste Daroussin 				break;
12604bf54857SBaptiste Daroussin 			}
12614bf54857SBaptiste Daroussin 			p ++;
12624bf54857SBaptiste Daroussin 		}
12634bf54857SBaptiste Daroussin 		if (need_glob) {
12648e3b1ab2SBaptiste Daroussin 			glob_t globbuf;
12654bf54857SBaptiste Daroussin 			memset (&globbuf, 0, sizeof (globbuf));
126639ee7a7aSBaptiste Daroussin 			ucl_strlcpy (glob_pattern, (const char *)data,
126739ee7a7aSBaptiste Daroussin 				(len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern)));
12684bf54857SBaptiste Daroussin 			if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
126939ee7a7aSBaptiste Daroussin 				return (!params->must_exist || false);
12704bf54857SBaptiste Daroussin 			}
12714bf54857SBaptiste Daroussin 			for (i = 0; i < globbuf.gl_pathc; i ++) {
12724bf54857SBaptiste Daroussin 				if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
127339ee7a7aSBaptiste Daroussin 						strlen (globbuf.gl_pathv[i]), parser, params)) {
127439ee7a7aSBaptiste Daroussin 					if (params->soft_fail) {
127539ee7a7aSBaptiste Daroussin 						continue;
127639ee7a7aSBaptiste Daroussin 					}
12774bf54857SBaptiste Daroussin 					globfree (&globbuf);
12784bf54857SBaptiste Daroussin 					return false;
12794bf54857SBaptiste Daroussin 				}
12804bf54857SBaptiste Daroussin 				cnt ++;
12814bf54857SBaptiste Daroussin 			}
12824bf54857SBaptiste Daroussin 			globfree (&globbuf);
12834bf54857SBaptiste Daroussin 
128439ee7a7aSBaptiste Daroussin 			if (cnt == 0 && params->must_exist) {
12854bf54857SBaptiste Daroussin 				ucl_create_err (&parser->err, "cannot match any files for pattern %s",
12864bf54857SBaptiste Daroussin 					glob_pattern);
12874bf54857SBaptiste Daroussin 				return false;
12884bf54857SBaptiste Daroussin 			}
12894bf54857SBaptiste Daroussin 		}
12904bf54857SBaptiste Daroussin 		else {
129139ee7a7aSBaptiste Daroussin 			return ucl_include_file_single (data, len, parser, params);
12924bf54857SBaptiste Daroussin 		}
12934bf54857SBaptiste Daroussin 	}
12948e3b1ab2SBaptiste Daroussin #else
12958e3b1ab2SBaptiste Daroussin 	/* Win32 compilers do not support globbing. Therefore, for Win32,
12968e3b1ab2SBaptiste Daroussin 	   treat allow_glob/need_glob as a NOOP and just return */
129739ee7a7aSBaptiste Daroussin 	return ucl_include_file_single (data, len, parser, params);
12988e3b1ab2SBaptiste Daroussin #endif
12994bf54857SBaptiste Daroussin 
13004bf54857SBaptiste Daroussin 	return true;
13014bf54857SBaptiste Daroussin }
13024bf54857SBaptiste Daroussin 
13034bf54857SBaptiste Daroussin /**
13044bf54857SBaptiste Daroussin  * Common function to handle .*include* macros
13054bf54857SBaptiste Daroussin  * @param data
13064bf54857SBaptiste Daroussin  * @param len
13074bf54857SBaptiste Daroussin  * @param args
13084bf54857SBaptiste Daroussin  * @param parser
13094bf54857SBaptiste Daroussin  * @param default_try
13104bf54857SBaptiste Daroussin  * @param default_sign
13114bf54857SBaptiste Daroussin  * @return
13124bf54857SBaptiste Daroussin  */
13134bf54857SBaptiste Daroussin static bool
13144bf54857SBaptiste Daroussin ucl_include_common (const unsigned char *data, size_t len,
13154bf54857SBaptiste Daroussin 		const ucl_object_t *args, struct ucl_parser *parser,
13164bf54857SBaptiste Daroussin 		bool default_try,
13174bf54857SBaptiste Daroussin 		bool default_sign)
13184bf54857SBaptiste Daroussin {
1319*d9f0ce31SBaptiste Daroussin 	bool allow_url = false, search = false;
132039ee7a7aSBaptiste Daroussin 	const char *duplicate;
13214bf54857SBaptiste Daroussin 	const ucl_object_t *param;
132239ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL, ip = NULL;
132339ee7a7aSBaptiste Daroussin 	char ipath[PATH_MAX];
132439ee7a7aSBaptiste Daroussin 	struct ucl_include_params params;
13254bf54857SBaptiste Daroussin 
13264bf54857SBaptiste Daroussin 	/* Default values */
132739ee7a7aSBaptiste Daroussin 	params.soft_fail = default_try;
132839ee7a7aSBaptiste Daroussin 	params.allow_glob = false;
132939ee7a7aSBaptiste Daroussin 	params.check_signature = default_sign;
133039ee7a7aSBaptiste Daroussin 	params.use_prefix = false;
133139ee7a7aSBaptiste Daroussin 	params.target = "object";
133239ee7a7aSBaptiste Daroussin 	params.prefix = NULL;
133339ee7a7aSBaptiste Daroussin 	params.priority = 0;
133439ee7a7aSBaptiste Daroussin 	params.parse_type = UCL_PARSE_UCL;
133539ee7a7aSBaptiste Daroussin 	params.strat = UCL_DUPLICATE_APPEND;
133639ee7a7aSBaptiste Daroussin 	params.must_exist = !default_try;
133739ee7a7aSBaptiste Daroussin 
13384bf54857SBaptiste Daroussin 	/* Process arguments */
13394bf54857SBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1340*d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
13414bf54857SBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
134239ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
134339ee7a7aSBaptiste Daroussin 					params.must_exist = !ucl_object_toboolean (param);
13444bf54857SBaptiste Daroussin 				}
134539ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "sign", param->keylen) == 0) {
134639ee7a7aSBaptiste Daroussin 					params.check_signature = ucl_object_toboolean (param);
13474bf54857SBaptiste Daroussin 				}
134839ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "glob", param->keylen) == 0) {
134939ee7a7aSBaptiste Daroussin 					params.allow_glob = ucl_object_toboolean (param);
13504bf54857SBaptiste Daroussin 				}
135139ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "url", param->keylen) == 0) {
13524bf54857SBaptiste Daroussin 					allow_url = ucl_object_toboolean (param);
13534bf54857SBaptiste Daroussin 				}
135439ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "prefix", param->keylen) == 0) {
135539ee7a7aSBaptiste Daroussin 					params.use_prefix = ucl_object_toboolean (param);
135639ee7a7aSBaptiste Daroussin 				}
135739ee7a7aSBaptiste Daroussin 			}
135839ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
135939ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
136039ee7a7aSBaptiste Daroussin 					params.prefix = ucl_object_tostring (param);
136139ee7a7aSBaptiste Daroussin 				}
136239ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
136339ee7a7aSBaptiste Daroussin 					params.target = ucl_object_tostring (param);
136439ee7a7aSBaptiste Daroussin 				}
136539ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "duplicate", param->keylen) == 0) {
136639ee7a7aSBaptiste Daroussin 					duplicate = ucl_object_tostring (param);
136739ee7a7aSBaptiste Daroussin 
136839ee7a7aSBaptiste Daroussin 					if (strcmp (duplicate, "append") == 0) {
136939ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_APPEND;
137039ee7a7aSBaptiste Daroussin 					}
137139ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "merge") == 0) {
137239ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_MERGE;
137339ee7a7aSBaptiste Daroussin 					}
137439ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "rewrite") == 0) {
137539ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_REWRITE;
137639ee7a7aSBaptiste Daroussin 					}
137739ee7a7aSBaptiste Daroussin 					else if (strcmp (duplicate, "error") == 0) {
137839ee7a7aSBaptiste Daroussin 						params.strat = UCL_DUPLICATE_ERROR;
137939ee7a7aSBaptiste Daroussin 					}
138039ee7a7aSBaptiste Daroussin 				}
138139ee7a7aSBaptiste Daroussin 			}
138239ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_ARRAY) {
138339ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "path", param->keylen) == 0) {
138439ee7a7aSBaptiste Daroussin 					ucl_set_include_path (parser, __DECONST(ucl_object_t *, param));
138539ee7a7aSBaptiste Daroussin 				}
13864bf54857SBaptiste Daroussin 			}
13874bf54857SBaptiste Daroussin 			else if (param->type == UCL_INT) {
138839ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
138939ee7a7aSBaptiste Daroussin 					params.priority = ucl_object_toint (param);
13904bf54857SBaptiste Daroussin 				}
13914bf54857SBaptiste Daroussin 			}
13924bf54857SBaptiste Daroussin 		}
13934bf54857SBaptiste Daroussin 	}
13944bf54857SBaptiste Daroussin 
139539ee7a7aSBaptiste Daroussin 	if (parser->includepaths == NULL) {
139639ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
13974bf54857SBaptiste Daroussin 			/* Globbing is not used for URL's */
139839ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
139939ee7a7aSBaptiste Daroussin 		}
140039ee7a7aSBaptiste Daroussin 		else if (data != NULL) {
140139ee7a7aSBaptiste Daroussin 			/* Try to load a file */
140239ee7a7aSBaptiste Daroussin 			return ucl_include_file (data, len, parser, &params);
140339ee7a7aSBaptiste Daroussin 		}
140439ee7a7aSBaptiste Daroussin 	}
140539ee7a7aSBaptiste Daroussin 	else {
140639ee7a7aSBaptiste Daroussin 		if (allow_url && ucl_strnstr (data, "://", len) != NULL) {
140739ee7a7aSBaptiste Daroussin 			/* Globbing is not used for URL's */
140839ee7a7aSBaptiste Daroussin 			return ucl_include_url (data, len, parser, &params);
140939ee7a7aSBaptiste Daroussin 		}
141039ee7a7aSBaptiste Daroussin 
141139ee7a7aSBaptiste Daroussin 		ip = ucl_object_iterate_new (parser->includepaths);
141239ee7a7aSBaptiste Daroussin 		while ((param = ucl_object_iterate_safe (ip, true)) != NULL) {
141339ee7a7aSBaptiste Daroussin 			if (ucl_object_type(param) == UCL_STRING) {
141439ee7a7aSBaptiste Daroussin 				snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param),
141539ee7a7aSBaptiste Daroussin 						(int)len, data);
141639ee7a7aSBaptiste Daroussin 				if ((search = ucl_include_file (ipath, strlen (ipath),
141739ee7a7aSBaptiste Daroussin 						parser, &params))) {
141839ee7a7aSBaptiste Daroussin 					if (!params.allow_glob) {
141939ee7a7aSBaptiste Daroussin 						break;
142039ee7a7aSBaptiste Daroussin 					}
142139ee7a7aSBaptiste Daroussin 				}
142239ee7a7aSBaptiste Daroussin 			}
142339ee7a7aSBaptiste Daroussin 		}
142439ee7a7aSBaptiste Daroussin 		ucl_object_iterate_free (ip);
142539ee7a7aSBaptiste Daroussin 		if (search == true) {
142639ee7a7aSBaptiste Daroussin 			return true;
142739ee7a7aSBaptiste Daroussin 		}
142839ee7a7aSBaptiste Daroussin 		else {
142939ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err,
143039ee7a7aSBaptiste Daroussin 					"cannot find file: %.*s in search path",
143139ee7a7aSBaptiste Daroussin 					(int)len, data);
143239ee7a7aSBaptiste Daroussin 			return false;
143339ee7a7aSBaptiste Daroussin 		}
14344bf54857SBaptiste Daroussin 	}
14354bf54857SBaptiste Daroussin 
14364bf54857SBaptiste Daroussin 	return false;
14374bf54857SBaptiste Daroussin }
14384bf54857SBaptiste Daroussin 
14394bf54857SBaptiste Daroussin /**
1440c99fb5f9SBaptiste Daroussin  * Handle include macro
1441c99fb5f9SBaptiste Daroussin  * @param data include data
1442c99fb5f9SBaptiste Daroussin  * @param len length of data
144339ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1444c99fb5f9SBaptiste Daroussin  * @param ud user data
1445c99fb5f9SBaptiste Daroussin  * @return
1446c99fb5f9SBaptiste Daroussin  */
144739ee7a7aSBaptiste Daroussin bool
14484bf54857SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len,
14494bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1450c99fb5f9SBaptiste Daroussin {
1451c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1452c99fb5f9SBaptiste Daroussin 
14534bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, false);
1454c99fb5f9SBaptiste Daroussin }
1455c99fb5f9SBaptiste Daroussin 
1456c99fb5f9SBaptiste Daroussin /**
1457c99fb5f9SBaptiste Daroussin  * Handle includes macro
1458c99fb5f9SBaptiste Daroussin  * @param data include data
1459c99fb5f9SBaptiste Daroussin  * @param len length of data
146039ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
1461c99fb5f9SBaptiste Daroussin  * @param ud user data
1462c99fb5f9SBaptiste Daroussin  * @return
1463c99fb5f9SBaptiste Daroussin  */
146439ee7a7aSBaptiste Daroussin bool
14654bf54857SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len,
14664bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1467c99fb5f9SBaptiste Daroussin {
1468c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1469c99fb5f9SBaptiste Daroussin 
14704bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, false, true);
1471c99fb5f9SBaptiste Daroussin }
1472c99fb5f9SBaptiste Daroussin 
147339ee7a7aSBaptiste Daroussin /**
147439ee7a7aSBaptiste Daroussin  * Handle tryinclude macro
147539ee7a7aSBaptiste Daroussin  * @param data include data
147639ee7a7aSBaptiste Daroussin  * @param len length of data
147739ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
147839ee7a7aSBaptiste Daroussin  * @param ud user data
147939ee7a7aSBaptiste Daroussin  * @return
148039ee7a7aSBaptiste Daroussin  */
148139ee7a7aSBaptiste Daroussin bool
14824bf54857SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len,
14834bf54857SBaptiste Daroussin 		const ucl_object_t *args, void* ud)
1484c99fb5f9SBaptiste Daroussin {
1485c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
1486c99fb5f9SBaptiste Daroussin 
14874bf54857SBaptiste Daroussin 	return ucl_include_common (data, len, args, parser, true, false);
1488c99fb5f9SBaptiste Daroussin }
1489c99fb5f9SBaptiste Daroussin 
149039ee7a7aSBaptiste Daroussin /**
149139ee7a7aSBaptiste Daroussin  * Handle priority macro
149239ee7a7aSBaptiste Daroussin  * @param data include data
149339ee7a7aSBaptiste Daroussin  * @param len length of data
149439ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
149539ee7a7aSBaptiste Daroussin  * @param ud user data
149639ee7a7aSBaptiste Daroussin  * @return
149739ee7a7aSBaptiste Daroussin  */
149839ee7a7aSBaptiste Daroussin bool
149939ee7a7aSBaptiste Daroussin ucl_priority_handler (const unsigned char *data, size_t len,
150039ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
150139ee7a7aSBaptiste Daroussin {
150239ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
150339ee7a7aSBaptiste Daroussin 	unsigned priority = 255;
150439ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
150539ee7a7aSBaptiste Daroussin 	bool found = false;
150639ee7a7aSBaptiste Daroussin 	char *value = NULL, *leftover = NULL;
150739ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
150839ee7a7aSBaptiste Daroussin 
150939ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
151039ee7a7aSBaptiste Daroussin 		return false;
151139ee7a7aSBaptiste Daroussin 	}
151239ee7a7aSBaptiste Daroussin 
151339ee7a7aSBaptiste Daroussin 	/* Process arguments */
151439ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1515*d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
151639ee7a7aSBaptiste Daroussin 			if (param->type == UCL_INT) {
151739ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
151839ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
151939ee7a7aSBaptiste Daroussin 					found = true;
152039ee7a7aSBaptiste Daroussin 				}
152139ee7a7aSBaptiste Daroussin 			}
152239ee7a7aSBaptiste Daroussin 		}
152339ee7a7aSBaptiste Daroussin 	}
152439ee7a7aSBaptiste Daroussin 
152539ee7a7aSBaptiste Daroussin 	if (len > 0) {
152639ee7a7aSBaptiste Daroussin 		value = malloc(len + 1);
152739ee7a7aSBaptiste Daroussin 		ucl_strlcpy(value, (const char *)data, len + 1);
152839ee7a7aSBaptiste Daroussin 		priority = strtol(value, &leftover, 10);
152939ee7a7aSBaptiste Daroussin 		if (*leftover != '\0') {
153039ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Invalid priority value in macro: %s",
153139ee7a7aSBaptiste Daroussin 				value);
153239ee7a7aSBaptiste Daroussin 			free(value);
153339ee7a7aSBaptiste Daroussin 			return false;
153439ee7a7aSBaptiste Daroussin 		}
153539ee7a7aSBaptiste Daroussin 		free(value);
153639ee7a7aSBaptiste Daroussin 		found = true;
153739ee7a7aSBaptiste Daroussin 	}
153839ee7a7aSBaptiste Daroussin 
153939ee7a7aSBaptiste Daroussin 	if (found == true) {
154039ee7a7aSBaptiste Daroussin 		parser->chunks->priority = priority;
154139ee7a7aSBaptiste Daroussin 		return true;
154239ee7a7aSBaptiste Daroussin 	}
154339ee7a7aSBaptiste Daroussin 
154439ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse priority macro");
154539ee7a7aSBaptiste Daroussin 	return false;
154639ee7a7aSBaptiste Daroussin }
154739ee7a7aSBaptiste Daroussin 
154839ee7a7aSBaptiste Daroussin /**
154939ee7a7aSBaptiste Daroussin  * Handle load macro
155039ee7a7aSBaptiste Daroussin  * @param data include data
155139ee7a7aSBaptiste Daroussin  * @param len length of data
155239ee7a7aSBaptiste Daroussin  * @param args UCL object representing arguments to the macro
155339ee7a7aSBaptiste Daroussin  * @param ud user data
155439ee7a7aSBaptiste Daroussin  * @return
155539ee7a7aSBaptiste Daroussin  */
155639ee7a7aSBaptiste Daroussin bool
155739ee7a7aSBaptiste Daroussin ucl_load_handler (const unsigned char *data, size_t len,
155839ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, void* ud)
155939ee7a7aSBaptiste Daroussin {
156039ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
156139ee7a7aSBaptiste Daroussin 	const ucl_object_t *param;
156239ee7a7aSBaptiste Daroussin 	ucl_object_t *obj, *old_obj;
156339ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
156439ee7a7aSBaptiste Daroussin 	bool try_load, multiline, test;
156539ee7a7aSBaptiste Daroussin 	const char *target, *prefix;
156639ee7a7aSBaptiste Daroussin 	char *load_file, *tmp;
156739ee7a7aSBaptiste Daroussin 	unsigned char *buf;
156839ee7a7aSBaptiste Daroussin 	size_t buflen;
156939ee7a7aSBaptiste Daroussin 	unsigned priority;
157039ee7a7aSBaptiste Daroussin 	int64_t iv;
1571*d9f0ce31SBaptiste Daroussin 	ucl_object_t *container = NULL;
157239ee7a7aSBaptiste Daroussin 	enum ucl_string_flags flags;
157339ee7a7aSBaptiste Daroussin 
157439ee7a7aSBaptiste Daroussin 	/* Default values */
157539ee7a7aSBaptiste Daroussin 	try_load = false;
157639ee7a7aSBaptiste Daroussin 	multiline = false;
157739ee7a7aSBaptiste Daroussin 	test = false;
157839ee7a7aSBaptiste Daroussin 	target = "string";
157939ee7a7aSBaptiste Daroussin 	prefix = NULL;
158039ee7a7aSBaptiste Daroussin 	load_file = NULL;
158139ee7a7aSBaptiste Daroussin 	buf = NULL;
158239ee7a7aSBaptiste Daroussin 	buflen = 0;
158339ee7a7aSBaptiste Daroussin 	priority = 0;
158439ee7a7aSBaptiste Daroussin 	obj = NULL;
158539ee7a7aSBaptiste Daroussin 	old_obj = NULL;
158639ee7a7aSBaptiste Daroussin 	flags = 0;
158739ee7a7aSBaptiste Daroussin 
158839ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
158939ee7a7aSBaptiste Daroussin 		return false;
159039ee7a7aSBaptiste Daroussin 	}
159139ee7a7aSBaptiste Daroussin 
159239ee7a7aSBaptiste Daroussin 	/* Process arguments */
159339ee7a7aSBaptiste Daroussin 	if (args != NULL && args->type == UCL_OBJECT) {
1594*d9f0ce31SBaptiste Daroussin 		while ((param = ucl_object_iterate (args, &it, true)) != NULL) {
159539ee7a7aSBaptiste Daroussin 			if (param->type == UCL_BOOLEAN) {
159639ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "try", param->keylen) == 0) {
159739ee7a7aSBaptiste Daroussin 					try_load = ucl_object_toboolean (param);
159839ee7a7aSBaptiste Daroussin 				}
159939ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "multiline", param->keylen) == 0) {
160039ee7a7aSBaptiste Daroussin 					multiline = ucl_object_toboolean (param);
160139ee7a7aSBaptiste Daroussin 				}
160239ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "escape", param->keylen) == 0) {
160339ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
160439ee7a7aSBaptiste Daroussin 					if (test) {
160539ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_ESCAPE;
160639ee7a7aSBaptiste Daroussin 					}
160739ee7a7aSBaptiste Daroussin 				}
160839ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "trim", param->keylen) == 0) {
160939ee7a7aSBaptiste Daroussin 					test = ucl_object_toboolean (param);
161039ee7a7aSBaptiste Daroussin 					if (test) {
161139ee7a7aSBaptiste Daroussin 						flags |= UCL_STRING_TRIM;
161239ee7a7aSBaptiste Daroussin 					}
161339ee7a7aSBaptiste Daroussin 				}
161439ee7a7aSBaptiste Daroussin 			}
161539ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_STRING) {
161639ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "key", param->keylen) == 0) {
161739ee7a7aSBaptiste Daroussin 					prefix = ucl_object_tostring (param);
161839ee7a7aSBaptiste Daroussin 				}
161939ee7a7aSBaptiste Daroussin 				else if (strncmp (param->key, "target", param->keylen) == 0) {
162039ee7a7aSBaptiste Daroussin 					target = ucl_object_tostring (param);
162139ee7a7aSBaptiste Daroussin 				}
162239ee7a7aSBaptiste Daroussin 			}
162339ee7a7aSBaptiste Daroussin 			else if (param->type == UCL_INT) {
162439ee7a7aSBaptiste Daroussin 				if (strncmp (param->key, "priority", param->keylen) == 0) {
162539ee7a7aSBaptiste Daroussin 					priority = ucl_object_toint (param);
162639ee7a7aSBaptiste Daroussin 				}
162739ee7a7aSBaptiste Daroussin 			}
162839ee7a7aSBaptiste Daroussin 		}
162939ee7a7aSBaptiste Daroussin 	}
163039ee7a7aSBaptiste Daroussin 
163139ee7a7aSBaptiste Daroussin 	if (prefix == NULL || strlen (prefix) == 0) {
163239ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "No Key specified in load macro");
163339ee7a7aSBaptiste Daroussin 		return false;
163439ee7a7aSBaptiste Daroussin 	}
163539ee7a7aSBaptiste Daroussin 
163639ee7a7aSBaptiste Daroussin 	if (len > 0) {
1637*d9f0ce31SBaptiste Daroussin 		load_file = malloc (len + 1);
1638*d9f0ce31SBaptiste Daroussin 		if (!load_file) {
1639*d9f0ce31SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate memory for suffix");
1640*d9f0ce31SBaptiste Daroussin 
1641*d9f0ce31SBaptiste Daroussin 			return false;
1642*d9f0ce31SBaptiste Daroussin 		}
1643*d9f0ce31SBaptiste Daroussin 
1644*d9f0ce31SBaptiste Daroussin 		snprintf (load_file, len + 1, "%.*s", (int)len, data);
1645*d9f0ce31SBaptiste Daroussin 
1646*d9f0ce31SBaptiste Daroussin 		if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err,
1647*d9f0ce31SBaptiste Daroussin 				!try_load)) {
1648*d9f0ce31SBaptiste Daroussin 			free (load_file);
1649*d9f0ce31SBaptiste Daroussin 
165039ee7a7aSBaptiste Daroussin 			return (try_load || false);
165139ee7a7aSBaptiste Daroussin 		}
165239ee7a7aSBaptiste Daroussin 
1653*d9f0ce31SBaptiste Daroussin 		free (load_file);
1654*d9f0ce31SBaptiste Daroussin 		container = parser->stack->obj;
1655*d9f0ce31SBaptiste Daroussin 		old_obj = __DECONST (ucl_object_t *, ucl_object_lookup (container,
1656*d9f0ce31SBaptiste Daroussin 				prefix));
1657*d9f0ce31SBaptiste Daroussin 
165839ee7a7aSBaptiste Daroussin 		if (old_obj != NULL) {
165939ee7a7aSBaptiste Daroussin 			ucl_create_err (&parser->err, "Key %s already exists", prefix);
1660*d9f0ce31SBaptiste Daroussin 			if (buf) {
1661*d9f0ce31SBaptiste Daroussin 				ucl_munmap (buf, buflen);
1662*d9f0ce31SBaptiste Daroussin 			}
1663*d9f0ce31SBaptiste Daroussin 
166439ee7a7aSBaptiste Daroussin 			return false;
166539ee7a7aSBaptiste Daroussin 		}
166639ee7a7aSBaptiste Daroussin 
166739ee7a7aSBaptiste Daroussin 		if (strcasecmp (target, "string") == 0) {
166839ee7a7aSBaptiste Daroussin 			obj = ucl_object_fromstring_common (buf, buflen, flags);
166939ee7a7aSBaptiste Daroussin 			ucl_copy_value_trash (obj);
167039ee7a7aSBaptiste Daroussin 			if (multiline) {
167139ee7a7aSBaptiste Daroussin 				obj->flags |= UCL_OBJECT_MULTILINE;
167239ee7a7aSBaptiste Daroussin 			}
167339ee7a7aSBaptiste Daroussin 		}
167439ee7a7aSBaptiste Daroussin 		else if (strcasecmp (target, "int") == 0) {
1675*d9f0ce31SBaptiste Daroussin 			tmp = malloc (buflen + 1);
1676*d9f0ce31SBaptiste Daroussin 
1677*d9f0ce31SBaptiste Daroussin 			if (tmp == NULL) {
1678*d9f0ce31SBaptiste Daroussin 				ucl_create_err (&parser->err, "Memory allocation failed");
1679*d9f0ce31SBaptiste Daroussin 				if (buf) {
1680*d9f0ce31SBaptiste Daroussin 					ucl_munmap (buf, buflen);
168139ee7a7aSBaptiste Daroussin 				}
168239ee7a7aSBaptiste Daroussin 
1683*d9f0ce31SBaptiste Daroussin 				return false;
1684*d9f0ce31SBaptiste Daroussin 			}
1685*d9f0ce31SBaptiste Daroussin 
1686*d9f0ce31SBaptiste Daroussin 			snprintf (tmp, buflen + 1, "%.*s", (int)buflen, buf);
1687*d9f0ce31SBaptiste Daroussin 			iv = strtoll (tmp, NULL, 10);
1688*d9f0ce31SBaptiste Daroussin 			obj = ucl_object_fromint (iv);
1689*d9f0ce31SBaptiste Daroussin 			free (tmp);
1690*d9f0ce31SBaptiste Daroussin 		}
1691*d9f0ce31SBaptiste Daroussin 
1692*d9f0ce31SBaptiste Daroussin 		if (buf) {
169339ee7a7aSBaptiste Daroussin 			ucl_munmap (buf, buflen);
169439ee7a7aSBaptiste Daroussin 		}
169539ee7a7aSBaptiste Daroussin 
169639ee7a7aSBaptiste Daroussin 		if (obj != NULL) {
169739ee7a7aSBaptiste Daroussin 			obj->key = prefix;
169839ee7a7aSBaptiste Daroussin 			obj->keylen = strlen (prefix);
169939ee7a7aSBaptiste Daroussin 			ucl_copy_key_trash (obj);
170039ee7a7aSBaptiste Daroussin 			obj->prev = obj;
170139ee7a7aSBaptiste Daroussin 			obj->next = NULL;
170239ee7a7aSBaptiste Daroussin 			ucl_object_set_priority (obj, priority);
1703*d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (container, obj, obj->key, obj->keylen, false);
170439ee7a7aSBaptiste Daroussin 		}
1705*d9f0ce31SBaptiste Daroussin 
170639ee7a7aSBaptiste Daroussin 		return true;
170739ee7a7aSBaptiste Daroussin 	}
170839ee7a7aSBaptiste Daroussin 
170939ee7a7aSBaptiste Daroussin 	ucl_create_err (&parser->err, "Unable to parse load macro");
171039ee7a7aSBaptiste Daroussin 	return false;
171139ee7a7aSBaptiste Daroussin }
171239ee7a7aSBaptiste Daroussin 
171339ee7a7aSBaptiste Daroussin bool
171439ee7a7aSBaptiste Daroussin ucl_inherit_handler (const unsigned char *data, size_t len,
171539ee7a7aSBaptiste Daroussin 		const ucl_object_t *args, const ucl_object_t *ctx, void* ud)
171639ee7a7aSBaptiste Daroussin {
171739ee7a7aSBaptiste Daroussin 	const ucl_object_t *parent, *cur;
171839ee7a7aSBaptiste Daroussin 	ucl_object_t *target, *copy;
171939ee7a7aSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
172039ee7a7aSBaptiste Daroussin 	bool replace = false;
172139ee7a7aSBaptiste Daroussin 	struct ucl_parser *parser = ud;
172239ee7a7aSBaptiste Daroussin 
1723*d9f0ce31SBaptiste Daroussin 	parent = ucl_object_lookup_len (ctx, data, len);
172439ee7a7aSBaptiste Daroussin 
172539ee7a7aSBaptiste Daroussin 	/* Some sanity checks */
172639ee7a7aSBaptiste Daroussin 	if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) {
172739ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Unable to find inherited object %*.s",
172839ee7a7aSBaptiste Daroussin 				(int)len, data);
172939ee7a7aSBaptiste Daroussin 		return false;
173039ee7a7aSBaptiste Daroussin 	}
173139ee7a7aSBaptiste Daroussin 
173239ee7a7aSBaptiste Daroussin 	if (parser->stack == NULL || parser->stack->obj == NULL ||
173339ee7a7aSBaptiste Daroussin 			ucl_object_type (parser->stack->obj) != UCL_OBJECT) {
173439ee7a7aSBaptiste Daroussin 		ucl_create_err (&parser->err, "Invalid inherit context");
173539ee7a7aSBaptiste Daroussin 		return false;
173639ee7a7aSBaptiste Daroussin 	}
173739ee7a7aSBaptiste Daroussin 
173839ee7a7aSBaptiste Daroussin 	target = parser->stack->obj;
173939ee7a7aSBaptiste Daroussin 
1740*d9f0ce31SBaptiste Daroussin 	if (args && (cur = ucl_object_lookup (args, "replace")) != NULL) {
174139ee7a7aSBaptiste Daroussin 		replace = ucl_object_toboolean (cur);
174239ee7a7aSBaptiste Daroussin 	}
174339ee7a7aSBaptiste Daroussin 
1744*d9f0ce31SBaptiste Daroussin 	while ((cur = ucl_object_iterate (parent, &it, true))) {
174539ee7a7aSBaptiste Daroussin 		/* We do not replace existing keys */
1746*d9f0ce31SBaptiste Daroussin 		if (!replace && ucl_object_lookup_len (target, cur->key, cur->keylen)) {
174739ee7a7aSBaptiste Daroussin 			continue;
174839ee7a7aSBaptiste Daroussin 		}
174939ee7a7aSBaptiste Daroussin 
175039ee7a7aSBaptiste Daroussin 		copy = ucl_object_copy (cur);
175139ee7a7aSBaptiste Daroussin 
175239ee7a7aSBaptiste Daroussin 		if (!replace) {
175339ee7a7aSBaptiste Daroussin 			copy->flags |= UCL_OBJECT_INHERITED;
175439ee7a7aSBaptiste Daroussin 		}
175539ee7a7aSBaptiste Daroussin 
175639ee7a7aSBaptiste Daroussin 		ucl_object_insert_key (target, copy, copy->key,
175739ee7a7aSBaptiste Daroussin 				copy->keylen, false);
175839ee7a7aSBaptiste Daroussin 	}
175939ee7a7aSBaptiste Daroussin 
176039ee7a7aSBaptiste Daroussin 	return true;
176139ee7a7aSBaptiste Daroussin }
176239ee7a7aSBaptiste Daroussin 
176339ee7a7aSBaptiste Daroussin bool
1764c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
1765c99fb5f9SBaptiste Daroussin {
1766c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX], *curdir;
1767c99fb5f9SBaptiste Daroussin 
1768c99fb5f9SBaptiste Daroussin 	if (filename != NULL) {
1769c99fb5f9SBaptiste Daroussin 		if (need_expand) {
177097bd480fSBaptiste Daroussin 			if (ucl_realpath (filename, realbuf) == NULL) {
1771c99fb5f9SBaptiste Daroussin 				return false;
1772c99fb5f9SBaptiste Daroussin 			}
1773c99fb5f9SBaptiste Daroussin 		}
1774c99fb5f9SBaptiste Daroussin 		else {
1775c99fb5f9SBaptiste Daroussin 			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
1776c99fb5f9SBaptiste Daroussin 		}
1777c99fb5f9SBaptiste Daroussin 
1778c99fb5f9SBaptiste Daroussin 		/* Define variables */
1779c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", realbuf);
1780c99fb5f9SBaptiste Daroussin 		curdir = dirname (realbuf);
1781c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1782c99fb5f9SBaptiste Daroussin 	}
1783c99fb5f9SBaptiste Daroussin 	else {
1784c99fb5f9SBaptiste Daroussin 		/* Set everything from the current dir */
1785c99fb5f9SBaptiste Daroussin 		curdir = getcwd (realbuf, sizeof (realbuf));
1786c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", "undef");
1787c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
1788c99fb5f9SBaptiste Daroussin 	}
1789c99fb5f9SBaptiste Daroussin 
1790c99fb5f9SBaptiste Daroussin 	return true;
1791c99fb5f9SBaptiste Daroussin }
1792c99fb5f9SBaptiste Daroussin 
179339ee7a7aSBaptiste Daroussin bool
179439ee7a7aSBaptiste Daroussin ucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename,
179539ee7a7aSBaptiste Daroussin 		unsigned priority)
1796c99fb5f9SBaptiste Daroussin {
1797c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
1798c99fb5f9SBaptiste Daroussin 	size_t len;
1799c99fb5f9SBaptiste Daroussin 	bool ret;
1800c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX];
1801c99fb5f9SBaptiste Daroussin 
180297bd480fSBaptiste Daroussin 	if (ucl_realpath (filename, realbuf) == NULL) {
1803c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
1804c99fb5f9SBaptiste Daroussin 				filename,
1805c99fb5f9SBaptiste Daroussin 				strerror (errno));
1806c99fb5f9SBaptiste Daroussin 		return false;
1807c99fb5f9SBaptiste Daroussin 	}
1808c99fb5f9SBaptiste Daroussin 
1809c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
1810c99fb5f9SBaptiste Daroussin 		return false;
1811c99fb5f9SBaptiste Daroussin 	}
1812c99fb5f9SBaptiste Daroussin 
18134bf54857SBaptiste Daroussin 	if (parser->cur_file) {
18144bf54857SBaptiste Daroussin 		free (parser->cur_file);
18154bf54857SBaptiste Daroussin 	}
18164bf54857SBaptiste Daroussin 	parser->cur_file = strdup (realbuf);
1817c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
181839ee7a7aSBaptiste Daroussin 	ret = ucl_parser_add_chunk_priority (parser, buf, len, priority);
1819c99fb5f9SBaptiste Daroussin 
1820c99fb5f9SBaptiste Daroussin 	if (len > 0) {
182197bd480fSBaptiste Daroussin 		ucl_munmap (buf, len);
1822c99fb5f9SBaptiste Daroussin 	}
1823c99fb5f9SBaptiste Daroussin 
1824c99fb5f9SBaptiste Daroussin 	return ret;
1825c99fb5f9SBaptiste Daroussin }
1826c99fb5f9SBaptiste Daroussin 
182739ee7a7aSBaptiste Daroussin bool
182839ee7a7aSBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
182939ee7a7aSBaptiste Daroussin {
183039ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
183139ee7a7aSBaptiste Daroussin 		return false;
183239ee7a7aSBaptiste Daroussin 	}
183339ee7a7aSBaptiste Daroussin 
183439ee7a7aSBaptiste Daroussin 	return ucl_parser_add_file_priority(parser, filename,
183539ee7a7aSBaptiste Daroussin 			parser->default_priority);
183639ee7a7aSBaptiste Daroussin }
183739ee7a7aSBaptiste Daroussin 
183839ee7a7aSBaptiste Daroussin bool
183939ee7a7aSBaptiste Daroussin ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
184039ee7a7aSBaptiste Daroussin 		unsigned priority)
18414bf54857SBaptiste Daroussin {
18424bf54857SBaptiste Daroussin 	unsigned char *buf;
18434bf54857SBaptiste Daroussin 	size_t len;
18444bf54857SBaptiste Daroussin 	bool ret;
18454bf54857SBaptiste Daroussin 	struct stat st;
18464bf54857SBaptiste Daroussin 
18474bf54857SBaptiste Daroussin 	if (fstat (fd, &st) == -1) {
18484bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot stat fd %d: %s",
18494bf54857SBaptiste Daroussin 			fd, strerror (errno));
18504bf54857SBaptiste Daroussin 		return false;
18514bf54857SBaptiste Daroussin 	}
18524bf54857SBaptiste Daroussin 	if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
18534bf54857SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
18544bf54857SBaptiste Daroussin 			fd, strerror (errno));
18554bf54857SBaptiste Daroussin 		return false;
18564bf54857SBaptiste Daroussin 	}
18574bf54857SBaptiste Daroussin 
18584bf54857SBaptiste Daroussin 	if (parser->cur_file) {
18594bf54857SBaptiste Daroussin 		free (parser->cur_file);
18604bf54857SBaptiste Daroussin 	}
18614bf54857SBaptiste Daroussin 	parser->cur_file = NULL;
18624bf54857SBaptiste Daroussin 	len = st.st_size;
186339ee7a7aSBaptiste Daroussin 	ret = ucl_parser_add_chunk_priority (parser, buf, len, priority);
18644bf54857SBaptiste Daroussin 
18654bf54857SBaptiste Daroussin 	if (len > 0) {
18664bf54857SBaptiste Daroussin 		ucl_munmap (buf, len);
18674bf54857SBaptiste Daroussin 	}
18684bf54857SBaptiste Daroussin 
18694bf54857SBaptiste Daroussin 	return ret;
18704bf54857SBaptiste Daroussin }
18714bf54857SBaptiste Daroussin 
187239ee7a7aSBaptiste Daroussin bool
187339ee7a7aSBaptiste Daroussin ucl_parser_add_fd (struct ucl_parser *parser, int fd)
187439ee7a7aSBaptiste Daroussin {
187539ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
187639ee7a7aSBaptiste Daroussin 		return false;
187739ee7a7aSBaptiste Daroussin 	}
187839ee7a7aSBaptiste Daroussin 
187939ee7a7aSBaptiste Daroussin 	return ucl_parser_add_fd_priority(parser, fd, parser->default_priority);
188039ee7a7aSBaptiste Daroussin }
188139ee7a7aSBaptiste Daroussin 
1882c99fb5f9SBaptiste Daroussin size_t
1883c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz)
1884c99fb5f9SBaptiste Daroussin {
1885c99fb5f9SBaptiste Daroussin 	char *d = dst;
1886c99fb5f9SBaptiste Daroussin 	const char *s = src;
1887c99fb5f9SBaptiste Daroussin 	size_t n = siz;
1888c99fb5f9SBaptiste Daroussin 
1889c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1890c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1891c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1892c99fb5f9SBaptiste Daroussin 			if ((*d++ = *s++) == '\0') {
1893c99fb5f9SBaptiste Daroussin 				break;
1894c99fb5f9SBaptiste Daroussin 			}
1895c99fb5f9SBaptiste Daroussin 		}
1896c99fb5f9SBaptiste Daroussin 	}
1897c99fb5f9SBaptiste Daroussin 
1898c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1899c99fb5f9SBaptiste Daroussin 		*d = '\0';
1900c99fb5f9SBaptiste Daroussin 	}
1901c99fb5f9SBaptiste Daroussin 
1902c99fb5f9SBaptiste Daroussin 	return (s - src - 1);    /* count does not include NUL */
1903c99fb5f9SBaptiste Daroussin }
1904c99fb5f9SBaptiste Daroussin 
1905c99fb5f9SBaptiste Daroussin size_t
1906c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
1907c99fb5f9SBaptiste Daroussin {
1908c99fb5f9SBaptiste Daroussin 	memcpy (dst, src, siz - 1);
1909c99fb5f9SBaptiste Daroussin 	dst[siz - 1] = '\0';
1910c99fb5f9SBaptiste Daroussin 
1911c99fb5f9SBaptiste Daroussin 	return siz - 1;
1912c99fb5f9SBaptiste Daroussin }
1913c99fb5f9SBaptiste Daroussin 
1914c99fb5f9SBaptiste Daroussin size_t
1915c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
1916c99fb5f9SBaptiste Daroussin {
1917c99fb5f9SBaptiste Daroussin 	char *d = dst;
1918c99fb5f9SBaptiste Daroussin 	const char *s = src;
1919c99fb5f9SBaptiste Daroussin 	size_t n = siz;
1920c99fb5f9SBaptiste Daroussin 
1921c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1922c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1923c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1924c99fb5f9SBaptiste Daroussin 			if ((*d++ = tolower (*s++)) == '\0') {
1925c99fb5f9SBaptiste Daroussin 				break;
1926c99fb5f9SBaptiste Daroussin 			}
1927c99fb5f9SBaptiste Daroussin 		}
1928c99fb5f9SBaptiste Daroussin 	}
1929c99fb5f9SBaptiste Daroussin 
1930c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1931c99fb5f9SBaptiste Daroussin 		*d = '\0';
1932c99fb5f9SBaptiste Daroussin 	}
1933c99fb5f9SBaptiste Daroussin 
1934c99fb5f9SBaptiste Daroussin 	return (s - src);    /* count does not include NUL */
1935c99fb5f9SBaptiste Daroussin }
1936c99fb5f9SBaptiste Daroussin 
193739ee7a7aSBaptiste Daroussin /*
193839ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s
193939ee7a7aSBaptiste Daroussin  */
194039ee7a7aSBaptiste Daroussin char *
194139ee7a7aSBaptiste Daroussin ucl_strnstr (const char *s, const char *find, int len)
194239ee7a7aSBaptiste Daroussin {
194339ee7a7aSBaptiste Daroussin 	char c, sc;
194439ee7a7aSBaptiste Daroussin 	int mlen;
194539ee7a7aSBaptiste Daroussin 
194639ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
194739ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
194839ee7a7aSBaptiste Daroussin 		do {
194939ee7a7aSBaptiste Daroussin 			do {
195039ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
195139ee7a7aSBaptiste Daroussin 					return (NULL);
195239ee7a7aSBaptiste Daroussin 			} while (sc != c);
195339ee7a7aSBaptiste Daroussin 		} while (strncmp (s, find, mlen) != 0);
195439ee7a7aSBaptiste Daroussin 		s--;
195539ee7a7aSBaptiste Daroussin 	}
195639ee7a7aSBaptiste Daroussin 	return ((char *)s);
195739ee7a7aSBaptiste Daroussin }
195839ee7a7aSBaptiste Daroussin 
195939ee7a7aSBaptiste Daroussin /*
196039ee7a7aSBaptiste Daroussin  * Find the first occurrence of find in s, ignore case.
196139ee7a7aSBaptiste Daroussin  */
196239ee7a7aSBaptiste Daroussin char *
196339ee7a7aSBaptiste Daroussin ucl_strncasestr (const char *s, const char *find, int len)
196439ee7a7aSBaptiste Daroussin {
196539ee7a7aSBaptiste Daroussin 	char c, sc;
196639ee7a7aSBaptiste Daroussin 	int mlen;
196739ee7a7aSBaptiste Daroussin 
196839ee7a7aSBaptiste Daroussin 	if ((c = *find++) != 0) {
196939ee7a7aSBaptiste Daroussin 		c = tolower (c);
197039ee7a7aSBaptiste Daroussin 		mlen = strlen (find);
197139ee7a7aSBaptiste Daroussin 		do {
197239ee7a7aSBaptiste Daroussin 			do {
197339ee7a7aSBaptiste Daroussin 				if ((sc = *s++) == 0 || len-- == 0)
197439ee7a7aSBaptiste Daroussin 					return (NULL);
197539ee7a7aSBaptiste Daroussin 			} while (tolower (sc) != c);
197639ee7a7aSBaptiste Daroussin 		} while (strncasecmp (s, find, mlen) != 0);
197739ee7a7aSBaptiste Daroussin 		s--;
197839ee7a7aSBaptiste Daroussin 	}
197939ee7a7aSBaptiste Daroussin 	return ((char *)s);
198039ee7a7aSBaptiste Daroussin }
198139ee7a7aSBaptiste Daroussin 
1982c99fb5f9SBaptiste Daroussin ucl_object_t *
1983c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
1984c99fb5f9SBaptiste Daroussin {
1985c99fb5f9SBaptiste Daroussin 	ucl_object_t *obj;
1986c99fb5f9SBaptiste Daroussin 	const char *start, *end, *p, *pos;
1987c99fb5f9SBaptiste Daroussin 	char *dst, *d;
1988c99fb5f9SBaptiste Daroussin 	size_t escaped_len;
1989c99fb5f9SBaptiste Daroussin 
1990c99fb5f9SBaptiste Daroussin 	if (str == NULL) {
1991c99fb5f9SBaptiste Daroussin 		return NULL;
1992c99fb5f9SBaptiste Daroussin 	}
1993c99fb5f9SBaptiste Daroussin 
1994c99fb5f9SBaptiste Daroussin 	obj = ucl_object_new ();
1995c99fb5f9SBaptiste Daroussin 	if (obj) {
1996c99fb5f9SBaptiste Daroussin 		if (len == 0) {
1997c99fb5f9SBaptiste Daroussin 			len = strlen (str);
1998c99fb5f9SBaptiste Daroussin 		}
1999c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_TRIM) {
2000c99fb5f9SBaptiste Daroussin 			/* Skip leading spaces */
2001c99fb5f9SBaptiste Daroussin 			for (start = str; (size_t)(start - str) < len; start ++) {
2002c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2003c99fb5f9SBaptiste Daroussin 					break;
2004c99fb5f9SBaptiste Daroussin 				}
2005c99fb5f9SBaptiste Daroussin 			}
2006c99fb5f9SBaptiste Daroussin 			/* Skip trailing spaces */
2007c99fb5f9SBaptiste Daroussin 			for (end = str + len - 1; end > start; end --) {
2008c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2009c99fb5f9SBaptiste Daroussin 					break;
2010c99fb5f9SBaptiste Daroussin 				}
2011c99fb5f9SBaptiste Daroussin 			}
2012c99fb5f9SBaptiste Daroussin 			end ++;
2013c99fb5f9SBaptiste Daroussin 		}
2014c99fb5f9SBaptiste Daroussin 		else {
2015c99fb5f9SBaptiste Daroussin 			start = str;
2016c99fb5f9SBaptiste Daroussin 			end = str + len;
2017c99fb5f9SBaptiste Daroussin 		}
2018c99fb5f9SBaptiste Daroussin 
2019c99fb5f9SBaptiste Daroussin 		obj->type = UCL_STRING;
2020c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_ESCAPE) {
2021c99fb5f9SBaptiste Daroussin 			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
2022c99fb5f9SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
2023c99fb5f9SBaptiste Daroussin 					escaped_len ++;
2024c99fb5f9SBaptiste Daroussin 				}
2025c99fb5f9SBaptiste Daroussin 			}
2026c99fb5f9SBaptiste Daroussin 			dst = malloc (escaped_len + 1);
2027c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2028c99fb5f9SBaptiste Daroussin 				for (p = start, d = dst; p < end; p ++, d ++) {
2029c99fb5f9SBaptiste Daroussin 					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
2030c99fb5f9SBaptiste Daroussin 						switch (*p) {
2031c99fb5f9SBaptiste Daroussin 						case '\n':
2032c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2033c99fb5f9SBaptiste Daroussin 							*d = 'n';
2034c99fb5f9SBaptiste Daroussin 							break;
2035c99fb5f9SBaptiste Daroussin 						case '\r':
2036c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2037c99fb5f9SBaptiste Daroussin 							*d = 'r';
2038c99fb5f9SBaptiste Daroussin 							break;
2039c99fb5f9SBaptiste Daroussin 						case '\b':
2040c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2041c99fb5f9SBaptiste Daroussin 							*d = 'b';
2042c99fb5f9SBaptiste Daroussin 							break;
2043c99fb5f9SBaptiste Daroussin 						case '\t':
2044c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2045c99fb5f9SBaptiste Daroussin 							*d = 't';
2046c99fb5f9SBaptiste Daroussin 							break;
2047c99fb5f9SBaptiste Daroussin 						case '\f':
2048c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2049c99fb5f9SBaptiste Daroussin 							*d = 'f';
2050c99fb5f9SBaptiste Daroussin 							break;
2051c99fb5f9SBaptiste Daroussin 						case '\\':
2052c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2053c99fb5f9SBaptiste Daroussin 							*d = '\\';
2054c99fb5f9SBaptiste Daroussin 							break;
2055c99fb5f9SBaptiste Daroussin 						case '"':
2056c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
2057c99fb5f9SBaptiste Daroussin 							*d = '"';
2058c99fb5f9SBaptiste Daroussin 							break;
2059c99fb5f9SBaptiste Daroussin 						}
2060c99fb5f9SBaptiste Daroussin 					}
2061c99fb5f9SBaptiste Daroussin 					else {
2062c99fb5f9SBaptiste Daroussin 						*d = *p;
2063c99fb5f9SBaptiste Daroussin 					}
2064c99fb5f9SBaptiste Daroussin 				}
2065c99fb5f9SBaptiste Daroussin 				*d = '\0';
2066c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2067c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2068c99fb5f9SBaptiste Daroussin 				obj->len = escaped_len;
2069c99fb5f9SBaptiste Daroussin 			}
2070c99fb5f9SBaptiste Daroussin 		}
2071c99fb5f9SBaptiste Daroussin 		else {
2072c99fb5f9SBaptiste Daroussin 			dst = malloc (end - start + 1);
2073c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
2074c99fb5f9SBaptiste Daroussin 				ucl_strlcpy_unsafe (dst, start, end - start + 1);
2075c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
2076c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
2077c99fb5f9SBaptiste Daroussin 				obj->len = end - start;
2078c99fb5f9SBaptiste Daroussin 			}
2079c99fb5f9SBaptiste Daroussin 		}
2080c99fb5f9SBaptiste Daroussin 		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
2081c99fb5f9SBaptiste Daroussin 			/* Parse what we have */
2082c99fb5f9SBaptiste Daroussin 			if (flags & UCL_STRING_PARSE_BOOLEAN) {
2083c99fb5f9SBaptiste Daroussin 				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
2084c99fb5f9SBaptiste Daroussin 					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
2085c99fb5f9SBaptiste Daroussin 							flags & UCL_STRING_PARSE_DOUBLE,
208697bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_BYTES,
208797bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_TIME);
2088c99fb5f9SBaptiste Daroussin 				}
2089c99fb5f9SBaptiste Daroussin 			}
2090c99fb5f9SBaptiste Daroussin 			else {
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 	}
2098c99fb5f9SBaptiste Daroussin 
2099c99fb5f9SBaptiste Daroussin 	return obj;
2100c99fb5f9SBaptiste Daroussin }
2101c99fb5f9SBaptiste Daroussin 
2102b04a7a0bSBaptiste Daroussin static bool
2103c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
2104c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
2105c99fb5f9SBaptiste Daroussin {
2106b04a7a0bSBaptiste Daroussin 	ucl_object_t *found, *tmp;
2107b04a7a0bSBaptiste Daroussin 	const ucl_object_t *cur;
2108c99fb5f9SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
2109c99fb5f9SBaptiste Daroussin 	const char *p;
2110b04a7a0bSBaptiste Daroussin 	int ret = true;
2111c99fb5f9SBaptiste Daroussin 
2112c99fb5f9SBaptiste Daroussin 	if (elt == NULL || key == NULL) {
2113b04a7a0bSBaptiste Daroussin 		return false;
2114c99fb5f9SBaptiste Daroussin 	}
2115c99fb5f9SBaptiste Daroussin 
2116c99fb5f9SBaptiste Daroussin 	if (top == NULL) {
2117b04a7a0bSBaptiste Daroussin 		return false;
2118c99fb5f9SBaptiste Daroussin 	}
2119c99fb5f9SBaptiste Daroussin 
2120c99fb5f9SBaptiste Daroussin 	if (top->type != UCL_OBJECT) {
2121c99fb5f9SBaptiste Daroussin 		/* It is possible to convert NULL type to an object */
2122c99fb5f9SBaptiste Daroussin 		if (top->type == UCL_NULL) {
2123c99fb5f9SBaptiste Daroussin 			top->type = UCL_OBJECT;
2124c99fb5f9SBaptiste Daroussin 		}
2125c99fb5f9SBaptiste Daroussin 		else {
2126c99fb5f9SBaptiste Daroussin 			/* Refuse converting of other object types */
2127b04a7a0bSBaptiste Daroussin 			return false;
2128c99fb5f9SBaptiste Daroussin 		}
2129c99fb5f9SBaptiste Daroussin 	}
2130c99fb5f9SBaptiste Daroussin 
2131c99fb5f9SBaptiste Daroussin 	if (top->value.ov == NULL) {
21328e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_create (false);
2133c99fb5f9SBaptiste Daroussin 	}
2134c99fb5f9SBaptiste Daroussin 
2135c99fb5f9SBaptiste Daroussin 	if (keylen == 0) {
2136c99fb5f9SBaptiste Daroussin 		keylen = strlen (key);
2137c99fb5f9SBaptiste Daroussin 	}
2138c99fb5f9SBaptiste Daroussin 
2139c99fb5f9SBaptiste Daroussin 	for (p = key; p < key + keylen; p ++) {
2140c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
2141c99fb5f9SBaptiste Daroussin 			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
2142c99fb5f9SBaptiste Daroussin 			break;
2143c99fb5f9SBaptiste Daroussin 		}
2144c99fb5f9SBaptiste Daroussin 	}
2145c99fb5f9SBaptiste Daroussin 
21464bf54857SBaptiste Daroussin 	/* workaround for some use cases */
21474bf54857SBaptiste Daroussin 	if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
21484bf54857SBaptiste Daroussin 			key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
21494bf54857SBaptiste Daroussin 		/* Remove copied key */
21504bf54857SBaptiste Daroussin 		free (elt->trash_stack[UCL_TRASH_KEY]);
21514bf54857SBaptiste Daroussin 		elt->trash_stack[UCL_TRASH_KEY] = NULL;
21524bf54857SBaptiste Daroussin 		elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
21534bf54857SBaptiste Daroussin 	}
21544bf54857SBaptiste Daroussin 
2155c99fb5f9SBaptiste Daroussin 	elt->key = key;
2156c99fb5f9SBaptiste Daroussin 	elt->keylen = keylen;
2157c99fb5f9SBaptiste Daroussin 
2158c99fb5f9SBaptiste Daroussin 	if (copy_key) {
2159c99fb5f9SBaptiste Daroussin 		ucl_copy_key_trash (elt);
2160c99fb5f9SBaptiste Daroussin 	}
2161c99fb5f9SBaptiste Daroussin 
2162b04a7a0bSBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
2163c99fb5f9SBaptiste Daroussin 
21644bf54857SBaptiste Daroussin 	if (found == NULL) {
21658e3b1ab2SBaptiste Daroussin 		top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
216697bd480fSBaptiste Daroussin 		top->len ++;
2167b04a7a0bSBaptiste Daroussin 		if (replace) {
2168b04a7a0bSBaptiste Daroussin 			ret = false;
2169b04a7a0bSBaptiste Daroussin 		}
2170c99fb5f9SBaptiste Daroussin 	}
2171c99fb5f9SBaptiste Daroussin 	else {
2172c99fb5f9SBaptiste Daroussin 		if (replace) {
21734bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, elt);
2174c99fb5f9SBaptiste Daroussin 			ucl_object_unref (found);
2175c99fb5f9SBaptiste Daroussin 		}
2176c99fb5f9SBaptiste Daroussin 		else if (merge) {
2177c99fb5f9SBaptiste Daroussin 			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
2178c99fb5f9SBaptiste Daroussin 				/* Insert old elt to new one */
2179b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (elt, found, found->key,
2180b04a7a0bSBaptiste Daroussin 						found->keylen, copy_key, false, false);
2181c99fb5f9SBaptiste Daroussin 				ucl_hash_delete (top->value.ov, found);
21828e3b1ab2SBaptiste Daroussin 				top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
2183c99fb5f9SBaptiste Daroussin 			}
2184c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
2185c99fb5f9SBaptiste Daroussin 				/* Insert new to old */
2186b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (found, elt, elt->key,
2187b04a7a0bSBaptiste Daroussin 						elt->keylen, copy_key, false, false);
2188c99fb5f9SBaptiste Daroussin 			}
2189c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
2190c99fb5f9SBaptiste Daroussin 				/* Mix two hashes */
2191*d9f0ce31SBaptiste Daroussin 				while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
2192b04a7a0bSBaptiste Daroussin 					tmp = ucl_object_ref (cur);
2193b04a7a0bSBaptiste Daroussin 					ucl_object_insert_key_common (found, tmp, cur->key,
2194b04a7a0bSBaptiste Daroussin 							cur->keylen, copy_key, false, false);
2195c99fb5f9SBaptiste Daroussin 				}
2196c99fb5f9SBaptiste Daroussin 				ucl_object_unref (elt);
2197c99fb5f9SBaptiste Daroussin 			}
2198c99fb5f9SBaptiste Daroussin 			else {
2199c99fb5f9SBaptiste Daroussin 				/* Just make a list of scalars */
2200c99fb5f9SBaptiste Daroussin 				DL_APPEND (found, elt);
2201c99fb5f9SBaptiste Daroussin 			}
2202c99fb5f9SBaptiste Daroussin 		}
2203c99fb5f9SBaptiste Daroussin 		else {
2204c99fb5f9SBaptiste Daroussin 			DL_APPEND (found, elt);
2205c99fb5f9SBaptiste Daroussin 		}
2206c99fb5f9SBaptiste Daroussin 	}
2207c99fb5f9SBaptiste Daroussin 
2208b04a7a0bSBaptiste Daroussin 	return ret;
2209c99fb5f9SBaptiste Daroussin }
2210c99fb5f9SBaptiste Daroussin 
221136c53d67SBaptiste Daroussin bool
221236c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
221336c53d67SBaptiste Daroussin {
221436c53d67SBaptiste Daroussin 	ucl_object_t *found;
221536c53d67SBaptiste Daroussin 
221697bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
221797bd480fSBaptiste Daroussin 		return false;
221897bd480fSBaptiste Daroussin 	}
221997bd480fSBaptiste Daroussin 
2220*d9f0ce31SBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_object_lookup_len (top, key, keylen));
222136c53d67SBaptiste Daroussin 
222297bd480fSBaptiste Daroussin 	if (found == NULL) {
222336c53d67SBaptiste Daroussin 		return false;
222497bd480fSBaptiste Daroussin 	}
222536c53d67SBaptiste Daroussin 
222636c53d67SBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
222736c53d67SBaptiste Daroussin 	ucl_object_unref (found);
222836c53d67SBaptiste Daroussin 	top->len --;
222936c53d67SBaptiste Daroussin 
223036c53d67SBaptiste Daroussin 	return true;
223136c53d67SBaptiste Daroussin }
223236c53d67SBaptiste Daroussin 
223336c53d67SBaptiste Daroussin bool
223436c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key)
223536c53d67SBaptiste Daroussin {
2236b04a7a0bSBaptiste Daroussin 	return ucl_object_delete_keyl (top, key, strlen (key));
223736c53d67SBaptiste Daroussin }
223836c53d67SBaptiste Daroussin 
2239c99fb5f9SBaptiste Daroussin ucl_object_t*
224097bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
224197bd480fSBaptiste Daroussin {
2242b04a7a0bSBaptiste Daroussin 	const ucl_object_t *found;
224397bd480fSBaptiste Daroussin 
224497bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
224597bd480fSBaptiste Daroussin 		return false;
224697bd480fSBaptiste Daroussin 	}
2247*d9f0ce31SBaptiste Daroussin 	found = ucl_object_lookup_len (top, key, keylen);
224897bd480fSBaptiste Daroussin 
224997bd480fSBaptiste Daroussin 	if (found == NULL) {
225097bd480fSBaptiste Daroussin 		return NULL;
225197bd480fSBaptiste Daroussin 	}
225297bd480fSBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
225397bd480fSBaptiste Daroussin 	top->len --;
225497bd480fSBaptiste Daroussin 
2255b04a7a0bSBaptiste Daroussin 	return __DECONST (ucl_object_t *, found);
225697bd480fSBaptiste Daroussin }
225797bd480fSBaptiste Daroussin 
225897bd480fSBaptiste Daroussin ucl_object_t*
225997bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key)
226097bd480fSBaptiste Daroussin {
2261b04a7a0bSBaptiste Daroussin 	return ucl_object_pop_keyl (top, key, strlen (key));
226297bd480fSBaptiste Daroussin }
226397bd480fSBaptiste Daroussin 
2264b04a7a0bSBaptiste Daroussin bool
2265c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
2266c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
2267c99fb5f9SBaptiste Daroussin {
2268c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
2269c99fb5f9SBaptiste Daroussin }
2270c99fb5f9SBaptiste Daroussin 
2271b04a7a0bSBaptiste Daroussin bool
2272c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (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, true, false);
2276c99fb5f9SBaptiste Daroussin }
2277c99fb5f9SBaptiste Daroussin 
2278b04a7a0bSBaptiste Daroussin bool
2279c99fb5f9SBaptiste Daroussin ucl_object_replace_key (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, false, true);
2283c99fb5f9SBaptiste Daroussin }
2284c99fb5f9SBaptiste Daroussin 
22854bf54857SBaptiste Daroussin bool
22864bf54857SBaptiste Daroussin ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
22874bf54857SBaptiste Daroussin {
22884bf54857SBaptiste Daroussin 	ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
22894bf54857SBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
22904bf54857SBaptiste Daroussin 
22914bf54857SBaptiste Daroussin 	if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
22924bf54857SBaptiste Daroussin 		return false;
22934bf54857SBaptiste Daroussin 	}
22944bf54857SBaptiste Daroussin 
22954bf54857SBaptiste Daroussin 	/* Mix two hashes */
22964bf54857SBaptiste Daroussin 	while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
22974bf54857SBaptiste Daroussin 		if (copy) {
22984bf54857SBaptiste Daroussin 			cp = ucl_object_copy (cur);
22994bf54857SBaptiste Daroussin 		}
23004bf54857SBaptiste Daroussin 		else {
23014bf54857SBaptiste Daroussin 			cp = ucl_object_ref (cur);
23024bf54857SBaptiste Daroussin 		}
23034bf54857SBaptiste Daroussin 		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
23044bf54857SBaptiste Daroussin 		if (found == NULL) {
23054bf54857SBaptiste Daroussin 			/* The key does not exist */
23068e3b1ab2SBaptiste Daroussin 			top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
23074bf54857SBaptiste Daroussin 			top->len ++;
23084bf54857SBaptiste Daroussin 		}
23094bf54857SBaptiste Daroussin 		else {
23104bf54857SBaptiste Daroussin 			/* The key already exists, replace it */
23114bf54857SBaptiste Daroussin 			ucl_hash_replace (top->value.ov, found, cp);
23124bf54857SBaptiste Daroussin 			ucl_object_unref (found);
23134bf54857SBaptiste Daroussin 		}
23144bf54857SBaptiste Daroussin 	}
23154bf54857SBaptiste Daroussin 
23164bf54857SBaptiste Daroussin 	return true;
23174bf54857SBaptiste Daroussin }
23184bf54857SBaptiste Daroussin 
2319b04a7a0bSBaptiste Daroussin const ucl_object_t *
2320*d9f0ce31SBaptiste Daroussin ucl_object_lookup_len (const ucl_object_t *obj, const char *key, size_t klen)
2321c99fb5f9SBaptiste Daroussin {
2322b04a7a0bSBaptiste Daroussin 	const ucl_object_t *ret;
2323b04a7a0bSBaptiste Daroussin 	ucl_object_t srch;
2324c99fb5f9SBaptiste Daroussin 
2325c99fb5f9SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
2326c99fb5f9SBaptiste Daroussin 		return NULL;
2327c99fb5f9SBaptiste Daroussin 	}
2328c99fb5f9SBaptiste Daroussin 
2329c99fb5f9SBaptiste Daroussin 	srch.key = key;
2330c99fb5f9SBaptiste Daroussin 	srch.keylen = klen;
2331c99fb5f9SBaptiste Daroussin 	ret = ucl_hash_search_obj (obj->value.ov, &srch);
2332c99fb5f9SBaptiste Daroussin 
2333c99fb5f9SBaptiste Daroussin 	return ret;
2334c99fb5f9SBaptiste Daroussin }
2335c99fb5f9SBaptiste Daroussin 
2336b04a7a0bSBaptiste Daroussin const ucl_object_t *
2337*d9f0ce31SBaptiste Daroussin ucl_object_lookup (const ucl_object_t *obj, const char *key)
2338c99fb5f9SBaptiste Daroussin {
233939ee7a7aSBaptiste Daroussin 	if (key == NULL) {
2340c99fb5f9SBaptiste Daroussin 		return NULL;
234139ee7a7aSBaptiste Daroussin 	}
2342c99fb5f9SBaptiste Daroussin 
2343*d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_len (obj, key, strlen (key));
2344c99fb5f9SBaptiste Daroussin }
2345c99fb5f9SBaptiste Daroussin 
2346b04a7a0bSBaptiste Daroussin const ucl_object_t*
2347*d9f0ce31SBaptiste Daroussin ucl_object_lookup_any (const ucl_object_t *obj,
234839ee7a7aSBaptiste Daroussin 		const char *key, ...)
234939ee7a7aSBaptiste Daroussin {
235039ee7a7aSBaptiste Daroussin 	va_list ap;
235139ee7a7aSBaptiste Daroussin 	const ucl_object_t *ret = NULL;
235239ee7a7aSBaptiste Daroussin 	const char *nk = NULL;
235339ee7a7aSBaptiste Daroussin 
235439ee7a7aSBaptiste Daroussin 	if (obj == NULL || key == NULL) {
235539ee7a7aSBaptiste Daroussin 		return NULL;
235639ee7a7aSBaptiste Daroussin 	}
235739ee7a7aSBaptiste Daroussin 
2358*d9f0ce31SBaptiste Daroussin 	ret = ucl_object_lookup_len (obj, key, strlen (key));
235939ee7a7aSBaptiste Daroussin 
236039ee7a7aSBaptiste Daroussin 	if (ret == NULL) {
236139ee7a7aSBaptiste Daroussin 		va_start (ap, key);
236239ee7a7aSBaptiste Daroussin 
236339ee7a7aSBaptiste Daroussin 		while (ret == NULL) {
236439ee7a7aSBaptiste Daroussin 			nk = va_arg (ap, const char *);
236539ee7a7aSBaptiste Daroussin 
236639ee7a7aSBaptiste Daroussin 			if (nk == NULL) {
236739ee7a7aSBaptiste Daroussin 				break;
236839ee7a7aSBaptiste Daroussin 			}
236939ee7a7aSBaptiste Daroussin 			else {
2370*d9f0ce31SBaptiste Daroussin 				ret = ucl_object_lookup_len (obj, nk, strlen (nk));
237139ee7a7aSBaptiste Daroussin 			}
237239ee7a7aSBaptiste Daroussin 		}
237339ee7a7aSBaptiste Daroussin 
237439ee7a7aSBaptiste Daroussin 		va_end (ap);
237539ee7a7aSBaptiste Daroussin 	}
237639ee7a7aSBaptiste Daroussin 
237739ee7a7aSBaptiste Daroussin 	return ret;
237839ee7a7aSBaptiste Daroussin }
237939ee7a7aSBaptiste Daroussin 
238039ee7a7aSBaptiste Daroussin const ucl_object_t*
2381*d9f0ce31SBaptiste Daroussin ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
2382c99fb5f9SBaptiste Daroussin {
23838e3b1ab2SBaptiste Daroussin 	const ucl_object_t *elt = NULL;
2384c99fb5f9SBaptiste Daroussin 
238597bd480fSBaptiste Daroussin 	if (obj == NULL || iter == NULL) {
238697bd480fSBaptiste Daroussin 		return NULL;
238797bd480fSBaptiste Daroussin 	}
238897bd480fSBaptiste Daroussin 
2389c99fb5f9SBaptiste Daroussin 	if (expand_values) {
2390c99fb5f9SBaptiste Daroussin 		switch (obj->type) {
2391c99fb5f9SBaptiste Daroussin 		case UCL_OBJECT:
2392b04a7a0bSBaptiste Daroussin 			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
2393c99fb5f9SBaptiste Daroussin 			break;
23948e3b1ab2SBaptiste Daroussin 		case UCL_ARRAY: {
23958e3b1ab2SBaptiste Daroussin 			unsigned int idx;
23968e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec, obj);
23978e3b1ab2SBaptiste Daroussin 			idx = (unsigned int)(uintptr_t)(*iter);
23988e3b1ab2SBaptiste Daroussin 
23998e3b1ab2SBaptiste Daroussin 			if (vec != NULL) {
24008e3b1ab2SBaptiste Daroussin 				while (idx < kv_size (*vec)) {
24018e3b1ab2SBaptiste Daroussin 					if ((elt = kv_A (*vec, idx)) != NULL) {
24028e3b1ab2SBaptiste Daroussin 						idx ++;
24038e3b1ab2SBaptiste Daroussin 						break;
2404c99fb5f9SBaptiste Daroussin 					}
24058e3b1ab2SBaptiste Daroussin 					idx ++;
2406c99fb5f9SBaptiste Daroussin 				}
24078e3b1ab2SBaptiste Daroussin 				*iter = (void *)(uintptr_t)idx;
2408c99fb5f9SBaptiste Daroussin 			}
24098e3b1ab2SBaptiste Daroussin 
2410c99fb5f9SBaptiste Daroussin 			return elt;
24118e3b1ab2SBaptiste Daroussin 			break;
24128e3b1ab2SBaptiste Daroussin 		}
2413c99fb5f9SBaptiste Daroussin 		default:
2414c99fb5f9SBaptiste Daroussin 			/* Go to linear iteration */
2415c99fb5f9SBaptiste Daroussin 			break;
2416c99fb5f9SBaptiste Daroussin 		}
2417c99fb5f9SBaptiste Daroussin 	}
2418c99fb5f9SBaptiste Daroussin 	/* Treat everything as a linear list */
2419c99fb5f9SBaptiste Daroussin 	elt = *iter;
2420c99fb5f9SBaptiste Daroussin 	if (elt == NULL) {
2421c99fb5f9SBaptiste Daroussin 		elt = obj;
2422c99fb5f9SBaptiste Daroussin 	}
2423c99fb5f9SBaptiste Daroussin 	else if (elt == obj) {
2424c99fb5f9SBaptiste Daroussin 		return NULL;
2425c99fb5f9SBaptiste Daroussin 	}
2426b04a7a0bSBaptiste Daroussin 	*iter = __DECONST (void *, elt->next ? elt->next : obj);
2427c99fb5f9SBaptiste Daroussin 	return elt;
2428c99fb5f9SBaptiste Daroussin 
2429c99fb5f9SBaptiste Daroussin 	/* Not reached */
2430c99fb5f9SBaptiste Daroussin 	return NULL;
2431c99fb5f9SBaptiste Daroussin }
243297bd480fSBaptiste Daroussin 
24338e3b1ab2SBaptiste Daroussin const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
24348e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter {
24358e3b1ab2SBaptiste Daroussin 	char magic[4]; /* safety check */
24368e3b1ab2SBaptiste Daroussin 	const ucl_object_t *impl_it; /* implicit object iteration */
24378e3b1ab2SBaptiste Daroussin 	ucl_object_iter_t expl_it; /* explicit iteration */
24388e3b1ab2SBaptiste Daroussin };
24398e3b1ab2SBaptiste Daroussin 
24408e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr)
24418e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER_CHECK(it) do { \
24428e3b1ab2SBaptiste Daroussin 	assert (it != NULL); \
24438e3b1ab2SBaptiste Daroussin 	assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \
24448e3b1ab2SBaptiste Daroussin  } while (0)
24458e3b1ab2SBaptiste Daroussin 
24468e3b1ab2SBaptiste Daroussin ucl_object_iter_t
24478e3b1ab2SBaptiste Daroussin ucl_object_iterate_new (const ucl_object_t *obj)
24488e3b1ab2SBaptiste Daroussin {
24498e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *it;
24508e3b1ab2SBaptiste Daroussin 
24518e3b1ab2SBaptiste Daroussin 	it = UCL_ALLOC (sizeof (*it));
24528e3b1ab2SBaptiste Daroussin 	if (it != NULL) {
24538e3b1ab2SBaptiste Daroussin 		memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
24548e3b1ab2SBaptiste Daroussin 		it->expl_it = NULL;
24558e3b1ab2SBaptiste Daroussin 		it->impl_it = obj;
24568e3b1ab2SBaptiste Daroussin 	}
24578e3b1ab2SBaptiste Daroussin 
24588e3b1ab2SBaptiste Daroussin 	return (ucl_object_iter_t)it;
24598e3b1ab2SBaptiste Daroussin }
24608e3b1ab2SBaptiste Daroussin 
24618e3b1ab2SBaptiste Daroussin 
24628e3b1ab2SBaptiste Daroussin ucl_object_iter_t
24638e3b1ab2SBaptiste Daroussin ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
24648e3b1ab2SBaptiste Daroussin {
24658e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
24668e3b1ab2SBaptiste Daroussin 
24678e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
24688e3b1ab2SBaptiste Daroussin 
24698e3b1ab2SBaptiste Daroussin 	rit->impl_it = obj;
24708e3b1ab2SBaptiste Daroussin 	rit->expl_it = NULL;
24718e3b1ab2SBaptiste Daroussin 
24728e3b1ab2SBaptiste Daroussin 	return it;
24738e3b1ab2SBaptiste Daroussin }
24748e3b1ab2SBaptiste Daroussin 
24758e3b1ab2SBaptiste Daroussin const ucl_object_t*
24768e3b1ab2SBaptiste Daroussin ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
24778e3b1ab2SBaptiste Daroussin {
24788e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
24798e3b1ab2SBaptiste Daroussin 	const ucl_object_t *ret = NULL;
24808e3b1ab2SBaptiste Daroussin 
24818e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
24828e3b1ab2SBaptiste Daroussin 
24838e3b1ab2SBaptiste Daroussin 	if (rit->impl_it == NULL) {
24848e3b1ab2SBaptiste Daroussin 		return NULL;
24858e3b1ab2SBaptiste Daroussin 	}
24868e3b1ab2SBaptiste Daroussin 
24878e3b1ab2SBaptiste Daroussin 	if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
2488*d9f0ce31SBaptiste Daroussin 		ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
24898e3b1ab2SBaptiste Daroussin 
24908e3b1ab2SBaptiste Daroussin 		if (ret == NULL) {
24918e3b1ab2SBaptiste Daroussin 			/* Need to switch to another implicit object in chain */
24928e3b1ab2SBaptiste Daroussin 			rit->impl_it = rit->impl_it->next;
24938e3b1ab2SBaptiste Daroussin 			rit->expl_it = NULL;
24948e3b1ab2SBaptiste Daroussin 			return ucl_object_iterate_safe (it, expand_values);
24958e3b1ab2SBaptiste Daroussin 		}
24968e3b1ab2SBaptiste Daroussin 	}
24978e3b1ab2SBaptiste Daroussin 	else {
24988e3b1ab2SBaptiste Daroussin 		/* Just iterate over the implicit array */
24998e3b1ab2SBaptiste Daroussin 		ret = rit->impl_it;
25008e3b1ab2SBaptiste Daroussin 		rit->impl_it = rit->impl_it->next;
25018e3b1ab2SBaptiste Daroussin 		if (expand_values) {
25028e3b1ab2SBaptiste Daroussin 			/* We flatten objects if need to expand values */
25038e3b1ab2SBaptiste Daroussin 			if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
25048e3b1ab2SBaptiste Daroussin 				return ucl_object_iterate_safe (it, expand_values);
25058e3b1ab2SBaptiste Daroussin 			}
25068e3b1ab2SBaptiste Daroussin 		}
25078e3b1ab2SBaptiste Daroussin 	}
25088e3b1ab2SBaptiste Daroussin 
25098e3b1ab2SBaptiste Daroussin 	return ret;
25108e3b1ab2SBaptiste Daroussin }
25118e3b1ab2SBaptiste Daroussin 
25128e3b1ab2SBaptiste Daroussin void
25138e3b1ab2SBaptiste Daroussin ucl_object_iterate_free (ucl_object_iter_t it)
25148e3b1ab2SBaptiste Daroussin {
25158e3b1ab2SBaptiste Daroussin 	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
25168e3b1ab2SBaptiste Daroussin 
25178e3b1ab2SBaptiste Daroussin 	UCL_SAFE_ITER_CHECK (rit);
25188e3b1ab2SBaptiste Daroussin 
25198e3b1ab2SBaptiste Daroussin 	UCL_FREE (sizeof (*rit), it);
25208e3b1ab2SBaptiste Daroussin }
25218e3b1ab2SBaptiste Daroussin 
25222e8ed2b8SBaptiste Daroussin const ucl_object_t *
2523*d9f0ce31SBaptiste Daroussin ucl_object_lookup_path (const ucl_object_t *top, const char *path_in) {
2524*d9f0ce31SBaptiste Daroussin 	return ucl_object_lookup_path_char (top, path_in, '.');
252539ee7a7aSBaptiste Daroussin }
252639ee7a7aSBaptiste Daroussin 
252739ee7a7aSBaptiste Daroussin 
252839ee7a7aSBaptiste Daroussin const ucl_object_t *
2529*d9f0ce31SBaptiste Daroussin ucl_object_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) {
25302e8ed2b8SBaptiste Daroussin 	const ucl_object_t *o = NULL, *found;
25312e8ed2b8SBaptiste Daroussin 	const char *p, *c;
25322e8ed2b8SBaptiste Daroussin 	char *err_str;
25332e8ed2b8SBaptiste Daroussin 	unsigned index;
25342e8ed2b8SBaptiste Daroussin 
25352e8ed2b8SBaptiste Daroussin 	if (path_in == NULL || top == NULL) {
25362e8ed2b8SBaptiste Daroussin 		return NULL;
25372e8ed2b8SBaptiste Daroussin 	}
25382e8ed2b8SBaptiste Daroussin 
25392e8ed2b8SBaptiste Daroussin 	found = NULL;
25402e8ed2b8SBaptiste Daroussin 	p = path_in;
25412e8ed2b8SBaptiste Daroussin 
25422e8ed2b8SBaptiste Daroussin 	/* Skip leading dots */
254339ee7a7aSBaptiste Daroussin 	while (*p == sep) {
25442e8ed2b8SBaptiste Daroussin 		p ++;
25452e8ed2b8SBaptiste Daroussin 	}
25462e8ed2b8SBaptiste Daroussin 
25472e8ed2b8SBaptiste Daroussin 	c = p;
25482e8ed2b8SBaptiste Daroussin 	while (*p != '\0') {
25492e8ed2b8SBaptiste Daroussin 		p ++;
255039ee7a7aSBaptiste Daroussin 		if (*p == sep || *p == '\0') {
25512e8ed2b8SBaptiste Daroussin 			if (p > c) {
25522e8ed2b8SBaptiste Daroussin 				switch (top->type) {
25532e8ed2b8SBaptiste Daroussin 				case UCL_ARRAY:
25542e8ed2b8SBaptiste Daroussin 					/* Key should be an int */
25552e8ed2b8SBaptiste Daroussin 					index = strtoul (c, &err_str, 10);
255639ee7a7aSBaptiste Daroussin 					if (err_str != NULL && (*err_str != sep && *err_str != '\0')) {
25572e8ed2b8SBaptiste Daroussin 						return NULL;
25582e8ed2b8SBaptiste Daroussin 					}
25592e8ed2b8SBaptiste Daroussin 					o = ucl_array_find_index (top, index);
25602e8ed2b8SBaptiste Daroussin 					break;
25612e8ed2b8SBaptiste Daroussin 				default:
2562*d9f0ce31SBaptiste Daroussin 					o = ucl_object_lookup_len (top, c, p - c);
25632e8ed2b8SBaptiste Daroussin 					break;
25642e8ed2b8SBaptiste Daroussin 				}
25652e8ed2b8SBaptiste Daroussin 				if (o == NULL) {
25662e8ed2b8SBaptiste Daroussin 					return NULL;
25672e8ed2b8SBaptiste Daroussin 				}
25682e8ed2b8SBaptiste Daroussin 				top = o;
25692e8ed2b8SBaptiste Daroussin 			}
25702e8ed2b8SBaptiste Daroussin 			if (*p != '\0') {
25712e8ed2b8SBaptiste Daroussin 				c = p + 1;
25722e8ed2b8SBaptiste Daroussin 			}
25732e8ed2b8SBaptiste Daroussin 		}
25742e8ed2b8SBaptiste Daroussin 	}
25752e8ed2b8SBaptiste Daroussin 	found = o;
25762e8ed2b8SBaptiste Daroussin 
25772e8ed2b8SBaptiste Daroussin 	return found;
25782e8ed2b8SBaptiste Daroussin }
25792e8ed2b8SBaptiste Daroussin 
258097bd480fSBaptiste Daroussin 
258197bd480fSBaptiste Daroussin ucl_object_t *
258297bd480fSBaptiste Daroussin ucl_object_new (void)
258397bd480fSBaptiste Daroussin {
25844bf54857SBaptiste Daroussin 	return ucl_object_typed_new (UCL_NULL);
258597bd480fSBaptiste Daroussin }
258697bd480fSBaptiste Daroussin 
258797bd480fSBaptiste Daroussin ucl_object_t *
25882e8ed2b8SBaptiste Daroussin ucl_object_typed_new (ucl_type_t type)
258997bd480fSBaptiste Daroussin {
25904bf54857SBaptiste Daroussin 	return ucl_object_new_full (type, 0);
25914bf54857SBaptiste Daroussin }
25924bf54857SBaptiste Daroussin 
25934bf54857SBaptiste Daroussin ucl_object_t *
25944bf54857SBaptiste Daroussin ucl_object_new_full (ucl_type_t type, unsigned priority)
25954bf54857SBaptiste Daroussin {
259697bd480fSBaptiste Daroussin 	ucl_object_t *new;
25974bf54857SBaptiste Daroussin 
25984bf54857SBaptiste Daroussin 	if (type != UCL_USERDATA) {
25994bf54857SBaptiste Daroussin 		new = UCL_ALLOC (sizeof (ucl_object_t));
260097bd480fSBaptiste Daroussin 		if (new != NULL) {
260197bd480fSBaptiste Daroussin 			memset (new, 0, sizeof (ucl_object_t));
260297bd480fSBaptiste Daroussin 			new->ref = 1;
260397bd480fSBaptiste Daroussin 			new->type = (type <= UCL_NULL ? type : UCL_NULL);
26044bf54857SBaptiste Daroussin 			new->next = NULL;
26054bf54857SBaptiste Daroussin 			new->prev = new;
26064bf54857SBaptiste Daroussin 			ucl_object_set_priority (new, priority);
26078e3b1ab2SBaptiste Daroussin 
26088e3b1ab2SBaptiste Daroussin 			if (type == UCL_ARRAY) {
26098e3b1ab2SBaptiste Daroussin 				new->value.av = UCL_ALLOC (sizeof (ucl_array_t));
26108e3b1ab2SBaptiste Daroussin 				if (new->value.av) {
26118e3b1ab2SBaptiste Daroussin 					memset (new->value.av, 0, sizeof (ucl_array_t));
26128e3b1ab2SBaptiste Daroussin 					UCL_ARRAY_GET (vec, new);
26138e3b1ab2SBaptiste Daroussin 
26148e3b1ab2SBaptiste Daroussin 					/* Preallocate some space for arrays */
26158e3b1ab2SBaptiste Daroussin 					kv_resize (ucl_object_t *, *vec, 8);
26168e3b1ab2SBaptiste Daroussin 				}
26178e3b1ab2SBaptiste Daroussin 			}
261897bd480fSBaptiste Daroussin 		}
26194bf54857SBaptiste Daroussin 	}
26204bf54857SBaptiste Daroussin 	else {
2621*d9f0ce31SBaptiste Daroussin 		new = ucl_object_new_userdata (NULL, NULL, NULL);
26224bf54857SBaptiste Daroussin 		ucl_object_set_priority (new, priority);
26234bf54857SBaptiste Daroussin 	}
26244bf54857SBaptiste Daroussin 
262597bd480fSBaptiste Daroussin 	return new;
262697bd480fSBaptiste Daroussin }
262797bd480fSBaptiste Daroussin 
26284bf54857SBaptiste Daroussin ucl_object_t*
2629*d9f0ce31SBaptiste Daroussin ucl_object_new_userdata (ucl_userdata_dtor dtor,
2630*d9f0ce31SBaptiste Daroussin 		ucl_userdata_emitter emitter,
2631*d9f0ce31SBaptiste Daroussin 		void *ptr)
26324bf54857SBaptiste Daroussin {
26334bf54857SBaptiste Daroussin 	struct ucl_object_userdata *new;
26344bf54857SBaptiste Daroussin 	size_t nsize = sizeof (*new);
26354bf54857SBaptiste Daroussin 
26364bf54857SBaptiste Daroussin 	new = UCL_ALLOC (nsize);
26374bf54857SBaptiste Daroussin 	if (new != NULL) {
26384bf54857SBaptiste Daroussin 		memset (new, 0, nsize);
26394bf54857SBaptiste Daroussin 		new->obj.ref = 1;
26404bf54857SBaptiste Daroussin 		new->obj.type = UCL_USERDATA;
26414bf54857SBaptiste Daroussin 		new->obj.next = NULL;
26424bf54857SBaptiste Daroussin 		new->obj.prev = (ucl_object_t *)new;
26434bf54857SBaptiste Daroussin 		new->dtor = dtor;
26444bf54857SBaptiste Daroussin 		new->emitter = emitter;
2645*d9f0ce31SBaptiste Daroussin 		new->obj.value.ud = ptr;
26464bf54857SBaptiste Daroussin 	}
26474bf54857SBaptiste Daroussin 
26484bf54857SBaptiste Daroussin 	return (ucl_object_t *)new;
26494bf54857SBaptiste Daroussin }
26504bf54857SBaptiste Daroussin 
26512e8ed2b8SBaptiste Daroussin ucl_type_t
26522e8ed2b8SBaptiste Daroussin ucl_object_type (const ucl_object_t *obj)
26532e8ed2b8SBaptiste Daroussin {
265439ee7a7aSBaptiste Daroussin 	if (obj == NULL) {
265539ee7a7aSBaptiste Daroussin 		return UCL_NULL;
265639ee7a7aSBaptiste Daroussin 	}
265739ee7a7aSBaptiste Daroussin 
26582e8ed2b8SBaptiste Daroussin 	return obj->type;
26592e8ed2b8SBaptiste Daroussin }
26602e8ed2b8SBaptiste Daroussin 
266197bd480fSBaptiste Daroussin ucl_object_t*
266297bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str)
266397bd480fSBaptiste Daroussin {
266497bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
266597bd480fSBaptiste Daroussin }
266697bd480fSBaptiste Daroussin 
266797bd480fSBaptiste Daroussin ucl_object_t *
266897bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len)
266997bd480fSBaptiste Daroussin {
267097bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
267197bd480fSBaptiste Daroussin }
267297bd480fSBaptiste Daroussin 
267397bd480fSBaptiste Daroussin ucl_object_t *
267497bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv)
267597bd480fSBaptiste Daroussin {
267697bd480fSBaptiste Daroussin 	ucl_object_t *obj;
267797bd480fSBaptiste Daroussin 
267897bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
267997bd480fSBaptiste Daroussin 	if (obj != NULL) {
268097bd480fSBaptiste Daroussin 		obj->type = UCL_INT;
268197bd480fSBaptiste Daroussin 		obj->value.iv = iv;
268297bd480fSBaptiste Daroussin 	}
268397bd480fSBaptiste Daroussin 
268497bd480fSBaptiste Daroussin 	return obj;
268597bd480fSBaptiste Daroussin }
268697bd480fSBaptiste Daroussin 
268797bd480fSBaptiste Daroussin ucl_object_t *
268897bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv)
268997bd480fSBaptiste Daroussin {
269097bd480fSBaptiste Daroussin 	ucl_object_t *obj;
269197bd480fSBaptiste Daroussin 
269297bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
269397bd480fSBaptiste Daroussin 	if (obj != NULL) {
269497bd480fSBaptiste Daroussin 		obj->type = UCL_FLOAT;
269597bd480fSBaptiste Daroussin 		obj->value.dv = dv;
269697bd480fSBaptiste Daroussin 	}
269797bd480fSBaptiste Daroussin 
269897bd480fSBaptiste Daroussin 	return obj;
269997bd480fSBaptiste Daroussin }
270097bd480fSBaptiste Daroussin 
270197bd480fSBaptiste Daroussin ucl_object_t*
270297bd480fSBaptiste Daroussin ucl_object_frombool (bool bv)
270397bd480fSBaptiste Daroussin {
270497bd480fSBaptiste Daroussin 	ucl_object_t *obj;
270597bd480fSBaptiste Daroussin 
270697bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
270797bd480fSBaptiste Daroussin 	if (obj != NULL) {
270897bd480fSBaptiste Daroussin 		obj->type = UCL_BOOLEAN;
270997bd480fSBaptiste Daroussin 		obj->value.iv = bv;
271097bd480fSBaptiste Daroussin 	}
271197bd480fSBaptiste Daroussin 
271297bd480fSBaptiste Daroussin 	return obj;
271397bd480fSBaptiste Daroussin }
271497bd480fSBaptiste Daroussin 
2715b04a7a0bSBaptiste Daroussin bool
271697bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
271797bd480fSBaptiste Daroussin {
27188e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
271997bd480fSBaptiste Daroussin 
2720b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
2721b04a7a0bSBaptiste Daroussin 		return false;
272297bd480fSBaptiste Daroussin 	}
272397bd480fSBaptiste Daroussin 
27248e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
27258e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
272639ee7a7aSBaptiste Daroussin 
272739ee7a7aSBaptiste Daroussin 		if (vec == NULL) {
272839ee7a7aSBaptiste Daroussin 			return false;
272939ee7a7aSBaptiste Daroussin 		}
273039ee7a7aSBaptiste Daroussin 
27318e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
27328e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
273397bd480fSBaptiste Daroussin 	}
27348e3b1ab2SBaptiste Daroussin 
27358e3b1ab2SBaptiste Daroussin 	kv_push (ucl_object_t *, *vec, elt);
27368e3b1ab2SBaptiste Daroussin 
273797bd480fSBaptiste Daroussin 	top->len ++;
2738b04a7a0bSBaptiste Daroussin 
2739b04a7a0bSBaptiste Daroussin 	return true;
274097bd480fSBaptiste Daroussin }
274197bd480fSBaptiste Daroussin 
2742b04a7a0bSBaptiste Daroussin bool
274397bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
274497bd480fSBaptiste Daroussin {
27458e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
274697bd480fSBaptiste Daroussin 
2747b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
2748b04a7a0bSBaptiste Daroussin 		return false;
274997bd480fSBaptiste Daroussin 	}
275097bd480fSBaptiste Daroussin 
27518e3b1ab2SBaptiste Daroussin 	if (vec == NULL) {
27528e3b1ab2SBaptiste Daroussin 		vec = UCL_ALLOC (sizeof (*vec));
27538e3b1ab2SBaptiste Daroussin 		kv_init (*vec);
27548e3b1ab2SBaptiste Daroussin 		top->value.av = (void *)vec;
27558e3b1ab2SBaptiste Daroussin 		kv_push (ucl_object_t *, *vec, elt);
275697bd480fSBaptiste Daroussin 	}
275797bd480fSBaptiste Daroussin 	else {
27588e3b1ab2SBaptiste Daroussin 		/* Slow O(n) algorithm */
27598e3b1ab2SBaptiste Daroussin 		kv_prepend (ucl_object_t *, *vec, elt);
276097bd480fSBaptiste Daroussin 	}
27618e3b1ab2SBaptiste Daroussin 
276297bd480fSBaptiste Daroussin 	top->len ++;
276397bd480fSBaptiste Daroussin 
2764b04a7a0bSBaptiste Daroussin 	return true;
276597bd480fSBaptiste Daroussin }
276697bd480fSBaptiste Daroussin 
27674bf54857SBaptiste Daroussin bool
27684bf54857SBaptiste Daroussin ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
27694bf54857SBaptiste Daroussin {
27708e3b1ab2SBaptiste Daroussin 	unsigned i;
277139ee7a7aSBaptiste Daroussin 	ucl_object_t *cp = NULL;
27728e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj;
27734bf54857SBaptiste Daroussin 
27744bf54857SBaptiste Daroussin 	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
27754bf54857SBaptiste Daroussin 		return false;
27764bf54857SBaptiste Daroussin 	}
27774bf54857SBaptiste Daroussin 
277839ee7a7aSBaptiste Daroussin 	if (copy) {
277939ee7a7aSBaptiste Daroussin 		cp = ucl_object_copy (elt);
278039ee7a7aSBaptiste Daroussin 	}
278139ee7a7aSBaptiste Daroussin 	else {
278239ee7a7aSBaptiste Daroussin 		cp = ucl_object_ref (elt);
278339ee7a7aSBaptiste Daroussin 	}
278439ee7a7aSBaptiste Daroussin 
278539ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v1, top);
278639ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (v2, cp);
278739ee7a7aSBaptiste Daroussin 
2788*d9f0ce31SBaptiste Daroussin 	if (v1 && v2) {
27898e3b1ab2SBaptiste Daroussin 		kv_concat (ucl_object_t *, *v1, *v2);
27908e3b1ab2SBaptiste Daroussin 
27918e3b1ab2SBaptiste Daroussin 		for (i = v2->n; i < v1->n; i ++) {
27928e3b1ab2SBaptiste Daroussin 			obj = &kv_A (*v1, i);
27938e3b1ab2SBaptiste Daroussin 			if (*obj == NULL) {
27948e3b1ab2SBaptiste Daroussin 				continue;
27958e3b1ab2SBaptiste Daroussin 			}
27968e3b1ab2SBaptiste Daroussin 			top->len ++;
27974bf54857SBaptiste Daroussin 		}
2798*d9f0ce31SBaptiste Daroussin 	}
27994bf54857SBaptiste Daroussin 
28004bf54857SBaptiste Daroussin 	return true;
28014bf54857SBaptiste Daroussin }
28024bf54857SBaptiste Daroussin 
280397bd480fSBaptiste Daroussin ucl_object_t *
280497bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
280597bd480fSBaptiste Daroussin {
28068e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28078e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
28088e3b1ab2SBaptiste Daroussin 	unsigned i;
280997bd480fSBaptiste Daroussin 
281039ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
281139ee7a7aSBaptiste Daroussin 		return NULL;
281239ee7a7aSBaptiste Daroussin 	}
281339ee7a7aSBaptiste Daroussin 
28148e3b1ab2SBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
28158e3b1ab2SBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
28168e3b1ab2SBaptiste Daroussin 			kv_del (ucl_object_t *, *vec, i);
28178e3b1ab2SBaptiste Daroussin 			ret = elt;
281897bd480fSBaptiste Daroussin 			top->len --;
28198e3b1ab2SBaptiste Daroussin 			break;
28208e3b1ab2SBaptiste Daroussin 		}
28218e3b1ab2SBaptiste Daroussin 	}
282297bd480fSBaptiste Daroussin 
28238e3b1ab2SBaptiste Daroussin 	return ret;
282497bd480fSBaptiste Daroussin }
282597bd480fSBaptiste Daroussin 
2826b04a7a0bSBaptiste Daroussin const ucl_object_t *
2827b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top)
282897bd480fSBaptiste Daroussin {
28298e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28308e3b1ab2SBaptiste Daroussin 
283139ee7a7aSBaptiste Daroussin 	if (vec == NULL || top == NULL || top->type != UCL_ARRAY ||
283239ee7a7aSBaptiste Daroussin 			top->value.av == NULL) {
283397bd480fSBaptiste Daroussin 		return NULL;
283497bd480fSBaptiste Daroussin 	}
28358e3b1ab2SBaptiste Daroussin 
28368e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[0] : NULL);
283797bd480fSBaptiste Daroussin }
283897bd480fSBaptiste Daroussin 
2839b04a7a0bSBaptiste Daroussin const ucl_object_t *
2840b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top)
284197bd480fSBaptiste Daroussin {
28428e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28438e3b1ab2SBaptiste Daroussin 
284497bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
284597bd480fSBaptiste Daroussin 		return NULL;
284697bd480fSBaptiste Daroussin 	}
28478e3b1ab2SBaptiste Daroussin 
28488e3b1ab2SBaptiste Daroussin 	return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
284997bd480fSBaptiste Daroussin }
285097bd480fSBaptiste Daroussin 
285197bd480fSBaptiste Daroussin ucl_object_t *
285297bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top)
285397bd480fSBaptiste Daroussin {
28548e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28558e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
28568e3b1ab2SBaptiste Daroussin 
28578e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
28588e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, vec->n - 1);
28598e3b1ab2SBaptiste Daroussin 		ret = *obj;
28608e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, vec->n - 1);
28618e3b1ab2SBaptiste Daroussin 		top->len --;
28628e3b1ab2SBaptiste Daroussin 	}
28638e3b1ab2SBaptiste Daroussin 
28648e3b1ab2SBaptiste Daroussin 	return ret;
286597bd480fSBaptiste Daroussin }
286697bd480fSBaptiste Daroussin 
286797bd480fSBaptiste Daroussin ucl_object_t *
286897bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top)
286997bd480fSBaptiste Daroussin {
28708e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28718e3b1ab2SBaptiste Daroussin 	ucl_object_t **obj, *ret = NULL;
28728e3b1ab2SBaptiste Daroussin 
28738e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0) {
28748e3b1ab2SBaptiste Daroussin 		obj = &kv_A (*vec, 0);
28758e3b1ab2SBaptiste Daroussin 		ret = *obj;
28768e3b1ab2SBaptiste Daroussin 		kv_del (ucl_object_t *, *vec, 0);
28778e3b1ab2SBaptiste Daroussin 		top->len --;
28788e3b1ab2SBaptiste Daroussin 	}
28798e3b1ab2SBaptiste Daroussin 
28808e3b1ab2SBaptiste Daroussin 	return ret;
288197bd480fSBaptiste Daroussin }
288297bd480fSBaptiste Daroussin 
28832e8ed2b8SBaptiste Daroussin const ucl_object_t *
28842e8ed2b8SBaptiste Daroussin ucl_array_find_index (const ucl_object_t *top, unsigned int index)
28852e8ed2b8SBaptiste Daroussin {
28868e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
28872e8ed2b8SBaptiste Daroussin 
28888e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
28898e3b1ab2SBaptiste Daroussin 		return kv_A (*vec, index);
28902e8ed2b8SBaptiste Daroussin 	}
28912e8ed2b8SBaptiste Daroussin 
28922e8ed2b8SBaptiste Daroussin 	return NULL;
28932e8ed2b8SBaptiste Daroussin }
28942e8ed2b8SBaptiste Daroussin 
289539ee7a7aSBaptiste Daroussin unsigned int
289639ee7a7aSBaptiste Daroussin ucl_array_index_of (ucl_object_t *top, ucl_object_t *elt)
289739ee7a7aSBaptiste Daroussin {
289839ee7a7aSBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
289939ee7a7aSBaptiste Daroussin 	unsigned i;
290039ee7a7aSBaptiste Daroussin 
290139ee7a7aSBaptiste Daroussin 	if (vec == NULL) {
290239ee7a7aSBaptiste Daroussin 		return (unsigned int)(-1);
290339ee7a7aSBaptiste Daroussin 	}
290439ee7a7aSBaptiste Daroussin 
290539ee7a7aSBaptiste Daroussin 	for (i = 0; i < vec->n; i ++) {
290639ee7a7aSBaptiste Daroussin 		if (kv_A (*vec, i) == elt) {
290739ee7a7aSBaptiste Daroussin 			return i;
290839ee7a7aSBaptiste Daroussin 		}
290939ee7a7aSBaptiste Daroussin 	}
291039ee7a7aSBaptiste Daroussin 
291139ee7a7aSBaptiste Daroussin 	return (unsigned int)(-1);
291239ee7a7aSBaptiste Daroussin }
291339ee7a7aSBaptiste Daroussin 
291497bd480fSBaptiste Daroussin ucl_object_t *
29154bf54857SBaptiste Daroussin ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
29164bf54857SBaptiste Daroussin 	unsigned int index)
29174bf54857SBaptiste Daroussin {
29188e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, top);
29198e3b1ab2SBaptiste Daroussin 	ucl_object_t *ret = NULL;
29204bf54857SBaptiste Daroussin 
29218e3b1ab2SBaptiste Daroussin 	if (vec != NULL && vec->n > 0 && index < vec->n) {
29228e3b1ab2SBaptiste Daroussin 		ret = kv_A (*vec, index);
29238e3b1ab2SBaptiste Daroussin 		kv_A (*vec, index) = elt;
29244bf54857SBaptiste Daroussin 	}
29254bf54857SBaptiste Daroussin 
29268e3b1ab2SBaptiste Daroussin 	return ret;
29274bf54857SBaptiste Daroussin }
29284bf54857SBaptiste Daroussin 
29294bf54857SBaptiste Daroussin ucl_object_t *
293097bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
293197bd480fSBaptiste Daroussin {
293297bd480fSBaptiste Daroussin 
293397bd480fSBaptiste Daroussin 	if (head == NULL) {
293497bd480fSBaptiste Daroussin 		elt->next = NULL;
293597bd480fSBaptiste Daroussin 		elt->prev = elt;
293697bd480fSBaptiste Daroussin 		head = elt;
293797bd480fSBaptiste Daroussin 	}
293897bd480fSBaptiste Daroussin 	else {
293997bd480fSBaptiste Daroussin 		elt->prev = head->prev;
294097bd480fSBaptiste Daroussin 		head->prev->next = elt;
294197bd480fSBaptiste Daroussin 		head->prev = elt;
294297bd480fSBaptiste Daroussin 		elt->next = NULL;
294397bd480fSBaptiste Daroussin 	}
294497bd480fSBaptiste Daroussin 
294597bd480fSBaptiste Daroussin 	return head;
294697bd480fSBaptiste Daroussin }
294797bd480fSBaptiste Daroussin 
294897bd480fSBaptiste Daroussin bool
2949b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
295097bd480fSBaptiste Daroussin {
295197bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
295297bd480fSBaptiste Daroussin 		return false;
295397bd480fSBaptiste Daroussin 	}
295497bd480fSBaptiste Daroussin 	switch (obj->type) {
295597bd480fSBaptiste Daroussin 	case UCL_INT:
295697bd480fSBaptiste Daroussin 		*target = obj->value.iv; /* Probaly could cause overflow */
295797bd480fSBaptiste Daroussin 		break;
295897bd480fSBaptiste Daroussin 	case UCL_FLOAT:
295997bd480fSBaptiste Daroussin 	case UCL_TIME:
296097bd480fSBaptiste Daroussin 		*target = obj->value.dv;
296197bd480fSBaptiste Daroussin 		break;
296297bd480fSBaptiste Daroussin 	default:
296397bd480fSBaptiste Daroussin 		return false;
296497bd480fSBaptiste Daroussin 	}
296597bd480fSBaptiste Daroussin 
296697bd480fSBaptiste Daroussin 	return true;
296797bd480fSBaptiste Daroussin }
296897bd480fSBaptiste Daroussin 
296997bd480fSBaptiste Daroussin double
2970b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj)
297197bd480fSBaptiste Daroussin {
297297bd480fSBaptiste Daroussin 	double result = 0.;
297397bd480fSBaptiste Daroussin 
297497bd480fSBaptiste Daroussin 	ucl_object_todouble_safe (obj, &result);
297597bd480fSBaptiste Daroussin 	return result;
297697bd480fSBaptiste Daroussin }
297797bd480fSBaptiste Daroussin 
297897bd480fSBaptiste Daroussin bool
2979b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
298097bd480fSBaptiste Daroussin {
298197bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
298297bd480fSBaptiste Daroussin 		return false;
298397bd480fSBaptiste Daroussin 	}
298497bd480fSBaptiste Daroussin 	switch (obj->type) {
298597bd480fSBaptiste Daroussin 	case UCL_INT:
298697bd480fSBaptiste Daroussin 		*target = obj->value.iv;
298797bd480fSBaptiste Daroussin 		break;
298897bd480fSBaptiste Daroussin 	case UCL_FLOAT:
298997bd480fSBaptiste Daroussin 	case UCL_TIME:
299097bd480fSBaptiste Daroussin 		*target = obj->value.dv; /* Loosing of decimal points */
299197bd480fSBaptiste Daroussin 		break;
299297bd480fSBaptiste Daroussin 	default:
299397bd480fSBaptiste Daroussin 		return false;
299497bd480fSBaptiste Daroussin 	}
299597bd480fSBaptiste Daroussin 
299697bd480fSBaptiste Daroussin 	return true;
299797bd480fSBaptiste Daroussin }
299897bd480fSBaptiste Daroussin 
299997bd480fSBaptiste Daroussin int64_t
3000b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj)
300197bd480fSBaptiste Daroussin {
300297bd480fSBaptiste Daroussin 	int64_t result = 0;
300397bd480fSBaptiste Daroussin 
300497bd480fSBaptiste Daroussin 	ucl_object_toint_safe (obj, &result);
300597bd480fSBaptiste Daroussin 	return result;
300697bd480fSBaptiste Daroussin }
300797bd480fSBaptiste Daroussin 
300897bd480fSBaptiste Daroussin bool
3009b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
301097bd480fSBaptiste Daroussin {
301197bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
301297bd480fSBaptiste Daroussin 		return false;
301397bd480fSBaptiste Daroussin 	}
301497bd480fSBaptiste Daroussin 	switch (obj->type) {
301597bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
301697bd480fSBaptiste Daroussin 		*target = (obj->value.iv == true);
301797bd480fSBaptiste Daroussin 		break;
301897bd480fSBaptiste Daroussin 	default:
301997bd480fSBaptiste Daroussin 		return false;
302097bd480fSBaptiste Daroussin 	}
302197bd480fSBaptiste Daroussin 
302297bd480fSBaptiste Daroussin 	return true;
302397bd480fSBaptiste Daroussin }
302497bd480fSBaptiste Daroussin 
302597bd480fSBaptiste Daroussin bool
3026b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj)
302797bd480fSBaptiste Daroussin {
302897bd480fSBaptiste Daroussin 	bool result = false;
302997bd480fSBaptiste Daroussin 
303097bd480fSBaptiste Daroussin 	ucl_object_toboolean_safe (obj, &result);
303197bd480fSBaptiste Daroussin 	return result;
303297bd480fSBaptiste Daroussin }
303397bd480fSBaptiste Daroussin 
303497bd480fSBaptiste Daroussin bool
3035b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
303697bd480fSBaptiste Daroussin {
303797bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
303897bd480fSBaptiste Daroussin 		return false;
303997bd480fSBaptiste Daroussin 	}
304097bd480fSBaptiste Daroussin 
304197bd480fSBaptiste Daroussin 	switch (obj->type) {
304297bd480fSBaptiste Daroussin 	case UCL_STRING:
304339ee7a7aSBaptiste Daroussin 		if (!(obj->flags & UCL_OBJECT_BINARY)) {
304497bd480fSBaptiste Daroussin 			*target = ucl_copy_value_trash (obj);
304539ee7a7aSBaptiste Daroussin 		}
304697bd480fSBaptiste Daroussin 		break;
304797bd480fSBaptiste Daroussin 	default:
304897bd480fSBaptiste Daroussin 		return false;
304997bd480fSBaptiste Daroussin 	}
305097bd480fSBaptiste Daroussin 
305197bd480fSBaptiste Daroussin 	return true;
305297bd480fSBaptiste Daroussin }
305397bd480fSBaptiste Daroussin 
305497bd480fSBaptiste Daroussin const char *
3055b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj)
305697bd480fSBaptiste Daroussin {
305797bd480fSBaptiste Daroussin 	const char *result = NULL;
305897bd480fSBaptiste Daroussin 
305997bd480fSBaptiste Daroussin 	ucl_object_tostring_safe (obj, &result);
306097bd480fSBaptiste Daroussin 	return result;
306197bd480fSBaptiste Daroussin }
306297bd480fSBaptiste Daroussin 
306397bd480fSBaptiste Daroussin const char *
3064b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj)
306597bd480fSBaptiste Daroussin {
306639ee7a7aSBaptiste Daroussin 	/* TODO: For binary strings we might encode string here */
306739ee7a7aSBaptiste Daroussin 	if (!(obj->flags & UCL_OBJECT_BINARY)) {
306897bd480fSBaptiste Daroussin 		return ucl_copy_value_trash (obj);
306997bd480fSBaptiste Daroussin 	}
307097bd480fSBaptiste Daroussin 
307139ee7a7aSBaptiste Daroussin 	return NULL;
307239ee7a7aSBaptiste Daroussin }
307339ee7a7aSBaptiste Daroussin 
307497bd480fSBaptiste Daroussin bool
3075b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
307697bd480fSBaptiste Daroussin {
307797bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
307897bd480fSBaptiste Daroussin 		return false;
307997bd480fSBaptiste Daroussin 	}
308097bd480fSBaptiste Daroussin 	switch (obj->type) {
308197bd480fSBaptiste Daroussin 	case UCL_STRING:
308297bd480fSBaptiste Daroussin 		*target = obj->value.sv;
308397bd480fSBaptiste Daroussin 		if (tlen != NULL) {
308497bd480fSBaptiste Daroussin 			*tlen = obj->len;
308597bd480fSBaptiste Daroussin 		}
308697bd480fSBaptiste Daroussin 		break;
308797bd480fSBaptiste Daroussin 	default:
308897bd480fSBaptiste Daroussin 		return false;
308997bd480fSBaptiste Daroussin 	}
309097bd480fSBaptiste Daroussin 
309197bd480fSBaptiste Daroussin 	return true;
309297bd480fSBaptiste Daroussin }
309397bd480fSBaptiste Daroussin 
309497bd480fSBaptiste Daroussin const char *
3095b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
309697bd480fSBaptiste Daroussin {
309797bd480fSBaptiste Daroussin 	const char *result = NULL;
309897bd480fSBaptiste Daroussin 
309997bd480fSBaptiste Daroussin 	ucl_object_tolstring_safe (obj, &result, tlen);
310097bd480fSBaptiste Daroussin 	return result;
310197bd480fSBaptiste Daroussin }
310297bd480fSBaptiste Daroussin 
310397bd480fSBaptiste Daroussin const char *
3104b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj)
310597bd480fSBaptiste Daroussin {
310697bd480fSBaptiste Daroussin 	return ucl_copy_key_trash (obj);
310797bd480fSBaptiste Daroussin }
310897bd480fSBaptiste Daroussin 
310997bd480fSBaptiste Daroussin const char *
3110b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len)
311197bd480fSBaptiste Daroussin {
311297bd480fSBaptiste Daroussin 	if (len == NULL || obj == NULL) {
311397bd480fSBaptiste Daroussin 		return NULL;
311497bd480fSBaptiste Daroussin 	}
311597bd480fSBaptiste Daroussin 	*len = obj->keylen;
311697bd480fSBaptiste Daroussin 	return obj->key;
311797bd480fSBaptiste Daroussin }
311897bd480fSBaptiste Daroussin 
311997bd480fSBaptiste Daroussin ucl_object_t *
3120b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj)
312197bd480fSBaptiste Daroussin {
3122b04a7a0bSBaptiste Daroussin 	ucl_object_t *res = NULL;
3123b04a7a0bSBaptiste Daroussin 
312497bd480fSBaptiste Daroussin 	if (obj != NULL) {
31254bf54857SBaptiste Daroussin 		if (obj->flags & UCL_OBJECT_EPHEMERAL) {
31264bf54857SBaptiste Daroussin 			/*
31274bf54857SBaptiste Daroussin 			 * Use deep copy for ephemeral objects, note that its refcount
31284bf54857SBaptiste Daroussin 			 * is NOT increased, since ephemeral objects does not need refcount
31294bf54857SBaptiste Daroussin 			 * at all
31304bf54857SBaptiste Daroussin 			 */
31314bf54857SBaptiste Daroussin 			res = ucl_object_copy (obj);
31324bf54857SBaptiste Daroussin 		}
31334bf54857SBaptiste Daroussin 		else {
3134b04a7a0bSBaptiste Daroussin 			res = __DECONST (ucl_object_t *, obj);
3135b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3136b04a7a0bSBaptiste Daroussin 			(void)__sync_add_and_fetch (&res->ref, 1);
3137b04a7a0bSBaptiste Daroussin #else
3138b04a7a0bSBaptiste Daroussin 			res->ref ++;
3139b04a7a0bSBaptiste Daroussin #endif
314097bd480fSBaptiste Daroussin 		}
31414bf54857SBaptiste Daroussin 	}
3142b04a7a0bSBaptiste Daroussin 	return res;
314397bd480fSBaptiste Daroussin }
314497bd480fSBaptiste Daroussin 
31454bf54857SBaptiste Daroussin static ucl_object_t *
31464bf54857SBaptiste Daroussin ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
31474bf54857SBaptiste Daroussin {
31484bf54857SBaptiste Daroussin 
31494bf54857SBaptiste Daroussin 	ucl_object_t *new;
31504bf54857SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
31514bf54857SBaptiste Daroussin 	const ucl_object_t *cur;
31524bf54857SBaptiste Daroussin 
31534bf54857SBaptiste Daroussin 	new = malloc (sizeof (*new));
31544bf54857SBaptiste Daroussin 
31554bf54857SBaptiste Daroussin 	if (new != NULL) {
31564bf54857SBaptiste Daroussin 		memcpy (new, other, sizeof (*new));
31574bf54857SBaptiste Daroussin 		if (other->flags & UCL_OBJECT_EPHEMERAL) {
31584bf54857SBaptiste Daroussin 			/* Copied object is always non ephemeral */
31594bf54857SBaptiste Daroussin 			new->flags &= ~UCL_OBJECT_EPHEMERAL;
31604bf54857SBaptiste Daroussin 		}
31614bf54857SBaptiste Daroussin 		new->ref = 1;
31624bf54857SBaptiste Daroussin 		/* Unlink from others */
31634bf54857SBaptiste Daroussin 		new->next = NULL;
31644bf54857SBaptiste Daroussin 		new->prev = new;
31654bf54857SBaptiste Daroussin 
31664bf54857SBaptiste Daroussin 		/* deep copy of values stored */
31674bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
31684bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_KEY] =
31694bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_KEY]);
31704bf54857SBaptiste Daroussin 			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
31714bf54857SBaptiste Daroussin 				new->key = new->trash_stack[UCL_TRASH_KEY];
31724bf54857SBaptiste Daroussin 			}
31734bf54857SBaptiste Daroussin 		}
31744bf54857SBaptiste Daroussin 		if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
31754bf54857SBaptiste Daroussin 			new->trash_stack[UCL_TRASH_VALUE] =
31764bf54857SBaptiste Daroussin 					strdup (other->trash_stack[UCL_TRASH_VALUE]);
31774bf54857SBaptiste Daroussin 			if (new->type == UCL_STRING) {
31784bf54857SBaptiste Daroussin 				new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
31794bf54857SBaptiste Daroussin 			}
31804bf54857SBaptiste Daroussin 		}
31814bf54857SBaptiste Daroussin 
31824bf54857SBaptiste Daroussin 		if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
31834bf54857SBaptiste Daroussin 			/* reset old value */
31844bf54857SBaptiste Daroussin 			memset (&new->value, 0, sizeof (new->value));
31854bf54857SBaptiste Daroussin 
3186*d9f0ce31SBaptiste Daroussin 			while ((cur = ucl_object_iterate (other, &it, true)) != NULL) {
31874bf54857SBaptiste Daroussin 				if (other->type == UCL_ARRAY) {
31884bf54857SBaptiste Daroussin 					ucl_array_append (new, ucl_object_copy_internal (cur, false));
31894bf54857SBaptiste Daroussin 				}
31904bf54857SBaptiste Daroussin 				else {
31914bf54857SBaptiste Daroussin 					ucl_object_t *cp = ucl_object_copy_internal (cur, true);
31924bf54857SBaptiste Daroussin 					if (cp != NULL) {
31934bf54857SBaptiste Daroussin 						ucl_object_insert_key (new, cp, cp->key, cp->keylen,
31944bf54857SBaptiste Daroussin 								false);
31954bf54857SBaptiste Daroussin 					}
31964bf54857SBaptiste Daroussin 				}
31974bf54857SBaptiste Daroussin 			}
31984bf54857SBaptiste Daroussin 		}
31994bf54857SBaptiste Daroussin 		else if (allow_array && other->next != NULL) {
32004bf54857SBaptiste Daroussin 			LL_FOREACH (other->next, cur) {
32014bf54857SBaptiste Daroussin 				ucl_object_t *cp = ucl_object_copy_internal (cur, false);
32024bf54857SBaptiste Daroussin 				if (cp != NULL) {
32034bf54857SBaptiste Daroussin 					DL_APPEND (new, cp);
32044bf54857SBaptiste Daroussin 				}
32054bf54857SBaptiste Daroussin 			}
32064bf54857SBaptiste Daroussin 		}
32074bf54857SBaptiste Daroussin 	}
32084bf54857SBaptiste Daroussin 
32094bf54857SBaptiste Daroussin 	return new;
32104bf54857SBaptiste Daroussin }
32114bf54857SBaptiste Daroussin 
32124bf54857SBaptiste Daroussin ucl_object_t *
32134bf54857SBaptiste Daroussin ucl_object_copy (const ucl_object_t *other)
32144bf54857SBaptiste Daroussin {
32154bf54857SBaptiste Daroussin 	return ucl_object_copy_internal (other, true);
32164bf54857SBaptiste Daroussin }
32174bf54857SBaptiste Daroussin 
321897bd480fSBaptiste Daroussin void
321997bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj)
322097bd480fSBaptiste Daroussin {
3221b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
3222b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
3223b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
3224b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
3225b04a7a0bSBaptiste Daroussin #else
3226b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
3227b04a7a0bSBaptiste Daroussin #endif
3228b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
3229b04a7a0bSBaptiste Daroussin 		}
323097bd480fSBaptiste Daroussin 	}
323197bd480fSBaptiste Daroussin }
323297bd480fSBaptiste Daroussin 
323397bd480fSBaptiste Daroussin int
3234b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
323597bd480fSBaptiste Daroussin {
3236b04a7a0bSBaptiste Daroussin 	const ucl_object_t *it1, *it2;
323797bd480fSBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
323897bd480fSBaptiste Daroussin 	int ret = 0;
323997bd480fSBaptiste Daroussin 
324097bd480fSBaptiste Daroussin 	if (o1->type != o2->type) {
324197bd480fSBaptiste Daroussin 		return (o1->type) - (o2->type);
324297bd480fSBaptiste Daroussin 	}
324397bd480fSBaptiste Daroussin 
324497bd480fSBaptiste Daroussin 	switch (o1->type) {
324597bd480fSBaptiste Daroussin 	case UCL_STRING:
32468e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
324797bd480fSBaptiste Daroussin 			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
324897bd480fSBaptiste Daroussin 		}
324997bd480fSBaptiste Daroussin 		else {
325097bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
325197bd480fSBaptiste Daroussin 		}
325297bd480fSBaptiste Daroussin 		break;
325397bd480fSBaptiste Daroussin 	case UCL_FLOAT:
325497bd480fSBaptiste Daroussin 	case UCL_INT:
325597bd480fSBaptiste Daroussin 	case UCL_TIME:
325697bd480fSBaptiste Daroussin 		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
325797bd480fSBaptiste Daroussin 		break;
325897bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
325997bd480fSBaptiste Daroussin 		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
326097bd480fSBaptiste Daroussin 		break;
326197bd480fSBaptiste Daroussin 	case UCL_ARRAY:
32628e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
32638e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec1, o1);
32648e3b1ab2SBaptiste Daroussin 			UCL_ARRAY_GET (vec2, o2);
32658e3b1ab2SBaptiste Daroussin 			unsigned i;
32668e3b1ab2SBaptiste Daroussin 
326797bd480fSBaptiste Daroussin 			/* Compare all elements in both arrays */
32688e3b1ab2SBaptiste Daroussin 			for (i = 0; i < vec1->n; i ++) {
32698e3b1ab2SBaptiste Daroussin 				it1 = kv_A (*vec1, i);
32708e3b1ab2SBaptiste Daroussin 				it2 = kv_A (*vec2, i);
32718e3b1ab2SBaptiste Daroussin 
32728e3b1ab2SBaptiste Daroussin 				if (it1 == NULL && it2 != NULL) {
32738e3b1ab2SBaptiste Daroussin 					return -1;
32748e3b1ab2SBaptiste Daroussin 				}
32758e3b1ab2SBaptiste Daroussin 				else if (it2 == NULL && it1 != NULL) {
32768e3b1ab2SBaptiste Daroussin 					return 1;
32778e3b1ab2SBaptiste Daroussin 				}
32788e3b1ab2SBaptiste Daroussin 				else if (it1 != NULL && it2 != NULL) {
327997bd480fSBaptiste Daroussin 					ret = ucl_object_compare (it1, it2);
328097bd480fSBaptiste Daroussin 					if (ret != 0) {
328197bd480fSBaptiste Daroussin 						break;
328297bd480fSBaptiste Daroussin 					}
32838e3b1ab2SBaptiste Daroussin 				}
328497bd480fSBaptiste Daroussin 			}
328597bd480fSBaptiste Daroussin 		}
328697bd480fSBaptiste Daroussin 		else {
328797bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
328897bd480fSBaptiste Daroussin 		}
328997bd480fSBaptiste Daroussin 		break;
329097bd480fSBaptiste Daroussin 	case UCL_OBJECT:
32918e3b1ab2SBaptiste Daroussin 		if (o1->len == o2->len && o1->len > 0) {
3292*d9f0ce31SBaptiste Daroussin 			while ((it1 = ucl_object_iterate (o1, &iter, true)) != NULL) {
3293*d9f0ce31SBaptiste Daroussin 				it2 = ucl_object_lookup (o2, ucl_object_key (it1));
329497bd480fSBaptiste Daroussin 				if (it2 == NULL) {
329597bd480fSBaptiste Daroussin 					ret = 1;
329697bd480fSBaptiste Daroussin 					break;
329797bd480fSBaptiste Daroussin 				}
329897bd480fSBaptiste Daroussin 				ret = ucl_object_compare (it1, it2);
329997bd480fSBaptiste Daroussin 				if (ret != 0) {
330097bd480fSBaptiste Daroussin 					break;
330197bd480fSBaptiste Daroussin 				}
330297bd480fSBaptiste Daroussin 			}
330397bd480fSBaptiste Daroussin 		}
330497bd480fSBaptiste Daroussin 		else {
330597bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
330697bd480fSBaptiste Daroussin 		}
330797bd480fSBaptiste Daroussin 		break;
330897bd480fSBaptiste Daroussin 	default:
330997bd480fSBaptiste Daroussin 		ret = 0;
331097bd480fSBaptiste Daroussin 		break;
331197bd480fSBaptiste Daroussin 	}
331297bd480fSBaptiste Daroussin 
331397bd480fSBaptiste Daroussin 	return ret;
331497bd480fSBaptiste Daroussin }
331597bd480fSBaptiste Daroussin 
3316*d9f0ce31SBaptiste Daroussin int
3317*d9f0ce31SBaptiste Daroussin ucl_object_compare_qsort (const ucl_object_t **o1,
3318*d9f0ce31SBaptiste Daroussin 		const ucl_object_t **o2)
3319*d9f0ce31SBaptiste Daroussin {
3320*d9f0ce31SBaptiste Daroussin 	return ucl_object_compare (*o1, *o2);
3321*d9f0ce31SBaptiste Daroussin }
3322*d9f0ce31SBaptiste Daroussin 
332397bd480fSBaptiste Daroussin void
332497bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar,
332539ee7a7aSBaptiste Daroussin 		int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2))
332697bd480fSBaptiste Daroussin {
33278e3b1ab2SBaptiste Daroussin 	UCL_ARRAY_GET (vec, ar);
33288e3b1ab2SBaptiste Daroussin 
332997bd480fSBaptiste Daroussin 	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
333097bd480fSBaptiste Daroussin 		return;
333197bd480fSBaptiste Daroussin 	}
333297bd480fSBaptiste Daroussin 
33338e3b1ab2SBaptiste Daroussin 	qsort (vec->a, vec->n, sizeof (ucl_object_t *),
33348e3b1ab2SBaptiste Daroussin 			(int (*)(const void *, const void *))cmp);
333597bd480fSBaptiste Daroussin }
33364bf54857SBaptiste Daroussin 
33374bf54857SBaptiste Daroussin #define PRIOBITS 4
33384bf54857SBaptiste Daroussin 
33394bf54857SBaptiste Daroussin unsigned int
33404bf54857SBaptiste Daroussin ucl_object_get_priority (const ucl_object_t *obj)
33414bf54857SBaptiste Daroussin {
33424bf54857SBaptiste Daroussin 	if (obj == NULL) {
33434bf54857SBaptiste Daroussin 		return 0;
33444bf54857SBaptiste Daroussin 	}
33454bf54857SBaptiste Daroussin 
33464bf54857SBaptiste Daroussin 	return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
33474bf54857SBaptiste Daroussin }
33484bf54857SBaptiste Daroussin 
33494bf54857SBaptiste Daroussin void
33504bf54857SBaptiste Daroussin ucl_object_set_priority (ucl_object_t *obj,
33514bf54857SBaptiste Daroussin 		unsigned int priority)
33524bf54857SBaptiste Daroussin {
33534bf54857SBaptiste Daroussin 	if (obj != NULL) {
33544bf54857SBaptiste Daroussin 		priority &= (0x1 << PRIOBITS) - 1;
335539ee7a7aSBaptiste Daroussin 		priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS);
335639ee7a7aSBaptiste Daroussin 		priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) -
335739ee7a7aSBaptiste Daroussin 				PRIOBITS)) - 1);
335839ee7a7aSBaptiste Daroussin 		obj->flags = priority;
33594bf54857SBaptiste Daroussin 	}
33604bf54857SBaptiste Daroussin }
3361*d9f0ce31SBaptiste Daroussin 
3362*d9f0ce31SBaptiste Daroussin bool
3363*d9f0ce31SBaptiste Daroussin ucl_object_string_to_type (const char *input, ucl_type_t *res)
3364*d9f0ce31SBaptiste Daroussin {
3365*d9f0ce31SBaptiste Daroussin 	if (strcasecmp (input, "object") == 0) {
3366*d9f0ce31SBaptiste Daroussin 		*res = UCL_OBJECT;
3367*d9f0ce31SBaptiste Daroussin 	}
3368*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "array") == 0) {
3369*d9f0ce31SBaptiste Daroussin 		*res = UCL_ARRAY;
3370*d9f0ce31SBaptiste Daroussin 	}
3371*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "integer") == 0) {
3372*d9f0ce31SBaptiste Daroussin 		*res = UCL_INT;
3373*d9f0ce31SBaptiste Daroussin 	}
3374*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "number") == 0) {
3375*d9f0ce31SBaptiste Daroussin 		*res = UCL_FLOAT;
3376*d9f0ce31SBaptiste Daroussin 	}
3377*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "string") == 0) {
3378*d9f0ce31SBaptiste Daroussin 		*res = UCL_STRING;
3379*d9f0ce31SBaptiste Daroussin 	}
3380*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "boolean") == 0) {
3381*d9f0ce31SBaptiste Daroussin 		*res = UCL_BOOLEAN;
3382*d9f0ce31SBaptiste Daroussin 	}
3383*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "null") == 0) {
3384*d9f0ce31SBaptiste Daroussin 		*res = UCL_NULL;
3385*d9f0ce31SBaptiste Daroussin 	}
3386*d9f0ce31SBaptiste Daroussin 	else if (strcasecmp (input, "userdata") == 0) {
3387*d9f0ce31SBaptiste Daroussin 		*res = UCL_USERDATA;
3388*d9f0ce31SBaptiste Daroussin 	}
3389*d9f0ce31SBaptiste Daroussin 	else {
3390*d9f0ce31SBaptiste Daroussin 		return false;
3391*d9f0ce31SBaptiste Daroussin 	}
3392*d9f0ce31SBaptiste Daroussin 
3393*d9f0ce31SBaptiste Daroussin 	return true;
3394*d9f0ce31SBaptiste Daroussin }
3395*d9f0ce31SBaptiste Daroussin 
3396*d9f0ce31SBaptiste Daroussin const char *
3397*d9f0ce31SBaptiste Daroussin ucl_object_type_to_string (ucl_type_t type)
3398*d9f0ce31SBaptiste Daroussin {
3399*d9f0ce31SBaptiste Daroussin 	const char *res = "unknown";
3400*d9f0ce31SBaptiste Daroussin 
3401*d9f0ce31SBaptiste Daroussin 	switch (type) {
3402*d9f0ce31SBaptiste Daroussin 	case UCL_OBJECT:
3403*d9f0ce31SBaptiste Daroussin 		res = "object";
3404*d9f0ce31SBaptiste Daroussin 		break;
3405*d9f0ce31SBaptiste Daroussin 	case UCL_ARRAY:
3406*d9f0ce31SBaptiste Daroussin 		res = "array";
3407*d9f0ce31SBaptiste Daroussin 		break;
3408*d9f0ce31SBaptiste Daroussin 	case UCL_INT:
3409*d9f0ce31SBaptiste Daroussin 		res = "integer";
3410*d9f0ce31SBaptiste Daroussin 		break;
3411*d9f0ce31SBaptiste Daroussin 	case UCL_FLOAT:
3412*d9f0ce31SBaptiste Daroussin 	case UCL_TIME:
3413*d9f0ce31SBaptiste Daroussin 		res = "number";
3414*d9f0ce31SBaptiste Daroussin 		break;
3415*d9f0ce31SBaptiste Daroussin 	case UCL_STRING:
3416*d9f0ce31SBaptiste Daroussin 		res = "string";
3417*d9f0ce31SBaptiste Daroussin 		break;
3418*d9f0ce31SBaptiste Daroussin 	case UCL_BOOLEAN:
3419*d9f0ce31SBaptiste Daroussin 		res = "boolean";
3420*d9f0ce31SBaptiste Daroussin 		break;
3421*d9f0ce31SBaptiste Daroussin 	case UCL_USERDATA:
3422*d9f0ce31SBaptiste Daroussin 		res = "userdata";
3423*d9f0ce31SBaptiste Daroussin 		break;
3424*d9f0ce31SBaptiste Daroussin 	case UCL_NULL:
3425*d9f0ce31SBaptiste Daroussin 		res = "null";
3426*d9f0ce31SBaptiste Daroussin 		break;
3427*d9f0ce31SBaptiste Daroussin 	}
3428*d9f0ce31SBaptiste Daroussin 
3429*d9f0ce31SBaptiste Daroussin 	return res;
3430*d9f0ce31SBaptiste Daroussin }
3431*d9f0ce31SBaptiste Daroussin 
3432*d9f0ce31SBaptiste Daroussin const ucl_object_t *
3433*d9f0ce31SBaptiste Daroussin ucl_parser_get_comments (struct ucl_parser *parser)
3434*d9f0ce31SBaptiste Daroussin {
3435*d9f0ce31SBaptiste Daroussin 	if (parser && parser->comments) {
3436*d9f0ce31SBaptiste Daroussin 		return parser->comments;
3437*d9f0ce31SBaptiste Daroussin 	}
3438*d9f0ce31SBaptiste Daroussin 
3439*d9f0ce31SBaptiste Daroussin 	return NULL;
3440*d9f0ce31SBaptiste Daroussin }
3441*d9f0ce31SBaptiste Daroussin 
3442*d9f0ce31SBaptiste Daroussin const ucl_object_t *
3443*d9f0ce31SBaptiste Daroussin ucl_comments_find (const ucl_object_t *comments,
3444*d9f0ce31SBaptiste Daroussin 		const ucl_object_t *srch)
3445*d9f0ce31SBaptiste Daroussin {
3446*d9f0ce31SBaptiste Daroussin 	if (comments && srch) {
3447*d9f0ce31SBaptiste Daroussin 		return ucl_object_lookup_len (comments, (const char *)&srch,
3448*d9f0ce31SBaptiste Daroussin 				sizeof (void *));
3449*d9f0ce31SBaptiste Daroussin 	}
3450*d9f0ce31SBaptiste Daroussin 
3451*d9f0ce31SBaptiste Daroussin 	return NULL;
3452*d9f0ce31SBaptiste Daroussin }
3453*d9f0ce31SBaptiste Daroussin 
3454*d9f0ce31SBaptiste Daroussin bool
3455*d9f0ce31SBaptiste Daroussin ucl_comments_move (ucl_object_t *comments,
3456*d9f0ce31SBaptiste Daroussin 		const ucl_object_t *from, const ucl_object_t *to)
3457*d9f0ce31SBaptiste Daroussin {
3458*d9f0ce31SBaptiste Daroussin 	const ucl_object_t *found;
3459*d9f0ce31SBaptiste Daroussin 	ucl_object_t *obj;
3460*d9f0ce31SBaptiste Daroussin 
3461*d9f0ce31SBaptiste Daroussin 	if (comments && from && to) {
3462*d9f0ce31SBaptiste Daroussin 		found = ucl_object_lookup_len (comments,
3463*d9f0ce31SBaptiste Daroussin 				(const char *)&from, sizeof (void *));
3464*d9f0ce31SBaptiste Daroussin 
3465*d9f0ce31SBaptiste Daroussin 		if (found) {
3466*d9f0ce31SBaptiste Daroussin 			/* Replace key */
3467*d9f0ce31SBaptiste Daroussin 			obj = ucl_object_ref (found);
3468*d9f0ce31SBaptiste Daroussin 			ucl_object_delete_keyl (comments, (const char *)&from,
3469*d9f0ce31SBaptiste Daroussin 					sizeof (void *));
3470*d9f0ce31SBaptiste Daroussin 			ucl_object_insert_key (comments, obj, (const char *)&to,
3471*d9f0ce31SBaptiste Daroussin 					sizeof (void *), true);
3472*d9f0ce31SBaptiste Daroussin 
3473*d9f0ce31SBaptiste Daroussin 			return true;
3474*d9f0ce31SBaptiste Daroussin 		}
3475*d9f0ce31SBaptiste Daroussin 	}
3476*d9f0ce31SBaptiste Daroussin 
3477*d9f0ce31SBaptiste Daroussin 	return false;
3478*d9f0ce31SBaptiste Daroussin }
3479*d9f0ce31SBaptiste Daroussin 
3480*d9f0ce31SBaptiste Daroussin void
3481*d9f0ce31SBaptiste Daroussin ucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj,
3482*d9f0ce31SBaptiste Daroussin 		const char *comment)
3483*d9f0ce31SBaptiste Daroussin {
3484*d9f0ce31SBaptiste Daroussin 	if (comments && obj && comment) {
3485*d9f0ce31SBaptiste Daroussin 		ucl_object_insert_key (comments, ucl_object_fromstring (comment),
3486*d9f0ce31SBaptiste Daroussin 				(const char *)&obj, sizeof (void *), true);
3487*d9f0ce31SBaptiste Daroussin 	}
3488*d9f0ce31SBaptiste Daroussin }
3489