1c99fb5f9SBaptiste Daroussin /* Copyright (c) 2013, Vsevolod Stakhov 2*39ee7a7aSBaptiste Daroussin * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> 3c99fb5f9SBaptiste Daroussin * All rights reserved. 4c99fb5f9SBaptiste Daroussin * 5c99fb5f9SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 6c99fb5f9SBaptiste Daroussin * modification, are permitted provided that the following conditions are met: 7c99fb5f9SBaptiste Daroussin * * Redistributions of source code must retain the above copyright 8c99fb5f9SBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 9c99fb5f9SBaptiste Daroussin * * Redistributions in binary form must reproduce the above copyright 10c99fb5f9SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 11c99fb5f9SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 12c99fb5f9SBaptiste Daroussin * 13c99fb5f9SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 14c99fb5f9SBaptiste Daroussin * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15c99fb5f9SBaptiste Daroussin * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16c99fb5f9SBaptiste Daroussin * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 17c99fb5f9SBaptiste Daroussin * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18c99fb5f9SBaptiste Daroussin * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19c99fb5f9SBaptiste Daroussin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20c99fb5f9SBaptiste Daroussin * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21c99fb5f9SBaptiste Daroussin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22c99fb5f9SBaptiste Daroussin * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23c99fb5f9SBaptiste Daroussin */ 24c99fb5f9SBaptiste Daroussin 25c99fb5f9SBaptiste Daroussin #include "ucl.h" 26c99fb5f9SBaptiste Daroussin #include "ucl_internal.h" 27c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h" 288e3b1ab2SBaptiste Daroussin #include "kvec.h" 29*39ee7a7aSBaptiste Daroussin #include <stdarg.h> 30c99fb5f9SBaptiste Daroussin 318e3b1ab2SBaptiste Daroussin #ifndef _WIN32 324bf54857SBaptiste Daroussin #include <glob.h> 338e3b1ab2SBaptiste Daroussin #endif 344bf54857SBaptiste Daroussin 3597bd480fSBaptiste Daroussin #ifdef HAVE_LIBGEN_H 36c99fb5f9SBaptiste Daroussin #include <libgen.h> /* For dirname */ 3797bd480fSBaptiste Daroussin #endif 38c99fb5f9SBaptiste Daroussin 398e3b1ab2SBaptiste Daroussin typedef kvec_t(ucl_object_t *) ucl_array_t; 408e3b1ab2SBaptiste Daroussin 418e3b1ab2SBaptiste Daroussin #define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \ 428e3b1ab2SBaptiste Daroussin (ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL) 438e3b1ab2SBaptiste Daroussin 44c99fb5f9SBaptiste Daroussin #ifdef HAVE_OPENSSL 45c99fb5f9SBaptiste Daroussin #include <openssl/err.h> 46c99fb5f9SBaptiste Daroussin #include <openssl/sha.h> 47c99fb5f9SBaptiste Daroussin #include <openssl/rsa.h> 48c99fb5f9SBaptiste Daroussin #include <openssl/ssl.h> 49c99fb5f9SBaptiste Daroussin #include <openssl/evp.h> 50c99fb5f9SBaptiste Daroussin #endif 51c99fb5f9SBaptiste Daroussin 5297bd480fSBaptiste Daroussin #ifdef CURL_FOUND 5397bd480fSBaptiste Daroussin #include <curl/curl.h> 5497bd480fSBaptiste Daroussin #endif 5597bd480fSBaptiste Daroussin #ifdef HAVE_FETCH_H 5697bd480fSBaptiste Daroussin #include <fetch.h> 5797bd480fSBaptiste Daroussin #endif 5897bd480fSBaptiste Daroussin 5936c53d67SBaptiste Daroussin #ifdef _WIN32 6036c53d67SBaptiste Daroussin #include <windows.h> 6136c53d67SBaptiste Daroussin 6297bd480fSBaptiste Daroussin #ifndef PROT_READ 6336c53d67SBaptiste Daroussin #define PROT_READ 1 6497bd480fSBaptiste Daroussin #endif 6597bd480fSBaptiste Daroussin #ifndef PROT_WRITE 6636c53d67SBaptiste Daroussin #define PROT_WRITE 2 6797bd480fSBaptiste Daroussin #endif 6897bd480fSBaptiste Daroussin #ifndef PROT_READWRITE 6936c53d67SBaptiste Daroussin #define PROT_READWRITE 3 7097bd480fSBaptiste Daroussin #endif 7197bd480fSBaptiste Daroussin #ifndef MAP_SHARED 7236c53d67SBaptiste Daroussin #define MAP_SHARED 1 7397bd480fSBaptiste Daroussin #endif 7497bd480fSBaptiste Daroussin #ifndef MAP_PRIVATE 7536c53d67SBaptiste Daroussin #define MAP_PRIVATE 2 7697bd480fSBaptiste Daroussin #endif 7797bd480fSBaptiste Daroussin #ifndef MAP_FAILED 7836c53d67SBaptiste Daroussin #define MAP_FAILED ((void *) -1) 7997bd480fSBaptiste Daroussin #endif 8036c53d67SBaptiste Daroussin 818e3b1ab2SBaptiste Daroussin #ifdef _WIN32 828e3b1ab2SBaptiste Daroussin #include <limits.h> 838e3b1ab2SBaptiste Daroussin #define NBBY CHAR_BIT 848e3b1ab2SBaptiste Daroussin #endif 858e3b1ab2SBaptiste Daroussin 8697bd480fSBaptiste Daroussin static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 8736c53d67SBaptiste Daroussin { 8836c53d67SBaptiste Daroussin void *map = NULL; 8936c53d67SBaptiste Daroussin HANDLE handle = INVALID_HANDLE_VALUE; 9036c53d67SBaptiste Daroussin 9136c53d67SBaptiste Daroussin switch (prot) { 9236c53d67SBaptiste Daroussin default: 9336c53d67SBaptiste Daroussin case PROT_READ: 9436c53d67SBaptiste Daroussin { 9536c53d67SBaptiste Daroussin handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 9636c53d67SBaptiste Daroussin if (!handle) break; 9736c53d67SBaptiste Daroussin map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 9836c53d67SBaptiste Daroussin CloseHandle(handle); 9936c53d67SBaptiste Daroussin break; 10036c53d67SBaptiste Daroussin } 10136c53d67SBaptiste Daroussin case PROT_WRITE: 10236c53d67SBaptiste Daroussin { 10336c53d67SBaptiste Daroussin handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 10436c53d67SBaptiste Daroussin if (!handle) break; 10536c53d67SBaptiste Daroussin map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 10636c53d67SBaptiste Daroussin CloseHandle(handle); 10736c53d67SBaptiste Daroussin break; 10836c53d67SBaptiste Daroussin } 10936c53d67SBaptiste Daroussin case PROT_READWRITE: 11036c53d67SBaptiste Daroussin { 11136c53d67SBaptiste Daroussin handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 11236c53d67SBaptiste Daroussin if (!handle) break; 11336c53d67SBaptiste Daroussin map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 11436c53d67SBaptiste Daroussin CloseHandle(handle); 11536c53d67SBaptiste Daroussin break; 11636c53d67SBaptiste Daroussin } 11736c53d67SBaptiste Daroussin } 11836c53d67SBaptiste Daroussin if (map == (void *) NULL) { 11936c53d67SBaptiste Daroussin return (void *) MAP_FAILED; 12036c53d67SBaptiste Daroussin } 12136c53d67SBaptiste Daroussin return (void *) ((char *) map + offset); 12236c53d67SBaptiste Daroussin } 12336c53d67SBaptiste Daroussin 12497bd480fSBaptiste Daroussin static int ucl_munmap(void *map,size_t length) 12536c53d67SBaptiste Daroussin { 12636c53d67SBaptiste Daroussin if (!UnmapViewOfFile(map)) { 12736c53d67SBaptiste Daroussin return(-1); 12836c53d67SBaptiste Daroussin } 12936c53d67SBaptiste Daroussin return(0); 13036c53d67SBaptiste Daroussin } 13136c53d67SBaptiste Daroussin 13297bd480fSBaptiste Daroussin static char* ucl_realpath(const char *path, char *resolved_path) { 13336c53d67SBaptiste Daroussin char *p; 13436c53d67SBaptiste Daroussin char tmp[MAX_PATH + 1]; 13536c53d67SBaptiste Daroussin strncpy(tmp, path, sizeof(tmp)-1); 13636c53d67SBaptiste Daroussin p = tmp; 13736c53d67SBaptiste Daroussin while(*p) { 13836c53d67SBaptiste Daroussin if (*p == '/') *p = '\\'; 13936c53d67SBaptiste Daroussin p++; 14036c53d67SBaptiste Daroussin } 14136c53d67SBaptiste Daroussin return _fullpath(resolved_path, tmp, MAX_PATH); 14236c53d67SBaptiste Daroussin } 14397bd480fSBaptiste Daroussin #else 14497bd480fSBaptiste Daroussin #define ucl_mmap mmap 14597bd480fSBaptiste Daroussin #define ucl_munmap munmap 14697bd480fSBaptiste Daroussin #define ucl_realpath realpath 14736c53d67SBaptiste Daroussin #endif 14836c53d67SBaptiste Daroussin 149b04a7a0bSBaptiste Daroussin typedef void (*ucl_object_dtor) (ucl_object_t *obj); 150b04a7a0bSBaptiste Daroussin static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 151b04a7a0bSBaptiste Daroussin ucl_object_dtor dtor); 152b04a7a0bSBaptiste Daroussin static void ucl_object_dtor_unref (ucl_object_t *obj); 153c99fb5f9SBaptiste Daroussin 154c99fb5f9SBaptiste Daroussin static void 155b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (ucl_object_t *obj) 156c99fb5f9SBaptiste Daroussin { 157c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 158c99fb5f9SBaptiste Daroussin UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 159c99fb5f9SBaptiste Daroussin } 160c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 161c99fb5f9SBaptiste Daroussin UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 162c99fb5f9SBaptiste Daroussin } 1634bf54857SBaptiste Daroussin /* Do not free ephemeral objects */ 1644bf54857SBaptiste Daroussin if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) { 1654bf54857SBaptiste Daroussin if (obj->type != UCL_USERDATA) { 166b04a7a0bSBaptiste Daroussin UCL_FREE (sizeof (ucl_object_t), obj); 167b04a7a0bSBaptiste Daroussin } 1684bf54857SBaptiste Daroussin else { 1694bf54857SBaptiste Daroussin struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj; 1704bf54857SBaptiste Daroussin if (ud->dtor) { 1714bf54857SBaptiste Daroussin ud->dtor (obj->value.ud); 1724bf54857SBaptiste Daroussin } 1734bf54857SBaptiste Daroussin UCL_FREE (sizeof (*ud), obj); 1744bf54857SBaptiste Daroussin } 1754bf54857SBaptiste Daroussin } 1764bf54857SBaptiste Daroussin } 177c99fb5f9SBaptiste Daroussin 178b04a7a0bSBaptiste Daroussin /* 179b04a7a0bSBaptiste Daroussin * This is a helper function that performs exactly the same as 180b04a7a0bSBaptiste Daroussin * `ucl_object_unref` but it doesn't iterate over elements allowing 181b04a7a0bSBaptiste Daroussin * to use it for individual elements of arrays and multiple values 182b04a7a0bSBaptiste Daroussin */ 183b04a7a0bSBaptiste Daroussin static void 184b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (ucl_object_t *obj) 185b04a7a0bSBaptiste Daroussin { 186b04a7a0bSBaptiste Daroussin if (obj != NULL) { 187b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS 188b04a7a0bSBaptiste Daroussin unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 189b04a7a0bSBaptiste Daroussin if (rc == 0) { 190b04a7a0bSBaptiste Daroussin #else 191b04a7a0bSBaptiste Daroussin if (--obj->ref == 0) { 192b04a7a0bSBaptiste Daroussin #endif 193b04a7a0bSBaptiste Daroussin ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 194b04a7a0bSBaptiste Daroussin } 195b04a7a0bSBaptiste Daroussin } 196b04a7a0bSBaptiste Daroussin } 197b04a7a0bSBaptiste Daroussin 198b04a7a0bSBaptiste Daroussin static void 199b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref (ucl_object_t *obj) 200b04a7a0bSBaptiste Daroussin { 201b04a7a0bSBaptiste Daroussin if (obj->ref == 0) { 202b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (obj); 203b04a7a0bSBaptiste Daroussin } 204b04a7a0bSBaptiste Daroussin else { 205b04a7a0bSBaptiste Daroussin /* This may cause dtor unref being called one more time */ 206b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (obj); 207b04a7a0bSBaptiste Daroussin } 208b04a7a0bSBaptiste Daroussin } 209b04a7a0bSBaptiste Daroussin 210b04a7a0bSBaptiste Daroussin static void 211b04a7a0bSBaptiste Daroussin ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 212b04a7a0bSBaptiste Daroussin { 2138e3b1ab2SBaptiste Daroussin ucl_object_t *tmp, *sub; 214b04a7a0bSBaptiste Daroussin 215b04a7a0bSBaptiste Daroussin while (obj != NULL) { 216c99fb5f9SBaptiste Daroussin if (obj->type == UCL_ARRAY) { 2178e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, obj); 2188e3b1ab2SBaptiste Daroussin unsigned int i; 2198e3b1ab2SBaptiste Daroussin 2208e3b1ab2SBaptiste Daroussin if (vec != NULL) { 2218e3b1ab2SBaptiste Daroussin for (i = 0; i < vec->n; i ++) { 2228e3b1ab2SBaptiste Daroussin sub = kv_A (*vec, i); 2238e3b1ab2SBaptiste Daroussin if (sub != NULL) { 2248e3b1ab2SBaptiste Daroussin tmp = sub; 2258e3b1ab2SBaptiste Daroussin while (sub) { 226c99fb5f9SBaptiste Daroussin tmp = sub->next; 227b04a7a0bSBaptiste Daroussin dtor (sub); 228c99fb5f9SBaptiste Daroussin sub = tmp; 229c99fb5f9SBaptiste Daroussin } 230c99fb5f9SBaptiste Daroussin } 2318e3b1ab2SBaptiste Daroussin } 2328e3b1ab2SBaptiste Daroussin kv_destroy (*vec); 2338e3b1ab2SBaptiste Daroussin UCL_FREE (sizeof (*vec), vec); 2348e3b1ab2SBaptiste Daroussin } 235*39ee7a7aSBaptiste Daroussin obj->value.av = NULL; 2368e3b1ab2SBaptiste Daroussin } 237c99fb5f9SBaptiste Daroussin else if (obj->type == UCL_OBJECT) { 238c99fb5f9SBaptiste Daroussin if (obj->value.ov != NULL) { 239b04a7a0bSBaptiste Daroussin ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); 240c99fb5f9SBaptiste Daroussin } 241*39ee7a7aSBaptiste Daroussin obj->value.ov = NULL; 242c99fb5f9SBaptiste Daroussin } 243c99fb5f9SBaptiste Daroussin tmp = obj->next; 244b04a7a0bSBaptiste Daroussin dtor (obj); 245c99fb5f9SBaptiste Daroussin obj = tmp; 246c99fb5f9SBaptiste Daroussin 247c99fb5f9SBaptiste Daroussin if (!allow_rec) { 248c99fb5f9SBaptiste Daroussin break; 249c99fb5f9SBaptiste Daroussin } 250c99fb5f9SBaptiste Daroussin } 251c99fb5f9SBaptiste Daroussin } 252c99fb5f9SBaptiste Daroussin 253c99fb5f9SBaptiste Daroussin void 254c99fb5f9SBaptiste Daroussin ucl_object_free (ucl_object_t *obj) 255c99fb5f9SBaptiste Daroussin { 256b04a7a0bSBaptiste Daroussin ucl_object_free_internal (obj, true, ucl_object_dtor_free); 257c99fb5f9SBaptiste Daroussin } 258c99fb5f9SBaptiste Daroussin 259c99fb5f9SBaptiste Daroussin size_t 260c99fb5f9SBaptiste Daroussin ucl_unescape_json_string (char *str, size_t len) 261c99fb5f9SBaptiste Daroussin { 262c99fb5f9SBaptiste Daroussin char *t = str, *h = str; 263c99fb5f9SBaptiste Daroussin int i, uval; 264c99fb5f9SBaptiste Daroussin 26597bd480fSBaptiste Daroussin if (len <= 1) { 26697bd480fSBaptiste Daroussin return len; 26797bd480fSBaptiste Daroussin } 268c99fb5f9SBaptiste Daroussin /* t is target (tortoise), h is source (hare) */ 269c99fb5f9SBaptiste Daroussin 270c99fb5f9SBaptiste Daroussin while (len) { 271c99fb5f9SBaptiste Daroussin if (*h == '\\') { 272c99fb5f9SBaptiste Daroussin h ++; 273*39ee7a7aSBaptiste Daroussin 274*39ee7a7aSBaptiste Daroussin if (len == 1) { 275*39ee7a7aSBaptiste Daroussin /* 276*39ee7a7aSBaptiste Daroussin * If \ is last, then do not try to go further 277*39ee7a7aSBaptiste Daroussin * Issue: #74 278*39ee7a7aSBaptiste Daroussin */ 279*39ee7a7aSBaptiste Daroussin len --; 280*39ee7a7aSBaptiste Daroussin *t++ = '\\'; 281*39ee7a7aSBaptiste Daroussin continue; 282*39ee7a7aSBaptiste Daroussin } 283*39ee7a7aSBaptiste Daroussin 284c99fb5f9SBaptiste Daroussin switch (*h) { 285c99fb5f9SBaptiste Daroussin case 'n': 286c99fb5f9SBaptiste Daroussin *t++ = '\n'; 287c99fb5f9SBaptiste Daroussin break; 288c99fb5f9SBaptiste Daroussin case 'r': 289c99fb5f9SBaptiste Daroussin *t++ = '\r'; 290c99fb5f9SBaptiste Daroussin break; 291c99fb5f9SBaptiste Daroussin case 'b': 292c99fb5f9SBaptiste Daroussin *t++ = '\b'; 293c99fb5f9SBaptiste Daroussin break; 294c99fb5f9SBaptiste Daroussin case 't': 295c99fb5f9SBaptiste Daroussin *t++ = '\t'; 296c99fb5f9SBaptiste Daroussin break; 297c99fb5f9SBaptiste Daroussin case 'f': 298c99fb5f9SBaptiste Daroussin *t++ = '\f'; 299c99fb5f9SBaptiste Daroussin break; 300c99fb5f9SBaptiste Daroussin case '\\': 301c99fb5f9SBaptiste Daroussin *t++ = '\\'; 302c99fb5f9SBaptiste Daroussin break; 303c99fb5f9SBaptiste Daroussin case '"': 304c99fb5f9SBaptiste Daroussin *t++ = '"'; 305c99fb5f9SBaptiste Daroussin break; 306c99fb5f9SBaptiste Daroussin case 'u': 307c99fb5f9SBaptiste Daroussin /* Unicode escape */ 308c99fb5f9SBaptiste Daroussin uval = 0; 30997bd480fSBaptiste Daroussin if (len > 3) { 310c99fb5f9SBaptiste Daroussin for (i = 0; i < 4; i++) { 311c99fb5f9SBaptiste Daroussin uval <<= 4; 312c99fb5f9SBaptiste Daroussin if (isdigit (h[i])) { 313c99fb5f9SBaptiste Daroussin uval += h[i] - '0'; 314c99fb5f9SBaptiste Daroussin } 315c99fb5f9SBaptiste Daroussin else if (h[i] >= 'a' && h[i] <= 'f') { 316c99fb5f9SBaptiste Daroussin uval += h[i] - 'a' + 10; 317c99fb5f9SBaptiste Daroussin } 318c99fb5f9SBaptiste Daroussin else if (h[i] >= 'A' && h[i] <= 'F') { 319c99fb5f9SBaptiste Daroussin uval += h[i] - 'A' + 10; 320c99fb5f9SBaptiste Daroussin } 32197bd480fSBaptiste Daroussin else { 32297bd480fSBaptiste Daroussin break; 32397bd480fSBaptiste Daroussin } 324c99fb5f9SBaptiste Daroussin } 325c99fb5f9SBaptiste Daroussin h += 3; 326c99fb5f9SBaptiste Daroussin len -= 3; 327c99fb5f9SBaptiste Daroussin /* Encode */ 328c99fb5f9SBaptiste Daroussin if(uval < 0x80) { 329c99fb5f9SBaptiste Daroussin t[0] = (char)uval; 330c99fb5f9SBaptiste Daroussin t ++; 331c99fb5f9SBaptiste Daroussin } 332c99fb5f9SBaptiste Daroussin else if(uval < 0x800) { 333c99fb5f9SBaptiste Daroussin t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 334c99fb5f9SBaptiste Daroussin t[1] = 0x80 + ((uval & 0x03F)); 335c99fb5f9SBaptiste Daroussin t += 2; 336c99fb5f9SBaptiste Daroussin } 337c99fb5f9SBaptiste Daroussin else if(uval < 0x10000) { 338c99fb5f9SBaptiste Daroussin t[0] = 0xE0 + ((uval & 0xF000) >> 12); 339c99fb5f9SBaptiste Daroussin t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 340c99fb5f9SBaptiste Daroussin t[2] = 0x80 + ((uval & 0x003F)); 341c99fb5f9SBaptiste Daroussin t += 3; 342c99fb5f9SBaptiste Daroussin } 343c99fb5f9SBaptiste Daroussin else if(uval <= 0x10FFFF) { 344c99fb5f9SBaptiste Daroussin t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 345c99fb5f9SBaptiste Daroussin t[1] = 0x80 + ((uval & 0x03F000) >> 12); 346c99fb5f9SBaptiste Daroussin t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 347c99fb5f9SBaptiste Daroussin t[3] = 0x80 + ((uval & 0x00003F)); 348c99fb5f9SBaptiste Daroussin t += 4; 349c99fb5f9SBaptiste Daroussin } 350c99fb5f9SBaptiste Daroussin else { 351c99fb5f9SBaptiste Daroussin *t++ = '?'; 352c99fb5f9SBaptiste Daroussin } 35397bd480fSBaptiste Daroussin } 35497bd480fSBaptiste Daroussin else { 35597bd480fSBaptiste Daroussin *t++ = 'u'; 35697bd480fSBaptiste Daroussin } 357c99fb5f9SBaptiste Daroussin break; 358c99fb5f9SBaptiste Daroussin default: 359c99fb5f9SBaptiste Daroussin *t++ = *h; 360c99fb5f9SBaptiste Daroussin break; 361c99fb5f9SBaptiste Daroussin } 362c99fb5f9SBaptiste Daroussin h ++; 363c99fb5f9SBaptiste Daroussin len --; 364c99fb5f9SBaptiste Daroussin } 365c99fb5f9SBaptiste Daroussin else { 366c99fb5f9SBaptiste Daroussin *t++ = *h++; 367c99fb5f9SBaptiste Daroussin } 368*39ee7a7aSBaptiste Daroussin 369*39ee7a7aSBaptiste Daroussin if (len > 0) { 370c99fb5f9SBaptiste Daroussin len --; 371c99fb5f9SBaptiste Daroussin } 372*39ee7a7aSBaptiste Daroussin } 373c99fb5f9SBaptiste Daroussin *t = '\0'; 374c99fb5f9SBaptiste Daroussin 375c99fb5f9SBaptiste Daroussin return (t - str); 376c99fb5f9SBaptiste Daroussin } 377c99fb5f9SBaptiste Daroussin 378b04a7a0bSBaptiste Daroussin char * 379b04a7a0bSBaptiste Daroussin ucl_copy_key_trash (const ucl_object_t *obj) 380c99fb5f9SBaptiste Daroussin { 381b04a7a0bSBaptiste Daroussin ucl_object_t *deconst; 382b04a7a0bSBaptiste Daroussin 38397bd480fSBaptiste Daroussin if (obj == NULL) { 38497bd480fSBaptiste Daroussin return NULL; 38597bd480fSBaptiste Daroussin } 386c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 387b04a7a0bSBaptiste Daroussin deconst = __DECONST (ucl_object_t *, obj); 388b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 389b04a7a0bSBaptiste Daroussin if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 390b04a7a0bSBaptiste Daroussin memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 391b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 392c99fb5f9SBaptiste Daroussin } 393b04a7a0bSBaptiste Daroussin deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 394b04a7a0bSBaptiste Daroussin deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 395c99fb5f9SBaptiste Daroussin } 396c99fb5f9SBaptiste Daroussin 397c99fb5f9SBaptiste Daroussin return obj->trash_stack[UCL_TRASH_KEY]; 398c99fb5f9SBaptiste Daroussin } 399c99fb5f9SBaptiste Daroussin 400b04a7a0bSBaptiste Daroussin char * 401b04a7a0bSBaptiste Daroussin ucl_copy_value_trash (const ucl_object_t *obj) 402c99fb5f9SBaptiste Daroussin { 403b04a7a0bSBaptiste Daroussin ucl_object_t *deconst; 404b04a7a0bSBaptiste Daroussin 40597bd480fSBaptiste Daroussin if (obj == NULL) { 40697bd480fSBaptiste Daroussin return NULL; 40797bd480fSBaptiste Daroussin } 408c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 409b04a7a0bSBaptiste Daroussin deconst = __DECONST (ucl_object_t *, obj); 410c99fb5f9SBaptiste Daroussin if (obj->type == UCL_STRING) { 411b04a7a0bSBaptiste Daroussin 412c99fb5f9SBaptiste Daroussin /* Special case for strings */ 413*39ee7a7aSBaptiste Daroussin if (obj->flags & UCL_OBJECT_BINARY) { 414*39ee7a7aSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len); 415*39ee7a7aSBaptiste Daroussin if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 416*39ee7a7aSBaptiste Daroussin memcpy (deconst->trash_stack[UCL_TRASH_VALUE], 417*39ee7a7aSBaptiste Daroussin obj->value.sv, 418*39ee7a7aSBaptiste Daroussin obj->len); 419*39ee7a7aSBaptiste Daroussin deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 420*39ee7a7aSBaptiste Daroussin } 421*39ee7a7aSBaptiste Daroussin } 422*39ee7a7aSBaptiste Daroussin else { 423b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 424b04a7a0bSBaptiste Daroussin if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 425*39ee7a7aSBaptiste Daroussin memcpy (deconst->trash_stack[UCL_TRASH_VALUE], 426*39ee7a7aSBaptiste Daroussin obj->value.sv, 427*39ee7a7aSBaptiste Daroussin obj->len); 428b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 429b04a7a0bSBaptiste Daroussin deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 430c99fb5f9SBaptiste Daroussin } 431c99fb5f9SBaptiste Daroussin } 432*39ee7a7aSBaptiste Daroussin } 433c99fb5f9SBaptiste Daroussin else { 434c99fb5f9SBaptiste Daroussin /* Just emit value in json notation */ 435b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 436b04a7a0bSBaptiste Daroussin deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 437c99fb5f9SBaptiste Daroussin } 438b04a7a0bSBaptiste Daroussin deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 439c99fb5f9SBaptiste Daroussin } 440*39ee7a7aSBaptiste Daroussin 441c99fb5f9SBaptiste Daroussin return obj->trash_stack[UCL_TRASH_VALUE]; 442c99fb5f9SBaptiste Daroussin } 443c99fb5f9SBaptiste Daroussin 444*39ee7a7aSBaptiste Daroussin ucl_object_t* 445c99fb5f9SBaptiste Daroussin ucl_parser_get_object (struct ucl_parser *parser) 446c99fb5f9SBaptiste Daroussin { 447c99fb5f9SBaptiste Daroussin if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 448c99fb5f9SBaptiste Daroussin return ucl_object_ref (parser->top_obj); 449c99fb5f9SBaptiste Daroussin } 450c99fb5f9SBaptiste Daroussin 451c99fb5f9SBaptiste Daroussin return NULL; 452c99fb5f9SBaptiste Daroussin } 453c99fb5f9SBaptiste Daroussin 454*39ee7a7aSBaptiste Daroussin void 455c99fb5f9SBaptiste Daroussin ucl_parser_free (struct ucl_parser *parser) 456c99fb5f9SBaptiste Daroussin { 457c99fb5f9SBaptiste Daroussin struct ucl_stack *stack, *stmp; 458c99fb5f9SBaptiste Daroussin struct ucl_macro *macro, *mtmp; 459c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, *ctmp; 460c99fb5f9SBaptiste Daroussin struct ucl_pubkey *key, *ktmp; 461c99fb5f9SBaptiste Daroussin struct ucl_variable *var, *vtmp; 462*39ee7a7aSBaptiste Daroussin ucl_object_t *tr, *trtmp; 463c99fb5f9SBaptiste Daroussin 46497bd480fSBaptiste Daroussin if (parser == NULL) { 46597bd480fSBaptiste Daroussin return; 46697bd480fSBaptiste Daroussin } 46797bd480fSBaptiste Daroussin 468c99fb5f9SBaptiste Daroussin if (parser->top_obj != NULL) { 469c99fb5f9SBaptiste Daroussin ucl_object_unref (parser->top_obj); 470c99fb5f9SBaptiste Daroussin } 471c99fb5f9SBaptiste Daroussin 472*39ee7a7aSBaptiste Daroussin if (parser->includepaths != NULL) { 473*39ee7a7aSBaptiste Daroussin ucl_object_unref (parser->includepaths); 474*39ee7a7aSBaptiste Daroussin } 475*39ee7a7aSBaptiste Daroussin 476c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->stack, stack, stmp) { 477c99fb5f9SBaptiste Daroussin free (stack); 478c99fb5f9SBaptiste Daroussin } 479c99fb5f9SBaptiste Daroussin HASH_ITER (hh, parser->macroes, macro, mtmp) { 480c99fb5f9SBaptiste Daroussin free (macro->name); 481c99fb5f9SBaptiste Daroussin HASH_DEL (parser->macroes, macro); 482c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_macro), macro); 483c99fb5f9SBaptiste Daroussin } 484c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 485c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_chunk), chunk); 486c99fb5f9SBaptiste Daroussin } 487c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->keys, key, ktmp) { 488c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_pubkey), key); 489c99fb5f9SBaptiste Daroussin } 490c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->variables, var, vtmp) { 491c99fb5f9SBaptiste Daroussin free (var->value); 492c99fb5f9SBaptiste Daroussin free (var->var); 493c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_variable), var); 494c99fb5f9SBaptiste Daroussin } 495*39ee7a7aSBaptiste Daroussin LL_FOREACH_SAFE (parser->trash_objs, tr, trtmp) { 496*39ee7a7aSBaptiste Daroussin ucl_object_free_internal (tr, false, ucl_object_dtor_free); 497*39ee7a7aSBaptiste Daroussin } 498c99fb5f9SBaptiste Daroussin 499c99fb5f9SBaptiste Daroussin if (parser->err != NULL) { 500c99fb5f9SBaptiste Daroussin utstring_free (parser->err); 501c99fb5f9SBaptiste Daroussin } 502c99fb5f9SBaptiste Daroussin 5034bf54857SBaptiste Daroussin if (parser->cur_file) { 5044bf54857SBaptiste Daroussin free (parser->cur_file); 5054bf54857SBaptiste Daroussin } 5064bf54857SBaptiste Daroussin 507c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_parser), parser); 508c99fb5f9SBaptiste Daroussin } 509c99fb5f9SBaptiste Daroussin 510*39ee7a7aSBaptiste Daroussin const char * 511c99fb5f9SBaptiste Daroussin ucl_parser_get_error(struct ucl_parser *parser) 512c99fb5f9SBaptiste Daroussin { 51397bd480fSBaptiste Daroussin if (parser == NULL) { 51497bd480fSBaptiste Daroussin return NULL; 51597bd480fSBaptiste Daroussin } 51697bd480fSBaptiste Daroussin 517*39ee7a7aSBaptiste Daroussin if (parser->err == NULL) { 518c99fb5f9SBaptiste Daroussin return NULL; 519*39ee7a7aSBaptiste Daroussin } 520c99fb5f9SBaptiste Daroussin 521c99fb5f9SBaptiste Daroussin return utstring_body (parser->err); 522c99fb5f9SBaptiste Daroussin } 523c99fb5f9SBaptiste Daroussin 524*39ee7a7aSBaptiste Daroussin int 525*39ee7a7aSBaptiste Daroussin ucl_parser_get_error_code(struct ucl_parser *parser) 526*39ee7a7aSBaptiste Daroussin { 527*39ee7a7aSBaptiste Daroussin if (parser == NULL) { 528*39ee7a7aSBaptiste Daroussin return 0; 529*39ee7a7aSBaptiste Daroussin } 530*39ee7a7aSBaptiste Daroussin 531*39ee7a7aSBaptiste Daroussin return parser->err_code; 532*39ee7a7aSBaptiste Daroussin } 533*39ee7a7aSBaptiste Daroussin 534*39ee7a7aSBaptiste Daroussin unsigned 535*39ee7a7aSBaptiste Daroussin ucl_parser_get_column(struct ucl_parser *parser) 536*39ee7a7aSBaptiste Daroussin { 537*39ee7a7aSBaptiste Daroussin if (parser == NULL || parser->chunks == NULL) { 538*39ee7a7aSBaptiste Daroussin return 0; 539*39ee7a7aSBaptiste Daroussin } 540*39ee7a7aSBaptiste Daroussin 541*39ee7a7aSBaptiste Daroussin return parser->chunks->column; 542*39ee7a7aSBaptiste Daroussin } 543*39ee7a7aSBaptiste Daroussin 544*39ee7a7aSBaptiste Daroussin unsigned 545*39ee7a7aSBaptiste Daroussin ucl_parser_get_linenum(struct ucl_parser *parser) 546*39ee7a7aSBaptiste Daroussin { 547*39ee7a7aSBaptiste Daroussin if (parser == NULL || parser->chunks == NULL) { 548*39ee7a7aSBaptiste Daroussin return 0; 549*39ee7a7aSBaptiste Daroussin } 550*39ee7a7aSBaptiste Daroussin 551*39ee7a7aSBaptiste Daroussin return parser->chunks->line; 552*39ee7a7aSBaptiste Daroussin } 553*39ee7a7aSBaptiste Daroussin 554*39ee7a7aSBaptiste Daroussin void 5558e3b1ab2SBaptiste Daroussin ucl_parser_clear_error(struct ucl_parser *parser) 5568e3b1ab2SBaptiste Daroussin { 5578e3b1ab2SBaptiste Daroussin if (parser != NULL && parser->err != NULL) { 5588e3b1ab2SBaptiste Daroussin utstring_free(parser->err); 5598e3b1ab2SBaptiste Daroussin parser->err = NULL; 560*39ee7a7aSBaptiste Daroussin parser->err_code = 0; 5618e3b1ab2SBaptiste Daroussin } 5628e3b1ab2SBaptiste Daroussin } 5638e3b1ab2SBaptiste Daroussin 564*39ee7a7aSBaptiste Daroussin bool 565c99fb5f9SBaptiste Daroussin ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 566c99fb5f9SBaptiste Daroussin { 567c99fb5f9SBaptiste Daroussin #ifndef HAVE_OPENSSL 568c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot check signatures without openssl"); 569c99fb5f9SBaptiste Daroussin return false; 570c99fb5f9SBaptiste Daroussin #else 571c99fb5f9SBaptiste Daroussin # if (OPENSSL_VERSION_NUMBER < 0x10000000L) 572c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 573c99fb5f9SBaptiste Daroussin return EXIT_FAILURE; 574c99fb5f9SBaptiste Daroussin # else 575c99fb5f9SBaptiste Daroussin struct ucl_pubkey *nkey; 576c99fb5f9SBaptiste Daroussin BIO *mem; 577c99fb5f9SBaptiste Daroussin 578c99fb5f9SBaptiste Daroussin mem = BIO_new_mem_buf ((void *)key, len); 579c99fb5f9SBaptiste Daroussin nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 58097bd480fSBaptiste Daroussin if (nkey == NULL) { 58197bd480fSBaptiste Daroussin ucl_create_err (&parser->err, "cannot allocate memory for key"); 58297bd480fSBaptiste Daroussin return false; 58397bd480fSBaptiste Daroussin } 584c99fb5f9SBaptiste Daroussin nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 585c99fb5f9SBaptiste Daroussin BIO_free (mem); 586c99fb5f9SBaptiste Daroussin if (nkey->key == NULL) { 587c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_pubkey), nkey); 588c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "%s", 589c99fb5f9SBaptiste Daroussin ERR_error_string (ERR_get_error (), NULL)); 590c99fb5f9SBaptiste Daroussin return false; 591c99fb5f9SBaptiste Daroussin } 592c99fb5f9SBaptiste Daroussin LL_PREPEND (parser->keys, nkey); 593c99fb5f9SBaptiste Daroussin # endif 594c99fb5f9SBaptiste Daroussin #endif 595c99fb5f9SBaptiste Daroussin return true; 596c99fb5f9SBaptiste Daroussin } 597c99fb5f9SBaptiste Daroussin 598c99fb5f9SBaptiste Daroussin #ifdef CURL_FOUND 599c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata { 600c99fb5f9SBaptiste Daroussin unsigned char *buf; 601c99fb5f9SBaptiste Daroussin size_t buflen; 602c99fb5f9SBaptiste Daroussin }; 603c99fb5f9SBaptiste Daroussin 604c99fb5f9SBaptiste Daroussin static size_t 605c99fb5f9SBaptiste Daroussin ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 606c99fb5f9SBaptiste Daroussin { 607c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata *cbdata = ud; 608c99fb5f9SBaptiste Daroussin size_t realsize = size * nmemb; 609c99fb5f9SBaptiste Daroussin 610c99fb5f9SBaptiste Daroussin cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 611c99fb5f9SBaptiste Daroussin if (cbdata->buf == NULL) { 612c99fb5f9SBaptiste Daroussin return 0; 613c99fb5f9SBaptiste Daroussin } 614c99fb5f9SBaptiste Daroussin 615c99fb5f9SBaptiste Daroussin memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 616c99fb5f9SBaptiste Daroussin cbdata->buflen += realsize; 617c99fb5f9SBaptiste Daroussin cbdata->buf[cbdata->buflen] = 0; 618c99fb5f9SBaptiste Daroussin 619c99fb5f9SBaptiste Daroussin return realsize; 620c99fb5f9SBaptiste Daroussin } 621c99fb5f9SBaptiste Daroussin #endif 622c99fb5f9SBaptiste Daroussin 623c99fb5f9SBaptiste Daroussin /** 624c99fb5f9SBaptiste Daroussin * Fetch a url and save results to the memory buffer 625c99fb5f9SBaptiste Daroussin * @param url url to fetch 626c99fb5f9SBaptiste Daroussin * @param len length of url 627c99fb5f9SBaptiste Daroussin * @param buf target buffer 628c99fb5f9SBaptiste Daroussin * @param buflen target length 629c99fb5f9SBaptiste Daroussin * @return 630c99fb5f9SBaptiste Daroussin */ 631c99fb5f9SBaptiste Daroussin static bool 632c99fb5f9SBaptiste Daroussin ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 633c99fb5f9SBaptiste Daroussin UT_string **err, bool must_exist) 634c99fb5f9SBaptiste Daroussin { 635c99fb5f9SBaptiste Daroussin 636c99fb5f9SBaptiste Daroussin #ifdef HAVE_FETCH_H 637c99fb5f9SBaptiste Daroussin struct url *fetch_url; 638c99fb5f9SBaptiste Daroussin struct url_stat us; 639c99fb5f9SBaptiste Daroussin FILE *in; 640c99fb5f9SBaptiste Daroussin 641c99fb5f9SBaptiste Daroussin fetch_url = fetchParseURL (url); 642c99fb5f9SBaptiste Daroussin if (fetch_url == NULL) { 643c99fb5f9SBaptiste Daroussin ucl_create_err (err, "invalid URL %s: %s", 644c99fb5f9SBaptiste Daroussin url, strerror (errno)); 645c99fb5f9SBaptiste Daroussin return false; 646c99fb5f9SBaptiste Daroussin } 647c99fb5f9SBaptiste Daroussin if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 648c99fb5f9SBaptiste Daroussin if (!must_exist) { 649c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot fetch URL %s: %s", 650c99fb5f9SBaptiste Daroussin url, strerror (errno)); 651c99fb5f9SBaptiste Daroussin } 652c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 653c99fb5f9SBaptiste Daroussin return false; 654c99fb5f9SBaptiste Daroussin } 655c99fb5f9SBaptiste Daroussin 656c99fb5f9SBaptiste Daroussin *buflen = us.size; 657c99fb5f9SBaptiste Daroussin *buf = malloc (*buflen); 658c99fb5f9SBaptiste Daroussin if (*buf == NULL) { 659c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 660c99fb5f9SBaptiste Daroussin url, strerror (errno)); 661c99fb5f9SBaptiste Daroussin fclose (in); 662c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 663c99fb5f9SBaptiste Daroussin return false; 664c99fb5f9SBaptiste Daroussin } 665c99fb5f9SBaptiste Daroussin 666c99fb5f9SBaptiste Daroussin if (fread (*buf, *buflen, 1, in) != 1) { 667c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot read URL %s: %s", 668c99fb5f9SBaptiste Daroussin url, strerror (errno)); 669c99fb5f9SBaptiste Daroussin fclose (in); 670c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 671c99fb5f9SBaptiste Daroussin return false; 672c99fb5f9SBaptiste Daroussin } 673c99fb5f9SBaptiste Daroussin 674c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 675c99fb5f9SBaptiste Daroussin return true; 676c99fb5f9SBaptiste Daroussin #elif defined(CURL_FOUND) 677c99fb5f9SBaptiste Daroussin CURL *curl; 678c99fb5f9SBaptiste Daroussin int r; 679c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata cbdata; 680c99fb5f9SBaptiste Daroussin 681c99fb5f9SBaptiste Daroussin curl = curl_easy_init (); 682c99fb5f9SBaptiste Daroussin if (curl == NULL) { 683c99fb5f9SBaptiste Daroussin ucl_create_err (err, "CURL interface is broken"); 684c99fb5f9SBaptiste Daroussin return false; 685c99fb5f9SBaptiste Daroussin } 686c99fb5f9SBaptiste Daroussin if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 687c99fb5f9SBaptiste Daroussin ucl_create_err (err, "invalid URL %s: %s", 688c99fb5f9SBaptiste Daroussin url, curl_easy_strerror (r)); 689c99fb5f9SBaptiste Daroussin curl_easy_cleanup (curl); 690c99fb5f9SBaptiste Daroussin return false; 691c99fb5f9SBaptiste Daroussin } 692c99fb5f9SBaptiste Daroussin curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 693c99fb5f9SBaptiste Daroussin cbdata.buf = *buf; 694c99fb5f9SBaptiste Daroussin cbdata.buflen = *buflen; 695c99fb5f9SBaptiste Daroussin curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 696c99fb5f9SBaptiste Daroussin 697c99fb5f9SBaptiste Daroussin if ((r = curl_easy_perform (curl)) != CURLE_OK) { 698c99fb5f9SBaptiste Daroussin if (!must_exist) { 699c99fb5f9SBaptiste Daroussin ucl_create_err (err, "error fetching URL %s: %s", 700c99fb5f9SBaptiste Daroussin url, curl_easy_strerror (r)); 701c99fb5f9SBaptiste Daroussin } 702c99fb5f9SBaptiste Daroussin curl_easy_cleanup (curl); 703c99fb5f9SBaptiste Daroussin if (cbdata.buf) { 704c99fb5f9SBaptiste Daroussin free (cbdata.buf); 705c99fb5f9SBaptiste Daroussin } 706c99fb5f9SBaptiste Daroussin return false; 707c99fb5f9SBaptiste Daroussin } 708c99fb5f9SBaptiste Daroussin *buf = cbdata.buf; 709c99fb5f9SBaptiste Daroussin *buflen = cbdata.buflen; 710c99fb5f9SBaptiste Daroussin 711c99fb5f9SBaptiste Daroussin return true; 712c99fb5f9SBaptiste Daroussin #else 713c99fb5f9SBaptiste Daroussin ucl_create_err (err, "URL support is disabled"); 714c99fb5f9SBaptiste Daroussin return false; 715c99fb5f9SBaptiste Daroussin #endif 716c99fb5f9SBaptiste Daroussin } 717c99fb5f9SBaptiste Daroussin 718c99fb5f9SBaptiste Daroussin /** 719c99fb5f9SBaptiste Daroussin * Fetch a file and save results to the memory buffer 720c99fb5f9SBaptiste Daroussin * @param filename filename to fetch 721c99fb5f9SBaptiste Daroussin * @param len length of filename 722c99fb5f9SBaptiste Daroussin * @param buf target buffer 723c99fb5f9SBaptiste Daroussin * @param buflen target length 724c99fb5f9SBaptiste Daroussin * @return 725c99fb5f9SBaptiste Daroussin */ 726c99fb5f9SBaptiste Daroussin static bool 727c99fb5f9SBaptiste Daroussin ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 728c99fb5f9SBaptiste Daroussin UT_string **err, bool must_exist) 729c99fb5f9SBaptiste Daroussin { 730c99fb5f9SBaptiste Daroussin int fd; 731c99fb5f9SBaptiste Daroussin struct stat st; 732c99fb5f9SBaptiste Daroussin 733c99fb5f9SBaptiste Daroussin if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 734c99fb5f9SBaptiste Daroussin if (must_exist) { 735c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot stat file %s: %s", 736c99fb5f9SBaptiste Daroussin filename, strerror (errno)); 737c99fb5f9SBaptiste Daroussin } 738c99fb5f9SBaptiste Daroussin return false; 739c99fb5f9SBaptiste Daroussin } 740c99fb5f9SBaptiste Daroussin if (st.st_size == 0) { 741c99fb5f9SBaptiste Daroussin /* Do not map empty files */ 742c99fb5f9SBaptiste Daroussin *buf = ""; 743c99fb5f9SBaptiste Daroussin *buflen = 0; 744c99fb5f9SBaptiste Daroussin } 745c99fb5f9SBaptiste Daroussin else { 746c99fb5f9SBaptiste Daroussin if ((fd = open (filename, O_RDONLY)) == -1) { 747c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot open file %s: %s", 748c99fb5f9SBaptiste Daroussin filename, strerror (errno)); 749c99fb5f9SBaptiste Daroussin return false; 750c99fb5f9SBaptiste Daroussin } 75197bd480fSBaptiste Daroussin if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 752c99fb5f9SBaptiste Daroussin close (fd); 753c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot mmap file %s: %s", 754c99fb5f9SBaptiste Daroussin filename, strerror (errno)); 755c99fb5f9SBaptiste Daroussin return false; 756c99fb5f9SBaptiste Daroussin } 757c99fb5f9SBaptiste Daroussin *buflen = st.st_size; 758c99fb5f9SBaptiste Daroussin close (fd); 759c99fb5f9SBaptiste Daroussin } 760c99fb5f9SBaptiste Daroussin 761c99fb5f9SBaptiste Daroussin return true; 762c99fb5f9SBaptiste Daroussin } 763c99fb5f9SBaptiste Daroussin 764c99fb5f9SBaptiste Daroussin 765c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 766c99fb5f9SBaptiste Daroussin static inline bool 767c99fb5f9SBaptiste Daroussin ucl_sig_check (const unsigned char *data, size_t datalen, 768c99fb5f9SBaptiste Daroussin const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 769c99fb5f9SBaptiste Daroussin { 770c99fb5f9SBaptiste Daroussin struct ucl_pubkey *key; 771c99fb5f9SBaptiste Daroussin char dig[EVP_MAX_MD_SIZE]; 772c99fb5f9SBaptiste Daroussin unsigned int diglen; 773c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX *key_ctx; 774c99fb5f9SBaptiste Daroussin EVP_MD_CTX *sign_ctx = NULL; 775c99fb5f9SBaptiste Daroussin 776c99fb5f9SBaptiste Daroussin sign_ctx = EVP_MD_CTX_create (); 777c99fb5f9SBaptiste Daroussin 778c99fb5f9SBaptiste Daroussin LL_FOREACH (parser->keys, key) { 779c99fb5f9SBaptiste Daroussin key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 780c99fb5f9SBaptiste Daroussin if (key_ctx != NULL) { 781c99fb5f9SBaptiste Daroussin if (EVP_PKEY_verify_init (key_ctx) <= 0) { 782c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 783c99fb5f9SBaptiste Daroussin continue; 784c99fb5f9SBaptiste Daroussin } 785c99fb5f9SBaptiste Daroussin if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 786c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 787c99fb5f9SBaptiste Daroussin continue; 788c99fb5f9SBaptiste Daroussin } 789c99fb5f9SBaptiste Daroussin if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 790c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 791c99fb5f9SBaptiste Daroussin continue; 792c99fb5f9SBaptiste Daroussin } 793c99fb5f9SBaptiste Daroussin EVP_DigestInit (sign_ctx, EVP_sha256 ()); 794c99fb5f9SBaptiste Daroussin EVP_DigestUpdate (sign_ctx, data, datalen); 795c99fb5f9SBaptiste Daroussin EVP_DigestFinal (sign_ctx, dig, &diglen); 796c99fb5f9SBaptiste Daroussin 797c99fb5f9SBaptiste Daroussin if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 798c99fb5f9SBaptiste Daroussin EVP_MD_CTX_destroy (sign_ctx); 799c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 800c99fb5f9SBaptiste Daroussin return true; 801c99fb5f9SBaptiste Daroussin } 802c99fb5f9SBaptiste Daroussin 803c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 804c99fb5f9SBaptiste Daroussin } 805c99fb5f9SBaptiste Daroussin } 806c99fb5f9SBaptiste Daroussin 807c99fb5f9SBaptiste Daroussin EVP_MD_CTX_destroy (sign_ctx); 808c99fb5f9SBaptiste Daroussin 809c99fb5f9SBaptiste Daroussin return false; 810c99fb5f9SBaptiste Daroussin } 811c99fb5f9SBaptiste Daroussin #endif 812c99fb5f9SBaptiste Daroussin 813*39ee7a7aSBaptiste Daroussin struct ucl_include_params { 814*39ee7a7aSBaptiste Daroussin bool check_signature; 815*39ee7a7aSBaptiste Daroussin bool must_exist; 816*39ee7a7aSBaptiste Daroussin bool use_glob; 817*39ee7a7aSBaptiste Daroussin bool use_prefix; 818*39ee7a7aSBaptiste Daroussin bool soft_fail; 819*39ee7a7aSBaptiste Daroussin bool allow_glob; 820*39ee7a7aSBaptiste Daroussin unsigned priority; 821*39ee7a7aSBaptiste Daroussin enum ucl_duplicate_strategy strat; 822*39ee7a7aSBaptiste Daroussin enum ucl_parse_type parse_type; 823*39ee7a7aSBaptiste Daroussin const char *prefix; 824*39ee7a7aSBaptiste Daroussin const char *target; 825*39ee7a7aSBaptiste Daroussin }; 826*39ee7a7aSBaptiste Daroussin 827c99fb5f9SBaptiste Daroussin /** 828c99fb5f9SBaptiste Daroussin * Include an url to configuration 829c99fb5f9SBaptiste Daroussin * @param data 830c99fb5f9SBaptiste Daroussin * @param len 831c99fb5f9SBaptiste Daroussin * @param parser 832c99fb5f9SBaptiste Daroussin * @param err 833c99fb5f9SBaptiste Daroussin * @return 834c99fb5f9SBaptiste Daroussin */ 835c99fb5f9SBaptiste Daroussin static bool 836c99fb5f9SBaptiste Daroussin ucl_include_url (const unsigned char *data, size_t len, 837*39ee7a7aSBaptiste Daroussin struct ucl_parser *parser, 838*39ee7a7aSBaptiste Daroussin struct ucl_include_params *params) 839c99fb5f9SBaptiste Daroussin { 840c99fb5f9SBaptiste Daroussin 841c99fb5f9SBaptiste Daroussin bool res; 842c99fb5f9SBaptiste Daroussin unsigned char *buf = NULL; 843c99fb5f9SBaptiste Daroussin size_t buflen = 0; 844c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk; 845c99fb5f9SBaptiste Daroussin char urlbuf[PATH_MAX]; 846c99fb5f9SBaptiste Daroussin int prev_state; 847c99fb5f9SBaptiste Daroussin 848c99fb5f9SBaptiste Daroussin snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 849c99fb5f9SBaptiste Daroussin 850*39ee7a7aSBaptiste Daroussin if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) { 851*39ee7a7aSBaptiste Daroussin return (!params->must_exist || false); 852c99fb5f9SBaptiste Daroussin } 853c99fb5f9SBaptiste Daroussin 854*39ee7a7aSBaptiste Daroussin if (params->check_signature) { 855c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 856c99fb5f9SBaptiste Daroussin unsigned char *sigbuf = NULL; 857c99fb5f9SBaptiste Daroussin size_t siglen = 0; 858c99fb5f9SBaptiste Daroussin /* We need to check signature first */ 859c99fb5f9SBaptiste Daroussin snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 860c99fb5f9SBaptiste Daroussin if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 861c99fb5f9SBaptiste Daroussin return false; 862c99fb5f9SBaptiste Daroussin } 863c99fb5f9SBaptiste Daroussin if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 864c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot verify url %s: %s", 865c99fb5f9SBaptiste Daroussin urlbuf, 866c99fb5f9SBaptiste Daroussin ERR_error_string (ERR_get_error (), NULL)); 867c99fb5f9SBaptiste Daroussin if (siglen > 0) { 86897bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 869c99fb5f9SBaptiste Daroussin } 870c99fb5f9SBaptiste Daroussin return false; 871c99fb5f9SBaptiste Daroussin } 872c99fb5f9SBaptiste Daroussin if (siglen > 0) { 87397bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 874c99fb5f9SBaptiste Daroussin } 875c99fb5f9SBaptiste Daroussin #endif 876c99fb5f9SBaptiste Daroussin } 877c99fb5f9SBaptiste Daroussin 878c99fb5f9SBaptiste Daroussin prev_state = parser->state; 879c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_INIT; 880c99fb5f9SBaptiste Daroussin 881*39ee7a7aSBaptiste Daroussin res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, 882*39ee7a7aSBaptiste Daroussin params->strat, params->parse_type); 883c99fb5f9SBaptiste Daroussin if (res == true) { 884c99fb5f9SBaptiste Daroussin /* Remove chunk from the stack */ 885c99fb5f9SBaptiste Daroussin chunk = parser->chunks; 886c99fb5f9SBaptiste Daroussin if (chunk != NULL) { 887c99fb5f9SBaptiste Daroussin parser->chunks = chunk->next; 888c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_chunk), chunk); 889c99fb5f9SBaptiste Daroussin } 890c99fb5f9SBaptiste Daroussin } 891c99fb5f9SBaptiste Daroussin 892c99fb5f9SBaptiste Daroussin parser->state = prev_state; 893c99fb5f9SBaptiste Daroussin free (buf); 894c99fb5f9SBaptiste Daroussin 895c99fb5f9SBaptiste Daroussin return res; 896c99fb5f9SBaptiste Daroussin } 897c99fb5f9SBaptiste Daroussin 898c99fb5f9SBaptiste Daroussin /** 8994bf54857SBaptiste Daroussin * Include a single file to the parser 900c99fb5f9SBaptiste Daroussin * @param data 901c99fb5f9SBaptiste Daroussin * @param len 902c99fb5f9SBaptiste Daroussin * @param parser 9034bf54857SBaptiste Daroussin * @param check_signature 9044bf54857SBaptiste Daroussin * @param must_exist 9054bf54857SBaptiste Daroussin * @param allow_glob 9064bf54857SBaptiste Daroussin * @param priority 907c99fb5f9SBaptiste Daroussin * @return 908c99fb5f9SBaptiste Daroussin */ 909c99fb5f9SBaptiste Daroussin static bool 9104bf54857SBaptiste Daroussin ucl_include_file_single (const unsigned char *data, size_t len, 911*39ee7a7aSBaptiste Daroussin struct ucl_parser *parser, struct ucl_include_params *params) 912c99fb5f9SBaptiste Daroussin { 913c99fb5f9SBaptiste Daroussin bool res; 914c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk; 915c99fb5f9SBaptiste Daroussin unsigned char *buf = NULL; 916*39ee7a7aSBaptiste Daroussin char *old_curfile, *ext; 917*39ee7a7aSBaptiste Daroussin size_t buflen = 0; 918c99fb5f9SBaptiste Daroussin char filebuf[PATH_MAX], realbuf[PATH_MAX]; 919c99fb5f9SBaptiste Daroussin int prev_state; 9204bf54857SBaptiste Daroussin struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL, 9214bf54857SBaptiste Daroussin *old_filename = NULL; 922*39ee7a7aSBaptiste Daroussin ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL; 923*39ee7a7aSBaptiste Daroussin ucl_hash_t *container = NULL; 924*39ee7a7aSBaptiste Daroussin struct ucl_stack *st = NULL; 925c99fb5f9SBaptiste Daroussin 926c99fb5f9SBaptiste Daroussin snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 92797bd480fSBaptiste Daroussin if (ucl_realpath (filebuf, realbuf) == NULL) { 928*39ee7a7aSBaptiste Daroussin if (params->soft_fail) { 929*39ee7a7aSBaptiste Daroussin return false; 930*39ee7a7aSBaptiste Daroussin } 931*39ee7a7aSBaptiste Daroussin if (!params->must_exist) { 932c99fb5f9SBaptiste Daroussin return true; 933c99fb5f9SBaptiste Daroussin } 934c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot open file %s: %s", 935c99fb5f9SBaptiste Daroussin filebuf, 936c99fb5f9SBaptiste Daroussin strerror (errno)); 937c99fb5f9SBaptiste Daroussin return false; 938c99fb5f9SBaptiste Daroussin } 939c99fb5f9SBaptiste Daroussin 9404bf54857SBaptiste Daroussin if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) { 9414bf54857SBaptiste Daroussin /* We are likely including the file itself */ 942*39ee7a7aSBaptiste Daroussin if (params->soft_fail) { 943*39ee7a7aSBaptiste Daroussin return false; 944*39ee7a7aSBaptiste Daroussin } 945*39ee7a7aSBaptiste Daroussin 9464bf54857SBaptiste Daroussin ucl_create_err (&parser->err, "trying to include the file %s from itself", 9474bf54857SBaptiste Daroussin realbuf); 9484bf54857SBaptiste Daroussin return false; 9494bf54857SBaptiste Daroussin } 9504bf54857SBaptiste Daroussin 951*39ee7a7aSBaptiste Daroussin if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, params->must_exist)) { 952*39ee7a7aSBaptiste Daroussin if (params->soft_fail) { 953*39ee7a7aSBaptiste Daroussin return false; 954*39ee7a7aSBaptiste Daroussin } 955*39ee7a7aSBaptiste Daroussin return (!params->must_exist || false); 956c99fb5f9SBaptiste Daroussin } 957c99fb5f9SBaptiste Daroussin 958*39ee7a7aSBaptiste Daroussin if (params->check_signature) { 959c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 960c99fb5f9SBaptiste Daroussin unsigned char *sigbuf = NULL; 961c99fb5f9SBaptiste Daroussin size_t siglen = 0; 962c99fb5f9SBaptiste Daroussin /* We need to check signature first */ 963c99fb5f9SBaptiste Daroussin snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 964c99fb5f9SBaptiste Daroussin if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 965c99fb5f9SBaptiste Daroussin return false; 966c99fb5f9SBaptiste Daroussin } 967c99fb5f9SBaptiste Daroussin if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 968c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot verify file %s: %s", 969c99fb5f9SBaptiste Daroussin filebuf, 970c99fb5f9SBaptiste Daroussin ERR_error_string (ERR_get_error (), NULL)); 971c99fb5f9SBaptiste Daroussin if (siglen > 0) { 97297bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 973c99fb5f9SBaptiste Daroussin } 974c99fb5f9SBaptiste Daroussin return false; 975c99fb5f9SBaptiste Daroussin } 976c99fb5f9SBaptiste Daroussin if (siglen > 0) { 97797bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 978c99fb5f9SBaptiste Daroussin } 979c99fb5f9SBaptiste Daroussin #endif 980c99fb5f9SBaptiste Daroussin } 981c99fb5f9SBaptiste Daroussin 9824bf54857SBaptiste Daroussin old_curfile = parser->cur_file; 9834bf54857SBaptiste Daroussin parser->cur_file = strdup (realbuf); 9844bf54857SBaptiste Daroussin 9854bf54857SBaptiste Daroussin /* Store old file vars */ 9864bf54857SBaptiste Daroussin DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 9874bf54857SBaptiste Daroussin if (strcmp (cur_var->var, "CURDIR") == 0) { 9884bf54857SBaptiste Daroussin old_curdir = cur_var; 9894bf54857SBaptiste Daroussin DL_DELETE (parser->variables, cur_var); 9904bf54857SBaptiste Daroussin } 9914bf54857SBaptiste Daroussin else if (strcmp (cur_var->var, "FILENAME") == 0) { 9924bf54857SBaptiste Daroussin old_filename = cur_var; 9934bf54857SBaptiste Daroussin DL_DELETE (parser->variables, cur_var); 9944bf54857SBaptiste Daroussin } 9954bf54857SBaptiste Daroussin } 9964bf54857SBaptiste Daroussin 997c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (parser, realbuf, false); 998c99fb5f9SBaptiste Daroussin 999c99fb5f9SBaptiste Daroussin prev_state = parser->state; 1000c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_INIT; 1001c99fb5f9SBaptiste Daroussin 1002*39ee7a7aSBaptiste Daroussin if (params->use_prefix && params->prefix == NULL) { 1003*39ee7a7aSBaptiste Daroussin /* Auto generate a key name based on the included filename */ 1004*39ee7a7aSBaptiste Daroussin params->prefix = basename (realbuf); 1005*39ee7a7aSBaptiste Daroussin ext = strrchr (params->prefix, '.'); 1006*39ee7a7aSBaptiste Daroussin if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) { 1007*39ee7a7aSBaptiste Daroussin /* Strip off .conf or .ucl */ 1008*39ee7a7aSBaptiste Daroussin *ext = '\0'; 1009*39ee7a7aSBaptiste Daroussin } 1010*39ee7a7aSBaptiste Daroussin } 1011*39ee7a7aSBaptiste Daroussin if (params->prefix != NULL) { 1012*39ee7a7aSBaptiste Daroussin /* This is a prefixed include */ 1013*39ee7a7aSBaptiste Daroussin container = parser->stack->obj->value.ov; 1014*39ee7a7aSBaptiste Daroussin 1015*39ee7a7aSBaptiste Daroussin old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, 1016*39ee7a7aSBaptiste Daroussin params->prefix, strlen (params->prefix))); 1017*39ee7a7aSBaptiste Daroussin 1018*39ee7a7aSBaptiste Daroussin if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) { 1019*39ee7a7aSBaptiste Daroussin /* Create an array with key: prefix */ 1020*39ee7a7aSBaptiste Daroussin old_obj = ucl_object_new_full (UCL_ARRAY, params->priority); 1021*39ee7a7aSBaptiste Daroussin old_obj->key = params->prefix; 1022*39ee7a7aSBaptiste Daroussin old_obj->keylen = strlen (params->prefix); 1023*39ee7a7aSBaptiste Daroussin ucl_copy_key_trash(old_obj); 1024*39ee7a7aSBaptiste Daroussin old_obj->prev = old_obj; 1025*39ee7a7aSBaptiste Daroussin old_obj->next = NULL; 1026*39ee7a7aSBaptiste Daroussin 1027*39ee7a7aSBaptiste Daroussin container = ucl_hash_insert_object (container, old_obj, 1028*39ee7a7aSBaptiste Daroussin parser->flags & UCL_PARSER_KEY_LOWERCASE); 1029*39ee7a7aSBaptiste Daroussin parser->stack->obj->len ++; 1030*39ee7a7aSBaptiste Daroussin 1031*39ee7a7aSBaptiste Daroussin nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1032*39ee7a7aSBaptiste Daroussin nest_obj->prev = nest_obj; 1033*39ee7a7aSBaptiste Daroussin nest_obj->next = NULL; 1034*39ee7a7aSBaptiste Daroussin 1035*39ee7a7aSBaptiste Daroussin ucl_array_append (old_obj, nest_obj); 1036*39ee7a7aSBaptiste Daroussin } 1037*39ee7a7aSBaptiste Daroussin else if (old_obj == NULL) { 1038*39ee7a7aSBaptiste Daroussin /* Create an object with key: prefix */ 1039*39ee7a7aSBaptiste Daroussin nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1040*39ee7a7aSBaptiste Daroussin nest_obj->key = params->prefix; 1041*39ee7a7aSBaptiste Daroussin nest_obj->keylen = strlen (params->prefix); 1042*39ee7a7aSBaptiste Daroussin ucl_copy_key_trash(nest_obj); 1043*39ee7a7aSBaptiste Daroussin nest_obj->prev = nest_obj; 1044*39ee7a7aSBaptiste Daroussin nest_obj->next = NULL; 1045*39ee7a7aSBaptiste Daroussin 1046*39ee7a7aSBaptiste Daroussin container = ucl_hash_insert_object (container, nest_obj, 1047*39ee7a7aSBaptiste Daroussin parser->flags & UCL_PARSER_KEY_LOWERCASE); 1048*39ee7a7aSBaptiste Daroussin parser->stack->obj->len ++; 1049*39ee7a7aSBaptiste Daroussin } 1050*39ee7a7aSBaptiste Daroussin else if (strcasecmp (params->target, "array") == 0 || 1051*39ee7a7aSBaptiste Daroussin ucl_object_type(old_obj) == UCL_ARRAY) { 1052*39ee7a7aSBaptiste Daroussin if (ucl_object_type(old_obj) == UCL_ARRAY) { 1053*39ee7a7aSBaptiste Daroussin /* Append to the existing array */ 1054*39ee7a7aSBaptiste Daroussin nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1055*39ee7a7aSBaptiste Daroussin nest_obj->prev = nest_obj; 1056*39ee7a7aSBaptiste Daroussin nest_obj->next = NULL; 1057*39ee7a7aSBaptiste Daroussin 1058*39ee7a7aSBaptiste Daroussin ucl_array_append (old_obj, nest_obj); 1059*39ee7a7aSBaptiste Daroussin } 1060*39ee7a7aSBaptiste Daroussin else { 1061*39ee7a7aSBaptiste Daroussin /* Convert the object to an array */ 1062*39ee7a7aSBaptiste Daroussin new_obj = ucl_object_typed_new (UCL_ARRAY); 1063*39ee7a7aSBaptiste Daroussin new_obj->key = old_obj->key; 1064*39ee7a7aSBaptiste Daroussin new_obj->keylen = old_obj->keylen; 1065*39ee7a7aSBaptiste Daroussin new_obj->flags |= UCL_OBJECT_MULTIVALUE; 1066*39ee7a7aSBaptiste Daroussin new_obj->prev = new_obj; 1067*39ee7a7aSBaptiste Daroussin new_obj->next = NULL; 1068*39ee7a7aSBaptiste Daroussin 1069*39ee7a7aSBaptiste Daroussin nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1070*39ee7a7aSBaptiste Daroussin nest_obj->prev = nest_obj; 1071*39ee7a7aSBaptiste Daroussin nest_obj->next = NULL; 1072*39ee7a7aSBaptiste Daroussin 1073*39ee7a7aSBaptiste Daroussin ucl_array_append (new_obj, old_obj); 1074*39ee7a7aSBaptiste Daroussin ucl_array_append (new_obj, nest_obj); 1075*39ee7a7aSBaptiste Daroussin ucl_hash_replace (container, old_obj, new_obj); 1076*39ee7a7aSBaptiste Daroussin } 1077*39ee7a7aSBaptiste Daroussin } 1078*39ee7a7aSBaptiste Daroussin else { 1079*39ee7a7aSBaptiste Daroussin if (ucl_object_type (old_obj) == UCL_OBJECT) { 1080*39ee7a7aSBaptiste Daroussin /* Append to existing Object*/ 1081*39ee7a7aSBaptiste Daroussin nest_obj = old_obj; 1082*39ee7a7aSBaptiste Daroussin } 1083*39ee7a7aSBaptiste Daroussin else { 1084*39ee7a7aSBaptiste Daroussin /* The key is not an object */ 1085*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, 1086*39ee7a7aSBaptiste Daroussin "Conflicting type for key: %s", 1087*39ee7a7aSBaptiste Daroussin params->prefix); 1088*39ee7a7aSBaptiste Daroussin return false; 1089*39ee7a7aSBaptiste Daroussin } 1090*39ee7a7aSBaptiste Daroussin } 1091*39ee7a7aSBaptiste Daroussin 1092*39ee7a7aSBaptiste Daroussin /* Put all of the content of the include inside that object */ 1093*39ee7a7aSBaptiste Daroussin parser->stack->obj->value.ov = container; 1094*39ee7a7aSBaptiste Daroussin 1095*39ee7a7aSBaptiste Daroussin if (nest_obj != NULL) { 1096*39ee7a7aSBaptiste Daroussin st = UCL_ALLOC (sizeof (struct ucl_stack)); 1097*39ee7a7aSBaptiste Daroussin if (st == NULL) { 1098*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1099*39ee7a7aSBaptiste Daroussin ucl_object_unref (nest_obj); 1100*39ee7a7aSBaptiste Daroussin return NULL; 1101*39ee7a7aSBaptiste Daroussin } 1102*39ee7a7aSBaptiste Daroussin st->obj = nest_obj; 1103*39ee7a7aSBaptiste Daroussin st->level = parser->stack->level; 1104*39ee7a7aSBaptiste Daroussin LL_PREPEND (parser->stack, st); 1105*39ee7a7aSBaptiste Daroussin parser->cur_obj = nest_obj; 1106*39ee7a7aSBaptiste Daroussin } 1107*39ee7a7aSBaptiste Daroussin } 1108*39ee7a7aSBaptiste Daroussin 1109*39ee7a7aSBaptiste Daroussin res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, 1110*39ee7a7aSBaptiste Daroussin params->strat, params->parse_type); 1111*39ee7a7aSBaptiste Daroussin if (!res && !params->must_exist) { 11124bf54857SBaptiste Daroussin /* Free error */ 11134bf54857SBaptiste Daroussin utstring_free (parser->err); 11144bf54857SBaptiste Daroussin parser->err = NULL; 11154bf54857SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 11164bf54857SBaptiste Daroussin } 11174bf54857SBaptiste Daroussin 1118*39ee7a7aSBaptiste Daroussin /* Stop nesting the include, take 1 level off the stack */ 1119*39ee7a7aSBaptiste Daroussin if (params->prefix != NULL && nest_obj != NULL) { 1120*39ee7a7aSBaptiste Daroussin parser->stack = st->next; 1121*39ee7a7aSBaptiste Daroussin UCL_FREE (sizeof (struct ucl_stack), st); 1122*39ee7a7aSBaptiste Daroussin } 1123*39ee7a7aSBaptiste Daroussin 1124c99fb5f9SBaptiste Daroussin /* Remove chunk from the stack */ 1125c99fb5f9SBaptiste Daroussin chunk = parser->chunks; 1126c99fb5f9SBaptiste Daroussin if (chunk != NULL) { 1127c99fb5f9SBaptiste Daroussin parser->chunks = chunk->next; 1128c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_chunk), chunk); 11294bf54857SBaptiste Daroussin parser->recursion --; 1130c99fb5f9SBaptiste Daroussin } 11314bf54857SBaptiste Daroussin 11324bf54857SBaptiste Daroussin /* Restore old file vars */ 1133*39ee7a7aSBaptiste Daroussin if (parser->cur_file) { 1134*39ee7a7aSBaptiste Daroussin free (parser->cur_file); 1135*39ee7a7aSBaptiste Daroussin } 1136*39ee7a7aSBaptiste Daroussin 11374bf54857SBaptiste Daroussin parser->cur_file = old_curfile; 11384bf54857SBaptiste Daroussin DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 11394bf54857SBaptiste Daroussin if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) { 11404bf54857SBaptiste Daroussin DL_DELETE (parser->variables, cur_var); 11414bf54857SBaptiste Daroussin free (cur_var->var); 11424bf54857SBaptiste Daroussin free (cur_var->value); 11434bf54857SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_variable), cur_var); 11444bf54857SBaptiste Daroussin } 11454bf54857SBaptiste Daroussin else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) { 11464bf54857SBaptiste Daroussin DL_DELETE (parser->variables, cur_var); 11474bf54857SBaptiste Daroussin free (cur_var->var); 11484bf54857SBaptiste Daroussin free (cur_var->value); 11494bf54857SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_variable), cur_var); 11504bf54857SBaptiste Daroussin } 11514bf54857SBaptiste Daroussin } 11524bf54857SBaptiste Daroussin if (old_filename) { 11534bf54857SBaptiste Daroussin DL_APPEND (parser->variables, old_filename); 11544bf54857SBaptiste Daroussin } 11554bf54857SBaptiste Daroussin if (old_curdir) { 11564bf54857SBaptiste Daroussin DL_APPEND (parser->variables, old_curdir); 11574bf54857SBaptiste Daroussin } 1158c99fb5f9SBaptiste Daroussin 1159c99fb5f9SBaptiste Daroussin parser->state = prev_state; 1160c99fb5f9SBaptiste Daroussin 1161c99fb5f9SBaptiste Daroussin if (buflen > 0) { 116297bd480fSBaptiste Daroussin ucl_munmap (buf, buflen); 1163c99fb5f9SBaptiste Daroussin } 1164c99fb5f9SBaptiste Daroussin 1165c99fb5f9SBaptiste Daroussin return res; 1166c99fb5f9SBaptiste Daroussin } 1167c99fb5f9SBaptiste Daroussin 1168c99fb5f9SBaptiste Daroussin /** 11694bf54857SBaptiste Daroussin * Include a file to configuration 11704bf54857SBaptiste Daroussin * @param data 11714bf54857SBaptiste Daroussin * @param len 11724bf54857SBaptiste Daroussin * @param parser 11734bf54857SBaptiste Daroussin * @param err 11744bf54857SBaptiste Daroussin * @return 11754bf54857SBaptiste Daroussin */ 11764bf54857SBaptiste Daroussin static bool 11774bf54857SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len, 1178*39ee7a7aSBaptiste Daroussin struct ucl_parser *parser, struct ucl_include_params *params) 11794bf54857SBaptiste Daroussin { 11804bf54857SBaptiste Daroussin const unsigned char *p = data, *end = data + len; 11814bf54857SBaptiste Daroussin bool need_glob = false; 11824bf54857SBaptiste Daroussin int cnt = 0; 11834bf54857SBaptiste Daroussin char glob_pattern[PATH_MAX]; 11844bf54857SBaptiste Daroussin size_t i; 11854bf54857SBaptiste Daroussin 11868e3b1ab2SBaptiste Daroussin #ifndef _WIN32 1187*39ee7a7aSBaptiste Daroussin if (!params->allow_glob) { 1188*39ee7a7aSBaptiste Daroussin return ucl_include_file_single (data, len, parser, params); 11894bf54857SBaptiste Daroussin } 11904bf54857SBaptiste Daroussin else { 11914bf54857SBaptiste Daroussin /* Check for special symbols in a filename */ 11924bf54857SBaptiste Daroussin while (p != end) { 11934bf54857SBaptiste Daroussin if (*p == '*' || *p == '?') { 11944bf54857SBaptiste Daroussin need_glob = true; 11954bf54857SBaptiste Daroussin break; 11964bf54857SBaptiste Daroussin } 11974bf54857SBaptiste Daroussin p ++; 11984bf54857SBaptiste Daroussin } 11994bf54857SBaptiste Daroussin if (need_glob) { 12008e3b1ab2SBaptiste Daroussin glob_t globbuf; 12014bf54857SBaptiste Daroussin memset (&globbuf, 0, sizeof (globbuf)); 1202*39ee7a7aSBaptiste Daroussin ucl_strlcpy (glob_pattern, (const char *)data, 1203*39ee7a7aSBaptiste Daroussin (len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern))); 12044bf54857SBaptiste Daroussin if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { 1205*39ee7a7aSBaptiste Daroussin return (!params->must_exist || false); 12064bf54857SBaptiste Daroussin } 12074bf54857SBaptiste Daroussin for (i = 0; i < globbuf.gl_pathc; i ++) { 12084bf54857SBaptiste Daroussin if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i], 1209*39ee7a7aSBaptiste Daroussin strlen (globbuf.gl_pathv[i]), parser, params)) { 1210*39ee7a7aSBaptiste Daroussin if (params->soft_fail) { 1211*39ee7a7aSBaptiste Daroussin continue; 1212*39ee7a7aSBaptiste Daroussin } 12134bf54857SBaptiste Daroussin globfree (&globbuf); 12144bf54857SBaptiste Daroussin return false; 12154bf54857SBaptiste Daroussin } 12164bf54857SBaptiste Daroussin cnt ++; 12174bf54857SBaptiste Daroussin } 12184bf54857SBaptiste Daroussin globfree (&globbuf); 12194bf54857SBaptiste Daroussin 1220*39ee7a7aSBaptiste Daroussin if (cnt == 0 && params->must_exist) { 12214bf54857SBaptiste Daroussin ucl_create_err (&parser->err, "cannot match any files for pattern %s", 12224bf54857SBaptiste Daroussin glob_pattern); 12234bf54857SBaptiste Daroussin return false; 12244bf54857SBaptiste Daroussin } 12254bf54857SBaptiste Daroussin } 12264bf54857SBaptiste Daroussin else { 1227*39ee7a7aSBaptiste Daroussin return ucl_include_file_single (data, len, parser, params); 12284bf54857SBaptiste Daroussin } 12294bf54857SBaptiste Daroussin } 12308e3b1ab2SBaptiste Daroussin #else 12318e3b1ab2SBaptiste Daroussin /* Win32 compilers do not support globbing. Therefore, for Win32, 12328e3b1ab2SBaptiste Daroussin treat allow_glob/need_glob as a NOOP and just return */ 1233*39ee7a7aSBaptiste Daroussin return ucl_include_file_single (data, len, parser, params); 12348e3b1ab2SBaptiste Daroussin #endif 12354bf54857SBaptiste Daroussin 12364bf54857SBaptiste Daroussin return true; 12374bf54857SBaptiste Daroussin } 12384bf54857SBaptiste Daroussin 12394bf54857SBaptiste Daroussin /** 12404bf54857SBaptiste Daroussin * Common function to handle .*include* macros 12414bf54857SBaptiste Daroussin * @param data 12424bf54857SBaptiste Daroussin * @param len 12434bf54857SBaptiste Daroussin * @param args 12444bf54857SBaptiste Daroussin * @param parser 12454bf54857SBaptiste Daroussin * @param default_try 12464bf54857SBaptiste Daroussin * @param default_sign 12474bf54857SBaptiste Daroussin * @return 12484bf54857SBaptiste Daroussin */ 12494bf54857SBaptiste Daroussin static bool 12504bf54857SBaptiste Daroussin ucl_include_common (const unsigned char *data, size_t len, 12514bf54857SBaptiste Daroussin const ucl_object_t *args, struct ucl_parser *parser, 12524bf54857SBaptiste Daroussin bool default_try, 12534bf54857SBaptiste Daroussin bool default_sign) 12544bf54857SBaptiste Daroussin { 1255*39ee7a7aSBaptiste Daroussin bool allow_url, search; 1256*39ee7a7aSBaptiste Daroussin const char *duplicate; 12574bf54857SBaptiste Daroussin const ucl_object_t *param; 1258*39ee7a7aSBaptiste Daroussin ucl_object_iter_t it = NULL, ip = NULL; 1259*39ee7a7aSBaptiste Daroussin char ipath[PATH_MAX]; 1260*39ee7a7aSBaptiste Daroussin struct ucl_include_params params; 12614bf54857SBaptiste Daroussin 12624bf54857SBaptiste Daroussin /* Default values */ 1263*39ee7a7aSBaptiste Daroussin params.soft_fail = default_try; 1264*39ee7a7aSBaptiste Daroussin params.allow_glob = false; 1265*39ee7a7aSBaptiste Daroussin params.check_signature = default_sign; 1266*39ee7a7aSBaptiste Daroussin params.use_prefix = false; 1267*39ee7a7aSBaptiste Daroussin params.target = "object"; 1268*39ee7a7aSBaptiste Daroussin params.prefix = NULL; 1269*39ee7a7aSBaptiste Daroussin params.priority = 0; 1270*39ee7a7aSBaptiste Daroussin params.parse_type = UCL_PARSE_UCL; 1271*39ee7a7aSBaptiste Daroussin params.strat = UCL_DUPLICATE_APPEND; 1272*39ee7a7aSBaptiste Daroussin params.must_exist = !default_try; 1273*39ee7a7aSBaptiste Daroussin 1274*39ee7a7aSBaptiste Daroussin search = false; 12754bf54857SBaptiste Daroussin 12764bf54857SBaptiste Daroussin /* Process arguments */ 12774bf54857SBaptiste Daroussin if (args != NULL && args->type == UCL_OBJECT) { 12784bf54857SBaptiste Daroussin while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 12794bf54857SBaptiste Daroussin if (param->type == UCL_BOOLEAN) { 1280*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "try", param->keylen) == 0) { 1281*39ee7a7aSBaptiste Daroussin params.must_exist = !ucl_object_toboolean (param); 12824bf54857SBaptiste Daroussin } 1283*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "sign", param->keylen) == 0) { 1284*39ee7a7aSBaptiste Daroussin params.check_signature = ucl_object_toboolean (param); 12854bf54857SBaptiste Daroussin } 1286*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "glob", param->keylen) == 0) { 1287*39ee7a7aSBaptiste Daroussin params.allow_glob = ucl_object_toboolean (param); 12884bf54857SBaptiste Daroussin } 1289*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "url", param->keylen) == 0) { 12904bf54857SBaptiste Daroussin allow_url = ucl_object_toboolean (param); 12914bf54857SBaptiste Daroussin } 1292*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "prefix", param->keylen) == 0) { 1293*39ee7a7aSBaptiste Daroussin params.use_prefix = ucl_object_toboolean (param); 1294*39ee7a7aSBaptiste Daroussin } 1295*39ee7a7aSBaptiste Daroussin } 1296*39ee7a7aSBaptiste Daroussin else if (param->type == UCL_STRING) { 1297*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "key", param->keylen) == 0) { 1298*39ee7a7aSBaptiste Daroussin params.prefix = ucl_object_tostring (param); 1299*39ee7a7aSBaptiste Daroussin } 1300*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "target", param->keylen) == 0) { 1301*39ee7a7aSBaptiste Daroussin params.target = ucl_object_tostring (param); 1302*39ee7a7aSBaptiste Daroussin } 1303*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "duplicate", param->keylen) == 0) { 1304*39ee7a7aSBaptiste Daroussin duplicate = ucl_object_tostring (param); 1305*39ee7a7aSBaptiste Daroussin 1306*39ee7a7aSBaptiste Daroussin if (strcmp (duplicate, "append") == 0) { 1307*39ee7a7aSBaptiste Daroussin params.strat = UCL_DUPLICATE_APPEND; 1308*39ee7a7aSBaptiste Daroussin } 1309*39ee7a7aSBaptiste Daroussin else if (strcmp (duplicate, "merge") == 0) { 1310*39ee7a7aSBaptiste Daroussin params.strat = UCL_DUPLICATE_MERGE; 1311*39ee7a7aSBaptiste Daroussin } 1312*39ee7a7aSBaptiste Daroussin else if (strcmp (duplicate, "rewrite") == 0) { 1313*39ee7a7aSBaptiste Daroussin params.strat = UCL_DUPLICATE_REWRITE; 1314*39ee7a7aSBaptiste Daroussin } 1315*39ee7a7aSBaptiste Daroussin else if (strcmp (duplicate, "error") == 0) { 1316*39ee7a7aSBaptiste Daroussin params.strat = UCL_DUPLICATE_ERROR; 1317*39ee7a7aSBaptiste Daroussin } 1318*39ee7a7aSBaptiste Daroussin } 1319*39ee7a7aSBaptiste Daroussin } 1320*39ee7a7aSBaptiste Daroussin else if (param->type == UCL_ARRAY) { 1321*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "path", param->keylen) == 0) { 1322*39ee7a7aSBaptiste Daroussin ucl_set_include_path (parser, __DECONST(ucl_object_t *, param)); 1323*39ee7a7aSBaptiste Daroussin } 13244bf54857SBaptiste Daroussin } 13254bf54857SBaptiste Daroussin else if (param->type == UCL_INT) { 1326*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "priority", param->keylen) == 0) { 1327*39ee7a7aSBaptiste Daroussin params.priority = ucl_object_toint (param); 13284bf54857SBaptiste Daroussin } 13294bf54857SBaptiste Daroussin } 13304bf54857SBaptiste Daroussin } 13314bf54857SBaptiste Daroussin } 13324bf54857SBaptiste Daroussin 1333*39ee7a7aSBaptiste Daroussin if (parser->includepaths == NULL) { 1334*39ee7a7aSBaptiste Daroussin if (allow_url && ucl_strnstr (data, "://", len) != NULL) { 13354bf54857SBaptiste Daroussin /* Globbing is not used for URL's */ 1336*39ee7a7aSBaptiste Daroussin return ucl_include_url (data, len, parser, ¶ms); 1337*39ee7a7aSBaptiste Daroussin } 1338*39ee7a7aSBaptiste Daroussin else if (data != NULL) { 1339*39ee7a7aSBaptiste Daroussin /* Try to load a file */ 1340*39ee7a7aSBaptiste Daroussin return ucl_include_file (data, len, parser, ¶ms); 1341*39ee7a7aSBaptiste Daroussin } 1342*39ee7a7aSBaptiste Daroussin } 1343*39ee7a7aSBaptiste Daroussin else { 1344*39ee7a7aSBaptiste Daroussin if (allow_url && ucl_strnstr (data, "://", len) != NULL) { 1345*39ee7a7aSBaptiste Daroussin /* Globbing is not used for URL's */ 1346*39ee7a7aSBaptiste Daroussin return ucl_include_url (data, len, parser, ¶ms); 1347*39ee7a7aSBaptiste Daroussin } 1348*39ee7a7aSBaptiste Daroussin 1349*39ee7a7aSBaptiste Daroussin ip = ucl_object_iterate_new (parser->includepaths); 1350*39ee7a7aSBaptiste Daroussin while ((param = ucl_object_iterate_safe (ip, true)) != NULL) { 1351*39ee7a7aSBaptiste Daroussin if (ucl_object_type(param) == UCL_STRING) { 1352*39ee7a7aSBaptiste Daroussin snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param), 1353*39ee7a7aSBaptiste Daroussin (int)len, data); 1354*39ee7a7aSBaptiste Daroussin if ((search = ucl_include_file (ipath, strlen (ipath), 1355*39ee7a7aSBaptiste Daroussin parser, ¶ms))) { 1356*39ee7a7aSBaptiste Daroussin if (!params.allow_glob) { 1357*39ee7a7aSBaptiste Daroussin break; 1358*39ee7a7aSBaptiste Daroussin } 1359*39ee7a7aSBaptiste Daroussin } 1360*39ee7a7aSBaptiste Daroussin } 1361*39ee7a7aSBaptiste Daroussin } 1362*39ee7a7aSBaptiste Daroussin ucl_object_iterate_free (ip); 1363*39ee7a7aSBaptiste Daroussin if (search == true) { 1364*39ee7a7aSBaptiste Daroussin return true; 1365*39ee7a7aSBaptiste Daroussin } 1366*39ee7a7aSBaptiste Daroussin else { 1367*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, 1368*39ee7a7aSBaptiste Daroussin "cannot find file: %.*s in search path", 1369*39ee7a7aSBaptiste Daroussin (int)len, data); 1370*39ee7a7aSBaptiste Daroussin return false; 1371*39ee7a7aSBaptiste Daroussin } 13724bf54857SBaptiste Daroussin } 13734bf54857SBaptiste Daroussin 13744bf54857SBaptiste Daroussin return false; 13754bf54857SBaptiste Daroussin } 13764bf54857SBaptiste Daroussin 13774bf54857SBaptiste Daroussin /** 1378c99fb5f9SBaptiste Daroussin * Handle include macro 1379c99fb5f9SBaptiste Daroussin * @param data include data 1380c99fb5f9SBaptiste Daroussin * @param len length of data 1381*39ee7a7aSBaptiste Daroussin * @param args UCL object representing arguments to the macro 1382c99fb5f9SBaptiste Daroussin * @param ud user data 1383c99fb5f9SBaptiste Daroussin * @return 1384c99fb5f9SBaptiste Daroussin */ 1385*39ee7a7aSBaptiste Daroussin bool 13864bf54857SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len, 13874bf54857SBaptiste Daroussin const ucl_object_t *args, void* ud) 1388c99fb5f9SBaptiste Daroussin { 1389c99fb5f9SBaptiste Daroussin struct ucl_parser *parser = ud; 1390c99fb5f9SBaptiste Daroussin 13914bf54857SBaptiste Daroussin return ucl_include_common (data, len, args, parser, false, false); 1392c99fb5f9SBaptiste Daroussin } 1393c99fb5f9SBaptiste Daroussin 1394c99fb5f9SBaptiste Daroussin /** 1395c99fb5f9SBaptiste Daroussin * Handle includes macro 1396c99fb5f9SBaptiste Daroussin * @param data include data 1397c99fb5f9SBaptiste Daroussin * @param len length of data 1398*39ee7a7aSBaptiste Daroussin * @param args UCL object representing arguments to the macro 1399c99fb5f9SBaptiste Daroussin * @param ud user data 1400c99fb5f9SBaptiste Daroussin * @return 1401c99fb5f9SBaptiste Daroussin */ 1402*39ee7a7aSBaptiste Daroussin bool 14034bf54857SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len, 14044bf54857SBaptiste Daroussin const ucl_object_t *args, void* ud) 1405c99fb5f9SBaptiste Daroussin { 1406c99fb5f9SBaptiste Daroussin struct ucl_parser *parser = ud; 1407c99fb5f9SBaptiste Daroussin 14084bf54857SBaptiste Daroussin return ucl_include_common (data, len, args, parser, false, true); 1409c99fb5f9SBaptiste Daroussin } 1410c99fb5f9SBaptiste Daroussin 1411*39ee7a7aSBaptiste Daroussin /** 1412*39ee7a7aSBaptiste Daroussin * Handle tryinclude macro 1413*39ee7a7aSBaptiste Daroussin * @param data include data 1414*39ee7a7aSBaptiste Daroussin * @param len length of data 1415*39ee7a7aSBaptiste Daroussin * @param args UCL object representing arguments to the macro 1416*39ee7a7aSBaptiste Daroussin * @param ud user data 1417*39ee7a7aSBaptiste Daroussin * @return 1418*39ee7a7aSBaptiste Daroussin */ 1419*39ee7a7aSBaptiste Daroussin bool 14204bf54857SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len, 14214bf54857SBaptiste Daroussin const ucl_object_t *args, void* ud) 1422c99fb5f9SBaptiste Daroussin { 1423c99fb5f9SBaptiste Daroussin struct ucl_parser *parser = ud; 1424c99fb5f9SBaptiste Daroussin 14254bf54857SBaptiste Daroussin return ucl_include_common (data, len, args, parser, true, false); 1426c99fb5f9SBaptiste Daroussin } 1427c99fb5f9SBaptiste Daroussin 1428*39ee7a7aSBaptiste Daroussin /** 1429*39ee7a7aSBaptiste Daroussin * Handle priority macro 1430*39ee7a7aSBaptiste Daroussin * @param data include data 1431*39ee7a7aSBaptiste Daroussin * @param len length of data 1432*39ee7a7aSBaptiste Daroussin * @param args UCL object representing arguments to the macro 1433*39ee7a7aSBaptiste Daroussin * @param ud user data 1434*39ee7a7aSBaptiste Daroussin * @return 1435*39ee7a7aSBaptiste Daroussin */ 1436*39ee7a7aSBaptiste Daroussin bool 1437*39ee7a7aSBaptiste Daroussin ucl_priority_handler (const unsigned char *data, size_t len, 1438*39ee7a7aSBaptiste Daroussin const ucl_object_t *args, void* ud) 1439*39ee7a7aSBaptiste Daroussin { 1440*39ee7a7aSBaptiste Daroussin struct ucl_parser *parser = ud; 1441*39ee7a7aSBaptiste Daroussin unsigned priority = 255; 1442*39ee7a7aSBaptiste Daroussin const ucl_object_t *param; 1443*39ee7a7aSBaptiste Daroussin bool found = false; 1444*39ee7a7aSBaptiste Daroussin char *value = NULL, *leftover = NULL; 1445*39ee7a7aSBaptiste Daroussin ucl_object_iter_t it = NULL; 1446*39ee7a7aSBaptiste Daroussin 1447*39ee7a7aSBaptiste Daroussin if (parser == NULL) { 1448*39ee7a7aSBaptiste Daroussin return false; 1449*39ee7a7aSBaptiste Daroussin } 1450*39ee7a7aSBaptiste Daroussin 1451*39ee7a7aSBaptiste Daroussin /* Process arguments */ 1452*39ee7a7aSBaptiste Daroussin if (args != NULL && args->type == UCL_OBJECT) { 1453*39ee7a7aSBaptiste Daroussin while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1454*39ee7a7aSBaptiste Daroussin if (param->type == UCL_INT) { 1455*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "priority", param->keylen) == 0) { 1456*39ee7a7aSBaptiste Daroussin priority = ucl_object_toint (param); 1457*39ee7a7aSBaptiste Daroussin found = true; 1458*39ee7a7aSBaptiste Daroussin } 1459*39ee7a7aSBaptiste Daroussin } 1460*39ee7a7aSBaptiste Daroussin } 1461*39ee7a7aSBaptiste Daroussin } 1462*39ee7a7aSBaptiste Daroussin 1463*39ee7a7aSBaptiste Daroussin if (len > 0) { 1464*39ee7a7aSBaptiste Daroussin value = malloc(len + 1); 1465*39ee7a7aSBaptiste Daroussin ucl_strlcpy(value, (const char *)data, len + 1); 1466*39ee7a7aSBaptiste Daroussin priority = strtol(value, &leftover, 10); 1467*39ee7a7aSBaptiste Daroussin if (*leftover != '\0') { 1468*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "Invalid priority value in macro: %s", 1469*39ee7a7aSBaptiste Daroussin value); 1470*39ee7a7aSBaptiste Daroussin free(value); 1471*39ee7a7aSBaptiste Daroussin return false; 1472*39ee7a7aSBaptiste Daroussin } 1473*39ee7a7aSBaptiste Daroussin free(value); 1474*39ee7a7aSBaptiste Daroussin found = true; 1475*39ee7a7aSBaptiste Daroussin } 1476*39ee7a7aSBaptiste Daroussin 1477*39ee7a7aSBaptiste Daroussin if (found == true) { 1478*39ee7a7aSBaptiste Daroussin parser->chunks->priority = priority; 1479*39ee7a7aSBaptiste Daroussin return true; 1480*39ee7a7aSBaptiste Daroussin } 1481*39ee7a7aSBaptiste Daroussin 1482*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "Unable to parse priority macro"); 1483*39ee7a7aSBaptiste Daroussin return false; 1484*39ee7a7aSBaptiste Daroussin } 1485*39ee7a7aSBaptiste Daroussin 1486*39ee7a7aSBaptiste Daroussin /** 1487*39ee7a7aSBaptiste Daroussin * Handle load macro 1488*39ee7a7aSBaptiste Daroussin * @param data include data 1489*39ee7a7aSBaptiste Daroussin * @param len length of data 1490*39ee7a7aSBaptiste Daroussin * @param args UCL object representing arguments to the macro 1491*39ee7a7aSBaptiste Daroussin * @param ud user data 1492*39ee7a7aSBaptiste Daroussin * @return 1493*39ee7a7aSBaptiste Daroussin */ 1494*39ee7a7aSBaptiste Daroussin bool 1495*39ee7a7aSBaptiste Daroussin ucl_load_handler (const unsigned char *data, size_t len, 1496*39ee7a7aSBaptiste Daroussin const ucl_object_t *args, void* ud) 1497*39ee7a7aSBaptiste Daroussin { 1498*39ee7a7aSBaptiste Daroussin struct ucl_parser *parser = ud; 1499*39ee7a7aSBaptiste Daroussin const ucl_object_t *param; 1500*39ee7a7aSBaptiste Daroussin ucl_object_t *obj, *old_obj; 1501*39ee7a7aSBaptiste Daroussin ucl_object_iter_t it = NULL; 1502*39ee7a7aSBaptiste Daroussin bool try_load, multiline, test; 1503*39ee7a7aSBaptiste Daroussin const char *target, *prefix; 1504*39ee7a7aSBaptiste Daroussin char *load_file, *tmp; 1505*39ee7a7aSBaptiste Daroussin unsigned char *buf; 1506*39ee7a7aSBaptiste Daroussin size_t buflen; 1507*39ee7a7aSBaptiste Daroussin unsigned priority; 1508*39ee7a7aSBaptiste Daroussin int64_t iv; 1509*39ee7a7aSBaptiste Daroussin ucl_hash_t *container = NULL; 1510*39ee7a7aSBaptiste Daroussin enum ucl_string_flags flags; 1511*39ee7a7aSBaptiste Daroussin 1512*39ee7a7aSBaptiste Daroussin /* Default values */ 1513*39ee7a7aSBaptiste Daroussin try_load = false; 1514*39ee7a7aSBaptiste Daroussin multiline = false; 1515*39ee7a7aSBaptiste Daroussin test = false; 1516*39ee7a7aSBaptiste Daroussin target = "string"; 1517*39ee7a7aSBaptiste Daroussin prefix = NULL; 1518*39ee7a7aSBaptiste Daroussin load_file = NULL; 1519*39ee7a7aSBaptiste Daroussin buf = NULL; 1520*39ee7a7aSBaptiste Daroussin buflen = 0; 1521*39ee7a7aSBaptiste Daroussin priority = 0; 1522*39ee7a7aSBaptiste Daroussin obj = NULL; 1523*39ee7a7aSBaptiste Daroussin old_obj = NULL; 1524*39ee7a7aSBaptiste Daroussin flags = 0; 1525*39ee7a7aSBaptiste Daroussin 1526*39ee7a7aSBaptiste Daroussin if (parser == NULL) { 1527*39ee7a7aSBaptiste Daroussin return false; 1528*39ee7a7aSBaptiste Daroussin } 1529*39ee7a7aSBaptiste Daroussin 1530*39ee7a7aSBaptiste Daroussin /* Process arguments */ 1531*39ee7a7aSBaptiste Daroussin if (args != NULL && args->type == UCL_OBJECT) { 1532*39ee7a7aSBaptiste Daroussin while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1533*39ee7a7aSBaptiste Daroussin if (param->type == UCL_BOOLEAN) { 1534*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "try", param->keylen) == 0) { 1535*39ee7a7aSBaptiste Daroussin try_load = ucl_object_toboolean (param); 1536*39ee7a7aSBaptiste Daroussin } 1537*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "multiline", param->keylen) == 0) { 1538*39ee7a7aSBaptiste Daroussin multiline = ucl_object_toboolean (param); 1539*39ee7a7aSBaptiste Daroussin } 1540*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "escape", param->keylen) == 0) { 1541*39ee7a7aSBaptiste Daroussin test = ucl_object_toboolean (param); 1542*39ee7a7aSBaptiste Daroussin if (test) { 1543*39ee7a7aSBaptiste Daroussin flags |= UCL_STRING_ESCAPE; 1544*39ee7a7aSBaptiste Daroussin } 1545*39ee7a7aSBaptiste Daroussin } 1546*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "trim", param->keylen) == 0) { 1547*39ee7a7aSBaptiste Daroussin test = ucl_object_toboolean (param); 1548*39ee7a7aSBaptiste Daroussin if (test) { 1549*39ee7a7aSBaptiste Daroussin flags |= UCL_STRING_TRIM; 1550*39ee7a7aSBaptiste Daroussin } 1551*39ee7a7aSBaptiste Daroussin } 1552*39ee7a7aSBaptiste Daroussin } 1553*39ee7a7aSBaptiste Daroussin else if (param->type == UCL_STRING) { 1554*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "key", param->keylen) == 0) { 1555*39ee7a7aSBaptiste Daroussin prefix = ucl_object_tostring (param); 1556*39ee7a7aSBaptiste Daroussin } 1557*39ee7a7aSBaptiste Daroussin else if (strncmp (param->key, "target", param->keylen) == 0) { 1558*39ee7a7aSBaptiste Daroussin target = ucl_object_tostring (param); 1559*39ee7a7aSBaptiste Daroussin } 1560*39ee7a7aSBaptiste Daroussin } 1561*39ee7a7aSBaptiste Daroussin else if (param->type == UCL_INT) { 1562*39ee7a7aSBaptiste Daroussin if (strncmp (param->key, "priority", param->keylen) == 0) { 1563*39ee7a7aSBaptiste Daroussin priority = ucl_object_toint (param); 1564*39ee7a7aSBaptiste Daroussin } 1565*39ee7a7aSBaptiste Daroussin } 1566*39ee7a7aSBaptiste Daroussin } 1567*39ee7a7aSBaptiste Daroussin } 1568*39ee7a7aSBaptiste Daroussin 1569*39ee7a7aSBaptiste Daroussin if (prefix == NULL || strlen(prefix) == 0) { 1570*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "No Key specified in load macro"); 1571*39ee7a7aSBaptiste Daroussin return false; 1572*39ee7a7aSBaptiste Daroussin } 1573*39ee7a7aSBaptiste Daroussin 1574*39ee7a7aSBaptiste Daroussin if (len > 0) { 1575*39ee7a7aSBaptiste Daroussin asprintf (&load_file, "%.*s", (int)len, data); 1576*39ee7a7aSBaptiste Daroussin if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err, !try_load)) { 1577*39ee7a7aSBaptiste Daroussin return (try_load || false); 1578*39ee7a7aSBaptiste Daroussin } 1579*39ee7a7aSBaptiste Daroussin 1580*39ee7a7aSBaptiste Daroussin container = parser->stack->obj->value.ov; 1581*39ee7a7aSBaptiste Daroussin old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix))); 1582*39ee7a7aSBaptiste Daroussin if (old_obj != NULL) { 1583*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "Key %s already exists", prefix); 1584*39ee7a7aSBaptiste Daroussin return false; 1585*39ee7a7aSBaptiste Daroussin } 1586*39ee7a7aSBaptiste Daroussin 1587*39ee7a7aSBaptiste Daroussin if (strcasecmp (target, "string") == 0) { 1588*39ee7a7aSBaptiste Daroussin obj = ucl_object_fromstring_common (buf, buflen, flags); 1589*39ee7a7aSBaptiste Daroussin ucl_copy_value_trash (obj); 1590*39ee7a7aSBaptiste Daroussin if (multiline) { 1591*39ee7a7aSBaptiste Daroussin obj->flags |= UCL_OBJECT_MULTILINE; 1592*39ee7a7aSBaptiste Daroussin } 1593*39ee7a7aSBaptiste Daroussin } 1594*39ee7a7aSBaptiste Daroussin else if (strcasecmp (target, "int") == 0) { 1595*39ee7a7aSBaptiste Daroussin asprintf(&tmp, "%.*s", (int)buflen, buf); 1596*39ee7a7aSBaptiste Daroussin iv = strtoll(tmp, NULL, 10); 1597*39ee7a7aSBaptiste Daroussin obj = ucl_object_fromint(iv); 1598*39ee7a7aSBaptiste Daroussin } 1599*39ee7a7aSBaptiste Daroussin 1600*39ee7a7aSBaptiste Daroussin if (buflen > 0) { 1601*39ee7a7aSBaptiste Daroussin ucl_munmap (buf, buflen); 1602*39ee7a7aSBaptiste Daroussin } 1603*39ee7a7aSBaptiste Daroussin 1604*39ee7a7aSBaptiste Daroussin if (obj != NULL) { 1605*39ee7a7aSBaptiste Daroussin obj->key = prefix; 1606*39ee7a7aSBaptiste Daroussin obj->keylen = strlen (prefix); 1607*39ee7a7aSBaptiste Daroussin ucl_copy_key_trash(obj); 1608*39ee7a7aSBaptiste Daroussin obj->prev = obj; 1609*39ee7a7aSBaptiste Daroussin obj->next = NULL; 1610*39ee7a7aSBaptiste Daroussin ucl_object_set_priority (obj, priority); 1611*39ee7a7aSBaptiste Daroussin container = ucl_hash_insert_object (container, obj, 1612*39ee7a7aSBaptiste Daroussin parser->flags & UCL_PARSER_KEY_LOWERCASE); 1613*39ee7a7aSBaptiste Daroussin parser->stack->obj->value.ov = container; 1614*39ee7a7aSBaptiste Daroussin } 1615*39ee7a7aSBaptiste Daroussin return true; 1616*39ee7a7aSBaptiste Daroussin } 1617*39ee7a7aSBaptiste Daroussin 1618*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "Unable to parse load macro"); 1619*39ee7a7aSBaptiste Daroussin return false; 1620*39ee7a7aSBaptiste Daroussin } 1621*39ee7a7aSBaptiste Daroussin 1622*39ee7a7aSBaptiste Daroussin bool 1623*39ee7a7aSBaptiste Daroussin ucl_inherit_handler (const unsigned char *data, size_t len, 1624*39ee7a7aSBaptiste Daroussin const ucl_object_t *args, const ucl_object_t *ctx, void* ud) 1625*39ee7a7aSBaptiste Daroussin { 1626*39ee7a7aSBaptiste Daroussin const ucl_object_t *parent, *cur; 1627*39ee7a7aSBaptiste Daroussin ucl_object_t *target, *copy; 1628*39ee7a7aSBaptiste Daroussin ucl_object_iter_t it = NULL; 1629*39ee7a7aSBaptiste Daroussin bool replace = false; 1630*39ee7a7aSBaptiste Daroussin struct ucl_parser *parser = ud; 1631*39ee7a7aSBaptiste Daroussin 1632*39ee7a7aSBaptiste Daroussin parent = ucl_object_find_keyl (ctx, data, len); 1633*39ee7a7aSBaptiste Daroussin 1634*39ee7a7aSBaptiste Daroussin /* Some sanity checks */ 1635*39ee7a7aSBaptiste Daroussin if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) { 1636*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "Unable to find inherited object %*.s", 1637*39ee7a7aSBaptiste Daroussin (int)len, data); 1638*39ee7a7aSBaptiste Daroussin return false; 1639*39ee7a7aSBaptiste Daroussin } 1640*39ee7a7aSBaptiste Daroussin 1641*39ee7a7aSBaptiste Daroussin if (parser->stack == NULL || parser->stack->obj == NULL || 1642*39ee7a7aSBaptiste Daroussin ucl_object_type (parser->stack->obj) != UCL_OBJECT) { 1643*39ee7a7aSBaptiste Daroussin ucl_create_err (&parser->err, "Invalid inherit context"); 1644*39ee7a7aSBaptiste Daroussin return false; 1645*39ee7a7aSBaptiste Daroussin } 1646*39ee7a7aSBaptiste Daroussin 1647*39ee7a7aSBaptiste Daroussin target = parser->stack->obj; 1648*39ee7a7aSBaptiste Daroussin 1649*39ee7a7aSBaptiste Daroussin if (args && (cur = ucl_object_find_key (args, "replace")) != NULL) { 1650*39ee7a7aSBaptiste Daroussin replace = ucl_object_toboolean (cur); 1651*39ee7a7aSBaptiste Daroussin } 1652*39ee7a7aSBaptiste Daroussin 1653*39ee7a7aSBaptiste Daroussin while ((cur = ucl_iterate_object (parent, &it, true))) { 1654*39ee7a7aSBaptiste Daroussin /* We do not replace existing keys */ 1655*39ee7a7aSBaptiste Daroussin if (!replace && ucl_object_find_keyl (target, cur->key, cur->keylen)) { 1656*39ee7a7aSBaptiste Daroussin continue; 1657*39ee7a7aSBaptiste Daroussin } 1658*39ee7a7aSBaptiste Daroussin 1659*39ee7a7aSBaptiste Daroussin copy = ucl_object_copy (cur); 1660*39ee7a7aSBaptiste Daroussin 1661*39ee7a7aSBaptiste Daroussin if (!replace) { 1662*39ee7a7aSBaptiste Daroussin copy->flags |= UCL_OBJECT_INHERITED; 1663*39ee7a7aSBaptiste Daroussin } 1664*39ee7a7aSBaptiste Daroussin 1665*39ee7a7aSBaptiste Daroussin ucl_object_insert_key (target, copy, copy->key, 1666*39ee7a7aSBaptiste Daroussin copy->keylen, false); 1667*39ee7a7aSBaptiste Daroussin } 1668*39ee7a7aSBaptiste Daroussin 1669*39ee7a7aSBaptiste Daroussin return true; 1670*39ee7a7aSBaptiste Daroussin } 1671*39ee7a7aSBaptiste Daroussin 1672*39ee7a7aSBaptiste Daroussin bool 1673c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 1674c99fb5f9SBaptiste Daroussin { 1675c99fb5f9SBaptiste Daroussin char realbuf[PATH_MAX], *curdir; 1676c99fb5f9SBaptiste Daroussin 1677c99fb5f9SBaptiste Daroussin if (filename != NULL) { 1678c99fb5f9SBaptiste Daroussin if (need_expand) { 167997bd480fSBaptiste Daroussin if (ucl_realpath (filename, realbuf) == NULL) { 1680c99fb5f9SBaptiste Daroussin return false; 1681c99fb5f9SBaptiste Daroussin } 1682c99fb5f9SBaptiste Daroussin } 1683c99fb5f9SBaptiste Daroussin else { 1684c99fb5f9SBaptiste Daroussin ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 1685c99fb5f9SBaptiste Daroussin } 1686c99fb5f9SBaptiste Daroussin 1687c99fb5f9SBaptiste Daroussin /* Define variables */ 1688c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "FILENAME", realbuf); 1689c99fb5f9SBaptiste Daroussin curdir = dirname (realbuf); 1690c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "CURDIR", curdir); 1691c99fb5f9SBaptiste Daroussin } 1692c99fb5f9SBaptiste Daroussin else { 1693c99fb5f9SBaptiste Daroussin /* Set everything from the current dir */ 1694c99fb5f9SBaptiste Daroussin curdir = getcwd (realbuf, sizeof (realbuf)); 1695c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "FILENAME", "undef"); 1696c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "CURDIR", curdir); 1697c99fb5f9SBaptiste Daroussin } 1698c99fb5f9SBaptiste Daroussin 1699c99fb5f9SBaptiste Daroussin return true; 1700c99fb5f9SBaptiste Daroussin } 1701c99fb5f9SBaptiste Daroussin 1702*39ee7a7aSBaptiste Daroussin bool 1703*39ee7a7aSBaptiste Daroussin ucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename, 1704*39ee7a7aSBaptiste Daroussin unsigned priority) 1705c99fb5f9SBaptiste Daroussin { 1706c99fb5f9SBaptiste Daroussin unsigned char *buf; 1707c99fb5f9SBaptiste Daroussin size_t len; 1708c99fb5f9SBaptiste Daroussin bool ret; 1709c99fb5f9SBaptiste Daroussin char realbuf[PATH_MAX]; 1710c99fb5f9SBaptiste Daroussin 171197bd480fSBaptiste Daroussin if (ucl_realpath (filename, realbuf) == NULL) { 1712c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot open file %s: %s", 1713c99fb5f9SBaptiste Daroussin filename, 1714c99fb5f9SBaptiste Daroussin strerror (errno)); 1715c99fb5f9SBaptiste Daroussin return false; 1716c99fb5f9SBaptiste Daroussin } 1717c99fb5f9SBaptiste Daroussin 1718c99fb5f9SBaptiste Daroussin if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 1719c99fb5f9SBaptiste Daroussin return false; 1720c99fb5f9SBaptiste Daroussin } 1721c99fb5f9SBaptiste Daroussin 17224bf54857SBaptiste Daroussin if (parser->cur_file) { 17234bf54857SBaptiste Daroussin free (parser->cur_file); 17244bf54857SBaptiste Daroussin } 17254bf54857SBaptiste Daroussin parser->cur_file = strdup (realbuf); 1726c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (parser, realbuf, false); 1727*39ee7a7aSBaptiste Daroussin ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); 1728c99fb5f9SBaptiste Daroussin 1729c99fb5f9SBaptiste Daroussin if (len > 0) { 173097bd480fSBaptiste Daroussin ucl_munmap (buf, len); 1731c99fb5f9SBaptiste Daroussin } 1732c99fb5f9SBaptiste Daroussin 1733c99fb5f9SBaptiste Daroussin return ret; 1734c99fb5f9SBaptiste Daroussin } 1735c99fb5f9SBaptiste Daroussin 1736*39ee7a7aSBaptiste Daroussin bool 1737*39ee7a7aSBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename) 1738*39ee7a7aSBaptiste Daroussin { 1739*39ee7a7aSBaptiste Daroussin if (parser == NULL) { 1740*39ee7a7aSBaptiste Daroussin return false; 1741*39ee7a7aSBaptiste Daroussin } 1742*39ee7a7aSBaptiste Daroussin 1743*39ee7a7aSBaptiste Daroussin return ucl_parser_add_file_priority(parser, filename, 1744*39ee7a7aSBaptiste Daroussin parser->default_priority); 1745*39ee7a7aSBaptiste Daroussin } 1746*39ee7a7aSBaptiste Daroussin 1747*39ee7a7aSBaptiste Daroussin bool 1748*39ee7a7aSBaptiste Daroussin ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd, 1749*39ee7a7aSBaptiste Daroussin unsigned priority) 17504bf54857SBaptiste Daroussin { 17514bf54857SBaptiste Daroussin unsigned char *buf; 17524bf54857SBaptiste Daroussin size_t len; 17534bf54857SBaptiste Daroussin bool ret; 17544bf54857SBaptiste Daroussin struct stat st; 17554bf54857SBaptiste Daroussin 17564bf54857SBaptiste Daroussin if (fstat (fd, &st) == -1) { 17574bf54857SBaptiste Daroussin ucl_create_err (&parser->err, "cannot stat fd %d: %s", 17584bf54857SBaptiste Daroussin fd, strerror (errno)); 17594bf54857SBaptiste Daroussin return false; 17604bf54857SBaptiste Daroussin } 17614bf54857SBaptiste Daroussin if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 17624bf54857SBaptiste Daroussin ucl_create_err (&parser->err, "cannot mmap fd %d: %s", 17634bf54857SBaptiste Daroussin fd, strerror (errno)); 17644bf54857SBaptiste Daroussin return false; 17654bf54857SBaptiste Daroussin } 17664bf54857SBaptiste Daroussin 17674bf54857SBaptiste Daroussin if (parser->cur_file) { 17684bf54857SBaptiste Daroussin free (parser->cur_file); 17694bf54857SBaptiste Daroussin } 17704bf54857SBaptiste Daroussin parser->cur_file = NULL; 17714bf54857SBaptiste Daroussin len = st.st_size; 1772*39ee7a7aSBaptiste Daroussin ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); 17734bf54857SBaptiste Daroussin 17744bf54857SBaptiste Daroussin if (len > 0) { 17754bf54857SBaptiste Daroussin ucl_munmap (buf, len); 17764bf54857SBaptiste Daroussin } 17774bf54857SBaptiste Daroussin 17784bf54857SBaptiste Daroussin return ret; 17794bf54857SBaptiste Daroussin } 17804bf54857SBaptiste Daroussin 1781*39ee7a7aSBaptiste Daroussin bool 1782*39ee7a7aSBaptiste Daroussin ucl_parser_add_fd (struct ucl_parser *parser, int fd) 1783*39ee7a7aSBaptiste Daroussin { 1784*39ee7a7aSBaptiste Daroussin if (parser == NULL) { 1785*39ee7a7aSBaptiste Daroussin return false; 1786*39ee7a7aSBaptiste Daroussin } 1787*39ee7a7aSBaptiste Daroussin 1788*39ee7a7aSBaptiste Daroussin return ucl_parser_add_fd_priority(parser, fd, parser->default_priority); 1789*39ee7a7aSBaptiste Daroussin } 1790*39ee7a7aSBaptiste Daroussin 1791c99fb5f9SBaptiste Daroussin size_t 1792c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz) 1793c99fb5f9SBaptiste Daroussin { 1794c99fb5f9SBaptiste Daroussin char *d = dst; 1795c99fb5f9SBaptiste Daroussin const char *s = src; 1796c99fb5f9SBaptiste Daroussin size_t n = siz; 1797c99fb5f9SBaptiste Daroussin 1798c99fb5f9SBaptiste Daroussin /* Copy as many bytes as will fit */ 1799c99fb5f9SBaptiste Daroussin if (n != 0) { 1800c99fb5f9SBaptiste Daroussin while (--n != 0) { 1801c99fb5f9SBaptiste Daroussin if ((*d++ = *s++) == '\0') { 1802c99fb5f9SBaptiste Daroussin break; 1803c99fb5f9SBaptiste Daroussin } 1804c99fb5f9SBaptiste Daroussin } 1805c99fb5f9SBaptiste Daroussin } 1806c99fb5f9SBaptiste Daroussin 1807c99fb5f9SBaptiste Daroussin if (n == 0 && siz != 0) { 1808c99fb5f9SBaptiste Daroussin *d = '\0'; 1809c99fb5f9SBaptiste Daroussin } 1810c99fb5f9SBaptiste Daroussin 1811c99fb5f9SBaptiste Daroussin return (s - src - 1); /* count does not include NUL */ 1812c99fb5f9SBaptiste Daroussin } 1813c99fb5f9SBaptiste Daroussin 1814c99fb5f9SBaptiste Daroussin size_t 1815c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 1816c99fb5f9SBaptiste Daroussin { 1817c99fb5f9SBaptiste Daroussin memcpy (dst, src, siz - 1); 1818c99fb5f9SBaptiste Daroussin dst[siz - 1] = '\0'; 1819c99fb5f9SBaptiste Daroussin 1820c99fb5f9SBaptiste Daroussin return siz - 1; 1821c99fb5f9SBaptiste Daroussin } 1822c99fb5f9SBaptiste Daroussin 1823c99fb5f9SBaptiste Daroussin size_t 1824c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 1825c99fb5f9SBaptiste Daroussin { 1826c99fb5f9SBaptiste Daroussin char *d = dst; 1827c99fb5f9SBaptiste Daroussin const char *s = src; 1828c99fb5f9SBaptiste Daroussin size_t n = siz; 1829c99fb5f9SBaptiste Daroussin 1830c99fb5f9SBaptiste Daroussin /* Copy as many bytes as will fit */ 1831c99fb5f9SBaptiste Daroussin if (n != 0) { 1832c99fb5f9SBaptiste Daroussin while (--n != 0) { 1833c99fb5f9SBaptiste Daroussin if ((*d++ = tolower (*s++)) == '\0') { 1834c99fb5f9SBaptiste Daroussin break; 1835c99fb5f9SBaptiste Daroussin } 1836c99fb5f9SBaptiste Daroussin } 1837c99fb5f9SBaptiste Daroussin } 1838c99fb5f9SBaptiste Daroussin 1839c99fb5f9SBaptiste Daroussin if (n == 0 && siz != 0) { 1840c99fb5f9SBaptiste Daroussin *d = '\0'; 1841c99fb5f9SBaptiste Daroussin } 1842c99fb5f9SBaptiste Daroussin 1843c99fb5f9SBaptiste Daroussin return (s - src); /* count does not include NUL */ 1844c99fb5f9SBaptiste Daroussin } 1845c99fb5f9SBaptiste Daroussin 1846*39ee7a7aSBaptiste Daroussin /* 1847*39ee7a7aSBaptiste Daroussin * Find the first occurrence of find in s 1848*39ee7a7aSBaptiste Daroussin */ 1849*39ee7a7aSBaptiste Daroussin char * 1850*39ee7a7aSBaptiste Daroussin ucl_strnstr (const char *s, const char *find, int len) 1851*39ee7a7aSBaptiste Daroussin { 1852*39ee7a7aSBaptiste Daroussin char c, sc; 1853*39ee7a7aSBaptiste Daroussin int mlen; 1854*39ee7a7aSBaptiste Daroussin 1855*39ee7a7aSBaptiste Daroussin if ((c = *find++) != 0) { 1856*39ee7a7aSBaptiste Daroussin mlen = strlen (find); 1857*39ee7a7aSBaptiste Daroussin do { 1858*39ee7a7aSBaptiste Daroussin do { 1859*39ee7a7aSBaptiste Daroussin if ((sc = *s++) == 0 || len-- == 0) 1860*39ee7a7aSBaptiste Daroussin return (NULL); 1861*39ee7a7aSBaptiste Daroussin } while (sc != c); 1862*39ee7a7aSBaptiste Daroussin } while (strncmp (s, find, mlen) != 0); 1863*39ee7a7aSBaptiste Daroussin s--; 1864*39ee7a7aSBaptiste Daroussin } 1865*39ee7a7aSBaptiste Daroussin return ((char *)s); 1866*39ee7a7aSBaptiste Daroussin } 1867*39ee7a7aSBaptiste Daroussin 1868*39ee7a7aSBaptiste Daroussin /* 1869*39ee7a7aSBaptiste Daroussin * Find the first occurrence of find in s, ignore case. 1870*39ee7a7aSBaptiste Daroussin */ 1871*39ee7a7aSBaptiste Daroussin char * 1872*39ee7a7aSBaptiste Daroussin ucl_strncasestr (const char *s, const char *find, int len) 1873*39ee7a7aSBaptiste Daroussin { 1874*39ee7a7aSBaptiste Daroussin char c, sc; 1875*39ee7a7aSBaptiste Daroussin int mlen; 1876*39ee7a7aSBaptiste Daroussin 1877*39ee7a7aSBaptiste Daroussin if ((c = *find++) != 0) { 1878*39ee7a7aSBaptiste Daroussin c = tolower (c); 1879*39ee7a7aSBaptiste Daroussin mlen = strlen (find); 1880*39ee7a7aSBaptiste Daroussin do { 1881*39ee7a7aSBaptiste Daroussin do { 1882*39ee7a7aSBaptiste Daroussin if ((sc = *s++) == 0 || len-- == 0) 1883*39ee7a7aSBaptiste Daroussin return (NULL); 1884*39ee7a7aSBaptiste Daroussin } while (tolower (sc) != c); 1885*39ee7a7aSBaptiste Daroussin } while (strncasecmp (s, find, mlen) != 0); 1886*39ee7a7aSBaptiste Daroussin s--; 1887*39ee7a7aSBaptiste Daroussin } 1888*39ee7a7aSBaptiste Daroussin return ((char *)s); 1889*39ee7a7aSBaptiste Daroussin } 1890*39ee7a7aSBaptiste Daroussin 1891c99fb5f9SBaptiste Daroussin ucl_object_t * 1892c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1893c99fb5f9SBaptiste Daroussin { 1894c99fb5f9SBaptiste Daroussin ucl_object_t *obj; 1895c99fb5f9SBaptiste Daroussin const char *start, *end, *p, *pos; 1896c99fb5f9SBaptiste Daroussin char *dst, *d; 1897c99fb5f9SBaptiste Daroussin size_t escaped_len; 1898c99fb5f9SBaptiste Daroussin 1899c99fb5f9SBaptiste Daroussin if (str == NULL) { 1900c99fb5f9SBaptiste Daroussin return NULL; 1901c99fb5f9SBaptiste Daroussin } 1902c99fb5f9SBaptiste Daroussin 1903c99fb5f9SBaptiste Daroussin obj = ucl_object_new (); 1904c99fb5f9SBaptiste Daroussin if (obj) { 1905c99fb5f9SBaptiste Daroussin if (len == 0) { 1906c99fb5f9SBaptiste Daroussin len = strlen (str); 1907c99fb5f9SBaptiste Daroussin } 1908c99fb5f9SBaptiste Daroussin if (flags & UCL_STRING_TRIM) { 1909c99fb5f9SBaptiste Daroussin /* Skip leading spaces */ 1910c99fb5f9SBaptiste Daroussin for (start = str; (size_t)(start - str) < len; start ++) { 1911c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1912c99fb5f9SBaptiste Daroussin break; 1913c99fb5f9SBaptiste Daroussin } 1914c99fb5f9SBaptiste Daroussin } 1915c99fb5f9SBaptiste Daroussin /* Skip trailing spaces */ 1916c99fb5f9SBaptiste Daroussin for (end = str + len - 1; end > start; end --) { 1917c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1918c99fb5f9SBaptiste Daroussin break; 1919c99fb5f9SBaptiste Daroussin } 1920c99fb5f9SBaptiste Daroussin } 1921c99fb5f9SBaptiste Daroussin end ++; 1922c99fb5f9SBaptiste Daroussin } 1923c99fb5f9SBaptiste Daroussin else { 1924c99fb5f9SBaptiste Daroussin start = str; 1925c99fb5f9SBaptiste Daroussin end = str + len; 1926c99fb5f9SBaptiste Daroussin } 1927c99fb5f9SBaptiste Daroussin 1928c99fb5f9SBaptiste Daroussin obj->type = UCL_STRING; 1929c99fb5f9SBaptiste Daroussin if (flags & UCL_STRING_ESCAPE) { 1930c99fb5f9SBaptiste Daroussin for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1931c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1932c99fb5f9SBaptiste Daroussin escaped_len ++; 1933c99fb5f9SBaptiste Daroussin } 1934c99fb5f9SBaptiste Daroussin } 1935c99fb5f9SBaptiste Daroussin dst = malloc (escaped_len + 1); 1936c99fb5f9SBaptiste Daroussin if (dst != NULL) { 1937c99fb5f9SBaptiste Daroussin for (p = start, d = dst; p < end; p ++, d ++) { 1938c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1939c99fb5f9SBaptiste Daroussin switch (*p) { 1940c99fb5f9SBaptiste Daroussin case '\n': 1941c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1942c99fb5f9SBaptiste Daroussin *d = 'n'; 1943c99fb5f9SBaptiste Daroussin break; 1944c99fb5f9SBaptiste Daroussin case '\r': 1945c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1946c99fb5f9SBaptiste Daroussin *d = 'r'; 1947c99fb5f9SBaptiste Daroussin break; 1948c99fb5f9SBaptiste Daroussin case '\b': 1949c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1950c99fb5f9SBaptiste Daroussin *d = 'b'; 1951c99fb5f9SBaptiste Daroussin break; 1952c99fb5f9SBaptiste Daroussin case '\t': 1953c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1954c99fb5f9SBaptiste Daroussin *d = 't'; 1955c99fb5f9SBaptiste Daroussin break; 1956c99fb5f9SBaptiste Daroussin case '\f': 1957c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1958c99fb5f9SBaptiste Daroussin *d = 'f'; 1959c99fb5f9SBaptiste Daroussin break; 1960c99fb5f9SBaptiste Daroussin case '\\': 1961c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1962c99fb5f9SBaptiste Daroussin *d = '\\'; 1963c99fb5f9SBaptiste Daroussin break; 1964c99fb5f9SBaptiste Daroussin case '"': 1965c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1966c99fb5f9SBaptiste Daroussin *d = '"'; 1967c99fb5f9SBaptiste Daroussin break; 1968c99fb5f9SBaptiste Daroussin } 1969c99fb5f9SBaptiste Daroussin } 1970c99fb5f9SBaptiste Daroussin else { 1971c99fb5f9SBaptiste Daroussin *d = *p; 1972c99fb5f9SBaptiste Daroussin } 1973c99fb5f9SBaptiste Daroussin } 1974c99fb5f9SBaptiste Daroussin *d = '\0'; 1975c99fb5f9SBaptiste Daroussin obj->value.sv = dst; 1976c99fb5f9SBaptiste Daroussin obj->trash_stack[UCL_TRASH_VALUE] = dst; 1977c99fb5f9SBaptiste Daroussin obj->len = escaped_len; 1978c99fb5f9SBaptiste Daroussin } 1979c99fb5f9SBaptiste Daroussin } 1980c99fb5f9SBaptiste Daroussin else { 1981c99fb5f9SBaptiste Daroussin dst = malloc (end - start + 1); 1982c99fb5f9SBaptiste Daroussin if (dst != NULL) { 1983c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (dst, start, end - start + 1); 1984c99fb5f9SBaptiste Daroussin obj->value.sv = dst; 1985c99fb5f9SBaptiste Daroussin obj->trash_stack[UCL_TRASH_VALUE] = dst; 1986c99fb5f9SBaptiste Daroussin obj->len = end - start; 1987c99fb5f9SBaptiste Daroussin } 1988c99fb5f9SBaptiste Daroussin } 1989c99fb5f9SBaptiste Daroussin if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1990c99fb5f9SBaptiste Daroussin /* Parse what we have */ 1991c99fb5f9SBaptiste Daroussin if (flags & UCL_STRING_PARSE_BOOLEAN) { 1992c99fb5f9SBaptiste Daroussin if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1993c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1994c99fb5f9SBaptiste Daroussin flags & UCL_STRING_PARSE_DOUBLE, 199597bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_BYTES, 199697bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_TIME); 1997c99fb5f9SBaptiste Daroussin } 1998c99fb5f9SBaptiste Daroussin } 1999c99fb5f9SBaptiste Daroussin else { 2000c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 2001c99fb5f9SBaptiste Daroussin flags & UCL_STRING_PARSE_DOUBLE, 200297bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_BYTES, 200397bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_TIME); 2004c99fb5f9SBaptiste Daroussin } 2005c99fb5f9SBaptiste Daroussin } 2006c99fb5f9SBaptiste Daroussin } 2007c99fb5f9SBaptiste Daroussin 2008c99fb5f9SBaptiste Daroussin return obj; 2009c99fb5f9SBaptiste Daroussin } 2010c99fb5f9SBaptiste Daroussin 2011b04a7a0bSBaptiste Daroussin static bool 2012c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 2013c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 2014c99fb5f9SBaptiste Daroussin { 2015b04a7a0bSBaptiste Daroussin ucl_object_t *found, *tmp; 2016b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 2017c99fb5f9SBaptiste Daroussin ucl_object_iter_t it = NULL; 2018c99fb5f9SBaptiste Daroussin const char *p; 2019b04a7a0bSBaptiste Daroussin int ret = true; 2020c99fb5f9SBaptiste Daroussin 2021c99fb5f9SBaptiste Daroussin if (elt == NULL || key == NULL) { 2022b04a7a0bSBaptiste Daroussin return false; 2023c99fb5f9SBaptiste Daroussin } 2024c99fb5f9SBaptiste Daroussin 2025c99fb5f9SBaptiste Daroussin if (top == NULL) { 2026b04a7a0bSBaptiste Daroussin return false; 2027c99fb5f9SBaptiste Daroussin } 2028c99fb5f9SBaptiste Daroussin 2029c99fb5f9SBaptiste Daroussin if (top->type != UCL_OBJECT) { 2030c99fb5f9SBaptiste Daroussin /* It is possible to convert NULL type to an object */ 2031c99fb5f9SBaptiste Daroussin if (top->type == UCL_NULL) { 2032c99fb5f9SBaptiste Daroussin top->type = UCL_OBJECT; 2033c99fb5f9SBaptiste Daroussin } 2034c99fb5f9SBaptiste Daroussin else { 2035c99fb5f9SBaptiste Daroussin /* Refuse converting of other object types */ 2036b04a7a0bSBaptiste Daroussin return false; 2037c99fb5f9SBaptiste Daroussin } 2038c99fb5f9SBaptiste Daroussin } 2039c99fb5f9SBaptiste Daroussin 2040c99fb5f9SBaptiste Daroussin if (top->value.ov == NULL) { 20418e3b1ab2SBaptiste Daroussin top->value.ov = ucl_hash_create (false); 2042c99fb5f9SBaptiste Daroussin } 2043c99fb5f9SBaptiste Daroussin 2044c99fb5f9SBaptiste Daroussin if (keylen == 0) { 2045c99fb5f9SBaptiste Daroussin keylen = strlen (key); 2046c99fb5f9SBaptiste Daroussin } 2047c99fb5f9SBaptiste Daroussin 2048c99fb5f9SBaptiste Daroussin for (p = key; p < key + keylen; p ++) { 2049c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 2050c99fb5f9SBaptiste Daroussin elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 2051c99fb5f9SBaptiste Daroussin break; 2052c99fb5f9SBaptiste Daroussin } 2053c99fb5f9SBaptiste Daroussin } 2054c99fb5f9SBaptiste Daroussin 20554bf54857SBaptiste Daroussin /* workaround for some use cases */ 20564bf54857SBaptiste Daroussin if (elt->trash_stack[UCL_TRASH_KEY] != NULL && 20574bf54857SBaptiste Daroussin key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) { 20584bf54857SBaptiste Daroussin /* Remove copied key */ 20594bf54857SBaptiste Daroussin free (elt->trash_stack[UCL_TRASH_KEY]); 20604bf54857SBaptiste Daroussin elt->trash_stack[UCL_TRASH_KEY] = NULL; 20614bf54857SBaptiste Daroussin elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY; 20624bf54857SBaptiste Daroussin } 20634bf54857SBaptiste Daroussin 2064c99fb5f9SBaptiste Daroussin elt->key = key; 2065c99fb5f9SBaptiste Daroussin elt->keylen = keylen; 2066c99fb5f9SBaptiste Daroussin 2067c99fb5f9SBaptiste Daroussin if (copy_key) { 2068c99fb5f9SBaptiste Daroussin ucl_copy_key_trash (elt); 2069c99fb5f9SBaptiste Daroussin } 2070c99fb5f9SBaptiste Daroussin 2071b04a7a0bSBaptiste Daroussin found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 2072c99fb5f9SBaptiste Daroussin 20734bf54857SBaptiste Daroussin if (found == NULL) { 20748e3b1ab2SBaptiste Daroussin top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); 207597bd480fSBaptiste Daroussin top->len ++; 2076b04a7a0bSBaptiste Daroussin if (replace) { 2077b04a7a0bSBaptiste Daroussin ret = false; 2078b04a7a0bSBaptiste Daroussin } 2079c99fb5f9SBaptiste Daroussin } 2080c99fb5f9SBaptiste Daroussin else { 2081c99fb5f9SBaptiste Daroussin if (replace) { 20824bf54857SBaptiste Daroussin ucl_hash_replace (top->value.ov, found, elt); 2083c99fb5f9SBaptiste Daroussin ucl_object_unref (found); 2084c99fb5f9SBaptiste Daroussin } 2085c99fb5f9SBaptiste Daroussin else if (merge) { 2086c99fb5f9SBaptiste Daroussin if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 2087c99fb5f9SBaptiste Daroussin /* Insert old elt to new one */ 2088b04a7a0bSBaptiste Daroussin ucl_object_insert_key_common (elt, found, found->key, 2089b04a7a0bSBaptiste Daroussin found->keylen, copy_key, false, false); 2090c99fb5f9SBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 20918e3b1ab2SBaptiste Daroussin top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); 2092c99fb5f9SBaptiste Daroussin } 2093c99fb5f9SBaptiste Daroussin else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 2094c99fb5f9SBaptiste Daroussin /* Insert new to old */ 2095b04a7a0bSBaptiste Daroussin ucl_object_insert_key_common (found, elt, elt->key, 2096b04a7a0bSBaptiste Daroussin elt->keylen, copy_key, false, false); 2097c99fb5f9SBaptiste Daroussin } 2098c99fb5f9SBaptiste Daroussin else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 2099c99fb5f9SBaptiste Daroussin /* Mix two hashes */ 2100c99fb5f9SBaptiste Daroussin while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 2101b04a7a0bSBaptiste Daroussin tmp = ucl_object_ref (cur); 2102b04a7a0bSBaptiste Daroussin ucl_object_insert_key_common (found, tmp, cur->key, 2103b04a7a0bSBaptiste Daroussin cur->keylen, copy_key, false, false); 2104c99fb5f9SBaptiste Daroussin } 2105c99fb5f9SBaptiste Daroussin ucl_object_unref (elt); 2106c99fb5f9SBaptiste Daroussin } 2107c99fb5f9SBaptiste Daroussin else { 2108c99fb5f9SBaptiste Daroussin /* Just make a list of scalars */ 2109c99fb5f9SBaptiste Daroussin DL_APPEND (found, elt); 2110c99fb5f9SBaptiste Daroussin } 2111c99fb5f9SBaptiste Daroussin } 2112c99fb5f9SBaptiste Daroussin else { 2113c99fb5f9SBaptiste Daroussin DL_APPEND (found, elt); 2114c99fb5f9SBaptiste Daroussin } 2115c99fb5f9SBaptiste Daroussin } 2116c99fb5f9SBaptiste Daroussin 2117b04a7a0bSBaptiste Daroussin return ret; 2118c99fb5f9SBaptiste Daroussin } 2119c99fb5f9SBaptiste Daroussin 212036c53d67SBaptiste Daroussin bool 212136c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 212236c53d67SBaptiste Daroussin { 212336c53d67SBaptiste Daroussin ucl_object_t *found; 212436c53d67SBaptiste Daroussin 212597bd480fSBaptiste Daroussin if (top == NULL || key == NULL) { 212697bd480fSBaptiste Daroussin return false; 212797bd480fSBaptiste Daroussin } 212897bd480fSBaptiste Daroussin 2129b04a7a0bSBaptiste Daroussin found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); 213036c53d67SBaptiste Daroussin 213197bd480fSBaptiste Daroussin if (found == NULL) { 213236c53d67SBaptiste Daroussin return false; 213397bd480fSBaptiste Daroussin } 213436c53d67SBaptiste Daroussin 213536c53d67SBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 213636c53d67SBaptiste Daroussin ucl_object_unref (found); 213736c53d67SBaptiste Daroussin top->len --; 213836c53d67SBaptiste Daroussin 213936c53d67SBaptiste Daroussin return true; 214036c53d67SBaptiste Daroussin } 214136c53d67SBaptiste Daroussin 214236c53d67SBaptiste Daroussin bool 214336c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key) 214436c53d67SBaptiste Daroussin { 2145b04a7a0bSBaptiste Daroussin return ucl_object_delete_keyl (top, key, strlen (key)); 214636c53d67SBaptiste Daroussin } 214736c53d67SBaptiste Daroussin 2148c99fb5f9SBaptiste Daroussin ucl_object_t* 214997bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 215097bd480fSBaptiste Daroussin { 2151b04a7a0bSBaptiste Daroussin const ucl_object_t *found; 215297bd480fSBaptiste Daroussin 215397bd480fSBaptiste Daroussin if (top == NULL || key == NULL) { 215497bd480fSBaptiste Daroussin return false; 215597bd480fSBaptiste Daroussin } 215697bd480fSBaptiste Daroussin found = ucl_object_find_keyl (top, key, keylen); 215797bd480fSBaptiste Daroussin 215897bd480fSBaptiste Daroussin if (found == NULL) { 215997bd480fSBaptiste Daroussin return NULL; 216097bd480fSBaptiste Daroussin } 216197bd480fSBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 216297bd480fSBaptiste Daroussin top->len --; 216397bd480fSBaptiste Daroussin 2164b04a7a0bSBaptiste Daroussin return __DECONST (ucl_object_t *, found); 216597bd480fSBaptiste Daroussin } 216697bd480fSBaptiste Daroussin 216797bd480fSBaptiste Daroussin ucl_object_t* 216897bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key) 216997bd480fSBaptiste Daroussin { 2170b04a7a0bSBaptiste Daroussin return ucl_object_pop_keyl (top, key, strlen (key)); 217197bd480fSBaptiste Daroussin } 217297bd480fSBaptiste Daroussin 2173b04a7a0bSBaptiste Daroussin bool 2174c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 2175c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key) 2176c99fb5f9SBaptiste Daroussin { 2177c99fb5f9SBaptiste Daroussin return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 2178c99fb5f9SBaptiste Daroussin } 2179c99fb5f9SBaptiste Daroussin 2180b04a7a0bSBaptiste Daroussin bool 2181c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 2182c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key) 2183c99fb5f9SBaptiste Daroussin { 2184c99fb5f9SBaptiste Daroussin return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 2185c99fb5f9SBaptiste Daroussin } 2186c99fb5f9SBaptiste Daroussin 2187b04a7a0bSBaptiste Daroussin bool 2188c99fb5f9SBaptiste Daroussin ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 2189c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key) 2190c99fb5f9SBaptiste Daroussin { 2191c99fb5f9SBaptiste Daroussin return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 2192c99fb5f9SBaptiste Daroussin } 2193c99fb5f9SBaptiste Daroussin 21944bf54857SBaptiste Daroussin bool 21954bf54857SBaptiste Daroussin ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 21964bf54857SBaptiste Daroussin { 21974bf54857SBaptiste Daroussin ucl_object_t *cur = NULL, *cp = NULL, *found = NULL; 21984bf54857SBaptiste Daroussin ucl_object_iter_t iter = NULL; 21994bf54857SBaptiste Daroussin 22004bf54857SBaptiste Daroussin if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) { 22014bf54857SBaptiste Daroussin return false; 22024bf54857SBaptiste Daroussin } 22034bf54857SBaptiste Daroussin 22044bf54857SBaptiste Daroussin /* Mix two hashes */ 22054bf54857SBaptiste Daroussin while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) { 22064bf54857SBaptiste Daroussin if (copy) { 22074bf54857SBaptiste Daroussin cp = ucl_object_copy (cur); 22084bf54857SBaptiste Daroussin } 22094bf54857SBaptiste Daroussin else { 22104bf54857SBaptiste Daroussin cp = ucl_object_ref (cur); 22114bf54857SBaptiste Daroussin } 22124bf54857SBaptiste Daroussin found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen)); 22134bf54857SBaptiste Daroussin if (found == NULL) { 22144bf54857SBaptiste Daroussin /* The key does not exist */ 22158e3b1ab2SBaptiste Daroussin top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false); 22164bf54857SBaptiste Daroussin top->len ++; 22174bf54857SBaptiste Daroussin } 22184bf54857SBaptiste Daroussin else { 22194bf54857SBaptiste Daroussin /* The key already exists, replace it */ 22204bf54857SBaptiste Daroussin ucl_hash_replace (top->value.ov, found, cp); 22214bf54857SBaptiste Daroussin ucl_object_unref (found); 22224bf54857SBaptiste Daroussin } 22234bf54857SBaptiste Daroussin } 22244bf54857SBaptiste Daroussin 22254bf54857SBaptiste Daroussin return true; 22264bf54857SBaptiste Daroussin } 22274bf54857SBaptiste Daroussin 2228b04a7a0bSBaptiste Daroussin const ucl_object_t * 2229b04a7a0bSBaptiste Daroussin ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) 2230c99fb5f9SBaptiste Daroussin { 2231b04a7a0bSBaptiste Daroussin const ucl_object_t *ret; 2232b04a7a0bSBaptiste Daroussin ucl_object_t srch; 2233c99fb5f9SBaptiste Daroussin 2234c99fb5f9SBaptiste Daroussin if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 2235c99fb5f9SBaptiste Daroussin return NULL; 2236c99fb5f9SBaptiste Daroussin } 2237c99fb5f9SBaptiste Daroussin 2238c99fb5f9SBaptiste Daroussin srch.key = key; 2239c99fb5f9SBaptiste Daroussin srch.keylen = klen; 2240c99fb5f9SBaptiste Daroussin ret = ucl_hash_search_obj (obj->value.ov, &srch); 2241c99fb5f9SBaptiste Daroussin 2242c99fb5f9SBaptiste Daroussin return ret; 2243c99fb5f9SBaptiste Daroussin } 2244c99fb5f9SBaptiste Daroussin 2245b04a7a0bSBaptiste Daroussin const ucl_object_t * 2246b04a7a0bSBaptiste Daroussin ucl_object_find_key (const ucl_object_t *obj, const char *key) 2247c99fb5f9SBaptiste Daroussin { 2248*39ee7a7aSBaptiste Daroussin if (key == NULL) { 2249c99fb5f9SBaptiste Daroussin return NULL; 2250*39ee7a7aSBaptiste Daroussin } 2251c99fb5f9SBaptiste Daroussin 22522e8ed2b8SBaptiste Daroussin return ucl_object_find_keyl (obj, key, strlen (key)); 2253c99fb5f9SBaptiste Daroussin } 2254c99fb5f9SBaptiste Daroussin 2255b04a7a0bSBaptiste Daroussin const ucl_object_t* 2256*39ee7a7aSBaptiste Daroussin ucl_object_find_any_key (const ucl_object_t *obj, 2257*39ee7a7aSBaptiste Daroussin const char *key, ...) 2258*39ee7a7aSBaptiste Daroussin { 2259*39ee7a7aSBaptiste Daroussin va_list ap; 2260*39ee7a7aSBaptiste Daroussin const ucl_object_t *ret = NULL; 2261*39ee7a7aSBaptiste Daroussin const char *nk = NULL; 2262*39ee7a7aSBaptiste Daroussin 2263*39ee7a7aSBaptiste Daroussin if (obj == NULL || key == NULL) { 2264*39ee7a7aSBaptiste Daroussin return NULL; 2265*39ee7a7aSBaptiste Daroussin } 2266*39ee7a7aSBaptiste Daroussin 2267*39ee7a7aSBaptiste Daroussin ret = ucl_object_find_keyl (obj, key, strlen (key)); 2268*39ee7a7aSBaptiste Daroussin 2269*39ee7a7aSBaptiste Daroussin if (ret == NULL) { 2270*39ee7a7aSBaptiste Daroussin va_start (ap, key); 2271*39ee7a7aSBaptiste Daroussin 2272*39ee7a7aSBaptiste Daroussin while (ret == NULL) { 2273*39ee7a7aSBaptiste Daroussin nk = va_arg (ap, const char *); 2274*39ee7a7aSBaptiste Daroussin 2275*39ee7a7aSBaptiste Daroussin if (nk == NULL) { 2276*39ee7a7aSBaptiste Daroussin break; 2277*39ee7a7aSBaptiste Daroussin } 2278*39ee7a7aSBaptiste Daroussin else { 2279*39ee7a7aSBaptiste Daroussin ret = ucl_object_find_keyl (obj, nk, strlen (nk)); 2280*39ee7a7aSBaptiste Daroussin } 2281*39ee7a7aSBaptiste Daroussin } 2282*39ee7a7aSBaptiste Daroussin 2283*39ee7a7aSBaptiste Daroussin va_end (ap); 2284*39ee7a7aSBaptiste Daroussin } 2285*39ee7a7aSBaptiste Daroussin 2286*39ee7a7aSBaptiste Daroussin return ret; 2287*39ee7a7aSBaptiste Daroussin } 2288*39ee7a7aSBaptiste Daroussin 2289*39ee7a7aSBaptiste Daroussin const ucl_object_t* 2290b04a7a0bSBaptiste Daroussin ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 2291c99fb5f9SBaptiste Daroussin { 22928e3b1ab2SBaptiste Daroussin const ucl_object_t *elt = NULL; 2293c99fb5f9SBaptiste Daroussin 229497bd480fSBaptiste Daroussin if (obj == NULL || iter == NULL) { 229597bd480fSBaptiste Daroussin return NULL; 229697bd480fSBaptiste Daroussin } 229797bd480fSBaptiste Daroussin 2298c99fb5f9SBaptiste Daroussin if (expand_values) { 2299c99fb5f9SBaptiste Daroussin switch (obj->type) { 2300c99fb5f9SBaptiste Daroussin case UCL_OBJECT: 2301b04a7a0bSBaptiste Daroussin return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 2302c99fb5f9SBaptiste Daroussin break; 23038e3b1ab2SBaptiste Daroussin case UCL_ARRAY: { 23048e3b1ab2SBaptiste Daroussin unsigned int idx; 23058e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, obj); 23068e3b1ab2SBaptiste Daroussin idx = (unsigned int)(uintptr_t)(*iter); 23078e3b1ab2SBaptiste Daroussin 23088e3b1ab2SBaptiste Daroussin if (vec != NULL) { 23098e3b1ab2SBaptiste Daroussin while (idx < kv_size (*vec)) { 23108e3b1ab2SBaptiste Daroussin if ((elt = kv_A (*vec, idx)) != NULL) { 23118e3b1ab2SBaptiste Daroussin idx ++; 23128e3b1ab2SBaptiste Daroussin break; 2313c99fb5f9SBaptiste Daroussin } 23148e3b1ab2SBaptiste Daroussin idx ++; 2315c99fb5f9SBaptiste Daroussin } 23168e3b1ab2SBaptiste Daroussin *iter = (void *)(uintptr_t)idx; 2317c99fb5f9SBaptiste Daroussin } 23188e3b1ab2SBaptiste Daroussin 2319c99fb5f9SBaptiste Daroussin return elt; 23208e3b1ab2SBaptiste Daroussin break; 23218e3b1ab2SBaptiste Daroussin } 2322c99fb5f9SBaptiste Daroussin default: 2323c99fb5f9SBaptiste Daroussin /* Go to linear iteration */ 2324c99fb5f9SBaptiste Daroussin break; 2325c99fb5f9SBaptiste Daroussin } 2326c99fb5f9SBaptiste Daroussin } 2327c99fb5f9SBaptiste Daroussin /* Treat everything as a linear list */ 2328c99fb5f9SBaptiste Daroussin elt = *iter; 2329c99fb5f9SBaptiste Daroussin if (elt == NULL) { 2330c99fb5f9SBaptiste Daroussin elt = obj; 2331c99fb5f9SBaptiste Daroussin } 2332c99fb5f9SBaptiste Daroussin else if (elt == obj) { 2333c99fb5f9SBaptiste Daroussin return NULL; 2334c99fb5f9SBaptiste Daroussin } 2335b04a7a0bSBaptiste Daroussin *iter = __DECONST (void *, elt->next ? elt->next : obj); 2336c99fb5f9SBaptiste Daroussin return elt; 2337c99fb5f9SBaptiste Daroussin 2338c99fb5f9SBaptiste Daroussin /* Not reached */ 2339c99fb5f9SBaptiste Daroussin return NULL; 2340c99fb5f9SBaptiste Daroussin } 234197bd480fSBaptiste Daroussin 23428e3b1ab2SBaptiste Daroussin const char safe_iter_magic[4] = {'u', 'i', 't', 'e'}; 23438e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter { 23448e3b1ab2SBaptiste Daroussin char magic[4]; /* safety check */ 23458e3b1ab2SBaptiste Daroussin const ucl_object_t *impl_it; /* implicit object iteration */ 23468e3b1ab2SBaptiste Daroussin ucl_object_iter_t expl_it; /* explicit iteration */ 23478e3b1ab2SBaptiste Daroussin }; 23488e3b1ab2SBaptiste Daroussin 23498e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr) 23508e3b1ab2SBaptiste Daroussin #define UCL_SAFE_ITER_CHECK(it) do { \ 23518e3b1ab2SBaptiste Daroussin assert (it != NULL); \ 23528e3b1ab2SBaptiste Daroussin assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \ 23538e3b1ab2SBaptiste Daroussin } while (0) 23548e3b1ab2SBaptiste Daroussin 23558e3b1ab2SBaptiste Daroussin ucl_object_iter_t 23568e3b1ab2SBaptiste Daroussin ucl_object_iterate_new (const ucl_object_t *obj) 23578e3b1ab2SBaptiste Daroussin { 23588e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter *it; 23598e3b1ab2SBaptiste Daroussin 23608e3b1ab2SBaptiste Daroussin it = UCL_ALLOC (sizeof (*it)); 23618e3b1ab2SBaptiste Daroussin if (it != NULL) { 23628e3b1ab2SBaptiste Daroussin memcpy (it->magic, safe_iter_magic, sizeof (it->magic)); 23638e3b1ab2SBaptiste Daroussin it->expl_it = NULL; 23648e3b1ab2SBaptiste Daroussin it->impl_it = obj; 23658e3b1ab2SBaptiste Daroussin } 23668e3b1ab2SBaptiste Daroussin 23678e3b1ab2SBaptiste Daroussin return (ucl_object_iter_t)it; 23688e3b1ab2SBaptiste Daroussin } 23698e3b1ab2SBaptiste Daroussin 23708e3b1ab2SBaptiste Daroussin 23718e3b1ab2SBaptiste Daroussin ucl_object_iter_t 23728e3b1ab2SBaptiste Daroussin ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj) 23738e3b1ab2SBaptiste Daroussin { 23748e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 23758e3b1ab2SBaptiste Daroussin 23768e3b1ab2SBaptiste Daroussin UCL_SAFE_ITER_CHECK (rit); 23778e3b1ab2SBaptiste Daroussin 23788e3b1ab2SBaptiste Daroussin rit->impl_it = obj; 23798e3b1ab2SBaptiste Daroussin rit->expl_it = NULL; 23808e3b1ab2SBaptiste Daroussin 23818e3b1ab2SBaptiste Daroussin return it; 23828e3b1ab2SBaptiste Daroussin } 23838e3b1ab2SBaptiste Daroussin 23848e3b1ab2SBaptiste Daroussin const ucl_object_t* 23858e3b1ab2SBaptiste Daroussin ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values) 23868e3b1ab2SBaptiste Daroussin { 23878e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 23888e3b1ab2SBaptiste Daroussin const ucl_object_t *ret = NULL; 23898e3b1ab2SBaptiste Daroussin 23908e3b1ab2SBaptiste Daroussin UCL_SAFE_ITER_CHECK (rit); 23918e3b1ab2SBaptiste Daroussin 23928e3b1ab2SBaptiste Daroussin if (rit->impl_it == NULL) { 23938e3b1ab2SBaptiste Daroussin return NULL; 23948e3b1ab2SBaptiste Daroussin } 23958e3b1ab2SBaptiste Daroussin 23968e3b1ab2SBaptiste Daroussin if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) { 23978e3b1ab2SBaptiste Daroussin ret = ucl_iterate_object (rit->impl_it, &rit->expl_it, true); 23988e3b1ab2SBaptiste Daroussin 23998e3b1ab2SBaptiste Daroussin if (ret == NULL) { 24008e3b1ab2SBaptiste Daroussin /* Need to switch to another implicit object in chain */ 24018e3b1ab2SBaptiste Daroussin rit->impl_it = rit->impl_it->next; 24028e3b1ab2SBaptiste Daroussin rit->expl_it = NULL; 24038e3b1ab2SBaptiste Daroussin return ucl_object_iterate_safe (it, expand_values); 24048e3b1ab2SBaptiste Daroussin } 24058e3b1ab2SBaptiste Daroussin } 24068e3b1ab2SBaptiste Daroussin else { 24078e3b1ab2SBaptiste Daroussin /* Just iterate over the implicit array */ 24088e3b1ab2SBaptiste Daroussin ret = rit->impl_it; 24098e3b1ab2SBaptiste Daroussin rit->impl_it = rit->impl_it->next; 24108e3b1ab2SBaptiste Daroussin if (expand_values) { 24118e3b1ab2SBaptiste Daroussin /* We flatten objects if need to expand values */ 24128e3b1ab2SBaptiste Daroussin if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) { 24138e3b1ab2SBaptiste Daroussin return ucl_object_iterate_safe (it, expand_values); 24148e3b1ab2SBaptiste Daroussin } 24158e3b1ab2SBaptiste Daroussin } 24168e3b1ab2SBaptiste Daroussin } 24178e3b1ab2SBaptiste Daroussin 24188e3b1ab2SBaptiste Daroussin return ret; 24198e3b1ab2SBaptiste Daroussin } 24208e3b1ab2SBaptiste Daroussin 24218e3b1ab2SBaptiste Daroussin void 24228e3b1ab2SBaptiste Daroussin ucl_object_iterate_free (ucl_object_iter_t it) 24238e3b1ab2SBaptiste Daroussin { 24248e3b1ab2SBaptiste Daroussin struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 24258e3b1ab2SBaptiste Daroussin 24268e3b1ab2SBaptiste Daroussin UCL_SAFE_ITER_CHECK (rit); 24278e3b1ab2SBaptiste Daroussin 24288e3b1ab2SBaptiste Daroussin UCL_FREE (sizeof (*rit), it); 24298e3b1ab2SBaptiste Daroussin } 24308e3b1ab2SBaptiste Daroussin 24312e8ed2b8SBaptiste Daroussin const ucl_object_t * 24322e8ed2b8SBaptiste Daroussin ucl_lookup_path (const ucl_object_t *top, const char *path_in) { 2433*39ee7a7aSBaptiste Daroussin return ucl_lookup_path_char (top, path_in, '.'); 2434*39ee7a7aSBaptiste Daroussin } 2435*39ee7a7aSBaptiste Daroussin 2436*39ee7a7aSBaptiste Daroussin 2437*39ee7a7aSBaptiste Daroussin const ucl_object_t * 2438*39ee7a7aSBaptiste Daroussin ucl_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) { 24392e8ed2b8SBaptiste Daroussin const ucl_object_t *o = NULL, *found; 24402e8ed2b8SBaptiste Daroussin const char *p, *c; 24412e8ed2b8SBaptiste Daroussin char *err_str; 24422e8ed2b8SBaptiste Daroussin unsigned index; 24432e8ed2b8SBaptiste Daroussin 24442e8ed2b8SBaptiste Daroussin if (path_in == NULL || top == NULL) { 24452e8ed2b8SBaptiste Daroussin return NULL; 24462e8ed2b8SBaptiste Daroussin } 24472e8ed2b8SBaptiste Daroussin 24482e8ed2b8SBaptiste Daroussin found = NULL; 24492e8ed2b8SBaptiste Daroussin p = path_in; 24502e8ed2b8SBaptiste Daroussin 24512e8ed2b8SBaptiste Daroussin /* Skip leading dots */ 2452*39ee7a7aSBaptiste Daroussin while (*p == sep) { 24532e8ed2b8SBaptiste Daroussin p ++; 24542e8ed2b8SBaptiste Daroussin } 24552e8ed2b8SBaptiste Daroussin 24562e8ed2b8SBaptiste Daroussin c = p; 24572e8ed2b8SBaptiste Daroussin while (*p != '\0') { 24582e8ed2b8SBaptiste Daroussin p ++; 2459*39ee7a7aSBaptiste Daroussin if (*p == sep || *p == '\0') { 24602e8ed2b8SBaptiste Daroussin if (p > c) { 24612e8ed2b8SBaptiste Daroussin switch (top->type) { 24622e8ed2b8SBaptiste Daroussin case UCL_ARRAY: 24632e8ed2b8SBaptiste Daroussin /* Key should be an int */ 24642e8ed2b8SBaptiste Daroussin index = strtoul (c, &err_str, 10); 2465*39ee7a7aSBaptiste Daroussin if (err_str != NULL && (*err_str != sep && *err_str != '\0')) { 24662e8ed2b8SBaptiste Daroussin return NULL; 24672e8ed2b8SBaptiste Daroussin } 24682e8ed2b8SBaptiste Daroussin o = ucl_array_find_index (top, index); 24692e8ed2b8SBaptiste Daroussin break; 24702e8ed2b8SBaptiste Daroussin default: 24712e8ed2b8SBaptiste Daroussin o = ucl_object_find_keyl (top, c, p - c); 24722e8ed2b8SBaptiste Daroussin break; 24732e8ed2b8SBaptiste Daroussin } 24742e8ed2b8SBaptiste Daroussin if (o == NULL) { 24752e8ed2b8SBaptiste Daroussin return NULL; 24762e8ed2b8SBaptiste Daroussin } 24772e8ed2b8SBaptiste Daroussin top = o; 24782e8ed2b8SBaptiste Daroussin } 24792e8ed2b8SBaptiste Daroussin if (*p != '\0') { 24802e8ed2b8SBaptiste Daroussin c = p + 1; 24812e8ed2b8SBaptiste Daroussin } 24822e8ed2b8SBaptiste Daroussin } 24832e8ed2b8SBaptiste Daroussin } 24842e8ed2b8SBaptiste Daroussin found = o; 24852e8ed2b8SBaptiste Daroussin 24862e8ed2b8SBaptiste Daroussin return found; 24872e8ed2b8SBaptiste Daroussin } 24882e8ed2b8SBaptiste Daroussin 248997bd480fSBaptiste Daroussin 249097bd480fSBaptiste Daroussin ucl_object_t * 249197bd480fSBaptiste Daroussin ucl_object_new (void) 249297bd480fSBaptiste Daroussin { 24934bf54857SBaptiste Daroussin return ucl_object_typed_new (UCL_NULL); 249497bd480fSBaptiste Daroussin } 249597bd480fSBaptiste Daroussin 249697bd480fSBaptiste Daroussin ucl_object_t * 24972e8ed2b8SBaptiste Daroussin ucl_object_typed_new (ucl_type_t type) 249897bd480fSBaptiste Daroussin { 24994bf54857SBaptiste Daroussin return ucl_object_new_full (type, 0); 25004bf54857SBaptiste Daroussin } 25014bf54857SBaptiste Daroussin 25024bf54857SBaptiste Daroussin ucl_object_t * 25034bf54857SBaptiste Daroussin ucl_object_new_full (ucl_type_t type, unsigned priority) 25044bf54857SBaptiste Daroussin { 250597bd480fSBaptiste Daroussin ucl_object_t *new; 25064bf54857SBaptiste Daroussin 25074bf54857SBaptiste Daroussin if (type != UCL_USERDATA) { 25084bf54857SBaptiste Daroussin new = UCL_ALLOC (sizeof (ucl_object_t)); 250997bd480fSBaptiste Daroussin if (new != NULL) { 251097bd480fSBaptiste Daroussin memset (new, 0, sizeof (ucl_object_t)); 251197bd480fSBaptiste Daroussin new->ref = 1; 251297bd480fSBaptiste Daroussin new->type = (type <= UCL_NULL ? type : UCL_NULL); 25134bf54857SBaptiste Daroussin new->next = NULL; 25144bf54857SBaptiste Daroussin new->prev = new; 25154bf54857SBaptiste Daroussin ucl_object_set_priority (new, priority); 25168e3b1ab2SBaptiste Daroussin 25178e3b1ab2SBaptiste Daroussin if (type == UCL_ARRAY) { 25188e3b1ab2SBaptiste Daroussin new->value.av = UCL_ALLOC (sizeof (ucl_array_t)); 25198e3b1ab2SBaptiste Daroussin if (new->value.av) { 25208e3b1ab2SBaptiste Daroussin memset (new->value.av, 0, sizeof (ucl_array_t)); 25218e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, new); 25228e3b1ab2SBaptiste Daroussin 25238e3b1ab2SBaptiste Daroussin /* Preallocate some space for arrays */ 25248e3b1ab2SBaptiste Daroussin kv_resize (ucl_object_t *, *vec, 8); 25258e3b1ab2SBaptiste Daroussin } 25268e3b1ab2SBaptiste Daroussin } 252797bd480fSBaptiste Daroussin } 25284bf54857SBaptiste Daroussin } 25294bf54857SBaptiste Daroussin else { 25304bf54857SBaptiste Daroussin new = ucl_object_new_userdata (NULL, NULL); 25314bf54857SBaptiste Daroussin ucl_object_set_priority (new, priority); 25324bf54857SBaptiste Daroussin } 25334bf54857SBaptiste Daroussin 253497bd480fSBaptiste Daroussin return new; 253597bd480fSBaptiste Daroussin } 253697bd480fSBaptiste Daroussin 25374bf54857SBaptiste Daroussin ucl_object_t* 25384bf54857SBaptiste Daroussin ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter) 25394bf54857SBaptiste Daroussin { 25404bf54857SBaptiste Daroussin struct ucl_object_userdata *new; 25414bf54857SBaptiste Daroussin size_t nsize = sizeof (*new); 25424bf54857SBaptiste Daroussin 25434bf54857SBaptiste Daroussin new = UCL_ALLOC (nsize); 25444bf54857SBaptiste Daroussin if (new != NULL) { 25454bf54857SBaptiste Daroussin memset (new, 0, nsize); 25464bf54857SBaptiste Daroussin new->obj.ref = 1; 25474bf54857SBaptiste Daroussin new->obj.type = UCL_USERDATA; 25484bf54857SBaptiste Daroussin new->obj.next = NULL; 25494bf54857SBaptiste Daroussin new->obj.prev = (ucl_object_t *)new; 25504bf54857SBaptiste Daroussin new->dtor = dtor; 25514bf54857SBaptiste Daroussin new->emitter = emitter; 25524bf54857SBaptiste Daroussin } 25534bf54857SBaptiste Daroussin 25544bf54857SBaptiste Daroussin return (ucl_object_t *)new; 25554bf54857SBaptiste Daroussin } 25564bf54857SBaptiste Daroussin 25572e8ed2b8SBaptiste Daroussin ucl_type_t 25582e8ed2b8SBaptiste Daroussin ucl_object_type (const ucl_object_t *obj) 25592e8ed2b8SBaptiste Daroussin { 2560*39ee7a7aSBaptiste Daroussin if (obj == NULL) { 2561*39ee7a7aSBaptiste Daroussin return UCL_NULL; 2562*39ee7a7aSBaptiste Daroussin } 2563*39ee7a7aSBaptiste Daroussin 25642e8ed2b8SBaptiste Daroussin return obj->type; 25652e8ed2b8SBaptiste Daroussin } 25662e8ed2b8SBaptiste Daroussin 256797bd480fSBaptiste Daroussin ucl_object_t* 256897bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str) 256997bd480fSBaptiste Daroussin { 257097bd480fSBaptiste Daroussin return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 257197bd480fSBaptiste Daroussin } 257297bd480fSBaptiste Daroussin 257397bd480fSBaptiste Daroussin ucl_object_t * 257497bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len) 257597bd480fSBaptiste Daroussin { 257697bd480fSBaptiste Daroussin return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 257797bd480fSBaptiste Daroussin } 257897bd480fSBaptiste Daroussin 257997bd480fSBaptiste Daroussin ucl_object_t * 258097bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv) 258197bd480fSBaptiste Daroussin { 258297bd480fSBaptiste Daroussin ucl_object_t *obj; 258397bd480fSBaptiste Daroussin 258497bd480fSBaptiste Daroussin obj = ucl_object_new (); 258597bd480fSBaptiste Daroussin if (obj != NULL) { 258697bd480fSBaptiste Daroussin obj->type = UCL_INT; 258797bd480fSBaptiste Daroussin obj->value.iv = iv; 258897bd480fSBaptiste Daroussin } 258997bd480fSBaptiste Daroussin 259097bd480fSBaptiste Daroussin return obj; 259197bd480fSBaptiste Daroussin } 259297bd480fSBaptiste Daroussin 259397bd480fSBaptiste Daroussin ucl_object_t * 259497bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv) 259597bd480fSBaptiste Daroussin { 259697bd480fSBaptiste Daroussin ucl_object_t *obj; 259797bd480fSBaptiste Daroussin 259897bd480fSBaptiste Daroussin obj = ucl_object_new (); 259997bd480fSBaptiste Daroussin if (obj != NULL) { 260097bd480fSBaptiste Daroussin obj->type = UCL_FLOAT; 260197bd480fSBaptiste Daroussin obj->value.dv = dv; 260297bd480fSBaptiste Daroussin } 260397bd480fSBaptiste Daroussin 260497bd480fSBaptiste Daroussin return obj; 260597bd480fSBaptiste Daroussin } 260697bd480fSBaptiste Daroussin 260797bd480fSBaptiste Daroussin ucl_object_t* 260897bd480fSBaptiste Daroussin ucl_object_frombool (bool bv) 260997bd480fSBaptiste Daroussin { 261097bd480fSBaptiste Daroussin ucl_object_t *obj; 261197bd480fSBaptiste Daroussin 261297bd480fSBaptiste Daroussin obj = ucl_object_new (); 261397bd480fSBaptiste Daroussin if (obj != NULL) { 261497bd480fSBaptiste Daroussin obj->type = UCL_BOOLEAN; 261597bd480fSBaptiste Daroussin obj->value.iv = bv; 261697bd480fSBaptiste Daroussin } 261797bd480fSBaptiste Daroussin 261897bd480fSBaptiste Daroussin return obj; 261997bd480fSBaptiste Daroussin } 262097bd480fSBaptiste Daroussin 2621b04a7a0bSBaptiste Daroussin bool 262297bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt) 262397bd480fSBaptiste Daroussin { 26248e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 262597bd480fSBaptiste Daroussin 2626b04a7a0bSBaptiste Daroussin if (elt == NULL || top == NULL) { 2627b04a7a0bSBaptiste Daroussin return false; 262897bd480fSBaptiste Daroussin } 262997bd480fSBaptiste Daroussin 26308e3b1ab2SBaptiste Daroussin if (vec == NULL) { 26318e3b1ab2SBaptiste Daroussin vec = UCL_ALLOC (sizeof (*vec)); 2632*39ee7a7aSBaptiste Daroussin 2633*39ee7a7aSBaptiste Daroussin if (vec == NULL) { 2634*39ee7a7aSBaptiste Daroussin return false; 2635*39ee7a7aSBaptiste Daroussin } 2636*39ee7a7aSBaptiste Daroussin 26378e3b1ab2SBaptiste Daroussin kv_init (*vec); 26388e3b1ab2SBaptiste Daroussin top->value.av = (void *)vec; 263997bd480fSBaptiste Daroussin } 26408e3b1ab2SBaptiste Daroussin 26418e3b1ab2SBaptiste Daroussin kv_push (ucl_object_t *, *vec, elt); 26428e3b1ab2SBaptiste Daroussin 264397bd480fSBaptiste Daroussin top->len ++; 2644b04a7a0bSBaptiste Daroussin 2645b04a7a0bSBaptiste Daroussin return true; 264697bd480fSBaptiste Daroussin } 264797bd480fSBaptiste Daroussin 2648b04a7a0bSBaptiste Daroussin bool 264997bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 265097bd480fSBaptiste Daroussin { 26518e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 265297bd480fSBaptiste Daroussin 2653b04a7a0bSBaptiste Daroussin if (elt == NULL || top == NULL) { 2654b04a7a0bSBaptiste Daroussin return false; 265597bd480fSBaptiste Daroussin } 265697bd480fSBaptiste Daroussin 26578e3b1ab2SBaptiste Daroussin if (vec == NULL) { 26588e3b1ab2SBaptiste Daroussin vec = UCL_ALLOC (sizeof (*vec)); 26598e3b1ab2SBaptiste Daroussin kv_init (*vec); 26608e3b1ab2SBaptiste Daroussin top->value.av = (void *)vec; 26618e3b1ab2SBaptiste Daroussin kv_push (ucl_object_t *, *vec, elt); 266297bd480fSBaptiste Daroussin } 266397bd480fSBaptiste Daroussin else { 26648e3b1ab2SBaptiste Daroussin /* Slow O(n) algorithm */ 26658e3b1ab2SBaptiste Daroussin kv_prepend (ucl_object_t *, *vec, elt); 266697bd480fSBaptiste Daroussin } 26678e3b1ab2SBaptiste Daroussin 266897bd480fSBaptiste Daroussin top->len ++; 266997bd480fSBaptiste Daroussin 2670b04a7a0bSBaptiste Daroussin return true; 267197bd480fSBaptiste Daroussin } 267297bd480fSBaptiste Daroussin 26734bf54857SBaptiste Daroussin bool 26744bf54857SBaptiste Daroussin ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 26754bf54857SBaptiste Daroussin { 26768e3b1ab2SBaptiste Daroussin unsigned i; 2677*39ee7a7aSBaptiste Daroussin ucl_object_t *cp = NULL; 26788e3b1ab2SBaptiste Daroussin ucl_object_t **obj; 26794bf54857SBaptiste Daroussin 26804bf54857SBaptiste Daroussin if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { 26814bf54857SBaptiste Daroussin return false; 26824bf54857SBaptiste Daroussin } 26834bf54857SBaptiste Daroussin 2684*39ee7a7aSBaptiste Daroussin if (copy) { 2685*39ee7a7aSBaptiste Daroussin cp = ucl_object_copy (elt); 2686*39ee7a7aSBaptiste Daroussin } 2687*39ee7a7aSBaptiste Daroussin else { 2688*39ee7a7aSBaptiste Daroussin cp = ucl_object_ref (elt); 2689*39ee7a7aSBaptiste Daroussin } 2690*39ee7a7aSBaptiste Daroussin 2691*39ee7a7aSBaptiste Daroussin UCL_ARRAY_GET (v1, top); 2692*39ee7a7aSBaptiste Daroussin UCL_ARRAY_GET (v2, cp); 2693*39ee7a7aSBaptiste Daroussin 26948e3b1ab2SBaptiste Daroussin kv_concat (ucl_object_t *, *v1, *v2); 26958e3b1ab2SBaptiste Daroussin 26968e3b1ab2SBaptiste Daroussin for (i = v2->n; i < v1->n; i ++) { 26978e3b1ab2SBaptiste Daroussin obj = &kv_A (*v1, i); 26988e3b1ab2SBaptiste Daroussin if (*obj == NULL) { 26998e3b1ab2SBaptiste Daroussin continue; 27008e3b1ab2SBaptiste Daroussin } 27018e3b1ab2SBaptiste Daroussin top->len ++; 27024bf54857SBaptiste Daroussin } 27034bf54857SBaptiste Daroussin 27044bf54857SBaptiste Daroussin return true; 27054bf54857SBaptiste Daroussin } 27064bf54857SBaptiste Daroussin 270797bd480fSBaptiste Daroussin ucl_object_t * 270897bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 270997bd480fSBaptiste Daroussin { 27108e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 27118e3b1ab2SBaptiste Daroussin ucl_object_t *ret = NULL; 27128e3b1ab2SBaptiste Daroussin unsigned i; 271397bd480fSBaptiste Daroussin 2714*39ee7a7aSBaptiste Daroussin if (vec == NULL) { 2715*39ee7a7aSBaptiste Daroussin return NULL; 2716*39ee7a7aSBaptiste Daroussin } 2717*39ee7a7aSBaptiste Daroussin 27188e3b1ab2SBaptiste Daroussin for (i = 0; i < vec->n; i ++) { 27198e3b1ab2SBaptiste Daroussin if (kv_A (*vec, i) == elt) { 27208e3b1ab2SBaptiste Daroussin kv_del (ucl_object_t *, *vec, i); 27218e3b1ab2SBaptiste Daroussin ret = elt; 272297bd480fSBaptiste Daroussin top->len --; 27238e3b1ab2SBaptiste Daroussin break; 27248e3b1ab2SBaptiste Daroussin } 27258e3b1ab2SBaptiste Daroussin } 272697bd480fSBaptiste Daroussin 27278e3b1ab2SBaptiste Daroussin return ret; 272897bd480fSBaptiste Daroussin } 272997bd480fSBaptiste Daroussin 2730b04a7a0bSBaptiste Daroussin const ucl_object_t * 2731b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top) 273297bd480fSBaptiste Daroussin { 27338e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 27348e3b1ab2SBaptiste Daroussin 2735*39ee7a7aSBaptiste Daroussin if (vec == NULL || top == NULL || top->type != UCL_ARRAY || 2736*39ee7a7aSBaptiste Daroussin top->value.av == NULL) { 273797bd480fSBaptiste Daroussin return NULL; 273897bd480fSBaptiste Daroussin } 27398e3b1ab2SBaptiste Daroussin 27408e3b1ab2SBaptiste Daroussin return (vec->n > 0 ? vec->a[0] : NULL); 274197bd480fSBaptiste Daroussin } 274297bd480fSBaptiste Daroussin 2743b04a7a0bSBaptiste Daroussin const ucl_object_t * 2744b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top) 274597bd480fSBaptiste Daroussin { 27468e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 27478e3b1ab2SBaptiste Daroussin 274897bd480fSBaptiste Daroussin if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 274997bd480fSBaptiste Daroussin return NULL; 275097bd480fSBaptiste Daroussin } 27518e3b1ab2SBaptiste Daroussin 27528e3b1ab2SBaptiste Daroussin return (vec->n > 0 ? vec->a[vec->n - 1] : NULL); 275397bd480fSBaptiste Daroussin } 275497bd480fSBaptiste Daroussin 275597bd480fSBaptiste Daroussin ucl_object_t * 275697bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top) 275797bd480fSBaptiste Daroussin { 27588e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 27598e3b1ab2SBaptiste Daroussin ucl_object_t **obj, *ret = NULL; 27608e3b1ab2SBaptiste Daroussin 27618e3b1ab2SBaptiste Daroussin if (vec != NULL && vec->n > 0) { 27628e3b1ab2SBaptiste Daroussin obj = &kv_A (*vec, vec->n - 1); 27638e3b1ab2SBaptiste Daroussin ret = *obj; 27648e3b1ab2SBaptiste Daroussin kv_del (ucl_object_t *, *vec, vec->n - 1); 27658e3b1ab2SBaptiste Daroussin top->len --; 27668e3b1ab2SBaptiste Daroussin } 27678e3b1ab2SBaptiste Daroussin 27688e3b1ab2SBaptiste Daroussin return ret; 276997bd480fSBaptiste Daroussin } 277097bd480fSBaptiste Daroussin 277197bd480fSBaptiste Daroussin ucl_object_t * 277297bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top) 277397bd480fSBaptiste Daroussin { 27748e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 27758e3b1ab2SBaptiste Daroussin ucl_object_t **obj, *ret = NULL; 27768e3b1ab2SBaptiste Daroussin 27778e3b1ab2SBaptiste Daroussin if (vec != NULL && vec->n > 0) { 27788e3b1ab2SBaptiste Daroussin obj = &kv_A (*vec, 0); 27798e3b1ab2SBaptiste Daroussin ret = *obj; 27808e3b1ab2SBaptiste Daroussin kv_del (ucl_object_t *, *vec, 0); 27818e3b1ab2SBaptiste Daroussin top->len --; 27828e3b1ab2SBaptiste Daroussin } 27838e3b1ab2SBaptiste Daroussin 27848e3b1ab2SBaptiste Daroussin return ret; 278597bd480fSBaptiste Daroussin } 278697bd480fSBaptiste Daroussin 27872e8ed2b8SBaptiste Daroussin const ucl_object_t * 27882e8ed2b8SBaptiste Daroussin ucl_array_find_index (const ucl_object_t *top, unsigned int index) 27892e8ed2b8SBaptiste Daroussin { 27908e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 27912e8ed2b8SBaptiste Daroussin 27928e3b1ab2SBaptiste Daroussin if (vec != NULL && vec->n > 0 && index < vec->n) { 27938e3b1ab2SBaptiste Daroussin return kv_A (*vec, index); 27942e8ed2b8SBaptiste Daroussin } 27952e8ed2b8SBaptiste Daroussin 27962e8ed2b8SBaptiste Daroussin return NULL; 27972e8ed2b8SBaptiste Daroussin } 27982e8ed2b8SBaptiste Daroussin 2799*39ee7a7aSBaptiste Daroussin unsigned int 2800*39ee7a7aSBaptiste Daroussin ucl_array_index_of (ucl_object_t *top, ucl_object_t *elt) 2801*39ee7a7aSBaptiste Daroussin { 2802*39ee7a7aSBaptiste Daroussin UCL_ARRAY_GET (vec, top); 2803*39ee7a7aSBaptiste Daroussin unsigned i; 2804*39ee7a7aSBaptiste Daroussin 2805*39ee7a7aSBaptiste Daroussin if (vec == NULL) { 2806*39ee7a7aSBaptiste Daroussin return (unsigned int)(-1); 2807*39ee7a7aSBaptiste Daroussin } 2808*39ee7a7aSBaptiste Daroussin 2809*39ee7a7aSBaptiste Daroussin for (i = 0; i < vec->n; i ++) { 2810*39ee7a7aSBaptiste Daroussin if (kv_A (*vec, i) == elt) { 2811*39ee7a7aSBaptiste Daroussin return i; 2812*39ee7a7aSBaptiste Daroussin } 2813*39ee7a7aSBaptiste Daroussin } 2814*39ee7a7aSBaptiste Daroussin 2815*39ee7a7aSBaptiste Daroussin return (unsigned int)(-1); 2816*39ee7a7aSBaptiste Daroussin } 2817*39ee7a7aSBaptiste Daroussin 281897bd480fSBaptiste Daroussin ucl_object_t * 28194bf54857SBaptiste Daroussin ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt, 28204bf54857SBaptiste Daroussin unsigned int index) 28214bf54857SBaptiste Daroussin { 28228e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, top); 28238e3b1ab2SBaptiste Daroussin ucl_object_t *ret = NULL; 28244bf54857SBaptiste Daroussin 28258e3b1ab2SBaptiste Daroussin if (vec != NULL && vec->n > 0 && index < vec->n) { 28268e3b1ab2SBaptiste Daroussin ret = kv_A (*vec, index); 28278e3b1ab2SBaptiste Daroussin kv_A (*vec, index) = elt; 28284bf54857SBaptiste Daroussin } 28294bf54857SBaptiste Daroussin 28308e3b1ab2SBaptiste Daroussin return ret; 28314bf54857SBaptiste Daroussin } 28324bf54857SBaptiste Daroussin 28334bf54857SBaptiste Daroussin ucl_object_t * 283497bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 283597bd480fSBaptiste Daroussin { 283697bd480fSBaptiste Daroussin 283797bd480fSBaptiste Daroussin if (head == NULL) { 283897bd480fSBaptiste Daroussin elt->next = NULL; 283997bd480fSBaptiste Daroussin elt->prev = elt; 284097bd480fSBaptiste Daroussin head = elt; 284197bd480fSBaptiste Daroussin } 284297bd480fSBaptiste Daroussin else { 284397bd480fSBaptiste Daroussin elt->prev = head->prev; 284497bd480fSBaptiste Daroussin head->prev->next = elt; 284597bd480fSBaptiste Daroussin head->prev = elt; 284697bd480fSBaptiste Daroussin elt->next = NULL; 284797bd480fSBaptiste Daroussin } 284897bd480fSBaptiste Daroussin 284997bd480fSBaptiste Daroussin return head; 285097bd480fSBaptiste Daroussin } 285197bd480fSBaptiste Daroussin 285297bd480fSBaptiste Daroussin bool 2853b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target) 285497bd480fSBaptiste Daroussin { 285597bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 285697bd480fSBaptiste Daroussin return false; 285797bd480fSBaptiste Daroussin } 285897bd480fSBaptiste Daroussin switch (obj->type) { 285997bd480fSBaptiste Daroussin case UCL_INT: 286097bd480fSBaptiste Daroussin *target = obj->value.iv; /* Probaly could cause overflow */ 286197bd480fSBaptiste Daroussin break; 286297bd480fSBaptiste Daroussin case UCL_FLOAT: 286397bd480fSBaptiste Daroussin case UCL_TIME: 286497bd480fSBaptiste Daroussin *target = obj->value.dv; 286597bd480fSBaptiste Daroussin break; 286697bd480fSBaptiste Daroussin default: 286797bd480fSBaptiste Daroussin return false; 286897bd480fSBaptiste Daroussin } 286997bd480fSBaptiste Daroussin 287097bd480fSBaptiste Daroussin return true; 287197bd480fSBaptiste Daroussin } 287297bd480fSBaptiste Daroussin 287397bd480fSBaptiste Daroussin double 2874b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj) 287597bd480fSBaptiste Daroussin { 287697bd480fSBaptiste Daroussin double result = 0.; 287797bd480fSBaptiste Daroussin 287897bd480fSBaptiste Daroussin ucl_object_todouble_safe (obj, &result); 287997bd480fSBaptiste Daroussin return result; 288097bd480fSBaptiste Daroussin } 288197bd480fSBaptiste Daroussin 288297bd480fSBaptiste Daroussin bool 2883b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 288497bd480fSBaptiste Daroussin { 288597bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 288697bd480fSBaptiste Daroussin return false; 288797bd480fSBaptiste Daroussin } 288897bd480fSBaptiste Daroussin switch (obj->type) { 288997bd480fSBaptiste Daroussin case UCL_INT: 289097bd480fSBaptiste Daroussin *target = obj->value.iv; 289197bd480fSBaptiste Daroussin break; 289297bd480fSBaptiste Daroussin case UCL_FLOAT: 289397bd480fSBaptiste Daroussin case UCL_TIME: 289497bd480fSBaptiste Daroussin *target = obj->value.dv; /* Loosing of decimal points */ 289597bd480fSBaptiste Daroussin break; 289697bd480fSBaptiste Daroussin default: 289797bd480fSBaptiste Daroussin return false; 289897bd480fSBaptiste Daroussin } 289997bd480fSBaptiste Daroussin 290097bd480fSBaptiste Daroussin return true; 290197bd480fSBaptiste Daroussin } 290297bd480fSBaptiste Daroussin 290397bd480fSBaptiste Daroussin int64_t 2904b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj) 290597bd480fSBaptiste Daroussin { 290697bd480fSBaptiste Daroussin int64_t result = 0; 290797bd480fSBaptiste Daroussin 290897bd480fSBaptiste Daroussin ucl_object_toint_safe (obj, &result); 290997bd480fSBaptiste Daroussin return result; 291097bd480fSBaptiste Daroussin } 291197bd480fSBaptiste Daroussin 291297bd480fSBaptiste Daroussin bool 2913b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 291497bd480fSBaptiste Daroussin { 291597bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 291697bd480fSBaptiste Daroussin return false; 291797bd480fSBaptiste Daroussin } 291897bd480fSBaptiste Daroussin switch (obj->type) { 291997bd480fSBaptiste Daroussin case UCL_BOOLEAN: 292097bd480fSBaptiste Daroussin *target = (obj->value.iv == true); 292197bd480fSBaptiste Daroussin break; 292297bd480fSBaptiste Daroussin default: 292397bd480fSBaptiste Daroussin return false; 292497bd480fSBaptiste Daroussin } 292597bd480fSBaptiste Daroussin 292697bd480fSBaptiste Daroussin return true; 292797bd480fSBaptiste Daroussin } 292897bd480fSBaptiste Daroussin 292997bd480fSBaptiste Daroussin bool 2930b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj) 293197bd480fSBaptiste Daroussin { 293297bd480fSBaptiste Daroussin bool result = false; 293397bd480fSBaptiste Daroussin 293497bd480fSBaptiste Daroussin ucl_object_toboolean_safe (obj, &result); 293597bd480fSBaptiste Daroussin return result; 293697bd480fSBaptiste Daroussin } 293797bd480fSBaptiste Daroussin 293897bd480fSBaptiste Daroussin bool 2939b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 294097bd480fSBaptiste Daroussin { 294197bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 294297bd480fSBaptiste Daroussin return false; 294397bd480fSBaptiste Daroussin } 294497bd480fSBaptiste Daroussin 294597bd480fSBaptiste Daroussin switch (obj->type) { 294697bd480fSBaptiste Daroussin case UCL_STRING: 2947*39ee7a7aSBaptiste Daroussin if (!(obj->flags & UCL_OBJECT_BINARY)) { 294897bd480fSBaptiste Daroussin *target = ucl_copy_value_trash (obj); 2949*39ee7a7aSBaptiste Daroussin } 295097bd480fSBaptiste Daroussin break; 295197bd480fSBaptiste Daroussin default: 295297bd480fSBaptiste Daroussin return false; 295397bd480fSBaptiste Daroussin } 295497bd480fSBaptiste Daroussin 295597bd480fSBaptiste Daroussin return true; 295697bd480fSBaptiste Daroussin } 295797bd480fSBaptiste Daroussin 295897bd480fSBaptiste Daroussin const char * 2959b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj) 296097bd480fSBaptiste Daroussin { 296197bd480fSBaptiste Daroussin const char *result = NULL; 296297bd480fSBaptiste Daroussin 296397bd480fSBaptiste Daroussin ucl_object_tostring_safe (obj, &result); 296497bd480fSBaptiste Daroussin return result; 296597bd480fSBaptiste Daroussin } 296697bd480fSBaptiste Daroussin 296797bd480fSBaptiste Daroussin const char * 2968b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj) 296997bd480fSBaptiste Daroussin { 2970*39ee7a7aSBaptiste Daroussin /* TODO: For binary strings we might encode string here */ 2971*39ee7a7aSBaptiste Daroussin if (!(obj->flags & UCL_OBJECT_BINARY)) { 297297bd480fSBaptiste Daroussin return ucl_copy_value_trash (obj); 297397bd480fSBaptiste Daroussin } 297497bd480fSBaptiste Daroussin 2975*39ee7a7aSBaptiste Daroussin return NULL; 2976*39ee7a7aSBaptiste Daroussin } 2977*39ee7a7aSBaptiste Daroussin 297897bd480fSBaptiste Daroussin bool 2979b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 298097bd480fSBaptiste Daroussin { 298197bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 298297bd480fSBaptiste Daroussin return false; 298397bd480fSBaptiste Daroussin } 298497bd480fSBaptiste Daroussin switch (obj->type) { 298597bd480fSBaptiste Daroussin case UCL_STRING: 298697bd480fSBaptiste Daroussin *target = obj->value.sv; 298797bd480fSBaptiste Daroussin if (tlen != NULL) { 298897bd480fSBaptiste Daroussin *tlen = obj->len; 298997bd480fSBaptiste Daroussin } 299097bd480fSBaptiste Daroussin break; 299197bd480fSBaptiste Daroussin default: 299297bd480fSBaptiste Daroussin return false; 299397bd480fSBaptiste Daroussin } 299497bd480fSBaptiste Daroussin 299597bd480fSBaptiste Daroussin return true; 299697bd480fSBaptiste Daroussin } 299797bd480fSBaptiste Daroussin 299897bd480fSBaptiste Daroussin const char * 2999b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 300097bd480fSBaptiste Daroussin { 300197bd480fSBaptiste Daroussin const char *result = NULL; 300297bd480fSBaptiste Daroussin 300397bd480fSBaptiste Daroussin ucl_object_tolstring_safe (obj, &result, tlen); 300497bd480fSBaptiste Daroussin return result; 300597bd480fSBaptiste Daroussin } 300697bd480fSBaptiste Daroussin 300797bd480fSBaptiste Daroussin const char * 3008b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj) 300997bd480fSBaptiste Daroussin { 301097bd480fSBaptiste Daroussin return ucl_copy_key_trash (obj); 301197bd480fSBaptiste Daroussin } 301297bd480fSBaptiste Daroussin 301397bd480fSBaptiste Daroussin const char * 3014b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len) 301597bd480fSBaptiste Daroussin { 301697bd480fSBaptiste Daroussin if (len == NULL || obj == NULL) { 301797bd480fSBaptiste Daroussin return NULL; 301897bd480fSBaptiste Daroussin } 301997bd480fSBaptiste Daroussin *len = obj->keylen; 302097bd480fSBaptiste Daroussin return obj->key; 302197bd480fSBaptiste Daroussin } 302297bd480fSBaptiste Daroussin 302397bd480fSBaptiste Daroussin ucl_object_t * 3024b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj) 302597bd480fSBaptiste Daroussin { 3026b04a7a0bSBaptiste Daroussin ucl_object_t *res = NULL; 3027b04a7a0bSBaptiste Daroussin 302897bd480fSBaptiste Daroussin if (obj != NULL) { 30294bf54857SBaptiste Daroussin if (obj->flags & UCL_OBJECT_EPHEMERAL) { 30304bf54857SBaptiste Daroussin /* 30314bf54857SBaptiste Daroussin * Use deep copy for ephemeral objects, note that its refcount 30324bf54857SBaptiste Daroussin * is NOT increased, since ephemeral objects does not need refcount 30334bf54857SBaptiste Daroussin * at all 30344bf54857SBaptiste Daroussin */ 30354bf54857SBaptiste Daroussin res = ucl_object_copy (obj); 30364bf54857SBaptiste Daroussin } 30374bf54857SBaptiste Daroussin else { 3038b04a7a0bSBaptiste Daroussin res = __DECONST (ucl_object_t *, obj); 3039b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS 3040b04a7a0bSBaptiste Daroussin (void)__sync_add_and_fetch (&res->ref, 1); 3041b04a7a0bSBaptiste Daroussin #else 3042b04a7a0bSBaptiste Daroussin res->ref ++; 3043b04a7a0bSBaptiste Daroussin #endif 304497bd480fSBaptiste Daroussin } 30454bf54857SBaptiste Daroussin } 3046b04a7a0bSBaptiste Daroussin return res; 304797bd480fSBaptiste Daroussin } 304897bd480fSBaptiste Daroussin 30494bf54857SBaptiste Daroussin static ucl_object_t * 30504bf54857SBaptiste Daroussin ucl_object_copy_internal (const ucl_object_t *other, bool allow_array) 30514bf54857SBaptiste Daroussin { 30524bf54857SBaptiste Daroussin 30534bf54857SBaptiste Daroussin ucl_object_t *new; 30544bf54857SBaptiste Daroussin ucl_object_iter_t it = NULL; 30554bf54857SBaptiste Daroussin const ucl_object_t *cur; 30564bf54857SBaptiste Daroussin 30574bf54857SBaptiste Daroussin new = malloc (sizeof (*new)); 30584bf54857SBaptiste Daroussin 30594bf54857SBaptiste Daroussin if (new != NULL) { 30604bf54857SBaptiste Daroussin memcpy (new, other, sizeof (*new)); 30614bf54857SBaptiste Daroussin if (other->flags & UCL_OBJECT_EPHEMERAL) { 30624bf54857SBaptiste Daroussin /* Copied object is always non ephemeral */ 30634bf54857SBaptiste Daroussin new->flags &= ~UCL_OBJECT_EPHEMERAL; 30644bf54857SBaptiste Daroussin } 30654bf54857SBaptiste Daroussin new->ref = 1; 30664bf54857SBaptiste Daroussin /* Unlink from others */ 30674bf54857SBaptiste Daroussin new->next = NULL; 30684bf54857SBaptiste Daroussin new->prev = new; 30694bf54857SBaptiste Daroussin 30704bf54857SBaptiste Daroussin /* deep copy of values stored */ 30714bf54857SBaptiste Daroussin if (other->trash_stack[UCL_TRASH_KEY] != NULL) { 30724bf54857SBaptiste Daroussin new->trash_stack[UCL_TRASH_KEY] = 30734bf54857SBaptiste Daroussin strdup (other->trash_stack[UCL_TRASH_KEY]); 30744bf54857SBaptiste Daroussin if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { 30754bf54857SBaptiste Daroussin new->key = new->trash_stack[UCL_TRASH_KEY]; 30764bf54857SBaptiste Daroussin } 30774bf54857SBaptiste Daroussin } 30784bf54857SBaptiste Daroussin if (other->trash_stack[UCL_TRASH_VALUE] != NULL) { 30794bf54857SBaptiste Daroussin new->trash_stack[UCL_TRASH_VALUE] = 30804bf54857SBaptiste Daroussin strdup (other->trash_stack[UCL_TRASH_VALUE]); 30814bf54857SBaptiste Daroussin if (new->type == UCL_STRING) { 30824bf54857SBaptiste Daroussin new->value.sv = new->trash_stack[UCL_TRASH_VALUE]; 30834bf54857SBaptiste Daroussin } 30844bf54857SBaptiste Daroussin } 30854bf54857SBaptiste Daroussin 30864bf54857SBaptiste Daroussin if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) { 30874bf54857SBaptiste Daroussin /* reset old value */ 30884bf54857SBaptiste Daroussin memset (&new->value, 0, sizeof (new->value)); 30894bf54857SBaptiste Daroussin 30904bf54857SBaptiste Daroussin while ((cur = ucl_iterate_object (other, &it, true)) != NULL) { 30914bf54857SBaptiste Daroussin if (other->type == UCL_ARRAY) { 30924bf54857SBaptiste Daroussin ucl_array_append (new, ucl_object_copy_internal (cur, false)); 30934bf54857SBaptiste Daroussin } 30944bf54857SBaptiste Daroussin else { 30954bf54857SBaptiste Daroussin ucl_object_t *cp = ucl_object_copy_internal (cur, true); 30964bf54857SBaptiste Daroussin if (cp != NULL) { 30974bf54857SBaptiste Daroussin ucl_object_insert_key (new, cp, cp->key, cp->keylen, 30984bf54857SBaptiste Daroussin false); 30994bf54857SBaptiste Daroussin } 31004bf54857SBaptiste Daroussin } 31014bf54857SBaptiste Daroussin } 31024bf54857SBaptiste Daroussin } 31034bf54857SBaptiste Daroussin else if (allow_array && other->next != NULL) { 31044bf54857SBaptiste Daroussin LL_FOREACH (other->next, cur) { 31054bf54857SBaptiste Daroussin ucl_object_t *cp = ucl_object_copy_internal (cur, false); 31064bf54857SBaptiste Daroussin if (cp != NULL) { 31074bf54857SBaptiste Daroussin DL_APPEND (new, cp); 31084bf54857SBaptiste Daroussin } 31094bf54857SBaptiste Daroussin } 31104bf54857SBaptiste Daroussin } 31114bf54857SBaptiste Daroussin } 31124bf54857SBaptiste Daroussin 31134bf54857SBaptiste Daroussin return new; 31144bf54857SBaptiste Daroussin } 31154bf54857SBaptiste Daroussin 31164bf54857SBaptiste Daroussin ucl_object_t * 31174bf54857SBaptiste Daroussin ucl_object_copy (const ucl_object_t *other) 31184bf54857SBaptiste Daroussin { 31194bf54857SBaptiste Daroussin return ucl_object_copy_internal (other, true); 31204bf54857SBaptiste Daroussin } 31214bf54857SBaptiste Daroussin 312297bd480fSBaptiste Daroussin void 312397bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj) 312497bd480fSBaptiste Daroussin { 3125b04a7a0bSBaptiste Daroussin if (obj != NULL) { 3126b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS 3127b04a7a0bSBaptiste Daroussin unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 3128b04a7a0bSBaptiste Daroussin if (rc == 0) { 3129b04a7a0bSBaptiste Daroussin #else 3130b04a7a0bSBaptiste Daroussin if (--obj->ref == 0) { 3131b04a7a0bSBaptiste Daroussin #endif 3132b04a7a0bSBaptiste Daroussin ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 3133b04a7a0bSBaptiste Daroussin } 313497bd480fSBaptiste Daroussin } 313597bd480fSBaptiste Daroussin } 313697bd480fSBaptiste Daroussin 313797bd480fSBaptiste Daroussin int 3138b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 313997bd480fSBaptiste Daroussin { 3140b04a7a0bSBaptiste Daroussin const ucl_object_t *it1, *it2; 314197bd480fSBaptiste Daroussin ucl_object_iter_t iter = NULL; 314297bd480fSBaptiste Daroussin int ret = 0; 314397bd480fSBaptiste Daroussin 314497bd480fSBaptiste Daroussin if (o1->type != o2->type) { 314597bd480fSBaptiste Daroussin return (o1->type) - (o2->type); 314697bd480fSBaptiste Daroussin } 314797bd480fSBaptiste Daroussin 314897bd480fSBaptiste Daroussin switch (o1->type) { 314997bd480fSBaptiste Daroussin case UCL_STRING: 31508e3b1ab2SBaptiste Daroussin if (o1->len == o2->len && o1->len > 0) { 315197bd480fSBaptiste Daroussin ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 315297bd480fSBaptiste Daroussin } 315397bd480fSBaptiste Daroussin else { 315497bd480fSBaptiste Daroussin ret = o1->len - o2->len; 315597bd480fSBaptiste Daroussin } 315697bd480fSBaptiste Daroussin break; 315797bd480fSBaptiste Daroussin case UCL_FLOAT: 315897bd480fSBaptiste Daroussin case UCL_INT: 315997bd480fSBaptiste Daroussin case UCL_TIME: 316097bd480fSBaptiste Daroussin ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 316197bd480fSBaptiste Daroussin break; 316297bd480fSBaptiste Daroussin case UCL_BOOLEAN: 316397bd480fSBaptiste Daroussin ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 316497bd480fSBaptiste Daroussin break; 316597bd480fSBaptiste Daroussin case UCL_ARRAY: 31668e3b1ab2SBaptiste Daroussin if (o1->len == o2->len && o1->len > 0) { 31678e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec1, o1); 31688e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec2, o2); 31698e3b1ab2SBaptiste Daroussin unsigned i; 31708e3b1ab2SBaptiste Daroussin 317197bd480fSBaptiste Daroussin /* Compare all elements in both arrays */ 31728e3b1ab2SBaptiste Daroussin for (i = 0; i < vec1->n; i ++) { 31738e3b1ab2SBaptiste Daroussin it1 = kv_A (*vec1, i); 31748e3b1ab2SBaptiste Daroussin it2 = kv_A (*vec2, i); 31758e3b1ab2SBaptiste Daroussin 31768e3b1ab2SBaptiste Daroussin if (it1 == NULL && it2 != NULL) { 31778e3b1ab2SBaptiste Daroussin return -1; 31788e3b1ab2SBaptiste Daroussin } 31798e3b1ab2SBaptiste Daroussin else if (it2 == NULL && it1 != NULL) { 31808e3b1ab2SBaptiste Daroussin return 1; 31818e3b1ab2SBaptiste Daroussin } 31828e3b1ab2SBaptiste Daroussin else if (it1 != NULL && it2 != NULL) { 318397bd480fSBaptiste Daroussin ret = ucl_object_compare (it1, it2); 318497bd480fSBaptiste Daroussin if (ret != 0) { 318597bd480fSBaptiste Daroussin break; 318697bd480fSBaptiste Daroussin } 31878e3b1ab2SBaptiste Daroussin } 318897bd480fSBaptiste Daroussin } 318997bd480fSBaptiste Daroussin } 319097bd480fSBaptiste Daroussin else { 319197bd480fSBaptiste Daroussin ret = o1->len - o2->len; 319297bd480fSBaptiste Daroussin } 319397bd480fSBaptiste Daroussin break; 319497bd480fSBaptiste Daroussin case UCL_OBJECT: 31958e3b1ab2SBaptiste Daroussin if (o1->len == o2->len && o1->len > 0) { 319697bd480fSBaptiste Daroussin while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 319797bd480fSBaptiste Daroussin it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 319897bd480fSBaptiste Daroussin if (it2 == NULL) { 319997bd480fSBaptiste Daroussin ret = 1; 320097bd480fSBaptiste Daroussin break; 320197bd480fSBaptiste Daroussin } 320297bd480fSBaptiste Daroussin ret = ucl_object_compare (it1, it2); 320397bd480fSBaptiste Daroussin if (ret != 0) { 320497bd480fSBaptiste Daroussin break; 320597bd480fSBaptiste Daroussin } 320697bd480fSBaptiste Daroussin } 320797bd480fSBaptiste Daroussin } 320897bd480fSBaptiste Daroussin else { 320997bd480fSBaptiste Daroussin ret = o1->len - o2->len; 321097bd480fSBaptiste Daroussin } 321197bd480fSBaptiste Daroussin break; 321297bd480fSBaptiste Daroussin default: 321397bd480fSBaptiste Daroussin ret = 0; 321497bd480fSBaptiste Daroussin break; 321597bd480fSBaptiste Daroussin } 321697bd480fSBaptiste Daroussin 321797bd480fSBaptiste Daroussin return ret; 321897bd480fSBaptiste Daroussin } 321997bd480fSBaptiste Daroussin 322097bd480fSBaptiste Daroussin void 322197bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar, 3222*39ee7a7aSBaptiste Daroussin int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2)) 322397bd480fSBaptiste Daroussin { 32248e3b1ab2SBaptiste Daroussin UCL_ARRAY_GET (vec, ar); 32258e3b1ab2SBaptiste Daroussin 322697bd480fSBaptiste Daroussin if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 322797bd480fSBaptiste Daroussin return; 322897bd480fSBaptiste Daroussin } 322997bd480fSBaptiste Daroussin 32308e3b1ab2SBaptiste Daroussin qsort (vec->a, vec->n, sizeof (ucl_object_t *), 32318e3b1ab2SBaptiste Daroussin (int (*)(const void *, const void *))cmp); 323297bd480fSBaptiste Daroussin } 32334bf54857SBaptiste Daroussin 32344bf54857SBaptiste Daroussin #define PRIOBITS 4 32354bf54857SBaptiste Daroussin 32364bf54857SBaptiste Daroussin unsigned int 32374bf54857SBaptiste Daroussin ucl_object_get_priority (const ucl_object_t *obj) 32384bf54857SBaptiste Daroussin { 32394bf54857SBaptiste Daroussin if (obj == NULL) { 32404bf54857SBaptiste Daroussin return 0; 32414bf54857SBaptiste Daroussin } 32424bf54857SBaptiste Daroussin 32434bf54857SBaptiste Daroussin return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS)); 32444bf54857SBaptiste Daroussin } 32454bf54857SBaptiste Daroussin 32464bf54857SBaptiste Daroussin void 32474bf54857SBaptiste Daroussin ucl_object_set_priority (ucl_object_t *obj, 32484bf54857SBaptiste Daroussin unsigned int priority) 32494bf54857SBaptiste Daroussin { 32504bf54857SBaptiste Daroussin if (obj != NULL) { 32514bf54857SBaptiste Daroussin priority &= (0x1 << PRIOBITS) - 1; 3252*39ee7a7aSBaptiste Daroussin priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS); 3253*39ee7a7aSBaptiste Daroussin priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) - 3254*39ee7a7aSBaptiste Daroussin PRIOBITS)) - 1); 3255*39ee7a7aSBaptiste Daroussin obj->flags = priority; 32564bf54857SBaptiste Daroussin } 32574bf54857SBaptiste Daroussin } 3258