ucl_util.c revision 290071
1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov 2290071Sbapt * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> 3262395Sbapt * All rights reserved. 4262395Sbapt * 5262395Sbapt * Redistribution and use in source and binary forms, with or without 6262395Sbapt * modification, are permitted provided that the following conditions are met: 7262395Sbapt * * Redistributions of source code must retain the above copyright 8262395Sbapt * notice, this list of conditions and the following disclaimer. 9262395Sbapt * * Redistributions in binary form must reproduce the above copyright 10262395Sbapt * notice, this list of conditions and the following disclaimer in the 11262395Sbapt * documentation and/or other materials provided with the distribution. 12262395Sbapt * 13262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 14262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 17262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23262395Sbapt */ 24262395Sbapt 25262395Sbapt#include "ucl.h" 26262395Sbapt#include "ucl_internal.h" 27262395Sbapt#include "ucl_chartable.h" 28279549Sbapt#include "kvec.h" 29290071Sbapt#include <stdarg.h> 30262395Sbapt 31279549Sbapt#ifndef _WIN32 32275223Sbapt#include <glob.h> 33279549Sbapt#endif 34275223Sbapt 35263648Sbapt#ifdef HAVE_LIBGEN_H 36262395Sbapt#include <libgen.h> /* For dirname */ 37263648Sbapt#endif 38262395Sbapt 39279549Sbapttypedef kvec_t(ucl_object_t *) ucl_array_t; 40279549Sbapt 41279549Sbapt#define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \ 42279549Sbapt (ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL) 43279549Sbapt 44262395Sbapt#ifdef HAVE_OPENSSL 45262395Sbapt#include <openssl/err.h> 46262395Sbapt#include <openssl/sha.h> 47262395Sbapt#include <openssl/rsa.h> 48262395Sbapt#include <openssl/ssl.h> 49262395Sbapt#include <openssl/evp.h> 50262395Sbapt#endif 51262395Sbapt 52263648Sbapt#ifdef CURL_FOUND 53263648Sbapt#include <curl/curl.h> 54263648Sbapt#endif 55263648Sbapt#ifdef HAVE_FETCH_H 56263648Sbapt#include <fetch.h> 57263648Sbapt#endif 58263648Sbapt 59262975Sbapt#ifdef _WIN32 60262975Sbapt#include <windows.h> 61262975Sbapt 62263648Sbapt#ifndef PROT_READ 63262975Sbapt#define PROT_READ 1 64263648Sbapt#endif 65263648Sbapt#ifndef PROT_WRITE 66262975Sbapt#define PROT_WRITE 2 67263648Sbapt#endif 68263648Sbapt#ifndef PROT_READWRITE 69262975Sbapt#define PROT_READWRITE 3 70263648Sbapt#endif 71263648Sbapt#ifndef MAP_SHARED 72262975Sbapt#define MAP_SHARED 1 73263648Sbapt#endif 74263648Sbapt#ifndef MAP_PRIVATE 75262975Sbapt#define MAP_PRIVATE 2 76263648Sbapt#endif 77263648Sbapt#ifndef MAP_FAILED 78262975Sbapt#define MAP_FAILED ((void *) -1) 79263648Sbapt#endif 80262975Sbapt 81279549Sbapt#ifdef _WIN32 82279549Sbapt#include <limits.h> 83279549Sbapt#define NBBY CHAR_BIT 84279549Sbapt#endif 85279549Sbapt 86263648Sbaptstatic void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 87262975Sbapt{ 88262975Sbapt void *map = NULL; 89262975Sbapt HANDLE handle = INVALID_HANDLE_VALUE; 90262975Sbapt 91262975Sbapt switch (prot) { 92262975Sbapt default: 93262975Sbapt case PROT_READ: 94262975Sbapt { 95262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 96262975Sbapt if (!handle) break; 97262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 98262975Sbapt CloseHandle(handle); 99262975Sbapt break; 100262975Sbapt } 101262975Sbapt case PROT_WRITE: 102262975Sbapt { 103262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 104262975Sbapt if (!handle) break; 105262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 106262975Sbapt CloseHandle(handle); 107262975Sbapt break; 108262975Sbapt } 109262975Sbapt case PROT_READWRITE: 110262975Sbapt { 111262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 112262975Sbapt if (!handle) break; 113262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 114262975Sbapt CloseHandle(handle); 115262975Sbapt break; 116262975Sbapt } 117262975Sbapt } 118262975Sbapt if (map == (void *) NULL) { 119262975Sbapt return (void *) MAP_FAILED; 120262975Sbapt } 121262975Sbapt return (void *) ((char *) map + offset); 122262975Sbapt} 123262975Sbapt 124263648Sbaptstatic int ucl_munmap(void *map,size_t length) 125262975Sbapt{ 126262975Sbapt if (!UnmapViewOfFile(map)) { 127262975Sbapt return(-1); 128262975Sbapt } 129262975Sbapt return(0); 130262975Sbapt} 131262975Sbapt 132263648Sbaptstatic char* ucl_realpath(const char *path, char *resolved_path) { 133262975Sbapt char *p; 134262975Sbapt char tmp[MAX_PATH + 1]; 135262975Sbapt strncpy(tmp, path, sizeof(tmp)-1); 136262975Sbapt p = tmp; 137262975Sbapt while(*p) { 138262975Sbapt if (*p == '/') *p = '\\'; 139262975Sbapt p++; 140262975Sbapt } 141262975Sbapt return _fullpath(resolved_path, tmp, MAX_PATH); 142262975Sbapt} 143263648Sbapt#else 144263648Sbapt#define ucl_mmap mmap 145263648Sbapt#define ucl_munmap munmap 146263648Sbapt#define ucl_realpath realpath 147262975Sbapt#endif 148262975Sbapt 149264789Sbapttypedef void (*ucl_object_dtor) (ucl_object_t *obj); 150264789Sbaptstatic void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 151264789Sbapt ucl_object_dtor dtor); 152264789Sbaptstatic void ucl_object_dtor_unref (ucl_object_t *obj); 153262395Sbapt 154262395Sbaptstatic void 155264789Sbaptucl_object_dtor_free (ucl_object_t *obj) 156262395Sbapt{ 157264789Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 158264789Sbapt UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 159264789Sbapt } 160264789Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 161264789Sbapt UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 162264789Sbapt } 163275223Sbapt /* Do not free ephemeral objects */ 164275223Sbapt if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) { 165275223Sbapt if (obj->type != UCL_USERDATA) { 166275223Sbapt UCL_FREE (sizeof (ucl_object_t), obj); 167275223Sbapt } 168275223Sbapt else { 169275223Sbapt struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj; 170275223Sbapt if (ud->dtor) { 171275223Sbapt ud->dtor (obj->value.ud); 172275223Sbapt } 173275223Sbapt UCL_FREE (sizeof (*ud), obj); 174275223Sbapt } 175275223Sbapt } 176264789Sbapt} 177264789Sbapt 178264789Sbapt/* 179264789Sbapt * This is a helper function that performs exactly the same as 180264789Sbapt * `ucl_object_unref` but it doesn't iterate over elements allowing 181264789Sbapt * to use it for individual elements of arrays and multiple values 182264789Sbapt */ 183264789Sbaptstatic void 184264789Sbaptucl_object_dtor_unref_single (ucl_object_t *obj) 185264789Sbapt{ 186264789Sbapt if (obj != NULL) { 187264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 188264789Sbapt unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 189264789Sbapt if (rc == 0) { 190264789Sbapt#else 191264789Sbapt if (--obj->ref == 0) { 192264789Sbapt#endif 193264789Sbapt ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 194264789Sbapt } 195264789Sbapt } 196264789Sbapt} 197264789Sbapt 198264789Sbaptstatic void 199264789Sbaptucl_object_dtor_unref (ucl_object_t *obj) 200264789Sbapt{ 201264789Sbapt if (obj->ref == 0) { 202264789Sbapt ucl_object_dtor_free (obj); 203264789Sbapt } 204264789Sbapt else { 205264789Sbapt /* This may cause dtor unref being called one more time */ 206264789Sbapt ucl_object_dtor_unref_single (obj); 207264789Sbapt } 208264789Sbapt} 209264789Sbapt 210264789Sbaptstatic void 211264789Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 212264789Sbapt{ 213279549Sbapt ucl_object_t *tmp, *sub; 214262395Sbapt 215262395Sbapt while (obj != NULL) { 216262395Sbapt if (obj->type == UCL_ARRAY) { 217279549Sbapt UCL_ARRAY_GET (vec, obj); 218279549Sbapt unsigned int i; 219279549Sbapt 220279549Sbapt if (vec != NULL) { 221279549Sbapt for (i = 0; i < vec->n; i ++) { 222279549Sbapt sub = kv_A (*vec, i); 223279549Sbapt if (sub != NULL) { 224279549Sbapt tmp = sub; 225279549Sbapt while (sub) { 226279549Sbapt tmp = sub->next; 227279549Sbapt dtor (sub); 228279549Sbapt sub = tmp; 229279549Sbapt } 230279549Sbapt } 231279549Sbapt } 232279549Sbapt kv_destroy (*vec); 233279549Sbapt UCL_FREE (sizeof (*vec), vec); 234262395Sbapt } 235290071Sbapt obj->value.av = NULL; 236262395Sbapt } 237262395Sbapt else if (obj->type == UCL_OBJECT) { 238262395Sbapt if (obj->value.ov != NULL) { 239264789Sbapt ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); 240262395Sbapt } 241290071Sbapt obj->value.ov = NULL; 242262395Sbapt } 243262395Sbapt tmp = obj->next; 244264789Sbapt dtor (obj); 245262395Sbapt obj = tmp; 246262395Sbapt 247262395Sbapt if (!allow_rec) { 248262395Sbapt break; 249262395Sbapt } 250262395Sbapt } 251262395Sbapt} 252262395Sbapt 253262395Sbaptvoid 254262395Sbaptucl_object_free (ucl_object_t *obj) 255262395Sbapt{ 256264789Sbapt ucl_object_free_internal (obj, true, ucl_object_dtor_free); 257262395Sbapt} 258262395Sbapt 259262395Sbaptsize_t 260262395Sbaptucl_unescape_json_string (char *str, size_t len) 261262395Sbapt{ 262262395Sbapt char *t = str, *h = str; 263262395Sbapt int i, uval; 264262395Sbapt 265263648Sbapt if (len <= 1) { 266263648Sbapt return len; 267263648Sbapt } 268262395Sbapt /* t is target (tortoise), h is source (hare) */ 269262395Sbapt 270262395Sbapt while (len) { 271262395Sbapt if (*h == '\\') { 272262395Sbapt h ++; 273290071Sbapt 274290071Sbapt if (len == 1) { 275290071Sbapt /* 276290071Sbapt * If \ is last, then do not try to go further 277290071Sbapt * Issue: #74 278290071Sbapt */ 279290071Sbapt len --; 280290071Sbapt *t++ = '\\'; 281290071Sbapt continue; 282290071Sbapt } 283290071Sbapt 284262395Sbapt switch (*h) { 285262395Sbapt case 'n': 286262395Sbapt *t++ = '\n'; 287262395Sbapt break; 288262395Sbapt case 'r': 289262395Sbapt *t++ = '\r'; 290262395Sbapt break; 291262395Sbapt case 'b': 292262395Sbapt *t++ = '\b'; 293262395Sbapt break; 294262395Sbapt case 't': 295262395Sbapt *t++ = '\t'; 296262395Sbapt break; 297262395Sbapt case 'f': 298262395Sbapt *t++ = '\f'; 299262395Sbapt break; 300262395Sbapt case '\\': 301262395Sbapt *t++ = '\\'; 302262395Sbapt break; 303262395Sbapt case '"': 304262395Sbapt *t++ = '"'; 305262395Sbapt break; 306262395Sbapt case 'u': 307262395Sbapt /* Unicode escape */ 308262395Sbapt uval = 0; 309263648Sbapt if (len > 3) { 310263648Sbapt for (i = 0; i < 4; i++) { 311263648Sbapt uval <<= 4; 312263648Sbapt if (isdigit (h[i])) { 313263648Sbapt uval += h[i] - '0'; 314263648Sbapt } 315263648Sbapt else if (h[i] >= 'a' && h[i] <= 'f') { 316263648Sbapt uval += h[i] - 'a' + 10; 317263648Sbapt } 318263648Sbapt else if (h[i] >= 'A' && h[i] <= 'F') { 319263648Sbapt uval += h[i] - 'A' + 10; 320263648Sbapt } 321263648Sbapt else { 322263648Sbapt break; 323263648Sbapt } 324262395Sbapt } 325263648Sbapt h += 3; 326263648Sbapt len -= 3; 327263648Sbapt /* Encode */ 328263648Sbapt if(uval < 0x80) { 329263648Sbapt t[0] = (char)uval; 330263648Sbapt t ++; 331262395Sbapt } 332263648Sbapt else if(uval < 0x800) { 333263648Sbapt t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 334263648Sbapt t[1] = 0x80 + ((uval & 0x03F)); 335263648Sbapt t += 2; 336262395Sbapt } 337263648Sbapt else if(uval < 0x10000) { 338263648Sbapt t[0] = 0xE0 + ((uval & 0xF000) >> 12); 339263648Sbapt t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 340263648Sbapt t[2] = 0x80 + ((uval & 0x003F)); 341263648Sbapt t += 3; 342263648Sbapt } 343263648Sbapt else if(uval <= 0x10FFFF) { 344263648Sbapt t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 345263648Sbapt t[1] = 0x80 + ((uval & 0x03F000) >> 12); 346263648Sbapt t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 347263648Sbapt t[3] = 0x80 + ((uval & 0x00003F)); 348263648Sbapt t += 4; 349263648Sbapt } 350263648Sbapt else { 351263648Sbapt *t++ = '?'; 352263648Sbapt } 353262395Sbapt } 354262395Sbapt else { 355263648Sbapt *t++ = 'u'; 356262395Sbapt } 357262395Sbapt break; 358262395Sbapt default: 359262395Sbapt *t++ = *h; 360262395Sbapt break; 361262395Sbapt } 362262395Sbapt h ++; 363262395Sbapt len --; 364262395Sbapt } 365262395Sbapt else { 366262395Sbapt *t++ = *h++; 367262395Sbapt } 368290071Sbapt 369290071Sbapt if (len > 0) { 370290071Sbapt len --; 371290071Sbapt } 372262395Sbapt } 373262395Sbapt *t = '\0'; 374262395Sbapt 375262395Sbapt return (t - str); 376262395Sbapt} 377262395Sbapt 378264789Sbaptchar * 379264789Sbaptucl_copy_key_trash (const ucl_object_t *obj) 380262395Sbapt{ 381264789Sbapt ucl_object_t *deconst; 382264789Sbapt 383263648Sbapt if (obj == NULL) { 384263648Sbapt return NULL; 385263648Sbapt } 386262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 387264789Sbapt deconst = __DECONST (ucl_object_t *, obj); 388264789Sbapt deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 389264789Sbapt if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 390264789Sbapt memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 391264789Sbapt deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 392262395Sbapt } 393264789Sbapt deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 394264789Sbapt deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 395262395Sbapt } 396262395Sbapt 397262395Sbapt return obj->trash_stack[UCL_TRASH_KEY]; 398262395Sbapt} 399262395Sbapt 400264789Sbaptchar * 401264789Sbaptucl_copy_value_trash (const ucl_object_t *obj) 402262395Sbapt{ 403264789Sbapt ucl_object_t *deconst; 404264789Sbapt 405263648Sbapt if (obj == NULL) { 406263648Sbapt return NULL; 407263648Sbapt } 408262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 409264789Sbapt deconst = __DECONST (ucl_object_t *, obj); 410262395Sbapt if (obj->type == UCL_STRING) { 411264789Sbapt 412262395Sbapt /* Special case for strings */ 413290071Sbapt if (obj->flags & UCL_OBJECT_BINARY) { 414290071Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len); 415290071Sbapt if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 416290071Sbapt memcpy (deconst->trash_stack[UCL_TRASH_VALUE], 417290071Sbapt obj->value.sv, 418290071Sbapt obj->len); 419290071Sbapt deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 420290071Sbapt } 421262395Sbapt } 422290071Sbapt else { 423290071Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 424290071Sbapt if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 425290071Sbapt memcpy (deconst->trash_stack[UCL_TRASH_VALUE], 426290071Sbapt obj->value.sv, 427290071Sbapt obj->len); 428290071Sbapt deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 429290071Sbapt deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 430290071Sbapt } 431290071Sbapt } 432262395Sbapt } 433262395Sbapt else { 434262395Sbapt /* Just emit value in json notation */ 435264789Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 436264789Sbapt deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 437262395Sbapt } 438264789Sbapt deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 439262395Sbapt } 440290071Sbapt 441262395Sbapt return obj->trash_stack[UCL_TRASH_VALUE]; 442262395Sbapt} 443262395Sbapt 444290071Sbaptucl_object_t* 445262395Sbaptucl_parser_get_object (struct ucl_parser *parser) 446262395Sbapt{ 447262395Sbapt if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 448262395Sbapt return ucl_object_ref (parser->top_obj); 449262395Sbapt } 450262395Sbapt 451262395Sbapt return NULL; 452262395Sbapt} 453262395Sbapt 454290071Sbaptvoid 455262395Sbaptucl_parser_free (struct ucl_parser *parser) 456262395Sbapt{ 457262395Sbapt struct ucl_stack *stack, *stmp; 458262395Sbapt struct ucl_macro *macro, *mtmp; 459262395Sbapt struct ucl_chunk *chunk, *ctmp; 460262395Sbapt struct ucl_pubkey *key, *ktmp; 461262395Sbapt struct ucl_variable *var, *vtmp; 462290071Sbapt ucl_object_t *tr, *trtmp; 463262395Sbapt 464263648Sbapt if (parser == NULL) { 465263648Sbapt return; 466263648Sbapt } 467263648Sbapt 468262395Sbapt if (parser->top_obj != NULL) { 469262395Sbapt ucl_object_unref (parser->top_obj); 470262395Sbapt } 471262395Sbapt 472290071Sbapt if (parser->includepaths != NULL) { 473290071Sbapt ucl_object_unref (parser->includepaths); 474290071Sbapt } 475290071Sbapt 476262395Sbapt LL_FOREACH_SAFE (parser->stack, stack, stmp) { 477262395Sbapt free (stack); 478262395Sbapt } 479262395Sbapt HASH_ITER (hh, parser->macroes, macro, mtmp) { 480262395Sbapt free (macro->name); 481262395Sbapt HASH_DEL (parser->macroes, macro); 482262395Sbapt UCL_FREE (sizeof (struct ucl_macro), macro); 483262395Sbapt } 484262395Sbapt LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 485262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 486262395Sbapt } 487262395Sbapt LL_FOREACH_SAFE (parser->keys, key, ktmp) { 488262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), key); 489262395Sbapt } 490262395Sbapt LL_FOREACH_SAFE (parser->variables, var, vtmp) { 491262395Sbapt free (var->value); 492262395Sbapt free (var->var); 493262395Sbapt UCL_FREE (sizeof (struct ucl_variable), var); 494262395Sbapt } 495290071Sbapt LL_FOREACH_SAFE (parser->trash_objs, tr, trtmp) { 496290071Sbapt ucl_object_free_internal (tr, false, ucl_object_dtor_free); 497290071Sbapt } 498262395Sbapt 499262395Sbapt if (parser->err != NULL) { 500275223Sbapt utstring_free (parser->err); 501262395Sbapt } 502262395Sbapt 503275223Sbapt if (parser->cur_file) { 504275223Sbapt free (parser->cur_file); 505275223Sbapt } 506275223Sbapt 507262395Sbapt UCL_FREE (sizeof (struct ucl_parser), parser); 508262395Sbapt} 509262395Sbapt 510290071Sbaptconst char * 511262395Sbaptucl_parser_get_error(struct ucl_parser *parser) 512262395Sbapt{ 513263648Sbapt if (parser == NULL) { 514263648Sbapt return NULL; 515263648Sbapt } 516263648Sbapt 517290071Sbapt if (parser->err == NULL) { 518262395Sbapt return NULL; 519290071Sbapt } 520262395Sbapt 521290071Sbapt return utstring_body (parser->err); 522262395Sbapt} 523262395Sbapt 524290071Sbaptint 525290071Sbaptucl_parser_get_error_code(struct ucl_parser *parser) 526290071Sbapt{ 527290071Sbapt if (parser == NULL) { 528290071Sbapt return 0; 529290071Sbapt } 530290071Sbapt 531290071Sbapt return parser->err_code; 532290071Sbapt} 533290071Sbapt 534290071Sbaptunsigned 535290071Sbaptucl_parser_get_column(struct ucl_parser *parser) 536290071Sbapt{ 537290071Sbapt if (parser == NULL || parser->chunks == NULL) { 538290071Sbapt return 0; 539290071Sbapt } 540290071Sbapt 541290071Sbapt return parser->chunks->column; 542290071Sbapt} 543290071Sbapt 544290071Sbaptunsigned 545290071Sbaptucl_parser_get_linenum(struct ucl_parser *parser) 546290071Sbapt{ 547290071Sbapt if (parser == NULL || parser->chunks == NULL) { 548290071Sbapt return 0; 549290071Sbapt } 550290071Sbapt 551290071Sbapt return parser->chunks->line; 552290071Sbapt} 553290071Sbapt 554290071Sbaptvoid 555279549Sbaptucl_parser_clear_error(struct ucl_parser *parser) 556279549Sbapt{ 557279549Sbapt if (parser != NULL && parser->err != NULL) { 558279549Sbapt utstring_free(parser->err); 559279549Sbapt parser->err = NULL; 560290071Sbapt parser->err_code = 0; 561279549Sbapt } 562279549Sbapt} 563279549Sbapt 564290071Sbaptbool 565262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 566262395Sbapt{ 567262395Sbapt#ifndef HAVE_OPENSSL 568262395Sbapt ucl_create_err (&parser->err, "cannot check signatures without openssl"); 569262395Sbapt return false; 570262395Sbapt#else 571262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 572262395Sbapt ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 573262395Sbapt return EXIT_FAILURE; 574262395Sbapt# else 575262395Sbapt struct ucl_pubkey *nkey; 576262395Sbapt BIO *mem; 577262395Sbapt 578262395Sbapt mem = BIO_new_mem_buf ((void *)key, len); 579262395Sbapt nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 580263648Sbapt if (nkey == NULL) { 581263648Sbapt ucl_create_err (&parser->err, "cannot allocate memory for key"); 582263648Sbapt return false; 583263648Sbapt } 584262395Sbapt nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 585262395Sbapt BIO_free (mem); 586262395Sbapt if (nkey->key == NULL) { 587262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), nkey); 588262395Sbapt ucl_create_err (&parser->err, "%s", 589262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 590262395Sbapt return false; 591262395Sbapt } 592262395Sbapt LL_PREPEND (parser->keys, nkey); 593262395Sbapt# endif 594262395Sbapt#endif 595262395Sbapt return true; 596262395Sbapt} 597262395Sbapt 598262395Sbapt#ifdef CURL_FOUND 599262395Sbaptstruct ucl_curl_cbdata { 600262395Sbapt unsigned char *buf; 601262395Sbapt size_t buflen; 602262395Sbapt}; 603262395Sbapt 604262395Sbaptstatic size_t 605262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 606262395Sbapt{ 607262395Sbapt struct ucl_curl_cbdata *cbdata = ud; 608262395Sbapt size_t realsize = size * nmemb; 609262395Sbapt 610262395Sbapt cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 611262395Sbapt if (cbdata->buf == NULL) { 612262395Sbapt return 0; 613262395Sbapt } 614262395Sbapt 615262395Sbapt memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 616262395Sbapt cbdata->buflen += realsize; 617262395Sbapt cbdata->buf[cbdata->buflen] = 0; 618262395Sbapt 619262395Sbapt return realsize; 620262395Sbapt} 621262395Sbapt#endif 622262395Sbapt 623262395Sbapt/** 624262395Sbapt * Fetch a url and save results to the memory buffer 625262395Sbapt * @param url url to fetch 626262395Sbapt * @param len length of url 627262395Sbapt * @param buf target buffer 628262395Sbapt * @param buflen target length 629262395Sbapt * @return 630262395Sbapt */ 631262395Sbaptstatic bool 632262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 633262395Sbapt UT_string **err, bool must_exist) 634262395Sbapt{ 635262395Sbapt 636262395Sbapt#ifdef HAVE_FETCH_H 637262395Sbapt struct url *fetch_url; 638262395Sbapt struct url_stat us; 639262395Sbapt FILE *in; 640262395Sbapt 641262395Sbapt fetch_url = fetchParseURL (url); 642262395Sbapt if (fetch_url == NULL) { 643262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 644262395Sbapt url, strerror (errno)); 645262395Sbapt return false; 646262395Sbapt } 647262395Sbapt if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 648262395Sbapt if (!must_exist) { 649262395Sbapt ucl_create_err (err, "cannot fetch URL %s: %s", 650262395Sbapt url, strerror (errno)); 651262395Sbapt } 652262395Sbapt fetchFreeURL (fetch_url); 653262395Sbapt return false; 654262395Sbapt } 655262395Sbapt 656262395Sbapt *buflen = us.size; 657262395Sbapt *buf = malloc (*buflen); 658262395Sbapt if (*buf == NULL) { 659262395Sbapt ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 660262395Sbapt url, strerror (errno)); 661262395Sbapt fclose (in); 662262395Sbapt fetchFreeURL (fetch_url); 663262395Sbapt return false; 664262395Sbapt } 665262395Sbapt 666262395Sbapt if (fread (*buf, *buflen, 1, in) != 1) { 667262395Sbapt ucl_create_err (err, "cannot read URL %s: %s", 668262395Sbapt url, strerror (errno)); 669262395Sbapt fclose (in); 670262395Sbapt fetchFreeURL (fetch_url); 671262395Sbapt return false; 672262395Sbapt } 673262395Sbapt 674262395Sbapt fetchFreeURL (fetch_url); 675262395Sbapt return true; 676262395Sbapt#elif defined(CURL_FOUND) 677262395Sbapt CURL *curl; 678262395Sbapt int r; 679262395Sbapt struct ucl_curl_cbdata cbdata; 680262395Sbapt 681262395Sbapt curl = curl_easy_init (); 682262395Sbapt if (curl == NULL) { 683262395Sbapt ucl_create_err (err, "CURL interface is broken"); 684262395Sbapt return false; 685262395Sbapt } 686262395Sbapt if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 687262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 688262395Sbapt url, curl_easy_strerror (r)); 689262395Sbapt curl_easy_cleanup (curl); 690262395Sbapt return false; 691262395Sbapt } 692262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 693262395Sbapt cbdata.buf = *buf; 694262395Sbapt cbdata.buflen = *buflen; 695262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 696262395Sbapt 697262395Sbapt if ((r = curl_easy_perform (curl)) != CURLE_OK) { 698262395Sbapt if (!must_exist) { 699262395Sbapt ucl_create_err (err, "error fetching URL %s: %s", 700262395Sbapt url, curl_easy_strerror (r)); 701262395Sbapt } 702262395Sbapt curl_easy_cleanup (curl); 703262395Sbapt if (cbdata.buf) { 704262395Sbapt free (cbdata.buf); 705262395Sbapt } 706262395Sbapt return false; 707262395Sbapt } 708262395Sbapt *buf = cbdata.buf; 709262395Sbapt *buflen = cbdata.buflen; 710262395Sbapt 711262395Sbapt return true; 712262395Sbapt#else 713262395Sbapt ucl_create_err (err, "URL support is disabled"); 714262395Sbapt return false; 715262395Sbapt#endif 716262395Sbapt} 717262395Sbapt 718262395Sbapt/** 719262395Sbapt * Fetch a file and save results to the memory buffer 720262395Sbapt * @param filename filename to fetch 721262395Sbapt * @param len length of filename 722262395Sbapt * @param buf target buffer 723262395Sbapt * @param buflen target length 724262395Sbapt * @return 725262395Sbapt */ 726262395Sbaptstatic bool 727262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 728262395Sbapt UT_string **err, bool must_exist) 729262395Sbapt{ 730262395Sbapt int fd; 731262395Sbapt struct stat st; 732262395Sbapt 733262395Sbapt if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 734262395Sbapt if (must_exist) { 735262395Sbapt ucl_create_err (err, "cannot stat file %s: %s", 736262395Sbapt filename, strerror (errno)); 737262395Sbapt } 738262395Sbapt return false; 739262395Sbapt } 740262395Sbapt if (st.st_size == 0) { 741262395Sbapt /* Do not map empty files */ 742262395Sbapt *buf = ""; 743262395Sbapt *buflen = 0; 744262395Sbapt } 745262395Sbapt else { 746262395Sbapt if ((fd = open (filename, O_RDONLY)) == -1) { 747262395Sbapt ucl_create_err (err, "cannot open file %s: %s", 748262395Sbapt filename, strerror (errno)); 749262395Sbapt return false; 750262395Sbapt } 751263648Sbapt if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 752262395Sbapt close (fd); 753262395Sbapt ucl_create_err (err, "cannot mmap file %s: %s", 754262395Sbapt filename, strerror (errno)); 755262395Sbapt return false; 756262395Sbapt } 757262395Sbapt *buflen = st.st_size; 758262395Sbapt close (fd); 759262395Sbapt } 760262395Sbapt 761262395Sbapt return true; 762262395Sbapt} 763262395Sbapt 764262395Sbapt 765262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 766262395Sbaptstatic inline bool 767262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen, 768262395Sbapt const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 769262395Sbapt{ 770262395Sbapt struct ucl_pubkey *key; 771262395Sbapt char dig[EVP_MAX_MD_SIZE]; 772262395Sbapt unsigned int diglen; 773262395Sbapt EVP_PKEY_CTX *key_ctx; 774262395Sbapt EVP_MD_CTX *sign_ctx = NULL; 775262395Sbapt 776262395Sbapt sign_ctx = EVP_MD_CTX_create (); 777262395Sbapt 778262395Sbapt LL_FOREACH (parser->keys, key) { 779262395Sbapt key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 780262395Sbapt if (key_ctx != NULL) { 781262395Sbapt if (EVP_PKEY_verify_init (key_ctx) <= 0) { 782262395Sbapt EVP_PKEY_CTX_free (key_ctx); 783262395Sbapt continue; 784262395Sbapt } 785262395Sbapt if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 786262395Sbapt EVP_PKEY_CTX_free (key_ctx); 787262395Sbapt continue; 788262395Sbapt } 789262395Sbapt if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 790262395Sbapt EVP_PKEY_CTX_free (key_ctx); 791262395Sbapt continue; 792262395Sbapt } 793262395Sbapt EVP_DigestInit (sign_ctx, EVP_sha256 ()); 794262395Sbapt EVP_DigestUpdate (sign_ctx, data, datalen); 795262395Sbapt EVP_DigestFinal (sign_ctx, dig, &diglen); 796262395Sbapt 797262395Sbapt if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 798262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 799262395Sbapt EVP_PKEY_CTX_free (key_ctx); 800262395Sbapt return true; 801262395Sbapt } 802262395Sbapt 803262395Sbapt EVP_PKEY_CTX_free (key_ctx); 804262395Sbapt } 805262395Sbapt } 806262395Sbapt 807262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 808262395Sbapt 809262395Sbapt return false; 810262395Sbapt} 811262395Sbapt#endif 812262395Sbapt 813290071Sbaptstruct ucl_include_params { 814290071Sbapt bool check_signature; 815290071Sbapt bool must_exist; 816290071Sbapt bool use_glob; 817290071Sbapt bool use_prefix; 818290071Sbapt bool soft_fail; 819290071Sbapt bool allow_glob; 820290071Sbapt unsigned priority; 821290071Sbapt enum ucl_duplicate_strategy strat; 822290071Sbapt enum ucl_parse_type parse_type; 823290071Sbapt const char *prefix; 824290071Sbapt const char *target; 825290071Sbapt}; 826290071Sbapt 827262395Sbapt/** 828262395Sbapt * Include an url to configuration 829262395Sbapt * @param data 830262395Sbapt * @param len 831262395Sbapt * @param parser 832262395Sbapt * @param err 833262395Sbapt * @return 834262395Sbapt */ 835262395Sbaptstatic bool 836262395Sbaptucl_include_url (const unsigned char *data, size_t len, 837290071Sbapt struct ucl_parser *parser, 838290071Sbapt struct ucl_include_params *params) 839262395Sbapt{ 840262395Sbapt 841262395Sbapt bool res; 842262395Sbapt unsigned char *buf = NULL; 843262395Sbapt size_t buflen = 0; 844262395Sbapt struct ucl_chunk *chunk; 845262395Sbapt char urlbuf[PATH_MAX]; 846262395Sbapt int prev_state; 847262395Sbapt 848262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 849262395Sbapt 850290071Sbapt if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) { 851290071Sbapt return (!params->must_exist || false); 852262395Sbapt } 853262395Sbapt 854290071Sbapt if (params->check_signature) { 855262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 856262395Sbapt unsigned char *sigbuf = NULL; 857262395Sbapt size_t siglen = 0; 858262395Sbapt /* We need to check signature first */ 859262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 860262395Sbapt if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 861262395Sbapt return false; 862262395Sbapt } 863262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 864262395Sbapt ucl_create_err (&parser->err, "cannot verify url %s: %s", 865262395Sbapt urlbuf, 866262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 867262395Sbapt if (siglen > 0) { 868263648Sbapt ucl_munmap (sigbuf, siglen); 869262395Sbapt } 870262395Sbapt return false; 871262395Sbapt } 872262395Sbapt if (siglen > 0) { 873263648Sbapt ucl_munmap (sigbuf, siglen); 874262395Sbapt } 875262395Sbapt#endif 876262395Sbapt } 877262395Sbapt 878262395Sbapt prev_state = parser->state; 879262395Sbapt parser->state = UCL_STATE_INIT; 880262395Sbapt 881290071Sbapt res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, 882290071Sbapt params->strat, params->parse_type); 883262395Sbapt if (res == true) { 884262395Sbapt /* Remove chunk from the stack */ 885262395Sbapt chunk = parser->chunks; 886262395Sbapt if (chunk != NULL) { 887262395Sbapt parser->chunks = chunk->next; 888262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 889262395Sbapt } 890262395Sbapt } 891262395Sbapt 892262395Sbapt parser->state = prev_state; 893262395Sbapt free (buf); 894262395Sbapt 895262395Sbapt return res; 896262395Sbapt} 897262395Sbapt 898262395Sbapt/** 899275223Sbapt * Include a single file to the parser 900262395Sbapt * @param data 901262395Sbapt * @param len 902262395Sbapt * @param parser 903275223Sbapt * @param check_signature 904275223Sbapt * @param must_exist 905275223Sbapt * @param allow_glob 906275223Sbapt * @param priority 907262395Sbapt * @return 908262395Sbapt */ 909262395Sbaptstatic bool 910275223Sbaptucl_include_file_single (const unsigned char *data, size_t len, 911290071Sbapt struct ucl_parser *parser, struct ucl_include_params *params) 912262395Sbapt{ 913262395Sbapt bool res; 914262395Sbapt struct ucl_chunk *chunk; 915262395Sbapt unsigned char *buf = NULL; 916290071Sbapt char *old_curfile, *ext; 917290071Sbapt size_t buflen = 0; 918262395Sbapt char filebuf[PATH_MAX], realbuf[PATH_MAX]; 919262395Sbapt int prev_state; 920275223Sbapt struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL, 921275223Sbapt *old_filename = NULL; 922290071Sbapt ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL; 923290071Sbapt ucl_hash_t *container = NULL; 924290071Sbapt struct ucl_stack *st = NULL; 925262395Sbapt 926262395Sbapt snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 927263648Sbapt if (ucl_realpath (filebuf, realbuf) == NULL) { 928290071Sbapt if (params->soft_fail) { 929290071Sbapt return false; 930290071Sbapt } 931290071Sbapt if (!params->must_exist) { 932262395Sbapt return true; 933262395Sbapt } 934262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 935262395Sbapt filebuf, 936262395Sbapt strerror (errno)); 937262395Sbapt return false; 938262395Sbapt } 939262395Sbapt 940275223Sbapt if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) { 941275223Sbapt /* We are likely including the file itself */ 942290071Sbapt if (params->soft_fail) { 943290071Sbapt return false; 944290071Sbapt } 945290071Sbapt 946275223Sbapt ucl_create_err (&parser->err, "trying to include the file %s from itself", 947275223Sbapt realbuf); 948275223Sbapt return false; 949275223Sbapt } 950275223Sbapt 951290071Sbapt if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, params->must_exist)) { 952290071Sbapt if (params->soft_fail) { 953290071Sbapt return false; 954290071Sbapt } 955290071Sbapt return (!params->must_exist || false); 956262395Sbapt } 957262395Sbapt 958290071Sbapt if (params->check_signature) { 959262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 960262395Sbapt unsigned char *sigbuf = NULL; 961262395Sbapt size_t siglen = 0; 962262395Sbapt /* We need to check signature first */ 963262395Sbapt snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 964262395Sbapt if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 965262395Sbapt return false; 966262395Sbapt } 967262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 968262395Sbapt ucl_create_err (&parser->err, "cannot verify file %s: %s", 969262395Sbapt filebuf, 970262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 971262395Sbapt if (siglen > 0) { 972263648Sbapt ucl_munmap (sigbuf, siglen); 973262395Sbapt } 974262395Sbapt return false; 975262395Sbapt } 976262395Sbapt if (siglen > 0) { 977263648Sbapt ucl_munmap (sigbuf, siglen); 978262395Sbapt } 979262395Sbapt#endif 980262395Sbapt } 981262395Sbapt 982275223Sbapt old_curfile = parser->cur_file; 983275223Sbapt parser->cur_file = strdup (realbuf); 984275223Sbapt 985275223Sbapt /* Store old file vars */ 986275223Sbapt DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 987275223Sbapt if (strcmp (cur_var->var, "CURDIR") == 0) { 988275223Sbapt old_curdir = cur_var; 989275223Sbapt DL_DELETE (parser->variables, cur_var); 990275223Sbapt } 991275223Sbapt else if (strcmp (cur_var->var, "FILENAME") == 0) { 992275223Sbapt old_filename = cur_var; 993275223Sbapt DL_DELETE (parser->variables, cur_var); 994275223Sbapt } 995275223Sbapt } 996275223Sbapt 997262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 998262395Sbapt 999262395Sbapt prev_state = parser->state; 1000262395Sbapt parser->state = UCL_STATE_INIT; 1001262395Sbapt 1002290071Sbapt if (params->use_prefix && params->prefix == NULL) { 1003290071Sbapt /* Auto generate a key name based on the included filename */ 1004290071Sbapt params->prefix = basename (realbuf); 1005290071Sbapt ext = strrchr (params->prefix, '.'); 1006290071Sbapt if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) { 1007290071Sbapt /* Strip off .conf or .ucl */ 1008290071Sbapt *ext = '\0'; 1009290071Sbapt } 1010290071Sbapt } 1011290071Sbapt if (params->prefix != NULL) { 1012290071Sbapt /* This is a prefixed include */ 1013290071Sbapt container = parser->stack->obj->value.ov; 1014290071Sbapt 1015290071Sbapt old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, 1016290071Sbapt params->prefix, strlen (params->prefix))); 1017290071Sbapt 1018290071Sbapt if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) { 1019290071Sbapt /* Create an array with key: prefix */ 1020290071Sbapt old_obj = ucl_object_new_full (UCL_ARRAY, params->priority); 1021290071Sbapt old_obj->key = params->prefix; 1022290071Sbapt old_obj->keylen = strlen (params->prefix); 1023290071Sbapt ucl_copy_key_trash(old_obj); 1024290071Sbapt old_obj->prev = old_obj; 1025290071Sbapt old_obj->next = NULL; 1026290071Sbapt 1027290071Sbapt container = ucl_hash_insert_object (container, old_obj, 1028290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1029290071Sbapt parser->stack->obj->len ++; 1030290071Sbapt 1031290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1032290071Sbapt nest_obj->prev = nest_obj; 1033290071Sbapt nest_obj->next = NULL; 1034290071Sbapt 1035290071Sbapt ucl_array_append (old_obj, nest_obj); 1036290071Sbapt } 1037290071Sbapt else if (old_obj == NULL) { 1038290071Sbapt /* Create an object with key: prefix */ 1039290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1040290071Sbapt nest_obj->key = params->prefix; 1041290071Sbapt nest_obj->keylen = strlen (params->prefix); 1042290071Sbapt ucl_copy_key_trash(nest_obj); 1043290071Sbapt nest_obj->prev = nest_obj; 1044290071Sbapt nest_obj->next = NULL; 1045290071Sbapt 1046290071Sbapt container = ucl_hash_insert_object (container, nest_obj, 1047290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1048290071Sbapt parser->stack->obj->len ++; 1049290071Sbapt } 1050290071Sbapt else if (strcasecmp (params->target, "array") == 0 || 1051290071Sbapt ucl_object_type(old_obj) == UCL_ARRAY) { 1052290071Sbapt if (ucl_object_type(old_obj) == UCL_ARRAY) { 1053290071Sbapt /* Append to the existing array */ 1054290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1055290071Sbapt nest_obj->prev = nest_obj; 1056290071Sbapt nest_obj->next = NULL; 1057290071Sbapt 1058290071Sbapt ucl_array_append (old_obj, nest_obj); 1059290071Sbapt } 1060290071Sbapt else { 1061290071Sbapt /* Convert the object to an array */ 1062290071Sbapt new_obj = ucl_object_typed_new (UCL_ARRAY); 1063290071Sbapt new_obj->key = old_obj->key; 1064290071Sbapt new_obj->keylen = old_obj->keylen; 1065290071Sbapt new_obj->flags |= UCL_OBJECT_MULTIVALUE; 1066290071Sbapt new_obj->prev = new_obj; 1067290071Sbapt new_obj->next = NULL; 1068290071Sbapt 1069290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1070290071Sbapt nest_obj->prev = nest_obj; 1071290071Sbapt nest_obj->next = NULL; 1072290071Sbapt 1073290071Sbapt ucl_array_append (new_obj, old_obj); 1074290071Sbapt ucl_array_append (new_obj, nest_obj); 1075290071Sbapt ucl_hash_replace (container, old_obj, new_obj); 1076290071Sbapt } 1077290071Sbapt } 1078290071Sbapt else { 1079290071Sbapt if (ucl_object_type (old_obj) == UCL_OBJECT) { 1080290071Sbapt /* Append to existing Object*/ 1081290071Sbapt nest_obj = old_obj; 1082290071Sbapt } 1083290071Sbapt else { 1084290071Sbapt /* The key is not an object */ 1085290071Sbapt ucl_create_err (&parser->err, 1086290071Sbapt "Conflicting type for key: %s", 1087290071Sbapt params->prefix); 1088290071Sbapt return false; 1089290071Sbapt } 1090290071Sbapt } 1091290071Sbapt 1092290071Sbapt /* Put all of the content of the include inside that object */ 1093290071Sbapt parser->stack->obj->value.ov = container; 1094290071Sbapt 1095290071Sbapt if (nest_obj != NULL) { 1096290071Sbapt st = UCL_ALLOC (sizeof (struct ucl_stack)); 1097290071Sbapt if (st == NULL) { 1098290071Sbapt ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1099290071Sbapt ucl_object_unref (nest_obj); 1100290071Sbapt return NULL; 1101290071Sbapt } 1102290071Sbapt st->obj = nest_obj; 1103290071Sbapt st->level = parser->stack->level; 1104290071Sbapt LL_PREPEND (parser->stack, st); 1105290071Sbapt parser->cur_obj = nest_obj; 1106290071Sbapt } 1107290071Sbapt } 1108290071Sbapt 1109290071Sbapt res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, 1110290071Sbapt params->strat, params->parse_type); 1111290071Sbapt if (!res && !params->must_exist) { 1112275223Sbapt /* Free error */ 1113275223Sbapt utstring_free (parser->err); 1114275223Sbapt parser->err = NULL; 1115275223Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1116275223Sbapt } 1117275223Sbapt 1118290071Sbapt /* Stop nesting the include, take 1 level off the stack */ 1119290071Sbapt if (params->prefix != NULL && nest_obj != NULL) { 1120290071Sbapt parser->stack = st->next; 1121290071Sbapt UCL_FREE (sizeof (struct ucl_stack), st); 1122290071Sbapt } 1123290071Sbapt 1124275223Sbapt /* Remove chunk from the stack */ 1125275223Sbapt chunk = parser->chunks; 1126275223Sbapt if (chunk != NULL) { 1127275223Sbapt parser->chunks = chunk->next; 1128275223Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 1129275223Sbapt parser->recursion --; 1130275223Sbapt } 1131275223Sbapt 1132275223Sbapt /* Restore old file vars */ 1133290071Sbapt if (parser->cur_file) { 1134290071Sbapt free (parser->cur_file); 1135290071Sbapt } 1136290071Sbapt 1137275223Sbapt parser->cur_file = old_curfile; 1138275223Sbapt DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 1139275223Sbapt if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) { 1140275223Sbapt DL_DELETE (parser->variables, cur_var); 1141275223Sbapt free (cur_var->var); 1142275223Sbapt free (cur_var->value); 1143275223Sbapt UCL_FREE (sizeof (struct ucl_variable), cur_var); 1144262395Sbapt } 1145275223Sbapt else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) { 1146275223Sbapt DL_DELETE (parser->variables, cur_var); 1147275223Sbapt free (cur_var->var); 1148275223Sbapt free (cur_var->value); 1149275223Sbapt UCL_FREE (sizeof (struct ucl_variable), cur_var); 1150275223Sbapt } 1151262395Sbapt } 1152275223Sbapt if (old_filename) { 1153275223Sbapt DL_APPEND (parser->variables, old_filename); 1154275223Sbapt } 1155275223Sbapt if (old_curdir) { 1156275223Sbapt DL_APPEND (parser->variables, old_curdir); 1157275223Sbapt } 1158262395Sbapt 1159262395Sbapt parser->state = prev_state; 1160262395Sbapt 1161262395Sbapt if (buflen > 0) { 1162263648Sbapt ucl_munmap (buf, buflen); 1163262395Sbapt } 1164262395Sbapt 1165262395Sbapt return res; 1166262395Sbapt} 1167262395Sbapt 1168262395Sbapt/** 1169275223Sbapt * Include a file to configuration 1170275223Sbapt * @param data 1171275223Sbapt * @param len 1172275223Sbapt * @param parser 1173275223Sbapt * @param err 1174275223Sbapt * @return 1175275223Sbapt */ 1176275223Sbaptstatic bool 1177275223Sbaptucl_include_file (const unsigned char *data, size_t len, 1178290071Sbapt struct ucl_parser *parser, struct ucl_include_params *params) 1179275223Sbapt{ 1180275223Sbapt const unsigned char *p = data, *end = data + len; 1181275223Sbapt bool need_glob = false; 1182275223Sbapt int cnt = 0; 1183275223Sbapt char glob_pattern[PATH_MAX]; 1184275223Sbapt size_t i; 1185275223Sbapt 1186279549Sbapt#ifndef _WIN32 1187290071Sbapt if (!params->allow_glob) { 1188290071Sbapt return ucl_include_file_single (data, len, parser, params); 1189275223Sbapt } 1190275223Sbapt else { 1191275223Sbapt /* Check for special symbols in a filename */ 1192275223Sbapt while (p != end) { 1193275223Sbapt if (*p == '*' || *p == '?') { 1194275223Sbapt need_glob = true; 1195275223Sbapt break; 1196275223Sbapt } 1197275223Sbapt p ++; 1198275223Sbapt } 1199275223Sbapt if (need_glob) { 1200279549Sbapt glob_t globbuf; 1201275223Sbapt memset (&globbuf, 0, sizeof (globbuf)); 1202290071Sbapt ucl_strlcpy (glob_pattern, (const char *)data, 1203290071Sbapt (len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern))); 1204275223Sbapt if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { 1205290071Sbapt return (!params->must_exist || false); 1206275223Sbapt } 1207275223Sbapt for (i = 0; i < globbuf.gl_pathc; i ++) { 1208275223Sbapt if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i], 1209290071Sbapt strlen (globbuf.gl_pathv[i]), parser, params)) { 1210290071Sbapt if (params->soft_fail) { 1211290071Sbapt continue; 1212290071Sbapt } 1213275223Sbapt globfree (&globbuf); 1214275223Sbapt return false; 1215275223Sbapt } 1216275223Sbapt cnt ++; 1217275223Sbapt } 1218275223Sbapt globfree (&globbuf); 1219275223Sbapt 1220290071Sbapt if (cnt == 0 && params->must_exist) { 1221275223Sbapt ucl_create_err (&parser->err, "cannot match any files for pattern %s", 1222275223Sbapt glob_pattern); 1223275223Sbapt return false; 1224275223Sbapt } 1225275223Sbapt } 1226275223Sbapt else { 1227290071Sbapt return ucl_include_file_single (data, len, parser, params); 1228275223Sbapt } 1229275223Sbapt } 1230279549Sbapt#else 1231279549Sbapt /* Win32 compilers do not support globbing. Therefore, for Win32, 1232279549Sbapt treat allow_glob/need_glob as a NOOP and just return */ 1233290071Sbapt return ucl_include_file_single (data, len, parser, params); 1234279549Sbapt#endif 1235279549Sbapt 1236275223Sbapt return true; 1237275223Sbapt} 1238275223Sbapt 1239275223Sbapt/** 1240275223Sbapt * Common function to handle .*include* macros 1241275223Sbapt * @param data 1242275223Sbapt * @param len 1243275223Sbapt * @param args 1244275223Sbapt * @param parser 1245275223Sbapt * @param default_try 1246275223Sbapt * @param default_sign 1247275223Sbapt * @return 1248275223Sbapt */ 1249275223Sbaptstatic bool 1250275223Sbaptucl_include_common (const unsigned char *data, size_t len, 1251275223Sbapt const ucl_object_t *args, struct ucl_parser *parser, 1252275223Sbapt bool default_try, 1253275223Sbapt bool default_sign) 1254275223Sbapt{ 1255290071Sbapt bool allow_url, search; 1256290071Sbapt const char *duplicate; 1257275223Sbapt const ucl_object_t *param; 1258290071Sbapt ucl_object_iter_t it = NULL, ip = NULL; 1259290071Sbapt char ipath[PATH_MAX]; 1260290071Sbapt struct ucl_include_params params; 1261275223Sbapt 1262275223Sbapt /* Default values */ 1263290071Sbapt params.soft_fail = default_try; 1264290071Sbapt params.allow_glob = false; 1265290071Sbapt params.check_signature = default_sign; 1266290071Sbapt params.use_prefix = false; 1267290071Sbapt params.target = "object"; 1268290071Sbapt params.prefix = NULL; 1269290071Sbapt params.priority = 0; 1270290071Sbapt params.parse_type = UCL_PARSE_UCL; 1271290071Sbapt params.strat = UCL_DUPLICATE_APPEND; 1272290071Sbapt params.must_exist = !default_try; 1273275223Sbapt 1274290071Sbapt search = false; 1275290071Sbapt 1276275223Sbapt /* Process arguments */ 1277275223Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1278275223Sbapt while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1279275223Sbapt if (param->type == UCL_BOOLEAN) { 1280290071Sbapt if (strncmp (param->key, "try", param->keylen) == 0) { 1281290071Sbapt params.must_exist = !ucl_object_toboolean (param); 1282275223Sbapt } 1283290071Sbapt else if (strncmp (param->key, "sign", param->keylen) == 0) { 1284290071Sbapt params.check_signature = ucl_object_toboolean (param); 1285275223Sbapt } 1286290071Sbapt else if (strncmp (param->key, "glob", param->keylen) == 0) { 1287290071Sbapt params.allow_glob = ucl_object_toboolean (param); 1288275223Sbapt } 1289290071Sbapt else if (strncmp (param->key, "url", param->keylen) == 0) { 1290290071Sbapt allow_url = ucl_object_toboolean (param); 1291275223Sbapt } 1292290071Sbapt else if (strncmp (param->key, "prefix", param->keylen) == 0) { 1293290071Sbapt params.use_prefix = ucl_object_toboolean (param); 1294290071Sbapt } 1295275223Sbapt } 1296290071Sbapt else if (param->type == UCL_STRING) { 1297290071Sbapt if (strncmp (param->key, "key", param->keylen) == 0) { 1298290071Sbapt params.prefix = ucl_object_tostring (param); 1299290071Sbapt } 1300290071Sbapt else if (strncmp (param->key, "target", param->keylen) == 0) { 1301290071Sbapt params.target = ucl_object_tostring (param); 1302290071Sbapt } 1303290071Sbapt else if (strncmp (param->key, "duplicate", param->keylen) == 0) { 1304290071Sbapt duplicate = ucl_object_tostring (param); 1305290071Sbapt 1306290071Sbapt if (strcmp (duplicate, "append") == 0) { 1307290071Sbapt params.strat = UCL_DUPLICATE_APPEND; 1308290071Sbapt } 1309290071Sbapt else if (strcmp (duplicate, "merge") == 0) { 1310290071Sbapt params.strat = UCL_DUPLICATE_MERGE; 1311290071Sbapt } 1312290071Sbapt else if (strcmp (duplicate, "rewrite") == 0) { 1313290071Sbapt params.strat = UCL_DUPLICATE_REWRITE; 1314290071Sbapt } 1315290071Sbapt else if (strcmp (duplicate, "error") == 0) { 1316290071Sbapt params.strat = UCL_DUPLICATE_ERROR; 1317290071Sbapt } 1318290071Sbapt } 1319290071Sbapt } 1320290071Sbapt else if (param->type == UCL_ARRAY) { 1321290071Sbapt if (strncmp (param->key, "path", param->keylen) == 0) { 1322290071Sbapt ucl_set_include_path (parser, __DECONST(ucl_object_t *, param)); 1323290071Sbapt } 1324290071Sbapt } 1325275223Sbapt else if (param->type == UCL_INT) { 1326290071Sbapt if (strncmp (param->key, "priority", param->keylen) == 0) { 1327290071Sbapt params.priority = ucl_object_toint (param); 1328275223Sbapt } 1329275223Sbapt } 1330275223Sbapt } 1331275223Sbapt } 1332275223Sbapt 1333290071Sbapt if (parser->includepaths == NULL) { 1334290071Sbapt if (allow_url && ucl_strnstr (data, "://", len) != NULL) { 1335290071Sbapt /* Globbing is not used for URL's */ 1336290071Sbapt return ucl_include_url (data, len, parser, ¶ms); 1337290071Sbapt } 1338290071Sbapt else if (data != NULL) { 1339290071Sbapt /* Try to load a file */ 1340290071Sbapt return ucl_include_file (data, len, parser, ¶ms); 1341290071Sbapt } 1342275223Sbapt } 1343290071Sbapt else { 1344290071Sbapt if (allow_url && ucl_strnstr (data, "://", len) != NULL) { 1345290071Sbapt /* Globbing is not used for URL's */ 1346290071Sbapt return ucl_include_url (data, len, parser, ¶ms); 1347290071Sbapt } 1348290071Sbapt 1349290071Sbapt ip = ucl_object_iterate_new (parser->includepaths); 1350290071Sbapt while ((param = ucl_object_iterate_safe (ip, true)) != NULL) { 1351290071Sbapt if (ucl_object_type(param) == UCL_STRING) { 1352290071Sbapt snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param), 1353290071Sbapt (int)len, data); 1354290071Sbapt if ((search = ucl_include_file (ipath, strlen (ipath), 1355290071Sbapt parser, ¶ms))) { 1356290071Sbapt if (!params.allow_glob) { 1357290071Sbapt break; 1358290071Sbapt } 1359290071Sbapt } 1360290071Sbapt } 1361290071Sbapt } 1362290071Sbapt ucl_object_iterate_free (ip); 1363290071Sbapt if (search == true) { 1364290071Sbapt return true; 1365290071Sbapt } 1366290071Sbapt else { 1367290071Sbapt ucl_create_err (&parser->err, 1368290071Sbapt "cannot find file: %.*s in search path", 1369290071Sbapt (int)len, data); 1370290071Sbapt return false; 1371290071Sbapt } 1372275223Sbapt } 1373275223Sbapt 1374275223Sbapt return false; 1375275223Sbapt} 1376275223Sbapt 1377275223Sbapt/** 1378262395Sbapt * Handle include macro 1379262395Sbapt * @param data include data 1380262395Sbapt * @param len length of data 1381290071Sbapt * @param args UCL object representing arguments to the macro 1382262395Sbapt * @param ud user data 1383262395Sbapt * @return 1384262395Sbapt */ 1385290071Sbaptbool 1386275223Sbaptucl_include_handler (const unsigned char *data, size_t len, 1387275223Sbapt const ucl_object_t *args, void* ud) 1388262395Sbapt{ 1389262395Sbapt struct ucl_parser *parser = ud; 1390262395Sbapt 1391275223Sbapt return ucl_include_common (data, len, args, parser, false, false); 1392262395Sbapt} 1393262395Sbapt 1394262395Sbapt/** 1395262395Sbapt * Handle includes macro 1396262395Sbapt * @param data include data 1397262395Sbapt * @param len length of data 1398290071Sbapt * @param args UCL object representing arguments to the macro 1399262395Sbapt * @param ud user data 1400262395Sbapt * @return 1401262395Sbapt */ 1402290071Sbaptbool 1403275223Sbaptucl_includes_handler (const unsigned char *data, size_t len, 1404275223Sbapt const ucl_object_t *args, void* ud) 1405262395Sbapt{ 1406262395Sbapt struct ucl_parser *parser = ud; 1407262395Sbapt 1408275223Sbapt return ucl_include_common (data, len, args, parser, false, true); 1409262395Sbapt} 1410262395Sbapt 1411290071Sbapt/** 1412290071Sbapt * Handle tryinclude macro 1413290071Sbapt * @param data include data 1414290071Sbapt * @param len length of data 1415290071Sbapt * @param args UCL object representing arguments to the macro 1416290071Sbapt * @param ud user data 1417290071Sbapt * @return 1418290071Sbapt */ 1419290071Sbaptbool 1420275223Sbaptucl_try_include_handler (const unsigned char *data, size_t len, 1421275223Sbapt const ucl_object_t *args, void* ud) 1422262395Sbapt{ 1423262395Sbapt struct ucl_parser *parser = ud; 1424262395Sbapt 1425275223Sbapt return ucl_include_common (data, len, args, parser, true, false); 1426262395Sbapt} 1427262395Sbapt 1428290071Sbapt/** 1429290071Sbapt * Handle priority macro 1430290071Sbapt * @param data include data 1431290071Sbapt * @param len length of data 1432290071Sbapt * @param args UCL object representing arguments to the macro 1433290071Sbapt * @param ud user data 1434290071Sbapt * @return 1435290071Sbapt */ 1436290071Sbaptbool 1437290071Sbaptucl_priority_handler (const unsigned char *data, size_t len, 1438290071Sbapt const ucl_object_t *args, void* ud) 1439290071Sbapt{ 1440290071Sbapt struct ucl_parser *parser = ud; 1441290071Sbapt unsigned priority = 255; 1442290071Sbapt const ucl_object_t *param; 1443290071Sbapt bool found = false; 1444290071Sbapt char *value = NULL, *leftover = NULL; 1445290071Sbapt ucl_object_iter_t it = NULL; 1446290071Sbapt 1447290071Sbapt if (parser == NULL) { 1448290071Sbapt return false; 1449290071Sbapt } 1450290071Sbapt 1451290071Sbapt /* Process arguments */ 1452290071Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1453290071Sbapt while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1454290071Sbapt if (param->type == UCL_INT) { 1455290071Sbapt if (strncmp (param->key, "priority", param->keylen) == 0) { 1456290071Sbapt priority = ucl_object_toint (param); 1457290071Sbapt found = true; 1458290071Sbapt } 1459290071Sbapt } 1460290071Sbapt } 1461290071Sbapt } 1462290071Sbapt 1463290071Sbapt if (len > 0) { 1464290071Sbapt value = malloc(len + 1); 1465290071Sbapt ucl_strlcpy(value, (const char *)data, len + 1); 1466290071Sbapt priority = strtol(value, &leftover, 10); 1467290071Sbapt if (*leftover != '\0') { 1468290071Sbapt ucl_create_err (&parser->err, "Invalid priority value in macro: %s", 1469290071Sbapt value); 1470290071Sbapt free(value); 1471290071Sbapt return false; 1472290071Sbapt } 1473290071Sbapt free(value); 1474290071Sbapt found = true; 1475290071Sbapt } 1476290071Sbapt 1477290071Sbapt if (found == true) { 1478290071Sbapt parser->chunks->priority = priority; 1479290071Sbapt return true; 1480290071Sbapt } 1481290071Sbapt 1482290071Sbapt ucl_create_err (&parser->err, "Unable to parse priority macro"); 1483290071Sbapt return false; 1484290071Sbapt} 1485290071Sbapt 1486290071Sbapt/** 1487290071Sbapt * Handle load macro 1488290071Sbapt * @param data include data 1489290071Sbapt * @param len length of data 1490290071Sbapt * @param args UCL object representing arguments to the macro 1491290071Sbapt * @param ud user data 1492290071Sbapt * @return 1493290071Sbapt */ 1494290071Sbaptbool 1495290071Sbaptucl_load_handler (const unsigned char *data, size_t len, 1496290071Sbapt const ucl_object_t *args, void* ud) 1497290071Sbapt{ 1498290071Sbapt struct ucl_parser *parser = ud; 1499290071Sbapt const ucl_object_t *param; 1500290071Sbapt ucl_object_t *obj, *old_obj; 1501290071Sbapt ucl_object_iter_t it = NULL; 1502290071Sbapt bool try_load, multiline, test; 1503290071Sbapt const char *target, *prefix; 1504290071Sbapt char *load_file, *tmp; 1505290071Sbapt unsigned char *buf; 1506290071Sbapt size_t buflen; 1507290071Sbapt unsigned priority; 1508290071Sbapt int64_t iv; 1509290071Sbapt ucl_hash_t *container = NULL; 1510290071Sbapt enum ucl_string_flags flags; 1511290071Sbapt 1512290071Sbapt /* Default values */ 1513290071Sbapt try_load = false; 1514290071Sbapt multiline = false; 1515290071Sbapt test = false; 1516290071Sbapt target = "string"; 1517290071Sbapt prefix = NULL; 1518290071Sbapt load_file = NULL; 1519290071Sbapt buf = NULL; 1520290071Sbapt buflen = 0; 1521290071Sbapt priority = 0; 1522290071Sbapt obj = NULL; 1523290071Sbapt old_obj = NULL; 1524290071Sbapt flags = 0; 1525290071Sbapt 1526290071Sbapt if (parser == NULL) { 1527290071Sbapt return false; 1528290071Sbapt } 1529290071Sbapt 1530290071Sbapt /* Process arguments */ 1531290071Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1532290071Sbapt while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1533290071Sbapt if (param->type == UCL_BOOLEAN) { 1534290071Sbapt if (strncmp (param->key, "try", param->keylen) == 0) { 1535290071Sbapt try_load = ucl_object_toboolean (param); 1536290071Sbapt } 1537290071Sbapt else if (strncmp (param->key, "multiline", param->keylen) == 0) { 1538290071Sbapt multiline = ucl_object_toboolean (param); 1539290071Sbapt } 1540290071Sbapt else if (strncmp (param->key, "escape", param->keylen) == 0) { 1541290071Sbapt test = ucl_object_toboolean (param); 1542290071Sbapt if (test) { 1543290071Sbapt flags |= UCL_STRING_ESCAPE; 1544290071Sbapt } 1545290071Sbapt } 1546290071Sbapt else if (strncmp (param->key, "trim", param->keylen) == 0) { 1547290071Sbapt test = ucl_object_toboolean (param); 1548290071Sbapt if (test) { 1549290071Sbapt flags |= UCL_STRING_TRIM; 1550290071Sbapt } 1551290071Sbapt } 1552290071Sbapt } 1553290071Sbapt else if (param->type == UCL_STRING) { 1554290071Sbapt if (strncmp (param->key, "key", param->keylen) == 0) { 1555290071Sbapt prefix = ucl_object_tostring (param); 1556290071Sbapt } 1557290071Sbapt else if (strncmp (param->key, "target", param->keylen) == 0) { 1558290071Sbapt target = ucl_object_tostring (param); 1559290071Sbapt } 1560290071Sbapt } 1561290071Sbapt else if (param->type == UCL_INT) { 1562290071Sbapt if (strncmp (param->key, "priority", param->keylen) == 0) { 1563290071Sbapt priority = ucl_object_toint (param); 1564290071Sbapt } 1565290071Sbapt } 1566290071Sbapt } 1567290071Sbapt } 1568290071Sbapt 1569290071Sbapt if (prefix == NULL || strlen(prefix) == 0) { 1570290071Sbapt ucl_create_err (&parser->err, "No Key specified in load macro"); 1571290071Sbapt return false; 1572290071Sbapt } 1573290071Sbapt 1574290071Sbapt if (len > 0) { 1575290071Sbapt asprintf (&load_file, "%.*s", (int)len, data); 1576290071Sbapt if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err, !try_load)) { 1577290071Sbapt return (try_load || false); 1578290071Sbapt } 1579290071Sbapt 1580290071Sbapt container = parser->stack->obj->value.ov; 1581290071Sbapt old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix))); 1582290071Sbapt if (old_obj != NULL) { 1583290071Sbapt ucl_create_err (&parser->err, "Key %s already exists", prefix); 1584290071Sbapt return false; 1585290071Sbapt } 1586290071Sbapt 1587290071Sbapt if (strcasecmp (target, "string") == 0) { 1588290071Sbapt obj = ucl_object_fromstring_common (buf, buflen, flags); 1589290071Sbapt ucl_copy_value_trash (obj); 1590290071Sbapt if (multiline) { 1591290071Sbapt obj->flags |= UCL_OBJECT_MULTILINE; 1592290071Sbapt } 1593290071Sbapt } 1594290071Sbapt else if (strcasecmp (target, "int") == 0) { 1595290071Sbapt asprintf(&tmp, "%.*s", (int)buflen, buf); 1596290071Sbapt iv = strtoll(tmp, NULL, 10); 1597290071Sbapt obj = ucl_object_fromint(iv); 1598290071Sbapt } 1599290071Sbapt 1600290071Sbapt if (buflen > 0) { 1601290071Sbapt ucl_munmap (buf, buflen); 1602290071Sbapt } 1603290071Sbapt 1604290071Sbapt if (obj != NULL) { 1605290071Sbapt obj->key = prefix; 1606290071Sbapt obj->keylen = strlen (prefix); 1607290071Sbapt ucl_copy_key_trash(obj); 1608290071Sbapt obj->prev = obj; 1609290071Sbapt obj->next = NULL; 1610290071Sbapt ucl_object_set_priority (obj, priority); 1611290071Sbapt container = ucl_hash_insert_object (container, obj, 1612290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1613290071Sbapt parser->stack->obj->value.ov = container; 1614290071Sbapt } 1615290071Sbapt return true; 1616290071Sbapt } 1617290071Sbapt 1618290071Sbapt ucl_create_err (&parser->err, "Unable to parse load macro"); 1619290071Sbapt return false; 1620290071Sbapt} 1621290071Sbapt 1622290071Sbaptbool 1623290071Sbaptucl_inherit_handler (const unsigned char *data, size_t len, 1624290071Sbapt const ucl_object_t *args, const ucl_object_t *ctx, void* ud) 1625290071Sbapt{ 1626290071Sbapt const ucl_object_t *parent, *cur; 1627290071Sbapt ucl_object_t *target, *copy; 1628290071Sbapt ucl_object_iter_t it = NULL; 1629290071Sbapt bool replace = false; 1630290071Sbapt struct ucl_parser *parser = ud; 1631290071Sbapt 1632290071Sbapt parent = ucl_object_find_keyl (ctx, data, len); 1633290071Sbapt 1634290071Sbapt /* Some sanity checks */ 1635290071Sbapt if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) { 1636290071Sbapt ucl_create_err (&parser->err, "Unable to find inherited object %*.s", 1637290071Sbapt (int)len, data); 1638290071Sbapt return false; 1639290071Sbapt } 1640290071Sbapt 1641290071Sbapt if (parser->stack == NULL || parser->stack->obj == NULL || 1642290071Sbapt ucl_object_type (parser->stack->obj) != UCL_OBJECT) { 1643290071Sbapt ucl_create_err (&parser->err, "Invalid inherit context"); 1644290071Sbapt return false; 1645290071Sbapt } 1646290071Sbapt 1647290071Sbapt target = parser->stack->obj; 1648290071Sbapt 1649290071Sbapt if (args && (cur = ucl_object_find_key (args, "replace")) != NULL) { 1650290071Sbapt replace = ucl_object_toboolean (cur); 1651290071Sbapt } 1652290071Sbapt 1653290071Sbapt while ((cur = ucl_iterate_object (parent, &it, true))) { 1654290071Sbapt /* We do not replace existing keys */ 1655290071Sbapt if (!replace && ucl_object_find_keyl (target, cur->key, cur->keylen)) { 1656290071Sbapt continue; 1657290071Sbapt } 1658290071Sbapt 1659290071Sbapt copy = ucl_object_copy (cur); 1660290071Sbapt 1661290071Sbapt if (!replace) { 1662290071Sbapt copy->flags |= UCL_OBJECT_INHERITED; 1663290071Sbapt } 1664290071Sbapt 1665290071Sbapt ucl_object_insert_key (target, copy, copy->key, 1666290071Sbapt copy->keylen, false); 1667290071Sbapt } 1668290071Sbapt 1669290071Sbapt return true; 1670290071Sbapt} 1671290071Sbapt 1672290071Sbaptbool 1673262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 1674262395Sbapt{ 1675262395Sbapt char realbuf[PATH_MAX], *curdir; 1676262395Sbapt 1677262395Sbapt if (filename != NULL) { 1678262395Sbapt if (need_expand) { 1679263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 1680262395Sbapt return false; 1681262395Sbapt } 1682262395Sbapt } 1683262395Sbapt else { 1684262395Sbapt ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 1685262395Sbapt } 1686262395Sbapt 1687262395Sbapt /* Define variables */ 1688262395Sbapt ucl_parser_register_variable (parser, "FILENAME", realbuf); 1689262395Sbapt curdir = dirname (realbuf); 1690262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 1691262395Sbapt } 1692262395Sbapt else { 1693262395Sbapt /* Set everything from the current dir */ 1694262395Sbapt curdir = getcwd (realbuf, sizeof (realbuf)); 1695262395Sbapt ucl_parser_register_variable (parser, "FILENAME", "undef"); 1696262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 1697262395Sbapt } 1698262395Sbapt 1699262395Sbapt return true; 1700262395Sbapt} 1701262395Sbapt 1702290071Sbaptbool 1703290071Sbaptucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename, 1704290071Sbapt unsigned priority) 1705262395Sbapt{ 1706262395Sbapt unsigned char *buf; 1707262395Sbapt size_t len; 1708262395Sbapt bool ret; 1709262395Sbapt char realbuf[PATH_MAX]; 1710262395Sbapt 1711263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 1712262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 1713262395Sbapt filename, 1714262395Sbapt strerror (errno)); 1715262395Sbapt return false; 1716262395Sbapt } 1717262395Sbapt 1718262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 1719262395Sbapt return false; 1720262395Sbapt } 1721262395Sbapt 1722275223Sbapt if (parser->cur_file) { 1723275223Sbapt free (parser->cur_file); 1724275223Sbapt } 1725275223Sbapt parser->cur_file = strdup (realbuf); 1726262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 1727290071Sbapt ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); 1728262395Sbapt 1729262395Sbapt if (len > 0) { 1730263648Sbapt ucl_munmap (buf, len); 1731262395Sbapt } 1732262395Sbapt 1733262395Sbapt return ret; 1734262395Sbapt} 1735262395Sbapt 1736290071Sbaptbool 1737290071Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename) 1738275223Sbapt{ 1739290071Sbapt if (parser == NULL) { 1740290071Sbapt return false; 1741290071Sbapt } 1742290071Sbapt 1743290071Sbapt return ucl_parser_add_file_priority(parser, filename, 1744290071Sbapt parser->default_priority); 1745290071Sbapt} 1746290071Sbapt 1747290071Sbaptbool 1748290071Sbaptucl_parser_add_fd_priority (struct ucl_parser *parser, int fd, 1749290071Sbapt unsigned priority) 1750290071Sbapt{ 1751275223Sbapt unsigned char *buf; 1752275223Sbapt size_t len; 1753275223Sbapt bool ret; 1754275223Sbapt struct stat st; 1755275223Sbapt 1756275223Sbapt if (fstat (fd, &st) == -1) { 1757275223Sbapt ucl_create_err (&parser->err, "cannot stat fd %d: %s", 1758275223Sbapt fd, strerror (errno)); 1759275223Sbapt return false; 1760275223Sbapt } 1761275223Sbapt if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 1762275223Sbapt ucl_create_err (&parser->err, "cannot mmap fd %d: %s", 1763275223Sbapt fd, strerror (errno)); 1764275223Sbapt return false; 1765275223Sbapt } 1766275223Sbapt 1767275223Sbapt if (parser->cur_file) { 1768275223Sbapt free (parser->cur_file); 1769275223Sbapt } 1770275223Sbapt parser->cur_file = NULL; 1771275223Sbapt len = st.st_size; 1772290071Sbapt ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); 1773275223Sbapt 1774275223Sbapt if (len > 0) { 1775275223Sbapt ucl_munmap (buf, len); 1776275223Sbapt } 1777275223Sbapt 1778275223Sbapt return ret; 1779275223Sbapt} 1780275223Sbapt 1781290071Sbaptbool 1782290071Sbaptucl_parser_add_fd (struct ucl_parser *parser, int fd) 1783290071Sbapt{ 1784290071Sbapt if (parser == NULL) { 1785290071Sbapt return false; 1786290071Sbapt } 1787290071Sbapt 1788290071Sbapt return ucl_parser_add_fd_priority(parser, fd, parser->default_priority); 1789290071Sbapt} 1790290071Sbapt 1791262395Sbaptsize_t 1792262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz) 1793262395Sbapt{ 1794262395Sbapt char *d = dst; 1795262395Sbapt const char *s = src; 1796262395Sbapt size_t n = siz; 1797262395Sbapt 1798262395Sbapt /* Copy as many bytes as will fit */ 1799262395Sbapt if (n != 0) { 1800262395Sbapt while (--n != 0) { 1801262395Sbapt if ((*d++ = *s++) == '\0') { 1802262395Sbapt break; 1803262395Sbapt } 1804262395Sbapt } 1805262395Sbapt } 1806262395Sbapt 1807262395Sbapt if (n == 0 && siz != 0) { 1808262395Sbapt *d = '\0'; 1809262395Sbapt } 1810262395Sbapt 1811262395Sbapt return (s - src - 1); /* count does not include NUL */ 1812262395Sbapt} 1813262395Sbapt 1814262395Sbaptsize_t 1815262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 1816262395Sbapt{ 1817262395Sbapt memcpy (dst, src, siz - 1); 1818262395Sbapt dst[siz - 1] = '\0'; 1819262395Sbapt 1820262395Sbapt return siz - 1; 1821262395Sbapt} 1822262395Sbapt 1823262395Sbaptsize_t 1824262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 1825262395Sbapt{ 1826262395Sbapt char *d = dst; 1827262395Sbapt const char *s = src; 1828262395Sbapt size_t n = siz; 1829262395Sbapt 1830262395Sbapt /* Copy as many bytes as will fit */ 1831262395Sbapt if (n != 0) { 1832262395Sbapt while (--n != 0) { 1833262395Sbapt if ((*d++ = tolower (*s++)) == '\0') { 1834262395Sbapt break; 1835262395Sbapt } 1836262395Sbapt } 1837262395Sbapt } 1838262395Sbapt 1839262395Sbapt if (n == 0 && siz != 0) { 1840262395Sbapt *d = '\0'; 1841262395Sbapt } 1842262395Sbapt 1843262395Sbapt return (s - src); /* count does not include NUL */ 1844262395Sbapt} 1845262395Sbapt 1846290071Sbapt/* 1847290071Sbapt * Find the first occurrence of find in s 1848290071Sbapt */ 1849290071Sbaptchar * 1850290071Sbaptucl_strnstr (const char *s, const char *find, int len) 1851290071Sbapt{ 1852290071Sbapt char c, sc; 1853290071Sbapt int mlen; 1854290071Sbapt 1855290071Sbapt if ((c = *find++) != 0) { 1856290071Sbapt mlen = strlen (find); 1857290071Sbapt do { 1858290071Sbapt do { 1859290071Sbapt if ((sc = *s++) == 0 || len-- == 0) 1860290071Sbapt return (NULL); 1861290071Sbapt } while (sc != c); 1862290071Sbapt } while (strncmp (s, find, mlen) != 0); 1863290071Sbapt s--; 1864290071Sbapt } 1865290071Sbapt return ((char *)s); 1866290071Sbapt} 1867290071Sbapt 1868290071Sbapt/* 1869290071Sbapt * Find the first occurrence of find in s, ignore case. 1870290071Sbapt */ 1871290071Sbaptchar * 1872290071Sbaptucl_strncasestr (const char *s, const char *find, int len) 1873290071Sbapt{ 1874290071Sbapt char c, sc; 1875290071Sbapt int mlen; 1876290071Sbapt 1877290071Sbapt if ((c = *find++) != 0) { 1878290071Sbapt c = tolower (c); 1879290071Sbapt mlen = strlen (find); 1880290071Sbapt do { 1881290071Sbapt do { 1882290071Sbapt if ((sc = *s++) == 0 || len-- == 0) 1883290071Sbapt return (NULL); 1884290071Sbapt } while (tolower (sc) != c); 1885290071Sbapt } while (strncasecmp (s, find, mlen) != 0); 1886290071Sbapt s--; 1887290071Sbapt } 1888290071Sbapt return ((char *)s); 1889290071Sbapt} 1890290071Sbapt 1891262395Sbaptucl_object_t * 1892262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1893262395Sbapt{ 1894262395Sbapt ucl_object_t *obj; 1895262395Sbapt const char *start, *end, *p, *pos; 1896262395Sbapt char *dst, *d; 1897262395Sbapt size_t escaped_len; 1898262395Sbapt 1899262395Sbapt if (str == NULL) { 1900262395Sbapt return NULL; 1901262395Sbapt } 1902262395Sbapt 1903262395Sbapt obj = ucl_object_new (); 1904262395Sbapt if (obj) { 1905262395Sbapt if (len == 0) { 1906262395Sbapt len = strlen (str); 1907262395Sbapt } 1908262395Sbapt if (flags & UCL_STRING_TRIM) { 1909262395Sbapt /* Skip leading spaces */ 1910262395Sbapt for (start = str; (size_t)(start - str) < len; start ++) { 1911262395Sbapt if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1912262395Sbapt break; 1913262395Sbapt } 1914262395Sbapt } 1915262395Sbapt /* Skip trailing spaces */ 1916262395Sbapt for (end = str + len - 1; end > start; end --) { 1917262395Sbapt if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1918262395Sbapt break; 1919262395Sbapt } 1920262395Sbapt } 1921262395Sbapt end ++; 1922262395Sbapt } 1923262395Sbapt else { 1924262395Sbapt start = str; 1925262395Sbapt end = str + len; 1926262395Sbapt } 1927262395Sbapt 1928262395Sbapt obj->type = UCL_STRING; 1929262395Sbapt if (flags & UCL_STRING_ESCAPE) { 1930262395Sbapt for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1931262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1932262395Sbapt escaped_len ++; 1933262395Sbapt } 1934262395Sbapt } 1935262395Sbapt dst = malloc (escaped_len + 1); 1936262395Sbapt if (dst != NULL) { 1937262395Sbapt for (p = start, d = dst; p < end; p ++, d ++) { 1938262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1939262395Sbapt switch (*p) { 1940262395Sbapt case '\n': 1941262395Sbapt *d++ = '\\'; 1942262395Sbapt *d = 'n'; 1943262395Sbapt break; 1944262395Sbapt case '\r': 1945262395Sbapt *d++ = '\\'; 1946262395Sbapt *d = 'r'; 1947262395Sbapt break; 1948262395Sbapt case '\b': 1949262395Sbapt *d++ = '\\'; 1950262395Sbapt *d = 'b'; 1951262395Sbapt break; 1952262395Sbapt case '\t': 1953262395Sbapt *d++ = '\\'; 1954262395Sbapt *d = 't'; 1955262395Sbapt break; 1956262395Sbapt case '\f': 1957262395Sbapt *d++ = '\\'; 1958262395Sbapt *d = 'f'; 1959262395Sbapt break; 1960262395Sbapt case '\\': 1961262395Sbapt *d++ = '\\'; 1962262395Sbapt *d = '\\'; 1963262395Sbapt break; 1964262395Sbapt case '"': 1965262395Sbapt *d++ = '\\'; 1966262395Sbapt *d = '"'; 1967262395Sbapt break; 1968262395Sbapt } 1969262395Sbapt } 1970262395Sbapt else { 1971262395Sbapt *d = *p; 1972262395Sbapt } 1973262395Sbapt } 1974262395Sbapt *d = '\0'; 1975262395Sbapt obj->value.sv = dst; 1976262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1977262395Sbapt obj->len = escaped_len; 1978262395Sbapt } 1979262395Sbapt } 1980262395Sbapt else { 1981262395Sbapt dst = malloc (end - start + 1); 1982262395Sbapt if (dst != NULL) { 1983262395Sbapt ucl_strlcpy_unsafe (dst, start, end - start + 1); 1984262395Sbapt obj->value.sv = dst; 1985262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1986262395Sbapt obj->len = end - start; 1987262395Sbapt } 1988262395Sbapt } 1989262395Sbapt if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1990262395Sbapt /* Parse what we have */ 1991262395Sbapt if (flags & UCL_STRING_PARSE_BOOLEAN) { 1992262395Sbapt if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1993262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1994262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1995263648Sbapt flags & UCL_STRING_PARSE_BYTES, 1996263648Sbapt flags & UCL_STRING_PARSE_TIME); 1997262395Sbapt } 1998262395Sbapt } 1999262395Sbapt else { 2000262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 2001262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 2002263648Sbapt flags & UCL_STRING_PARSE_BYTES, 2003263648Sbapt flags & UCL_STRING_PARSE_TIME); 2004262395Sbapt } 2005262395Sbapt } 2006262395Sbapt } 2007262395Sbapt 2008262395Sbapt return obj; 2009262395Sbapt} 2010262395Sbapt 2011264789Sbaptstatic bool 2012262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 2013262395Sbapt const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 2014262395Sbapt{ 2015264789Sbapt ucl_object_t *found, *tmp; 2016264789Sbapt const ucl_object_t *cur; 2017262395Sbapt ucl_object_iter_t it = NULL; 2018262395Sbapt const char *p; 2019264789Sbapt int ret = true; 2020262395Sbapt 2021262395Sbapt if (elt == NULL || key == NULL) { 2022264789Sbapt return false; 2023262395Sbapt } 2024262395Sbapt 2025262395Sbapt if (top == NULL) { 2026264789Sbapt return false; 2027262395Sbapt } 2028262395Sbapt 2029262395Sbapt if (top->type != UCL_OBJECT) { 2030262395Sbapt /* It is possible to convert NULL type to an object */ 2031262395Sbapt if (top->type == UCL_NULL) { 2032262395Sbapt top->type = UCL_OBJECT; 2033262395Sbapt } 2034262395Sbapt else { 2035262395Sbapt /* Refuse converting of other object types */ 2036264789Sbapt return false; 2037262395Sbapt } 2038262395Sbapt } 2039262395Sbapt 2040262395Sbapt if (top->value.ov == NULL) { 2041279549Sbapt top->value.ov = ucl_hash_create (false); 2042262395Sbapt } 2043262395Sbapt 2044262395Sbapt if (keylen == 0) { 2045262395Sbapt keylen = strlen (key); 2046262395Sbapt } 2047262395Sbapt 2048262395Sbapt for (p = key; p < key + keylen; p ++) { 2049262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 2050262395Sbapt elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 2051262395Sbapt break; 2052262395Sbapt } 2053262395Sbapt } 2054262395Sbapt 2055275223Sbapt /* workaround for some use cases */ 2056275223Sbapt if (elt->trash_stack[UCL_TRASH_KEY] != NULL && 2057275223Sbapt key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) { 2058275223Sbapt /* Remove copied key */ 2059275223Sbapt free (elt->trash_stack[UCL_TRASH_KEY]); 2060275223Sbapt elt->trash_stack[UCL_TRASH_KEY] = NULL; 2061275223Sbapt elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY; 2062275223Sbapt } 2063275223Sbapt 2064262395Sbapt elt->key = key; 2065262395Sbapt elt->keylen = keylen; 2066262395Sbapt 2067262395Sbapt if (copy_key) { 2068262395Sbapt ucl_copy_key_trash (elt); 2069262395Sbapt } 2070262395Sbapt 2071264789Sbapt found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 2072262395Sbapt 2073275223Sbapt if (found == NULL) { 2074279549Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); 2075263648Sbapt top->len ++; 2076264789Sbapt if (replace) { 2077264789Sbapt ret = false; 2078264789Sbapt } 2079262395Sbapt } 2080262395Sbapt else { 2081262395Sbapt if (replace) { 2082275223Sbapt ucl_hash_replace (top->value.ov, found, elt); 2083262395Sbapt ucl_object_unref (found); 2084262395Sbapt } 2085262395Sbapt else if (merge) { 2086262395Sbapt if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 2087262395Sbapt /* Insert old elt to new one */ 2088264789Sbapt ucl_object_insert_key_common (elt, found, found->key, 2089264789Sbapt found->keylen, copy_key, false, false); 2090262395Sbapt ucl_hash_delete (top->value.ov, found); 2091279549Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); 2092262395Sbapt } 2093262395Sbapt else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 2094262395Sbapt /* Insert new to old */ 2095264789Sbapt ucl_object_insert_key_common (found, elt, elt->key, 2096264789Sbapt elt->keylen, copy_key, false, false); 2097262395Sbapt } 2098262395Sbapt else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 2099262395Sbapt /* Mix two hashes */ 2100262395Sbapt while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 2101264789Sbapt tmp = ucl_object_ref (cur); 2102264789Sbapt ucl_object_insert_key_common (found, tmp, cur->key, 2103264789Sbapt cur->keylen, copy_key, false, false); 2104262395Sbapt } 2105262395Sbapt ucl_object_unref (elt); 2106262395Sbapt } 2107262395Sbapt else { 2108262395Sbapt /* Just make a list of scalars */ 2109262395Sbapt DL_APPEND (found, elt); 2110262395Sbapt } 2111262395Sbapt } 2112262395Sbapt else { 2113262395Sbapt DL_APPEND (found, elt); 2114262395Sbapt } 2115262395Sbapt } 2116262395Sbapt 2117264789Sbapt return ret; 2118262395Sbapt} 2119262395Sbapt 2120262975Sbaptbool 2121264789Sbaptucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 2122262975Sbapt{ 2123262975Sbapt ucl_object_t *found; 2124262975Sbapt 2125263648Sbapt if (top == NULL || key == NULL) { 2126263648Sbapt return false; 2127263648Sbapt } 2128263648Sbapt 2129264789Sbapt found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); 2130262975Sbapt 2131263648Sbapt if (found == NULL) { 2132262975Sbapt return false; 2133263648Sbapt } 2134262975Sbapt 2135264789Sbapt ucl_hash_delete (top->value.ov, found); 2136262975Sbapt ucl_object_unref (found); 2137262975Sbapt top->len --; 2138262975Sbapt 2139262975Sbapt return true; 2140262975Sbapt} 2141262975Sbapt 2142262975Sbaptbool 2143264789Sbaptucl_object_delete_key (ucl_object_t *top, const char *key) 2144262975Sbapt{ 2145290071Sbapt return ucl_object_delete_keyl (top, key, strlen (key)); 2146262975Sbapt} 2147262975Sbapt 2148263648Sbaptucl_object_t* 2149263648Sbaptucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 2150263648Sbapt{ 2151264789Sbapt const ucl_object_t *found; 2152263648Sbapt 2153263648Sbapt if (top == NULL || key == NULL) { 2154263648Sbapt return false; 2155263648Sbapt } 2156264789Sbapt found = ucl_object_find_keyl (top, key, keylen); 2157263648Sbapt 2158263648Sbapt if (found == NULL) { 2159263648Sbapt return NULL; 2160263648Sbapt } 2161264789Sbapt ucl_hash_delete (top->value.ov, found); 2162263648Sbapt top->len --; 2163263648Sbapt 2164264789Sbapt return __DECONST (ucl_object_t *, found); 2165263648Sbapt} 2166263648Sbapt 2167263648Sbaptucl_object_t* 2168263648Sbaptucl_object_pop_key (ucl_object_t *top, const char *key) 2169263648Sbapt{ 2170290071Sbapt return ucl_object_pop_keyl (top, key, strlen (key)); 2171263648Sbapt} 2172263648Sbapt 2173264789Sbaptbool 2174262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 2175262395Sbapt const char *key, size_t keylen, bool copy_key) 2176262395Sbapt{ 2177262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 2178262395Sbapt} 2179262395Sbapt 2180264789Sbaptbool 2181262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 2182262395Sbapt const char *key, size_t keylen, bool copy_key) 2183262395Sbapt{ 2184262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 2185262395Sbapt} 2186262395Sbapt 2187264789Sbaptbool 2188262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 2189262395Sbapt const char *key, size_t keylen, bool copy_key) 2190262395Sbapt{ 2191262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 2192262395Sbapt} 2193262395Sbapt 2194275223Sbaptbool 2195275223Sbaptucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 2196275223Sbapt{ 2197275223Sbapt ucl_object_t *cur = NULL, *cp = NULL, *found = NULL; 2198275223Sbapt ucl_object_iter_t iter = NULL; 2199275223Sbapt 2200275223Sbapt if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) { 2201275223Sbapt return false; 2202275223Sbapt } 2203275223Sbapt 2204275223Sbapt /* Mix two hashes */ 2205275223Sbapt while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) { 2206275223Sbapt if (copy) { 2207275223Sbapt cp = ucl_object_copy (cur); 2208275223Sbapt } 2209275223Sbapt else { 2210275223Sbapt cp = ucl_object_ref (cur); 2211275223Sbapt } 2212275223Sbapt found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen)); 2213275223Sbapt if (found == NULL) { 2214275223Sbapt /* The key does not exist */ 2215279549Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false); 2216275223Sbapt top->len ++; 2217275223Sbapt } 2218275223Sbapt else { 2219275223Sbapt /* The key already exists, replace it */ 2220275223Sbapt ucl_hash_replace (top->value.ov, found, cp); 2221275223Sbapt ucl_object_unref (found); 2222275223Sbapt } 2223275223Sbapt } 2224275223Sbapt 2225275223Sbapt return true; 2226275223Sbapt} 2227275223Sbapt 2228264789Sbaptconst ucl_object_t * 2229264789Sbaptucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) 2230262395Sbapt{ 2231264789Sbapt const ucl_object_t *ret; 2232264789Sbapt ucl_object_t srch; 2233262395Sbapt 2234262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 2235262395Sbapt return NULL; 2236262395Sbapt } 2237262395Sbapt 2238262395Sbapt srch.key = key; 2239262395Sbapt srch.keylen = klen; 2240262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 2241262395Sbapt 2242262395Sbapt return ret; 2243262395Sbapt} 2244262395Sbapt 2245264789Sbaptconst ucl_object_t * 2246264789Sbaptucl_object_find_key (const ucl_object_t *obj, const char *key) 2247262395Sbapt{ 2248290071Sbapt if (key == NULL) { 2249262395Sbapt return NULL; 2250290071Sbapt } 2251262395Sbapt 2252290071Sbapt return ucl_object_find_keyl (obj, key, strlen (key)); 2253262395Sbapt} 2254262395Sbapt 2255264789Sbaptconst ucl_object_t* 2256290071Sbaptucl_object_find_any_key (const ucl_object_t *obj, 2257290071Sbapt const char *key, ...) 2258290071Sbapt{ 2259290071Sbapt va_list ap; 2260290071Sbapt const ucl_object_t *ret = NULL; 2261290071Sbapt const char *nk = NULL; 2262290071Sbapt 2263290071Sbapt if (obj == NULL || key == NULL) { 2264290071Sbapt return NULL; 2265290071Sbapt } 2266290071Sbapt 2267290071Sbapt ret = ucl_object_find_keyl (obj, key, strlen (key)); 2268290071Sbapt 2269290071Sbapt if (ret == NULL) { 2270290071Sbapt va_start (ap, key); 2271290071Sbapt 2272290071Sbapt while (ret == NULL) { 2273290071Sbapt nk = va_arg (ap, const char *); 2274290071Sbapt 2275290071Sbapt if (nk == NULL) { 2276290071Sbapt break; 2277290071Sbapt } 2278290071Sbapt else { 2279290071Sbapt ret = ucl_object_find_keyl (obj, nk, strlen (nk)); 2280290071Sbapt } 2281290071Sbapt } 2282290071Sbapt 2283290071Sbapt va_end (ap); 2284290071Sbapt } 2285290071Sbapt 2286290071Sbapt return ret; 2287290071Sbapt} 2288290071Sbapt 2289290071Sbaptconst ucl_object_t* 2290264789Sbaptucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 2291262395Sbapt{ 2292279549Sbapt const ucl_object_t *elt = NULL; 2293262395Sbapt 2294263648Sbapt if (obj == NULL || iter == NULL) { 2295263648Sbapt return NULL; 2296263648Sbapt } 2297263648Sbapt 2298262395Sbapt if (expand_values) { 2299262395Sbapt switch (obj->type) { 2300262395Sbapt case UCL_OBJECT: 2301264789Sbapt return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 2302262395Sbapt break; 2303279549Sbapt case UCL_ARRAY: { 2304279549Sbapt unsigned int idx; 2305279549Sbapt UCL_ARRAY_GET (vec, obj); 2306279549Sbapt idx = (unsigned int)(uintptr_t)(*iter); 2307279549Sbapt 2308279549Sbapt if (vec != NULL) { 2309279549Sbapt while (idx < kv_size (*vec)) { 2310279549Sbapt if ((elt = kv_A (*vec, idx)) != NULL) { 2311279549Sbapt idx ++; 2312279549Sbapt break; 2313279549Sbapt } 2314279549Sbapt idx ++; 2315262395Sbapt } 2316279549Sbapt *iter = (void *)(uintptr_t)idx; 2317262395Sbapt } 2318279549Sbapt 2319262395Sbapt return elt; 2320279549Sbapt break; 2321279549Sbapt } 2322262395Sbapt default: 2323262395Sbapt /* Go to linear iteration */ 2324262395Sbapt break; 2325262395Sbapt } 2326262395Sbapt } 2327262395Sbapt /* Treat everything as a linear list */ 2328262395Sbapt elt = *iter; 2329262395Sbapt if (elt == NULL) { 2330262395Sbapt elt = obj; 2331262395Sbapt } 2332262395Sbapt else if (elt == obj) { 2333262395Sbapt return NULL; 2334262395Sbapt } 2335264789Sbapt *iter = __DECONST (void *, elt->next ? elt->next : obj); 2336262395Sbapt return elt; 2337262395Sbapt 2338262395Sbapt /* Not reached */ 2339262395Sbapt return NULL; 2340262395Sbapt} 2341263648Sbapt 2342279549Sbaptconst char safe_iter_magic[4] = {'u', 'i', 't', 'e'}; 2343279549Sbaptstruct ucl_object_safe_iter { 2344279549Sbapt char magic[4]; /* safety check */ 2345279549Sbapt const ucl_object_t *impl_it; /* implicit object iteration */ 2346279549Sbapt ucl_object_iter_t expl_it; /* explicit iteration */ 2347279549Sbapt}; 2348279549Sbapt 2349279549Sbapt#define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr) 2350279549Sbapt#define UCL_SAFE_ITER_CHECK(it) do { \ 2351279549Sbapt assert (it != NULL); \ 2352279549Sbapt assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \ 2353279549Sbapt } while (0) 2354279549Sbapt 2355279549Sbaptucl_object_iter_t 2356279549Sbaptucl_object_iterate_new (const ucl_object_t *obj) 2357279549Sbapt{ 2358279549Sbapt struct ucl_object_safe_iter *it; 2359279549Sbapt 2360279549Sbapt it = UCL_ALLOC (sizeof (*it)); 2361279549Sbapt if (it != NULL) { 2362279549Sbapt memcpy (it->magic, safe_iter_magic, sizeof (it->magic)); 2363279549Sbapt it->expl_it = NULL; 2364279549Sbapt it->impl_it = obj; 2365279549Sbapt } 2366279549Sbapt 2367279549Sbapt return (ucl_object_iter_t)it; 2368279549Sbapt} 2369279549Sbapt 2370279549Sbapt 2371279549Sbaptucl_object_iter_t 2372279549Sbaptucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj) 2373279549Sbapt{ 2374279549Sbapt struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 2375279549Sbapt 2376279549Sbapt UCL_SAFE_ITER_CHECK (rit); 2377279549Sbapt 2378279549Sbapt rit->impl_it = obj; 2379279549Sbapt rit->expl_it = NULL; 2380279549Sbapt 2381279549Sbapt return it; 2382279549Sbapt} 2383279549Sbapt 2384279549Sbaptconst ucl_object_t* 2385279549Sbaptucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values) 2386279549Sbapt{ 2387279549Sbapt struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 2388279549Sbapt const ucl_object_t *ret = NULL; 2389279549Sbapt 2390279549Sbapt UCL_SAFE_ITER_CHECK (rit); 2391279549Sbapt 2392279549Sbapt if (rit->impl_it == NULL) { 2393279549Sbapt return NULL; 2394279549Sbapt } 2395279549Sbapt 2396279549Sbapt if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) { 2397279549Sbapt ret = ucl_iterate_object (rit->impl_it, &rit->expl_it, true); 2398279549Sbapt 2399279549Sbapt if (ret == NULL) { 2400279549Sbapt /* Need to switch to another implicit object in chain */ 2401279549Sbapt rit->impl_it = rit->impl_it->next; 2402279549Sbapt rit->expl_it = NULL; 2403279549Sbapt return ucl_object_iterate_safe (it, expand_values); 2404279549Sbapt } 2405279549Sbapt } 2406279549Sbapt else { 2407279549Sbapt /* Just iterate over the implicit array */ 2408279549Sbapt ret = rit->impl_it; 2409279549Sbapt rit->impl_it = rit->impl_it->next; 2410279549Sbapt if (expand_values) { 2411279549Sbapt /* We flatten objects if need to expand values */ 2412279549Sbapt if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) { 2413279549Sbapt return ucl_object_iterate_safe (it, expand_values); 2414279549Sbapt } 2415279549Sbapt } 2416279549Sbapt } 2417279549Sbapt 2418279549Sbapt return ret; 2419279549Sbapt} 2420279549Sbapt 2421279549Sbaptvoid 2422279549Sbaptucl_object_iterate_free (ucl_object_iter_t it) 2423279549Sbapt{ 2424279549Sbapt struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 2425279549Sbapt 2426279549Sbapt UCL_SAFE_ITER_CHECK (rit); 2427279549Sbapt 2428279549Sbapt UCL_FREE (sizeof (*rit), it); 2429279549Sbapt} 2430279549Sbapt 2431266636Sbaptconst ucl_object_t * 2432266636Sbaptucl_lookup_path (const ucl_object_t *top, const char *path_in) { 2433290071Sbapt return ucl_lookup_path_char (top, path_in, '.'); 2434290071Sbapt} 2435290071Sbapt 2436290071Sbapt 2437290071Sbaptconst ucl_object_t * 2438290071Sbaptucl_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) { 2439266636Sbapt const ucl_object_t *o = NULL, *found; 2440266636Sbapt const char *p, *c; 2441266636Sbapt char *err_str; 2442266636Sbapt unsigned index; 2443263648Sbapt 2444266636Sbapt if (path_in == NULL || top == NULL) { 2445266636Sbapt return NULL; 2446266636Sbapt } 2447266636Sbapt 2448266636Sbapt found = NULL; 2449266636Sbapt p = path_in; 2450266636Sbapt 2451266636Sbapt /* Skip leading dots */ 2452290071Sbapt while (*p == sep) { 2453266636Sbapt p ++; 2454266636Sbapt } 2455266636Sbapt 2456266636Sbapt c = p; 2457266636Sbapt while (*p != '\0') { 2458266636Sbapt p ++; 2459290071Sbapt if (*p == sep || *p == '\0') { 2460266636Sbapt if (p > c) { 2461266636Sbapt switch (top->type) { 2462266636Sbapt case UCL_ARRAY: 2463266636Sbapt /* Key should be an int */ 2464266636Sbapt index = strtoul (c, &err_str, 10); 2465290071Sbapt if (err_str != NULL && (*err_str != sep && *err_str != '\0')) { 2466266636Sbapt return NULL; 2467266636Sbapt } 2468266636Sbapt o = ucl_array_find_index (top, index); 2469266636Sbapt break; 2470266636Sbapt default: 2471266636Sbapt o = ucl_object_find_keyl (top, c, p - c); 2472266636Sbapt break; 2473266636Sbapt } 2474266636Sbapt if (o == NULL) { 2475266636Sbapt return NULL; 2476266636Sbapt } 2477266636Sbapt top = o; 2478266636Sbapt } 2479266636Sbapt if (*p != '\0') { 2480266636Sbapt c = p + 1; 2481266636Sbapt } 2482266636Sbapt } 2483266636Sbapt } 2484266636Sbapt found = o; 2485266636Sbapt 2486266636Sbapt return found; 2487266636Sbapt} 2488266636Sbapt 2489266636Sbapt 2490263648Sbaptucl_object_t * 2491263648Sbaptucl_object_new (void) 2492263648Sbapt{ 2493275223Sbapt return ucl_object_typed_new (UCL_NULL); 2494263648Sbapt} 2495263648Sbapt 2496263648Sbaptucl_object_t * 2497266636Sbaptucl_object_typed_new (ucl_type_t type) 2498263648Sbapt{ 2499275223Sbapt return ucl_object_new_full (type, 0); 2500275223Sbapt} 2501275223Sbapt 2502275223Sbaptucl_object_t * 2503275223Sbaptucl_object_new_full (ucl_type_t type, unsigned priority) 2504275223Sbapt{ 2505263648Sbapt ucl_object_t *new; 2506275223Sbapt 2507275223Sbapt if (type != UCL_USERDATA) { 2508275223Sbapt new = UCL_ALLOC (sizeof (ucl_object_t)); 2509275223Sbapt if (new != NULL) { 2510275223Sbapt memset (new, 0, sizeof (ucl_object_t)); 2511275223Sbapt new->ref = 1; 2512275223Sbapt new->type = (type <= UCL_NULL ? type : UCL_NULL); 2513275223Sbapt new->next = NULL; 2514275223Sbapt new->prev = new; 2515275223Sbapt ucl_object_set_priority (new, priority); 2516279549Sbapt 2517279549Sbapt if (type == UCL_ARRAY) { 2518279549Sbapt new->value.av = UCL_ALLOC (sizeof (ucl_array_t)); 2519279549Sbapt if (new->value.av) { 2520279549Sbapt memset (new->value.av, 0, sizeof (ucl_array_t)); 2521279549Sbapt UCL_ARRAY_GET (vec, new); 2522279549Sbapt 2523279549Sbapt /* Preallocate some space for arrays */ 2524279549Sbapt kv_resize (ucl_object_t *, *vec, 8); 2525279549Sbapt } 2526279549Sbapt } 2527275223Sbapt } 2528263648Sbapt } 2529275223Sbapt else { 2530275223Sbapt new = ucl_object_new_userdata (NULL, NULL); 2531275223Sbapt ucl_object_set_priority (new, priority); 2532275223Sbapt } 2533275223Sbapt 2534263648Sbapt return new; 2535263648Sbapt} 2536263648Sbapt 2537275223Sbaptucl_object_t* 2538275223Sbaptucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter) 2539275223Sbapt{ 2540275223Sbapt struct ucl_object_userdata *new; 2541275223Sbapt size_t nsize = sizeof (*new); 2542275223Sbapt 2543275223Sbapt new = UCL_ALLOC (nsize); 2544275223Sbapt if (new != NULL) { 2545275223Sbapt memset (new, 0, nsize); 2546275223Sbapt new->obj.ref = 1; 2547275223Sbapt new->obj.type = UCL_USERDATA; 2548275223Sbapt new->obj.next = NULL; 2549275223Sbapt new->obj.prev = (ucl_object_t *)new; 2550275223Sbapt new->dtor = dtor; 2551275223Sbapt new->emitter = emitter; 2552275223Sbapt } 2553275223Sbapt 2554275223Sbapt return (ucl_object_t *)new; 2555275223Sbapt} 2556275223Sbapt 2557266636Sbaptucl_type_t 2558266636Sbaptucl_object_type (const ucl_object_t *obj) 2559266636Sbapt{ 2560290071Sbapt if (obj == NULL) { 2561290071Sbapt return UCL_NULL; 2562290071Sbapt } 2563290071Sbapt 2564266636Sbapt return obj->type; 2565266636Sbapt} 2566266636Sbapt 2567263648Sbaptucl_object_t* 2568263648Sbaptucl_object_fromstring (const char *str) 2569263648Sbapt{ 2570263648Sbapt return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 2571263648Sbapt} 2572263648Sbapt 2573263648Sbaptucl_object_t * 2574263648Sbaptucl_object_fromlstring (const char *str, size_t len) 2575263648Sbapt{ 2576263648Sbapt return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 2577263648Sbapt} 2578263648Sbapt 2579263648Sbaptucl_object_t * 2580263648Sbaptucl_object_fromint (int64_t iv) 2581263648Sbapt{ 2582263648Sbapt ucl_object_t *obj; 2583263648Sbapt 2584263648Sbapt obj = ucl_object_new (); 2585263648Sbapt if (obj != NULL) { 2586263648Sbapt obj->type = UCL_INT; 2587263648Sbapt obj->value.iv = iv; 2588263648Sbapt } 2589263648Sbapt 2590263648Sbapt return obj; 2591263648Sbapt} 2592263648Sbapt 2593263648Sbaptucl_object_t * 2594263648Sbaptucl_object_fromdouble (double dv) 2595263648Sbapt{ 2596263648Sbapt ucl_object_t *obj; 2597263648Sbapt 2598263648Sbapt obj = ucl_object_new (); 2599263648Sbapt if (obj != NULL) { 2600263648Sbapt obj->type = UCL_FLOAT; 2601263648Sbapt obj->value.dv = dv; 2602263648Sbapt } 2603263648Sbapt 2604263648Sbapt return obj; 2605263648Sbapt} 2606263648Sbapt 2607263648Sbaptucl_object_t* 2608263648Sbaptucl_object_frombool (bool bv) 2609263648Sbapt{ 2610263648Sbapt ucl_object_t *obj; 2611263648Sbapt 2612263648Sbapt obj = ucl_object_new (); 2613263648Sbapt if (obj != NULL) { 2614263648Sbapt obj->type = UCL_BOOLEAN; 2615263648Sbapt obj->value.iv = bv; 2616263648Sbapt } 2617263648Sbapt 2618263648Sbapt return obj; 2619263648Sbapt} 2620263648Sbapt 2621264789Sbaptbool 2622263648Sbaptucl_array_append (ucl_object_t *top, ucl_object_t *elt) 2623263648Sbapt{ 2624279549Sbapt UCL_ARRAY_GET (vec, top); 2625263648Sbapt 2626264789Sbapt if (elt == NULL || top == NULL) { 2627264789Sbapt return false; 2628263648Sbapt } 2629263648Sbapt 2630279549Sbapt if (vec == NULL) { 2631279549Sbapt vec = UCL_ALLOC (sizeof (*vec)); 2632290071Sbapt 2633290071Sbapt if (vec == NULL) { 2634290071Sbapt return false; 2635290071Sbapt } 2636290071Sbapt 2637279549Sbapt kv_init (*vec); 2638279549Sbapt top->value.av = (void *)vec; 2639263648Sbapt } 2640279549Sbapt 2641279549Sbapt kv_push (ucl_object_t *, *vec, elt); 2642279549Sbapt 2643264789Sbapt top->len ++; 2644263648Sbapt 2645264789Sbapt return true; 2646263648Sbapt} 2647263648Sbapt 2648264789Sbaptbool 2649263648Sbaptucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 2650263648Sbapt{ 2651279549Sbapt UCL_ARRAY_GET (vec, top); 2652263648Sbapt 2653264789Sbapt if (elt == NULL || top == NULL) { 2654264789Sbapt return false; 2655263648Sbapt } 2656263648Sbapt 2657279549Sbapt if (vec == NULL) { 2658279549Sbapt vec = UCL_ALLOC (sizeof (*vec)); 2659279549Sbapt kv_init (*vec); 2660279549Sbapt top->value.av = (void *)vec; 2661279549Sbapt kv_push (ucl_object_t *, *vec, elt); 2662263648Sbapt } 2663263648Sbapt else { 2664279549Sbapt /* Slow O(n) algorithm */ 2665279549Sbapt kv_prepend (ucl_object_t *, *vec, elt); 2666263648Sbapt } 2667279549Sbapt 2668264789Sbapt top->len ++; 2669263648Sbapt 2670264789Sbapt return true; 2671263648Sbapt} 2672263648Sbapt 2673275223Sbaptbool 2674275223Sbaptucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 2675275223Sbapt{ 2676279549Sbapt unsigned i; 2677290071Sbapt ucl_object_t *cp = NULL; 2678279549Sbapt ucl_object_t **obj; 2679275223Sbapt 2680275223Sbapt if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { 2681275223Sbapt return false; 2682275223Sbapt } 2683275223Sbapt 2684290071Sbapt if (copy) { 2685290071Sbapt cp = ucl_object_copy (elt); 2686290071Sbapt } 2687290071Sbapt else { 2688290071Sbapt cp = ucl_object_ref (elt); 2689290071Sbapt } 2690290071Sbapt 2691290071Sbapt UCL_ARRAY_GET (v1, top); 2692290071Sbapt UCL_ARRAY_GET (v2, cp); 2693290071Sbapt 2694279549Sbapt kv_concat (ucl_object_t *, *v1, *v2); 2695279549Sbapt 2696279549Sbapt for (i = v2->n; i < v1->n; i ++) { 2697279549Sbapt obj = &kv_A (*v1, i); 2698279549Sbapt if (*obj == NULL) { 2699279549Sbapt continue; 2700279549Sbapt } 2701279549Sbapt top->len ++; 2702275223Sbapt } 2703275223Sbapt 2704275223Sbapt return true; 2705275223Sbapt} 2706275223Sbapt 2707263648Sbaptucl_object_t * 2708263648Sbaptucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 2709263648Sbapt{ 2710279549Sbapt UCL_ARRAY_GET (vec, top); 2711279549Sbapt ucl_object_t *ret = NULL; 2712279549Sbapt unsigned i; 2713263648Sbapt 2714290071Sbapt if (vec == NULL) { 2715290071Sbapt return NULL; 2716290071Sbapt } 2717290071Sbapt 2718279549Sbapt for (i = 0; i < vec->n; i ++) { 2719279549Sbapt if (kv_A (*vec, i) == elt) { 2720279549Sbapt kv_del (ucl_object_t *, *vec, i); 2721279549Sbapt ret = elt; 2722279549Sbapt top->len --; 2723279549Sbapt break; 2724263648Sbapt } 2725263648Sbapt } 2726263648Sbapt 2727279549Sbapt return ret; 2728263648Sbapt} 2729263648Sbapt 2730264789Sbaptconst ucl_object_t * 2731264789Sbaptucl_array_head (const ucl_object_t *top) 2732263648Sbapt{ 2733279549Sbapt UCL_ARRAY_GET (vec, top); 2734279549Sbapt 2735290071Sbapt if (vec == NULL || top == NULL || top->type != UCL_ARRAY || 2736290071Sbapt top->value.av == NULL) { 2737263648Sbapt return NULL; 2738263648Sbapt } 2739279549Sbapt 2740279549Sbapt return (vec->n > 0 ? vec->a[0] : NULL); 2741263648Sbapt} 2742263648Sbapt 2743264789Sbaptconst ucl_object_t * 2744264789Sbaptucl_array_tail (const ucl_object_t *top) 2745263648Sbapt{ 2746279549Sbapt UCL_ARRAY_GET (vec, top); 2747279549Sbapt 2748263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 2749263648Sbapt return NULL; 2750263648Sbapt } 2751279549Sbapt 2752279549Sbapt return (vec->n > 0 ? vec->a[vec->n - 1] : NULL); 2753263648Sbapt} 2754263648Sbapt 2755263648Sbaptucl_object_t * 2756263648Sbaptucl_array_pop_last (ucl_object_t *top) 2757263648Sbapt{ 2758279549Sbapt UCL_ARRAY_GET (vec, top); 2759279549Sbapt ucl_object_t **obj, *ret = NULL; 2760279549Sbapt 2761279549Sbapt if (vec != NULL && vec->n > 0) { 2762279549Sbapt obj = &kv_A (*vec, vec->n - 1); 2763279549Sbapt ret = *obj; 2764279549Sbapt kv_del (ucl_object_t *, *vec, vec->n - 1); 2765279549Sbapt top->len --; 2766279549Sbapt } 2767279549Sbapt 2768279549Sbapt return ret; 2769263648Sbapt} 2770263648Sbapt 2771263648Sbaptucl_object_t * 2772263648Sbaptucl_array_pop_first (ucl_object_t *top) 2773263648Sbapt{ 2774279549Sbapt UCL_ARRAY_GET (vec, top); 2775279549Sbapt ucl_object_t **obj, *ret = NULL; 2776279549Sbapt 2777279549Sbapt if (vec != NULL && vec->n > 0) { 2778279549Sbapt obj = &kv_A (*vec, 0); 2779279549Sbapt ret = *obj; 2780279549Sbapt kv_del (ucl_object_t *, *vec, 0); 2781279549Sbapt top->len --; 2782279549Sbapt } 2783279549Sbapt 2784279549Sbapt return ret; 2785263648Sbapt} 2786263648Sbapt 2787266636Sbaptconst ucl_object_t * 2788266636Sbaptucl_array_find_index (const ucl_object_t *top, unsigned int index) 2789266636Sbapt{ 2790279549Sbapt UCL_ARRAY_GET (vec, top); 2791266636Sbapt 2792279549Sbapt if (vec != NULL && vec->n > 0 && index < vec->n) { 2793279549Sbapt return kv_A (*vec, index); 2794266636Sbapt } 2795266636Sbapt 2796266636Sbapt return NULL; 2797266636Sbapt} 2798266636Sbapt 2799290071Sbaptunsigned int 2800290071Sbaptucl_array_index_of (ucl_object_t *top, ucl_object_t *elt) 2801290071Sbapt{ 2802290071Sbapt UCL_ARRAY_GET (vec, top); 2803290071Sbapt unsigned i; 2804290071Sbapt 2805290071Sbapt if (vec == NULL) { 2806290071Sbapt return (unsigned int)(-1); 2807290071Sbapt } 2808290071Sbapt 2809290071Sbapt for (i = 0; i < vec->n; i ++) { 2810290071Sbapt if (kv_A (*vec, i) == elt) { 2811290071Sbapt return i; 2812290071Sbapt } 2813290071Sbapt } 2814290071Sbapt 2815290071Sbapt return (unsigned int)(-1); 2816290071Sbapt} 2817290071Sbapt 2818263648Sbaptucl_object_t * 2819275223Sbaptucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt, 2820275223Sbapt unsigned int index) 2821275223Sbapt{ 2822279549Sbapt UCL_ARRAY_GET (vec, top); 2823279549Sbapt ucl_object_t *ret = NULL; 2824275223Sbapt 2825279549Sbapt if (vec != NULL && vec->n > 0 && index < vec->n) { 2826279549Sbapt ret = kv_A (*vec, index); 2827279549Sbapt kv_A (*vec, index) = elt; 2828275223Sbapt } 2829275223Sbapt 2830279549Sbapt return ret; 2831275223Sbapt} 2832275223Sbapt 2833275223Sbaptucl_object_t * 2834263648Sbaptucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 2835263648Sbapt{ 2836263648Sbapt 2837263648Sbapt if (head == NULL) { 2838263648Sbapt elt->next = NULL; 2839263648Sbapt elt->prev = elt; 2840263648Sbapt head = elt; 2841263648Sbapt } 2842263648Sbapt else { 2843263648Sbapt elt->prev = head->prev; 2844263648Sbapt head->prev->next = elt; 2845263648Sbapt head->prev = elt; 2846263648Sbapt elt->next = NULL; 2847263648Sbapt } 2848263648Sbapt 2849263648Sbapt return head; 2850263648Sbapt} 2851263648Sbapt 2852263648Sbaptbool 2853264789Sbaptucl_object_todouble_safe (const ucl_object_t *obj, double *target) 2854263648Sbapt{ 2855263648Sbapt if (obj == NULL || target == NULL) { 2856263648Sbapt return false; 2857263648Sbapt } 2858263648Sbapt switch (obj->type) { 2859263648Sbapt case UCL_INT: 2860263648Sbapt *target = obj->value.iv; /* Probaly could cause overflow */ 2861263648Sbapt break; 2862263648Sbapt case UCL_FLOAT: 2863263648Sbapt case UCL_TIME: 2864263648Sbapt *target = obj->value.dv; 2865263648Sbapt break; 2866263648Sbapt default: 2867263648Sbapt return false; 2868263648Sbapt } 2869263648Sbapt 2870263648Sbapt return true; 2871263648Sbapt} 2872263648Sbapt 2873263648Sbaptdouble 2874264789Sbaptucl_object_todouble (const ucl_object_t *obj) 2875263648Sbapt{ 2876263648Sbapt double result = 0.; 2877263648Sbapt 2878263648Sbapt ucl_object_todouble_safe (obj, &result); 2879263648Sbapt return result; 2880263648Sbapt} 2881263648Sbapt 2882263648Sbaptbool 2883264789Sbaptucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 2884263648Sbapt{ 2885263648Sbapt if (obj == NULL || target == NULL) { 2886263648Sbapt return false; 2887263648Sbapt } 2888263648Sbapt switch (obj->type) { 2889263648Sbapt case UCL_INT: 2890263648Sbapt *target = obj->value.iv; 2891263648Sbapt break; 2892263648Sbapt case UCL_FLOAT: 2893263648Sbapt case UCL_TIME: 2894263648Sbapt *target = obj->value.dv; /* Loosing of decimal points */ 2895263648Sbapt break; 2896263648Sbapt default: 2897263648Sbapt return false; 2898263648Sbapt } 2899263648Sbapt 2900263648Sbapt return true; 2901263648Sbapt} 2902263648Sbapt 2903263648Sbaptint64_t 2904264789Sbaptucl_object_toint (const ucl_object_t *obj) 2905263648Sbapt{ 2906263648Sbapt int64_t result = 0; 2907263648Sbapt 2908263648Sbapt ucl_object_toint_safe (obj, &result); 2909263648Sbapt return result; 2910263648Sbapt} 2911263648Sbapt 2912263648Sbaptbool 2913264789Sbaptucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 2914263648Sbapt{ 2915263648Sbapt if (obj == NULL || target == NULL) { 2916263648Sbapt return false; 2917263648Sbapt } 2918263648Sbapt switch (obj->type) { 2919263648Sbapt case UCL_BOOLEAN: 2920263648Sbapt *target = (obj->value.iv == true); 2921263648Sbapt break; 2922263648Sbapt default: 2923263648Sbapt return false; 2924263648Sbapt } 2925263648Sbapt 2926263648Sbapt return true; 2927263648Sbapt} 2928263648Sbapt 2929263648Sbaptbool 2930264789Sbaptucl_object_toboolean (const ucl_object_t *obj) 2931263648Sbapt{ 2932263648Sbapt bool result = false; 2933263648Sbapt 2934263648Sbapt ucl_object_toboolean_safe (obj, &result); 2935263648Sbapt return result; 2936263648Sbapt} 2937263648Sbapt 2938263648Sbaptbool 2939264789Sbaptucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 2940263648Sbapt{ 2941263648Sbapt if (obj == NULL || target == NULL) { 2942263648Sbapt return false; 2943263648Sbapt } 2944263648Sbapt 2945263648Sbapt switch (obj->type) { 2946263648Sbapt case UCL_STRING: 2947290071Sbapt if (!(obj->flags & UCL_OBJECT_BINARY)) { 2948290071Sbapt *target = ucl_copy_value_trash (obj); 2949290071Sbapt } 2950263648Sbapt break; 2951263648Sbapt default: 2952263648Sbapt return false; 2953263648Sbapt } 2954263648Sbapt 2955263648Sbapt return true; 2956263648Sbapt} 2957263648Sbapt 2958263648Sbaptconst char * 2959264789Sbaptucl_object_tostring (const ucl_object_t *obj) 2960263648Sbapt{ 2961263648Sbapt const char *result = NULL; 2962263648Sbapt 2963263648Sbapt ucl_object_tostring_safe (obj, &result); 2964263648Sbapt return result; 2965263648Sbapt} 2966263648Sbapt 2967263648Sbaptconst char * 2968264789Sbaptucl_object_tostring_forced (const ucl_object_t *obj) 2969263648Sbapt{ 2970290071Sbapt /* TODO: For binary strings we might encode string here */ 2971290071Sbapt if (!(obj->flags & UCL_OBJECT_BINARY)) { 2972290071Sbapt return ucl_copy_value_trash (obj); 2973290071Sbapt } 2974290071Sbapt 2975290071Sbapt return NULL; 2976263648Sbapt} 2977263648Sbapt 2978263648Sbaptbool 2979264789Sbaptucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 2980263648Sbapt{ 2981263648Sbapt if (obj == NULL || target == NULL) { 2982263648Sbapt return false; 2983263648Sbapt } 2984263648Sbapt switch (obj->type) { 2985263648Sbapt case UCL_STRING: 2986263648Sbapt *target = obj->value.sv; 2987263648Sbapt if (tlen != NULL) { 2988263648Sbapt *tlen = obj->len; 2989263648Sbapt } 2990263648Sbapt break; 2991263648Sbapt default: 2992263648Sbapt return false; 2993263648Sbapt } 2994263648Sbapt 2995263648Sbapt return true; 2996263648Sbapt} 2997263648Sbapt 2998263648Sbaptconst char * 2999264789Sbaptucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 3000263648Sbapt{ 3001263648Sbapt const char *result = NULL; 3002263648Sbapt 3003263648Sbapt ucl_object_tolstring_safe (obj, &result, tlen); 3004263648Sbapt return result; 3005263648Sbapt} 3006263648Sbapt 3007263648Sbaptconst char * 3008264789Sbaptucl_object_key (const ucl_object_t *obj) 3009263648Sbapt{ 3010263648Sbapt return ucl_copy_key_trash (obj); 3011263648Sbapt} 3012263648Sbapt 3013263648Sbaptconst char * 3014264789Sbaptucl_object_keyl (const ucl_object_t *obj, size_t *len) 3015263648Sbapt{ 3016263648Sbapt if (len == NULL || obj == NULL) { 3017263648Sbapt return NULL; 3018263648Sbapt } 3019263648Sbapt *len = obj->keylen; 3020263648Sbapt return obj->key; 3021263648Sbapt} 3022263648Sbapt 3023263648Sbaptucl_object_t * 3024264789Sbaptucl_object_ref (const ucl_object_t *obj) 3025263648Sbapt{ 3026264789Sbapt ucl_object_t *res = NULL; 3027264789Sbapt 3028263648Sbapt if (obj != NULL) { 3029275223Sbapt if (obj->flags & UCL_OBJECT_EPHEMERAL) { 3030275223Sbapt /* 3031275223Sbapt * Use deep copy for ephemeral objects, note that its refcount 3032275223Sbapt * is NOT increased, since ephemeral objects does not need refcount 3033275223Sbapt * at all 3034275223Sbapt */ 3035275223Sbapt res = ucl_object_copy (obj); 3036275223Sbapt } 3037275223Sbapt else { 3038275223Sbapt res = __DECONST (ucl_object_t *, obj); 3039264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 3040275223Sbapt (void)__sync_add_and_fetch (&res->ref, 1); 3041264789Sbapt#else 3042275223Sbapt res->ref ++; 3043264789Sbapt#endif 3044275223Sbapt } 3045263648Sbapt } 3046264789Sbapt return res; 3047263648Sbapt} 3048263648Sbapt 3049275223Sbaptstatic ucl_object_t * 3050275223Sbaptucl_object_copy_internal (const ucl_object_t *other, bool allow_array) 3051275223Sbapt{ 3052275223Sbapt 3053275223Sbapt ucl_object_t *new; 3054275223Sbapt ucl_object_iter_t it = NULL; 3055275223Sbapt const ucl_object_t *cur; 3056275223Sbapt 3057275223Sbapt new = malloc (sizeof (*new)); 3058275223Sbapt 3059275223Sbapt if (new != NULL) { 3060275223Sbapt memcpy (new, other, sizeof (*new)); 3061275223Sbapt if (other->flags & UCL_OBJECT_EPHEMERAL) { 3062275223Sbapt /* Copied object is always non ephemeral */ 3063275223Sbapt new->flags &= ~UCL_OBJECT_EPHEMERAL; 3064275223Sbapt } 3065275223Sbapt new->ref = 1; 3066275223Sbapt /* Unlink from others */ 3067275223Sbapt new->next = NULL; 3068275223Sbapt new->prev = new; 3069275223Sbapt 3070275223Sbapt /* deep copy of values stored */ 3071275223Sbapt if (other->trash_stack[UCL_TRASH_KEY] != NULL) { 3072275223Sbapt new->trash_stack[UCL_TRASH_KEY] = 3073275223Sbapt strdup (other->trash_stack[UCL_TRASH_KEY]); 3074275223Sbapt if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { 3075275223Sbapt new->key = new->trash_stack[UCL_TRASH_KEY]; 3076275223Sbapt } 3077275223Sbapt } 3078275223Sbapt if (other->trash_stack[UCL_TRASH_VALUE] != NULL) { 3079275223Sbapt new->trash_stack[UCL_TRASH_VALUE] = 3080275223Sbapt strdup (other->trash_stack[UCL_TRASH_VALUE]); 3081275223Sbapt if (new->type == UCL_STRING) { 3082275223Sbapt new->value.sv = new->trash_stack[UCL_TRASH_VALUE]; 3083275223Sbapt } 3084275223Sbapt } 3085275223Sbapt 3086275223Sbapt if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) { 3087275223Sbapt /* reset old value */ 3088275223Sbapt memset (&new->value, 0, sizeof (new->value)); 3089275223Sbapt 3090275223Sbapt while ((cur = ucl_iterate_object (other, &it, true)) != NULL) { 3091275223Sbapt if (other->type == UCL_ARRAY) { 3092275223Sbapt ucl_array_append (new, ucl_object_copy_internal (cur, false)); 3093275223Sbapt } 3094275223Sbapt else { 3095275223Sbapt ucl_object_t *cp = ucl_object_copy_internal (cur, true); 3096275223Sbapt if (cp != NULL) { 3097275223Sbapt ucl_object_insert_key (new, cp, cp->key, cp->keylen, 3098275223Sbapt false); 3099275223Sbapt } 3100275223Sbapt } 3101275223Sbapt } 3102275223Sbapt } 3103275223Sbapt else if (allow_array && other->next != NULL) { 3104275223Sbapt LL_FOREACH (other->next, cur) { 3105275223Sbapt ucl_object_t *cp = ucl_object_copy_internal (cur, false); 3106275223Sbapt if (cp != NULL) { 3107275223Sbapt DL_APPEND (new, cp); 3108275223Sbapt } 3109275223Sbapt } 3110275223Sbapt } 3111275223Sbapt } 3112275223Sbapt 3113275223Sbapt return new; 3114275223Sbapt} 3115275223Sbapt 3116275223Sbaptucl_object_t * 3117275223Sbaptucl_object_copy (const ucl_object_t *other) 3118275223Sbapt{ 3119275223Sbapt return ucl_object_copy_internal (other, true); 3120275223Sbapt} 3121275223Sbapt 3122263648Sbaptvoid 3123263648Sbaptucl_object_unref (ucl_object_t *obj) 3124263648Sbapt{ 3125264789Sbapt if (obj != NULL) { 3126264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 3127264789Sbapt unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 3128264789Sbapt if (rc == 0) { 3129264789Sbapt#else 3130264789Sbapt if (--obj->ref == 0) { 3131264789Sbapt#endif 3132264789Sbapt ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 3133264789Sbapt } 3134263648Sbapt } 3135263648Sbapt} 3136263648Sbapt 3137263648Sbaptint 3138264789Sbaptucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 3139263648Sbapt{ 3140264789Sbapt const ucl_object_t *it1, *it2; 3141263648Sbapt ucl_object_iter_t iter = NULL; 3142263648Sbapt int ret = 0; 3143263648Sbapt 3144263648Sbapt if (o1->type != o2->type) { 3145263648Sbapt return (o1->type) - (o2->type); 3146263648Sbapt } 3147263648Sbapt 3148263648Sbapt switch (o1->type) { 3149263648Sbapt case UCL_STRING: 3150279549Sbapt if (o1->len == o2->len && o1->len > 0) { 3151263648Sbapt ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 3152263648Sbapt } 3153263648Sbapt else { 3154263648Sbapt ret = o1->len - o2->len; 3155263648Sbapt } 3156263648Sbapt break; 3157263648Sbapt case UCL_FLOAT: 3158263648Sbapt case UCL_INT: 3159263648Sbapt case UCL_TIME: 3160263648Sbapt ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 3161263648Sbapt break; 3162263648Sbapt case UCL_BOOLEAN: 3163263648Sbapt ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 3164263648Sbapt break; 3165263648Sbapt case UCL_ARRAY: 3166279549Sbapt if (o1->len == o2->len && o1->len > 0) { 3167279549Sbapt UCL_ARRAY_GET (vec1, o1); 3168279549Sbapt UCL_ARRAY_GET (vec2, o2); 3169279549Sbapt unsigned i; 3170279549Sbapt 3171263648Sbapt /* Compare all elements in both arrays */ 3172279549Sbapt for (i = 0; i < vec1->n; i ++) { 3173279549Sbapt it1 = kv_A (*vec1, i); 3174279549Sbapt it2 = kv_A (*vec2, i); 3175279549Sbapt 3176279549Sbapt if (it1 == NULL && it2 != NULL) { 3177279549Sbapt return -1; 3178263648Sbapt } 3179279549Sbapt else if (it2 == NULL && it1 != NULL) { 3180279549Sbapt return 1; 3181279549Sbapt } 3182279549Sbapt else if (it1 != NULL && it2 != NULL) { 3183279549Sbapt ret = ucl_object_compare (it1, it2); 3184279549Sbapt if (ret != 0) { 3185279549Sbapt break; 3186279549Sbapt } 3187279549Sbapt } 3188263648Sbapt } 3189263648Sbapt } 3190263648Sbapt else { 3191263648Sbapt ret = o1->len - o2->len; 3192263648Sbapt } 3193263648Sbapt break; 3194263648Sbapt case UCL_OBJECT: 3195279549Sbapt if (o1->len == o2->len && o1->len > 0) { 3196263648Sbapt while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 3197263648Sbapt it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 3198263648Sbapt if (it2 == NULL) { 3199263648Sbapt ret = 1; 3200263648Sbapt break; 3201263648Sbapt } 3202263648Sbapt ret = ucl_object_compare (it1, it2); 3203263648Sbapt if (ret != 0) { 3204263648Sbapt break; 3205263648Sbapt } 3206263648Sbapt } 3207263648Sbapt } 3208263648Sbapt else { 3209263648Sbapt ret = o1->len - o2->len; 3210263648Sbapt } 3211263648Sbapt break; 3212263648Sbapt default: 3213263648Sbapt ret = 0; 3214263648Sbapt break; 3215263648Sbapt } 3216263648Sbapt 3217263648Sbapt return ret; 3218263648Sbapt} 3219263648Sbapt 3220263648Sbaptvoid 3221263648Sbaptucl_object_array_sort (ucl_object_t *ar, 3222290071Sbapt int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2)) 3223263648Sbapt{ 3224279549Sbapt UCL_ARRAY_GET (vec, ar); 3225279549Sbapt 3226263648Sbapt if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 3227263648Sbapt return; 3228263648Sbapt } 3229263648Sbapt 3230279549Sbapt qsort (vec->a, vec->n, sizeof (ucl_object_t *), 3231279549Sbapt (int (*)(const void *, const void *))cmp); 3232263648Sbapt} 3233275223Sbapt 3234275223Sbapt#define PRIOBITS 4 3235275223Sbapt 3236275223Sbaptunsigned int 3237275223Sbaptucl_object_get_priority (const ucl_object_t *obj) 3238275223Sbapt{ 3239275223Sbapt if (obj == NULL) { 3240275223Sbapt return 0; 3241275223Sbapt } 3242275223Sbapt 3243275223Sbapt return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS)); 3244275223Sbapt} 3245275223Sbapt 3246275223Sbaptvoid 3247275223Sbaptucl_object_set_priority (ucl_object_t *obj, 3248275223Sbapt unsigned int priority) 3249275223Sbapt{ 3250275223Sbapt if (obj != NULL) { 3251275223Sbapt priority &= (0x1 << PRIOBITS) - 1; 3252290071Sbapt priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS); 3253290071Sbapt priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) - 3254290071Sbapt PRIOBITS)) - 1); 3255290071Sbapt obj->flags = priority; 3256275223Sbapt } 3257275223Sbapt} 3258