xref: /freebsd-src/contrib/libucl/src/ucl_util.c (revision b04a7a0baf6523245034b8ccd06cd0176b8a18cf)
1c99fb5f9SBaptiste Daroussin /* Copyright (c) 2013, Vsevolod Stakhov
2c99fb5f9SBaptiste Daroussin  * All rights reserved.
3c99fb5f9SBaptiste Daroussin  *
4c99fb5f9SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
5c99fb5f9SBaptiste Daroussin  * modification, are permitted provided that the following conditions are met:
6c99fb5f9SBaptiste Daroussin  *       * Redistributions of source code must retain the above copyright
7c99fb5f9SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer.
8c99fb5f9SBaptiste Daroussin  *       * Redistributions in binary form must reproduce the above copyright
9c99fb5f9SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer in the
10c99fb5f9SBaptiste Daroussin  *         documentation and/or other materials provided with the distribution.
11c99fb5f9SBaptiste Daroussin  *
12c99fb5f9SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13c99fb5f9SBaptiste Daroussin  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14c99fb5f9SBaptiste Daroussin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15c99fb5f9SBaptiste Daroussin  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16c99fb5f9SBaptiste Daroussin  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17c99fb5f9SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18c99fb5f9SBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19c99fb5f9SBaptiste Daroussin  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20c99fb5f9SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21c99fb5f9SBaptiste Daroussin  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22c99fb5f9SBaptiste Daroussin  */
23c99fb5f9SBaptiste Daroussin 
24c99fb5f9SBaptiste Daroussin #include "ucl.h"
25c99fb5f9SBaptiste Daroussin #include "ucl_internal.h"
26c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h"
27c99fb5f9SBaptiste Daroussin 
2897bd480fSBaptiste Daroussin #ifdef HAVE_LIBGEN_H
29c99fb5f9SBaptiste Daroussin #include <libgen.h> /* For dirname */
3097bd480fSBaptiste Daroussin #endif
31c99fb5f9SBaptiste Daroussin 
32c99fb5f9SBaptiste Daroussin #ifdef HAVE_OPENSSL
33c99fb5f9SBaptiste Daroussin #include <openssl/err.h>
34c99fb5f9SBaptiste Daroussin #include <openssl/sha.h>
35c99fb5f9SBaptiste Daroussin #include <openssl/rsa.h>
36c99fb5f9SBaptiste Daroussin #include <openssl/ssl.h>
37c99fb5f9SBaptiste Daroussin #include <openssl/evp.h>
38c99fb5f9SBaptiste Daroussin #endif
39c99fb5f9SBaptiste Daroussin 
4097bd480fSBaptiste Daroussin #ifdef CURL_FOUND
4197bd480fSBaptiste Daroussin #include <curl/curl.h>
4297bd480fSBaptiste Daroussin #endif
4397bd480fSBaptiste Daroussin #ifdef HAVE_FETCH_H
4497bd480fSBaptiste Daroussin #include <fetch.h>
4597bd480fSBaptiste Daroussin #endif
4697bd480fSBaptiste Daroussin 
4736c53d67SBaptiste Daroussin #ifdef _WIN32
4836c53d67SBaptiste Daroussin #include <windows.h>
4936c53d67SBaptiste Daroussin 
5097bd480fSBaptiste Daroussin #ifndef PROT_READ
5136c53d67SBaptiste Daroussin #define PROT_READ       1
5297bd480fSBaptiste Daroussin #endif
5397bd480fSBaptiste Daroussin #ifndef PROT_WRITE
5436c53d67SBaptiste Daroussin #define PROT_WRITE      2
5597bd480fSBaptiste Daroussin #endif
5697bd480fSBaptiste Daroussin #ifndef PROT_READWRITE
5736c53d67SBaptiste Daroussin #define PROT_READWRITE  3
5897bd480fSBaptiste Daroussin #endif
5997bd480fSBaptiste Daroussin #ifndef MAP_SHARED
6036c53d67SBaptiste Daroussin #define MAP_SHARED      1
6197bd480fSBaptiste Daroussin #endif
6297bd480fSBaptiste Daroussin #ifndef MAP_PRIVATE
6336c53d67SBaptiste Daroussin #define MAP_PRIVATE     2
6497bd480fSBaptiste Daroussin #endif
6597bd480fSBaptiste Daroussin #ifndef MAP_FAILED
6636c53d67SBaptiste Daroussin #define MAP_FAILED      ((void *) -1)
6797bd480fSBaptiste Daroussin #endif
6836c53d67SBaptiste Daroussin 
6997bd480fSBaptiste Daroussin static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
7036c53d67SBaptiste Daroussin {
7136c53d67SBaptiste Daroussin 	void *map = NULL;
7236c53d67SBaptiste Daroussin 	HANDLE handle = INVALID_HANDLE_VALUE;
7336c53d67SBaptiste Daroussin 
7436c53d67SBaptiste Daroussin 	switch (prot) {
7536c53d67SBaptiste Daroussin 	default:
7636c53d67SBaptiste Daroussin 	case PROT_READ:
7736c53d67SBaptiste Daroussin 		{
7836c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
7936c53d67SBaptiste Daroussin 			if (!handle) break;
8036c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
8136c53d67SBaptiste Daroussin 			CloseHandle(handle);
8236c53d67SBaptiste Daroussin 			break;
8336c53d67SBaptiste Daroussin 		}
8436c53d67SBaptiste Daroussin 	case PROT_WRITE:
8536c53d67SBaptiste Daroussin 		{
8636c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
8736c53d67SBaptiste Daroussin 			if (!handle) break;
8836c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
8936c53d67SBaptiste Daroussin 			CloseHandle(handle);
9036c53d67SBaptiste Daroussin 			break;
9136c53d67SBaptiste Daroussin 		}
9236c53d67SBaptiste Daroussin 	case PROT_READWRITE:
9336c53d67SBaptiste Daroussin 		{
9436c53d67SBaptiste Daroussin 			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
9536c53d67SBaptiste Daroussin 			if (!handle) break;
9636c53d67SBaptiste Daroussin 			map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
9736c53d67SBaptiste Daroussin 			CloseHandle(handle);
9836c53d67SBaptiste Daroussin 			break;
9936c53d67SBaptiste Daroussin 		}
10036c53d67SBaptiste Daroussin 	}
10136c53d67SBaptiste Daroussin 	if (map == (void *) NULL) {
10236c53d67SBaptiste Daroussin 		return (void *) MAP_FAILED;
10336c53d67SBaptiste Daroussin 	}
10436c53d67SBaptiste Daroussin 	return (void *) ((char *) map + offset);
10536c53d67SBaptiste Daroussin }
10636c53d67SBaptiste Daroussin 
10797bd480fSBaptiste Daroussin static int ucl_munmap(void *map,size_t length)
10836c53d67SBaptiste Daroussin {
10936c53d67SBaptiste Daroussin 	if (!UnmapViewOfFile(map)) {
11036c53d67SBaptiste Daroussin 		return(-1);
11136c53d67SBaptiste Daroussin 	}
11236c53d67SBaptiste Daroussin 	return(0);
11336c53d67SBaptiste Daroussin }
11436c53d67SBaptiste Daroussin 
11597bd480fSBaptiste Daroussin static char* ucl_realpath(const char *path, char *resolved_path) {
11636c53d67SBaptiste Daroussin     char *p;
11736c53d67SBaptiste Daroussin     char tmp[MAX_PATH + 1];
11836c53d67SBaptiste Daroussin     strncpy(tmp, path, sizeof(tmp)-1);
11936c53d67SBaptiste Daroussin     p = tmp;
12036c53d67SBaptiste Daroussin     while(*p) {
12136c53d67SBaptiste Daroussin         if (*p == '/') *p = '\\';
12236c53d67SBaptiste Daroussin         p++;
12336c53d67SBaptiste Daroussin     }
12436c53d67SBaptiste Daroussin     return _fullpath(resolved_path, tmp, MAX_PATH);
12536c53d67SBaptiste Daroussin }
12697bd480fSBaptiste Daroussin #else
12797bd480fSBaptiste Daroussin #define ucl_mmap mmap
12897bd480fSBaptiste Daroussin #define ucl_munmap munmap
12997bd480fSBaptiste Daroussin #define ucl_realpath realpath
13036c53d67SBaptiste Daroussin #endif
13136c53d67SBaptiste Daroussin 
132c99fb5f9SBaptiste Daroussin /**
133c99fb5f9SBaptiste Daroussin  * @file rcl_util.c
134c99fb5f9SBaptiste Daroussin  * Utilities for rcl parsing
135c99fb5f9SBaptiste Daroussin  */
136c99fb5f9SBaptiste Daroussin 
137*b04a7a0bSBaptiste Daroussin typedef void (*ucl_object_dtor) (ucl_object_t *obj);
138*b04a7a0bSBaptiste Daroussin static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
139*b04a7a0bSBaptiste Daroussin 		ucl_object_dtor dtor);
140*b04a7a0bSBaptiste Daroussin static void ucl_object_dtor_unref (ucl_object_t *obj);
141c99fb5f9SBaptiste Daroussin 
142c99fb5f9SBaptiste Daroussin static void
143*b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (ucl_object_t *obj)
144c99fb5f9SBaptiste Daroussin {
145c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
146c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
147c99fb5f9SBaptiste Daroussin 	}
148c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
149c99fb5f9SBaptiste Daroussin 		UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
150c99fb5f9SBaptiste Daroussin 	}
151*b04a7a0bSBaptiste Daroussin 	UCL_FREE (sizeof (ucl_object_t), obj);
152*b04a7a0bSBaptiste Daroussin }
153c99fb5f9SBaptiste Daroussin 
154*b04a7a0bSBaptiste Daroussin /*
155*b04a7a0bSBaptiste Daroussin  * This is a helper function that performs exactly the same as
156*b04a7a0bSBaptiste Daroussin  * `ucl_object_unref` but it doesn't iterate over elements allowing
157*b04a7a0bSBaptiste Daroussin  * to use it for individual elements of arrays and multiple values
158*b04a7a0bSBaptiste Daroussin  */
159*b04a7a0bSBaptiste Daroussin static void
160*b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (ucl_object_t *obj)
161*b04a7a0bSBaptiste Daroussin {
162*b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
163*b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
164*b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
165*b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
166*b04a7a0bSBaptiste Daroussin #else
167*b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
168*b04a7a0bSBaptiste Daroussin #endif
169*b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, false, ucl_object_dtor_unref);
170*b04a7a0bSBaptiste Daroussin 		}
171*b04a7a0bSBaptiste Daroussin 	}
172*b04a7a0bSBaptiste Daroussin }
173*b04a7a0bSBaptiste Daroussin 
174*b04a7a0bSBaptiste Daroussin static void
175*b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref (ucl_object_t *obj)
176*b04a7a0bSBaptiste Daroussin {
177*b04a7a0bSBaptiste Daroussin 	if (obj->ref == 0) {
178*b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_free (obj);
179*b04a7a0bSBaptiste Daroussin 	}
180*b04a7a0bSBaptiste Daroussin 	else {
181*b04a7a0bSBaptiste Daroussin 		/* This may cause dtor unref being called one more time */
182*b04a7a0bSBaptiste Daroussin 		ucl_object_dtor_unref_single (obj);
183*b04a7a0bSBaptiste Daroussin 	}
184*b04a7a0bSBaptiste Daroussin }
185*b04a7a0bSBaptiste Daroussin 
186*b04a7a0bSBaptiste Daroussin static void
187*b04a7a0bSBaptiste Daroussin ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
188*b04a7a0bSBaptiste Daroussin {
189*b04a7a0bSBaptiste Daroussin 	ucl_object_t *sub, *tmp;
190*b04a7a0bSBaptiste Daroussin 
191*b04a7a0bSBaptiste Daroussin 	while (obj != NULL) {
192c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_ARRAY) {
193c99fb5f9SBaptiste Daroussin 			sub = obj->value.av;
194c99fb5f9SBaptiste Daroussin 			while (sub != NULL) {
195c99fb5f9SBaptiste Daroussin 				tmp = sub->next;
196*b04a7a0bSBaptiste Daroussin 				dtor (sub);
197c99fb5f9SBaptiste Daroussin 				sub = tmp;
198c99fb5f9SBaptiste Daroussin 			}
199c99fb5f9SBaptiste Daroussin 		}
200c99fb5f9SBaptiste Daroussin 		else if (obj->type == UCL_OBJECT) {
201c99fb5f9SBaptiste Daroussin 			if (obj->value.ov != NULL) {
202*b04a7a0bSBaptiste Daroussin 				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor);
203c99fb5f9SBaptiste Daroussin 			}
204c99fb5f9SBaptiste Daroussin 		}
205c99fb5f9SBaptiste Daroussin 		tmp = obj->next;
206*b04a7a0bSBaptiste Daroussin 		dtor (obj);
207c99fb5f9SBaptiste Daroussin 		obj = tmp;
208c99fb5f9SBaptiste Daroussin 
209c99fb5f9SBaptiste Daroussin 		if (!allow_rec) {
210c99fb5f9SBaptiste Daroussin 			break;
211c99fb5f9SBaptiste Daroussin 		}
212c99fb5f9SBaptiste Daroussin 	}
213c99fb5f9SBaptiste Daroussin }
214c99fb5f9SBaptiste Daroussin 
215c99fb5f9SBaptiste Daroussin void
216c99fb5f9SBaptiste Daroussin ucl_object_free (ucl_object_t *obj)
217c99fb5f9SBaptiste Daroussin {
218*b04a7a0bSBaptiste Daroussin 	ucl_object_free_internal (obj, true, ucl_object_dtor_free);
219c99fb5f9SBaptiste Daroussin }
220c99fb5f9SBaptiste Daroussin 
221c99fb5f9SBaptiste Daroussin size_t
222c99fb5f9SBaptiste Daroussin ucl_unescape_json_string (char *str, size_t len)
223c99fb5f9SBaptiste Daroussin {
224c99fb5f9SBaptiste Daroussin 	char *t = str, *h = str;
225c99fb5f9SBaptiste Daroussin 	int i, uval;
226c99fb5f9SBaptiste Daroussin 
22797bd480fSBaptiste Daroussin 	if (len <= 1) {
22897bd480fSBaptiste Daroussin 		return len;
22997bd480fSBaptiste Daroussin 	}
230c99fb5f9SBaptiste Daroussin 	/* t is target (tortoise), h is source (hare) */
231c99fb5f9SBaptiste Daroussin 
232c99fb5f9SBaptiste Daroussin 	while (len) {
233c99fb5f9SBaptiste Daroussin 		if (*h == '\\') {
234c99fb5f9SBaptiste Daroussin 			h ++;
235c99fb5f9SBaptiste Daroussin 			switch (*h) {
236c99fb5f9SBaptiste Daroussin 			case 'n':
237c99fb5f9SBaptiste Daroussin 				*t++ = '\n';
238c99fb5f9SBaptiste Daroussin 				break;
239c99fb5f9SBaptiste Daroussin 			case 'r':
240c99fb5f9SBaptiste Daroussin 				*t++ = '\r';
241c99fb5f9SBaptiste Daroussin 				break;
242c99fb5f9SBaptiste Daroussin 			case 'b':
243c99fb5f9SBaptiste Daroussin 				*t++ = '\b';
244c99fb5f9SBaptiste Daroussin 				break;
245c99fb5f9SBaptiste Daroussin 			case 't':
246c99fb5f9SBaptiste Daroussin 				*t++ = '\t';
247c99fb5f9SBaptiste Daroussin 				break;
248c99fb5f9SBaptiste Daroussin 			case 'f':
249c99fb5f9SBaptiste Daroussin 				*t++ = '\f';
250c99fb5f9SBaptiste Daroussin 				break;
251c99fb5f9SBaptiste Daroussin 			case '\\':
252c99fb5f9SBaptiste Daroussin 				*t++ = '\\';
253c99fb5f9SBaptiste Daroussin 				break;
254c99fb5f9SBaptiste Daroussin 			case '"':
255c99fb5f9SBaptiste Daroussin 				*t++ = '"';
256c99fb5f9SBaptiste Daroussin 				break;
257c99fb5f9SBaptiste Daroussin 			case 'u':
258c99fb5f9SBaptiste Daroussin 				/* Unicode escape */
259c99fb5f9SBaptiste Daroussin 				uval = 0;
26097bd480fSBaptiste Daroussin 				if (len > 3) {
261c99fb5f9SBaptiste Daroussin 					for (i = 0; i < 4; i++) {
262c99fb5f9SBaptiste Daroussin 						uval <<= 4;
263c99fb5f9SBaptiste Daroussin 						if (isdigit (h[i])) {
264c99fb5f9SBaptiste Daroussin 							uval += h[i] - '0';
265c99fb5f9SBaptiste Daroussin 						}
266c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'a' && h[i] <= 'f') {
267c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'a' + 10;
268c99fb5f9SBaptiste Daroussin 						}
269c99fb5f9SBaptiste Daroussin 						else if (h[i] >= 'A' && h[i] <= 'F') {
270c99fb5f9SBaptiste Daroussin 							uval += h[i] - 'A' + 10;
271c99fb5f9SBaptiste Daroussin 						}
27297bd480fSBaptiste Daroussin 						else {
27397bd480fSBaptiste Daroussin 							break;
27497bd480fSBaptiste Daroussin 						}
275c99fb5f9SBaptiste Daroussin 					}
276c99fb5f9SBaptiste Daroussin 					h += 3;
277c99fb5f9SBaptiste Daroussin 					len -= 3;
278c99fb5f9SBaptiste Daroussin 					/* Encode */
279c99fb5f9SBaptiste Daroussin 					if(uval < 0x80) {
280c99fb5f9SBaptiste Daroussin 						t[0] = (char)uval;
281c99fb5f9SBaptiste Daroussin 						t ++;
282c99fb5f9SBaptiste Daroussin 					}
283c99fb5f9SBaptiste Daroussin 					else if(uval < 0x800) {
284c99fb5f9SBaptiste Daroussin 						t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
285c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F));
286c99fb5f9SBaptiste Daroussin 						t += 2;
287c99fb5f9SBaptiste Daroussin 					}
288c99fb5f9SBaptiste Daroussin 					else if(uval < 0x10000) {
289c99fb5f9SBaptiste Daroussin 						t[0] = 0xE0 + ((uval & 0xF000) >> 12);
290c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
291c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x003F));
292c99fb5f9SBaptiste Daroussin 						t += 3;
293c99fb5f9SBaptiste Daroussin 					}
294c99fb5f9SBaptiste Daroussin 					else if(uval <= 0x10FFFF) {
295c99fb5f9SBaptiste Daroussin 						t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
296c99fb5f9SBaptiste Daroussin 						t[1] = 0x80 + ((uval & 0x03F000) >> 12);
297c99fb5f9SBaptiste Daroussin 						t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
298c99fb5f9SBaptiste Daroussin 						t[3] = 0x80 + ((uval & 0x00003F));
299c99fb5f9SBaptiste Daroussin 						t += 4;
300c99fb5f9SBaptiste Daroussin 					}
301c99fb5f9SBaptiste Daroussin 					else {
302c99fb5f9SBaptiste Daroussin 						*t++ = '?';
303c99fb5f9SBaptiste Daroussin 					}
30497bd480fSBaptiste Daroussin 				}
30597bd480fSBaptiste Daroussin 				else {
30697bd480fSBaptiste Daroussin 					*t++ = 'u';
30797bd480fSBaptiste Daroussin 				}
308c99fb5f9SBaptiste Daroussin 				break;
309c99fb5f9SBaptiste Daroussin 			default:
310c99fb5f9SBaptiste Daroussin 				*t++ = *h;
311c99fb5f9SBaptiste Daroussin 				break;
312c99fb5f9SBaptiste Daroussin 			}
313c99fb5f9SBaptiste Daroussin 			h ++;
314c99fb5f9SBaptiste Daroussin 			len --;
315c99fb5f9SBaptiste Daroussin 		}
316c99fb5f9SBaptiste Daroussin 		else {
317c99fb5f9SBaptiste Daroussin 			*t++ = *h++;
318c99fb5f9SBaptiste Daroussin 		}
319c99fb5f9SBaptiste Daroussin 		len --;
320c99fb5f9SBaptiste Daroussin 	}
321c99fb5f9SBaptiste Daroussin 	*t = '\0';
322c99fb5f9SBaptiste Daroussin 
323c99fb5f9SBaptiste Daroussin 	return (t - str);
324c99fb5f9SBaptiste Daroussin }
325c99fb5f9SBaptiste Daroussin 
326*b04a7a0bSBaptiste Daroussin char *
327*b04a7a0bSBaptiste Daroussin ucl_copy_key_trash (const ucl_object_t *obj)
328c99fb5f9SBaptiste Daroussin {
329*b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
330*b04a7a0bSBaptiste Daroussin 
33197bd480fSBaptiste Daroussin 	if (obj == NULL) {
33297bd480fSBaptiste Daroussin 		return NULL;
33397bd480fSBaptiste Daroussin 	}
334c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
335*b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
336*b04a7a0bSBaptiste Daroussin 		deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
337*b04a7a0bSBaptiste Daroussin 		if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) {
338*b04a7a0bSBaptiste Daroussin 			memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
339*b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
340c99fb5f9SBaptiste Daroussin 		}
341*b04a7a0bSBaptiste Daroussin 		deconst->key = obj->trash_stack[UCL_TRASH_KEY];
342*b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_KEY;
343c99fb5f9SBaptiste Daroussin 	}
344c99fb5f9SBaptiste Daroussin 
345c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_KEY];
346c99fb5f9SBaptiste Daroussin }
347c99fb5f9SBaptiste Daroussin 
348*b04a7a0bSBaptiste Daroussin char *
349*b04a7a0bSBaptiste Daroussin ucl_copy_value_trash (const ucl_object_t *obj)
350c99fb5f9SBaptiste Daroussin {
351*b04a7a0bSBaptiste Daroussin 	ucl_object_t *deconst;
352*b04a7a0bSBaptiste Daroussin 
35397bd480fSBaptiste Daroussin 	if (obj == NULL) {
35497bd480fSBaptiste Daroussin 		return NULL;
35597bd480fSBaptiste Daroussin 	}
356c99fb5f9SBaptiste Daroussin 	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
357*b04a7a0bSBaptiste Daroussin 		deconst = __DECONST (ucl_object_t *, obj);
358c99fb5f9SBaptiste Daroussin 		if (obj->type == UCL_STRING) {
359*b04a7a0bSBaptiste Daroussin 
360c99fb5f9SBaptiste Daroussin 			/* Special case for strings */
361*b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
362*b04a7a0bSBaptiste Daroussin 			if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) {
363*b04a7a0bSBaptiste Daroussin 				memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
364*b04a7a0bSBaptiste Daroussin 				deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
365*b04a7a0bSBaptiste Daroussin 				deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
366c99fb5f9SBaptiste Daroussin 			}
367c99fb5f9SBaptiste Daroussin 		}
368c99fb5f9SBaptiste Daroussin 		else {
369c99fb5f9SBaptiste Daroussin 			/* Just emit value in json notation */
370*b04a7a0bSBaptiste Daroussin 			deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
371*b04a7a0bSBaptiste Daroussin 			deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
372c99fb5f9SBaptiste Daroussin 		}
373*b04a7a0bSBaptiste Daroussin 		deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
374c99fb5f9SBaptiste Daroussin 	}
375c99fb5f9SBaptiste Daroussin 	return obj->trash_stack[UCL_TRASH_VALUE];
376c99fb5f9SBaptiste Daroussin }
377c99fb5f9SBaptiste Daroussin 
37836c53d67SBaptiste Daroussin UCL_EXTERN ucl_object_t*
379c99fb5f9SBaptiste Daroussin ucl_parser_get_object (struct ucl_parser *parser)
380c99fb5f9SBaptiste Daroussin {
381c99fb5f9SBaptiste Daroussin 	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
382c99fb5f9SBaptiste Daroussin 		return ucl_object_ref (parser->top_obj);
383c99fb5f9SBaptiste Daroussin 	}
384c99fb5f9SBaptiste Daroussin 
385c99fb5f9SBaptiste Daroussin 	return NULL;
386c99fb5f9SBaptiste Daroussin }
387c99fb5f9SBaptiste Daroussin 
38836c53d67SBaptiste Daroussin UCL_EXTERN void
389c99fb5f9SBaptiste Daroussin ucl_parser_free (struct ucl_parser *parser)
390c99fb5f9SBaptiste Daroussin {
391c99fb5f9SBaptiste Daroussin 	struct ucl_stack *stack, *stmp;
392c99fb5f9SBaptiste Daroussin 	struct ucl_macro *macro, *mtmp;
393c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk, *ctmp;
394c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key, *ktmp;
395c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var, *vtmp;
396c99fb5f9SBaptiste Daroussin 
39797bd480fSBaptiste Daroussin 	if (parser == NULL) {
39897bd480fSBaptiste Daroussin 		return;
39997bd480fSBaptiste Daroussin 	}
40097bd480fSBaptiste Daroussin 
401c99fb5f9SBaptiste Daroussin 	if (parser->top_obj != NULL) {
402c99fb5f9SBaptiste Daroussin 		ucl_object_unref (parser->top_obj);
403c99fb5f9SBaptiste Daroussin 	}
404c99fb5f9SBaptiste Daroussin 
405c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
406c99fb5f9SBaptiste Daroussin 		free (stack);
407c99fb5f9SBaptiste Daroussin 	}
408c99fb5f9SBaptiste Daroussin 	HASH_ITER (hh, parser->macroes, macro, mtmp) {
409c99fb5f9SBaptiste Daroussin 		free (macro->name);
410c99fb5f9SBaptiste Daroussin 		HASH_DEL (parser->macroes, macro);
411c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_macro), macro);
412c99fb5f9SBaptiste Daroussin 	}
413c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
414c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_chunk), chunk);
415c99fb5f9SBaptiste Daroussin 	}
416c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
417c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), key);
418c99fb5f9SBaptiste Daroussin 	}
419c99fb5f9SBaptiste Daroussin 	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
420c99fb5f9SBaptiste Daroussin 		free (var->value);
421c99fb5f9SBaptiste Daroussin 		free (var->var);
422c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_variable), var);
423c99fb5f9SBaptiste Daroussin 	}
424c99fb5f9SBaptiste Daroussin 
425c99fb5f9SBaptiste Daroussin 	if (parser->err != NULL) {
426c99fb5f9SBaptiste Daroussin 		utstring_free(parser->err);
427c99fb5f9SBaptiste Daroussin 	}
428c99fb5f9SBaptiste Daroussin 
429c99fb5f9SBaptiste Daroussin 	UCL_FREE (sizeof (struct ucl_parser), parser);
430c99fb5f9SBaptiste Daroussin }
431c99fb5f9SBaptiste Daroussin 
43236c53d67SBaptiste Daroussin UCL_EXTERN const char *
433c99fb5f9SBaptiste Daroussin ucl_parser_get_error(struct ucl_parser *parser)
434c99fb5f9SBaptiste Daroussin {
43597bd480fSBaptiste Daroussin 	if (parser == NULL) {
43697bd480fSBaptiste Daroussin 		return NULL;
43797bd480fSBaptiste Daroussin 	}
43897bd480fSBaptiste Daroussin 
439c99fb5f9SBaptiste Daroussin 	if (parser->err == NULL)
440c99fb5f9SBaptiste Daroussin 		return NULL;
441c99fb5f9SBaptiste Daroussin 
442c99fb5f9SBaptiste Daroussin 	return utstring_body(parser->err);
443c99fb5f9SBaptiste Daroussin }
444c99fb5f9SBaptiste Daroussin 
44536c53d67SBaptiste Daroussin UCL_EXTERN bool
446c99fb5f9SBaptiste Daroussin ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
447c99fb5f9SBaptiste Daroussin {
448c99fb5f9SBaptiste Daroussin #ifndef HAVE_OPENSSL
449c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures without openssl");
450c99fb5f9SBaptiste Daroussin 	return false;
451c99fb5f9SBaptiste Daroussin #else
452c99fb5f9SBaptiste Daroussin # if (OPENSSL_VERSION_NUMBER < 0x10000000L)
453c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
454c99fb5f9SBaptiste Daroussin 	return EXIT_FAILURE;
455c99fb5f9SBaptiste Daroussin # else
456c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *nkey;
457c99fb5f9SBaptiste Daroussin 	BIO *mem;
458c99fb5f9SBaptiste Daroussin 
459c99fb5f9SBaptiste Daroussin 	mem = BIO_new_mem_buf ((void *)key, len);
460c99fb5f9SBaptiste Daroussin 	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
46197bd480fSBaptiste Daroussin 	if (nkey == NULL) {
46297bd480fSBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot allocate memory for key");
46397bd480fSBaptiste Daroussin 		return false;
46497bd480fSBaptiste Daroussin 	}
465c99fb5f9SBaptiste Daroussin 	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
466c99fb5f9SBaptiste Daroussin 	BIO_free (mem);
467c99fb5f9SBaptiste Daroussin 	if (nkey->key == NULL) {
468c99fb5f9SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
469c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "%s",
470c99fb5f9SBaptiste Daroussin 				ERR_error_string (ERR_get_error (), NULL));
471c99fb5f9SBaptiste Daroussin 		return false;
472c99fb5f9SBaptiste Daroussin 	}
473c99fb5f9SBaptiste Daroussin 	LL_PREPEND (parser->keys, nkey);
474c99fb5f9SBaptiste Daroussin # endif
475c99fb5f9SBaptiste Daroussin #endif
476c99fb5f9SBaptiste Daroussin 	return true;
477c99fb5f9SBaptiste Daroussin }
478c99fb5f9SBaptiste Daroussin 
479c99fb5f9SBaptiste Daroussin #ifdef CURL_FOUND
480c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata {
481c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
482c99fb5f9SBaptiste Daroussin 	size_t buflen;
483c99fb5f9SBaptiste Daroussin };
484c99fb5f9SBaptiste Daroussin 
485c99fb5f9SBaptiste Daroussin static size_t
486c99fb5f9SBaptiste Daroussin ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
487c99fb5f9SBaptiste Daroussin {
488c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata *cbdata = ud;
489c99fb5f9SBaptiste Daroussin 	size_t realsize = size * nmemb;
490c99fb5f9SBaptiste Daroussin 
491c99fb5f9SBaptiste Daroussin 	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
492c99fb5f9SBaptiste Daroussin 	if (cbdata->buf == NULL) {
493c99fb5f9SBaptiste Daroussin 		return 0;
494c99fb5f9SBaptiste Daroussin 	}
495c99fb5f9SBaptiste Daroussin 
496c99fb5f9SBaptiste Daroussin 	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
497c99fb5f9SBaptiste Daroussin 	cbdata->buflen += realsize;
498c99fb5f9SBaptiste Daroussin 	cbdata->buf[cbdata->buflen] = 0;
499c99fb5f9SBaptiste Daroussin 
500c99fb5f9SBaptiste Daroussin 	return realsize;
501c99fb5f9SBaptiste Daroussin }
502c99fb5f9SBaptiste Daroussin #endif
503c99fb5f9SBaptiste Daroussin 
504c99fb5f9SBaptiste Daroussin /**
505c99fb5f9SBaptiste Daroussin  * Fetch a url and save results to the memory buffer
506c99fb5f9SBaptiste Daroussin  * @param url url to fetch
507c99fb5f9SBaptiste Daroussin  * @param len length of url
508c99fb5f9SBaptiste Daroussin  * @param buf target buffer
509c99fb5f9SBaptiste Daroussin  * @param buflen target length
510c99fb5f9SBaptiste Daroussin  * @return
511c99fb5f9SBaptiste Daroussin  */
512c99fb5f9SBaptiste Daroussin static bool
513c99fb5f9SBaptiste Daroussin ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
514c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
515c99fb5f9SBaptiste Daroussin {
516c99fb5f9SBaptiste Daroussin 
517c99fb5f9SBaptiste Daroussin #ifdef HAVE_FETCH_H
518c99fb5f9SBaptiste Daroussin 	struct url *fetch_url;
519c99fb5f9SBaptiste Daroussin 	struct url_stat us;
520c99fb5f9SBaptiste Daroussin 	FILE *in;
521c99fb5f9SBaptiste Daroussin 
522c99fb5f9SBaptiste Daroussin 	fetch_url = fetchParseURL (url);
523c99fb5f9SBaptiste Daroussin 	if (fetch_url == NULL) {
524c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
525c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
526c99fb5f9SBaptiste Daroussin 		return false;
527c99fb5f9SBaptiste Daroussin 	}
528c99fb5f9SBaptiste Daroussin 	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
529c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
530c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot fetch URL %s: %s",
531c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
532c99fb5f9SBaptiste Daroussin 		}
533c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
534c99fb5f9SBaptiste Daroussin 		return false;
535c99fb5f9SBaptiste Daroussin 	}
536c99fb5f9SBaptiste Daroussin 
537c99fb5f9SBaptiste Daroussin 	*buflen = us.size;
538c99fb5f9SBaptiste Daroussin 	*buf = malloc (*buflen);
539c99fb5f9SBaptiste Daroussin 	if (*buf == NULL) {
540c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
541c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
542c99fb5f9SBaptiste Daroussin 		fclose (in);
543c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
544c99fb5f9SBaptiste Daroussin 		return false;
545c99fb5f9SBaptiste Daroussin 	}
546c99fb5f9SBaptiste Daroussin 
547c99fb5f9SBaptiste Daroussin 	if (fread (*buf, *buflen, 1, in) != 1) {
548c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "cannot read URL %s: %s",
549c99fb5f9SBaptiste Daroussin 				url, strerror (errno));
550c99fb5f9SBaptiste Daroussin 		fclose (in);
551c99fb5f9SBaptiste Daroussin 		fetchFreeURL (fetch_url);
552c99fb5f9SBaptiste Daroussin 		return false;
553c99fb5f9SBaptiste Daroussin 	}
554c99fb5f9SBaptiste Daroussin 
555c99fb5f9SBaptiste Daroussin 	fetchFreeURL (fetch_url);
556c99fb5f9SBaptiste Daroussin 	return true;
557c99fb5f9SBaptiste Daroussin #elif defined(CURL_FOUND)
558c99fb5f9SBaptiste Daroussin 	CURL *curl;
559c99fb5f9SBaptiste Daroussin 	int r;
560c99fb5f9SBaptiste Daroussin 	struct ucl_curl_cbdata cbdata;
561c99fb5f9SBaptiste Daroussin 
562c99fb5f9SBaptiste Daroussin 	curl = curl_easy_init ();
563c99fb5f9SBaptiste Daroussin 	if (curl == NULL) {
564c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "CURL interface is broken");
565c99fb5f9SBaptiste Daroussin 		return false;
566c99fb5f9SBaptiste Daroussin 	}
567c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
568c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "invalid URL %s: %s",
569c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
570c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
571c99fb5f9SBaptiste Daroussin 		return false;
572c99fb5f9SBaptiste Daroussin 	}
573c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
574c99fb5f9SBaptiste Daroussin 	cbdata.buf = *buf;
575c99fb5f9SBaptiste Daroussin 	cbdata.buflen = *buflen;
576c99fb5f9SBaptiste Daroussin 	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
577c99fb5f9SBaptiste Daroussin 
578c99fb5f9SBaptiste Daroussin 	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
579c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
580c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "error fetching URL %s: %s",
581c99fb5f9SBaptiste Daroussin 				url, curl_easy_strerror (r));
582c99fb5f9SBaptiste Daroussin 		}
583c99fb5f9SBaptiste Daroussin 		curl_easy_cleanup (curl);
584c99fb5f9SBaptiste Daroussin 		if (cbdata.buf) {
585c99fb5f9SBaptiste Daroussin 			free (cbdata.buf);
586c99fb5f9SBaptiste Daroussin 		}
587c99fb5f9SBaptiste Daroussin 		return false;
588c99fb5f9SBaptiste Daroussin 	}
589c99fb5f9SBaptiste Daroussin 	*buf = cbdata.buf;
590c99fb5f9SBaptiste Daroussin 	*buflen = cbdata.buflen;
591c99fb5f9SBaptiste Daroussin 
592c99fb5f9SBaptiste Daroussin 	return true;
593c99fb5f9SBaptiste Daroussin #else
594c99fb5f9SBaptiste Daroussin 	ucl_create_err (err, "URL support is disabled");
595c99fb5f9SBaptiste Daroussin 	return false;
596c99fb5f9SBaptiste Daroussin #endif
597c99fb5f9SBaptiste Daroussin }
598c99fb5f9SBaptiste Daroussin 
599c99fb5f9SBaptiste Daroussin /**
600c99fb5f9SBaptiste Daroussin  * Fetch a file and save results to the memory buffer
601c99fb5f9SBaptiste Daroussin  * @param filename filename to fetch
602c99fb5f9SBaptiste Daroussin  * @param len length of filename
603c99fb5f9SBaptiste Daroussin  * @param buf target buffer
604c99fb5f9SBaptiste Daroussin  * @param buflen target length
605c99fb5f9SBaptiste Daroussin  * @return
606c99fb5f9SBaptiste Daroussin  */
607c99fb5f9SBaptiste Daroussin static bool
608c99fb5f9SBaptiste Daroussin ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
609c99fb5f9SBaptiste Daroussin 		UT_string **err, bool must_exist)
610c99fb5f9SBaptiste Daroussin {
611c99fb5f9SBaptiste Daroussin 	int fd;
612c99fb5f9SBaptiste Daroussin 	struct stat st;
613c99fb5f9SBaptiste Daroussin 
614c99fb5f9SBaptiste Daroussin 	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
615c99fb5f9SBaptiste Daroussin 		if (must_exist) {
616c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot stat file %s: %s",
617c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
618c99fb5f9SBaptiste Daroussin 		}
619c99fb5f9SBaptiste Daroussin 		return false;
620c99fb5f9SBaptiste Daroussin 	}
621c99fb5f9SBaptiste Daroussin 	if (st.st_size == 0) {
622c99fb5f9SBaptiste Daroussin 		/* Do not map empty files */
623c99fb5f9SBaptiste Daroussin 		*buf = "";
624c99fb5f9SBaptiste Daroussin 		*buflen = 0;
625c99fb5f9SBaptiste Daroussin 	}
626c99fb5f9SBaptiste Daroussin 	else {
627c99fb5f9SBaptiste Daroussin 		if ((fd = open (filename, O_RDONLY)) == -1) {
628c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot open file %s: %s",
629c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
630c99fb5f9SBaptiste Daroussin 			return false;
631c99fb5f9SBaptiste Daroussin 		}
63297bd480fSBaptiste Daroussin 		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
633c99fb5f9SBaptiste Daroussin 			close (fd);
634c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "cannot mmap file %s: %s",
635c99fb5f9SBaptiste Daroussin 					filename, strerror (errno));
636c99fb5f9SBaptiste Daroussin 			return false;
637c99fb5f9SBaptiste Daroussin 		}
638c99fb5f9SBaptiste Daroussin 		*buflen = st.st_size;
639c99fb5f9SBaptiste Daroussin 		close (fd);
640c99fb5f9SBaptiste Daroussin 	}
641c99fb5f9SBaptiste Daroussin 
642c99fb5f9SBaptiste Daroussin 	return true;
643c99fb5f9SBaptiste Daroussin }
644c99fb5f9SBaptiste Daroussin 
645c99fb5f9SBaptiste Daroussin 
646c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
647c99fb5f9SBaptiste Daroussin static inline bool
648c99fb5f9SBaptiste Daroussin ucl_sig_check (const unsigned char *data, size_t datalen,
649c99fb5f9SBaptiste Daroussin 		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
650c99fb5f9SBaptiste Daroussin {
651c99fb5f9SBaptiste Daroussin 	struct ucl_pubkey *key;
652c99fb5f9SBaptiste Daroussin 	char dig[EVP_MAX_MD_SIZE];
653c99fb5f9SBaptiste Daroussin 	unsigned int diglen;
654c99fb5f9SBaptiste Daroussin 	EVP_PKEY_CTX *key_ctx;
655c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX *sign_ctx = NULL;
656c99fb5f9SBaptiste Daroussin 
657c99fb5f9SBaptiste Daroussin 	sign_ctx = EVP_MD_CTX_create ();
658c99fb5f9SBaptiste Daroussin 
659c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->keys, key) {
660c99fb5f9SBaptiste Daroussin 		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
661c99fb5f9SBaptiste Daroussin 		if (key_ctx != NULL) {
662c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
663c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
664c99fb5f9SBaptiste Daroussin 				continue;
665c99fb5f9SBaptiste Daroussin 			}
666c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
667c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
668c99fb5f9SBaptiste Daroussin 				continue;
669c99fb5f9SBaptiste Daroussin 			}
670c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
671c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
672c99fb5f9SBaptiste Daroussin 				continue;
673c99fb5f9SBaptiste Daroussin 			}
674c99fb5f9SBaptiste Daroussin 			EVP_DigestInit (sign_ctx, EVP_sha256 ());
675c99fb5f9SBaptiste Daroussin 			EVP_DigestUpdate (sign_ctx, data, datalen);
676c99fb5f9SBaptiste Daroussin 			EVP_DigestFinal (sign_ctx, dig, &diglen);
677c99fb5f9SBaptiste Daroussin 
678c99fb5f9SBaptiste Daroussin 			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
679c99fb5f9SBaptiste Daroussin 				EVP_MD_CTX_destroy (sign_ctx);
680c99fb5f9SBaptiste Daroussin 				EVP_PKEY_CTX_free (key_ctx);
681c99fb5f9SBaptiste Daroussin 				return true;
682c99fb5f9SBaptiste Daroussin 			}
683c99fb5f9SBaptiste Daroussin 
684c99fb5f9SBaptiste Daroussin 			EVP_PKEY_CTX_free (key_ctx);
685c99fb5f9SBaptiste Daroussin 		}
686c99fb5f9SBaptiste Daroussin 	}
687c99fb5f9SBaptiste Daroussin 
688c99fb5f9SBaptiste Daroussin 	EVP_MD_CTX_destroy (sign_ctx);
689c99fb5f9SBaptiste Daroussin 
690c99fb5f9SBaptiste Daroussin 	return false;
691c99fb5f9SBaptiste Daroussin }
692c99fb5f9SBaptiste Daroussin #endif
693c99fb5f9SBaptiste Daroussin 
694c99fb5f9SBaptiste Daroussin /**
695c99fb5f9SBaptiste Daroussin  * Include an url to configuration
696c99fb5f9SBaptiste Daroussin  * @param data
697c99fb5f9SBaptiste Daroussin  * @param len
698c99fb5f9SBaptiste Daroussin  * @param parser
699c99fb5f9SBaptiste Daroussin  * @param err
700c99fb5f9SBaptiste Daroussin  * @return
701c99fb5f9SBaptiste Daroussin  */
702c99fb5f9SBaptiste Daroussin static bool
703c99fb5f9SBaptiste Daroussin ucl_include_url (const unsigned char *data, size_t len,
704c99fb5f9SBaptiste Daroussin 		struct ucl_parser *parser, bool check_signature, bool must_exist)
705c99fb5f9SBaptiste Daroussin {
706c99fb5f9SBaptiste Daroussin 
707c99fb5f9SBaptiste Daroussin 	bool res;
708c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
709c99fb5f9SBaptiste Daroussin 	size_t buflen = 0;
710c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
711c99fb5f9SBaptiste Daroussin 	char urlbuf[PATH_MAX];
712c99fb5f9SBaptiste Daroussin 	int prev_state;
713c99fb5f9SBaptiste Daroussin 
714c99fb5f9SBaptiste Daroussin 	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
715c99fb5f9SBaptiste Daroussin 
716c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) {
717c99fb5f9SBaptiste Daroussin 		return (!must_exist || false);
718c99fb5f9SBaptiste Daroussin 	}
719c99fb5f9SBaptiste Daroussin 
720c99fb5f9SBaptiste Daroussin 	if (check_signature) {
721c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
722c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
723c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
724c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
725c99fb5f9SBaptiste Daroussin 		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
726c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
727c99fb5f9SBaptiste Daroussin 			return false;
728c99fb5f9SBaptiste Daroussin 		}
729c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
730c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify url %s: %s",
731c99fb5f9SBaptiste Daroussin 							urlbuf,
732c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
733c99fb5f9SBaptiste Daroussin 			if (siglen > 0) {
73497bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
735c99fb5f9SBaptiste Daroussin 			}
736c99fb5f9SBaptiste Daroussin 			return false;
737c99fb5f9SBaptiste Daroussin 		}
738c99fb5f9SBaptiste Daroussin 		if (siglen > 0) {
73997bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
740c99fb5f9SBaptiste Daroussin 		}
741c99fb5f9SBaptiste Daroussin #endif
742c99fb5f9SBaptiste Daroussin 	}
743c99fb5f9SBaptiste Daroussin 
744c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
745c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
746c99fb5f9SBaptiste Daroussin 
747c99fb5f9SBaptiste Daroussin 	res = ucl_parser_add_chunk (parser, buf, buflen);
748c99fb5f9SBaptiste Daroussin 	if (res == true) {
749c99fb5f9SBaptiste Daroussin 		/* Remove chunk from the stack */
750c99fb5f9SBaptiste Daroussin 		chunk = parser->chunks;
751c99fb5f9SBaptiste Daroussin 		if (chunk != NULL) {
752c99fb5f9SBaptiste Daroussin 			parser->chunks = chunk->next;
753c99fb5f9SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_chunk), chunk);
754c99fb5f9SBaptiste Daroussin 		}
755c99fb5f9SBaptiste Daroussin 	}
756c99fb5f9SBaptiste Daroussin 
757c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
758c99fb5f9SBaptiste Daroussin 	free (buf);
759c99fb5f9SBaptiste Daroussin 
760c99fb5f9SBaptiste Daroussin 	return res;
761c99fb5f9SBaptiste Daroussin }
762c99fb5f9SBaptiste Daroussin 
763c99fb5f9SBaptiste Daroussin /**
764c99fb5f9SBaptiste Daroussin  * Include a file to configuration
765c99fb5f9SBaptiste Daroussin  * @param data
766c99fb5f9SBaptiste Daroussin  * @param len
767c99fb5f9SBaptiste Daroussin  * @param parser
768c99fb5f9SBaptiste Daroussin  * @param err
769c99fb5f9SBaptiste Daroussin  * @return
770c99fb5f9SBaptiste Daroussin  */
771c99fb5f9SBaptiste Daroussin static bool
772c99fb5f9SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len,
773c99fb5f9SBaptiste Daroussin 		struct ucl_parser *parser, bool check_signature, bool must_exist)
774c99fb5f9SBaptiste Daroussin {
775c99fb5f9SBaptiste Daroussin 	bool res;
776c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
777c99fb5f9SBaptiste Daroussin 	unsigned char *buf = NULL;
778c99fb5f9SBaptiste Daroussin 	size_t buflen;
779c99fb5f9SBaptiste Daroussin 	char filebuf[PATH_MAX], realbuf[PATH_MAX];
780c99fb5f9SBaptiste Daroussin 	int prev_state;
781c99fb5f9SBaptiste Daroussin 
782c99fb5f9SBaptiste Daroussin 	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
78397bd480fSBaptiste Daroussin 	if (ucl_realpath (filebuf, realbuf) == NULL) {
784c99fb5f9SBaptiste Daroussin 		if (!must_exist) {
785c99fb5f9SBaptiste Daroussin 			return true;
786c99fb5f9SBaptiste Daroussin 		}
787c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
788c99fb5f9SBaptiste Daroussin 									filebuf,
789c99fb5f9SBaptiste Daroussin 									strerror (errno));
790c99fb5f9SBaptiste Daroussin 		return false;
791c99fb5f9SBaptiste Daroussin 	}
792c99fb5f9SBaptiste Daroussin 
793c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
794c99fb5f9SBaptiste Daroussin 		return (!must_exist || false);
795c99fb5f9SBaptiste Daroussin 	}
796c99fb5f9SBaptiste Daroussin 
797c99fb5f9SBaptiste Daroussin 	if (check_signature) {
798c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
799c99fb5f9SBaptiste Daroussin 		unsigned char *sigbuf = NULL;
800c99fb5f9SBaptiste Daroussin 		size_t siglen = 0;
801c99fb5f9SBaptiste Daroussin 		/* We need to check signature first */
802c99fb5f9SBaptiste Daroussin 		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
803c99fb5f9SBaptiste Daroussin 		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
804c99fb5f9SBaptiste Daroussin 			return false;
805c99fb5f9SBaptiste Daroussin 		}
806c99fb5f9SBaptiste Daroussin 		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
807c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot verify file %s: %s",
808c99fb5f9SBaptiste Daroussin 							filebuf,
809c99fb5f9SBaptiste Daroussin 							ERR_error_string (ERR_get_error (), NULL));
810c99fb5f9SBaptiste Daroussin 			if (siglen > 0) {
81197bd480fSBaptiste Daroussin 				ucl_munmap (sigbuf, siglen);
812c99fb5f9SBaptiste Daroussin 			}
813c99fb5f9SBaptiste Daroussin 			return false;
814c99fb5f9SBaptiste Daroussin 		}
815c99fb5f9SBaptiste Daroussin 		if (siglen > 0) {
81697bd480fSBaptiste Daroussin 			ucl_munmap (sigbuf, siglen);
817c99fb5f9SBaptiste Daroussin 		}
818c99fb5f9SBaptiste Daroussin #endif
819c99fb5f9SBaptiste Daroussin 	}
820c99fb5f9SBaptiste Daroussin 
821c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
822c99fb5f9SBaptiste Daroussin 
823c99fb5f9SBaptiste Daroussin 	prev_state = parser->state;
824c99fb5f9SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
825c99fb5f9SBaptiste Daroussin 
826c99fb5f9SBaptiste Daroussin 	res = ucl_parser_add_chunk (parser, buf, buflen);
827c99fb5f9SBaptiste Daroussin 	if (res == true) {
828c99fb5f9SBaptiste Daroussin 		/* Remove chunk from the stack */
829c99fb5f9SBaptiste Daroussin 		chunk = parser->chunks;
830c99fb5f9SBaptiste Daroussin 		if (chunk != NULL) {
831c99fb5f9SBaptiste Daroussin 			parser->chunks = chunk->next;
832c99fb5f9SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_chunk), chunk);
833c99fb5f9SBaptiste Daroussin 		}
834c99fb5f9SBaptiste Daroussin 	}
835c99fb5f9SBaptiste Daroussin 
836c99fb5f9SBaptiste Daroussin 	parser->state = prev_state;
837c99fb5f9SBaptiste Daroussin 
838c99fb5f9SBaptiste Daroussin 	if (buflen > 0) {
83997bd480fSBaptiste Daroussin 		ucl_munmap (buf, buflen);
840c99fb5f9SBaptiste Daroussin 	}
841c99fb5f9SBaptiste Daroussin 
842c99fb5f9SBaptiste Daroussin 	return res;
843c99fb5f9SBaptiste Daroussin }
844c99fb5f9SBaptiste Daroussin 
845c99fb5f9SBaptiste Daroussin /**
846c99fb5f9SBaptiste Daroussin  * Handle include macro
847c99fb5f9SBaptiste Daroussin  * @param data include data
848c99fb5f9SBaptiste Daroussin  * @param len length of data
849c99fb5f9SBaptiste Daroussin  * @param ud user data
850c99fb5f9SBaptiste Daroussin  * @param err error ptr
851c99fb5f9SBaptiste Daroussin  * @return
852c99fb5f9SBaptiste Daroussin  */
85336c53d67SBaptiste Daroussin UCL_EXTERN bool
854c99fb5f9SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len, void* ud)
855c99fb5f9SBaptiste Daroussin {
856c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
857c99fb5f9SBaptiste Daroussin 
858c99fb5f9SBaptiste Daroussin 	if (*data == '/' || *data == '.') {
859c99fb5f9SBaptiste Daroussin 		/* Try to load a file */
860c99fb5f9SBaptiste Daroussin 		return ucl_include_file (data, len, parser, false, true);
861c99fb5f9SBaptiste Daroussin 	}
862c99fb5f9SBaptiste Daroussin 
863c99fb5f9SBaptiste Daroussin 	return ucl_include_url (data, len, parser, false, true);
864c99fb5f9SBaptiste Daroussin }
865c99fb5f9SBaptiste Daroussin 
866c99fb5f9SBaptiste Daroussin /**
867c99fb5f9SBaptiste Daroussin  * Handle includes macro
868c99fb5f9SBaptiste Daroussin  * @param data include data
869c99fb5f9SBaptiste Daroussin  * @param len length of data
870c99fb5f9SBaptiste Daroussin  * @param ud user data
871c99fb5f9SBaptiste Daroussin  * @param err error ptr
872c99fb5f9SBaptiste Daroussin  * @return
873c99fb5f9SBaptiste Daroussin  */
87436c53d67SBaptiste Daroussin UCL_EXTERN bool
875c99fb5f9SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
876c99fb5f9SBaptiste Daroussin {
877c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
878c99fb5f9SBaptiste Daroussin 
879c99fb5f9SBaptiste Daroussin 	if (*data == '/' || *data == '.') {
880c99fb5f9SBaptiste Daroussin 		/* Try to load a file */
881c99fb5f9SBaptiste Daroussin 		return ucl_include_file (data, len, parser, true, true);
882c99fb5f9SBaptiste Daroussin 	}
883c99fb5f9SBaptiste Daroussin 
884c99fb5f9SBaptiste Daroussin 	return ucl_include_url (data, len, parser, true, true);
885c99fb5f9SBaptiste Daroussin }
886c99fb5f9SBaptiste Daroussin 
887c99fb5f9SBaptiste Daroussin 
88836c53d67SBaptiste Daroussin UCL_EXTERN bool
889c99fb5f9SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
890c99fb5f9SBaptiste Daroussin {
891c99fb5f9SBaptiste Daroussin 	struct ucl_parser *parser = ud;
892c99fb5f9SBaptiste Daroussin 
893c99fb5f9SBaptiste Daroussin 	if (*data == '/' || *data == '.') {
894c99fb5f9SBaptiste Daroussin 		/* Try to load a file */
895c99fb5f9SBaptiste Daroussin 		return ucl_include_file (data, len, parser, false, false);
896c99fb5f9SBaptiste Daroussin 	}
897c99fb5f9SBaptiste Daroussin 
898c99fb5f9SBaptiste Daroussin 	return ucl_include_url (data, len, parser, false, false);
899c99fb5f9SBaptiste Daroussin }
900c99fb5f9SBaptiste Daroussin 
90136c53d67SBaptiste Daroussin UCL_EXTERN bool
902c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
903c99fb5f9SBaptiste Daroussin {
904c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX], *curdir;
905c99fb5f9SBaptiste Daroussin 
906c99fb5f9SBaptiste Daroussin 	if (filename != NULL) {
907c99fb5f9SBaptiste Daroussin 		if (need_expand) {
90897bd480fSBaptiste Daroussin 			if (ucl_realpath (filename, realbuf) == NULL) {
909c99fb5f9SBaptiste Daroussin 				return false;
910c99fb5f9SBaptiste Daroussin 			}
911c99fb5f9SBaptiste Daroussin 		}
912c99fb5f9SBaptiste Daroussin 		else {
913c99fb5f9SBaptiste Daroussin 			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
914c99fb5f9SBaptiste Daroussin 		}
915c99fb5f9SBaptiste Daroussin 
916c99fb5f9SBaptiste Daroussin 		/* Define variables */
917c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", realbuf);
918c99fb5f9SBaptiste Daroussin 		curdir = dirname (realbuf);
919c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
920c99fb5f9SBaptiste Daroussin 	}
921c99fb5f9SBaptiste Daroussin 	else {
922c99fb5f9SBaptiste Daroussin 		/* Set everything from the current dir */
923c99fb5f9SBaptiste Daroussin 		curdir = getcwd (realbuf, sizeof (realbuf));
924c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "FILENAME", "undef");
925c99fb5f9SBaptiste Daroussin 		ucl_parser_register_variable (parser, "CURDIR", curdir);
926c99fb5f9SBaptiste Daroussin 	}
927c99fb5f9SBaptiste Daroussin 
928c99fb5f9SBaptiste Daroussin 	return true;
929c99fb5f9SBaptiste Daroussin }
930c99fb5f9SBaptiste Daroussin 
93136c53d67SBaptiste Daroussin UCL_EXTERN bool
932c99fb5f9SBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
933c99fb5f9SBaptiste Daroussin {
934c99fb5f9SBaptiste Daroussin 	unsigned char *buf;
935c99fb5f9SBaptiste Daroussin 	size_t len;
936c99fb5f9SBaptiste Daroussin 	bool ret;
937c99fb5f9SBaptiste Daroussin 	char realbuf[PATH_MAX];
938c99fb5f9SBaptiste Daroussin 
93997bd480fSBaptiste Daroussin 	if (ucl_realpath (filename, realbuf) == NULL) {
940c99fb5f9SBaptiste Daroussin 		ucl_create_err (&parser->err, "cannot open file %s: %s",
941c99fb5f9SBaptiste Daroussin 				filename,
942c99fb5f9SBaptiste Daroussin 				strerror (errno));
943c99fb5f9SBaptiste Daroussin 		return false;
944c99fb5f9SBaptiste Daroussin 	}
945c99fb5f9SBaptiste Daroussin 
946c99fb5f9SBaptiste Daroussin 	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
947c99fb5f9SBaptiste Daroussin 		return false;
948c99fb5f9SBaptiste Daroussin 	}
949c99fb5f9SBaptiste Daroussin 
950c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (parser, realbuf, false);
951c99fb5f9SBaptiste Daroussin 	ret = ucl_parser_add_chunk (parser, buf, len);
952c99fb5f9SBaptiste Daroussin 
953c99fb5f9SBaptiste Daroussin 	if (len > 0) {
95497bd480fSBaptiste Daroussin 		ucl_munmap (buf, len);
955c99fb5f9SBaptiste Daroussin 	}
956c99fb5f9SBaptiste Daroussin 
957c99fb5f9SBaptiste Daroussin 	return ret;
958c99fb5f9SBaptiste Daroussin }
959c99fb5f9SBaptiste Daroussin 
960c99fb5f9SBaptiste Daroussin size_t
961c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz)
962c99fb5f9SBaptiste Daroussin {
963c99fb5f9SBaptiste Daroussin 	char *d = dst;
964c99fb5f9SBaptiste Daroussin 	const char *s = src;
965c99fb5f9SBaptiste Daroussin 	size_t n = siz;
966c99fb5f9SBaptiste Daroussin 
967c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
968c99fb5f9SBaptiste Daroussin 	if (n != 0) {
969c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
970c99fb5f9SBaptiste Daroussin 			if ((*d++ = *s++) == '\0') {
971c99fb5f9SBaptiste Daroussin 				break;
972c99fb5f9SBaptiste Daroussin 			}
973c99fb5f9SBaptiste Daroussin 		}
974c99fb5f9SBaptiste Daroussin 	}
975c99fb5f9SBaptiste Daroussin 
976c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
977c99fb5f9SBaptiste Daroussin 		*d = '\0';
978c99fb5f9SBaptiste Daroussin 	}
979c99fb5f9SBaptiste Daroussin 
980c99fb5f9SBaptiste Daroussin 	return (s - src - 1);    /* count does not include NUL */
981c99fb5f9SBaptiste Daroussin }
982c99fb5f9SBaptiste Daroussin 
983c99fb5f9SBaptiste Daroussin size_t
984c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
985c99fb5f9SBaptiste Daroussin {
986c99fb5f9SBaptiste Daroussin 	memcpy (dst, src, siz - 1);
987c99fb5f9SBaptiste Daroussin 	dst[siz - 1] = '\0';
988c99fb5f9SBaptiste Daroussin 
989c99fb5f9SBaptiste Daroussin 	return siz - 1;
990c99fb5f9SBaptiste Daroussin }
991c99fb5f9SBaptiste Daroussin 
992c99fb5f9SBaptiste Daroussin size_t
993c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
994c99fb5f9SBaptiste Daroussin {
995c99fb5f9SBaptiste Daroussin 	char *d = dst;
996c99fb5f9SBaptiste Daroussin 	const char *s = src;
997c99fb5f9SBaptiste Daroussin 	size_t n = siz;
998c99fb5f9SBaptiste Daroussin 
999c99fb5f9SBaptiste Daroussin 	/* Copy as many bytes as will fit */
1000c99fb5f9SBaptiste Daroussin 	if (n != 0) {
1001c99fb5f9SBaptiste Daroussin 		while (--n != 0) {
1002c99fb5f9SBaptiste Daroussin 			if ((*d++ = tolower (*s++)) == '\0') {
1003c99fb5f9SBaptiste Daroussin 				break;
1004c99fb5f9SBaptiste Daroussin 			}
1005c99fb5f9SBaptiste Daroussin 		}
1006c99fb5f9SBaptiste Daroussin 	}
1007c99fb5f9SBaptiste Daroussin 
1008c99fb5f9SBaptiste Daroussin 	if (n == 0 && siz != 0) {
1009c99fb5f9SBaptiste Daroussin 		*d = '\0';
1010c99fb5f9SBaptiste Daroussin 	}
1011c99fb5f9SBaptiste Daroussin 
1012c99fb5f9SBaptiste Daroussin 	return (s - src);    /* count does not include NUL */
1013c99fb5f9SBaptiste Daroussin }
1014c99fb5f9SBaptiste Daroussin 
1015c99fb5f9SBaptiste Daroussin ucl_object_t *
1016c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
1017c99fb5f9SBaptiste Daroussin {
1018c99fb5f9SBaptiste Daroussin 	ucl_object_t *obj;
1019c99fb5f9SBaptiste Daroussin 	const char *start, *end, *p, *pos;
1020c99fb5f9SBaptiste Daroussin 	char *dst, *d;
1021c99fb5f9SBaptiste Daroussin 	size_t escaped_len;
1022c99fb5f9SBaptiste Daroussin 
1023c99fb5f9SBaptiste Daroussin 	if (str == NULL) {
1024c99fb5f9SBaptiste Daroussin 		return NULL;
1025c99fb5f9SBaptiste Daroussin 	}
1026c99fb5f9SBaptiste Daroussin 
1027c99fb5f9SBaptiste Daroussin 	obj = ucl_object_new ();
1028c99fb5f9SBaptiste Daroussin 	if (obj) {
1029c99fb5f9SBaptiste Daroussin 		if (len == 0) {
1030c99fb5f9SBaptiste Daroussin 			len = strlen (str);
1031c99fb5f9SBaptiste Daroussin 		}
1032c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_TRIM) {
1033c99fb5f9SBaptiste Daroussin 			/* Skip leading spaces */
1034c99fb5f9SBaptiste Daroussin 			for (start = str; (size_t)(start - str) < len; start ++) {
1035c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1036c99fb5f9SBaptiste Daroussin 					break;
1037c99fb5f9SBaptiste Daroussin 				}
1038c99fb5f9SBaptiste Daroussin 			}
1039c99fb5f9SBaptiste Daroussin 			/* Skip trailing spaces */
1040c99fb5f9SBaptiste Daroussin 			for (end = str + len - 1; end > start; end --) {
1041c99fb5f9SBaptiste Daroussin 				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1042c99fb5f9SBaptiste Daroussin 					break;
1043c99fb5f9SBaptiste Daroussin 				}
1044c99fb5f9SBaptiste Daroussin 			}
1045c99fb5f9SBaptiste Daroussin 			end ++;
1046c99fb5f9SBaptiste Daroussin 		}
1047c99fb5f9SBaptiste Daroussin 		else {
1048c99fb5f9SBaptiste Daroussin 			start = str;
1049c99fb5f9SBaptiste Daroussin 			end = str + len;
1050c99fb5f9SBaptiste Daroussin 		}
1051c99fb5f9SBaptiste Daroussin 
1052c99fb5f9SBaptiste Daroussin 		obj->type = UCL_STRING;
1053c99fb5f9SBaptiste Daroussin 		if (flags & UCL_STRING_ESCAPE) {
1054c99fb5f9SBaptiste Daroussin 			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
1055c99fb5f9SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1056c99fb5f9SBaptiste Daroussin 					escaped_len ++;
1057c99fb5f9SBaptiste Daroussin 				}
1058c99fb5f9SBaptiste Daroussin 			}
1059c99fb5f9SBaptiste Daroussin 			dst = malloc (escaped_len + 1);
1060c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
1061c99fb5f9SBaptiste Daroussin 				for (p = start, d = dst; p < end; p ++, d ++) {
1062c99fb5f9SBaptiste Daroussin 					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1063c99fb5f9SBaptiste Daroussin 						switch (*p) {
1064c99fb5f9SBaptiste Daroussin 						case '\n':
1065c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1066c99fb5f9SBaptiste Daroussin 							*d = 'n';
1067c99fb5f9SBaptiste Daroussin 							break;
1068c99fb5f9SBaptiste Daroussin 						case '\r':
1069c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1070c99fb5f9SBaptiste Daroussin 							*d = 'r';
1071c99fb5f9SBaptiste Daroussin 							break;
1072c99fb5f9SBaptiste Daroussin 						case '\b':
1073c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1074c99fb5f9SBaptiste Daroussin 							*d = 'b';
1075c99fb5f9SBaptiste Daroussin 							break;
1076c99fb5f9SBaptiste Daroussin 						case '\t':
1077c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1078c99fb5f9SBaptiste Daroussin 							*d = 't';
1079c99fb5f9SBaptiste Daroussin 							break;
1080c99fb5f9SBaptiste Daroussin 						case '\f':
1081c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1082c99fb5f9SBaptiste Daroussin 							*d = 'f';
1083c99fb5f9SBaptiste Daroussin 							break;
1084c99fb5f9SBaptiste Daroussin 						case '\\':
1085c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1086c99fb5f9SBaptiste Daroussin 							*d = '\\';
1087c99fb5f9SBaptiste Daroussin 							break;
1088c99fb5f9SBaptiste Daroussin 						case '"':
1089c99fb5f9SBaptiste Daroussin 							*d++ = '\\';
1090c99fb5f9SBaptiste Daroussin 							*d = '"';
1091c99fb5f9SBaptiste Daroussin 							break;
1092c99fb5f9SBaptiste Daroussin 						}
1093c99fb5f9SBaptiste Daroussin 					}
1094c99fb5f9SBaptiste Daroussin 					else {
1095c99fb5f9SBaptiste Daroussin 						*d = *p;
1096c99fb5f9SBaptiste Daroussin 					}
1097c99fb5f9SBaptiste Daroussin 				}
1098c99fb5f9SBaptiste Daroussin 				*d = '\0';
1099c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
1100c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1101c99fb5f9SBaptiste Daroussin 				obj->len = escaped_len;
1102c99fb5f9SBaptiste Daroussin 			}
1103c99fb5f9SBaptiste Daroussin 		}
1104c99fb5f9SBaptiste Daroussin 		else {
1105c99fb5f9SBaptiste Daroussin 			dst = malloc (end - start + 1);
1106c99fb5f9SBaptiste Daroussin 			if (dst != NULL) {
1107c99fb5f9SBaptiste Daroussin 				ucl_strlcpy_unsafe (dst, start, end - start + 1);
1108c99fb5f9SBaptiste Daroussin 				obj->value.sv = dst;
1109c99fb5f9SBaptiste Daroussin 				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1110c99fb5f9SBaptiste Daroussin 				obj->len = end - start;
1111c99fb5f9SBaptiste Daroussin 			}
1112c99fb5f9SBaptiste Daroussin 		}
1113c99fb5f9SBaptiste Daroussin 		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
1114c99fb5f9SBaptiste Daroussin 			/* Parse what we have */
1115c99fb5f9SBaptiste Daroussin 			if (flags & UCL_STRING_PARSE_BOOLEAN) {
1116c99fb5f9SBaptiste Daroussin 				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
1117c99fb5f9SBaptiste Daroussin 					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1118c99fb5f9SBaptiste Daroussin 							flags & UCL_STRING_PARSE_DOUBLE,
111997bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_BYTES,
112097bd480fSBaptiste Daroussin 							flags & UCL_STRING_PARSE_TIME);
1121c99fb5f9SBaptiste Daroussin 				}
1122c99fb5f9SBaptiste Daroussin 			}
1123c99fb5f9SBaptiste Daroussin 			else {
1124c99fb5f9SBaptiste Daroussin 				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1125c99fb5f9SBaptiste Daroussin 						flags & UCL_STRING_PARSE_DOUBLE,
112697bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_BYTES,
112797bd480fSBaptiste Daroussin 						flags & UCL_STRING_PARSE_TIME);
1128c99fb5f9SBaptiste Daroussin 			}
1129c99fb5f9SBaptiste Daroussin 		}
1130c99fb5f9SBaptiste Daroussin 	}
1131c99fb5f9SBaptiste Daroussin 
1132c99fb5f9SBaptiste Daroussin 	return obj;
1133c99fb5f9SBaptiste Daroussin }
1134c99fb5f9SBaptiste Daroussin 
1135*b04a7a0bSBaptiste Daroussin static bool
1136c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
1137c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
1138c99fb5f9SBaptiste Daroussin {
1139*b04a7a0bSBaptiste Daroussin 	ucl_object_t *found, *tmp;
1140*b04a7a0bSBaptiste Daroussin 	const ucl_object_t *cur;
1141c99fb5f9SBaptiste Daroussin 	ucl_object_iter_t it = NULL;
1142c99fb5f9SBaptiste Daroussin 	const char *p;
1143*b04a7a0bSBaptiste Daroussin 	int ret = true;
1144c99fb5f9SBaptiste Daroussin 
1145c99fb5f9SBaptiste Daroussin 	if (elt == NULL || key == NULL) {
1146*b04a7a0bSBaptiste Daroussin 		return false;
1147c99fb5f9SBaptiste Daroussin 	}
1148c99fb5f9SBaptiste Daroussin 
1149c99fb5f9SBaptiste Daroussin 	if (top == NULL) {
1150*b04a7a0bSBaptiste Daroussin 		return false;
1151c99fb5f9SBaptiste Daroussin 	}
1152c99fb5f9SBaptiste Daroussin 
1153c99fb5f9SBaptiste Daroussin 	if (top->type != UCL_OBJECT) {
1154c99fb5f9SBaptiste Daroussin 		/* It is possible to convert NULL type to an object */
1155c99fb5f9SBaptiste Daroussin 		if (top->type == UCL_NULL) {
1156c99fb5f9SBaptiste Daroussin 			top->type = UCL_OBJECT;
1157c99fb5f9SBaptiste Daroussin 		}
1158c99fb5f9SBaptiste Daroussin 		else {
1159c99fb5f9SBaptiste Daroussin 			/* Refuse converting of other object types */
1160*b04a7a0bSBaptiste Daroussin 			return false;
1161c99fb5f9SBaptiste Daroussin 		}
1162c99fb5f9SBaptiste Daroussin 	}
1163c99fb5f9SBaptiste Daroussin 
1164c99fb5f9SBaptiste Daroussin 	if (top->value.ov == NULL) {
1165c99fb5f9SBaptiste Daroussin 		top->value.ov = ucl_hash_create ();
1166c99fb5f9SBaptiste Daroussin 	}
1167c99fb5f9SBaptiste Daroussin 
1168c99fb5f9SBaptiste Daroussin 	if (keylen == 0) {
1169c99fb5f9SBaptiste Daroussin 		keylen = strlen (key);
1170c99fb5f9SBaptiste Daroussin 	}
1171c99fb5f9SBaptiste Daroussin 
1172c99fb5f9SBaptiste Daroussin 	for (p = key; p < key + keylen; p ++) {
1173c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
1174c99fb5f9SBaptiste Daroussin 			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1175c99fb5f9SBaptiste Daroussin 			break;
1176c99fb5f9SBaptiste Daroussin 		}
1177c99fb5f9SBaptiste Daroussin 	}
1178c99fb5f9SBaptiste Daroussin 
1179c99fb5f9SBaptiste Daroussin 	elt->key = key;
1180c99fb5f9SBaptiste Daroussin 	elt->keylen = keylen;
1181c99fb5f9SBaptiste Daroussin 
1182c99fb5f9SBaptiste Daroussin 	if (copy_key) {
1183c99fb5f9SBaptiste Daroussin 		ucl_copy_key_trash (elt);
1184c99fb5f9SBaptiste Daroussin 	}
1185c99fb5f9SBaptiste Daroussin 
1186*b04a7a0bSBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
1187c99fb5f9SBaptiste Daroussin 
1188c99fb5f9SBaptiste Daroussin 	if (!found) {
1189c99fb5f9SBaptiste Daroussin 		top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1190c99fb5f9SBaptiste Daroussin 		DL_APPEND (found, elt);
119197bd480fSBaptiste Daroussin 		top->len ++;
1192*b04a7a0bSBaptiste Daroussin 		if (replace) {
1193*b04a7a0bSBaptiste Daroussin 			ret = false;
1194*b04a7a0bSBaptiste Daroussin 		}
1195c99fb5f9SBaptiste Daroussin 	}
1196c99fb5f9SBaptiste Daroussin 	else {
1197c99fb5f9SBaptiste Daroussin 		if (replace) {
1198c99fb5f9SBaptiste Daroussin 			ucl_hash_delete (top->value.ov, found);
1199c99fb5f9SBaptiste Daroussin 			ucl_object_unref (found);
1200c99fb5f9SBaptiste Daroussin 			top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1201c99fb5f9SBaptiste Daroussin 			found = NULL;
1202c99fb5f9SBaptiste Daroussin 			DL_APPEND (found, elt);
1203c99fb5f9SBaptiste Daroussin 		}
1204c99fb5f9SBaptiste Daroussin 		else if (merge) {
1205c99fb5f9SBaptiste Daroussin 			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
1206c99fb5f9SBaptiste Daroussin 				/* Insert old elt to new one */
1207*b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (elt, found, found->key,
1208*b04a7a0bSBaptiste Daroussin 						found->keylen, copy_key, false, false);
1209c99fb5f9SBaptiste Daroussin 				ucl_hash_delete (top->value.ov, found);
1210c99fb5f9SBaptiste Daroussin 				top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1211c99fb5f9SBaptiste Daroussin 			}
1212c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
1213c99fb5f9SBaptiste Daroussin 				/* Insert new to old */
1214*b04a7a0bSBaptiste Daroussin 				ucl_object_insert_key_common (found, elt, elt->key,
1215*b04a7a0bSBaptiste Daroussin 						elt->keylen, copy_key, false, false);
1216c99fb5f9SBaptiste Daroussin 			}
1217c99fb5f9SBaptiste Daroussin 			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
1218c99fb5f9SBaptiste Daroussin 				/* Mix two hashes */
1219c99fb5f9SBaptiste Daroussin 				while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
1220*b04a7a0bSBaptiste Daroussin 					tmp = ucl_object_ref (cur);
1221*b04a7a0bSBaptiste Daroussin 					ucl_object_insert_key_common (found, tmp, cur->key,
1222*b04a7a0bSBaptiste Daroussin 							cur->keylen, copy_key, false, false);
1223c99fb5f9SBaptiste Daroussin 				}
1224c99fb5f9SBaptiste Daroussin 				ucl_object_unref (elt);
1225c99fb5f9SBaptiste Daroussin 			}
1226c99fb5f9SBaptiste Daroussin 			else {
1227c99fb5f9SBaptiste Daroussin 				/* Just make a list of scalars */
1228c99fb5f9SBaptiste Daroussin 				DL_APPEND (found, elt);
1229c99fb5f9SBaptiste Daroussin 			}
1230c99fb5f9SBaptiste Daroussin 		}
1231c99fb5f9SBaptiste Daroussin 		else {
1232c99fb5f9SBaptiste Daroussin 			DL_APPEND (found, elt);
1233c99fb5f9SBaptiste Daroussin 		}
1234c99fb5f9SBaptiste Daroussin 	}
1235c99fb5f9SBaptiste Daroussin 
1236*b04a7a0bSBaptiste Daroussin 	return ret;
1237c99fb5f9SBaptiste Daroussin }
1238c99fb5f9SBaptiste Daroussin 
123936c53d67SBaptiste Daroussin bool
124036c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen)
124136c53d67SBaptiste Daroussin {
124236c53d67SBaptiste Daroussin 	ucl_object_t *found;
124336c53d67SBaptiste Daroussin 
124497bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
124597bd480fSBaptiste Daroussin 		return false;
124697bd480fSBaptiste Daroussin 	}
124797bd480fSBaptiste Daroussin 
1248*b04a7a0bSBaptiste Daroussin 	found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen));
124936c53d67SBaptiste Daroussin 
125097bd480fSBaptiste Daroussin 	if (found == NULL) {
125136c53d67SBaptiste Daroussin 		return false;
125297bd480fSBaptiste Daroussin 	}
125336c53d67SBaptiste Daroussin 
125436c53d67SBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
125536c53d67SBaptiste Daroussin 	ucl_object_unref (found);
125636c53d67SBaptiste Daroussin 	top->len --;
125736c53d67SBaptiste Daroussin 
125836c53d67SBaptiste Daroussin 	return true;
125936c53d67SBaptiste Daroussin }
126036c53d67SBaptiste Daroussin 
126136c53d67SBaptiste Daroussin bool
126236c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key)
126336c53d67SBaptiste Daroussin {
1264*b04a7a0bSBaptiste Daroussin 	return ucl_object_delete_keyl (top, key, strlen(key));
126536c53d67SBaptiste Daroussin }
126636c53d67SBaptiste Daroussin 
1267c99fb5f9SBaptiste Daroussin ucl_object_t*
126897bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
126997bd480fSBaptiste Daroussin {
1270*b04a7a0bSBaptiste Daroussin 	const ucl_object_t *found;
127197bd480fSBaptiste Daroussin 
127297bd480fSBaptiste Daroussin 	if (top == NULL || key == NULL) {
127397bd480fSBaptiste Daroussin 		return false;
127497bd480fSBaptiste Daroussin 	}
127597bd480fSBaptiste Daroussin 	found = ucl_object_find_keyl (top, key, keylen);
127697bd480fSBaptiste Daroussin 
127797bd480fSBaptiste Daroussin 	if (found == NULL) {
127897bd480fSBaptiste Daroussin 		return NULL;
127997bd480fSBaptiste Daroussin 	}
128097bd480fSBaptiste Daroussin 	ucl_hash_delete (top->value.ov, found);
128197bd480fSBaptiste Daroussin 	top->len --;
128297bd480fSBaptiste Daroussin 
1283*b04a7a0bSBaptiste Daroussin 	return __DECONST (ucl_object_t *, found);
128497bd480fSBaptiste Daroussin }
128597bd480fSBaptiste Daroussin 
128697bd480fSBaptiste Daroussin ucl_object_t*
128797bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key)
128897bd480fSBaptiste Daroussin {
1289*b04a7a0bSBaptiste Daroussin 	return ucl_object_pop_keyl (top, key, strlen(key));
129097bd480fSBaptiste Daroussin }
129197bd480fSBaptiste Daroussin 
1292*b04a7a0bSBaptiste Daroussin bool
1293c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
1294c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
1295c99fb5f9SBaptiste Daroussin {
1296c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
1297c99fb5f9SBaptiste Daroussin }
1298c99fb5f9SBaptiste Daroussin 
1299*b04a7a0bSBaptiste Daroussin bool
1300c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
1301c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
1302c99fb5f9SBaptiste Daroussin {
1303c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
1304c99fb5f9SBaptiste Daroussin }
1305c99fb5f9SBaptiste Daroussin 
1306*b04a7a0bSBaptiste Daroussin bool
1307c99fb5f9SBaptiste Daroussin ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
1308c99fb5f9SBaptiste Daroussin 		const char *key, size_t keylen, bool copy_key)
1309c99fb5f9SBaptiste Daroussin {
1310c99fb5f9SBaptiste Daroussin 	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
1311c99fb5f9SBaptiste Daroussin }
1312c99fb5f9SBaptiste Daroussin 
1313*b04a7a0bSBaptiste Daroussin const ucl_object_t *
1314*b04a7a0bSBaptiste Daroussin ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
1315c99fb5f9SBaptiste Daroussin {
1316*b04a7a0bSBaptiste Daroussin 	const ucl_object_t *ret;
1317*b04a7a0bSBaptiste Daroussin 	ucl_object_t srch;
1318c99fb5f9SBaptiste Daroussin 
1319c99fb5f9SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1320c99fb5f9SBaptiste Daroussin 		return NULL;
1321c99fb5f9SBaptiste Daroussin 	}
1322c99fb5f9SBaptiste Daroussin 
1323c99fb5f9SBaptiste Daroussin 	srch.key = key;
1324c99fb5f9SBaptiste Daroussin 	srch.keylen = klen;
1325c99fb5f9SBaptiste Daroussin 	ret = ucl_hash_search_obj (obj->value.ov, &srch);
1326c99fb5f9SBaptiste Daroussin 
1327c99fb5f9SBaptiste Daroussin 	return ret;
1328c99fb5f9SBaptiste Daroussin }
1329c99fb5f9SBaptiste Daroussin 
1330*b04a7a0bSBaptiste Daroussin const ucl_object_t *
1331*b04a7a0bSBaptiste Daroussin ucl_object_find_key (const ucl_object_t *obj, const char *key)
1332c99fb5f9SBaptiste Daroussin {
1333c99fb5f9SBaptiste Daroussin 	size_t klen;
1334*b04a7a0bSBaptiste Daroussin 	const ucl_object_t *ret;
1335*b04a7a0bSBaptiste Daroussin 	ucl_object_t srch;
1336c99fb5f9SBaptiste Daroussin 
1337c99fb5f9SBaptiste Daroussin 	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1338c99fb5f9SBaptiste Daroussin 		return NULL;
1339c99fb5f9SBaptiste Daroussin 	}
1340c99fb5f9SBaptiste Daroussin 
1341c99fb5f9SBaptiste Daroussin 	klen = strlen (key);
1342c99fb5f9SBaptiste Daroussin 	srch.key = key;
1343c99fb5f9SBaptiste Daroussin 	srch.keylen = klen;
1344c99fb5f9SBaptiste Daroussin 	ret = ucl_hash_search_obj (obj->value.ov, &srch);
1345c99fb5f9SBaptiste Daroussin 
1346c99fb5f9SBaptiste Daroussin 	return ret;
1347c99fb5f9SBaptiste Daroussin }
1348c99fb5f9SBaptiste Daroussin 
1349*b04a7a0bSBaptiste Daroussin const ucl_object_t*
1350*b04a7a0bSBaptiste Daroussin ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
1351c99fb5f9SBaptiste Daroussin {
1352*b04a7a0bSBaptiste Daroussin 	const ucl_object_t *elt;
1353c99fb5f9SBaptiste Daroussin 
135497bd480fSBaptiste Daroussin 	if (obj == NULL || iter == NULL) {
135597bd480fSBaptiste Daroussin 		return NULL;
135697bd480fSBaptiste Daroussin 	}
135797bd480fSBaptiste Daroussin 
1358c99fb5f9SBaptiste Daroussin 	if (expand_values) {
1359c99fb5f9SBaptiste Daroussin 		switch (obj->type) {
1360c99fb5f9SBaptiste Daroussin 		case UCL_OBJECT:
1361*b04a7a0bSBaptiste Daroussin 			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
1362c99fb5f9SBaptiste Daroussin 			break;
1363c99fb5f9SBaptiste Daroussin 		case UCL_ARRAY:
1364c99fb5f9SBaptiste Daroussin 			elt = *iter;
1365c99fb5f9SBaptiste Daroussin 			if (elt == NULL) {
1366c99fb5f9SBaptiste Daroussin 				elt = obj->value.av;
1367c99fb5f9SBaptiste Daroussin 				if (elt == NULL) {
1368c99fb5f9SBaptiste Daroussin 					return NULL;
1369c99fb5f9SBaptiste Daroussin 				}
1370c99fb5f9SBaptiste Daroussin 			}
1371c99fb5f9SBaptiste Daroussin 			else if (elt == obj->value.av) {
1372c99fb5f9SBaptiste Daroussin 				return NULL;
1373c99fb5f9SBaptiste Daroussin 			}
1374c99fb5f9SBaptiste Daroussin 			*iter = elt->next ? elt->next : obj->value.av;
1375c99fb5f9SBaptiste Daroussin 			return elt;
1376c99fb5f9SBaptiste Daroussin 		default:
1377c99fb5f9SBaptiste Daroussin 			/* Go to linear iteration */
1378c99fb5f9SBaptiste Daroussin 			break;
1379c99fb5f9SBaptiste Daroussin 		}
1380c99fb5f9SBaptiste Daroussin 	}
1381c99fb5f9SBaptiste Daroussin 	/* Treat everything as a linear list */
1382c99fb5f9SBaptiste Daroussin 	elt = *iter;
1383c99fb5f9SBaptiste Daroussin 	if (elt == NULL) {
1384c99fb5f9SBaptiste Daroussin 		elt = obj;
1385c99fb5f9SBaptiste Daroussin 		if (elt == NULL) {
1386c99fb5f9SBaptiste Daroussin 			return NULL;
1387c99fb5f9SBaptiste Daroussin 		}
1388c99fb5f9SBaptiste Daroussin 	}
1389c99fb5f9SBaptiste Daroussin 	else if (elt == obj) {
1390c99fb5f9SBaptiste Daroussin 		return NULL;
1391c99fb5f9SBaptiste Daroussin 	}
1392*b04a7a0bSBaptiste Daroussin 	*iter = __DECONST (void *, elt->next ? elt->next : obj);
1393c99fb5f9SBaptiste Daroussin 	return elt;
1394c99fb5f9SBaptiste Daroussin 
1395c99fb5f9SBaptiste Daroussin 	/* Not reached */
1396c99fb5f9SBaptiste Daroussin 	return NULL;
1397c99fb5f9SBaptiste Daroussin }
139897bd480fSBaptiste Daroussin 
139997bd480fSBaptiste Daroussin 
140097bd480fSBaptiste Daroussin ucl_object_t *
140197bd480fSBaptiste Daroussin ucl_object_new (void)
140297bd480fSBaptiste Daroussin {
140397bd480fSBaptiste Daroussin 	ucl_object_t *new;
140497bd480fSBaptiste Daroussin 	new = malloc (sizeof (ucl_object_t));
140597bd480fSBaptiste Daroussin 	if (new != NULL) {
140697bd480fSBaptiste Daroussin 		memset (new, 0, sizeof (ucl_object_t));
140797bd480fSBaptiste Daroussin 		new->ref = 1;
140897bd480fSBaptiste Daroussin 		new->type = UCL_NULL;
140997bd480fSBaptiste Daroussin 	}
141097bd480fSBaptiste Daroussin 	return new;
141197bd480fSBaptiste Daroussin }
141297bd480fSBaptiste Daroussin 
141397bd480fSBaptiste Daroussin ucl_object_t *
141497bd480fSBaptiste Daroussin ucl_object_typed_new (unsigned int type)
141597bd480fSBaptiste Daroussin {
141697bd480fSBaptiste Daroussin 	ucl_object_t *new;
141797bd480fSBaptiste Daroussin 	new = malloc (sizeof (ucl_object_t));
141897bd480fSBaptiste Daroussin 	if (new != NULL) {
141997bd480fSBaptiste Daroussin 		memset (new, 0, sizeof (ucl_object_t));
142097bd480fSBaptiste Daroussin 		new->ref = 1;
142197bd480fSBaptiste Daroussin 		new->type = (type <= UCL_NULL ? type : UCL_NULL);
142297bd480fSBaptiste Daroussin 	}
142397bd480fSBaptiste Daroussin 	return new;
142497bd480fSBaptiste Daroussin }
142597bd480fSBaptiste Daroussin 
142697bd480fSBaptiste Daroussin ucl_object_t*
142797bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str)
142897bd480fSBaptiste Daroussin {
142997bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
143097bd480fSBaptiste Daroussin }
143197bd480fSBaptiste Daroussin 
143297bd480fSBaptiste Daroussin ucl_object_t *
143397bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len)
143497bd480fSBaptiste Daroussin {
143597bd480fSBaptiste Daroussin 	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
143697bd480fSBaptiste Daroussin }
143797bd480fSBaptiste Daroussin 
143897bd480fSBaptiste Daroussin ucl_object_t *
143997bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv)
144097bd480fSBaptiste Daroussin {
144197bd480fSBaptiste Daroussin 	ucl_object_t *obj;
144297bd480fSBaptiste Daroussin 
144397bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
144497bd480fSBaptiste Daroussin 	if (obj != NULL) {
144597bd480fSBaptiste Daroussin 		obj->type = UCL_INT;
144697bd480fSBaptiste Daroussin 		obj->value.iv = iv;
144797bd480fSBaptiste Daroussin 	}
144897bd480fSBaptiste Daroussin 
144997bd480fSBaptiste Daroussin 	return obj;
145097bd480fSBaptiste Daroussin }
145197bd480fSBaptiste Daroussin 
145297bd480fSBaptiste Daroussin ucl_object_t *
145397bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv)
145497bd480fSBaptiste Daroussin {
145597bd480fSBaptiste Daroussin 	ucl_object_t *obj;
145697bd480fSBaptiste Daroussin 
145797bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
145897bd480fSBaptiste Daroussin 	if (obj != NULL) {
145997bd480fSBaptiste Daroussin 		obj->type = UCL_FLOAT;
146097bd480fSBaptiste Daroussin 		obj->value.dv = dv;
146197bd480fSBaptiste Daroussin 	}
146297bd480fSBaptiste Daroussin 
146397bd480fSBaptiste Daroussin 	return obj;
146497bd480fSBaptiste Daroussin }
146597bd480fSBaptiste Daroussin 
146697bd480fSBaptiste Daroussin ucl_object_t*
146797bd480fSBaptiste Daroussin ucl_object_frombool (bool bv)
146897bd480fSBaptiste Daroussin {
146997bd480fSBaptiste Daroussin 	ucl_object_t *obj;
147097bd480fSBaptiste Daroussin 
147197bd480fSBaptiste Daroussin 	obj = ucl_object_new ();
147297bd480fSBaptiste Daroussin 	if (obj != NULL) {
147397bd480fSBaptiste Daroussin 		obj->type = UCL_BOOLEAN;
147497bd480fSBaptiste Daroussin 		obj->value.iv = bv;
147597bd480fSBaptiste Daroussin 	}
147697bd480fSBaptiste Daroussin 
147797bd480fSBaptiste Daroussin 	return obj;
147897bd480fSBaptiste Daroussin }
147997bd480fSBaptiste Daroussin 
1480*b04a7a0bSBaptiste Daroussin bool
148197bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
148297bd480fSBaptiste Daroussin {
148397bd480fSBaptiste Daroussin 	ucl_object_t *head;
148497bd480fSBaptiste Daroussin 
1485*b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
1486*b04a7a0bSBaptiste Daroussin 		return false;
148797bd480fSBaptiste Daroussin 	}
148897bd480fSBaptiste Daroussin 
148997bd480fSBaptiste Daroussin 	head = top->value.av;
149097bd480fSBaptiste Daroussin 	if (head == NULL) {
149197bd480fSBaptiste Daroussin 		top->value.av = elt;
149297bd480fSBaptiste Daroussin 		elt->prev = elt;
149397bd480fSBaptiste Daroussin 	}
149497bd480fSBaptiste Daroussin 	else {
149597bd480fSBaptiste Daroussin 		elt->prev = head->prev;
149697bd480fSBaptiste Daroussin 		head->prev->next = elt;
149797bd480fSBaptiste Daroussin 		head->prev = elt;
149897bd480fSBaptiste Daroussin 	}
149997bd480fSBaptiste Daroussin 	elt->next = NULL;
150097bd480fSBaptiste Daroussin 	top->len ++;
1501*b04a7a0bSBaptiste Daroussin 
1502*b04a7a0bSBaptiste Daroussin 	return true;
150397bd480fSBaptiste Daroussin }
150497bd480fSBaptiste Daroussin 
1505*b04a7a0bSBaptiste Daroussin bool
150697bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
150797bd480fSBaptiste Daroussin {
150897bd480fSBaptiste Daroussin 	ucl_object_t *head;
150997bd480fSBaptiste Daroussin 
1510*b04a7a0bSBaptiste Daroussin 	if (elt == NULL || top == NULL) {
1511*b04a7a0bSBaptiste Daroussin 		return false;
151297bd480fSBaptiste Daroussin 	}
151397bd480fSBaptiste Daroussin 
1514*b04a7a0bSBaptiste Daroussin 
151597bd480fSBaptiste Daroussin 	head = top->value.av;
151697bd480fSBaptiste Daroussin 	if (head == NULL) {
151797bd480fSBaptiste Daroussin 		top->value.av = elt;
151897bd480fSBaptiste Daroussin 		elt->prev = elt;
151997bd480fSBaptiste Daroussin 	}
152097bd480fSBaptiste Daroussin 	else {
152197bd480fSBaptiste Daroussin 		elt->prev = head->prev;
152297bd480fSBaptiste Daroussin 		head->prev = elt;
152397bd480fSBaptiste Daroussin 	}
152497bd480fSBaptiste Daroussin 	elt->next = head;
152597bd480fSBaptiste Daroussin 	top->value.av = elt;
152697bd480fSBaptiste Daroussin 	top->len ++;
152797bd480fSBaptiste Daroussin 
1528*b04a7a0bSBaptiste Daroussin 	return true;
152997bd480fSBaptiste Daroussin }
153097bd480fSBaptiste Daroussin 
153197bd480fSBaptiste Daroussin ucl_object_t *
153297bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
153397bd480fSBaptiste Daroussin {
153497bd480fSBaptiste Daroussin 	ucl_object_t *head;
153597bd480fSBaptiste Daroussin 
153697bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
153797bd480fSBaptiste Daroussin 		return NULL;
153897bd480fSBaptiste Daroussin 	}
153997bd480fSBaptiste Daroussin 	head = top->value.av;
154097bd480fSBaptiste Daroussin 
154197bd480fSBaptiste Daroussin 	if (elt->prev == elt) {
154297bd480fSBaptiste Daroussin 		top->value.av = NULL;
154397bd480fSBaptiste Daroussin 	}
154497bd480fSBaptiste Daroussin 	else if (elt == head) {
154597bd480fSBaptiste Daroussin 		elt->next->prev = elt->prev;
154697bd480fSBaptiste Daroussin 		top->value.av = elt->next;
154797bd480fSBaptiste Daroussin 	}
154897bd480fSBaptiste Daroussin 	else {
154997bd480fSBaptiste Daroussin 		elt->prev->next = elt->next;
155097bd480fSBaptiste Daroussin 		if (elt->next) {
155197bd480fSBaptiste Daroussin 			elt->next->prev = elt->prev;
155297bd480fSBaptiste Daroussin 		}
155397bd480fSBaptiste Daroussin 		else {
155497bd480fSBaptiste Daroussin 			head->prev = elt->prev;
155597bd480fSBaptiste Daroussin 		}
155697bd480fSBaptiste Daroussin 	}
155797bd480fSBaptiste Daroussin 	elt->next = NULL;
155897bd480fSBaptiste Daroussin 	elt->prev = elt;
155997bd480fSBaptiste Daroussin 	top->len --;
156097bd480fSBaptiste Daroussin 
156197bd480fSBaptiste Daroussin 	return elt;
156297bd480fSBaptiste Daroussin }
156397bd480fSBaptiste Daroussin 
1564*b04a7a0bSBaptiste Daroussin const ucl_object_t *
1565*b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top)
156697bd480fSBaptiste Daroussin {
156797bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
156897bd480fSBaptiste Daroussin 		return NULL;
156997bd480fSBaptiste Daroussin 	}
157097bd480fSBaptiste Daroussin 	return top->value.av;
157197bd480fSBaptiste Daroussin }
157297bd480fSBaptiste Daroussin 
1573*b04a7a0bSBaptiste Daroussin const ucl_object_t *
1574*b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top)
157597bd480fSBaptiste Daroussin {
157697bd480fSBaptiste Daroussin 	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
157797bd480fSBaptiste Daroussin 		return NULL;
157897bd480fSBaptiste Daroussin 	}
157997bd480fSBaptiste Daroussin 	return top->value.av->prev;
158097bd480fSBaptiste Daroussin }
158197bd480fSBaptiste Daroussin 
158297bd480fSBaptiste Daroussin ucl_object_t *
158397bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top)
158497bd480fSBaptiste Daroussin {
1585*b04a7a0bSBaptiste Daroussin 	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top)));
158697bd480fSBaptiste Daroussin }
158797bd480fSBaptiste Daroussin 
158897bd480fSBaptiste Daroussin ucl_object_t *
158997bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top)
159097bd480fSBaptiste Daroussin {
1591*b04a7a0bSBaptiste Daroussin 	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top)));
159297bd480fSBaptiste Daroussin }
159397bd480fSBaptiste Daroussin 
159497bd480fSBaptiste Daroussin ucl_object_t *
159597bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
159697bd480fSBaptiste Daroussin {
159797bd480fSBaptiste Daroussin 
159897bd480fSBaptiste Daroussin 	if (head == NULL) {
159997bd480fSBaptiste Daroussin 		elt->next = NULL;
160097bd480fSBaptiste Daroussin 		elt->prev = elt;
160197bd480fSBaptiste Daroussin 		head = elt;
160297bd480fSBaptiste Daroussin 	}
160397bd480fSBaptiste Daroussin 	else {
160497bd480fSBaptiste Daroussin 		elt->prev = head->prev;
160597bd480fSBaptiste Daroussin 		head->prev->next = elt;
160697bd480fSBaptiste Daroussin 		head->prev = elt;
160797bd480fSBaptiste Daroussin 		elt->next = NULL;
160897bd480fSBaptiste Daroussin 	}
160997bd480fSBaptiste Daroussin 
161097bd480fSBaptiste Daroussin 	return head;
161197bd480fSBaptiste Daroussin }
161297bd480fSBaptiste Daroussin 
161397bd480fSBaptiste Daroussin bool
1614*b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target)
161597bd480fSBaptiste Daroussin {
161697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
161797bd480fSBaptiste Daroussin 		return false;
161897bd480fSBaptiste Daroussin 	}
161997bd480fSBaptiste Daroussin 	switch (obj->type) {
162097bd480fSBaptiste Daroussin 	case UCL_INT:
162197bd480fSBaptiste Daroussin 		*target = obj->value.iv; /* Probaly could cause overflow */
162297bd480fSBaptiste Daroussin 		break;
162397bd480fSBaptiste Daroussin 	case UCL_FLOAT:
162497bd480fSBaptiste Daroussin 	case UCL_TIME:
162597bd480fSBaptiste Daroussin 		*target = obj->value.dv;
162697bd480fSBaptiste Daroussin 		break;
162797bd480fSBaptiste Daroussin 	default:
162897bd480fSBaptiste Daroussin 		return false;
162997bd480fSBaptiste Daroussin 	}
163097bd480fSBaptiste Daroussin 
163197bd480fSBaptiste Daroussin 	return true;
163297bd480fSBaptiste Daroussin }
163397bd480fSBaptiste Daroussin 
163497bd480fSBaptiste Daroussin double
1635*b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj)
163697bd480fSBaptiste Daroussin {
163797bd480fSBaptiste Daroussin 	double result = 0.;
163897bd480fSBaptiste Daroussin 
163997bd480fSBaptiste Daroussin 	ucl_object_todouble_safe (obj, &result);
164097bd480fSBaptiste Daroussin 	return result;
164197bd480fSBaptiste Daroussin }
164297bd480fSBaptiste Daroussin 
164397bd480fSBaptiste Daroussin bool
1644*b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target)
164597bd480fSBaptiste Daroussin {
164697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
164797bd480fSBaptiste Daroussin 		return false;
164897bd480fSBaptiste Daroussin 	}
164997bd480fSBaptiste Daroussin 	switch (obj->type) {
165097bd480fSBaptiste Daroussin 	case UCL_INT:
165197bd480fSBaptiste Daroussin 		*target = obj->value.iv;
165297bd480fSBaptiste Daroussin 		break;
165397bd480fSBaptiste Daroussin 	case UCL_FLOAT:
165497bd480fSBaptiste Daroussin 	case UCL_TIME:
165597bd480fSBaptiste Daroussin 		*target = obj->value.dv; /* Loosing of decimal points */
165697bd480fSBaptiste Daroussin 		break;
165797bd480fSBaptiste Daroussin 	default:
165897bd480fSBaptiste Daroussin 		return false;
165997bd480fSBaptiste Daroussin 	}
166097bd480fSBaptiste Daroussin 
166197bd480fSBaptiste Daroussin 	return true;
166297bd480fSBaptiste Daroussin }
166397bd480fSBaptiste Daroussin 
166497bd480fSBaptiste Daroussin int64_t
1665*b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj)
166697bd480fSBaptiste Daroussin {
166797bd480fSBaptiste Daroussin 	int64_t result = 0;
166897bd480fSBaptiste Daroussin 
166997bd480fSBaptiste Daroussin 	ucl_object_toint_safe (obj, &result);
167097bd480fSBaptiste Daroussin 	return result;
167197bd480fSBaptiste Daroussin }
167297bd480fSBaptiste Daroussin 
167397bd480fSBaptiste Daroussin bool
1674*b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target)
167597bd480fSBaptiste Daroussin {
167697bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
167797bd480fSBaptiste Daroussin 		return false;
167897bd480fSBaptiste Daroussin 	}
167997bd480fSBaptiste Daroussin 	switch (obj->type) {
168097bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
168197bd480fSBaptiste Daroussin 		*target = (obj->value.iv == true);
168297bd480fSBaptiste Daroussin 		break;
168397bd480fSBaptiste Daroussin 	default:
168497bd480fSBaptiste Daroussin 		return false;
168597bd480fSBaptiste Daroussin 	}
168697bd480fSBaptiste Daroussin 
168797bd480fSBaptiste Daroussin 	return true;
168897bd480fSBaptiste Daroussin }
168997bd480fSBaptiste Daroussin 
169097bd480fSBaptiste Daroussin bool
1691*b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj)
169297bd480fSBaptiste Daroussin {
169397bd480fSBaptiste Daroussin 	bool result = false;
169497bd480fSBaptiste Daroussin 
169597bd480fSBaptiste Daroussin 	ucl_object_toboolean_safe (obj, &result);
169697bd480fSBaptiste Daroussin 	return result;
169797bd480fSBaptiste Daroussin }
169897bd480fSBaptiste Daroussin 
169997bd480fSBaptiste Daroussin bool
1700*b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target)
170197bd480fSBaptiste Daroussin {
170297bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
170397bd480fSBaptiste Daroussin 		return false;
170497bd480fSBaptiste Daroussin 	}
170597bd480fSBaptiste Daroussin 
170697bd480fSBaptiste Daroussin 	switch (obj->type) {
170797bd480fSBaptiste Daroussin 	case UCL_STRING:
170897bd480fSBaptiste Daroussin 		*target = ucl_copy_value_trash (obj);
170997bd480fSBaptiste Daroussin 		break;
171097bd480fSBaptiste Daroussin 	default:
171197bd480fSBaptiste Daroussin 		return false;
171297bd480fSBaptiste Daroussin 	}
171397bd480fSBaptiste Daroussin 
171497bd480fSBaptiste Daroussin 	return true;
171597bd480fSBaptiste Daroussin }
171697bd480fSBaptiste Daroussin 
171797bd480fSBaptiste Daroussin const char *
1718*b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj)
171997bd480fSBaptiste Daroussin {
172097bd480fSBaptiste Daroussin 	const char *result = NULL;
172197bd480fSBaptiste Daroussin 
172297bd480fSBaptiste Daroussin 	ucl_object_tostring_safe (obj, &result);
172397bd480fSBaptiste Daroussin 	return result;
172497bd480fSBaptiste Daroussin }
172597bd480fSBaptiste Daroussin 
172697bd480fSBaptiste Daroussin const char *
1727*b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj)
172897bd480fSBaptiste Daroussin {
172997bd480fSBaptiste Daroussin 	return ucl_copy_value_trash (obj);
173097bd480fSBaptiste Daroussin }
173197bd480fSBaptiste Daroussin 
173297bd480fSBaptiste Daroussin bool
1733*b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen)
173497bd480fSBaptiste Daroussin {
173597bd480fSBaptiste Daroussin 	if (obj == NULL || target == NULL) {
173697bd480fSBaptiste Daroussin 		return false;
173797bd480fSBaptiste Daroussin 	}
173897bd480fSBaptiste Daroussin 	switch (obj->type) {
173997bd480fSBaptiste Daroussin 	case UCL_STRING:
174097bd480fSBaptiste Daroussin 		*target = obj->value.sv;
174197bd480fSBaptiste Daroussin 		if (tlen != NULL) {
174297bd480fSBaptiste Daroussin 			*tlen = obj->len;
174397bd480fSBaptiste Daroussin 		}
174497bd480fSBaptiste Daroussin 		break;
174597bd480fSBaptiste Daroussin 	default:
174697bd480fSBaptiste Daroussin 		return false;
174797bd480fSBaptiste Daroussin 	}
174897bd480fSBaptiste Daroussin 
174997bd480fSBaptiste Daroussin 	return true;
175097bd480fSBaptiste Daroussin }
175197bd480fSBaptiste Daroussin 
175297bd480fSBaptiste Daroussin const char *
1753*b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen)
175497bd480fSBaptiste Daroussin {
175597bd480fSBaptiste Daroussin 	const char *result = NULL;
175697bd480fSBaptiste Daroussin 
175797bd480fSBaptiste Daroussin 	ucl_object_tolstring_safe (obj, &result, tlen);
175897bd480fSBaptiste Daroussin 	return result;
175997bd480fSBaptiste Daroussin }
176097bd480fSBaptiste Daroussin 
176197bd480fSBaptiste Daroussin const char *
1762*b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj)
176397bd480fSBaptiste Daroussin {
176497bd480fSBaptiste Daroussin 	return ucl_copy_key_trash (obj);
176597bd480fSBaptiste Daroussin }
176697bd480fSBaptiste Daroussin 
176797bd480fSBaptiste Daroussin const char *
1768*b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len)
176997bd480fSBaptiste Daroussin {
177097bd480fSBaptiste Daroussin 	if (len == NULL || obj == NULL) {
177197bd480fSBaptiste Daroussin 		return NULL;
177297bd480fSBaptiste Daroussin 	}
177397bd480fSBaptiste Daroussin 	*len = obj->keylen;
177497bd480fSBaptiste Daroussin 	return obj->key;
177597bd480fSBaptiste Daroussin }
177697bd480fSBaptiste Daroussin 
177797bd480fSBaptiste Daroussin ucl_object_t *
1778*b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj)
177997bd480fSBaptiste Daroussin {
1780*b04a7a0bSBaptiste Daroussin 	ucl_object_t *res = NULL;
1781*b04a7a0bSBaptiste Daroussin 
178297bd480fSBaptiste Daroussin 	if (obj != NULL) {
1783*b04a7a0bSBaptiste Daroussin 		res = __DECONST (ucl_object_t *, obj);
1784*b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
1785*b04a7a0bSBaptiste Daroussin 		(void)__sync_add_and_fetch (&res->ref, 1);
1786*b04a7a0bSBaptiste Daroussin #else
1787*b04a7a0bSBaptiste Daroussin 		res->ref ++;
1788*b04a7a0bSBaptiste Daroussin #endif
178997bd480fSBaptiste Daroussin 	}
1790*b04a7a0bSBaptiste Daroussin 	return res;
179197bd480fSBaptiste Daroussin }
179297bd480fSBaptiste Daroussin 
179397bd480fSBaptiste Daroussin void
179497bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj)
179597bd480fSBaptiste Daroussin {
1796*b04a7a0bSBaptiste Daroussin 	if (obj != NULL) {
1797*b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS
1798*b04a7a0bSBaptiste Daroussin 		unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1);
1799*b04a7a0bSBaptiste Daroussin 		if (rc == 0) {
1800*b04a7a0bSBaptiste Daroussin #else
1801*b04a7a0bSBaptiste Daroussin 		if (--obj->ref == 0) {
1802*b04a7a0bSBaptiste Daroussin #endif
1803*b04a7a0bSBaptiste Daroussin 			ucl_object_free_internal (obj, true, ucl_object_dtor_unref);
1804*b04a7a0bSBaptiste Daroussin 		}
180597bd480fSBaptiste Daroussin 	}
180697bd480fSBaptiste Daroussin }
180797bd480fSBaptiste Daroussin 
180897bd480fSBaptiste Daroussin int
1809*b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
181097bd480fSBaptiste Daroussin {
1811*b04a7a0bSBaptiste Daroussin 	const ucl_object_t *it1, *it2;
181297bd480fSBaptiste Daroussin 	ucl_object_iter_t iter = NULL;
181397bd480fSBaptiste Daroussin 	int ret = 0;
181497bd480fSBaptiste Daroussin 
181597bd480fSBaptiste Daroussin 	if (o1->type != o2->type) {
181697bd480fSBaptiste Daroussin 		return (o1->type) - (o2->type);
181797bd480fSBaptiste Daroussin 	}
181897bd480fSBaptiste Daroussin 
181997bd480fSBaptiste Daroussin 	switch (o1->type) {
182097bd480fSBaptiste Daroussin 	case UCL_STRING:
182197bd480fSBaptiste Daroussin 		if (o1->len == o2->len) {
182297bd480fSBaptiste Daroussin 			ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
182397bd480fSBaptiste Daroussin 		}
182497bd480fSBaptiste Daroussin 		else {
182597bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
182697bd480fSBaptiste Daroussin 		}
182797bd480fSBaptiste Daroussin 		break;
182897bd480fSBaptiste Daroussin 	case UCL_FLOAT:
182997bd480fSBaptiste Daroussin 	case UCL_INT:
183097bd480fSBaptiste Daroussin 	case UCL_TIME:
183197bd480fSBaptiste Daroussin 		ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
183297bd480fSBaptiste Daroussin 		break;
183397bd480fSBaptiste Daroussin 	case UCL_BOOLEAN:
183497bd480fSBaptiste Daroussin 		ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
183597bd480fSBaptiste Daroussin 		break;
183697bd480fSBaptiste Daroussin 	case UCL_ARRAY:
183797bd480fSBaptiste Daroussin 		if (o1->len == o2->len) {
183897bd480fSBaptiste Daroussin 			it1 = o1->value.av;
183997bd480fSBaptiste Daroussin 			it2 = o2->value.av;
184097bd480fSBaptiste Daroussin 			/* Compare all elements in both arrays */
184197bd480fSBaptiste Daroussin 			while (it1 != NULL && it2 != NULL) {
184297bd480fSBaptiste Daroussin 				ret = ucl_object_compare (it1, it2);
184397bd480fSBaptiste Daroussin 				if (ret != 0) {
184497bd480fSBaptiste Daroussin 					break;
184597bd480fSBaptiste Daroussin 				}
184697bd480fSBaptiste Daroussin 				it1 = it1->next;
184797bd480fSBaptiste Daroussin 				it2 = it2->next;
184897bd480fSBaptiste Daroussin 			}
184997bd480fSBaptiste Daroussin 		}
185097bd480fSBaptiste Daroussin 		else {
185197bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
185297bd480fSBaptiste Daroussin 		}
185397bd480fSBaptiste Daroussin 		break;
185497bd480fSBaptiste Daroussin 	case UCL_OBJECT:
185597bd480fSBaptiste Daroussin 		if (o1->len == o2->len) {
185697bd480fSBaptiste Daroussin 			while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) {
185797bd480fSBaptiste Daroussin 				it2 = ucl_object_find_key (o2, ucl_object_key (it1));
185897bd480fSBaptiste Daroussin 				if (it2 == NULL) {
185997bd480fSBaptiste Daroussin 					ret = 1;
186097bd480fSBaptiste Daroussin 					break;
186197bd480fSBaptiste Daroussin 				}
186297bd480fSBaptiste Daroussin 				ret = ucl_object_compare (it1, it2);
186397bd480fSBaptiste Daroussin 				if (ret != 0) {
186497bd480fSBaptiste Daroussin 					break;
186597bd480fSBaptiste Daroussin 				}
186697bd480fSBaptiste Daroussin 			}
186797bd480fSBaptiste Daroussin 		}
186897bd480fSBaptiste Daroussin 		else {
186997bd480fSBaptiste Daroussin 			ret = o1->len - o2->len;
187097bd480fSBaptiste Daroussin 		}
187197bd480fSBaptiste Daroussin 		break;
187297bd480fSBaptiste Daroussin 	default:
187397bd480fSBaptiste Daroussin 		ret = 0;
187497bd480fSBaptiste Daroussin 		break;
187597bd480fSBaptiste Daroussin 	}
187697bd480fSBaptiste Daroussin 
187797bd480fSBaptiste Daroussin 	return ret;
187897bd480fSBaptiste Daroussin }
187997bd480fSBaptiste Daroussin 
188097bd480fSBaptiste Daroussin void
188197bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar,
1882*b04a7a0bSBaptiste Daroussin 		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2))
188397bd480fSBaptiste Daroussin {
188497bd480fSBaptiste Daroussin 	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
188597bd480fSBaptiste Daroussin 		return;
188697bd480fSBaptiste Daroussin 	}
188797bd480fSBaptiste Daroussin 
188897bd480fSBaptiste Daroussin 	DL_SORT (ar->value.av, cmp);
188997bd480fSBaptiste Daroussin }
1890