ucl_util.c revision 275223
1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov 2262395Sbapt * All rights reserved. 3262395Sbapt * 4262395Sbapt * Redistribution and use in source and binary forms, with or without 5262395Sbapt * modification, are permitted provided that the following conditions are met: 6262395Sbapt * * Redistributions of source code must retain the above copyright 7262395Sbapt * notice, this list of conditions and the following disclaimer. 8262395Sbapt * * Redistributions in binary form must reproduce the above copyright 9262395Sbapt * notice, this list of conditions and the following disclaimer in the 10262395Sbapt * documentation and/or other materials provided with the distribution. 11262395Sbapt * 12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22262395Sbapt */ 23262395Sbapt 24262395Sbapt#include "ucl.h" 25262395Sbapt#include "ucl_internal.h" 26262395Sbapt#include "ucl_chartable.h" 27262395Sbapt 28275223Sbapt#include <glob.h> 29275223Sbapt 30263648Sbapt#ifdef HAVE_LIBGEN_H 31262395Sbapt#include <libgen.h> /* For dirname */ 32263648Sbapt#endif 33262395Sbapt 34262395Sbapt#ifdef HAVE_OPENSSL 35262395Sbapt#include <openssl/err.h> 36262395Sbapt#include <openssl/sha.h> 37262395Sbapt#include <openssl/rsa.h> 38262395Sbapt#include <openssl/ssl.h> 39262395Sbapt#include <openssl/evp.h> 40262395Sbapt#endif 41262395Sbapt 42263648Sbapt#ifdef CURL_FOUND 43263648Sbapt#include <curl/curl.h> 44263648Sbapt#endif 45263648Sbapt#ifdef HAVE_FETCH_H 46263648Sbapt#include <fetch.h> 47263648Sbapt#endif 48263648Sbapt 49262975Sbapt#ifdef _WIN32 50262975Sbapt#include <windows.h> 51262975Sbapt 52263648Sbapt#ifndef PROT_READ 53262975Sbapt#define PROT_READ 1 54263648Sbapt#endif 55263648Sbapt#ifndef PROT_WRITE 56262975Sbapt#define PROT_WRITE 2 57263648Sbapt#endif 58263648Sbapt#ifndef PROT_READWRITE 59262975Sbapt#define PROT_READWRITE 3 60263648Sbapt#endif 61263648Sbapt#ifndef MAP_SHARED 62262975Sbapt#define MAP_SHARED 1 63263648Sbapt#endif 64263648Sbapt#ifndef MAP_PRIVATE 65262975Sbapt#define MAP_PRIVATE 2 66263648Sbapt#endif 67263648Sbapt#ifndef MAP_FAILED 68262975Sbapt#define MAP_FAILED ((void *) -1) 69263648Sbapt#endif 70262975Sbapt 71263648Sbaptstatic void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 72262975Sbapt{ 73262975Sbapt void *map = NULL; 74262975Sbapt HANDLE handle = INVALID_HANDLE_VALUE; 75262975Sbapt 76262975Sbapt switch (prot) { 77262975Sbapt default: 78262975Sbapt case PROT_READ: 79262975Sbapt { 80262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 81262975Sbapt if (!handle) break; 82262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 83262975Sbapt CloseHandle(handle); 84262975Sbapt break; 85262975Sbapt } 86262975Sbapt case PROT_WRITE: 87262975Sbapt { 88262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 89262975Sbapt if (!handle) break; 90262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 91262975Sbapt CloseHandle(handle); 92262975Sbapt break; 93262975Sbapt } 94262975Sbapt case PROT_READWRITE: 95262975Sbapt { 96262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 97262975Sbapt if (!handle) break; 98262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 99262975Sbapt CloseHandle(handle); 100262975Sbapt break; 101262975Sbapt } 102262975Sbapt } 103262975Sbapt if (map == (void *) NULL) { 104262975Sbapt return (void *) MAP_FAILED; 105262975Sbapt } 106262975Sbapt return (void *) ((char *) map + offset); 107262975Sbapt} 108262975Sbapt 109263648Sbaptstatic int ucl_munmap(void *map,size_t length) 110262975Sbapt{ 111262975Sbapt if (!UnmapViewOfFile(map)) { 112262975Sbapt return(-1); 113262975Sbapt } 114262975Sbapt return(0); 115262975Sbapt} 116262975Sbapt 117263648Sbaptstatic char* ucl_realpath(const char *path, char *resolved_path) { 118262975Sbapt char *p; 119262975Sbapt char tmp[MAX_PATH + 1]; 120262975Sbapt strncpy(tmp, path, sizeof(tmp)-1); 121262975Sbapt p = tmp; 122262975Sbapt while(*p) { 123262975Sbapt if (*p == '/') *p = '\\'; 124262975Sbapt p++; 125262975Sbapt } 126262975Sbapt return _fullpath(resolved_path, tmp, MAX_PATH); 127262975Sbapt} 128263648Sbapt#else 129263648Sbapt#define ucl_mmap mmap 130263648Sbapt#define ucl_munmap munmap 131263648Sbapt#define ucl_realpath realpath 132262975Sbapt#endif 133262975Sbapt 134264789Sbapttypedef void (*ucl_object_dtor) (ucl_object_t *obj); 135264789Sbaptstatic void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 136264789Sbapt ucl_object_dtor dtor); 137264789Sbaptstatic void ucl_object_dtor_unref (ucl_object_t *obj); 138262395Sbapt 139262395Sbaptstatic void 140264789Sbaptucl_object_dtor_free (ucl_object_t *obj) 141262395Sbapt{ 142264789Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 143264789Sbapt UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 144264789Sbapt } 145264789Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 146264789Sbapt UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 147264789Sbapt } 148275223Sbapt /* Do not free ephemeral objects */ 149275223Sbapt if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) { 150275223Sbapt if (obj->type != UCL_USERDATA) { 151275223Sbapt UCL_FREE (sizeof (ucl_object_t), obj); 152275223Sbapt } 153275223Sbapt else { 154275223Sbapt struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj; 155275223Sbapt if (ud->dtor) { 156275223Sbapt ud->dtor (obj->value.ud); 157275223Sbapt } 158275223Sbapt UCL_FREE (sizeof (*ud), obj); 159275223Sbapt } 160275223Sbapt } 161264789Sbapt} 162264789Sbapt 163264789Sbapt/* 164264789Sbapt * This is a helper function that performs exactly the same as 165264789Sbapt * `ucl_object_unref` but it doesn't iterate over elements allowing 166264789Sbapt * to use it for individual elements of arrays and multiple values 167264789Sbapt */ 168264789Sbaptstatic void 169264789Sbaptucl_object_dtor_unref_single (ucl_object_t *obj) 170264789Sbapt{ 171264789Sbapt if (obj != NULL) { 172264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 173264789Sbapt unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 174264789Sbapt if (rc == 0) { 175264789Sbapt#else 176264789Sbapt if (--obj->ref == 0) { 177264789Sbapt#endif 178264789Sbapt ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 179264789Sbapt } 180264789Sbapt } 181264789Sbapt} 182264789Sbapt 183264789Sbaptstatic void 184264789Sbaptucl_object_dtor_unref (ucl_object_t *obj) 185264789Sbapt{ 186264789Sbapt if (obj->ref == 0) { 187264789Sbapt ucl_object_dtor_free (obj); 188264789Sbapt } 189264789Sbapt else { 190264789Sbapt /* This may cause dtor unref being called one more time */ 191264789Sbapt ucl_object_dtor_unref_single (obj); 192264789Sbapt } 193264789Sbapt} 194264789Sbapt 195264789Sbaptstatic void 196264789Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 197264789Sbapt{ 198262395Sbapt ucl_object_t *sub, *tmp; 199262395Sbapt 200262395Sbapt while (obj != NULL) { 201262395Sbapt if (obj->type == UCL_ARRAY) { 202262395Sbapt sub = obj->value.av; 203262395Sbapt while (sub != NULL) { 204262395Sbapt tmp = sub->next; 205264789Sbapt dtor (sub); 206262395Sbapt sub = tmp; 207262395Sbapt } 208262395Sbapt } 209262395Sbapt else if (obj->type == UCL_OBJECT) { 210262395Sbapt if (obj->value.ov != NULL) { 211264789Sbapt ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); 212262395Sbapt } 213262395Sbapt } 214262395Sbapt tmp = obj->next; 215264789Sbapt dtor (obj); 216262395Sbapt obj = tmp; 217262395Sbapt 218262395Sbapt if (!allow_rec) { 219262395Sbapt break; 220262395Sbapt } 221262395Sbapt } 222262395Sbapt} 223262395Sbapt 224262395Sbaptvoid 225262395Sbaptucl_object_free (ucl_object_t *obj) 226262395Sbapt{ 227264789Sbapt ucl_object_free_internal (obj, true, ucl_object_dtor_free); 228262395Sbapt} 229262395Sbapt 230262395Sbaptsize_t 231262395Sbaptucl_unescape_json_string (char *str, size_t len) 232262395Sbapt{ 233262395Sbapt char *t = str, *h = str; 234262395Sbapt int i, uval; 235262395Sbapt 236263648Sbapt if (len <= 1) { 237263648Sbapt return len; 238263648Sbapt } 239262395Sbapt /* t is target (tortoise), h is source (hare) */ 240262395Sbapt 241262395Sbapt while (len) { 242262395Sbapt if (*h == '\\') { 243262395Sbapt h ++; 244262395Sbapt switch (*h) { 245262395Sbapt case 'n': 246262395Sbapt *t++ = '\n'; 247262395Sbapt break; 248262395Sbapt case 'r': 249262395Sbapt *t++ = '\r'; 250262395Sbapt break; 251262395Sbapt case 'b': 252262395Sbapt *t++ = '\b'; 253262395Sbapt break; 254262395Sbapt case 't': 255262395Sbapt *t++ = '\t'; 256262395Sbapt break; 257262395Sbapt case 'f': 258262395Sbapt *t++ = '\f'; 259262395Sbapt break; 260262395Sbapt case '\\': 261262395Sbapt *t++ = '\\'; 262262395Sbapt break; 263262395Sbapt case '"': 264262395Sbapt *t++ = '"'; 265262395Sbapt break; 266262395Sbapt case 'u': 267262395Sbapt /* Unicode escape */ 268262395Sbapt uval = 0; 269263648Sbapt if (len > 3) { 270263648Sbapt for (i = 0; i < 4; i++) { 271263648Sbapt uval <<= 4; 272263648Sbapt if (isdigit (h[i])) { 273263648Sbapt uval += h[i] - '0'; 274263648Sbapt } 275263648Sbapt else if (h[i] >= 'a' && h[i] <= 'f') { 276263648Sbapt uval += h[i] - 'a' + 10; 277263648Sbapt } 278263648Sbapt else if (h[i] >= 'A' && h[i] <= 'F') { 279263648Sbapt uval += h[i] - 'A' + 10; 280263648Sbapt } 281263648Sbapt else { 282263648Sbapt break; 283263648Sbapt } 284262395Sbapt } 285263648Sbapt h += 3; 286263648Sbapt len -= 3; 287263648Sbapt /* Encode */ 288263648Sbapt if(uval < 0x80) { 289263648Sbapt t[0] = (char)uval; 290263648Sbapt t ++; 291262395Sbapt } 292263648Sbapt else if(uval < 0x800) { 293263648Sbapt t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 294263648Sbapt t[1] = 0x80 + ((uval & 0x03F)); 295263648Sbapt t += 2; 296262395Sbapt } 297263648Sbapt else if(uval < 0x10000) { 298263648Sbapt t[0] = 0xE0 + ((uval & 0xF000) >> 12); 299263648Sbapt t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 300263648Sbapt t[2] = 0x80 + ((uval & 0x003F)); 301263648Sbapt t += 3; 302263648Sbapt } 303263648Sbapt else if(uval <= 0x10FFFF) { 304263648Sbapt t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 305263648Sbapt t[1] = 0x80 + ((uval & 0x03F000) >> 12); 306263648Sbapt t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 307263648Sbapt t[3] = 0x80 + ((uval & 0x00003F)); 308263648Sbapt t += 4; 309263648Sbapt } 310263648Sbapt else { 311263648Sbapt *t++ = '?'; 312263648Sbapt } 313262395Sbapt } 314262395Sbapt else { 315263648Sbapt *t++ = 'u'; 316262395Sbapt } 317262395Sbapt break; 318262395Sbapt default: 319262395Sbapt *t++ = *h; 320262395Sbapt break; 321262395Sbapt } 322262395Sbapt h ++; 323262395Sbapt len --; 324262395Sbapt } 325262395Sbapt else { 326262395Sbapt *t++ = *h++; 327262395Sbapt } 328262395Sbapt len --; 329262395Sbapt } 330262395Sbapt *t = '\0'; 331262395Sbapt 332262395Sbapt return (t - str); 333262395Sbapt} 334262395Sbapt 335264789Sbaptchar * 336264789Sbaptucl_copy_key_trash (const ucl_object_t *obj) 337262395Sbapt{ 338264789Sbapt ucl_object_t *deconst; 339264789Sbapt 340263648Sbapt if (obj == NULL) { 341263648Sbapt return NULL; 342263648Sbapt } 343262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 344264789Sbapt deconst = __DECONST (ucl_object_t *, obj); 345264789Sbapt deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 346264789Sbapt if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 347264789Sbapt memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 348264789Sbapt deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 349262395Sbapt } 350264789Sbapt deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 351264789Sbapt deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 352262395Sbapt } 353262395Sbapt 354262395Sbapt return obj->trash_stack[UCL_TRASH_KEY]; 355262395Sbapt} 356262395Sbapt 357264789Sbaptchar * 358264789Sbaptucl_copy_value_trash (const ucl_object_t *obj) 359262395Sbapt{ 360264789Sbapt ucl_object_t *deconst; 361264789Sbapt 362263648Sbapt if (obj == NULL) { 363263648Sbapt return NULL; 364263648Sbapt } 365262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 366264789Sbapt deconst = __DECONST (ucl_object_t *, obj); 367262395Sbapt if (obj->type == UCL_STRING) { 368264789Sbapt 369262395Sbapt /* Special case for strings */ 370264789Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 371264789Sbapt if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 372264789Sbapt memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 373264789Sbapt deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 374264789Sbapt deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 375262395Sbapt } 376262395Sbapt } 377262395Sbapt else { 378262395Sbapt /* Just emit value in json notation */ 379264789Sbapt deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 380264789Sbapt deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 381262395Sbapt } 382264789Sbapt deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 383262395Sbapt } 384262395Sbapt return obj->trash_stack[UCL_TRASH_VALUE]; 385262395Sbapt} 386262395Sbapt 387262975SbaptUCL_EXTERN ucl_object_t* 388262395Sbaptucl_parser_get_object (struct ucl_parser *parser) 389262395Sbapt{ 390262395Sbapt if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 391262395Sbapt return ucl_object_ref (parser->top_obj); 392262395Sbapt } 393262395Sbapt 394262395Sbapt return NULL; 395262395Sbapt} 396262395Sbapt 397262975SbaptUCL_EXTERN void 398262395Sbaptucl_parser_free (struct ucl_parser *parser) 399262395Sbapt{ 400262395Sbapt struct ucl_stack *stack, *stmp; 401262395Sbapt struct ucl_macro *macro, *mtmp; 402262395Sbapt struct ucl_chunk *chunk, *ctmp; 403262395Sbapt struct ucl_pubkey *key, *ktmp; 404262395Sbapt struct ucl_variable *var, *vtmp; 405262395Sbapt 406263648Sbapt if (parser == NULL) { 407263648Sbapt return; 408263648Sbapt } 409263648Sbapt 410262395Sbapt if (parser->top_obj != NULL) { 411262395Sbapt ucl_object_unref (parser->top_obj); 412262395Sbapt } 413262395Sbapt 414262395Sbapt LL_FOREACH_SAFE (parser->stack, stack, stmp) { 415262395Sbapt free (stack); 416262395Sbapt } 417262395Sbapt HASH_ITER (hh, parser->macroes, macro, mtmp) { 418262395Sbapt free (macro->name); 419262395Sbapt HASH_DEL (parser->macroes, macro); 420262395Sbapt UCL_FREE (sizeof (struct ucl_macro), macro); 421262395Sbapt } 422262395Sbapt LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 423262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 424262395Sbapt } 425262395Sbapt LL_FOREACH_SAFE (parser->keys, key, ktmp) { 426262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), key); 427262395Sbapt } 428262395Sbapt LL_FOREACH_SAFE (parser->variables, var, vtmp) { 429262395Sbapt free (var->value); 430262395Sbapt free (var->var); 431262395Sbapt UCL_FREE (sizeof (struct ucl_variable), var); 432262395Sbapt } 433262395Sbapt 434262395Sbapt if (parser->err != NULL) { 435275223Sbapt utstring_free (parser->err); 436262395Sbapt } 437262395Sbapt 438275223Sbapt if (parser->cur_file) { 439275223Sbapt free (parser->cur_file); 440275223Sbapt } 441275223Sbapt 442262395Sbapt UCL_FREE (sizeof (struct ucl_parser), parser); 443262395Sbapt} 444262395Sbapt 445262975SbaptUCL_EXTERN const char * 446262395Sbaptucl_parser_get_error(struct ucl_parser *parser) 447262395Sbapt{ 448263648Sbapt if (parser == NULL) { 449263648Sbapt return NULL; 450263648Sbapt } 451263648Sbapt 452262395Sbapt if (parser->err == NULL) 453262395Sbapt return NULL; 454262395Sbapt 455262395Sbapt return utstring_body(parser->err); 456262395Sbapt} 457262395Sbapt 458262975SbaptUCL_EXTERN bool 459262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 460262395Sbapt{ 461262395Sbapt#ifndef HAVE_OPENSSL 462262395Sbapt ucl_create_err (&parser->err, "cannot check signatures without openssl"); 463262395Sbapt return false; 464262395Sbapt#else 465262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 466262395Sbapt ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 467262395Sbapt return EXIT_FAILURE; 468262395Sbapt# else 469262395Sbapt struct ucl_pubkey *nkey; 470262395Sbapt BIO *mem; 471262395Sbapt 472262395Sbapt mem = BIO_new_mem_buf ((void *)key, len); 473262395Sbapt nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 474263648Sbapt if (nkey == NULL) { 475263648Sbapt ucl_create_err (&parser->err, "cannot allocate memory for key"); 476263648Sbapt return false; 477263648Sbapt } 478262395Sbapt nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 479262395Sbapt BIO_free (mem); 480262395Sbapt if (nkey->key == NULL) { 481262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), nkey); 482262395Sbapt ucl_create_err (&parser->err, "%s", 483262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 484262395Sbapt return false; 485262395Sbapt } 486262395Sbapt LL_PREPEND (parser->keys, nkey); 487262395Sbapt# endif 488262395Sbapt#endif 489262395Sbapt return true; 490262395Sbapt} 491262395Sbapt 492262395Sbapt#ifdef CURL_FOUND 493262395Sbaptstruct ucl_curl_cbdata { 494262395Sbapt unsigned char *buf; 495262395Sbapt size_t buflen; 496262395Sbapt}; 497262395Sbapt 498262395Sbaptstatic size_t 499262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 500262395Sbapt{ 501262395Sbapt struct ucl_curl_cbdata *cbdata = ud; 502262395Sbapt size_t realsize = size * nmemb; 503262395Sbapt 504262395Sbapt cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 505262395Sbapt if (cbdata->buf == NULL) { 506262395Sbapt return 0; 507262395Sbapt } 508262395Sbapt 509262395Sbapt memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 510262395Sbapt cbdata->buflen += realsize; 511262395Sbapt cbdata->buf[cbdata->buflen] = 0; 512262395Sbapt 513262395Sbapt return realsize; 514262395Sbapt} 515262395Sbapt#endif 516262395Sbapt 517262395Sbapt/** 518262395Sbapt * Fetch a url and save results to the memory buffer 519262395Sbapt * @param url url to fetch 520262395Sbapt * @param len length of url 521262395Sbapt * @param buf target buffer 522262395Sbapt * @param buflen target length 523262395Sbapt * @return 524262395Sbapt */ 525262395Sbaptstatic bool 526262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 527262395Sbapt UT_string **err, bool must_exist) 528262395Sbapt{ 529262395Sbapt 530262395Sbapt#ifdef HAVE_FETCH_H 531262395Sbapt struct url *fetch_url; 532262395Sbapt struct url_stat us; 533262395Sbapt FILE *in; 534262395Sbapt 535262395Sbapt fetch_url = fetchParseURL (url); 536262395Sbapt if (fetch_url == NULL) { 537262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 538262395Sbapt url, strerror (errno)); 539262395Sbapt return false; 540262395Sbapt } 541262395Sbapt if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 542262395Sbapt if (!must_exist) { 543262395Sbapt ucl_create_err (err, "cannot fetch URL %s: %s", 544262395Sbapt url, strerror (errno)); 545262395Sbapt } 546262395Sbapt fetchFreeURL (fetch_url); 547262395Sbapt return false; 548262395Sbapt } 549262395Sbapt 550262395Sbapt *buflen = us.size; 551262395Sbapt *buf = malloc (*buflen); 552262395Sbapt if (*buf == NULL) { 553262395Sbapt ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 554262395Sbapt url, strerror (errno)); 555262395Sbapt fclose (in); 556262395Sbapt fetchFreeURL (fetch_url); 557262395Sbapt return false; 558262395Sbapt } 559262395Sbapt 560262395Sbapt if (fread (*buf, *buflen, 1, in) != 1) { 561262395Sbapt ucl_create_err (err, "cannot read URL %s: %s", 562262395Sbapt url, strerror (errno)); 563262395Sbapt fclose (in); 564262395Sbapt fetchFreeURL (fetch_url); 565262395Sbapt return false; 566262395Sbapt } 567262395Sbapt 568262395Sbapt fetchFreeURL (fetch_url); 569262395Sbapt return true; 570262395Sbapt#elif defined(CURL_FOUND) 571262395Sbapt CURL *curl; 572262395Sbapt int r; 573262395Sbapt struct ucl_curl_cbdata cbdata; 574262395Sbapt 575262395Sbapt curl = curl_easy_init (); 576262395Sbapt if (curl == NULL) { 577262395Sbapt ucl_create_err (err, "CURL interface is broken"); 578262395Sbapt return false; 579262395Sbapt } 580262395Sbapt if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 581262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 582262395Sbapt url, curl_easy_strerror (r)); 583262395Sbapt curl_easy_cleanup (curl); 584262395Sbapt return false; 585262395Sbapt } 586262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 587262395Sbapt cbdata.buf = *buf; 588262395Sbapt cbdata.buflen = *buflen; 589262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 590262395Sbapt 591262395Sbapt if ((r = curl_easy_perform (curl)) != CURLE_OK) { 592262395Sbapt if (!must_exist) { 593262395Sbapt ucl_create_err (err, "error fetching URL %s: %s", 594262395Sbapt url, curl_easy_strerror (r)); 595262395Sbapt } 596262395Sbapt curl_easy_cleanup (curl); 597262395Sbapt if (cbdata.buf) { 598262395Sbapt free (cbdata.buf); 599262395Sbapt } 600262395Sbapt return false; 601262395Sbapt } 602262395Sbapt *buf = cbdata.buf; 603262395Sbapt *buflen = cbdata.buflen; 604262395Sbapt 605262395Sbapt return true; 606262395Sbapt#else 607262395Sbapt ucl_create_err (err, "URL support is disabled"); 608262395Sbapt return false; 609262395Sbapt#endif 610262395Sbapt} 611262395Sbapt 612262395Sbapt/** 613262395Sbapt * Fetch a file and save results to the memory buffer 614262395Sbapt * @param filename filename to fetch 615262395Sbapt * @param len length of filename 616262395Sbapt * @param buf target buffer 617262395Sbapt * @param buflen target length 618262395Sbapt * @return 619262395Sbapt */ 620262395Sbaptstatic bool 621262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 622262395Sbapt UT_string **err, bool must_exist) 623262395Sbapt{ 624262395Sbapt int fd; 625262395Sbapt struct stat st; 626262395Sbapt 627262395Sbapt if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 628262395Sbapt if (must_exist) { 629262395Sbapt ucl_create_err (err, "cannot stat file %s: %s", 630262395Sbapt filename, strerror (errno)); 631262395Sbapt } 632262395Sbapt return false; 633262395Sbapt } 634262395Sbapt if (st.st_size == 0) { 635262395Sbapt /* Do not map empty files */ 636262395Sbapt *buf = ""; 637262395Sbapt *buflen = 0; 638262395Sbapt } 639262395Sbapt else { 640262395Sbapt if ((fd = open (filename, O_RDONLY)) == -1) { 641262395Sbapt ucl_create_err (err, "cannot open file %s: %s", 642262395Sbapt filename, strerror (errno)); 643262395Sbapt return false; 644262395Sbapt } 645263648Sbapt if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 646262395Sbapt close (fd); 647262395Sbapt ucl_create_err (err, "cannot mmap file %s: %s", 648262395Sbapt filename, strerror (errno)); 649262395Sbapt return false; 650262395Sbapt } 651262395Sbapt *buflen = st.st_size; 652262395Sbapt close (fd); 653262395Sbapt } 654262395Sbapt 655262395Sbapt return true; 656262395Sbapt} 657262395Sbapt 658262395Sbapt 659262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 660262395Sbaptstatic inline bool 661262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen, 662262395Sbapt const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 663262395Sbapt{ 664262395Sbapt struct ucl_pubkey *key; 665262395Sbapt char dig[EVP_MAX_MD_SIZE]; 666262395Sbapt unsigned int diglen; 667262395Sbapt EVP_PKEY_CTX *key_ctx; 668262395Sbapt EVP_MD_CTX *sign_ctx = NULL; 669262395Sbapt 670262395Sbapt sign_ctx = EVP_MD_CTX_create (); 671262395Sbapt 672262395Sbapt LL_FOREACH (parser->keys, key) { 673262395Sbapt key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 674262395Sbapt if (key_ctx != NULL) { 675262395Sbapt if (EVP_PKEY_verify_init (key_ctx) <= 0) { 676262395Sbapt EVP_PKEY_CTX_free (key_ctx); 677262395Sbapt continue; 678262395Sbapt } 679262395Sbapt if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 680262395Sbapt EVP_PKEY_CTX_free (key_ctx); 681262395Sbapt continue; 682262395Sbapt } 683262395Sbapt if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 684262395Sbapt EVP_PKEY_CTX_free (key_ctx); 685262395Sbapt continue; 686262395Sbapt } 687262395Sbapt EVP_DigestInit (sign_ctx, EVP_sha256 ()); 688262395Sbapt EVP_DigestUpdate (sign_ctx, data, datalen); 689262395Sbapt EVP_DigestFinal (sign_ctx, dig, &diglen); 690262395Sbapt 691262395Sbapt if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 692262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 693262395Sbapt EVP_PKEY_CTX_free (key_ctx); 694262395Sbapt return true; 695262395Sbapt } 696262395Sbapt 697262395Sbapt EVP_PKEY_CTX_free (key_ctx); 698262395Sbapt } 699262395Sbapt } 700262395Sbapt 701262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 702262395Sbapt 703262395Sbapt return false; 704262395Sbapt} 705262395Sbapt#endif 706262395Sbapt 707262395Sbapt/** 708262395Sbapt * Include an url to configuration 709262395Sbapt * @param data 710262395Sbapt * @param len 711262395Sbapt * @param parser 712262395Sbapt * @param err 713262395Sbapt * @return 714262395Sbapt */ 715262395Sbaptstatic bool 716262395Sbaptucl_include_url (const unsigned char *data, size_t len, 717275223Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist, 718275223Sbapt unsigned priority) 719262395Sbapt{ 720262395Sbapt 721262395Sbapt bool res; 722262395Sbapt unsigned char *buf = NULL; 723262395Sbapt size_t buflen = 0; 724262395Sbapt struct ucl_chunk *chunk; 725262395Sbapt char urlbuf[PATH_MAX]; 726262395Sbapt int prev_state; 727262395Sbapt 728262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 729262395Sbapt 730262395Sbapt if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 731262395Sbapt return (!must_exist || false); 732262395Sbapt } 733262395Sbapt 734262395Sbapt if (check_signature) { 735262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 736262395Sbapt unsigned char *sigbuf = NULL; 737262395Sbapt size_t siglen = 0; 738262395Sbapt /* We need to check signature first */ 739262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 740262395Sbapt if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 741262395Sbapt return false; 742262395Sbapt } 743262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 744262395Sbapt ucl_create_err (&parser->err, "cannot verify url %s: %s", 745262395Sbapt urlbuf, 746262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 747262395Sbapt if (siglen > 0) { 748263648Sbapt ucl_munmap (sigbuf, siglen); 749262395Sbapt } 750262395Sbapt return false; 751262395Sbapt } 752262395Sbapt if (siglen > 0) { 753263648Sbapt ucl_munmap (sigbuf, siglen); 754262395Sbapt } 755262395Sbapt#endif 756262395Sbapt } 757262395Sbapt 758262395Sbapt prev_state = parser->state; 759262395Sbapt parser->state = UCL_STATE_INIT; 760262395Sbapt 761275223Sbapt res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority); 762262395Sbapt if (res == true) { 763262395Sbapt /* Remove chunk from the stack */ 764262395Sbapt chunk = parser->chunks; 765262395Sbapt if (chunk != NULL) { 766262395Sbapt parser->chunks = chunk->next; 767262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 768262395Sbapt } 769262395Sbapt } 770262395Sbapt 771262395Sbapt parser->state = prev_state; 772262395Sbapt free (buf); 773262395Sbapt 774262395Sbapt return res; 775262395Sbapt} 776262395Sbapt 777262395Sbapt/** 778275223Sbapt * Include a single file to the parser 779262395Sbapt * @param data 780262395Sbapt * @param len 781262395Sbapt * @param parser 782275223Sbapt * @param check_signature 783275223Sbapt * @param must_exist 784275223Sbapt * @param allow_glob 785275223Sbapt * @param priority 786262395Sbapt * @return 787262395Sbapt */ 788262395Sbaptstatic bool 789275223Sbaptucl_include_file_single (const unsigned char *data, size_t len, 790275223Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist, 791275223Sbapt unsigned priority) 792262395Sbapt{ 793262395Sbapt bool res; 794262395Sbapt struct ucl_chunk *chunk; 795262395Sbapt unsigned char *buf = NULL; 796275223Sbapt char *old_curfile; 797262395Sbapt size_t buflen; 798262395Sbapt char filebuf[PATH_MAX], realbuf[PATH_MAX]; 799262395Sbapt int prev_state; 800275223Sbapt struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL, 801275223Sbapt *old_filename = NULL; 802262395Sbapt 803262395Sbapt snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 804263648Sbapt if (ucl_realpath (filebuf, realbuf) == NULL) { 805262395Sbapt if (!must_exist) { 806262395Sbapt return true; 807262395Sbapt } 808262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 809262395Sbapt filebuf, 810262395Sbapt strerror (errno)); 811262395Sbapt return false; 812262395Sbapt } 813262395Sbapt 814275223Sbapt if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) { 815275223Sbapt /* We are likely including the file itself */ 816275223Sbapt ucl_create_err (&parser->err, "trying to include the file %s from itself", 817275223Sbapt realbuf); 818275223Sbapt return false; 819275223Sbapt } 820275223Sbapt 821262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 822262395Sbapt return (!must_exist || false); 823262395Sbapt } 824262395Sbapt 825262395Sbapt if (check_signature) { 826262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 827262395Sbapt unsigned char *sigbuf = NULL; 828262395Sbapt size_t siglen = 0; 829262395Sbapt /* We need to check signature first */ 830262395Sbapt snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 831262395Sbapt if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 832262395Sbapt return false; 833262395Sbapt } 834262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 835262395Sbapt ucl_create_err (&parser->err, "cannot verify file %s: %s", 836262395Sbapt filebuf, 837262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 838262395Sbapt if (siglen > 0) { 839263648Sbapt ucl_munmap (sigbuf, siglen); 840262395Sbapt } 841262395Sbapt return false; 842262395Sbapt } 843262395Sbapt if (siglen > 0) { 844263648Sbapt ucl_munmap (sigbuf, siglen); 845262395Sbapt } 846262395Sbapt#endif 847262395Sbapt } 848262395Sbapt 849275223Sbapt old_curfile = parser->cur_file; 850275223Sbapt parser->cur_file = strdup (realbuf); 851275223Sbapt 852275223Sbapt /* Store old file vars */ 853275223Sbapt DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 854275223Sbapt if (strcmp (cur_var->var, "CURDIR") == 0) { 855275223Sbapt old_curdir = cur_var; 856275223Sbapt DL_DELETE (parser->variables, cur_var); 857275223Sbapt } 858275223Sbapt else if (strcmp (cur_var->var, "FILENAME") == 0) { 859275223Sbapt old_filename = cur_var; 860275223Sbapt DL_DELETE (parser->variables, cur_var); 861275223Sbapt } 862275223Sbapt } 863275223Sbapt 864262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 865262395Sbapt 866262395Sbapt prev_state = parser->state; 867262395Sbapt parser->state = UCL_STATE_INIT; 868262395Sbapt 869275223Sbapt res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority); 870275223Sbapt if (!res && !must_exist) { 871275223Sbapt /* Free error */ 872275223Sbapt utstring_free (parser->err); 873275223Sbapt parser->err = NULL; 874275223Sbapt parser->state = UCL_STATE_AFTER_VALUE; 875275223Sbapt } 876275223Sbapt 877275223Sbapt /* Remove chunk from the stack */ 878275223Sbapt chunk = parser->chunks; 879275223Sbapt if (chunk != NULL) { 880275223Sbapt parser->chunks = chunk->next; 881275223Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 882275223Sbapt parser->recursion --; 883275223Sbapt } 884275223Sbapt 885275223Sbapt /* Restore old file vars */ 886275223Sbapt parser->cur_file = old_curfile; 887275223Sbapt DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 888275223Sbapt if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) { 889275223Sbapt DL_DELETE (parser->variables, cur_var); 890275223Sbapt free (cur_var->var); 891275223Sbapt free (cur_var->value); 892275223Sbapt UCL_FREE (sizeof (struct ucl_variable), cur_var); 893262395Sbapt } 894275223Sbapt else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) { 895275223Sbapt DL_DELETE (parser->variables, cur_var); 896275223Sbapt free (cur_var->var); 897275223Sbapt free (cur_var->value); 898275223Sbapt UCL_FREE (sizeof (struct ucl_variable), cur_var); 899275223Sbapt } 900262395Sbapt } 901275223Sbapt if (old_filename) { 902275223Sbapt DL_APPEND (parser->variables, old_filename); 903275223Sbapt } 904275223Sbapt if (old_curdir) { 905275223Sbapt DL_APPEND (parser->variables, old_curdir); 906275223Sbapt } 907275223Sbapt if (old_curfile) { 908275223Sbapt free (old_curfile); 909275223Sbapt } 910262395Sbapt 911262395Sbapt parser->state = prev_state; 912262395Sbapt 913262395Sbapt if (buflen > 0) { 914263648Sbapt ucl_munmap (buf, buflen); 915262395Sbapt } 916262395Sbapt 917262395Sbapt return res; 918262395Sbapt} 919262395Sbapt 920262395Sbapt/** 921275223Sbapt * Include a file to configuration 922275223Sbapt * @param data 923275223Sbapt * @param len 924275223Sbapt * @param parser 925275223Sbapt * @param err 926275223Sbapt * @return 927275223Sbapt */ 928275223Sbaptstatic bool 929275223Sbaptucl_include_file (const unsigned char *data, size_t len, 930275223Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist, 931275223Sbapt bool allow_glob, unsigned priority) 932275223Sbapt{ 933275223Sbapt const unsigned char *p = data, *end = data + len; 934275223Sbapt bool need_glob = false; 935275223Sbapt int cnt = 0; 936275223Sbapt glob_t globbuf; 937275223Sbapt char glob_pattern[PATH_MAX]; 938275223Sbapt size_t i; 939275223Sbapt 940275223Sbapt if (!allow_glob) { 941275223Sbapt return ucl_include_file_single (data, len, parser, check_signature, 942275223Sbapt must_exist, priority); 943275223Sbapt } 944275223Sbapt else { 945275223Sbapt /* Check for special symbols in a filename */ 946275223Sbapt while (p != end) { 947275223Sbapt if (*p == '*' || *p == '?') { 948275223Sbapt need_glob = true; 949275223Sbapt break; 950275223Sbapt } 951275223Sbapt p ++; 952275223Sbapt } 953275223Sbapt if (need_glob) { 954275223Sbapt memset (&globbuf, 0, sizeof (globbuf)); 955275223Sbapt ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern)); 956275223Sbapt if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { 957275223Sbapt return (!must_exist || false); 958275223Sbapt } 959275223Sbapt for (i = 0; i < globbuf.gl_pathc; i ++) { 960275223Sbapt if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i], 961275223Sbapt strlen (globbuf.gl_pathv[i]), parser, check_signature, 962275223Sbapt must_exist, priority)) { 963275223Sbapt globfree (&globbuf); 964275223Sbapt return false; 965275223Sbapt } 966275223Sbapt cnt ++; 967275223Sbapt } 968275223Sbapt globfree (&globbuf); 969275223Sbapt 970275223Sbapt if (cnt == 0 && must_exist) { 971275223Sbapt ucl_create_err (&parser->err, "cannot match any files for pattern %s", 972275223Sbapt glob_pattern); 973275223Sbapt return false; 974275223Sbapt } 975275223Sbapt } 976275223Sbapt else { 977275223Sbapt return ucl_include_file_single (data, len, parser, check_signature, 978275223Sbapt must_exist, priority); 979275223Sbapt } 980275223Sbapt } 981275223Sbapt 982275223Sbapt return true; 983275223Sbapt} 984275223Sbapt 985275223Sbapt/** 986275223Sbapt * Common function to handle .*include* macros 987275223Sbapt * @param data 988275223Sbapt * @param len 989275223Sbapt * @param args 990275223Sbapt * @param parser 991275223Sbapt * @param default_try 992275223Sbapt * @param default_sign 993275223Sbapt * @return 994275223Sbapt */ 995275223Sbaptstatic bool 996275223Sbaptucl_include_common (const unsigned char *data, size_t len, 997275223Sbapt const ucl_object_t *args, struct ucl_parser *parser, 998275223Sbapt bool default_try, 999275223Sbapt bool default_sign) 1000275223Sbapt{ 1001275223Sbapt bool try_load, allow_glob, allow_url, need_sign; 1002275223Sbapt unsigned priority; 1003275223Sbapt const ucl_object_t *param; 1004275223Sbapt ucl_object_iter_t it = NULL; 1005275223Sbapt 1006275223Sbapt /* Default values */ 1007275223Sbapt try_load = default_try; 1008275223Sbapt allow_glob = false; 1009275223Sbapt allow_url = true; 1010275223Sbapt need_sign = default_sign; 1011275223Sbapt priority = 0; 1012275223Sbapt 1013275223Sbapt /* Process arguments */ 1014275223Sbapt if (args != NULL && args->type == UCL_OBJECT) { 1015275223Sbapt while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1016275223Sbapt if (param->type == UCL_BOOLEAN) { 1017275223Sbapt if (strcmp (param->key, "try") == 0) { 1018275223Sbapt try_load = ucl_object_toboolean (param); 1019275223Sbapt } 1020275223Sbapt else if (strcmp (param->key, "sign") == 0) { 1021275223Sbapt need_sign = ucl_object_toboolean (param); 1022275223Sbapt } 1023275223Sbapt else if (strcmp (param->key, "glob") == 0) { 1024275223Sbapt allow_glob = ucl_object_toboolean (param); 1025275223Sbapt } 1026275223Sbapt else if (strcmp (param->key, "url") == 0) { 1027275223Sbapt allow_url = ucl_object_toboolean (param); 1028275223Sbapt } 1029275223Sbapt } 1030275223Sbapt else if (param->type == UCL_INT) { 1031275223Sbapt if (strcmp (param->key, "priority") == 0) { 1032275223Sbapt priority = ucl_object_toint (param); 1033275223Sbapt } 1034275223Sbapt } 1035275223Sbapt } 1036275223Sbapt } 1037275223Sbapt 1038275223Sbapt if (*data == '/' || *data == '.') { 1039275223Sbapt /* Try to load a file */ 1040275223Sbapt return ucl_include_file (data, len, parser, need_sign, !try_load, 1041275223Sbapt allow_glob, priority); 1042275223Sbapt } 1043275223Sbapt else if (allow_url) { 1044275223Sbapt /* Globbing is not used for URL's */ 1045275223Sbapt return ucl_include_url (data, len, parser, need_sign, !try_load, 1046275223Sbapt priority); 1047275223Sbapt } 1048275223Sbapt 1049275223Sbapt return false; 1050275223Sbapt} 1051275223Sbapt 1052275223Sbapt/** 1053262395Sbapt * Handle include macro 1054262395Sbapt * @param data include data 1055262395Sbapt * @param len length of data 1056262395Sbapt * @param ud user data 1057262395Sbapt * @param err error ptr 1058262395Sbapt * @return 1059262395Sbapt */ 1060262975SbaptUCL_EXTERN bool 1061275223Sbaptucl_include_handler (const unsigned char *data, size_t len, 1062275223Sbapt const ucl_object_t *args, void* ud) 1063262395Sbapt{ 1064262395Sbapt struct ucl_parser *parser = ud; 1065262395Sbapt 1066275223Sbapt return ucl_include_common (data, len, args, parser, false, false); 1067262395Sbapt} 1068262395Sbapt 1069262395Sbapt/** 1070262395Sbapt * Handle includes macro 1071262395Sbapt * @param data include data 1072262395Sbapt * @param len length of data 1073262395Sbapt * @param ud user data 1074262395Sbapt * @param err error ptr 1075262395Sbapt * @return 1076262395Sbapt */ 1077262975SbaptUCL_EXTERN bool 1078275223Sbaptucl_includes_handler (const unsigned char *data, size_t len, 1079275223Sbapt const ucl_object_t *args, void* ud) 1080262395Sbapt{ 1081262395Sbapt struct ucl_parser *parser = ud; 1082262395Sbapt 1083275223Sbapt return ucl_include_common (data, len, args, parser, false, true); 1084262395Sbapt} 1085262395Sbapt 1086262395Sbapt 1087262975SbaptUCL_EXTERN bool 1088275223Sbaptucl_try_include_handler (const unsigned char *data, size_t len, 1089275223Sbapt const ucl_object_t *args, void* ud) 1090262395Sbapt{ 1091262395Sbapt struct ucl_parser *parser = ud; 1092262395Sbapt 1093275223Sbapt return ucl_include_common (data, len, args, parser, true, false); 1094262395Sbapt} 1095262395Sbapt 1096262975SbaptUCL_EXTERN bool 1097262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 1098262395Sbapt{ 1099262395Sbapt char realbuf[PATH_MAX], *curdir; 1100262395Sbapt 1101262395Sbapt if (filename != NULL) { 1102262395Sbapt if (need_expand) { 1103263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 1104262395Sbapt return false; 1105262395Sbapt } 1106262395Sbapt } 1107262395Sbapt else { 1108262395Sbapt ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 1109262395Sbapt } 1110262395Sbapt 1111262395Sbapt /* Define variables */ 1112262395Sbapt ucl_parser_register_variable (parser, "FILENAME", realbuf); 1113262395Sbapt curdir = dirname (realbuf); 1114262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 1115262395Sbapt } 1116262395Sbapt else { 1117262395Sbapt /* Set everything from the current dir */ 1118262395Sbapt curdir = getcwd (realbuf, sizeof (realbuf)); 1119262395Sbapt ucl_parser_register_variable (parser, "FILENAME", "undef"); 1120262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 1121262395Sbapt } 1122262395Sbapt 1123262395Sbapt return true; 1124262395Sbapt} 1125262395Sbapt 1126262975SbaptUCL_EXTERN bool 1127262395Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename) 1128262395Sbapt{ 1129262395Sbapt unsigned char *buf; 1130262395Sbapt size_t len; 1131262395Sbapt bool ret; 1132262395Sbapt char realbuf[PATH_MAX]; 1133262395Sbapt 1134263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 1135262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 1136262395Sbapt filename, 1137262395Sbapt strerror (errno)); 1138262395Sbapt return false; 1139262395Sbapt } 1140262395Sbapt 1141262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 1142262395Sbapt return false; 1143262395Sbapt } 1144262395Sbapt 1145275223Sbapt if (parser->cur_file) { 1146275223Sbapt free (parser->cur_file); 1147275223Sbapt } 1148275223Sbapt parser->cur_file = strdup (realbuf); 1149262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 1150262395Sbapt ret = ucl_parser_add_chunk (parser, buf, len); 1151262395Sbapt 1152262395Sbapt if (len > 0) { 1153263648Sbapt ucl_munmap (buf, len); 1154262395Sbapt } 1155262395Sbapt 1156262395Sbapt return ret; 1157262395Sbapt} 1158262395Sbapt 1159275223SbaptUCL_EXTERN bool 1160275223Sbaptucl_parser_add_fd (struct ucl_parser *parser, int fd) 1161275223Sbapt{ 1162275223Sbapt unsigned char *buf; 1163275223Sbapt size_t len; 1164275223Sbapt bool ret; 1165275223Sbapt struct stat st; 1166275223Sbapt 1167275223Sbapt if (fstat (fd, &st) == -1) { 1168275223Sbapt ucl_create_err (&parser->err, "cannot stat fd %d: %s", 1169275223Sbapt fd, strerror (errno)); 1170275223Sbapt return false; 1171275223Sbapt } 1172275223Sbapt if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 1173275223Sbapt ucl_create_err (&parser->err, "cannot mmap fd %d: %s", 1174275223Sbapt fd, strerror (errno)); 1175275223Sbapt return false; 1176275223Sbapt } 1177275223Sbapt 1178275223Sbapt if (parser->cur_file) { 1179275223Sbapt free (parser->cur_file); 1180275223Sbapt } 1181275223Sbapt parser->cur_file = NULL; 1182275223Sbapt len = st.st_size; 1183275223Sbapt ret = ucl_parser_add_chunk (parser, buf, len); 1184275223Sbapt 1185275223Sbapt if (len > 0) { 1186275223Sbapt ucl_munmap (buf, len); 1187275223Sbapt } 1188275223Sbapt 1189275223Sbapt return ret; 1190275223Sbapt} 1191275223Sbapt 1192262395Sbaptsize_t 1193262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz) 1194262395Sbapt{ 1195262395Sbapt char *d = dst; 1196262395Sbapt const char *s = src; 1197262395Sbapt size_t n = siz; 1198262395Sbapt 1199262395Sbapt /* Copy as many bytes as will fit */ 1200262395Sbapt if (n != 0) { 1201262395Sbapt while (--n != 0) { 1202262395Sbapt if ((*d++ = *s++) == '\0') { 1203262395Sbapt break; 1204262395Sbapt } 1205262395Sbapt } 1206262395Sbapt } 1207262395Sbapt 1208262395Sbapt if (n == 0 && siz != 0) { 1209262395Sbapt *d = '\0'; 1210262395Sbapt } 1211262395Sbapt 1212262395Sbapt return (s - src - 1); /* count does not include NUL */ 1213262395Sbapt} 1214262395Sbapt 1215262395Sbaptsize_t 1216262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 1217262395Sbapt{ 1218262395Sbapt memcpy (dst, src, siz - 1); 1219262395Sbapt dst[siz - 1] = '\0'; 1220262395Sbapt 1221262395Sbapt return siz - 1; 1222262395Sbapt} 1223262395Sbapt 1224262395Sbaptsize_t 1225262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 1226262395Sbapt{ 1227262395Sbapt char *d = dst; 1228262395Sbapt const char *s = src; 1229262395Sbapt size_t n = siz; 1230262395Sbapt 1231262395Sbapt /* Copy as many bytes as will fit */ 1232262395Sbapt if (n != 0) { 1233262395Sbapt while (--n != 0) { 1234262395Sbapt if ((*d++ = tolower (*s++)) == '\0') { 1235262395Sbapt break; 1236262395Sbapt } 1237262395Sbapt } 1238262395Sbapt } 1239262395Sbapt 1240262395Sbapt if (n == 0 && siz != 0) { 1241262395Sbapt *d = '\0'; 1242262395Sbapt } 1243262395Sbapt 1244262395Sbapt return (s - src); /* count does not include NUL */ 1245262395Sbapt} 1246262395Sbapt 1247262395Sbaptucl_object_t * 1248262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1249262395Sbapt{ 1250262395Sbapt ucl_object_t *obj; 1251262395Sbapt const char *start, *end, *p, *pos; 1252262395Sbapt char *dst, *d; 1253262395Sbapt size_t escaped_len; 1254262395Sbapt 1255262395Sbapt if (str == NULL) { 1256262395Sbapt return NULL; 1257262395Sbapt } 1258262395Sbapt 1259262395Sbapt obj = ucl_object_new (); 1260262395Sbapt if (obj) { 1261262395Sbapt if (len == 0) { 1262262395Sbapt len = strlen (str); 1263262395Sbapt } 1264262395Sbapt if (flags & UCL_STRING_TRIM) { 1265262395Sbapt /* Skip leading spaces */ 1266262395Sbapt for (start = str; (size_t)(start - str) < len; start ++) { 1267262395Sbapt if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1268262395Sbapt break; 1269262395Sbapt } 1270262395Sbapt } 1271262395Sbapt /* Skip trailing spaces */ 1272262395Sbapt for (end = str + len - 1; end > start; end --) { 1273262395Sbapt if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1274262395Sbapt break; 1275262395Sbapt } 1276262395Sbapt } 1277262395Sbapt end ++; 1278262395Sbapt } 1279262395Sbapt else { 1280262395Sbapt start = str; 1281262395Sbapt end = str + len; 1282262395Sbapt } 1283262395Sbapt 1284262395Sbapt obj->type = UCL_STRING; 1285262395Sbapt if (flags & UCL_STRING_ESCAPE) { 1286262395Sbapt for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1287262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1288262395Sbapt escaped_len ++; 1289262395Sbapt } 1290262395Sbapt } 1291262395Sbapt dst = malloc (escaped_len + 1); 1292262395Sbapt if (dst != NULL) { 1293262395Sbapt for (p = start, d = dst; p < end; p ++, d ++) { 1294262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1295262395Sbapt switch (*p) { 1296262395Sbapt case '\n': 1297262395Sbapt *d++ = '\\'; 1298262395Sbapt *d = 'n'; 1299262395Sbapt break; 1300262395Sbapt case '\r': 1301262395Sbapt *d++ = '\\'; 1302262395Sbapt *d = 'r'; 1303262395Sbapt break; 1304262395Sbapt case '\b': 1305262395Sbapt *d++ = '\\'; 1306262395Sbapt *d = 'b'; 1307262395Sbapt break; 1308262395Sbapt case '\t': 1309262395Sbapt *d++ = '\\'; 1310262395Sbapt *d = 't'; 1311262395Sbapt break; 1312262395Sbapt case '\f': 1313262395Sbapt *d++ = '\\'; 1314262395Sbapt *d = 'f'; 1315262395Sbapt break; 1316262395Sbapt case '\\': 1317262395Sbapt *d++ = '\\'; 1318262395Sbapt *d = '\\'; 1319262395Sbapt break; 1320262395Sbapt case '"': 1321262395Sbapt *d++ = '\\'; 1322262395Sbapt *d = '"'; 1323262395Sbapt break; 1324262395Sbapt } 1325262395Sbapt } 1326262395Sbapt else { 1327262395Sbapt *d = *p; 1328262395Sbapt } 1329262395Sbapt } 1330262395Sbapt *d = '\0'; 1331262395Sbapt obj->value.sv = dst; 1332262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1333262395Sbapt obj->len = escaped_len; 1334262395Sbapt } 1335262395Sbapt } 1336262395Sbapt else { 1337262395Sbapt dst = malloc (end - start + 1); 1338262395Sbapt if (dst != NULL) { 1339262395Sbapt ucl_strlcpy_unsafe (dst, start, end - start + 1); 1340262395Sbapt obj->value.sv = dst; 1341262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1342262395Sbapt obj->len = end - start; 1343262395Sbapt } 1344262395Sbapt } 1345262395Sbapt if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1346262395Sbapt /* Parse what we have */ 1347262395Sbapt if (flags & UCL_STRING_PARSE_BOOLEAN) { 1348262395Sbapt if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1349262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1350262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1351263648Sbapt flags & UCL_STRING_PARSE_BYTES, 1352263648Sbapt flags & UCL_STRING_PARSE_TIME); 1353262395Sbapt } 1354262395Sbapt } 1355262395Sbapt else { 1356262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1357262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1358263648Sbapt flags & UCL_STRING_PARSE_BYTES, 1359263648Sbapt flags & UCL_STRING_PARSE_TIME); 1360262395Sbapt } 1361262395Sbapt } 1362262395Sbapt } 1363262395Sbapt 1364262395Sbapt return obj; 1365262395Sbapt} 1366262395Sbapt 1367264789Sbaptstatic bool 1368262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1369262395Sbapt const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1370262395Sbapt{ 1371264789Sbapt ucl_object_t *found, *tmp; 1372264789Sbapt const ucl_object_t *cur; 1373262395Sbapt ucl_object_iter_t it = NULL; 1374262395Sbapt const char *p; 1375264789Sbapt int ret = true; 1376262395Sbapt 1377262395Sbapt if (elt == NULL || key == NULL) { 1378264789Sbapt return false; 1379262395Sbapt } 1380262395Sbapt 1381262395Sbapt if (top == NULL) { 1382264789Sbapt return false; 1383262395Sbapt } 1384262395Sbapt 1385262395Sbapt if (top->type != UCL_OBJECT) { 1386262395Sbapt /* It is possible to convert NULL type to an object */ 1387262395Sbapt if (top->type == UCL_NULL) { 1388262395Sbapt top->type = UCL_OBJECT; 1389262395Sbapt } 1390262395Sbapt else { 1391262395Sbapt /* Refuse converting of other object types */ 1392264789Sbapt return false; 1393262395Sbapt } 1394262395Sbapt } 1395262395Sbapt 1396262395Sbapt if (top->value.ov == NULL) { 1397262395Sbapt top->value.ov = ucl_hash_create (); 1398262395Sbapt } 1399262395Sbapt 1400262395Sbapt if (keylen == 0) { 1401262395Sbapt keylen = strlen (key); 1402262395Sbapt } 1403262395Sbapt 1404262395Sbapt for (p = key; p < key + keylen; p ++) { 1405262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1406262395Sbapt elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1407262395Sbapt break; 1408262395Sbapt } 1409262395Sbapt } 1410262395Sbapt 1411275223Sbapt /* workaround for some use cases */ 1412275223Sbapt if (elt->trash_stack[UCL_TRASH_KEY] != NULL && 1413275223Sbapt key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) { 1414275223Sbapt /* Remove copied key */ 1415275223Sbapt free (elt->trash_stack[UCL_TRASH_KEY]); 1416275223Sbapt elt->trash_stack[UCL_TRASH_KEY] = NULL; 1417275223Sbapt elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY; 1418275223Sbapt } 1419275223Sbapt 1420262395Sbapt elt->key = key; 1421262395Sbapt elt->keylen = keylen; 1422262395Sbapt 1423262395Sbapt if (copy_key) { 1424262395Sbapt ucl_copy_key_trash (elt); 1425262395Sbapt } 1426262395Sbapt 1427264789Sbapt found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 1428262395Sbapt 1429275223Sbapt if (found == NULL) { 1430262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1431263648Sbapt top->len ++; 1432264789Sbapt if (replace) { 1433264789Sbapt ret = false; 1434264789Sbapt } 1435262395Sbapt } 1436262395Sbapt else { 1437262395Sbapt if (replace) { 1438275223Sbapt ucl_hash_replace (top->value.ov, found, elt); 1439262395Sbapt ucl_object_unref (found); 1440262395Sbapt } 1441262395Sbapt else if (merge) { 1442262395Sbapt if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1443262395Sbapt /* Insert old elt to new one */ 1444264789Sbapt ucl_object_insert_key_common (elt, found, found->key, 1445264789Sbapt found->keylen, copy_key, false, false); 1446262395Sbapt ucl_hash_delete (top->value.ov, found); 1447262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1448262395Sbapt } 1449262395Sbapt else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1450262395Sbapt /* Insert new to old */ 1451264789Sbapt ucl_object_insert_key_common (found, elt, elt->key, 1452264789Sbapt elt->keylen, copy_key, false, false); 1453262395Sbapt } 1454262395Sbapt else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1455262395Sbapt /* Mix two hashes */ 1456262395Sbapt while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1457264789Sbapt tmp = ucl_object_ref (cur); 1458264789Sbapt ucl_object_insert_key_common (found, tmp, cur->key, 1459264789Sbapt cur->keylen, copy_key, false, false); 1460262395Sbapt } 1461262395Sbapt ucl_object_unref (elt); 1462262395Sbapt } 1463262395Sbapt else { 1464262395Sbapt /* Just make a list of scalars */ 1465262395Sbapt DL_APPEND (found, elt); 1466262395Sbapt } 1467262395Sbapt } 1468262395Sbapt else { 1469262395Sbapt DL_APPEND (found, elt); 1470262395Sbapt } 1471262395Sbapt } 1472262395Sbapt 1473264789Sbapt return ret; 1474262395Sbapt} 1475262395Sbapt 1476262975Sbaptbool 1477264789Sbaptucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 1478262975Sbapt{ 1479262975Sbapt ucl_object_t *found; 1480262975Sbapt 1481263648Sbapt if (top == NULL || key == NULL) { 1482263648Sbapt return false; 1483263648Sbapt } 1484263648Sbapt 1485264789Sbapt found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); 1486262975Sbapt 1487263648Sbapt if (found == NULL) { 1488262975Sbapt return false; 1489263648Sbapt } 1490262975Sbapt 1491264789Sbapt ucl_hash_delete (top->value.ov, found); 1492262975Sbapt ucl_object_unref (found); 1493262975Sbapt top->len --; 1494262975Sbapt 1495262975Sbapt return true; 1496262975Sbapt} 1497262975Sbapt 1498262975Sbaptbool 1499264789Sbaptucl_object_delete_key (ucl_object_t *top, const char *key) 1500262975Sbapt{ 1501264789Sbapt return ucl_object_delete_keyl (top, key, strlen(key)); 1502262975Sbapt} 1503262975Sbapt 1504263648Sbaptucl_object_t* 1505263648Sbaptucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 1506263648Sbapt{ 1507264789Sbapt const ucl_object_t *found; 1508263648Sbapt 1509263648Sbapt if (top == NULL || key == NULL) { 1510263648Sbapt return false; 1511263648Sbapt } 1512264789Sbapt found = ucl_object_find_keyl (top, key, keylen); 1513263648Sbapt 1514263648Sbapt if (found == NULL) { 1515263648Sbapt return NULL; 1516263648Sbapt } 1517264789Sbapt ucl_hash_delete (top->value.ov, found); 1518263648Sbapt top->len --; 1519263648Sbapt 1520264789Sbapt return __DECONST (ucl_object_t *, found); 1521263648Sbapt} 1522263648Sbapt 1523263648Sbaptucl_object_t* 1524263648Sbaptucl_object_pop_key (ucl_object_t *top, const char *key) 1525263648Sbapt{ 1526264789Sbapt return ucl_object_pop_keyl (top, key, strlen(key)); 1527263648Sbapt} 1528263648Sbapt 1529264789Sbaptbool 1530262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1531262395Sbapt const char *key, size_t keylen, bool copy_key) 1532262395Sbapt{ 1533262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1534262395Sbapt} 1535262395Sbapt 1536264789Sbaptbool 1537262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1538262395Sbapt const char *key, size_t keylen, bool copy_key) 1539262395Sbapt{ 1540262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1541262395Sbapt} 1542262395Sbapt 1543264789Sbaptbool 1544262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1545262395Sbapt const char *key, size_t keylen, bool copy_key) 1546262395Sbapt{ 1547262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1548262395Sbapt} 1549262395Sbapt 1550275223Sbaptbool 1551275223Sbaptucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 1552275223Sbapt{ 1553275223Sbapt ucl_object_t *cur = NULL, *cp = NULL, *found = NULL; 1554275223Sbapt ucl_object_iter_t iter = NULL; 1555275223Sbapt 1556275223Sbapt if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) { 1557275223Sbapt return false; 1558275223Sbapt } 1559275223Sbapt 1560275223Sbapt /* Mix two hashes */ 1561275223Sbapt while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) { 1562275223Sbapt if (copy) { 1563275223Sbapt cp = ucl_object_copy (cur); 1564275223Sbapt } 1565275223Sbapt else { 1566275223Sbapt cp = ucl_object_ref (cur); 1567275223Sbapt } 1568275223Sbapt found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen)); 1569275223Sbapt if (found == NULL) { 1570275223Sbapt /* The key does not exist */ 1571275223Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, cp); 1572275223Sbapt top->len ++; 1573275223Sbapt } 1574275223Sbapt else { 1575275223Sbapt /* The key already exists, replace it */ 1576275223Sbapt ucl_hash_replace (top->value.ov, found, cp); 1577275223Sbapt ucl_object_unref (found); 1578275223Sbapt } 1579275223Sbapt } 1580275223Sbapt 1581275223Sbapt return true; 1582275223Sbapt} 1583275223Sbapt 1584264789Sbaptconst ucl_object_t * 1585264789Sbaptucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) 1586262395Sbapt{ 1587264789Sbapt const ucl_object_t *ret; 1588264789Sbapt ucl_object_t srch; 1589262395Sbapt 1590262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1591262395Sbapt return NULL; 1592262395Sbapt } 1593262395Sbapt 1594262395Sbapt srch.key = key; 1595262395Sbapt srch.keylen = klen; 1596262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1597262395Sbapt 1598262395Sbapt return ret; 1599262395Sbapt} 1600262395Sbapt 1601264789Sbaptconst ucl_object_t * 1602264789Sbaptucl_object_find_key (const ucl_object_t *obj, const char *key) 1603262395Sbapt{ 1604266636Sbapt if (key == NULL) 1605262395Sbapt return NULL; 1606262395Sbapt 1607266636Sbapt return ucl_object_find_keyl (obj, key, strlen(key)); 1608262395Sbapt} 1609262395Sbapt 1610264789Sbaptconst ucl_object_t* 1611264789Sbaptucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1612262395Sbapt{ 1613264789Sbapt const ucl_object_t *elt; 1614262395Sbapt 1615263648Sbapt if (obj == NULL || iter == NULL) { 1616263648Sbapt return NULL; 1617263648Sbapt } 1618263648Sbapt 1619262395Sbapt if (expand_values) { 1620262395Sbapt switch (obj->type) { 1621262395Sbapt case UCL_OBJECT: 1622264789Sbapt return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1623262395Sbapt break; 1624262395Sbapt case UCL_ARRAY: 1625262395Sbapt elt = *iter; 1626262395Sbapt if (elt == NULL) { 1627262395Sbapt elt = obj->value.av; 1628262395Sbapt if (elt == NULL) { 1629262395Sbapt return NULL; 1630262395Sbapt } 1631262395Sbapt } 1632262395Sbapt else if (elt == obj->value.av) { 1633262395Sbapt return NULL; 1634262395Sbapt } 1635262395Sbapt *iter = elt->next ? elt->next : obj->value.av; 1636262395Sbapt return elt; 1637262395Sbapt default: 1638262395Sbapt /* Go to linear iteration */ 1639262395Sbapt break; 1640262395Sbapt } 1641262395Sbapt } 1642262395Sbapt /* Treat everything as a linear list */ 1643262395Sbapt elt = *iter; 1644262395Sbapt if (elt == NULL) { 1645262395Sbapt elt = obj; 1646262395Sbapt } 1647262395Sbapt else if (elt == obj) { 1648262395Sbapt return NULL; 1649262395Sbapt } 1650264789Sbapt *iter = __DECONST (void *, elt->next ? elt->next : obj); 1651262395Sbapt return elt; 1652262395Sbapt 1653262395Sbapt /* Not reached */ 1654262395Sbapt return NULL; 1655262395Sbapt} 1656263648Sbapt 1657266636Sbaptconst ucl_object_t * 1658266636Sbaptucl_lookup_path (const ucl_object_t *top, const char *path_in) { 1659266636Sbapt const ucl_object_t *o = NULL, *found; 1660266636Sbapt const char *p, *c; 1661266636Sbapt char *err_str; 1662266636Sbapt unsigned index; 1663263648Sbapt 1664266636Sbapt if (path_in == NULL || top == NULL) { 1665266636Sbapt return NULL; 1666266636Sbapt } 1667266636Sbapt 1668266636Sbapt found = NULL; 1669266636Sbapt p = path_in; 1670266636Sbapt 1671266636Sbapt /* Skip leading dots */ 1672266636Sbapt while (*p == '.') { 1673266636Sbapt p ++; 1674266636Sbapt } 1675266636Sbapt 1676266636Sbapt c = p; 1677266636Sbapt while (*p != '\0') { 1678266636Sbapt p ++; 1679266636Sbapt if (*p == '.' || *p == '\0') { 1680266636Sbapt if (p > c) { 1681266636Sbapt switch (top->type) { 1682266636Sbapt case UCL_ARRAY: 1683266636Sbapt /* Key should be an int */ 1684266636Sbapt index = strtoul (c, &err_str, 10); 1685266636Sbapt if (err_str != NULL && (*err_str != '.' && *err_str != '\0')) { 1686266636Sbapt return NULL; 1687266636Sbapt } 1688266636Sbapt o = ucl_array_find_index (top, index); 1689266636Sbapt break; 1690266636Sbapt default: 1691266636Sbapt o = ucl_object_find_keyl (top, c, p - c); 1692266636Sbapt break; 1693266636Sbapt } 1694266636Sbapt if (o == NULL) { 1695266636Sbapt return NULL; 1696266636Sbapt } 1697266636Sbapt top = o; 1698266636Sbapt } 1699266636Sbapt if (*p != '\0') { 1700266636Sbapt c = p + 1; 1701266636Sbapt } 1702266636Sbapt } 1703266636Sbapt } 1704266636Sbapt found = o; 1705266636Sbapt 1706266636Sbapt return found; 1707266636Sbapt} 1708266636Sbapt 1709266636Sbapt 1710263648Sbaptucl_object_t * 1711263648Sbaptucl_object_new (void) 1712263648Sbapt{ 1713275223Sbapt return ucl_object_typed_new (UCL_NULL); 1714263648Sbapt} 1715263648Sbapt 1716263648Sbaptucl_object_t * 1717266636Sbaptucl_object_typed_new (ucl_type_t type) 1718263648Sbapt{ 1719275223Sbapt return ucl_object_new_full (type, 0); 1720275223Sbapt} 1721275223Sbapt 1722275223Sbaptucl_object_t * 1723275223Sbaptucl_object_new_full (ucl_type_t type, unsigned priority) 1724275223Sbapt{ 1725263648Sbapt ucl_object_t *new; 1726275223Sbapt 1727275223Sbapt if (type != UCL_USERDATA) { 1728275223Sbapt new = UCL_ALLOC (sizeof (ucl_object_t)); 1729275223Sbapt if (new != NULL) { 1730275223Sbapt memset (new, 0, sizeof (ucl_object_t)); 1731275223Sbapt new->ref = 1; 1732275223Sbapt new->type = (type <= UCL_NULL ? type : UCL_NULL); 1733275223Sbapt new->next = NULL; 1734275223Sbapt new->prev = new; 1735275223Sbapt ucl_object_set_priority (new, priority); 1736275223Sbapt } 1737263648Sbapt } 1738275223Sbapt else { 1739275223Sbapt new = ucl_object_new_userdata (NULL, NULL); 1740275223Sbapt ucl_object_set_priority (new, priority); 1741275223Sbapt } 1742275223Sbapt 1743263648Sbapt return new; 1744263648Sbapt} 1745263648Sbapt 1746275223Sbaptucl_object_t* 1747275223Sbaptucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter) 1748275223Sbapt{ 1749275223Sbapt struct ucl_object_userdata *new; 1750275223Sbapt size_t nsize = sizeof (*new); 1751275223Sbapt 1752275223Sbapt new = UCL_ALLOC (nsize); 1753275223Sbapt if (new != NULL) { 1754275223Sbapt memset (new, 0, nsize); 1755275223Sbapt new->obj.ref = 1; 1756275223Sbapt new->obj.type = UCL_USERDATA; 1757275223Sbapt new->obj.next = NULL; 1758275223Sbapt new->obj.prev = (ucl_object_t *)new; 1759275223Sbapt new->dtor = dtor; 1760275223Sbapt new->emitter = emitter; 1761275223Sbapt } 1762275223Sbapt 1763275223Sbapt return (ucl_object_t *)new; 1764275223Sbapt} 1765275223Sbapt 1766266636Sbaptucl_type_t 1767266636Sbaptucl_object_type (const ucl_object_t *obj) 1768266636Sbapt{ 1769266636Sbapt return obj->type; 1770266636Sbapt} 1771266636Sbapt 1772263648Sbaptucl_object_t* 1773263648Sbaptucl_object_fromstring (const char *str) 1774263648Sbapt{ 1775263648Sbapt return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 1776263648Sbapt} 1777263648Sbapt 1778263648Sbaptucl_object_t * 1779263648Sbaptucl_object_fromlstring (const char *str, size_t len) 1780263648Sbapt{ 1781263648Sbapt return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 1782263648Sbapt} 1783263648Sbapt 1784263648Sbaptucl_object_t * 1785263648Sbaptucl_object_fromint (int64_t iv) 1786263648Sbapt{ 1787263648Sbapt ucl_object_t *obj; 1788263648Sbapt 1789263648Sbapt obj = ucl_object_new (); 1790263648Sbapt if (obj != NULL) { 1791263648Sbapt obj->type = UCL_INT; 1792263648Sbapt obj->value.iv = iv; 1793263648Sbapt } 1794263648Sbapt 1795263648Sbapt return obj; 1796263648Sbapt} 1797263648Sbapt 1798263648Sbaptucl_object_t * 1799263648Sbaptucl_object_fromdouble (double dv) 1800263648Sbapt{ 1801263648Sbapt ucl_object_t *obj; 1802263648Sbapt 1803263648Sbapt obj = ucl_object_new (); 1804263648Sbapt if (obj != NULL) { 1805263648Sbapt obj->type = UCL_FLOAT; 1806263648Sbapt obj->value.dv = dv; 1807263648Sbapt } 1808263648Sbapt 1809263648Sbapt return obj; 1810263648Sbapt} 1811263648Sbapt 1812263648Sbaptucl_object_t* 1813263648Sbaptucl_object_frombool (bool bv) 1814263648Sbapt{ 1815263648Sbapt ucl_object_t *obj; 1816263648Sbapt 1817263648Sbapt obj = ucl_object_new (); 1818263648Sbapt if (obj != NULL) { 1819263648Sbapt obj->type = UCL_BOOLEAN; 1820263648Sbapt obj->value.iv = bv; 1821263648Sbapt } 1822263648Sbapt 1823263648Sbapt return obj; 1824263648Sbapt} 1825263648Sbapt 1826264789Sbaptbool 1827263648Sbaptucl_array_append (ucl_object_t *top, ucl_object_t *elt) 1828263648Sbapt{ 1829263648Sbapt ucl_object_t *head; 1830263648Sbapt 1831264789Sbapt if (elt == NULL || top == NULL) { 1832264789Sbapt return false; 1833263648Sbapt } 1834263648Sbapt 1835264789Sbapt head = top->value.av; 1836264789Sbapt if (head == NULL) { 1837263648Sbapt top->value.av = elt; 1838263648Sbapt elt->prev = elt; 1839263648Sbapt } 1840263648Sbapt else { 1841264789Sbapt elt->prev = head->prev; 1842264789Sbapt head->prev->next = elt; 1843264789Sbapt head->prev = elt; 1844263648Sbapt } 1845264789Sbapt elt->next = NULL; 1846264789Sbapt top->len ++; 1847263648Sbapt 1848264789Sbapt return true; 1849263648Sbapt} 1850263648Sbapt 1851264789Sbaptbool 1852263648Sbaptucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 1853263648Sbapt{ 1854263648Sbapt ucl_object_t *head; 1855263648Sbapt 1856264789Sbapt if (elt == NULL || top == NULL) { 1857264789Sbapt return false; 1858263648Sbapt } 1859263648Sbapt 1860264789Sbapt 1861264789Sbapt head = top->value.av; 1862264789Sbapt if (head == NULL) { 1863263648Sbapt top->value.av = elt; 1864263648Sbapt elt->prev = elt; 1865263648Sbapt } 1866263648Sbapt else { 1867264789Sbapt elt->prev = head->prev; 1868264789Sbapt head->prev = elt; 1869263648Sbapt } 1870264789Sbapt elt->next = head; 1871264789Sbapt top->value.av = elt; 1872264789Sbapt top->len ++; 1873263648Sbapt 1874264789Sbapt return true; 1875263648Sbapt} 1876263648Sbapt 1877275223Sbaptbool 1878275223Sbaptucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 1879275223Sbapt{ 1880275223Sbapt ucl_object_t *cur, *tmp, *cp; 1881275223Sbapt 1882275223Sbapt if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { 1883275223Sbapt return false; 1884275223Sbapt } 1885275223Sbapt 1886275223Sbapt DL_FOREACH_SAFE (elt->value.av, cur, tmp) { 1887275223Sbapt if (copy) { 1888275223Sbapt cp = ucl_object_copy (cur); 1889275223Sbapt } 1890275223Sbapt else { 1891275223Sbapt cp = ucl_object_ref (cur); 1892275223Sbapt } 1893275223Sbapt if (cp != NULL) { 1894275223Sbapt ucl_array_append (top, cp); 1895275223Sbapt } 1896275223Sbapt } 1897275223Sbapt 1898275223Sbapt return true; 1899275223Sbapt} 1900275223Sbapt 1901263648Sbaptucl_object_t * 1902263648Sbaptucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 1903263648Sbapt{ 1904263648Sbapt ucl_object_t *head; 1905263648Sbapt 1906263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1907263648Sbapt return NULL; 1908263648Sbapt } 1909263648Sbapt head = top->value.av; 1910263648Sbapt 1911263648Sbapt if (elt->prev == elt) { 1912263648Sbapt top->value.av = NULL; 1913263648Sbapt } 1914263648Sbapt else if (elt == head) { 1915263648Sbapt elt->next->prev = elt->prev; 1916263648Sbapt top->value.av = elt->next; 1917263648Sbapt } 1918263648Sbapt else { 1919263648Sbapt elt->prev->next = elt->next; 1920263648Sbapt if (elt->next) { 1921263648Sbapt elt->next->prev = elt->prev; 1922263648Sbapt } 1923263648Sbapt else { 1924263648Sbapt head->prev = elt->prev; 1925263648Sbapt } 1926263648Sbapt } 1927263648Sbapt elt->next = NULL; 1928263648Sbapt elt->prev = elt; 1929263648Sbapt top->len --; 1930263648Sbapt 1931263648Sbapt return elt; 1932263648Sbapt} 1933263648Sbapt 1934264789Sbaptconst ucl_object_t * 1935264789Sbaptucl_array_head (const ucl_object_t *top) 1936263648Sbapt{ 1937263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1938263648Sbapt return NULL; 1939263648Sbapt } 1940263648Sbapt return top->value.av; 1941263648Sbapt} 1942263648Sbapt 1943264789Sbaptconst ucl_object_t * 1944264789Sbaptucl_array_tail (const ucl_object_t *top) 1945263648Sbapt{ 1946263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1947263648Sbapt return NULL; 1948263648Sbapt } 1949263648Sbapt return top->value.av->prev; 1950263648Sbapt} 1951263648Sbapt 1952263648Sbaptucl_object_t * 1953263648Sbaptucl_array_pop_last (ucl_object_t *top) 1954263648Sbapt{ 1955264789Sbapt return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top))); 1956263648Sbapt} 1957263648Sbapt 1958263648Sbaptucl_object_t * 1959263648Sbaptucl_array_pop_first (ucl_object_t *top) 1960263648Sbapt{ 1961264789Sbapt return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top))); 1962263648Sbapt} 1963263648Sbapt 1964266636Sbaptconst ucl_object_t * 1965266636Sbaptucl_array_find_index (const ucl_object_t *top, unsigned int index) 1966266636Sbapt{ 1967266636Sbapt ucl_object_iter_t it = NULL; 1968266636Sbapt const ucl_object_t *ret; 1969266636Sbapt 1970266636Sbapt if (top == NULL || top->type != UCL_ARRAY || top->len == 0 || 1971266636Sbapt (index + 1) > top->len) { 1972266636Sbapt return NULL; 1973266636Sbapt } 1974266636Sbapt 1975266636Sbapt while ((ret = ucl_iterate_object (top, &it, true)) != NULL) { 1976266636Sbapt if (index == 0) { 1977266636Sbapt return ret; 1978266636Sbapt } 1979266636Sbapt --index; 1980266636Sbapt } 1981266636Sbapt 1982266636Sbapt return NULL; 1983266636Sbapt} 1984266636Sbapt 1985263648Sbaptucl_object_t * 1986275223Sbaptucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt, 1987275223Sbapt unsigned int index) 1988275223Sbapt{ 1989275223Sbapt ucl_object_t *cur, *tmp; 1990275223Sbapt 1991275223Sbapt if (top == NULL || top->type != UCL_ARRAY || elt == NULL || 1992275223Sbapt top->len == 0 || (index + 1) > top->len) { 1993275223Sbapt return NULL; 1994275223Sbapt } 1995275223Sbapt 1996275223Sbapt DL_FOREACH_SAFE (top->value.av, cur, tmp) { 1997275223Sbapt if (index == 0) { 1998275223Sbapt DL_REPLACE_ELEM (top->value.av, cur, elt); 1999275223Sbapt return cur; 2000275223Sbapt } 2001275223Sbapt --index; 2002275223Sbapt } 2003275223Sbapt 2004275223Sbapt return NULL; 2005275223Sbapt} 2006275223Sbapt 2007275223Sbaptucl_object_t * 2008263648Sbaptucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 2009263648Sbapt{ 2010263648Sbapt 2011263648Sbapt if (head == NULL) { 2012263648Sbapt elt->next = NULL; 2013263648Sbapt elt->prev = elt; 2014263648Sbapt head = elt; 2015263648Sbapt } 2016263648Sbapt else { 2017263648Sbapt elt->prev = head->prev; 2018263648Sbapt head->prev->next = elt; 2019263648Sbapt head->prev = elt; 2020263648Sbapt elt->next = NULL; 2021263648Sbapt } 2022263648Sbapt 2023263648Sbapt return head; 2024263648Sbapt} 2025263648Sbapt 2026263648Sbaptbool 2027264789Sbaptucl_object_todouble_safe (const ucl_object_t *obj, double *target) 2028263648Sbapt{ 2029263648Sbapt if (obj == NULL || target == NULL) { 2030263648Sbapt return false; 2031263648Sbapt } 2032263648Sbapt switch (obj->type) { 2033263648Sbapt case UCL_INT: 2034263648Sbapt *target = obj->value.iv; /* Probaly could cause overflow */ 2035263648Sbapt break; 2036263648Sbapt case UCL_FLOAT: 2037263648Sbapt case UCL_TIME: 2038263648Sbapt *target = obj->value.dv; 2039263648Sbapt break; 2040263648Sbapt default: 2041263648Sbapt return false; 2042263648Sbapt } 2043263648Sbapt 2044263648Sbapt return true; 2045263648Sbapt} 2046263648Sbapt 2047263648Sbaptdouble 2048264789Sbaptucl_object_todouble (const ucl_object_t *obj) 2049263648Sbapt{ 2050263648Sbapt double result = 0.; 2051263648Sbapt 2052263648Sbapt ucl_object_todouble_safe (obj, &result); 2053263648Sbapt return result; 2054263648Sbapt} 2055263648Sbapt 2056263648Sbaptbool 2057264789Sbaptucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 2058263648Sbapt{ 2059263648Sbapt if (obj == NULL || target == NULL) { 2060263648Sbapt return false; 2061263648Sbapt } 2062263648Sbapt switch (obj->type) { 2063263648Sbapt case UCL_INT: 2064263648Sbapt *target = obj->value.iv; 2065263648Sbapt break; 2066263648Sbapt case UCL_FLOAT: 2067263648Sbapt case UCL_TIME: 2068263648Sbapt *target = obj->value.dv; /* Loosing of decimal points */ 2069263648Sbapt break; 2070263648Sbapt default: 2071263648Sbapt return false; 2072263648Sbapt } 2073263648Sbapt 2074263648Sbapt return true; 2075263648Sbapt} 2076263648Sbapt 2077263648Sbaptint64_t 2078264789Sbaptucl_object_toint (const ucl_object_t *obj) 2079263648Sbapt{ 2080263648Sbapt int64_t result = 0; 2081263648Sbapt 2082263648Sbapt ucl_object_toint_safe (obj, &result); 2083263648Sbapt return result; 2084263648Sbapt} 2085263648Sbapt 2086263648Sbaptbool 2087264789Sbaptucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 2088263648Sbapt{ 2089263648Sbapt if (obj == NULL || target == NULL) { 2090263648Sbapt return false; 2091263648Sbapt } 2092263648Sbapt switch (obj->type) { 2093263648Sbapt case UCL_BOOLEAN: 2094263648Sbapt *target = (obj->value.iv == true); 2095263648Sbapt break; 2096263648Sbapt default: 2097263648Sbapt return false; 2098263648Sbapt } 2099263648Sbapt 2100263648Sbapt return true; 2101263648Sbapt} 2102263648Sbapt 2103263648Sbaptbool 2104264789Sbaptucl_object_toboolean (const ucl_object_t *obj) 2105263648Sbapt{ 2106263648Sbapt bool result = false; 2107263648Sbapt 2108263648Sbapt ucl_object_toboolean_safe (obj, &result); 2109263648Sbapt return result; 2110263648Sbapt} 2111263648Sbapt 2112263648Sbaptbool 2113264789Sbaptucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 2114263648Sbapt{ 2115263648Sbapt if (obj == NULL || target == NULL) { 2116263648Sbapt return false; 2117263648Sbapt } 2118263648Sbapt 2119263648Sbapt switch (obj->type) { 2120263648Sbapt case UCL_STRING: 2121263648Sbapt *target = ucl_copy_value_trash (obj); 2122263648Sbapt break; 2123263648Sbapt default: 2124263648Sbapt return false; 2125263648Sbapt } 2126263648Sbapt 2127263648Sbapt return true; 2128263648Sbapt} 2129263648Sbapt 2130263648Sbaptconst char * 2131264789Sbaptucl_object_tostring (const ucl_object_t *obj) 2132263648Sbapt{ 2133263648Sbapt const char *result = NULL; 2134263648Sbapt 2135263648Sbapt ucl_object_tostring_safe (obj, &result); 2136263648Sbapt return result; 2137263648Sbapt} 2138263648Sbapt 2139263648Sbaptconst char * 2140264789Sbaptucl_object_tostring_forced (const ucl_object_t *obj) 2141263648Sbapt{ 2142263648Sbapt return ucl_copy_value_trash (obj); 2143263648Sbapt} 2144263648Sbapt 2145263648Sbaptbool 2146264789Sbaptucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 2147263648Sbapt{ 2148263648Sbapt if (obj == NULL || target == NULL) { 2149263648Sbapt return false; 2150263648Sbapt } 2151263648Sbapt switch (obj->type) { 2152263648Sbapt case UCL_STRING: 2153263648Sbapt *target = obj->value.sv; 2154263648Sbapt if (tlen != NULL) { 2155263648Sbapt *tlen = obj->len; 2156263648Sbapt } 2157263648Sbapt break; 2158263648Sbapt default: 2159263648Sbapt return false; 2160263648Sbapt } 2161263648Sbapt 2162263648Sbapt return true; 2163263648Sbapt} 2164263648Sbapt 2165263648Sbaptconst char * 2166264789Sbaptucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 2167263648Sbapt{ 2168263648Sbapt const char *result = NULL; 2169263648Sbapt 2170263648Sbapt ucl_object_tolstring_safe (obj, &result, tlen); 2171263648Sbapt return result; 2172263648Sbapt} 2173263648Sbapt 2174263648Sbaptconst char * 2175264789Sbaptucl_object_key (const ucl_object_t *obj) 2176263648Sbapt{ 2177263648Sbapt return ucl_copy_key_trash (obj); 2178263648Sbapt} 2179263648Sbapt 2180263648Sbaptconst char * 2181264789Sbaptucl_object_keyl (const ucl_object_t *obj, size_t *len) 2182263648Sbapt{ 2183263648Sbapt if (len == NULL || obj == NULL) { 2184263648Sbapt return NULL; 2185263648Sbapt } 2186263648Sbapt *len = obj->keylen; 2187263648Sbapt return obj->key; 2188263648Sbapt} 2189263648Sbapt 2190263648Sbaptucl_object_t * 2191264789Sbaptucl_object_ref (const ucl_object_t *obj) 2192263648Sbapt{ 2193264789Sbapt ucl_object_t *res = NULL; 2194264789Sbapt 2195263648Sbapt if (obj != NULL) { 2196275223Sbapt if (obj->flags & UCL_OBJECT_EPHEMERAL) { 2197275223Sbapt /* 2198275223Sbapt * Use deep copy for ephemeral objects, note that its refcount 2199275223Sbapt * is NOT increased, since ephemeral objects does not need refcount 2200275223Sbapt * at all 2201275223Sbapt */ 2202275223Sbapt res = ucl_object_copy (obj); 2203275223Sbapt } 2204275223Sbapt else { 2205275223Sbapt res = __DECONST (ucl_object_t *, obj); 2206264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 2207275223Sbapt (void)__sync_add_and_fetch (&res->ref, 1); 2208264789Sbapt#else 2209275223Sbapt res->ref ++; 2210264789Sbapt#endif 2211275223Sbapt } 2212263648Sbapt } 2213264789Sbapt return res; 2214263648Sbapt} 2215263648Sbapt 2216275223Sbaptstatic ucl_object_t * 2217275223Sbaptucl_object_copy_internal (const ucl_object_t *other, bool allow_array) 2218275223Sbapt{ 2219275223Sbapt 2220275223Sbapt ucl_object_t *new; 2221275223Sbapt ucl_object_iter_t it = NULL; 2222275223Sbapt const ucl_object_t *cur; 2223275223Sbapt 2224275223Sbapt new = malloc (sizeof (*new)); 2225275223Sbapt 2226275223Sbapt if (new != NULL) { 2227275223Sbapt memcpy (new, other, sizeof (*new)); 2228275223Sbapt if (other->flags & UCL_OBJECT_EPHEMERAL) { 2229275223Sbapt /* Copied object is always non ephemeral */ 2230275223Sbapt new->flags &= ~UCL_OBJECT_EPHEMERAL; 2231275223Sbapt } 2232275223Sbapt new->ref = 1; 2233275223Sbapt /* Unlink from others */ 2234275223Sbapt new->next = NULL; 2235275223Sbapt new->prev = new; 2236275223Sbapt 2237275223Sbapt /* deep copy of values stored */ 2238275223Sbapt if (other->trash_stack[UCL_TRASH_KEY] != NULL) { 2239275223Sbapt new->trash_stack[UCL_TRASH_KEY] = 2240275223Sbapt strdup (other->trash_stack[UCL_TRASH_KEY]); 2241275223Sbapt if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { 2242275223Sbapt new->key = new->trash_stack[UCL_TRASH_KEY]; 2243275223Sbapt } 2244275223Sbapt } 2245275223Sbapt if (other->trash_stack[UCL_TRASH_VALUE] != NULL) { 2246275223Sbapt new->trash_stack[UCL_TRASH_VALUE] = 2247275223Sbapt strdup (other->trash_stack[UCL_TRASH_VALUE]); 2248275223Sbapt if (new->type == UCL_STRING) { 2249275223Sbapt new->value.sv = new->trash_stack[UCL_TRASH_VALUE]; 2250275223Sbapt } 2251275223Sbapt } 2252275223Sbapt 2253275223Sbapt if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) { 2254275223Sbapt /* reset old value */ 2255275223Sbapt memset (&new->value, 0, sizeof (new->value)); 2256275223Sbapt 2257275223Sbapt while ((cur = ucl_iterate_object (other, &it, true)) != NULL) { 2258275223Sbapt if (other->type == UCL_ARRAY) { 2259275223Sbapt ucl_array_append (new, ucl_object_copy_internal (cur, false)); 2260275223Sbapt } 2261275223Sbapt else { 2262275223Sbapt ucl_object_t *cp = ucl_object_copy_internal (cur, true); 2263275223Sbapt if (cp != NULL) { 2264275223Sbapt ucl_object_insert_key (new, cp, cp->key, cp->keylen, 2265275223Sbapt false); 2266275223Sbapt } 2267275223Sbapt } 2268275223Sbapt } 2269275223Sbapt } 2270275223Sbapt else if (allow_array && other->next != NULL) { 2271275223Sbapt LL_FOREACH (other->next, cur) { 2272275223Sbapt ucl_object_t *cp = ucl_object_copy_internal (cur, false); 2273275223Sbapt if (cp != NULL) { 2274275223Sbapt DL_APPEND (new, cp); 2275275223Sbapt } 2276275223Sbapt } 2277275223Sbapt } 2278275223Sbapt } 2279275223Sbapt 2280275223Sbapt return new; 2281275223Sbapt} 2282275223Sbapt 2283275223Sbaptucl_object_t * 2284275223Sbaptucl_object_copy (const ucl_object_t *other) 2285275223Sbapt{ 2286275223Sbapt return ucl_object_copy_internal (other, true); 2287275223Sbapt} 2288275223Sbapt 2289263648Sbaptvoid 2290263648Sbaptucl_object_unref (ucl_object_t *obj) 2291263648Sbapt{ 2292264789Sbapt if (obj != NULL) { 2293264789Sbapt#ifdef HAVE_ATOMIC_BUILTINS 2294264789Sbapt unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 2295264789Sbapt if (rc == 0) { 2296264789Sbapt#else 2297264789Sbapt if (--obj->ref == 0) { 2298264789Sbapt#endif 2299264789Sbapt ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 2300264789Sbapt } 2301263648Sbapt } 2302263648Sbapt} 2303263648Sbapt 2304263648Sbaptint 2305264789Sbaptucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 2306263648Sbapt{ 2307264789Sbapt const ucl_object_t *it1, *it2; 2308263648Sbapt ucl_object_iter_t iter = NULL; 2309263648Sbapt int ret = 0; 2310263648Sbapt 2311263648Sbapt if (o1->type != o2->type) { 2312263648Sbapt return (o1->type) - (o2->type); 2313263648Sbapt } 2314263648Sbapt 2315263648Sbapt switch (o1->type) { 2316263648Sbapt case UCL_STRING: 2317263648Sbapt if (o1->len == o2->len) { 2318263648Sbapt ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 2319263648Sbapt } 2320263648Sbapt else { 2321263648Sbapt ret = o1->len - o2->len; 2322263648Sbapt } 2323263648Sbapt break; 2324263648Sbapt case UCL_FLOAT: 2325263648Sbapt case UCL_INT: 2326263648Sbapt case UCL_TIME: 2327263648Sbapt ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 2328263648Sbapt break; 2329263648Sbapt case UCL_BOOLEAN: 2330263648Sbapt ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 2331263648Sbapt break; 2332263648Sbapt case UCL_ARRAY: 2333263648Sbapt if (o1->len == o2->len) { 2334263648Sbapt it1 = o1->value.av; 2335263648Sbapt it2 = o2->value.av; 2336263648Sbapt /* Compare all elements in both arrays */ 2337263648Sbapt while (it1 != NULL && it2 != NULL) { 2338263648Sbapt ret = ucl_object_compare (it1, it2); 2339263648Sbapt if (ret != 0) { 2340263648Sbapt break; 2341263648Sbapt } 2342263648Sbapt it1 = it1->next; 2343263648Sbapt it2 = it2->next; 2344263648Sbapt } 2345263648Sbapt } 2346263648Sbapt else { 2347263648Sbapt ret = o1->len - o2->len; 2348263648Sbapt } 2349263648Sbapt break; 2350263648Sbapt case UCL_OBJECT: 2351263648Sbapt if (o1->len == o2->len) { 2352263648Sbapt while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 2353263648Sbapt it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 2354263648Sbapt if (it2 == NULL) { 2355263648Sbapt ret = 1; 2356263648Sbapt break; 2357263648Sbapt } 2358263648Sbapt ret = ucl_object_compare (it1, it2); 2359263648Sbapt if (ret != 0) { 2360263648Sbapt break; 2361263648Sbapt } 2362263648Sbapt } 2363263648Sbapt } 2364263648Sbapt else { 2365263648Sbapt ret = o1->len - o2->len; 2366263648Sbapt } 2367263648Sbapt break; 2368263648Sbapt default: 2369263648Sbapt ret = 0; 2370263648Sbapt break; 2371263648Sbapt } 2372263648Sbapt 2373263648Sbapt return ret; 2374263648Sbapt} 2375263648Sbapt 2376263648Sbaptvoid 2377263648Sbaptucl_object_array_sort (ucl_object_t *ar, 2378264789Sbapt int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2)) 2379263648Sbapt{ 2380263648Sbapt if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 2381263648Sbapt return; 2382263648Sbapt } 2383263648Sbapt 2384263648Sbapt DL_SORT (ar->value.av, cmp); 2385263648Sbapt} 2386275223Sbapt 2387275223Sbapt#define PRIOBITS 4 2388275223Sbapt 2389275223Sbaptunsigned int 2390275223Sbaptucl_object_get_priority (const ucl_object_t *obj) 2391275223Sbapt{ 2392275223Sbapt if (obj == NULL) { 2393275223Sbapt return 0; 2394275223Sbapt } 2395275223Sbapt 2396275223Sbapt return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS)); 2397275223Sbapt} 2398275223Sbapt 2399275223Sbaptvoid 2400275223Sbaptucl_object_set_priority (ucl_object_t *obj, 2401275223Sbapt unsigned int priority) 2402275223Sbapt{ 2403275223Sbapt if (obj != NULL) { 2404275223Sbapt priority &= (0x1 << PRIOBITS) - 1; 2405275223Sbapt obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS); 2406275223Sbapt } 2407275223Sbapt} 2408