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