ucl_util.c revision 301339
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> 30298166Sbapt#include <stdio.h> /* for snprintf */ 31262395Sbapt 32279549Sbapt#ifndef _WIN32 33275223Sbapt#include <glob.h> 34279549Sbapt#endif 35275223Sbapt 36263648Sbapt#ifdef HAVE_LIBGEN_H 37262395Sbapt#include <libgen.h> /* For dirname */ 38263648Sbapt#endif 39262395Sbapt 40279549Sbapttypedef kvec_t(ucl_object_t *) ucl_array_t; 41279549Sbapt 42279549Sbapt#define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \ 43279549Sbapt (ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL) 44279549Sbapt 45262395Sbapt#ifdef HAVE_OPENSSL 46262395Sbapt#include <openssl/err.h> 47262395Sbapt#include <openssl/sha.h> 48262395Sbapt#include <openssl/rsa.h> 49262395Sbapt#include <openssl/ssl.h> 50262395Sbapt#include <openssl/evp.h> 51262395Sbapt#endif 52262395Sbapt 53263648Sbapt#ifdef CURL_FOUND 54298166Sbapt/* Seems to be broken */ 55298166Sbapt#define CURL_DISABLE_TYPECHECK 1 56263648Sbapt#include <curl/curl.h> 57263648Sbapt#endif 58263648Sbapt#ifdef HAVE_FETCH_H 59263648Sbapt#include <fetch.h> 60263648Sbapt#endif 61263648Sbapt 62262975Sbapt#ifdef _WIN32 63262975Sbapt#include <windows.h> 64262975Sbapt 65263648Sbapt#ifndef PROT_READ 66262975Sbapt#define PROT_READ 1 67263648Sbapt#endif 68263648Sbapt#ifndef PROT_WRITE 69262975Sbapt#define PROT_WRITE 2 70263648Sbapt#endif 71263648Sbapt#ifndef PROT_READWRITE 72262975Sbapt#define PROT_READWRITE 3 73263648Sbapt#endif 74263648Sbapt#ifndef MAP_SHARED 75262975Sbapt#define MAP_SHARED 1 76263648Sbapt#endif 77263648Sbapt#ifndef MAP_PRIVATE 78262975Sbapt#define MAP_PRIVATE 2 79263648Sbapt#endif 80263648Sbapt#ifndef MAP_FAILED 81262975Sbapt#define MAP_FAILED ((void *) -1) 82263648Sbapt#endif 83262975Sbapt 84279549Sbapt#ifdef _WIN32 85279549Sbapt#include <limits.h> 86279549Sbapt#define NBBY CHAR_BIT 87279549Sbapt#endif 88279549Sbapt 89263648Sbaptstatic void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 90262975Sbapt{ 91262975Sbapt void *map = NULL; 92262975Sbapt HANDLE handle = INVALID_HANDLE_VALUE; 93262975Sbapt 94262975Sbapt switch (prot) { 95262975Sbapt default: 96262975Sbapt case PROT_READ: 97262975Sbapt { 98262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 99262975Sbapt if (!handle) break; 100262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 101262975Sbapt CloseHandle(handle); 102262975Sbapt break; 103262975Sbapt } 104262975Sbapt case PROT_WRITE: 105262975Sbapt { 106262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 107262975Sbapt if (!handle) break; 108262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 109262975Sbapt CloseHandle(handle); 110262975Sbapt break; 111262975Sbapt } 112262975Sbapt case PROT_READWRITE: 113262975Sbapt { 114262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 115262975Sbapt if (!handle) break; 116262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 117262975Sbapt CloseHandle(handle); 118262975Sbapt break; 119262975Sbapt } 120262975Sbapt } 121262975Sbapt if (map == (void *) NULL) { 122262975Sbapt return (void *) MAP_FAILED; 123262975Sbapt } 124262975Sbapt return (void *) ((char *) map + offset); 125262975Sbapt} 126262975Sbapt 127263648Sbaptstatic int ucl_munmap(void *map,size_t length) 128262975Sbapt{ 129262975Sbapt if (!UnmapViewOfFile(map)) { 130262975Sbapt return(-1); 131262975Sbapt } 132262975Sbapt return(0); 133262975Sbapt} 134262975Sbapt 135263648Sbaptstatic char* ucl_realpath(const char *path, char *resolved_path) { 136262975Sbapt char *p; 137262975Sbapt char tmp[MAX_PATH + 1]; 138262975Sbapt strncpy(tmp, path, sizeof(tmp)-1); 139262975Sbapt p = tmp; 140262975Sbapt while(*p) { 141262975Sbapt if (*p == '/') *p = '\\'; 142262975Sbapt p++; 143262975Sbapt } 144262975Sbapt return _fullpath(resolved_path, tmp, MAX_PATH); 145262975Sbapt} 146263648Sbapt#else 147263648Sbapt#define ucl_mmap mmap 148263648Sbapt#define ucl_munmap munmap 149263648Sbapt#define ucl_realpath realpath 150262975Sbapt#endif 151262975Sbapt 152264789Sbapttypedef void (*ucl_object_dtor) (ucl_object_t *obj); 153264789Sbaptstatic void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 154264789Sbapt ucl_object_dtor dtor); 155264789Sbaptstatic void ucl_object_dtor_unref (ucl_object_t *obj); 156262395Sbapt 157262395Sbaptstatic void 158264789Sbaptucl_object_dtor_free (ucl_object_t *obj) 159262395Sbapt{ 160264789Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 161264789Sbapt UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 162264789Sbapt } 163264789Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 164264789Sbapt UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 165264789Sbapt } 166275223Sbapt /* Do not free ephemeral objects */ 167275223Sbapt if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) { 168275223Sbapt if (obj->type != UCL_USERDATA) { 169275223Sbapt UCL_FREE (sizeof (ucl_object_t), obj); 170275223Sbapt } 171275223Sbapt else { 172275223Sbapt struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj; 173275223Sbapt if (ud->dtor) { 174275223Sbapt ud->dtor (obj->value.ud); 175275223Sbapt } 176275223Sbapt UCL_FREE (sizeof (*ud), obj); 177275223Sbapt } 178275223Sbapt } 179264789Sbapt} 180264789Sbapt 181264789Sbapt/* 182264789Sbapt * This is a helper function that performs exactly the same as 183264789Sbapt * `ucl_object_unref` but it doesn't iterate over elements allowing 184264789Sbapt * to use it for individual elements of arrays and multiple values 185264789Sbapt */ 186264789Sbaptstatic void 187264789Sbaptucl_object_dtor_unref_single (ucl_object_t *obj) 188264789Sbapt{ 189264789Sbapt if (obj != NULL) { 190264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 191264789Sbapt unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 192264789Sbapt if (rc == 0) { 193264789Sbapt#else 194264789Sbapt if (--obj->ref == 0) { 195264789Sbapt#endif 196264789Sbapt ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 197264789Sbapt } 198264789Sbapt } 199264789Sbapt} 200264789Sbapt 201264789Sbaptstatic void 202264789Sbaptucl_object_dtor_unref (ucl_object_t *obj) 203264789Sbapt{ 204264789Sbapt if (obj->ref == 0) { 205264789Sbapt ucl_object_dtor_free (obj); 206264789Sbapt } 207264789Sbapt else { 208264789Sbapt /* This may cause dtor unref being called one more time */ 209264789Sbapt ucl_object_dtor_unref_single (obj); 210264789Sbapt } 211264789Sbapt} 212264789Sbapt 213264789Sbaptstatic void 214264789Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 215264789Sbapt{ 216279549Sbapt ucl_object_t *tmp, *sub; 217262395Sbapt 218262395Sbapt while (obj != NULL) { 219262395Sbapt if (obj->type == UCL_ARRAY) { 220279549Sbapt UCL_ARRAY_GET (vec, obj); 221279549Sbapt unsigned int i; 222279549Sbapt 223279549Sbapt if (vec != NULL) { 224279549Sbapt for (i = 0; i < vec->n; i ++) { 225279549Sbapt sub = kv_A (*vec, i); 226279549Sbapt if (sub != NULL) { 227279549Sbapt tmp = sub; 228279549Sbapt while (sub) { 229279549Sbapt tmp = sub->next; 230279549Sbapt dtor (sub); 231279549Sbapt sub = tmp; 232279549Sbapt } 233279549Sbapt } 234279549Sbapt } 235279549Sbapt kv_destroy (*vec); 236279549Sbapt UCL_FREE (sizeof (*vec), vec); 237262395Sbapt } 238290071Sbapt obj->value.av = NULL; 239262395Sbapt } 240262395Sbapt else if (obj->type == UCL_OBJECT) { 241262395Sbapt if (obj->value.ov != NULL) { 242298166Sbapt ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor); 243262395Sbapt } 244290071Sbapt obj->value.ov = NULL; 245262395Sbapt } 246262395Sbapt tmp = obj->next; 247264789Sbapt dtor (obj); 248262395Sbapt obj = tmp; 249262395Sbapt 250262395Sbapt if (!allow_rec) { 251262395Sbapt break; 252262395Sbapt } 253262395Sbapt } 254262395Sbapt} 255262395Sbapt 256262395Sbaptvoid 257262395Sbaptucl_object_free (ucl_object_t *obj) 258262395Sbapt{ 259264789Sbapt ucl_object_free_internal (obj, true, ucl_object_dtor_free); 260262395Sbapt} 261262395Sbapt 262262395Sbaptsize_t 263262395Sbaptucl_unescape_json_string (char *str, size_t len) 264262395Sbapt{ 265262395Sbapt char *t = str, *h = str; 266262395Sbapt int i, uval; 267262395Sbapt 268263648Sbapt if (len <= 1) { 269263648Sbapt return len; 270263648Sbapt } 271262395Sbapt /* t is target (tortoise), h is source (hare) */ 272262395Sbapt 273262395Sbapt while (len) { 274262395Sbapt if (*h == '\\') { 275262395Sbapt h ++; 276290071Sbapt 277290071Sbapt if (len == 1) { 278290071Sbapt /* 279290071Sbapt * If \ is last, then do not try to go further 280290071Sbapt * Issue: #74 281290071Sbapt */ 282290071Sbapt len --; 283290071Sbapt *t++ = '\\'; 284290071Sbapt continue; 285290071Sbapt } 286290071Sbapt 287262395Sbapt switch (*h) { 288262395Sbapt case 'n': 289262395Sbapt *t++ = '\n'; 290262395Sbapt break; 291262395Sbapt case 'r': 292262395Sbapt *t++ = '\r'; 293262395Sbapt break; 294262395Sbapt case 'b': 295262395Sbapt *t++ = '\b'; 296262395Sbapt break; 297262395Sbapt case 't': 298262395Sbapt *t++ = '\t'; 299262395Sbapt break; 300262395Sbapt case 'f': 301262395Sbapt *t++ = '\f'; 302262395Sbapt break; 303262395Sbapt case '\\': 304262395Sbapt *t++ = '\\'; 305262395Sbapt break; 306262395Sbapt case '"': 307262395Sbapt *t++ = '"'; 308262395Sbapt break; 309262395Sbapt case 'u': 310262395Sbapt /* Unicode escape */ 311262395Sbapt uval = 0; 312298166Sbapt h ++; /* u character */ 313298166Sbapt len --; 314298166Sbapt 315263648Sbapt if (len > 3) { 316263648Sbapt for (i = 0; i < 4; i++) { 317263648Sbapt uval <<= 4; 318263648Sbapt if (isdigit (h[i])) { 319263648Sbapt uval += h[i] - '0'; 320263648Sbapt } 321263648Sbapt else if (h[i] >= 'a' && h[i] <= 'f') { 322263648Sbapt uval += h[i] - 'a' + 10; 323263648Sbapt } 324263648Sbapt else if (h[i] >= 'A' && h[i] <= 'F') { 325263648Sbapt uval += h[i] - 'A' + 10; 326263648Sbapt } 327263648Sbapt else { 328263648Sbapt break; 329263648Sbapt } 330262395Sbapt } 331298166Sbapt 332263648Sbapt /* Encode */ 333263648Sbapt if(uval < 0x80) { 334263648Sbapt t[0] = (char)uval; 335263648Sbapt t ++; 336262395Sbapt } 337263648Sbapt else if(uval < 0x800) { 338263648Sbapt t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 339263648Sbapt t[1] = 0x80 + ((uval & 0x03F)); 340263648Sbapt t += 2; 341262395Sbapt } 342263648Sbapt else if(uval < 0x10000) { 343263648Sbapt t[0] = 0xE0 + ((uval & 0xF000) >> 12); 344263648Sbapt t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 345263648Sbapt t[2] = 0x80 + ((uval & 0x003F)); 346263648Sbapt t += 3; 347263648Sbapt } 348298166Sbapt#if 0 349298166Sbapt /* It's not actually supported now */ 350263648Sbapt else if(uval <= 0x10FFFF) { 351263648Sbapt t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 352263648Sbapt t[1] = 0x80 + ((uval & 0x03F000) >> 12); 353263648Sbapt t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 354263648Sbapt t[3] = 0x80 + ((uval & 0x00003F)); 355263648Sbapt t += 4; 356263648Sbapt } 357298166Sbapt#endif 358263648Sbapt else { 359263648Sbapt *t++ = '?'; 360263648Sbapt } 361298166Sbapt 362298166Sbapt /* Consume 4 characters of source */ 363298166Sbapt h += 4; 364298166Sbapt len -= 4; 365298166Sbapt 366298166Sbapt if (len > 0) { 367298166Sbapt len --; /* for '\' character */ 368298166Sbapt } 369298166Sbapt continue; 370262395Sbapt } 371262395Sbapt else { 372263648Sbapt *t++ = 'u'; 373262395Sbapt } 374262395Sbapt break; 375262395Sbapt default: 376262395Sbapt *t++ = *h; 377262395Sbapt break; 378262395Sbapt } 379262395Sbapt h ++; 380262395Sbapt len --; 381262395Sbapt } 382262395Sbapt else { 383262395Sbapt *t++ = *h++; 384262395Sbapt } 385290071Sbapt 386290071Sbapt if (len > 0) { 387290071Sbapt len --; 388290071Sbapt } 389262395Sbapt } 390262395Sbapt *t = '\0'; 391262395Sbapt 392262395Sbapt return (t - str); 393262395Sbapt} 394262395Sbapt 395264789Sbaptchar * 396264789Sbaptucl_copy_key_trash (const ucl_object_t *obj) 397262395Sbapt{ 398264789Sbapt ucl_object_t *deconst; 399264789Sbapt 400263648Sbapt if (obj == NULL) { 401263648Sbapt return NULL; 402263648Sbapt } 403262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 404264789Sbapt deconst = __DECONST (ucl_object_t *, obj); 405264789Sbapt deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 406264789Sbapt if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 407264789Sbapt memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 408264789Sbapt deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 409262395Sbapt } 410264789Sbapt deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 411264789Sbapt deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 412262395Sbapt } 413262395Sbapt 414262395Sbapt return obj->trash_stack[UCL_TRASH_KEY]; 415262395Sbapt} 416262395Sbapt 417264789Sbaptchar * 418264789Sbaptucl_copy_value_trash (const ucl_object_t *obj) 419262395Sbapt{ 420264789Sbapt ucl_object_t *deconst; 421264789Sbapt 422263648Sbapt if (obj == NULL) { 423263648Sbapt return NULL; 424263648Sbapt } 425262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 426264789Sbapt deconst = __DECONST (ucl_object_t *, obj); 427262395Sbapt if (obj->type == UCL_STRING) { 428264789Sbapt 429262395Sbapt /* Special case for strings */ 430290071Sbapt if (obj->flags & UCL_OBJECT_BINARY) { 431290071Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len); 432290071Sbapt if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 433290071Sbapt memcpy (deconst->trash_stack[UCL_TRASH_VALUE], 434290071Sbapt obj->value.sv, 435290071Sbapt obj->len); 436290071Sbapt deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 437290071Sbapt } 438262395Sbapt } 439290071Sbapt else { 440290071Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 441290071Sbapt if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 442290071Sbapt memcpy (deconst->trash_stack[UCL_TRASH_VALUE], 443290071Sbapt obj->value.sv, 444290071Sbapt obj->len); 445290071Sbapt deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 446290071Sbapt deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 447290071Sbapt } 448290071Sbapt } 449262395Sbapt } 450262395Sbapt else { 451262395Sbapt /* Just emit value in json notation */ 452264789Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 453264789Sbapt deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 454262395Sbapt } 455264789Sbapt deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 456262395Sbapt } 457298166Sbapt 458262395Sbapt return obj->trash_stack[UCL_TRASH_VALUE]; 459262395Sbapt} 460262395Sbapt 461290071Sbaptucl_object_t* 462262395Sbaptucl_parser_get_object (struct ucl_parser *parser) 463262395Sbapt{ 464262395Sbapt if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 465262395Sbapt return ucl_object_ref (parser->top_obj); 466262395Sbapt } 467262395Sbapt 468262395Sbapt return NULL; 469262395Sbapt} 470262395Sbapt 471290071Sbaptvoid 472262395Sbaptucl_parser_free (struct ucl_parser *parser) 473262395Sbapt{ 474262395Sbapt struct ucl_stack *stack, *stmp; 475262395Sbapt struct ucl_macro *macro, *mtmp; 476262395Sbapt struct ucl_chunk *chunk, *ctmp; 477262395Sbapt struct ucl_pubkey *key, *ktmp; 478262395Sbapt struct ucl_variable *var, *vtmp; 479290071Sbapt ucl_object_t *tr, *trtmp; 480262395Sbapt 481263648Sbapt if (parser == NULL) { 482263648Sbapt return; 483263648Sbapt } 484263648Sbapt 485262395Sbapt if (parser->top_obj != NULL) { 486262395Sbapt ucl_object_unref (parser->top_obj); 487262395Sbapt } 488262395Sbapt 489290071Sbapt if (parser->includepaths != NULL) { 490290071Sbapt ucl_object_unref (parser->includepaths); 491290071Sbapt } 492290071Sbapt 493262395Sbapt LL_FOREACH_SAFE (parser->stack, stack, stmp) { 494262395Sbapt free (stack); 495262395Sbapt } 496262395Sbapt HASH_ITER (hh, parser->macroes, macro, mtmp) { 497262395Sbapt free (macro->name); 498262395Sbapt HASH_DEL (parser->macroes, macro); 499262395Sbapt UCL_FREE (sizeof (struct ucl_macro), macro); 500262395Sbapt } 501262395Sbapt LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 502262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 503262395Sbapt } 504262395Sbapt LL_FOREACH_SAFE (parser->keys, key, ktmp) { 505262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), key); 506262395Sbapt } 507262395Sbapt LL_FOREACH_SAFE (parser->variables, var, vtmp) { 508262395Sbapt free (var->value); 509262395Sbapt free (var->var); 510262395Sbapt UCL_FREE (sizeof (struct ucl_variable), var); 511262395Sbapt } 512290071Sbapt LL_FOREACH_SAFE (parser->trash_objs, tr, trtmp) { 513290071Sbapt ucl_object_free_internal (tr, false, ucl_object_dtor_free); 514290071Sbapt } 515262395Sbapt 516262395Sbapt if (parser->err != NULL) { 517275223Sbapt utstring_free (parser->err); 518262395Sbapt } 519262395Sbapt 520275223Sbapt if (parser->cur_file) { 521275223Sbapt free (parser->cur_file); 522275223Sbapt } 523275223Sbapt 524298166Sbapt if (parser->comments) { 525298166Sbapt ucl_object_unref (parser->comments); 526298166Sbapt } 527298166Sbapt 528262395Sbapt UCL_FREE (sizeof (struct ucl_parser), parser); 529262395Sbapt} 530262395Sbapt 531290071Sbaptconst char * 532262395Sbaptucl_parser_get_error(struct ucl_parser *parser) 533262395Sbapt{ 534263648Sbapt if (parser == NULL) { 535263648Sbapt return NULL; 536263648Sbapt } 537263648Sbapt 538290071Sbapt if (parser->err == NULL) { 539262395Sbapt return NULL; 540290071Sbapt } 541262395Sbapt 542290071Sbapt return utstring_body (parser->err); 543262395Sbapt} 544262395Sbapt 545290071Sbaptint 546290071Sbaptucl_parser_get_error_code(struct ucl_parser *parser) 547290071Sbapt{ 548290071Sbapt if (parser == NULL) { 549290071Sbapt return 0; 550290071Sbapt } 551290071Sbapt 552290071Sbapt return parser->err_code; 553290071Sbapt} 554290071Sbapt 555290071Sbaptunsigned 556290071Sbaptucl_parser_get_column(struct ucl_parser *parser) 557290071Sbapt{ 558290071Sbapt if (parser == NULL || parser->chunks == NULL) { 559290071Sbapt return 0; 560290071Sbapt } 561290071Sbapt 562290071Sbapt return parser->chunks->column; 563290071Sbapt} 564290071Sbapt 565290071Sbaptunsigned 566290071Sbaptucl_parser_get_linenum(struct ucl_parser *parser) 567290071Sbapt{ 568290071Sbapt if (parser == NULL || parser->chunks == NULL) { 569290071Sbapt return 0; 570290071Sbapt } 571290071Sbapt 572290071Sbapt return parser->chunks->line; 573290071Sbapt} 574290071Sbapt 575290071Sbaptvoid 576279549Sbaptucl_parser_clear_error(struct ucl_parser *parser) 577279549Sbapt{ 578279549Sbapt if (parser != NULL && parser->err != NULL) { 579279549Sbapt utstring_free(parser->err); 580279549Sbapt parser->err = NULL; 581290071Sbapt parser->err_code = 0; 582279549Sbapt } 583279549Sbapt} 584279549Sbapt 585290071Sbaptbool 586262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 587262395Sbapt{ 588262395Sbapt#ifndef HAVE_OPENSSL 589262395Sbapt ucl_create_err (&parser->err, "cannot check signatures without openssl"); 590262395Sbapt return false; 591262395Sbapt#else 592262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 593262395Sbapt ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 594262395Sbapt return EXIT_FAILURE; 595262395Sbapt# else 596262395Sbapt struct ucl_pubkey *nkey; 597262395Sbapt BIO *mem; 598262395Sbapt 599262395Sbapt mem = BIO_new_mem_buf ((void *)key, len); 600262395Sbapt nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 601263648Sbapt if (nkey == NULL) { 602263648Sbapt ucl_create_err (&parser->err, "cannot allocate memory for key"); 603263648Sbapt return false; 604263648Sbapt } 605262395Sbapt nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 606262395Sbapt BIO_free (mem); 607262395Sbapt if (nkey->key == NULL) { 608262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), nkey); 609262395Sbapt ucl_create_err (&parser->err, "%s", 610262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 611262395Sbapt return false; 612262395Sbapt } 613262395Sbapt LL_PREPEND (parser->keys, nkey); 614262395Sbapt# endif 615262395Sbapt#endif 616262395Sbapt return true; 617262395Sbapt} 618262395Sbapt 619262395Sbapt#ifdef CURL_FOUND 620262395Sbaptstruct ucl_curl_cbdata { 621262395Sbapt unsigned char *buf; 622262395Sbapt size_t buflen; 623262395Sbapt}; 624262395Sbapt 625262395Sbaptstatic size_t 626262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 627262395Sbapt{ 628262395Sbapt struct ucl_curl_cbdata *cbdata = ud; 629262395Sbapt size_t realsize = size * nmemb; 630262395Sbapt 631262395Sbapt cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 632262395Sbapt if (cbdata->buf == NULL) { 633262395Sbapt return 0; 634262395Sbapt } 635262395Sbapt 636262395Sbapt memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 637262395Sbapt cbdata->buflen += realsize; 638262395Sbapt cbdata->buf[cbdata->buflen] = 0; 639262395Sbapt 640262395Sbapt return realsize; 641262395Sbapt} 642262395Sbapt#endif 643262395Sbapt 644262395Sbapt/** 645262395Sbapt * Fetch a url and save results to the memory buffer 646262395Sbapt * @param url url to fetch 647262395Sbapt * @param len length of url 648262395Sbapt * @param buf target buffer 649262395Sbapt * @param buflen target length 650262395Sbapt * @return 651262395Sbapt */ 652298166Sbaptbool 653262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 654262395Sbapt UT_string **err, bool must_exist) 655262395Sbapt{ 656262395Sbapt 657262395Sbapt#ifdef HAVE_FETCH_H 658262395Sbapt struct url *fetch_url; 659262395Sbapt struct url_stat us; 660262395Sbapt FILE *in; 661262395Sbapt 662262395Sbapt fetch_url = fetchParseURL (url); 663262395Sbapt if (fetch_url == NULL) { 664262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 665262395Sbapt url, strerror (errno)); 666262395Sbapt return false; 667262395Sbapt } 668262395Sbapt if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 669262395Sbapt if (!must_exist) { 670262395Sbapt ucl_create_err (err, "cannot fetch URL %s: %s", 671262395Sbapt url, strerror (errno)); 672262395Sbapt } 673262395Sbapt fetchFreeURL (fetch_url); 674262395Sbapt return false; 675262395Sbapt } 676262395Sbapt 677262395Sbapt *buflen = us.size; 678262395Sbapt *buf = malloc (*buflen); 679262395Sbapt if (*buf == NULL) { 680262395Sbapt ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 681262395Sbapt url, strerror (errno)); 682262395Sbapt fclose (in); 683262395Sbapt fetchFreeURL (fetch_url); 684262395Sbapt return false; 685262395Sbapt } 686262395Sbapt 687262395Sbapt if (fread (*buf, *buflen, 1, in) != 1) { 688262395Sbapt ucl_create_err (err, "cannot read URL %s: %s", 689262395Sbapt url, strerror (errno)); 690262395Sbapt fclose (in); 691262395Sbapt fetchFreeURL (fetch_url); 692262395Sbapt return false; 693262395Sbapt } 694262395Sbapt 695262395Sbapt fetchFreeURL (fetch_url); 696262395Sbapt return true; 697262395Sbapt#elif defined(CURL_FOUND) 698262395Sbapt CURL *curl; 699262395Sbapt int r; 700262395Sbapt struct ucl_curl_cbdata cbdata; 701262395Sbapt 702262395Sbapt curl = curl_easy_init (); 703262395Sbapt if (curl == NULL) { 704262395Sbapt ucl_create_err (err, "CURL interface is broken"); 705262395Sbapt return false; 706262395Sbapt } 707262395Sbapt if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 708262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 709262395Sbapt url, curl_easy_strerror (r)); 710262395Sbapt curl_easy_cleanup (curl); 711262395Sbapt return false; 712262395Sbapt } 713262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 714298166Sbapt cbdata.buf = NULL; 715298166Sbapt cbdata.buflen = 0; 716262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 717262395Sbapt 718262395Sbapt if ((r = curl_easy_perform (curl)) != CURLE_OK) { 719262395Sbapt if (!must_exist) { 720262395Sbapt ucl_create_err (err, "error fetching URL %s: %s", 721262395Sbapt url, curl_easy_strerror (r)); 722262395Sbapt } 723262395Sbapt curl_easy_cleanup (curl); 724262395Sbapt if (cbdata.buf) { 725262395Sbapt free (cbdata.buf); 726262395Sbapt } 727262395Sbapt return false; 728262395Sbapt } 729262395Sbapt *buf = cbdata.buf; 730262395Sbapt *buflen = cbdata.buflen; 731262395Sbapt 732262395Sbapt return true; 733262395Sbapt#else 734262395Sbapt ucl_create_err (err, "URL support is disabled"); 735262395Sbapt return false; 736262395Sbapt#endif 737262395Sbapt} 738262395Sbapt 739262395Sbapt/** 740262395Sbapt * Fetch a file and save results to the memory buffer 741262395Sbapt * @param filename filename to fetch 742262395Sbapt * @param len length of filename 743262395Sbapt * @param buf target buffer 744262395Sbapt * @param buflen target length 745262395Sbapt * @return 746262395Sbapt */ 747298166Sbaptbool 748262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 749262395Sbapt UT_string **err, bool must_exist) 750262395Sbapt{ 751262395Sbapt int fd; 752262395Sbapt struct stat st; 753262395Sbapt 754262395Sbapt if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 755262395Sbapt if (must_exist) { 756262395Sbapt ucl_create_err (err, "cannot stat file %s: %s", 757262395Sbapt filename, strerror (errno)); 758262395Sbapt } 759262395Sbapt return false; 760262395Sbapt } 761262395Sbapt if (st.st_size == 0) { 762262395Sbapt /* Do not map empty files */ 763298166Sbapt *buf = NULL; 764262395Sbapt *buflen = 0; 765262395Sbapt } 766262395Sbapt else { 767262395Sbapt if ((fd = open (filename, O_RDONLY)) == -1) { 768262395Sbapt ucl_create_err (err, "cannot open file %s: %s", 769262395Sbapt filename, strerror (errno)); 770262395Sbapt return false; 771262395Sbapt } 772263648Sbapt if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 773262395Sbapt close (fd); 774262395Sbapt ucl_create_err (err, "cannot mmap file %s: %s", 775262395Sbapt filename, strerror (errno)); 776298166Sbapt *buf = NULL; 777298166Sbapt 778262395Sbapt return false; 779262395Sbapt } 780262395Sbapt *buflen = st.st_size; 781262395Sbapt close (fd); 782262395Sbapt } 783262395Sbapt 784262395Sbapt return true; 785262395Sbapt} 786262395Sbapt 787262395Sbapt 788262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 789262395Sbaptstatic inline bool 790262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen, 791262395Sbapt const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 792262395Sbapt{ 793262395Sbapt struct ucl_pubkey *key; 794262395Sbapt char dig[EVP_MAX_MD_SIZE]; 795262395Sbapt unsigned int diglen; 796262395Sbapt EVP_PKEY_CTX *key_ctx; 797262395Sbapt EVP_MD_CTX *sign_ctx = NULL; 798262395Sbapt 799262395Sbapt sign_ctx = EVP_MD_CTX_create (); 800262395Sbapt 801262395Sbapt LL_FOREACH (parser->keys, key) { 802262395Sbapt key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 803262395Sbapt if (key_ctx != NULL) { 804262395Sbapt if (EVP_PKEY_verify_init (key_ctx) <= 0) { 805262395Sbapt EVP_PKEY_CTX_free (key_ctx); 806262395Sbapt continue; 807262395Sbapt } 808262395Sbapt if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 809262395Sbapt EVP_PKEY_CTX_free (key_ctx); 810262395Sbapt continue; 811262395Sbapt } 812262395Sbapt if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 813262395Sbapt EVP_PKEY_CTX_free (key_ctx); 814262395Sbapt continue; 815262395Sbapt } 816262395Sbapt EVP_DigestInit (sign_ctx, EVP_sha256 ()); 817262395Sbapt EVP_DigestUpdate (sign_ctx, data, datalen); 818262395Sbapt EVP_DigestFinal (sign_ctx, dig, &diglen); 819262395Sbapt 820262395Sbapt if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 821262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 822262395Sbapt EVP_PKEY_CTX_free (key_ctx); 823262395Sbapt return true; 824262395Sbapt } 825262395Sbapt 826262395Sbapt EVP_PKEY_CTX_free (key_ctx); 827262395Sbapt } 828262395Sbapt } 829262395Sbapt 830262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 831262395Sbapt 832262395Sbapt return false; 833262395Sbapt} 834262395Sbapt#endif 835262395Sbapt 836290071Sbaptstruct ucl_include_params { 837290071Sbapt bool check_signature; 838290071Sbapt bool must_exist; 839290071Sbapt bool use_glob; 840290071Sbapt bool use_prefix; 841290071Sbapt bool soft_fail; 842290071Sbapt bool allow_glob; 843290071Sbapt unsigned priority; 844290071Sbapt enum ucl_duplicate_strategy strat; 845290071Sbapt enum ucl_parse_type parse_type; 846290071Sbapt const char *prefix; 847290071Sbapt const char *target; 848290071Sbapt}; 849290071Sbapt 850262395Sbapt/** 851262395Sbapt * Include an url to configuration 852262395Sbapt * @param data 853262395Sbapt * @param len 854262395Sbapt * @param parser 855262395Sbapt * @param err 856262395Sbapt * @return 857262395Sbapt */ 858262395Sbaptstatic bool 859262395Sbaptucl_include_url (const unsigned char *data, size_t len, 860290071Sbapt struct ucl_parser *parser, 861290071Sbapt struct ucl_include_params *params) 862262395Sbapt{ 863262395Sbapt 864262395Sbapt bool res; 865262395Sbapt unsigned char *buf = NULL; 866262395Sbapt size_t buflen = 0; 867262395Sbapt struct ucl_chunk *chunk; 868262395Sbapt char urlbuf[PATH_MAX]; 869262395Sbapt int prev_state; 870262395Sbapt 871262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 872262395Sbapt 873290071Sbapt if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) { 874298166Sbapt return !params->must_exist; 875262395Sbapt } 876262395Sbapt 877290071Sbapt if (params->check_signature) { 878262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 879262395Sbapt unsigned char *sigbuf = NULL; 880262395Sbapt size_t siglen = 0; 881262395Sbapt /* We need to check signature first */ 882262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 883262395Sbapt if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 884262395Sbapt return false; 885262395Sbapt } 886262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 887262395Sbapt ucl_create_err (&parser->err, "cannot verify url %s: %s", 888262395Sbapt urlbuf, 889262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 890262395Sbapt if (siglen > 0) { 891263648Sbapt ucl_munmap (sigbuf, siglen); 892262395Sbapt } 893262395Sbapt return false; 894262395Sbapt } 895262395Sbapt if (siglen > 0) { 896263648Sbapt ucl_munmap (sigbuf, siglen); 897262395Sbapt } 898262395Sbapt#endif 899262395Sbapt } 900262395Sbapt 901262395Sbapt prev_state = parser->state; 902262395Sbapt parser->state = UCL_STATE_INIT; 903262395Sbapt 904290071Sbapt res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, 905290071Sbapt params->strat, params->parse_type); 906262395Sbapt if (res == true) { 907262395Sbapt /* Remove chunk from the stack */ 908262395Sbapt chunk = parser->chunks; 909262395Sbapt if (chunk != NULL) { 910262395Sbapt parser->chunks = chunk->next; 911262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 912262395Sbapt } 913262395Sbapt } 914262395Sbapt 915262395Sbapt parser->state = prev_state; 916262395Sbapt free (buf); 917262395Sbapt 918262395Sbapt return res; 919262395Sbapt} 920262395Sbapt 921262395Sbapt/** 922275223Sbapt * Include a single file to the parser 923262395Sbapt * @param data 924262395Sbapt * @param len 925262395Sbapt * @param parser 926275223Sbapt * @param check_signature 927275223Sbapt * @param must_exist 928275223Sbapt * @param allow_glob 929275223Sbapt * @param priority 930262395Sbapt * @return 931262395Sbapt */ 932262395Sbaptstatic bool 933275223Sbaptucl_include_file_single (const unsigned char *data, size_t len, 934290071Sbapt struct ucl_parser *parser, struct ucl_include_params *params) 935262395Sbapt{ 936262395Sbapt bool res; 937262395Sbapt struct ucl_chunk *chunk; 938262395Sbapt unsigned char *buf = NULL; 939290071Sbapt char *old_curfile, *ext; 940290071Sbapt size_t buflen = 0; 941262395Sbapt char filebuf[PATH_MAX], realbuf[PATH_MAX]; 942262395Sbapt int prev_state; 943275223Sbapt struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL, 944275223Sbapt *old_filename = NULL; 945290071Sbapt ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL; 946290071Sbapt ucl_hash_t *container = NULL; 947290071Sbapt struct ucl_stack *st = NULL; 948262395Sbapt 949262395Sbapt snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 950263648Sbapt if (ucl_realpath (filebuf, realbuf) == NULL) { 951290071Sbapt if (params->soft_fail) { 952290071Sbapt return false; 953290071Sbapt } 954290071Sbapt if (!params->must_exist) { 955262395Sbapt return true; 956262395Sbapt } 957262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 958262395Sbapt filebuf, 959262395Sbapt strerror (errno)); 960262395Sbapt return false; 961262395Sbapt } 962262395Sbapt 963275223Sbapt if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) { 964275223Sbapt /* We are likely including the file itself */ 965290071Sbapt if (params->soft_fail) { 966290071Sbapt return false; 967290071Sbapt } 968290071Sbapt 969275223Sbapt ucl_create_err (&parser->err, "trying to include the file %s from itself", 970275223Sbapt realbuf); 971275223Sbapt return false; 972275223Sbapt } 973275223Sbapt 974290071Sbapt if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, params->must_exist)) { 975290071Sbapt if (params->soft_fail) { 976290071Sbapt return false; 977290071Sbapt } 978301339Sbapt 979290071Sbapt return (!params->must_exist || false); 980262395Sbapt } 981262395Sbapt 982290071Sbapt if (params->check_signature) { 983262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 984262395Sbapt unsigned char *sigbuf = NULL; 985262395Sbapt size_t siglen = 0; 986262395Sbapt /* We need to check signature first */ 987262395Sbapt snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 988262395Sbapt if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 989262395Sbapt return false; 990262395Sbapt } 991262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 992262395Sbapt ucl_create_err (&parser->err, "cannot verify file %s: %s", 993262395Sbapt filebuf, 994262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 995298166Sbapt if (sigbuf) { 996263648Sbapt ucl_munmap (sigbuf, siglen); 997262395Sbapt } 998262395Sbapt return false; 999262395Sbapt } 1000298166Sbapt if (sigbuf) { 1001263648Sbapt ucl_munmap (sigbuf, siglen); 1002262395Sbapt } 1003262395Sbapt#endif 1004262395Sbapt } 1005262395Sbapt 1006275223Sbapt old_curfile = parser->cur_file; 1007275223Sbapt parser->cur_file = strdup (realbuf); 1008275223Sbapt 1009275223Sbapt /* Store old file vars */ 1010275223Sbapt DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 1011275223Sbapt if (strcmp (cur_var->var, "CURDIR") == 0) { 1012275223Sbapt old_curdir = cur_var; 1013275223Sbapt DL_DELETE (parser->variables, cur_var); 1014275223Sbapt } 1015275223Sbapt else if (strcmp (cur_var->var, "FILENAME") == 0) { 1016275223Sbapt old_filename = cur_var; 1017275223Sbapt DL_DELETE (parser->variables, cur_var); 1018275223Sbapt } 1019275223Sbapt } 1020275223Sbapt 1021262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 1022262395Sbapt 1023262395Sbapt prev_state = parser->state; 1024262395Sbapt parser->state = UCL_STATE_INIT; 1025262395Sbapt 1026290071Sbapt if (params->use_prefix && params->prefix == NULL) { 1027290071Sbapt /* Auto generate a key name based on the included filename */ 1028290071Sbapt params->prefix = basename (realbuf); 1029290071Sbapt ext = strrchr (params->prefix, '.'); 1030290071Sbapt if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) { 1031290071Sbapt /* Strip off .conf or .ucl */ 1032290071Sbapt *ext = '\0'; 1033290071Sbapt } 1034290071Sbapt } 1035290071Sbapt if (params->prefix != NULL) { 1036290071Sbapt /* This is a prefixed include */ 1037290071Sbapt container = parser->stack->obj->value.ov; 1038290071Sbapt 1039290071Sbapt old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, 1040290071Sbapt params->prefix, strlen (params->prefix))); 1041290071Sbapt 1042290071Sbapt if (strcasecmp (params->target, "array") == 0 && old_obj == NULL) { 1043290071Sbapt /* Create an array with key: prefix */ 1044290071Sbapt old_obj = ucl_object_new_full (UCL_ARRAY, params->priority); 1045290071Sbapt old_obj->key = params->prefix; 1046290071Sbapt old_obj->keylen = strlen (params->prefix); 1047290071Sbapt ucl_copy_key_trash(old_obj); 1048290071Sbapt old_obj->prev = old_obj; 1049290071Sbapt old_obj->next = NULL; 1050290071Sbapt 1051290071Sbapt container = ucl_hash_insert_object (container, old_obj, 1052290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1053290071Sbapt parser->stack->obj->len ++; 1054290071Sbapt 1055290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1056290071Sbapt nest_obj->prev = nest_obj; 1057290071Sbapt nest_obj->next = NULL; 1058290071Sbapt 1059290071Sbapt ucl_array_append (old_obj, nest_obj); 1060290071Sbapt } 1061290071Sbapt else if (old_obj == NULL) { 1062290071Sbapt /* Create an object with key: prefix */ 1063290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1064298166Sbapt 1065298166Sbapt if (nest_obj == NULL) { 1066298166Sbapt ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1067298166Sbapt if (buf) { 1068298166Sbapt ucl_munmap (buf, buflen); 1069298166Sbapt } 1070298166Sbapt 1071298166Sbapt return false; 1072298166Sbapt } 1073298166Sbapt 1074290071Sbapt nest_obj->key = params->prefix; 1075290071Sbapt nest_obj->keylen = strlen (params->prefix); 1076290071Sbapt ucl_copy_key_trash(nest_obj); 1077290071Sbapt nest_obj->prev = nest_obj; 1078290071Sbapt nest_obj->next = NULL; 1079290071Sbapt 1080290071Sbapt container = ucl_hash_insert_object (container, nest_obj, 1081290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1082290071Sbapt parser->stack->obj->len ++; 1083290071Sbapt } 1084290071Sbapt else if (strcasecmp (params->target, "array") == 0 || 1085290071Sbapt ucl_object_type(old_obj) == UCL_ARRAY) { 1086290071Sbapt if (ucl_object_type(old_obj) == UCL_ARRAY) { 1087290071Sbapt /* Append to the existing array */ 1088290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1089298166Sbapt if (nest_obj == NULL) { 1090298166Sbapt ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1091298166Sbapt if (buf) { 1092298166Sbapt ucl_munmap (buf, buflen); 1093298166Sbapt } 1094298166Sbapt 1095298166Sbapt return false; 1096298166Sbapt } 1097290071Sbapt nest_obj->prev = nest_obj; 1098290071Sbapt nest_obj->next = NULL; 1099290071Sbapt 1100290071Sbapt ucl_array_append (old_obj, nest_obj); 1101290071Sbapt } 1102290071Sbapt else { 1103290071Sbapt /* Convert the object to an array */ 1104290071Sbapt new_obj = ucl_object_typed_new (UCL_ARRAY); 1105298166Sbapt if (new_obj == NULL) { 1106298166Sbapt ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1107298166Sbapt if (buf) { 1108298166Sbapt ucl_munmap (buf, buflen); 1109298166Sbapt } 1110298166Sbapt 1111298166Sbapt return false; 1112298166Sbapt } 1113290071Sbapt new_obj->key = old_obj->key; 1114290071Sbapt new_obj->keylen = old_obj->keylen; 1115290071Sbapt new_obj->flags |= UCL_OBJECT_MULTIVALUE; 1116290071Sbapt new_obj->prev = new_obj; 1117290071Sbapt new_obj->next = NULL; 1118290071Sbapt 1119290071Sbapt nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority); 1120298166Sbapt if (nest_obj == NULL) { 1121298166Sbapt ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1122298166Sbapt if (buf) { 1123298166Sbapt ucl_munmap (buf, buflen); 1124298166Sbapt } 1125298166Sbapt 1126298166Sbapt return false; 1127298166Sbapt } 1128290071Sbapt nest_obj->prev = nest_obj; 1129290071Sbapt nest_obj->next = NULL; 1130290071Sbapt 1131290071Sbapt ucl_array_append (new_obj, old_obj); 1132290071Sbapt ucl_array_append (new_obj, nest_obj); 1133290071Sbapt ucl_hash_replace (container, old_obj, new_obj); 1134290071Sbapt } 1135290071Sbapt } 1136290071Sbapt else { 1137290071Sbapt if (ucl_object_type (old_obj) == UCL_OBJECT) { 1138290071Sbapt /* Append to existing Object*/ 1139290071Sbapt nest_obj = old_obj; 1140290071Sbapt } 1141290071Sbapt else { 1142290071Sbapt /* The key is not an object */ 1143290071Sbapt ucl_create_err (&parser->err, 1144290071Sbapt "Conflicting type for key: %s", 1145290071Sbapt params->prefix); 1146298166Sbapt if (buf) { 1147298166Sbapt ucl_munmap (buf, buflen); 1148298166Sbapt } 1149298166Sbapt 1150290071Sbapt return false; 1151290071Sbapt } 1152290071Sbapt } 1153290071Sbapt 1154290071Sbapt /* Put all of the content of the include inside that object */ 1155290071Sbapt parser->stack->obj->value.ov = container; 1156290071Sbapt 1157298166Sbapt st = UCL_ALLOC (sizeof (struct ucl_stack)); 1158298166Sbapt if (st == NULL) { 1159298166Sbapt ucl_create_err (&parser->err, "cannot allocate memory for an object"); 1160298166Sbapt ucl_object_unref (nest_obj); 1161298166Sbapt 1162298166Sbapt if (buf) { 1163298166Sbapt ucl_munmap (buf, buflen); 1164290071Sbapt } 1165298166Sbapt 1166298166Sbapt return false; 1167290071Sbapt } 1168298166Sbapt st->obj = nest_obj; 1169298166Sbapt st->level = parser->stack->level; 1170298166Sbapt LL_PREPEND (parser->stack, st); 1171298166Sbapt parser->cur_obj = nest_obj; 1172290071Sbapt } 1173290071Sbapt 1174290071Sbapt res = ucl_parser_add_chunk_full (parser, buf, buflen, params->priority, 1175290071Sbapt params->strat, params->parse_type); 1176301339Sbapt 1177301339Sbapt if (!res) { 1178301339Sbapt if (!params->must_exist) { 1179301339Sbapt /* Free error */ 1180301339Sbapt utstring_free (parser->err); 1181301339Sbapt parser->err = NULL; 1182301339Sbapt res = true; 1183301339Sbapt } 1184275223Sbapt } 1185275223Sbapt 1186290071Sbapt /* Stop nesting the include, take 1 level off the stack */ 1187290071Sbapt if (params->prefix != NULL && nest_obj != NULL) { 1188290071Sbapt parser->stack = st->next; 1189290071Sbapt UCL_FREE (sizeof (struct ucl_stack), st); 1190290071Sbapt } 1191290071Sbapt 1192275223Sbapt /* Remove chunk from the stack */ 1193275223Sbapt chunk = parser->chunks; 1194275223Sbapt if (chunk != NULL) { 1195275223Sbapt parser->chunks = chunk->next; 1196275223Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 1197275223Sbapt parser->recursion --; 1198275223Sbapt } 1199275223Sbapt 1200275223Sbapt /* Restore old file vars */ 1201290071Sbapt if (parser->cur_file) { 1202290071Sbapt free (parser->cur_file); 1203290071Sbapt } 1204290071Sbapt 1205275223Sbapt parser->cur_file = old_curfile; 1206275223Sbapt DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 1207275223Sbapt if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) { 1208275223Sbapt DL_DELETE (parser->variables, cur_var); 1209275223Sbapt free (cur_var->var); 1210275223Sbapt free (cur_var->value); 1211275223Sbapt UCL_FREE (sizeof (struct ucl_variable), cur_var); 1212262395Sbapt } 1213275223Sbapt else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) { 1214275223Sbapt DL_DELETE (parser->variables, cur_var); 1215275223Sbapt free (cur_var->var); 1216275223Sbapt free (cur_var->value); 1217275223Sbapt UCL_FREE (sizeof (struct ucl_variable), cur_var); 1218275223Sbapt } 1219262395Sbapt } 1220275223Sbapt if (old_filename) { 1221275223Sbapt DL_APPEND (parser->variables, old_filename); 1222275223Sbapt } 1223275223Sbapt if (old_curdir) { 1224275223Sbapt DL_APPEND (parser->variables, old_curdir); 1225275223Sbapt } 1226262395Sbapt 1227262395Sbapt parser->state = prev_state; 1228262395Sbapt 1229262395Sbapt if (buflen > 0) { 1230263648Sbapt ucl_munmap (buf, buflen); 1231262395Sbapt } 1232262395Sbapt 1233262395Sbapt return res; 1234262395Sbapt} 1235262395Sbapt 1236262395Sbapt/** 1237275223Sbapt * Include a file to configuration 1238275223Sbapt * @param data 1239275223Sbapt * @param len 1240275223Sbapt * @param parser 1241275223Sbapt * @param err 1242275223Sbapt * @return 1243275223Sbapt */ 1244275223Sbaptstatic bool 1245275223Sbaptucl_include_file (const unsigned char *data, size_t len, 1246290071Sbapt struct ucl_parser *parser, struct ucl_include_params *params) 1247275223Sbapt{ 1248275223Sbapt const unsigned char *p = data, *end = data + len; 1249275223Sbapt bool need_glob = false; 1250275223Sbapt int cnt = 0; 1251275223Sbapt char glob_pattern[PATH_MAX]; 1252275223Sbapt size_t i; 1253275223Sbapt 1254279549Sbapt#ifndef _WIN32 1255290071Sbapt if (!params->allow_glob) { 1256290071Sbapt return ucl_include_file_single (data, len, parser, params); 1257275223Sbapt } 1258275223Sbapt else { 1259275223Sbapt /* Check for special symbols in a filename */ 1260275223Sbapt while (p != end) { 1261275223Sbapt if (*p == '*' || *p == '?') { 1262275223Sbapt need_glob = true; 1263275223Sbapt break; 1264275223Sbapt } 1265275223Sbapt p ++; 1266275223Sbapt } 1267275223Sbapt if (need_glob) { 1268279549Sbapt glob_t globbuf; 1269275223Sbapt memset (&globbuf, 0, sizeof (globbuf)); 1270290071Sbapt ucl_strlcpy (glob_pattern, (const char *)data, 1271290071Sbapt (len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern))); 1272275223Sbapt if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { 1273290071Sbapt return (!params->must_exist || false); 1274275223Sbapt } 1275275223Sbapt for (i = 0; i < globbuf.gl_pathc; i ++) { 1276275223Sbapt if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i], 1277290071Sbapt strlen (globbuf.gl_pathv[i]), parser, params)) { 1278290071Sbapt if (params->soft_fail) { 1279290071Sbapt continue; 1280290071Sbapt } 1281275223Sbapt globfree (&globbuf); 1282275223Sbapt return false; 1283275223Sbapt } 1284275223Sbapt cnt ++; 1285275223Sbapt } 1286275223Sbapt globfree (&globbuf); 1287275223Sbapt 1288290071Sbapt if (cnt == 0 && params->must_exist) { 1289275223Sbapt ucl_create_err (&parser->err, "cannot match any files for pattern %s", 1290275223Sbapt glob_pattern); 1291275223Sbapt return false; 1292275223Sbapt } 1293275223Sbapt } 1294275223Sbapt else { 1295290071Sbapt return ucl_include_file_single (data, len, parser, params); 1296275223Sbapt } 1297275223Sbapt } 1298279549Sbapt#else 1299279549Sbapt /* Win32 compilers do not support globbing. Therefore, for Win32, 1300279549Sbapt treat allow_glob/need_glob as a NOOP and just return */ 1301290071Sbapt return ucl_include_file_single (data, len, parser, params); 1302279549Sbapt#endif 1303298166Sbapt 1304275223Sbapt return true; 1305275223Sbapt} 1306275223Sbapt 1307275223Sbapt/** 1308275223Sbapt * Common function to handle .*include* macros 1309275223Sbapt * @param data 1310275223Sbapt * @param len 1311275223Sbapt * @param args 1312275223Sbapt * @param parser 1313275223Sbapt * @param default_try 1314275223Sbapt * @param default_sign 1315275223Sbapt * @return 1316275223Sbapt */ 1317275223Sbaptstatic bool 1318275223Sbaptucl_include_common (const unsigned char *data, size_t len, 1319275223Sbapt const ucl_object_t *args, struct ucl_parser *parser, 1320275223Sbapt bool default_try, 1321275223Sbapt bool default_sign) 1322275223Sbapt{ 1323298166Sbapt bool allow_url = false, search = false; 1324290071Sbapt const char *duplicate; 1325275223Sbapt const ucl_object_t *param; 1326290071Sbapt ucl_object_iter_t it = NULL, ip = NULL; 1327290071Sbapt char ipath[PATH_MAX]; 1328290071Sbapt struct ucl_include_params params; 1329275223Sbapt 1330275223Sbapt /* Default values */ 1331290071Sbapt params.soft_fail = default_try; 1332290071Sbapt params.allow_glob = false; 1333290071Sbapt params.check_signature = default_sign; 1334290071Sbapt params.use_prefix = false; 1335290071Sbapt params.target = "object"; 1336290071Sbapt params.prefix = NULL; 1337290071Sbapt params.priority = 0; 1338290071Sbapt params.parse_type = UCL_PARSE_UCL; 1339290071Sbapt params.strat = UCL_DUPLICATE_APPEND; 1340290071Sbapt params.must_exist = !default_try; 1341275223Sbapt 1342275223Sbapt /* Process arguments */ 1343275223Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1344298166Sbapt while ((param = ucl_object_iterate (args, &it, true)) != NULL) { 1345275223Sbapt if (param->type == UCL_BOOLEAN) { 1346290071Sbapt if (strncmp (param->key, "try", param->keylen) == 0) { 1347290071Sbapt params.must_exist = !ucl_object_toboolean (param); 1348275223Sbapt } 1349290071Sbapt else if (strncmp (param->key, "sign", param->keylen) == 0) { 1350290071Sbapt params.check_signature = ucl_object_toboolean (param); 1351275223Sbapt } 1352290071Sbapt else if (strncmp (param->key, "glob", param->keylen) == 0) { 1353290071Sbapt params.allow_glob = ucl_object_toboolean (param); 1354275223Sbapt } 1355290071Sbapt else if (strncmp (param->key, "url", param->keylen) == 0) { 1356290071Sbapt allow_url = ucl_object_toboolean (param); 1357275223Sbapt } 1358290071Sbapt else if (strncmp (param->key, "prefix", param->keylen) == 0) { 1359290071Sbapt params.use_prefix = ucl_object_toboolean (param); 1360290071Sbapt } 1361275223Sbapt } 1362290071Sbapt else if (param->type == UCL_STRING) { 1363290071Sbapt if (strncmp (param->key, "key", param->keylen) == 0) { 1364290071Sbapt params.prefix = ucl_object_tostring (param); 1365290071Sbapt } 1366290071Sbapt else if (strncmp (param->key, "target", param->keylen) == 0) { 1367290071Sbapt params.target = ucl_object_tostring (param); 1368290071Sbapt } 1369290071Sbapt else if (strncmp (param->key, "duplicate", param->keylen) == 0) { 1370290071Sbapt duplicate = ucl_object_tostring (param); 1371290071Sbapt 1372290071Sbapt if (strcmp (duplicate, "append") == 0) { 1373290071Sbapt params.strat = UCL_DUPLICATE_APPEND; 1374290071Sbapt } 1375290071Sbapt else if (strcmp (duplicate, "merge") == 0) { 1376290071Sbapt params.strat = UCL_DUPLICATE_MERGE; 1377290071Sbapt } 1378290071Sbapt else if (strcmp (duplicate, "rewrite") == 0) { 1379290071Sbapt params.strat = UCL_DUPLICATE_REWRITE; 1380290071Sbapt } 1381290071Sbapt else if (strcmp (duplicate, "error") == 0) { 1382290071Sbapt params.strat = UCL_DUPLICATE_ERROR; 1383290071Sbapt } 1384290071Sbapt } 1385290071Sbapt } 1386290071Sbapt else if (param->type == UCL_ARRAY) { 1387290071Sbapt if (strncmp (param->key, "path", param->keylen) == 0) { 1388290071Sbapt ucl_set_include_path (parser, __DECONST(ucl_object_t *, param)); 1389290071Sbapt } 1390290071Sbapt } 1391275223Sbapt else if (param->type == UCL_INT) { 1392290071Sbapt if (strncmp (param->key, "priority", param->keylen) == 0) { 1393290071Sbapt params.priority = ucl_object_toint (param); 1394275223Sbapt } 1395275223Sbapt } 1396275223Sbapt } 1397275223Sbapt } 1398275223Sbapt 1399290071Sbapt if (parser->includepaths == NULL) { 1400290071Sbapt if (allow_url && ucl_strnstr (data, "://", len) != NULL) { 1401290071Sbapt /* Globbing is not used for URL's */ 1402290071Sbapt return ucl_include_url (data, len, parser, ¶ms); 1403290071Sbapt } 1404290071Sbapt else if (data != NULL) { 1405290071Sbapt /* Try to load a file */ 1406290071Sbapt return ucl_include_file (data, len, parser, ¶ms); 1407290071Sbapt } 1408275223Sbapt } 1409290071Sbapt else { 1410290071Sbapt if (allow_url && ucl_strnstr (data, "://", len) != NULL) { 1411290071Sbapt /* Globbing is not used for URL's */ 1412290071Sbapt return ucl_include_url (data, len, parser, ¶ms); 1413290071Sbapt } 1414290071Sbapt 1415290071Sbapt ip = ucl_object_iterate_new (parser->includepaths); 1416290071Sbapt while ((param = ucl_object_iterate_safe (ip, true)) != NULL) { 1417290071Sbapt if (ucl_object_type(param) == UCL_STRING) { 1418290071Sbapt snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param), 1419290071Sbapt (int)len, data); 1420290071Sbapt if ((search = ucl_include_file (ipath, strlen (ipath), 1421290071Sbapt parser, ¶ms))) { 1422290071Sbapt if (!params.allow_glob) { 1423290071Sbapt break; 1424290071Sbapt } 1425290071Sbapt } 1426290071Sbapt } 1427290071Sbapt } 1428290071Sbapt ucl_object_iterate_free (ip); 1429290071Sbapt if (search == true) { 1430290071Sbapt return true; 1431290071Sbapt } 1432290071Sbapt else { 1433290071Sbapt ucl_create_err (&parser->err, 1434290071Sbapt "cannot find file: %.*s in search path", 1435290071Sbapt (int)len, data); 1436290071Sbapt return false; 1437290071Sbapt } 1438275223Sbapt } 1439275223Sbapt 1440275223Sbapt return false; 1441275223Sbapt} 1442275223Sbapt 1443275223Sbapt/** 1444262395Sbapt * Handle include macro 1445262395Sbapt * @param data include data 1446262395Sbapt * @param len length of data 1447290071Sbapt * @param args UCL object representing arguments to the macro 1448262395Sbapt * @param ud user data 1449262395Sbapt * @return 1450262395Sbapt */ 1451290071Sbaptbool 1452275223Sbaptucl_include_handler (const unsigned char *data, size_t len, 1453275223Sbapt const ucl_object_t *args, void* ud) 1454262395Sbapt{ 1455262395Sbapt struct ucl_parser *parser = ud; 1456262395Sbapt 1457275223Sbapt return ucl_include_common (data, len, args, parser, false, false); 1458262395Sbapt} 1459262395Sbapt 1460262395Sbapt/** 1461262395Sbapt * Handle includes macro 1462262395Sbapt * @param data include data 1463262395Sbapt * @param len length of data 1464290071Sbapt * @param args UCL object representing arguments to the macro 1465262395Sbapt * @param ud user data 1466262395Sbapt * @return 1467262395Sbapt */ 1468290071Sbaptbool 1469275223Sbaptucl_includes_handler (const unsigned char *data, size_t len, 1470275223Sbapt const ucl_object_t *args, void* ud) 1471262395Sbapt{ 1472262395Sbapt struct ucl_parser *parser = ud; 1473262395Sbapt 1474275223Sbapt return ucl_include_common (data, len, args, parser, false, true); 1475262395Sbapt} 1476262395Sbapt 1477290071Sbapt/** 1478290071Sbapt * Handle tryinclude macro 1479290071Sbapt * @param data include data 1480290071Sbapt * @param len length of data 1481290071Sbapt * @param args UCL object representing arguments to the macro 1482290071Sbapt * @param ud user data 1483290071Sbapt * @return 1484290071Sbapt */ 1485290071Sbaptbool 1486275223Sbaptucl_try_include_handler (const unsigned char *data, size_t len, 1487275223Sbapt const ucl_object_t *args, void* ud) 1488262395Sbapt{ 1489262395Sbapt struct ucl_parser *parser = ud; 1490262395Sbapt 1491275223Sbapt return ucl_include_common (data, len, args, parser, true, false); 1492262395Sbapt} 1493262395Sbapt 1494290071Sbapt/** 1495290071Sbapt * Handle priority macro 1496290071Sbapt * @param data include data 1497290071Sbapt * @param len length of data 1498290071Sbapt * @param args UCL object representing arguments to the macro 1499290071Sbapt * @param ud user data 1500290071Sbapt * @return 1501290071Sbapt */ 1502290071Sbaptbool 1503290071Sbaptucl_priority_handler (const unsigned char *data, size_t len, 1504290071Sbapt const ucl_object_t *args, void* ud) 1505290071Sbapt{ 1506290071Sbapt struct ucl_parser *parser = ud; 1507290071Sbapt unsigned priority = 255; 1508290071Sbapt const ucl_object_t *param; 1509290071Sbapt bool found = false; 1510290071Sbapt char *value = NULL, *leftover = NULL; 1511290071Sbapt ucl_object_iter_t it = NULL; 1512290071Sbapt 1513290071Sbapt if (parser == NULL) { 1514290071Sbapt return false; 1515290071Sbapt } 1516290071Sbapt 1517290071Sbapt /* Process arguments */ 1518290071Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1519298166Sbapt while ((param = ucl_object_iterate (args, &it, true)) != NULL) { 1520290071Sbapt if (param->type == UCL_INT) { 1521290071Sbapt if (strncmp (param->key, "priority", param->keylen) == 0) { 1522290071Sbapt priority = ucl_object_toint (param); 1523290071Sbapt found = true; 1524290071Sbapt } 1525290071Sbapt } 1526290071Sbapt } 1527290071Sbapt } 1528290071Sbapt 1529290071Sbapt if (len > 0) { 1530290071Sbapt value = malloc(len + 1); 1531290071Sbapt ucl_strlcpy(value, (const char *)data, len + 1); 1532290071Sbapt priority = strtol(value, &leftover, 10); 1533290071Sbapt if (*leftover != '\0') { 1534290071Sbapt ucl_create_err (&parser->err, "Invalid priority value in macro: %s", 1535290071Sbapt value); 1536290071Sbapt free(value); 1537290071Sbapt return false; 1538290071Sbapt } 1539290071Sbapt free(value); 1540290071Sbapt found = true; 1541290071Sbapt } 1542290071Sbapt 1543290071Sbapt if (found == true) { 1544290071Sbapt parser->chunks->priority = priority; 1545290071Sbapt return true; 1546290071Sbapt } 1547290071Sbapt 1548290071Sbapt ucl_create_err (&parser->err, "Unable to parse priority macro"); 1549290071Sbapt return false; 1550290071Sbapt} 1551290071Sbapt 1552290071Sbapt/** 1553290071Sbapt * Handle load macro 1554290071Sbapt * @param data include data 1555290071Sbapt * @param len length of data 1556290071Sbapt * @param args UCL object representing arguments to the macro 1557290071Sbapt * @param ud user data 1558290071Sbapt * @return 1559290071Sbapt */ 1560290071Sbaptbool 1561290071Sbaptucl_load_handler (const unsigned char *data, size_t len, 1562290071Sbapt const ucl_object_t *args, void* ud) 1563290071Sbapt{ 1564290071Sbapt struct ucl_parser *parser = ud; 1565290071Sbapt const ucl_object_t *param; 1566290071Sbapt ucl_object_t *obj, *old_obj; 1567290071Sbapt ucl_object_iter_t it = NULL; 1568290071Sbapt bool try_load, multiline, test; 1569290071Sbapt const char *target, *prefix; 1570290071Sbapt char *load_file, *tmp; 1571290071Sbapt unsigned char *buf; 1572290071Sbapt size_t buflen; 1573290071Sbapt unsigned priority; 1574290071Sbapt int64_t iv; 1575298166Sbapt ucl_object_t *container = NULL; 1576290071Sbapt enum ucl_string_flags flags; 1577290071Sbapt 1578290071Sbapt /* Default values */ 1579290071Sbapt try_load = false; 1580290071Sbapt multiline = false; 1581290071Sbapt test = false; 1582290071Sbapt target = "string"; 1583290071Sbapt prefix = NULL; 1584290071Sbapt load_file = NULL; 1585290071Sbapt buf = NULL; 1586290071Sbapt buflen = 0; 1587290071Sbapt priority = 0; 1588290071Sbapt obj = NULL; 1589290071Sbapt old_obj = NULL; 1590290071Sbapt flags = 0; 1591290071Sbapt 1592290071Sbapt if (parser == NULL) { 1593290071Sbapt return false; 1594290071Sbapt } 1595290071Sbapt 1596290071Sbapt /* Process arguments */ 1597290071Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1598298166Sbapt while ((param = ucl_object_iterate (args, &it, true)) != NULL) { 1599290071Sbapt if (param->type == UCL_BOOLEAN) { 1600290071Sbapt if (strncmp (param->key, "try", param->keylen) == 0) { 1601290071Sbapt try_load = ucl_object_toboolean (param); 1602290071Sbapt } 1603290071Sbapt else if (strncmp (param->key, "multiline", param->keylen) == 0) { 1604290071Sbapt multiline = ucl_object_toboolean (param); 1605290071Sbapt } 1606290071Sbapt else if (strncmp (param->key, "escape", param->keylen) == 0) { 1607290071Sbapt test = ucl_object_toboolean (param); 1608290071Sbapt if (test) { 1609290071Sbapt flags |= UCL_STRING_ESCAPE; 1610290071Sbapt } 1611290071Sbapt } 1612290071Sbapt else if (strncmp (param->key, "trim", param->keylen) == 0) { 1613290071Sbapt test = ucl_object_toboolean (param); 1614290071Sbapt if (test) { 1615290071Sbapt flags |= UCL_STRING_TRIM; 1616290071Sbapt } 1617290071Sbapt } 1618290071Sbapt } 1619290071Sbapt else if (param->type == UCL_STRING) { 1620290071Sbapt if (strncmp (param->key, "key", param->keylen) == 0) { 1621290071Sbapt prefix = ucl_object_tostring (param); 1622290071Sbapt } 1623290071Sbapt else if (strncmp (param->key, "target", param->keylen) == 0) { 1624290071Sbapt target = ucl_object_tostring (param); 1625290071Sbapt } 1626290071Sbapt } 1627290071Sbapt else if (param->type == UCL_INT) { 1628290071Sbapt if (strncmp (param->key, "priority", param->keylen) == 0) { 1629290071Sbapt priority = ucl_object_toint (param); 1630290071Sbapt } 1631290071Sbapt } 1632290071Sbapt } 1633290071Sbapt } 1634290071Sbapt 1635298166Sbapt if (prefix == NULL || strlen (prefix) == 0) { 1636290071Sbapt ucl_create_err (&parser->err, "No Key specified in load macro"); 1637290071Sbapt return false; 1638290071Sbapt } 1639290071Sbapt 1640290071Sbapt if (len > 0) { 1641298166Sbapt load_file = malloc (len + 1); 1642298166Sbapt if (!load_file) { 1643298166Sbapt ucl_create_err (&parser->err, "cannot allocate memory for suffix"); 1644298166Sbapt 1645298166Sbapt return false; 1646298166Sbapt } 1647298166Sbapt 1648298166Sbapt snprintf (load_file, len + 1, "%.*s", (int)len, data); 1649298166Sbapt 1650298166Sbapt if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err, 1651298166Sbapt !try_load)) { 1652298166Sbapt free (load_file); 1653298166Sbapt 1654290071Sbapt return (try_load || false); 1655290071Sbapt } 1656290071Sbapt 1657298166Sbapt free (load_file); 1658298166Sbapt container = parser->stack->obj; 1659298166Sbapt old_obj = __DECONST (ucl_object_t *, ucl_object_lookup (container, 1660298166Sbapt prefix)); 1661298166Sbapt 1662290071Sbapt if (old_obj != NULL) { 1663290071Sbapt ucl_create_err (&parser->err, "Key %s already exists", prefix); 1664298166Sbapt if (buf) { 1665298166Sbapt ucl_munmap (buf, buflen); 1666298166Sbapt } 1667298166Sbapt 1668290071Sbapt return false; 1669290071Sbapt } 1670290071Sbapt 1671290071Sbapt if (strcasecmp (target, "string") == 0) { 1672290071Sbapt obj = ucl_object_fromstring_common (buf, buflen, flags); 1673290071Sbapt ucl_copy_value_trash (obj); 1674290071Sbapt if (multiline) { 1675290071Sbapt obj->flags |= UCL_OBJECT_MULTILINE; 1676290071Sbapt } 1677290071Sbapt } 1678290071Sbapt else if (strcasecmp (target, "int") == 0) { 1679298166Sbapt tmp = malloc (buflen + 1); 1680298166Sbapt 1681298166Sbapt if (tmp == NULL) { 1682298166Sbapt ucl_create_err (&parser->err, "Memory allocation failed"); 1683298166Sbapt if (buf) { 1684298166Sbapt ucl_munmap (buf, buflen); 1685298166Sbapt } 1686298166Sbapt 1687298166Sbapt return false; 1688298166Sbapt } 1689298166Sbapt 1690298166Sbapt snprintf (tmp, buflen + 1, "%.*s", (int)buflen, buf); 1691298166Sbapt iv = strtoll (tmp, NULL, 10); 1692298166Sbapt obj = ucl_object_fromint (iv); 1693298166Sbapt free (tmp); 1694290071Sbapt } 1695290071Sbapt 1696298166Sbapt if (buf) { 1697290071Sbapt ucl_munmap (buf, buflen); 1698290071Sbapt } 1699290071Sbapt 1700290071Sbapt if (obj != NULL) { 1701290071Sbapt obj->key = prefix; 1702290071Sbapt obj->keylen = strlen (prefix); 1703298166Sbapt ucl_copy_key_trash (obj); 1704290071Sbapt obj->prev = obj; 1705290071Sbapt obj->next = NULL; 1706290071Sbapt ucl_object_set_priority (obj, priority); 1707298166Sbapt ucl_object_insert_key (container, obj, obj->key, obj->keylen, false); 1708290071Sbapt } 1709298166Sbapt 1710290071Sbapt return true; 1711290071Sbapt } 1712290071Sbapt 1713290071Sbapt ucl_create_err (&parser->err, "Unable to parse load macro"); 1714290071Sbapt return false; 1715290071Sbapt} 1716290071Sbapt 1717290071Sbaptbool 1718290071Sbaptucl_inherit_handler (const unsigned char *data, size_t len, 1719290071Sbapt const ucl_object_t *args, const ucl_object_t *ctx, void* ud) 1720290071Sbapt{ 1721290071Sbapt const ucl_object_t *parent, *cur; 1722290071Sbapt ucl_object_t *target, *copy; 1723290071Sbapt ucl_object_iter_t it = NULL; 1724290071Sbapt bool replace = false; 1725290071Sbapt struct ucl_parser *parser = ud; 1726290071Sbapt 1727298166Sbapt parent = ucl_object_lookup_len (ctx, data, len); 1728290071Sbapt 1729290071Sbapt /* Some sanity checks */ 1730290071Sbapt if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) { 1731290071Sbapt ucl_create_err (&parser->err, "Unable to find inherited object %*.s", 1732290071Sbapt (int)len, data); 1733290071Sbapt return false; 1734290071Sbapt } 1735290071Sbapt 1736290071Sbapt if (parser->stack == NULL || parser->stack->obj == NULL || 1737290071Sbapt ucl_object_type (parser->stack->obj) != UCL_OBJECT) { 1738290071Sbapt ucl_create_err (&parser->err, "Invalid inherit context"); 1739290071Sbapt return false; 1740290071Sbapt } 1741290071Sbapt 1742290071Sbapt target = parser->stack->obj; 1743290071Sbapt 1744298166Sbapt if (args && (cur = ucl_object_lookup (args, "replace")) != NULL) { 1745290071Sbapt replace = ucl_object_toboolean (cur); 1746290071Sbapt } 1747290071Sbapt 1748298166Sbapt while ((cur = ucl_object_iterate (parent, &it, true))) { 1749290071Sbapt /* We do not replace existing keys */ 1750298166Sbapt if (!replace && ucl_object_lookup_len (target, cur->key, cur->keylen)) { 1751290071Sbapt continue; 1752290071Sbapt } 1753290071Sbapt 1754290071Sbapt copy = ucl_object_copy (cur); 1755290071Sbapt 1756290071Sbapt if (!replace) { 1757290071Sbapt copy->flags |= UCL_OBJECT_INHERITED; 1758290071Sbapt } 1759290071Sbapt 1760290071Sbapt ucl_object_insert_key (target, copy, copy->key, 1761290071Sbapt copy->keylen, false); 1762290071Sbapt } 1763290071Sbapt 1764290071Sbapt return true; 1765290071Sbapt} 1766290071Sbapt 1767290071Sbaptbool 1768262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 1769262395Sbapt{ 1770262395Sbapt char realbuf[PATH_MAX], *curdir; 1771262395Sbapt 1772262395Sbapt if (filename != NULL) { 1773262395Sbapt if (need_expand) { 1774263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 1775262395Sbapt return false; 1776262395Sbapt } 1777262395Sbapt } 1778262395Sbapt else { 1779262395Sbapt ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 1780262395Sbapt } 1781262395Sbapt 1782262395Sbapt /* Define variables */ 1783262395Sbapt ucl_parser_register_variable (parser, "FILENAME", realbuf); 1784262395Sbapt curdir = dirname (realbuf); 1785262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 1786262395Sbapt } 1787262395Sbapt else { 1788262395Sbapt /* Set everything from the current dir */ 1789262395Sbapt curdir = getcwd (realbuf, sizeof (realbuf)); 1790262395Sbapt ucl_parser_register_variable (parser, "FILENAME", "undef"); 1791262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 1792262395Sbapt } 1793262395Sbapt 1794262395Sbapt return true; 1795262395Sbapt} 1796262395Sbapt 1797290071Sbaptbool 1798290071Sbaptucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename, 1799290071Sbapt unsigned priority) 1800262395Sbapt{ 1801262395Sbapt unsigned char *buf; 1802262395Sbapt size_t len; 1803262395Sbapt bool ret; 1804262395Sbapt char realbuf[PATH_MAX]; 1805262395Sbapt 1806263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 1807262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 1808262395Sbapt filename, 1809262395Sbapt strerror (errno)); 1810262395Sbapt return false; 1811262395Sbapt } 1812262395Sbapt 1813262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 1814262395Sbapt return false; 1815262395Sbapt } 1816262395Sbapt 1817275223Sbapt if (parser->cur_file) { 1818275223Sbapt free (parser->cur_file); 1819275223Sbapt } 1820275223Sbapt parser->cur_file = strdup (realbuf); 1821262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 1822290071Sbapt ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); 1823262395Sbapt 1824262395Sbapt if (len > 0) { 1825263648Sbapt ucl_munmap (buf, len); 1826262395Sbapt } 1827262395Sbapt 1828262395Sbapt return ret; 1829262395Sbapt} 1830262395Sbapt 1831290071Sbaptbool 1832290071Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename) 1833275223Sbapt{ 1834290071Sbapt if (parser == NULL) { 1835290071Sbapt return false; 1836290071Sbapt } 1837290071Sbapt 1838290071Sbapt return ucl_parser_add_file_priority(parser, filename, 1839290071Sbapt parser->default_priority); 1840290071Sbapt} 1841290071Sbapt 1842290071Sbaptbool 1843290071Sbaptucl_parser_add_fd_priority (struct ucl_parser *parser, int fd, 1844290071Sbapt unsigned priority) 1845290071Sbapt{ 1846275223Sbapt unsigned char *buf; 1847275223Sbapt size_t len; 1848275223Sbapt bool ret; 1849275223Sbapt struct stat st; 1850275223Sbapt 1851275223Sbapt if (fstat (fd, &st) == -1) { 1852275223Sbapt ucl_create_err (&parser->err, "cannot stat fd %d: %s", 1853275223Sbapt fd, strerror (errno)); 1854275223Sbapt return false; 1855275223Sbapt } 1856301339Sbapt if (st.st_size == 0) { 1857301339Sbapt return true; 1858301339Sbapt } 1859275223Sbapt if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 1860275223Sbapt ucl_create_err (&parser->err, "cannot mmap fd %d: %s", 1861275223Sbapt fd, strerror (errno)); 1862275223Sbapt return false; 1863275223Sbapt } 1864275223Sbapt 1865275223Sbapt if (parser->cur_file) { 1866275223Sbapt free (parser->cur_file); 1867275223Sbapt } 1868275223Sbapt parser->cur_file = NULL; 1869275223Sbapt len = st.st_size; 1870290071Sbapt ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); 1871275223Sbapt 1872275223Sbapt if (len > 0) { 1873275223Sbapt ucl_munmap (buf, len); 1874275223Sbapt } 1875275223Sbapt 1876275223Sbapt return ret; 1877275223Sbapt} 1878275223Sbapt 1879290071Sbaptbool 1880290071Sbaptucl_parser_add_fd (struct ucl_parser *parser, int fd) 1881290071Sbapt{ 1882290071Sbapt if (parser == NULL) { 1883290071Sbapt return false; 1884290071Sbapt } 1885290071Sbapt 1886290071Sbapt return ucl_parser_add_fd_priority(parser, fd, parser->default_priority); 1887290071Sbapt} 1888290071Sbapt 1889262395Sbaptsize_t 1890262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz) 1891262395Sbapt{ 1892262395Sbapt char *d = dst; 1893262395Sbapt const char *s = src; 1894262395Sbapt size_t n = siz; 1895262395Sbapt 1896262395Sbapt /* Copy as many bytes as will fit */ 1897262395Sbapt if (n != 0) { 1898262395Sbapt while (--n != 0) { 1899262395Sbapt if ((*d++ = *s++) == '\0') { 1900262395Sbapt break; 1901262395Sbapt } 1902262395Sbapt } 1903262395Sbapt } 1904262395Sbapt 1905262395Sbapt if (n == 0 && siz != 0) { 1906262395Sbapt *d = '\0'; 1907262395Sbapt } 1908262395Sbapt 1909262395Sbapt return (s - src - 1); /* count does not include NUL */ 1910262395Sbapt} 1911262395Sbapt 1912262395Sbaptsize_t 1913262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 1914262395Sbapt{ 1915262395Sbapt memcpy (dst, src, siz - 1); 1916262395Sbapt dst[siz - 1] = '\0'; 1917262395Sbapt 1918262395Sbapt return siz - 1; 1919262395Sbapt} 1920262395Sbapt 1921262395Sbaptsize_t 1922262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 1923262395Sbapt{ 1924262395Sbapt char *d = dst; 1925262395Sbapt const char *s = src; 1926262395Sbapt size_t n = siz; 1927262395Sbapt 1928262395Sbapt /* Copy as many bytes as will fit */ 1929262395Sbapt if (n != 0) { 1930262395Sbapt while (--n != 0) { 1931262395Sbapt if ((*d++ = tolower (*s++)) == '\0') { 1932262395Sbapt break; 1933262395Sbapt } 1934262395Sbapt } 1935262395Sbapt } 1936262395Sbapt 1937262395Sbapt if (n == 0 && siz != 0) { 1938262395Sbapt *d = '\0'; 1939262395Sbapt } 1940262395Sbapt 1941262395Sbapt return (s - src); /* count does not include NUL */ 1942262395Sbapt} 1943262395Sbapt 1944290071Sbapt/* 1945290071Sbapt * Find the first occurrence of find in s 1946290071Sbapt */ 1947290071Sbaptchar * 1948290071Sbaptucl_strnstr (const char *s, const char *find, int len) 1949290071Sbapt{ 1950290071Sbapt char c, sc; 1951290071Sbapt int mlen; 1952290071Sbapt 1953290071Sbapt if ((c = *find++) != 0) { 1954290071Sbapt mlen = strlen (find); 1955290071Sbapt do { 1956290071Sbapt do { 1957290071Sbapt if ((sc = *s++) == 0 || len-- == 0) 1958290071Sbapt return (NULL); 1959290071Sbapt } while (sc != c); 1960290071Sbapt } while (strncmp (s, find, mlen) != 0); 1961290071Sbapt s--; 1962290071Sbapt } 1963290071Sbapt return ((char *)s); 1964290071Sbapt} 1965290071Sbapt 1966290071Sbapt/* 1967290071Sbapt * Find the first occurrence of find in s, ignore case. 1968290071Sbapt */ 1969290071Sbaptchar * 1970290071Sbaptucl_strncasestr (const char *s, const char *find, int len) 1971290071Sbapt{ 1972290071Sbapt char c, sc; 1973290071Sbapt int mlen; 1974290071Sbapt 1975290071Sbapt if ((c = *find++) != 0) { 1976290071Sbapt c = tolower (c); 1977290071Sbapt mlen = strlen (find); 1978290071Sbapt do { 1979290071Sbapt do { 1980290071Sbapt if ((sc = *s++) == 0 || len-- == 0) 1981290071Sbapt return (NULL); 1982290071Sbapt } while (tolower (sc) != c); 1983290071Sbapt } while (strncasecmp (s, find, mlen) != 0); 1984290071Sbapt s--; 1985290071Sbapt } 1986290071Sbapt return ((char *)s); 1987290071Sbapt} 1988290071Sbapt 1989262395Sbaptucl_object_t * 1990262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1991262395Sbapt{ 1992262395Sbapt ucl_object_t *obj; 1993262395Sbapt const char *start, *end, *p, *pos; 1994262395Sbapt char *dst, *d; 1995262395Sbapt size_t escaped_len; 1996262395Sbapt 1997262395Sbapt if (str == NULL) { 1998262395Sbapt return NULL; 1999262395Sbapt } 2000262395Sbapt 2001262395Sbapt obj = ucl_object_new (); 2002262395Sbapt if (obj) { 2003262395Sbapt if (len == 0) { 2004262395Sbapt len = strlen (str); 2005262395Sbapt } 2006262395Sbapt if (flags & UCL_STRING_TRIM) { 2007262395Sbapt /* Skip leading spaces */ 2008262395Sbapt for (start = str; (size_t)(start - str) < len; start ++) { 2009262395Sbapt if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 2010262395Sbapt break; 2011262395Sbapt } 2012262395Sbapt } 2013262395Sbapt /* Skip trailing spaces */ 2014262395Sbapt for (end = str + len - 1; end > start; end --) { 2015262395Sbapt if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 2016262395Sbapt break; 2017262395Sbapt } 2018262395Sbapt } 2019262395Sbapt end ++; 2020262395Sbapt } 2021262395Sbapt else { 2022262395Sbapt start = str; 2023262395Sbapt end = str + len; 2024262395Sbapt } 2025262395Sbapt 2026262395Sbapt obj->type = UCL_STRING; 2027262395Sbapt if (flags & UCL_STRING_ESCAPE) { 2028262395Sbapt for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 2029262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 2030262395Sbapt escaped_len ++; 2031262395Sbapt } 2032262395Sbapt } 2033262395Sbapt dst = malloc (escaped_len + 1); 2034262395Sbapt if (dst != NULL) { 2035262395Sbapt for (p = start, d = dst; p < end; p ++, d ++) { 2036262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 2037262395Sbapt switch (*p) { 2038262395Sbapt case '\n': 2039262395Sbapt *d++ = '\\'; 2040262395Sbapt *d = 'n'; 2041262395Sbapt break; 2042262395Sbapt case '\r': 2043262395Sbapt *d++ = '\\'; 2044262395Sbapt *d = 'r'; 2045262395Sbapt break; 2046262395Sbapt case '\b': 2047262395Sbapt *d++ = '\\'; 2048262395Sbapt *d = 'b'; 2049262395Sbapt break; 2050262395Sbapt case '\t': 2051262395Sbapt *d++ = '\\'; 2052262395Sbapt *d = 't'; 2053262395Sbapt break; 2054262395Sbapt case '\f': 2055262395Sbapt *d++ = '\\'; 2056262395Sbapt *d = 'f'; 2057262395Sbapt break; 2058262395Sbapt case '\\': 2059262395Sbapt *d++ = '\\'; 2060262395Sbapt *d = '\\'; 2061262395Sbapt break; 2062262395Sbapt case '"': 2063262395Sbapt *d++ = '\\'; 2064262395Sbapt *d = '"'; 2065262395Sbapt break; 2066262395Sbapt } 2067262395Sbapt } 2068262395Sbapt else { 2069262395Sbapt *d = *p; 2070262395Sbapt } 2071262395Sbapt } 2072262395Sbapt *d = '\0'; 2073262395Sbapt obj->value.sv = dst; 2074262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 2075262395Sbapt obj->len = escaped_len; 2076262395Sbapt } 2077262395Sbapt } 2078262395Sbapt else { 2079262395Sbapt dst = malloc (end - start + 1); 2080262395Sbapt if (dst != NULL) { 2081262395Sbapt ucl_strlcpy_unsafe (dst, start, end - start + 1); 2082262395Sbapt obj->value.sv = dst; 2083262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 2084262395Sbapt obj->len = end - start; 2085262395Sbapt } 2086262395Sbapt } 2087262395Sbapt if ((flags & UCL_STRING_PARSE) && dst != NULL) { 2088262395Sbapt /* Parse what we have */ 2089262395Sbapt if (flags & UCL_STRING_PARSE_BOOLEAN) { 2090262395Sbapt if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 2091262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 2092262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 2093263648Sbapt flags & UCL_STRING_PARSE_BYTES, 2094263648Sbapt flags & UCL_STRING_PARSE_TIME); 2095262395Sbapt } 2096262395Sbapt } 2097262395Sbapt else { 2098262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 2099262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 2100263648Sbapt flags & UCL_STRING_PARSE_BYTES, 2101263648Sbapt flags & UCL_STRING_PARSE_TIME); 2102262395Sbapt } 2103262395Sbapt } 2104262395Sbapt } 2105262395Sbapt 2106262395Sbapt return obj; 2107262395Sbapt} 2108262395Sbapt 2109264789Sbaptstatic bool 2110262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 2111262395Sbapt const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 2112262395Sbapt{ 2113264789Sbapt ucl_object_t *found, *tmp; 2114264789Sbapt const ucl_object_t *cur; 2115262395Sbapt ucl_object_iter_t it = NULL; 2116262395Sbapt const char *p; 2117264789Sbapt int ret = true; 2118262395Sbapt 2119262395Sbapt if (elt == NULL || key == NULL) { 2120264789Sbapt return false; 2121262395Sbapt } 2122262395Sbapt 2123262395Sbapt if (top == NULL) { 2124264789Sbapt return false; 2125262395Sbapt } 2126262395Sbapt 2127262395Sbapt if (top->type != UCL_OBJECT) { 2128262395Sbapt /* It is possible to convert NULL type to an object */ 2129262395Sbapt if (top->type == UCL_NULL) { 2130262395Sbapt top->type = UCL_OBJECT; 2131262395Sbapt } 2132262395Sbapt else { 2133262395Sbapt /* Refuse converting of other object types */ 2134264789Sbapt return false; 2135262395Sbapt } 2136262395Sbapt } 2137262395Sbapt 2138262395Sbapt if (top->value.ov == NULL) { 2139279549Sbapt top->value.ov = ucl_hash_create (false); 2140262395Sbapt } 2141262395Sbapt 2142262395Sbapt if (keylen == 0) { 2143262395Sbapt keylen = strlen (key); 2144262395Sbapt } 2145262395Sbapt 2146262395Sbapt for (p = key; p < key + keylen; p ++) { 2147262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 2148262395Sbapt elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 2149262395Sbapt break; 2150262395Sbapt } 2151262395Sbapt } 2152262395Sbapt 2153275223Sbapt /* workaround for some use cases */ 2154275223Sbapt if (elt->trash_stack[UCL_TRASH_KEY] != NULL && 2155275223Sbapt key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) { 2156275223Sbapt /* Remove copied key */ 2157275223Sbapt free (elt->trash_stack[UCL_TRASH_KEY]); 2158275223Sbapt elt->trash_stack[UCL_TRASH_KEY] = NULL; 2159275223Sbapt elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY; 2160275223Sbapt } 2161275223Sbapt 2162262395Sbapt elt->key = key; 2163262395Sbapt elt->keylen = keylen; 2164262395Sbapt 2165262395Sbapt if (copy_key) { 2166262395Sbapt ucl_copy_key_trash (elt); 2167262395Sbapt } 2168262395Sbapt 2169264789Sbapt found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 2170262395Sbapt 2171275223Sbapt if (found == NULL) { 2172279549Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); 2173263648Sbapt top->len ++; 2174264789Sbapt if (replace) { 2175264789Sbapt ret = false; 2176264789Sbapt } 2177262395Sbapt } 2178262395Sbapt else { 2179262395Sbapt if (replace) { 2180275223Sbapt ucl_hash_replace (top->value.ov, found, elt); 2181262395Sbapt ucl_object_unref (found); 2182262395Sbapt } 2183262395Sbapt else if (merge) { 2184262395Sbapt if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 2185262395Sbapt /* Insert old elt to new one */ 2186264789Sbapt ucl_object_insert_key_common (elt, found, found->key, 2187264789Sbapt found->keylen, copy_key, false, false); 2188262395Sbapt ucl_hash_delete (top->value.ov, found); 2189279549Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); 2190262395Sbapt } 2191262395Sbapt else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 2192262395Sbapt /* Insert new to old */ 2193264789Sbapt ucl_object_insert_key_common (found, elt, elt->key, 2194264789Sbapt elt->keylen, copy_key, false, false); 2195262395Sbapt } 2196262395Sbapt else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 2197262395Sbapt /* Mix two hashes */ 2198298166Sbapt while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) { 2199264789Sbapt tmp = ucl_object_ref (cur); 2200264789Sbapt ucl_object_insert_key_common (found, tmp, cur->key, 2201264789Sbapt cur->keylen, copy_key, false, false); 2202262395Sbapt } 2203262395Sbapt ucl_object_unref (elt); 2204262395Sbapt } 2205262395Sbapt else { 2206262395Sbapt /* Just make a list of scalars */ 2207262395Sbapt DL_APPEND (found, elt); 2208262395Sbapt } 2209262395Sbapt } 2210262395Sbapt else { 2211262395Sbapt DL_APPEND (found, elt); 2212262395Sbapt } 2213262395Sbapt } 2214262395Sbapt 2215264789Sbapt return ret; 2216262395Sbapt} 2217262395Sbapt 2218262975Sbaptbool 2219264789Sbaptucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 2220262975Sbapt{ 2221262975Sbapt ucl_object_t *found; 2222262975Sbapt 2223263648Sbapt if (top == NULL || key == NULL) { 2224263648Sbapt return false; 2225263648Sbapt } 2226263648Sbapt 2227298166Sbapt found = __DECONST (ucl_object_t *, ucl_object_lookup_len (top, key, keylen)); 2228262975Sbapt 2229263648Sbapt if (found == NULL) { 2230262975Sbapt return false; 2231263648Sbapt } 2232262975Sbapt 2233264789Sbapt ucl_hash_delete (top->value.ov, found); 2234262975Sbapt ucl_object_unref (found); 2235262975Sbapt top->len --; 2236262975Sbapt 2237262975Sbapt return true; 2238262975Sbapt} 2239262975Sbapt 2240262975Sbaptbool 2241264789Sbaptucl_object_delete_key (ucl_object_t *top, const char *key) 2242262975Sbapt{ 2243290071Sbapt return ucl_object_delete_keyl (top, key, strlen (key)); 2244262975Sbapt} 2245262975Sbapt 2246263648Sbaptucl_object_t* 2247263648Sbaptucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 2248263648Sbapt{ 2249264789Sbapt const ucl_object_t *found; 2250263648Sbapt 2251263648Sbapt if (top == NULL || key == NULL) { 2252263648Sbapt return false; 2253263648Sbapt } 2254298166Sbapt found = ucl_object_lookup_len (top, key, keylen); 2255263648Sbapt 2256263648Sbapt if (found == NULL) { 2257263648Sbapt return NULL; 2258263648Sbapt } 2259264789Sbapt ucl_hash_delete (top->value.ov, found); 2260263648Sbapt top->len --; 2261263648Sbapt 2262264789Sbapt return __DECONST (ucl_object_t *, found); 2263263648Sbapt} 2264263648Sbapt 2265263648Sbaptucl_object_t* 2266263648Sbaptucl_object_pop_key (ucl_object_t *top, const char *key) 2267263648Sbapt{ 2268290071Sbapt return ucl_object_pop_keyl (top, key, strlen (key)); 2269263648Sbapt} 2270263648Sbapt 2271264789Sbaptbool 2272262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 2273262395Sbapt const char *key, size_t keylen, bool copy_key) 2274262395Sbapt{ 2275262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 2276262395Sbapt} 2277262395Sbapt 2278264789Sbaptbool 2279262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 2280262395Sbapt const char *key, size_t keylen, bool copy_key) 2281262395Sbapt{ 2282262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 2283262395Sbapt} 2284262395Sbapt 2285264789Sbaptbool 2286262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 2287262395Sbapt const char *key, size_t keylen, bool copy_key) 2288262395Sbapt{ 2289262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 2290262395Sbapt} 2291262395Sbapt 2292275223Sbaptbool 2293275223Sbaptucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 2294275223Sbapt{ 2295275223Sbapt ucl_object_t *cur = NULL, *cp = NULL, *found = NULL; 2296275223Sbapt ucl_object_iter_t iter = NULL; 2297275223Sbapt 2298275223Sbapt if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) { 2299275223Sbapt return false; 2300275223Sbapt } 2301275223Sbapt 2302275223Sbapt /* Mix two hashes */ 2303275223Sbapt while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) { 2304275223Sbapt if (copy) { 2305275223Sbapt cp = ucl_object_copy (cur); 2306275223Sbapt } 2307275223Sbapt else { 2308275223Sbapt cp = ucl_object_ref (cur); 2309275223Sbapt } 2310275223Sbapt found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen)); 2311275223Sbapt if (found == NULL) { 2312275223Sbapt /* The key does not exist */ 2313279549Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false); 2314275223Sbapt top->len ++; 2315275223Sbapt } 2316275223Sbapt else { 2317275223Sbapt /* The key already exists, replace it */ 2318275223Sbapt ucl_hash_replace (top->value.ov, found, cp); 2319275223Sbapt ucl_object_unref (found); 2320275223Sbapt } 2321275223Sbapt } 2322275223Sbapt 2323275223Sbapt return true; 2324275223Sbapt} 2325275223Sbapt 2326264789Sbaptconst ucl_object_t * 2327298166Sbaptucl_object_lookup_len (const ucl_object_t *obj, const char *key, size_t klen) 2328262395Sbapt{ 2329264789Sbapt const ucl_object_t *ret; 2330264789Sbapt ucl_object_t srch; 2331262395Sbapt 2332262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 2333262395Sbapt return NULL; 2334262395Sbapt } 2335262395Sbapt 2336262395Sbapt srch.key = key; 2337262395Sbapt srch.keylen = klen; 2338262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 2339262395Sbapt 2340262395Sbapt return ret; 2341262395Sbapt} 2342262395Sbapt 2343264789Sbaptconst ucl_object_t * 2344298166Sbaptucl_object_lookup (const ucl_object_t *obj, const char *key) 2345262395Sbapt{ 2346290071Sbapt if (key == NULL) { 2347262395Sbapt return NULL; 2348290071Sbapt } 2349262395Sbapt 2350298166Sbapt return ucl_object_lookup_len (obj, key, strlen (key)); 2351262395Sbapt} 2352262395Sbapt 2353264789Sbaptconst ucl_object_t* 2354298166Sbaptucl_object_lookup_any (const ucl_object_t *obj, 2355290071Sbapt const char *key, ...) 2356290071Sbapt{ 2357290071Sbapt va_list ap; 2358290071Sbapt const ucl_object_t *ret = NULL; 2359290071Sbapt const char *nk = NULL; 2360290071Sbapt 2361290071Sbapt if (obj == NULL || key == NULL) { 2362290071Sbapt return NULL; 2363290071Sbapt } 2364290071Sbapt 2365298166Sbapt ret = ucl_object_lookup_len (obj, key, strlen (key)); 2366290071Sbapt 2367290071Sbapt if (ret == NULL) { 2368290071Sbapt va_start (ap, key); 2369290071Sbapt 2370290071Sbapt while (ret == NULL) { 2371290071Sbapt nk = va_arg (ap, const char *); 2372290071Sbapt 2373290071Sbapt if (nk == NULL) { 2374290071Sbapt break; 2375290071Sbapt } 2376290071Sbapt else { 2377298166Sbapt ret = ucl_object_lookup_len (obj, nk, strlen (nk)); 2378290071Sbapt } 2379290071Sbapt } 2380290071Sbapt 2381290071Sbapt va_end (ap); 2382290071Sbapt } 2383290071Sbapt 2384290071Sbapt return ret; 2385290071Sbapt} 2386290071Sbapt 2387290071Sbaptconst ucl_object_t* 2388298166Sbaptucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 2389262395Sbapt{ 2390279549Sbapt const ucl_object_t *elt = NULL; 2391262395Sbapt 2392263648Sbapt if (obj == NULL || iter == NULL) { 2393263648Sbapt return NULL; 2394263648Sbapt } 2395263648Sbapt 2396262395Sbapt if (expand_values) { 2397262395Sbapt switch (obj->type) { 2398262395Sbapt case UCL_OBJECT: 2399264789Sbapt return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 2400262395Sbapt break; 2401279549Sbapt case UCL_ARRAY: { 2402279549Sbapt unsigned int idx; 2403279549Sbapt UCL_ARRAY_GET (vec, obj); 2404279549Sbapt idx = (unsigned int)(uintptr_t)(*iter); 2405279549Sbapt 2406279549Sbapt if (vec != NULL) { 2407279549Sbapt while (idx < kv_size (*vec)) { 2408279549Sbapt if ((elt = kv_A (*vec, idx)) != NULL) { 2409279549Sbapt idx ++; 2410279549Sbapt break; 2411279549Sbapt } 2412279549Sbapt idx ++; 2413262395Sbapt } 2414279549Sbapt *iter = (void *)(uintptr_t)idx; 2415262395Sbapt } 2416279549Sbapt 2417262395Sbapt return elt; 2418279549Sbapt break; 2419279549Sbapt } 2420262395Sbapt default: 2421262395Sbapt /* Go to linear iteration */ 2422262395Sbapt break; 2423262395Sbapt } 2424262395Sbapt } 2425262395Sbapt /* Treat everything as a linear list */ 2426262395Sbapt elt = *iter; 2427262395Sbapt if (elt == NULL) { 2428262395Sbapt elt = obj; 2429262395Sbapt } 2430262395Sbapt else if (elt == obj) { 2431262395Sbapt return NULL; 2432262395Sbapt } 2433264789Sbapt *iter = __DECONST (void *, elt->next ? elt->next : obj); 2434262395Sbapt return elt; 2435262395Sbapt 2436262395Sbapt /* Not reached */ 2437262395Sbapt return NULL; 2438262395Sbapt} 2439263648Sbapt 2440279549Sbaptconst char safe_iter_magic[4] = {'u', 'i', 't', 'e'}; 2441279549Sbaptstruct ucl_object_safe_iter { 2442279549Sbapt char magic[4]; /* safety check */ 2443279549Sbapt const ucl_object_t *impl_it; /* implicit object iteration */ 2444279549Sbapt ucl_object_iter_t expl_it; /* explicit iteration */ 2445279549Sbapt}; 2446279549Sbapt 2447279549Sbapt#define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr) 2448279549Sbapt#define UCL_SAFE_ITER_CHECK(it) do { \ 2449279549Sbapt assert (it != NULL); \ 2450279549Sbapt assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \ 2451279549Sbapt } while (0) 2452279549Sbapt 2453279549Sbaptucl_object_iter_t 2454279549Sbaptucl_object_iterate_new (const ucl_object_t *obj) 2455279549Sbapt{ 2456279549Sbapt struct ucl_object_safe_iter *it; 2457279549Sbapt 2458279549Sbapt it = UCL_ALLOC (sizeof (*it)); 2459279549Sbapt if (it != NULL) { 2460279549Sbapt memcpy (it->magic, safe_iter_magic, sizeof (it->magic)); 2461279549Sbapt it->expl_it = NULL; 2462279549Sbapt it->impl_it = obj; 2463279549Sbapt } 2464279549Sbapt 2465279549Sbapt return (ucl_object_iter_t)it; 2466279549Sbapt} 2467279549Sbapt 2468279549Sbapt 2469279549Sbaptucl_object_iter_t 2470279549Sbaptucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj) 2471279549Sbapt{ 2472279549Sbapt struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 2473279549Sbapt 2474279549Sbapt UCL_SAFE_ITER_CHECK (rit); 2475279549Sbapt 2476279549Sbapt rit->impl_it = obj; 2477279549Sbapt rit->expl_it = NULL; 2478279549Sbapt 2479279549Sbapt return it; 2480279549Sbapt} 2481279549Sbapt 2482279549Sbaptconst ucl_object_t* 2483279549Sbaptucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values) 2484279549Sbapt{ 2485279549Sbapt struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 2486279549Sbapt const ucl_object_t *ret = NULL; 2487279549Sbapt 2488279549Sbapt UCL_SAFE_ITER_CHECK (rit); 2489279549Sbapt 2490279549Sbapt if (rit->impl_it == NULL) { 2491279549Sbapt return NULL; 2492279549Sbapt } 2493279549Sbapt 2494279549Sbapt if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) { 2495298166Sbapt ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true); 2496279549Sbapt 2497279549Sbapt if (ret == NULL) { 2498279549Sbapt /* Need to switch to another implicit object in chain */ 2499279549Sbapt rit->impl_it = rit->impl_it->next; 2500279549Sbapt rit->expl_it = NULL; 2501279549Sbapt return ucl_object_iterate_safe (it, expand_values); 2502279549Sbapt } 2503279549Sbapt } 2504279549Sbapt else { 2505279549Sbapt /* Just iterate over the implicit array */ 2506279549Sbapt ret = rit->impl_it; 2507279549Sbapt rit->impl_it = rit->impl_it->next; 2508279549Sbapt if (expand_values) { 2509279549Sbapt /* We flatten objects if need to expand values */ 2510279549Sbapt if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) { 2511279549Sbapt return ucl_object_iterate_safe (it, expand_values); 2512279549Sbapt } 2513279549Sbapt } 2514279549Sbapt } 2515279549Sbapt 2516279549Sbapt return ret; 2517279549Sbapt} 2518279549Sbapt 2519279549Sbaptvoid 2520279549Sbaptucl_object_iterate_free (ucl_object_iter_t it) 2521279549Sbapt{ 2522279549Sbapt struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); 2523279549Sbapt 2524279549Sbapt UCL_SAFE_ITER_CHECK (rit); 2525279549Sbapt 2526279549Sbapt UCL_FREE (sizeof (*rit), it); 2527279549Sbapt} 2528279549Sbapt 2529266636Sbaptconst ucl_object_t * 2530298166Sbaptucl_object_lookup_path (const ucl_object_t *top, const char *path_in) { 2531298166Sbapt return ucl_object_lookup_path_char (top, path_in, '.'); 2532290071Sbapt} 2533290071Sbapt 2534290071Sbapt 2535290071Sbaptconst ucl_object_t * 2536298166Sbaptucl_object_lookup_path_char (const ucl_object_t *top, const char *path_in, const char sep) { 2537266636Sbapt const ucl_object_t *o = NULL, *found; 2538266636Sbapt const char *p, *c; 2539266636Sbapt char *err_str; 2540266636Sbapt unsigned index; 2541263648Sbapt 2542266636Sbapt if (path_in == NULL || top == NULL) { 2543266636Sbapt return NULL; 2544266636Sbapt } 2545266636Sbapt 2546266636Sbapt found = NULL; 2547266636Sbapt p = path_in; 2548266636Sbapt 2549266636Sbapt /* Skip leading dots */ 2550290071Sbapt while (*p == sep) { 2551266636Sbapt p ++; 2552266636Sbapt } 2553266636Sbapt 2554266636Sbapt c = p; 2555266636Sbapt while (*p != '\0') { 2556266636Sbapt p ++; 2557290071Sbapt if (*p == sep || *p == '\0') { 2558266636Sbapt if (p > c) { 2559266636Sbapt switch (top->type) { 2560266636Sbapt case UCL_ARRAY: 2561266636Sbapt /* Key should be an int */ 2562266636Sbapt index = strtoul (c, &err_str, 10); 2563290071Sbapt if (err_str != NULL && (*err_str != sep && *err_str != '\0')) { 2564266636Sbapt return NULL; 2565266636Sbapt } 2566266636Sbapt o = ucl_array_find_index (top, index); 2567266636Sbapt break; 2568266636Sbapt default: 2569298166Sbapt o = ucl_object_lookup_len (top, c, p - c); 2570266636Sbapt break; 2571266636Sbapt } 2572266636Sbapt if (o == NULL) { 2573266636Sbapt return NULL; 2574266636Sbapt } 2575266636Sbapt top = o; 2576266636Sbapt } 2577266636Sbapt if (*p != '\0') { 2578266636Sbapt c = p + 1; 2579266636Sbapt } 2580266636Sbapt } 2581266636Sbapt } 2582266636Sbapt found = o; 2583266636Sbapt 2584266636Sbapt return found; 2585266636Sbapt} 2586266636Sbapt 2587266636Sbapt 2588263648Sbaptucl_object_t * 2589263648Sbaptucl_object_new (void) 2590263648Sbapt{ 2591275223Sbapt return ucl_object_typed_new (UCL_NULL); 2592263648Sbapt} 2593263648Sbapt 2594263648Sbaptucl_object_t * 2595266636Sbaptucl_object_typed_new (ucl_type_t type) 2596263648Sbapt{ 2597275223Sbapt return ucl_object_new_full (type, 0); 2598275223Sbapt} 2599275223Sbapt 2600275223Sbaptucl_object_t * 2601275223Sbaptucl_object_new_full (ucl_type_t type, unsigned priority) 2602275223Sbapt{ 2603263648Sbapt ucl_object_t *new; 2604275223Sbapt 2605275223Sbapt if (type != UCL_USERDATA) { 2606275223Sbapt new = UCL_ALLOC (sizeof (ucl_object_t)); 2607275223Sbapt if (new != NULL) { 2608275223Sbapt memset (new, 0, sizeof (ucl_object_t)); 2609275223Sbapt new->ref = 1; 2610275223Sbapt new->type = (type <= UCL_NULL ? type : UCL_NULL); 2611275223Sbapt new->next = NULL; 2612275223Sbapt new->prev = new; 2613275223Sbapt ucl_object_set_priority (new, priority); 2614279549Sbapt 2615279549Sbapt if (type == UCL_ARRAY) { 2616279549Sbapt new->value.av = UCL_ALLOC (sizeof (ucl_array_t)); 2617279549Sbapt if (new->value.av) { 2618279549Sbapt memset (new->value.av, 0, sizeof (ucl_array_t)); 2619279549Sbapt UCL_ARRAY_GET (vec, new); 2620279549Sbapt 2621279549Sbapt /* Preallocate some space for arrays */ 2622279549Sbapt kv_resize (ucl_object_t *, *vec, 8); 2623279549Sbapt } 2624279549Sbapt } 2625275223Sbapt } 2626263648Sbapt } 2627275223Sbapt else { 2628298166Sbapt new = ucl_object_new_userdata (NULL, NULL, NULL); 2629275223Sbapt ucl_object_set_priority (new, priority); 2630275223Sbapt } 2631275223Sbapt 2632263648Sbapt return new; 2633263648Sbapt} 2634263648Sbapt 2635275223Sbaptucl_object_t* 2636298166Sbaptucl_object_new_userdata (ucl_userdata_dtor dtor, 2637298166Sbapt ucl_userdata_emitter emitter, 2638298166Sbapt void *ptr) 2639275223Sbapt{ 2640275223Sbapt struct ucl_object_userdata *new; 2641275223Sbapt size_t nsize = sizeof (*new); 2642275223Sbapt 2643275223Sbapt new = UCL_ALLOC (nsize); 2644275223Sbapt if (new != NULL) { 2645275223Sbapt memset (new, 0, nsize); 2646275223Sbapt new->obj.ref = 1; 2647275223Sbapt new->obj.type = UCL_USERDATA; 2648275223Sbapt new->obj.next = NULL; 2649275223Sbapt new->obj.prev = (ucl_object_t *)new; 2650275223Sbapt new->dtor = dtor; 2651275223Sbapt new->emitter = emitter; 2652298166Sbapt new->obj.value.ud = ptr; 2653275223Sbapt } 2654275223Sbapt 2655275223Sbapt return (ucl_object_t *)new; 2656275223Sbapt} 2657275223Sbapt 2658266636Sbaptucl_type_t 2659266636Sbaptucl_object_type (const ucl_object_t *obj) 2660266636Sbapt{ 2661290071Sbapt if (obj == NULL) { 2662290071Sbapt return UCL_NULL; 2663290071Sbapt } 2664290071Sbapt 2665266636Sbapt return obj->type; 2666266636Sbapt} 2667266636Sbapt 2668263648Sbaptucl_object_t* 2669263648Sbaptucl_object_fromstring (const char *str) 2670263648Sbapt{ 2671263648Sbapt return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 2672263648Sbapt} 2673263648Sbapt 2674263648Sbaptucl_object_t * 2675263648Sbaptucl_object_fromlstring (const char *str, size_t len) 2676263648Sbapt{ 2677263648Sbapt return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 2678263648Sbapt} 2679263648Sbapt 2680263648Sbaptucl_object_t * 2681263648Sbaptucl_object_fromint (int64_t iv) 2682263648Sbapt{ 2683263648Sbapt ucl_object_t *obj; 2684263648Sbapt 2685263648Sbapt obj = ucl_object_new (); 2686263648Sbapt if (obj != NULL) { 2687263648Sbapt obj->type = UCL_INT; 2688263648Sbapt obj->value.iv = iv; 2689263648Sbapt } 2690263648Sbapt 2691263648Sbapt return obj; 2692263648Sbapt} 2693263648Sbapt 2694263648Sbaptucl_object_t * 2695263648Sbaptucl_object_fromdouble (double dv) 2696263648Sbapt{ 2697263648Sbapt ucl_object_t *obj; 2698263648Sbapt 2699263648Sbapt obj = ucl_object_new (); 2700263648Sbapt if (obj != NULL) { 2701263648Sbapt obj->type = UCL_FLOAT; 2702263648Sbapt obj->value.dv = dv; 2703263648Sbapt } 2704263648Sbapt 2705263648Sbapt return obj; 2706263648Sbapt} 2707263648Sbapt 2708263648Sbaptucl_object_t* 2709263648Sbaptucl_object_frombool (bool bv) 2710263648Sbapt{ 2711263648Sbapt ucl_object_t *obj; 2712263648Sbapt 2713263648Sbapt obj = ucl_object_new (); 2714263648Sbapt if (obj != NULL) { 2715263648Sbapt obj->type = UCL_BOOLEAN; 2716263648Sbapt obj->value.iv = bv; 2717263648Sbapt } 2718263648Sbapt 2719263648Sbapt return obj; 2720263648Sbapt} 2721263648Sbapt 2722264789Sbaptbool 2723263648Sbaptucl_array_append (ucl_object_t *top, ucl_object_t *elt) 2724263648Sbapt{ 2725279549Sbapt UCL_ARRAY_GET (vec, top); 2726263648Sbapt 2727264789Sbapt if (elt == NULL || top == NULL) { 2728264789Sbapt return false; 2729263648Sbapt } 2730263648Sbapt 2731279549Sbapt if (vec == NULL) { 2732279549Sbapt vec = UCL_ALLOC (sizeof (*vec)); 2733290071Sbapt 2734290071Sbapt if (vec == NULL) { 2735290071Sbapt return false; 2736290071Sbapt } 2737290071Sbapt 2738279549Sbapt kv_init (*vec); 2739279549Sbapt top->value.av = (void *)vec; 2740263648Sbapt } 2741279549Sbapt 2742279549Sbapt kv_push (ucl_object_t *, *vec, elt); 2743279549Sbapt 2744264789Sbapt top->len ++; 2745263648Sbapt 2746264789Sbapt return true; 2747263648Sbapt} 2748263648Sbapt 2749264789Sbaptbool 2750263648Sbaptucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 2751263648Sbapt{ 2752279549Sbapt UCL_ARRAY_GET (vec, top); 2753263648Sbapt 2754264789Sbapt if (elt == NULL || top == NULL) { 2755264789Sbapt return false; 2756263648Sbapt } 2757263648Sbapt 2758279549Sbapt if (vec == NULL) { 2759279549Sbapt vec = UCL_ALLOC (sizeof (*vec)); 2760279549Sbapt kv_init (*vec); 2761279549Sbapt top->value.av = (void *)vec; 2762279549Sbapt kv_push (ucl_object_t *, *vec, elt); 2763263648Sbapt } 2764263648Sbapt else { 2765279549Sbapt /* Slow O(n) algorithm */ 2766279549Sbapt kv_prepend (ucl_object_t *, *vec, elt); 2767263648Sbapt } 2768279549Sbapt 2769264789Sbapt top->len ++; 2770263648Sbapt 2771264789Sbapt return true; 2772263648Sbapt} 2773263648Sbapt 2774275223Sbaptbool 2775275223Sbaptucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 2776275223Sbapt{ 2777279549Sbapt unsigned i; 2778290071Sbapt ucl_object_t *cp = NULL; 2779279549Sbapt ucl_object_t **obj; 2780275223Sbapt 2781275223Sbapt if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { 2782275223Sbapt return false; 2783275223Sbapt } 2784275223Sbapt 2785290071Sbapt if (copy) { 2786290071Sbapt cp = ucl_object_copy (elt); 2787290071Sbapt } 2788290071Sbapt else { 2789290071Sbapt cp = ucl_object_ref (elt); 2790290071Sbapt } 2791290071Sbapt 2792290071Sbapt UCL_ARRAY_GET (v1, top); 2793290071Sbapt UCL_ARRAY_GET (v2, cp); 2794290071Sbapt 2795298166Sbapt if (v1 && v2) { 2796298166Sbapt kv_concat (ucl_object_t *, *v1, *v2); 2797279549Sbapt 2798298166Sbapt for (i = v2->n; i < v1->n; i ++) { 2799298166Sbapt obj = &kv_A (*v1, i); 2800298166Sbapt if (*obj == NULL) { 2801298166Sbapt continue; 2802298166Sbapt } 2803298166Sbapt top->len ++; 2804279549Sbapt } 2805275223Sbapt } 2806275223Sbapt 2807275223Sbapt return true; 2808275223Sbapt} 2809275223Sbapt 2810263648Sbaptucl_object_t * 2811263648Sbaptucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 2812263648Sbapt{ 2813279549Sbapt UCL_ARRAY_GET (vec, top); 2814279549Sbapt ucl_object_t *ret = NULL; 2815279549Sbapt unsigned i; 2816263648Sbapt 2817290071Sbapt if (vec == NULL) { 2818290071Sbapt return NULL; 2819290071Sbapt } 2820290071Sbapt 2821279549Sbapt for (i = 0; i < vec->n; i ++) { 2822279549Sbapt if (kv_A (*vec, i) == elt) { 2823279549Sbapt kv_del (ucl_object_t *, *vec, i); 2824279549Sbapt ret = elt; 2825279549Sbapt top->len --; 2826279549Sbapt break; 2827263648Sbapt } 2828263648Sbapt } 2829263648Sbapt 2830279549Sbapt return ret; 2831263648Sbapt} 2832263648Sbapt 2833264789Sbaptconst ucl_object_t * 2834264789Sbaptucl_array_head (const ucl_object_t *top) 2835263648Sbapt{ 2836279549Sbapt UCL_ARRAY_GET (vec, top); 2837279549Sbapt 2838290071Sbapt if (vec == NULL || top == NULL || top->type != UCL_ARRAY || 2839290071Sbapt top->value.av == NULL) { 2840263648Sbapt return NULL; 2841263648Sbapt } 2842279549Sbapt 2843279549Sbapt return (vec->n > 0 ? vec->a[0] : NULL); 2844263648Sbapt} 2845263648Sbapt 2846264789Sbaptconst ucl_object_t * 2847264789Sbaptucl_array_tail (const ucl_object_t *top) 2848263648Sbapt{ 2849279549Sbapt UCL_ARRAY_GET (vec, top); 2850279549Sbapt 2851263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 2852263648Sbapt return NULL; 2853263648Sbapt } 2854279549Sbapt 2855279549Sbapt return (vec->n > 0 ? vec->a[vec->n - 1] : NULL); 2856263648Sbapt} 2857263648Sbapt 2858263648Sbaptucl_object_t * 2859263648Sbaptucl_array_pop_last (ucl_object_t *top) 2860263648Sbapt{ 2861279549Sbapt UCL_ARRAY_GET (vec, top); 2862279549Sbapt ucl_object_t **obj, *ret = NULL; 2863279549Sbapt 2864279549Sbapt if (vec != NULL && vec->n > 0) { 2865279549Sbapt obj = &kv_A (*vec, vec->n - 1); 2866279549Sbapt ret = *obj; 2867279549Sbapt kv_del (ucl_object_t *, *vec, vec->n - 1); 2868279549Sbapt top->len --; 2869279549Sbapt } 2870279549Sbapt 2871279549Sbapt return ret; 2872263648Sbapt} 2873263648Sbapt 2874263648Sbaptucl_object_t * 2875263648Sbaptucl_array_pop_first (ucl_object_t *top) 2876263648Sbapt{ 2877279549Sbapt UCL_ARRAY_GET (vec, top); 2878279549Sbapt ucl_object_t **obj, *ret = NULL; 2879279549Sbapt 2880279549Sbapt if (vec != NULL && vec->n > 0) { 2881279549Sbapt obj = &kv_A (*vec, 0); 2882279549Sbapt ret = *obj; 2883279549Sbapt kv_del (ucl_object_t *, *vec, 0); 2884279549Sbapt top->len --; 2885279549Sbapt } 2886279549Sbapt 2887279549Sbapt return ret; 2888263648Sbapt} 2889263648Sbapt 2890266636Sbaptconst ucl_object_t * 2891266636Sbaptucl_array_find_index (const ucl_object_t *top, unsigned int index) 2892266636Sbapt{ 2893279549Sbapt UCL_ARRAY_GET (vec, top); 2894266636Sbapt 2895279549Sbapt if (vec != NULL && vec->n > 0 && index < vec->n) { 2896279549Sbapt return kv_A (*vec, index); 2897266636Sbapt } 2898266636Sbapt 2899266636Sbapt return NULL; 2900266636Sbapt} 2901266636Sbapt 2902290071Sbaptunsigned int 2903290071Sbaptucl_array_index_of (ucl_object_t *top, ucl_object_t *elt) 2904290071Sbapt{ 2905290071Sbapt UCL_ARRAY_GET (vec, top); 2906290071Sbapt unsigned i; 2907290071Sbapt 2908290071Sbapt if (vec == NULL) { 2909290071Sbapt return (unsigned int)(-1); 2910290071Sbapt } 2911290071Sbapt 2912290071Sbapt for (i = 0; i < vec->n; i ++) { 2913290071Sbapt if (kv_A (*vec, i) == elt) { 2914290071Sbapt return i; 2915290071Sbapt } 2916290071Sbapt } 2917290071Sbapt 2918290071Sbapt return (unsigned int)(-1); 2919290071Sbapt} 2920290071Sbapt 2921263648Sbaptucl_object_t * 2922275223Sbaptucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt, 2923275223Sbapt unsigned int index) 2924275223Sbapt{ 2925279549Sbapt UCL_ARRAY_GET (vec, top); 2926279549Sbapt ucl_object_t *ret = NULL; 2927275223Sbapt 2928279549Sbapt if (vec != NULL && vec->n > 0 && index < vec->n) { 2929279549Sbapt ret = kv_A (*vec, index); 2930279549Sbapt kv_A (*vec, index) = elt; 2931275223Sbapt } 2932275223Sbapt 2933279549Sbapt return ret; 2934275223Sbapt} 2935275223Sbapt 2936275223Sbaptucl_object_t * 2937263648Sbaptucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 2938263648Sbapt{ 2939263648Sbapt 2940263648Sbapt if (head == NULL) { 2941263648Sbapt elt->next = NULL; 2942263648Sbapt elt->prev = elt; 2943263648Sbapt head = elt; 2944263648Sbapt } 2945263648Sbapt else { 2946263648Sbapt elt->prev = head->prev; 2947263648Sbapt head->prev->next = elt; 2948263648Sbapt head->prev = elt; 2949263648Sbapt elt->next = NULL; 2950263648Sbapt } 2951263648Sbapt 2952263648Sbapt return head; 2953263648Sbapt} 2954263648Sbapt 2955263648Sbaptbool 2956264789Sbaptucl_object_todouble_safe (const ucl_object_t *obj, double *target) 2957263648Sbapt{ 2958263648Sbapt if (obj == NULL || target == NULL) { 2959263648Sbapt return false; 2960263648Sbapt } 2961263648Sbapt switch (obj->type) { 2962263648Sbapt case UCL_INT: 2963263648Sbapt *target = obj->value.iv; /* Probaly could cause overflow */ 2964263648Sbapt break; 2965263648Sbapt case UCL_FLOAT: 2966263648Sbapt case UCL_TIME: 2967263648Sbapt *target = obj->value.dv; 2968263648Sbapt break; 2969263648Sbapt default: 2970263648Sbapt return false; 2971263648Sbapt } 2972263648Sbapt 2973263648Sbapt return true; 2974263648Sbapt} 2975263648Sbapt 2976263648Sbaptdouble 2977264789Sbaptucl_object_todouble (const ucl_object_t *obj) 2978263648Sbapt{ 2979263648Sbapt double result = 0.; 2980263648Sbapt 2981263648Sbapt ucl_object_todouble_safe (obj, &result); 2982263648Sbapt return result; 2983263648Sbapt} 2984263648Sbapt 2985263648Sbaptbool 2986264789Sbaptucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 2987263648Sbapt{ 2988263648Sbapt if (obj == NULL || target == NULL) { 2989263648Sbapt return false; 2990263648Sbapt } 2991263648Sbapt switch (obj->type) { 2992263648Sbapt case UCL_INT: 2993263648Sbapt *target = obj->value.iv; 2994263648Sbapt break; 2995263648Sbapt case UCL_FLOAT: 2996263648Sbapt case UCL_TIME: 2997263648Sbapt *target = obj->value.dv; /* Loosing of decimal points */ 2998263648Sbapt break; 2999263648Sbapt default: 3000263648Sbapt return false; 3001263648Sbapt } 3002263648Sbapt 3003263648Sbapt return true; 3004263648Sbapt} 3005263648Sbapt 3006263648Sbaptint64_t 3007264789Sbaptucl_object_toint (const ucl_object_t *obj) 3008263648Sbapt{ 3009263648Sbapt int64_t result = 0; 3010263648Sbapt 3011263648Sbapt ucl_object_toint_safe (obj, &result); 3012263648Sbapt return result; 3013263648Sbapt} 3014263648Sbapt 3015263648Sbaptbool 3016264789Sbaptucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 3017263648Sbapt{ 3018263648Sbapt if (obj == NULL || target == NULL) { 3019263648Sbapt return false; 3020263648Sbapt } 3021263648Sbapt switch (obj->type) { 3022263648Sbapt case UCL_BOOLEAN: 3023263648Sbapt *target = (obj->value.iv == true); 3024263648Sbapt break; 3025263648Sbapt default: 3026263648Sbapt return false; 3027263648Sbapt } 3028263648Sbapt 3029263648Sbapt return true; 3030263648Sbapt} 3031263648Sbapt 3032263648Sbaptbool 3033264789Sbaptucl_object_toboolean (const ucl_object_t *obj) 3034263648Sbapt{ 3035263648Sbapt bool result = false; 3036263648Sbapt 3037263648Sbapt ucl_object_toboolean_safe (obj, &result); 3038263648Sbapt return result; 3039263648Sbapt} 3040263648Sbapt 3041263648Sbaptbool 3042264789Sbaptucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 3043263648Sbapt{ 3044263648Sbapt if (obj == NULL || target == NULL) { 3045263648Sbapt return false; 3046263648Sbapt } 3047263648Sbapt 3048263648Sbapt switch (obj->type) { 3049263648Sbapt case UCL_STRING: 3050290071Sbapt if (!(obj->flags & UCL_OBJECT_BINARY)) { 3051290071Sbapt *target = ucl_copy_value_trash (obj); 3052290071Sbapt } 3053263648Sbapt break; 3054263648Sbapt default: 3055263648Sbapt return false; 3056263648Sbapt } 3057263648Sbapt 3058263648Sbapt return true; 3059263648Sbapt} 3060263648Sbapt 3061263648Sbaptconst char * 3062264789Sbaptucl_object_tostring (const ucl_object_t *obj) 3063263648Sbapt{ 3064263648Sbapt const char *result = NULL; 3065263648Sbapt 3066263648Sbapt ucl_object_tostring_safe (obj, &result); 3067263648Sbapt return result; 3068263648Sbapt} 3069263648Sbapt 3070263648Sbaptconst char * 3071264789Sbaptucl_object_tostring_forced (const ucl_object_t *obj) 3072263648Sbapt{ 3073290071Sbapt /* TODO: For binary strings we might encode string here */ 3074290071Sbapt if (!(obj->flags & UCL_OBJECT_BINARY)) { 3075290071Sbapt return ucl_copy_value_trash (obj); 3076290071Sbapt } 3077290071Sbapt 3078290071Sbapt return NULL; 3079263648Sbapt} 3080263648Sbapt 3081263648Sbaptbool 3082264789Sbaptucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 3083263648Sbapt{ 3084263648Sbapt if (obj == NULL || target == NULL) { 3085263648Sbapt return false; 3086263648Sbapt } 3087263648Sbapt switch (obj->type) { 3088263648Sbapt case UCL_STRING: 3089263648Sbapt *target = obj->value.sv; 3090263648Sbapt if (tlen != NULL) { 3091263648Sbapt *tlen = obj->len; 3092263648Sbapt } 3093263648Sbapt break; 3094263648Sbapt default: 3095263648Sbapt return false; 3096263648Sbapt } 3097263648Sbapt 3098263648Sbapt return true; 3099263648Sbapt} 3100263648Sbapt 3101263648Sbaptconst char * 3102264789Sbaptucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 3103263648Sbapt{ 3104263648Sbapt const char *result = NULL; 3105263648Sbapt 3106263648Sbapt ucl_object_tolstring_safe (obj, &result, tlen); 3107263648Sbapt return result; 3108263648Sbapt} 3109263648Sbapt 3110263648Sbaptconst char * 3111264789Sbaptucl_object_key (const ucl_object_t *obj) 3112263648Sbapt{ 3113263648Sbapt return ucl_copy_key_trash (obj); 3114263648Sbapt} 3115263648Sbapt 3116263648Sbaptconst char * 3117264789Sbaptucl_object_keyl (const ucl_object_t *obj, size_t *len) 3118263648Sbapt{ 3119263648Sbapt if (len == NULL || obj == NULL) { 3120263648Sbapt return NULL; 3121263648Sbapt } 3122263648Sbapt *len = obj->keylen; 3123263648Sbapt return obj->key; 3124263648Sbapt} 3125263648Sbapt 3126263648Sbaptucl_object_t * 3127264789Sbaptucl_object_ref (const ucl_object_t *obj) 3128263648Sbapt{ 3129264789Sbapt ucl_object_t *res = NULL; 3130264789Sbapt 3131263648Sbapt if (obj != NULL) { 3132275223Sbapt if (obj->flags & UCL_OBJECT_EPHEMERAL) { 3133275223Sbapt /* 3134275223Sbapt * Use deep copy for ephemeral objects, note that its refcount 3135275223Sbapt * is NOT increased, since ephemeral objects does not need refcount 3136275223Sbapt * at all 3137275223Sbapt */ 3138275223Sbapt res = ucl_object_copy (obj); 3139275223Sbapt } 3140275223Sbapt else { 3141275223Sbapt res = __DECONST (ucl_object_t *, obj); 3142264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 3143275223Sbapt (void)__sync_add_and_fetch (&res->ref, 1); 3144264789Sbapt#else 3145275223Sbapt res->ref ++; 3146264789Sbapt#endif 3147275223Sbapt } 3148263648Sbapt } 3149264789Sbapt return res; 3150263648Sbapt} 3151263648Sbapt 3152275223Sbaptstatic ucl_object_t * 3153275223Sbaptucl_object_copy_internal (const ucl_object_t *other, bool allow_array) 3154275223Sbapt{ 3155275223Sbapt 3156275223Sbapt ucl_object_t *new; 3157275223Sbapt ucl_object_iter_t it = NULL; 3158275223Sbapt const ucl_object_t *cur; 3159275223Sbapt 3160275223Sbapt new = malloc (sizeof (*new)); 3161275223Sbapt 3162275223Sbapt if (new != NULL) { 3163275223Sbapt memcpy (new, other, sizeof (*new)); 3164275223Sbapt if (other->flags & UCL_OBJECT_EPHEMERAL) { 3165275223Sbapt /* Copied object is always non ephemeral */ 3166275223Sbapt new->flags &= ~UCL_OBJECT_EPHEMERAL; 3167275223Sbapt } 3168275223Sbapt new->ref = 1; 3169275223Sbapt /* Unlink from others */ 3170275223Sbapt new->next = NULL; 3171275223Sbapt new->prev = new; 3172275223Sbapt 3173275223Sbapt /* deep copy of values stored */ 3174275223Sbapt if (other->trash_stack[UCL_TRASH_KEY] != NULL) { 3175275223Sbapt new->trash_stack[UCL_TRASH_KEY] = 3176275223Sbapt strdup (other->trash_stack[UCL_TRASH_KEY]); 3177275223Sbapt if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { 3178275223Sbapt new->key = new->trash_stack[UCL_TRASH_KEY]; 3179275223Sbapt } 3180275223Sbapt } 3181275223Sbapt if (other->trash_stack[UCL_TRASH_VALUE] != NULL) { 3182275223Sbapt new->trash_stack[UCL_TRASH_VALUE] = 3183275223Sbapt strdup (other->trash_stack[UCL_TRASH_VALUE]); 3184275223Sbapt if (new->type == UCL_STRING) { 3185275223Sbapt new->value.sv = new->trash_stack[UCL_TRASH_VALUE]; 3186275223Sbapt } 3187275223Sbapt } 3188275223Sbapt 3189275223Sbapt if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) { 3190275223Sbapt /* reset old value */ 3191275223Sbapt memset (&new->value, 0, sizeof (new->value)); 3192275223Sbapt 3193298166Sbapt while ((cur = ucl_object_iterate (other, &it, true)) != NULL) { 3194275223Sbapt if (other->type == UCL_ARRAY) { 3195275223Sbapt ucl_array_append (new, ucl_object_copy_internal (cur, false)); 3196275223Sbapt } 3197275223Sbapt else { 3198275223Sbapt ucl_object_t *cp = ucl_object_copy_internal (cur, true); 3199275223Sbapt if (cp != NULL) { 3200275223Sbapt ucl_object_insert_key (new, cp, cp->key, cp->keylen, 3201275223Sbapt false); 3202275223Sbapt } 3203275223Sbapt } 3204275223Sbapt } 3205275223Sbapt } 3206275223Sbapt else if (allow_array && other->next != NULL) { 3207275223Sbapt LL_FOREACH (other->next, cur) { 3208275223Sbapt ucl_object_t *cp = ucl_object_copy_internal (cur, false); 3209275223Sbapt if (cp != NULL) { 3210275223Sbapt DL_APPEND (new, cp); 3211275223Sbapt } 3212275223Sbapt } 3213275223Sbapt } 3214275223Sbapt } 3215275223Sbapt 3216275223Sbapt return new; 3217275223Sbapt} 3218275223Sbapt 3219275223Sbaptucl_object_t * 3220275223Sbaptucl_object_copy (const ucl_object_t *other) 3221275223Sbapt{ 3222275223Sbapt return ucl_object_copy_internal (other, true); 3223275223Sbapt} 3224275223Sbapt 3225263648Sbaptvoid 3226263648Sbaptucl_object_unref (ucl_object_t *obj) 3227263648Sbapt{ 3228264789Sbapt if (obj != NULL) { 3229264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 3230264789Sbapt unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 3231264789Sbapt if (rc == 0) { 3232264789Sbapt#else 3233264789Sbapt if (--obj->ref == 0) { 3234264789Sbapt#endif 3235264789Sbapt ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 3236264789Sbapt } 3237263648Sbapt } 3238263648Sbapt} 3239263648Sbapt 3240263648Sbaptint 3241264789Sbaptucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 3242263648Sbapt{ 3243264789Sbapt const ucl_object_t *it1, *it2; 3244263648Sbapt ucl_object_iter_t iter = NULL; 3245263648Sbapt int ret = 0; 3246263648Sbapt 3247263648Sbapt if (o1->type != o2->type) { 3248263648Sbapt return (o1->type) - (o2->type); 3249263648Sbapt } 3250263648Sbapt 3251263648Sbapt switch (o1->type) { 3252263648Sbapt case UCL_STRING: 3253279549Sbapt if (o1->len == o2->len && o1->len > 0) { 3254263648Sbapt ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 3255263648Sbapt } 3256263648Sbapt else { 3257263648Sbapt ret = o1->len - o2->len; 3258263648Sbapt } 3259263648Sbapt break; 3260263648Sbapt case UCL_FLOAT: 3261263648Sbapt case UCL_INT: 3262263648Sbapt case UCL_TIME: 3263263648Sbapt ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 3264263648Sbapt break; 3265263648Sbapt case UCL_BOOLEAN: 3266263648Sbapt ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 3267263648Sbapt break; 3268263648Sbapt case UCL_ARRAY: 3269279549Sbapt if (o1->len == o2->len && o1->len > 0) { 3270279549Sbapt UCL_ARRAY_GET (vec1, o1); 3271279549Sbapt UCL_ARRAY_GET (vec2, o2); 3272279549Sbapt unsigned i; 3273279549Sbapt 3274263648Sbapt /* Compare all elements in both arrays */ 3275279549Sbapt for (i = 0; i < vec1->n; i ++) { 3276279549Sbapt it1 = kv_A (*vec1, i); 3277279549Sbapt it2 = kv_A (*vec2, i); 3278279549Sbapt 3279279549Sbapt if (it1 == NULL && it2 != NULL) { 3280279549Sbapt return -1; 3281263648Sbapt } 3282279549Sbapt else if (it2 == NULL && it1 != NULL) { 3283279549Sbapt return 1; 3284279549Sbapt } 3285279549Sbapt else if (it1 != NULL && it2 != NULL) { 3286279549Sbapt ret = ucl_object_compare (it1, it2); 3287279549Sbapt if (ret != 0) { 3288279549Sbapt break; 3289279549Sbapt } 3290279549Sbapt } 3291263648Sbapt } 3292263648Sbapt } 3293263648Sbapt else { 3294263648Sbapt ret = o1->len - o2->len; 3295263648Sbapt } 3296263648Sbapt break; 3297263648Sbapt case UCL_OBJECT: 3298279549Sbapt if (o1->len == o2->len && o1->len > 0) { 3299298166Sbapt while ((it1 = ucl_object_iterate (o1, &iter, true)) != NULL) { 3300298166Sbapt it2 = ucl_object_lookup (o2, ucl_object_key (it1)); 3301263648Sbapt if (it2 == NULL) { 3302263648Sbapt ret = 1; 3303263648Sbapt break; 3304263648Sbapt } 3305263648Sbapt ret = ucl_object_compare (it1, it2); 3306263648Sbapt if (ret != 0) { 3307263648Sbapt break; 3308263648Sbapt } 3309263648Sbapt } 3310263648Sbapt } 3311263648Sbapt else { 3312263648Sbapt ret = o1->len - o2->len; 3313263648Sbapt } 3314263648Sbapt break; 3315263648Sbapt default: 3316263648Sbapt ret = 0; 3317263648Sbapt break; 3318263648Sbapt } 3319263648Sbapt 3320263648Sbapt return ret; 3321263648Sbapt} 3322263648Sbapt 3323298166Sbaptint 3324298166Sbaptucl_object_compare_qsort (const ucl_object_t **o1, 3325298166Sbapt const ucl_object_t **o2) 3326298166Sbapt{ 3327298166Sbapt return ucl_object_compare (*o1, *o2); 3328298166Sbapt} 3329298166Sbapt 3330263648Sbaptvoid 3331263648Sbaptucl_object_array_sort (ucl_object_t *ar, 3332290071Sbapt int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2)) 3333263648Sbapt{ 3334279549Sbapt UCL_ARRAY_GET (vec, ar); 3335279549Sbapt 3336263648Sbapt if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 3337263648Sbapt return; 3338263648Sbapt } 3339263648Sbapt 3340279549Sbapt qsort (vec->a, vec->n, sizeof (ucl_object_t *), 3341279549Sbapt (int (*)(const void *, const void *))cmp); 3342263648Sbapt} 3343275223Sbapt 3344275223Sbapt#define PRIOBITS 4 3345275223Sbapt 3346275223Sbaptunsigned int 3347275223Sbaptucl_object_get_priority (const ucl_object_t *obj) 3348275223Sbapt{ 3349275223Sbapt if (obj == NULL) { 3350275223Sbapt return 0; 3351275223Sbapt } 3352275223Sbapt 3353275223Sbapt return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS)); 3354275223Sbapt} 3355275223Sbapt 3356275223Sbaptvoid 3357275223Sbaptucl_object_set_priority (ucl_object_t *obj, 3358275223Sbapt unsigned int priority) 3359275223Sbapt{ 3360275223Sbapt if (obj != NULL) { 3361275223Sbapt priority &= (0x1 << PRIOBITS) - 1; 3362290071Sbapt priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS); 3363290071Sbapt priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) - 3364290071Sbapt PRIOBITS)) - 1); 3365290071Sbapt obj->flags = priority; 3366275223Sbapt } 3367275223Sbapt} 3368298166Sbapt 3369298166Sbaptbool 3370298166Sbaptucl_object_string_to_type (const char *input, ucl_type_t *res) 3371298166Sbapt{ 3372298166Sbapt if (strcasecmp (input, "object") == 0) { 3373298166Sbapt *res = UCL_OBJECT; 3374298166Sbapt } 3375298166Sbapt else if (strcasecmp (input, "array") == 0) { 3376298166Sbapt *res = UCL_ARRAY; 3377298166Sbapt } 3378298166Sbapt else if (strcasecmp (input, "integer") == 0) { 3379298166Sbapt *res = UCL_INT; 3380298166Sbapt } 3381298166Sbapt else if (strcasecmp (input, "number") == 0) { 3382298166Sbapt *res = UCL_FLOAT; 3383298166Sbapt } 3384298166Sbapt else if (strcasecmp (input, "string") == 0) { 3385298166Sbapt *res = UCL_STRING; 3386298166Sbapt } 3387298166Sbapt else if (strcasecmp (input, "boolean") == 0) { 3388298166Sbapt *res = UCL_BOOLEAN; 3389298166Sbapt } 3390298166Sbapt else if (strcasecmp (input, "null") == 0) { 3391298166Sbapt *res = UCL_NULL; 3392298166Sbapt } 3393298166Sbapt else if (strcasecmp (input, "userdata") == 0) { 3394298166Sbapt *res = UCL_USERDATA; 3395298166Sbapt } 3396298166Sbapt else { 3397298166Sbapt return false; 3398298166Sbapt } 3399298166Sbapt 3400298166Sbapt return true; 3401298166Sbapt} 3402298166Sbapt 3403298166Sbaptconst char * 3404298166Sbaptucl_object_type_to_string (ucl_type_t type) 3405298166Sbapt{ 3406298166Sbapt const char *res = "unknown"; 3407298166Sbapt 3408298166Sbapt switch (type) { 3409298166Sbapt case UCL_OBJECT: 3410298166Sbapt res = "object"; 3411298166Sbapt break; 3412298166Sbapt case UCL_ARRAY: 3413298166Sbapt res = "array"; 3414298166Sbapt break; 3415298166Sbapt case UCL_INT: 3416298166Sbapt res = "integer"; 3417298166Sbapt break; 3418298166Sbapt case UCL_FLOAT: 3419298166Sbapt case UCL_TIME: 3420298166Sbapt res = "number"; 3421298166Sbapt break; 3422298166Sbapt case UCL_STRING: 3423298166Sbapt res = "string"; 3424298166Sbapt break; 3425298166Sbapt case UCL_BOOLEAN: 3426298166Sbapt res = "boolean"; 3427298166Sbapt break; 3428298166Sbapt case UCL_USERDATA: 3429298166Sbapt res = "userdata"; 3430298166Sbapt break; 3431298166Sbapt case UCL_NULL: 3432298166Sbapt res = "null"; 3433298166Sbapt break; 3434298166Sbapt } 3435298166Sbapt 3436298166Sbapt return res; 3437298166Sbapt} 3438298166Sbapt 3439298166Sbaptconst ucl_object_t * 3440298166Sbaptucl_parser_get_comments (struct ucl_parser *parser) 3441298166Sbapt{ 3442298166Sbapt if (parser && parser->comments) { 3443298166Sbapt return parser->comments; 3444298166Sbapt } 3445298166Sbapt 3446298166Sbapt return NULL; 3447298166Sbapt} 3448298166Sbapt 3449298166Sbaptconst ucl_object_t * 3450298166Sbaptucl_comments_find (const ucl_object_t *comments, 3451298166Sbapt const ucl_object_t *srch) 3452298166Sbapt{ 3453298166Sbapt if (comments && srch) { 3454298166Sbapt return ucl_object_lookup_len (comments, (const char *)&srch, 3455298166Sbapt sizeof (void *)); 3456298166Sbapt } 3457298166Sbapt 3458298166Sbapt return NULL; 3459298166Sbapt} 3460298166Sbapt 3461298166Sbaptbool 3462298166Sbaptucl_comments_move (ucl_object_t *comments, 3463298166Sbapt const ucl_object_t *from, const ucl_object_t *to) 3464298166Sbapt{ 3465298166Sbapt const ucl_object_t *found; 3466298166Sbapt ucl_object_t *obj; 3467298166Sbapt 3468298166Sbapt if (comments && from && to) { 3469298166Sbapt found = ucl_object_lookup_len (comments, 3470298166Sbapt (const char *)&from, sizeof (void *)); 3471298166Sbapt 3472298166Sbapt if (found) { 3473298166Sbapt /* Replace key */ 3474298166Sbapt obj = ucl_object_ref (found); 3475298166Sbapt ucl_object_delete_keyl (comments, (const char *)&from, 3476298166Sbapt sizeof (void *)); 3477298166Sbapt ucl_object_insert_key (comments, obj, (const char *)&to, 3478298166Sbapt sizeof (void *), true); 3479298166Sbapt 3480298166Sbapt return true; 3481298166Sbapt } 3482298166Sbapt } 3483298166Sbapt 3484298166Sbapt return false; 3485298166Sbapt} 3486298166Sbapt 3487298166Sbaptvoid 3488298166Sbaptucl_comments_add (ucl_object_t *comments, const ucl_object_t *obj, 3489298166Sbapt const char *comment) 3490298166Sbapt{ 3491298166Sbapt if (comments && obj && comment) { 3492298166Sbapt ucl_object_insert_key (comments, ucl_object_fromstring (comment), 3493298166Sbapt (const char *)&obj, sizeof (void *), true); 3494298166Sbapt } 3495298166Sbapt} 3496