ucl_util.c revision 264789
1221828Sgrehan/* Copyright (c) 2013, Vsevolod Stakhov 2221828Sgrehan * All rights reserved. 3221828Sgrehan * 4221828Sgrehan * Redistribution and use in source and binary forms, with or without 5221828Sgrehan * modification, are permitted provided that the following conditions are met: 6221828Sgrehan * * Redistributions of source code must retain the above copyright 7221828Sgrehan * notice, this list of conditions and the following disclaimer. 8221828Sgrehan * * Redistributions in binary form must reproduce the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer in the 10221828Sgrehan * documentation and/or other materials provided with the distribution. 11221828Sgrehan * 12221828Sgrehan * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13221828Sgrehan * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14221828Sgrehan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15221828Sgrehan * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16221828Sgrehan * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17221828Sgrehan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18221828Sgrehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19221828Sgrehan * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20221828Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21221828Sgrehan * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22221828Sgrehan */ 23221828Sgrehan 24221828Sgrehan#include "ucl.h" 25221828Sgrehan#include "ucl_internal.h" 26221828Sgrehan#include "ucl_chartable.h" 27221828Sgrehan 28221828Sgrehan#ifdef HAVE_LIBGEN_H 29221828Sgrehan#include <libgen.h> /* For dirname */ 30221828Sgrehan#endif 31221828Sgrehan 32240941Sneel#ifdef HAVE_OPENSSL 33267427Sjhb#include <openssl/err.h> 34222610Sjhb#include <openssl/sha.h> 35276349Sneel#include <openssl/rsa.h> 36221828Sgrehan#include <openssl/ssl.h> 37249324Sneel#include <openssl/evp.h> 38221828Sgrehan#endif 39222610Sjhb 40267427Sjhb#ifdef CURL_FOUND 41221828Sgrehan#include <curl/curl.h> 42221828Sgrehan#endif 43240941Sneel#ifdef HAVE_FETCH_H 44240941Sneel#include <fetch.h> 45267427Sjhb#endif 46276403Sneel 47276403Sneel#ifdef _WIN32 48221828Sgrehan#include <windows.h> 49221828Sgrehan 50276349Sneel#ifndef PROT_READ 51276349Sneel#define PROT_READ 1 52276349Sneel#endif 53222610Sjhb#ifndef PROT_WRITE 54222610Sjhb#define PROT_WRITE 2 55252335Sgrehan#endif 56222610Sjhb#ifndef PROT_READWRITE 57252335Sgrehan#define PROT_READWRITE 3 58276403Sneel#endif 59276403Sneel#ifndef MAP_SHARED 60252335Sgrehan#define MAP_SHARED 1 61276349Sneel#endif 62276349Sneel#ifndef MAP_PRIVATE 63276349Sneel#define MAP_PRIVATE 2 64276349Sneel#endif 65276349Sneel#ifndef MAP_FAILED 66276349Sneel#define MAP_FAILED ((void *) -1) 67276349Sneel#endif 68276349Sneel 69276349Sneelstatic void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 70276349Sneel{ 71276349Sneel void *map = NULL; 72276349Sneel HANDLE handle = INVALID_HANDLE_VALUE; 73276349Sneel 74276349Sneel switch (prot) { 75276349Sneel default: 76276349Sneel case PROT_READ: 77276349Sneel { 78276349Sneel handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 79276349Sneel if (!handle) break; 80276349Sneel map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 81276349Sneel CloseHandle(handle); 82276349Sneel break; 83276349Sneel } 84276349Sneel case PROT_WRITE: 85276349Sneel { 86276349Sneel handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 87221828Sgrehan if (!handle) break; 88240941Sneel map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 89240941Sneel CloseHandle(handle); 90221828Sgrehan break; 91267427Sjhb } 92267427Sjhb case PROT_READWRITE: 93276349Sneel { 94276349Sneel handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 95240941Sneel if (!handle) break; 96221828Sgrehan map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 97276403Sneel CloseHandle(handle); 98276403Sneel break; 99222610Sjhb } 100222610Sjhb } 101222610Sjhb if (map == (void *) NULL) { 102222610Sjhb return (void *) MAP_FAILED; 103222610Sjhb } 104222610Sjhb return (void *) ((char *) map + offset); 105222610Sjhb} 106222610Sjhb 107222610Sjhbstatic int ucl_munmap(void *map,size_t length) 108222610Sjhb{ 109222610Sjhb if (!UnmapViewOfFile(map)) { 110222610Sjhb return(-1); 111222610Sjhb } 112221828Sgrehan return(0); 113246774Sneel} 114246774Sneel 115222610Sjhbstatic char* ucl_realpath(const char *path, char *resolved_path) { 116222610Sjhb char *p; 117222610Sjhb char tmp[MAX_PATH + 1]; 118222610Sjhb strncpy(tmp, path, sizeof(tmp)-1); 119222610Sjhb p = tmp; 120222610Sjhb while(*p) { 121252335Sgrehan if (*p == '/') *p = '\\'; 122252335Sgrehan p++; 123252335Sgrehan } 124221828Sgrehan return _fullpath(resolved_path, tmp, MAX_PATH); 125221828Sgrehan} 126221828Sgrehan#else 127221828Sgrehan#define ucl_mmap mmap 128221828Sgrehan#define ucl_munmap munmap 129221828Sgrehan#define ucl_realpath realpath 130221828Sgrehan#endif 131221828Sgrehan 132276403Sneel/** 133276403Sneel * @file rcl_util.c 134221828Sgrehan * Utilities for rcl parsing 135222610Sjhb */ 136276403Sneel 137276403Sneeltypedef void (*ucl_object_dtor) (ucl_object_t *obj); 138276403Sneelstatic void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 139276403Sneel ucl_object_dtor dtor); 140276403Sneelstatic void ucl_object_dtor_unref (ucl_object_t *obj); 141276403Sneel 142276403Sneelstatic void 143276403Sneelucl_object_dtor_free (ucl_object_t *obj) 144276403Sneel{ 145276403Sneel if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 146276403Sneel UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 147276403Sneel } 148276403Sneel if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 149276403Sneel UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 150221828Sgrehan } 151221828Sgrehan UCL_FREE (sizeof (ucl_object_t), obj); 152252335Sgrehan} 153276403Sneel 154276403Sneel/* 155252335Sgrehan * This is a helper function that performs exactly the same as 156276403Sneel * `ucl_object_unref` but it doesn't iterate over elements allowing 157276403Sneel * to use it for individual elements of arrays and multiple values 158276403Sneel */ 159276403Sneelstatic void 160276403Sneelucl_object_dtor_unref_single (ucl_object_t *obj) 161276403Sneel{ 162276403Sneel if (obj != NULL) { 163276403Sneel#ifdef HAVE_ATOMIC_BUILTINS 164276403Sneel unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 165276403Sneel if (rc == 0) { 166276403Sneel#else 167276403Sneel if (--obj->ref == 0) { 168276403Sneel#endif 169276403Sneel ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 170276403Sneel } 171276403Sneel } 172276403Sneel} 173276403Sneel 174276403Sneelstatic void 175276403Sneelucl_object_dtor_unref (ucl_object_t *obj) 176276403Sneel{ 177276403Sneel if (obj->ref == 0) { 178276403Sneel ucl_object_dtor_free (obj); 179315928Sgrehan } 180315928Sgrehan else { 181315928Sgrehan /* This may cause dtor unref being called one more time */ 182276403Sneel ucl_object_dtor_unref_single (obj); 183252335Sgrehan } 184252335Sgrehan} 185252335Sgrehan 186252335Sgrehanstatic void 187252335Sgrehanucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 188252335Sgrehan{ 189249324Sneel ucl_object_t *sub, *tmp; 190249324Sneel 191276403Sneel while (obj != NULL) { 192276403Sneel if (obj->type == UCL_ARRAY) { 193276403Sneel sub = obj->value.av; 194276403Sneel while (sub != NULL) { 195249324Sneel tmp = sub->next; 196276403Sneel dtor (sub); 197276403Sneel sub = tmp; 198276403Sneel } 199276403Sneel } 200276403Sneel else if (obj->type == UCL_OBJECT) { 201276403Sneel if (obj->value.ov != NULL) { 202276403Sneel ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); 203276403Sneel } 204276403Sneel } 205276403Sneel tmp = obj->next; 206276403Sneel dtor (obj); 207276403Sneel obj = tmp; 208276403Sneel 209276403Sneel if (!allow_rec) { 210249324Sneel break; 211249324Sneel } 212249324Sneel } 213249324Sneel} 214249324Sneel 215249324Sneelvoid 216276403Sneelucl_object_free (ucl_object_t *obj) 217276403Sneel{ 218249324Sneel ucl_object_free_internal (obj, true, ucl_object_dtor_free); 219249324Sneel} 220221828Sgrehan 221222610Sjhbsize_t 222222610Sjhbucl_unescape_json_string (char *str, size_t len) 223240941Sneel{ 224240941Sneel char *t = str, *h = str; 225240941Sneel int i, uval; 226240941Sneel 227240941Sneel if (len <= 1) { 228240941Sneel return len; 229221828Sgrehan } 230221828Sgrehan /* t is target (tortoise), h is source (hare) */ 231221828Sgrehan 232222610Sjhb while (len) { 233222610Sjhb if (*h == '\\') { 234221828Sgrehan h ++; 235221828Sgrehan switch (*h) { 236284900Sneel case 'n': 237222610Sjhb *t++ = '\n'; 238221828Sgrehan break; 239222610Sjhb case 'r': 240284900Sneel *t++ = '\r'; 241221828Sgrehan break; 242240941Sneel case 'b': 243240941Sneel *t++ = '\b'; 244240941Sneel break; 245240941Sneel case 't': 246267447Sjhb *t++ = '\t'; 247267447Sjhb break; 248240941Sneel case 'f': 249221828Sgrehan *t++ = '\f'; 250267427Sjhb break; 251267427Sjhb case '\\': 252234939Sgrehan *t++ = '\\'; 253267427Sjhb break; 254267427Sjhb case '"': 255234939Sgrehan *t++ = '"'; 256234939Sgrehan break; 257267427Sjhb case 'u': 258267427Sjhb /* Unicode escape */ 259267427Sjhb uval = 0; 260267427Sjhb if (len > 3) { 261267427Sjhb for (i = 0; i < 4; i++) { 262267427Sjhb uval <<= 4; 263267427Sjhb if (isdigit (h[i])) { 264267427Sjhb uval += h[i] - '0'; 265267427Sjhb } 266267427Sjhb else if (h[i] >= 'a' && h[i] <= 'f') { 267267427Sjhb uval += h[i] - 'a' + 10; 268267427Sjhb } 269267427Sjhb else if (h[i] >= 'A' && h[i] <= 'F') { 270267427Sjhb uval += h[i] - 'A' + 10; 271267427Sjhb } 272267427Sjhb else { 273242060Sneel break; 274242060Sneel } 275242060Sneel } 276242060Sneel h += 3; 277242060Sneel len -= 3; 278252335Sgrehan /* Encode */ 279252335Sgrehan if(uval < 0x80) { 280252335Sgrehan t[0] = (char)uval; 281252335Sgrehan t ++; 282255645Sgrehan } 283242060Sneel else if(uval < 0x800) { 284255645Sgrehan t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 285255645Sgrehan t[1] = 0x80 + ((uval & 0x03F)); 286255645Sgrehan t += 2; 287255645Sgrehan } 288255645Sgrehan else if(uval < 0x10000) { 289222105Sgrehan t[0] = 0xE0 + ((uval & 0xF000) >> 12); 290222105Sgrehan t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 291222105Sgrehan t[2] = 0x80 + ((uval & 0x003F)); 292284900Sneel t += 3; 293222105Sgrehan } 294284900Sneel else if(uval <= 0x10FFFF) { 295221828Sgrehan t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 296252335Sgrehan t[1] = 0x80 + ((uval & 0x03F000) >> 12); 297252335Sgrehan t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 298284900Sneel t[3] = 0x80 + ((uval & 0x00003F)); 299284900Sneel t += 4; 300284900Sneel } 301284900Sneel else { 302284900Sneel *t++ = '?'; 303284900Sneel } 304284900Sneel } 305284900Sneel else { 306276349Sneel *t++ = 'u'; 307222610Sjhb } 308276349Sneel break; 309276349Sneel default: 310221828Sgrehan *t++ = *h; 311221828Sgrehan break; 312222610Sjhb } 313276349Sneel h ++; 314222610Sjhb len --; 315276349Sneel } 316276349Sneel else { 317276349Sneel *t++ = *h++; 318276349Sneel } 319276349Sneel len --; 320276349Sneel } 321276349Sneel *t = '\0'; 322276349Sneel 323276349Sneel return (t - str); 324276349Sneel} 325276349Sneel 326276349Sneelchar * 327276349Sneelucl_copy_key_trash (const ucl_object_t *obj) 328276349Sneel{ 329276349Sneel ucl_object_t *deconst; 330276349Sneel 331222610Sjhb if (obj == NULL) { 332222610Sjhb return NULL; 333256869Sneel } 334256869Sneel if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 335256869Sneel deconst = __DECONST (ucl_object_t *, obj); 336256869Sneel deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 337256869Sneel if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 338256869Sneel memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 339256869Sneel deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 340256869Sneel } 341267427Sjhb deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 342267427Sjhb deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 343267427Sjhb } 344267427Sjhb 345267427Sjhb return obj->trash_stack[UCL_TRASH_KEY]; 346267427Sjhb} 347267427Sjhb 348267427Sjhbchar * 349267427Sjhbucl_copy_value_trash (const ucl_object_t *obj) 350267427Sjhb{ 351267427Sjhb ucl_object_t *deconst; 352267427Sjhb 353267427Sjhb if (obj == NULL) { 354267427Sjhb return NULL; 355267427Sjhb } 356267427Sjhb if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 357267427Sjhb deconst = __DECONST (ucl_object_t *, obj); 358267427Sjhb if (obj->type == UCL_STRING) { 359267427Sjhb 360267427Sjhb /* Special case for strings */ 361256869Sneel deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 362256869Sneel if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 363256869Sneel memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 364256869Sneel deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 365256869Sneel deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 366256869Sneel } 367256869Sneel } 368222105Sgrehan else { 369280839Smav /* Just emit value in json notation */ 370280839Smav deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 371280839Smav deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 372280839Smav } 373280839Smav deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 374280839Smav } 375252335Sgrehan return obj->trash_stack[UCL_TRASH_VALUE]; 376222105Sgrehan} 377222105Sgrehan 378222105SgrehanUCL_EXTERN ucl_object_t* 379222105Sgrehanucl_parser_get_object (struct ucl_parser *parser) 380222105Sgrehan{ 381222105Sgrehan if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 382222105Sgrehan return ucl_object_ref (parser->top_obj); 383222105Sgrehan } 384222105Sgrehan 385222105Sgrehan return NULL; 386221828Sgrehan} 387221828Sgrehan 388221828SgrehanUCL_EXTERN void 389221828Sgrehanucl_parser_free (struct ucl_parser *parser) 390276349Sneel{ 391276349Sneel struct ucl_stack *stack, *stmp; 392276349Sneel struct ucl_macro *macro, *mtmp; 393276349Sneel struct ucl_chunk *chunk, *ctmp; 394276349Sneel struct ucl_pubkey *key, *ktmp; 395276349Sneel struct ucl_variable *var, *vtmp; 396276349Sneel 397276349Sneel if (parser == NULL) { 398276349Sneel return; 399276349Sneel } 400276349Sneel 401276349Sneel if (parser->top_obj != NULL) { 402276349Sneel ucl_object_unref (parser->top_obj); 403276349Sneel } 404276349Sneel 405276349Sneel LL_FOREACH_SAFE (parser->stack, stack, stmp) { 406276349Sneel free (stack); 407276349Sneel } 408276349Sneel HASH_ITER (hh, parser->macroes, macro, mtmp) { 409276349Sneel free (macro->name); 410276349Sneel HASH_DEL (parser->macroes, macro); 411276349Sneel UCL_FREE (sizeof (struct ucl_macro), macro); 412276349Sneel } 413276349Sneel LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 414276349Sneel UCL_FREE (sizeof (struct ucl_chunk), chunk); 415276349Sneel } 416221828Sgrehan LL_FOREACH_SAFE (parser->keys, key, ktmp) { 417221828Sgrehan UCL_FREE (sizeof (struct ucl_pubkey), key); 418267427Sjhb } 419267427Sjhb LL_FOREACH_SAFE (parser->variables, var, vtmp) { 420267427Sjhb free (var->value); 421267427Sjhb free (var->var); 422267427Sjhb UCL_FREE (sizeof (struct ucl_variable), var); 423267427Sjhb } 424267427Sjhb 425267427Sjhb if (parser->err != NULL) { 426267427Sjhb utstring_free(parser->err); 427267427Sjhb } 428267427Sjhb 429267427Sjhb UCL_FREE (sizeof (struct ucl_parser), parser); 430267427Sjhb} 431267427Sjhb 432267427SjhbUCL_EXTERN const char * 433267427Sjhbucl_parser_get_error(struct ucl_parser *parser) 434267427Sjhb{ 435267427Sjhb if (parser == NULL) { 436267427Sjhb return NULL; 437267427Sjhb } 438267427Sjhb 439267427Sjhb if (parser->err == NULL) 440267427Sjhb return NULL; 441267427Sjhb 442267427Sjhb return utstring_body(parser->err); 443267427Sjhb} 444267427Sjhb 445267427SjhbUCL_EXTERN bool 446267427Sjhbucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 447267427Sjhb{ 448267427Sjhb#ifndef HAVE_OPENSSL 449267427Sjhb ucl_create_err (&parser->err, "cannot check signatures without openssl"); 450267427Sjhb return false; 451267427Sjhb#else 452267427Sjhb# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 453267427Sjhb ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 454267427Sjhb return EXIT_FAILURE; 455267427Sjhb# else 456267427Sjhb struct ucl_pubkey *nkey; 457267427Sjhb BIO *mem; 458267427Sjhb 459267427Sjhb mem = BIO_new_mem_buf ((void *)key, len); 460267427Sjhb nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 461267427Sjhb if (nkey == NULL) { 462267427Sjhb ucl_create_err (&parser->err, "cannot allocate memory for key"); 463267427Sjhb return false; 464267427Sjhb } 465267427Sjhb nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 466267427Sjhb BIO_free (mem); 467267427Sjhb if (nkey->key == NULL) { 468267427Sjhb UCL_FREE (sizeof (struct ucl_pubkey), nkey); 469222610Sjhb ucl_create_err (&parser->err, "%s", 470222610Sjhb ERR_error_string (ERR_get_error (), NULL)); 471222610Sjhb return false; 472252335Sgrehan } 473252335Sgrehan LL_PREPEND (parser->keys, nkey); 474222610Sjhb# endif 475252335Sgrehan#endif 476221828Sgrehan return true; 477252335Sgrehan} 478252335Sgrehan 479252335Sgrehan#ifdef CURL_FOUND 480252335Sgrehanstruct ucl_curl_cbdata { 481252335Sgrehan unsigned char *buf; 482252335Sgrehan size_t buflen; 483252335Sgrehan}; 484252335Sgrehan 485221828Sgrehanstatic size_t 486221828Sgrehanucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 487221828Sgrehan{ 488221828Sgrehan struct ucl_curl_cbdata *cbdata = ud; 489221828Sgrehan size_t realsize = size * nmemb; 490221828Sgrehan 491252335Sgrehan cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 492221828Sgrehan if (cbdata->buf == NULL) { 493221828Sgrehan return 0; 494284900Sneel } 495284900Sneel 496284900Sneel memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 497284900Sneel cbdata->buflen += realsize; 498284900Sneel cbdata->buf[cbdata->buflen] = 0; 499284900Sneel 500284900Sneel return realsize; 501284900Sneel} 502284900Sneel#endif 503284900Sneel 504284900Sneel/** 505284900Sneel * Fetch a url and save results to the memory buffer 506284900Sneel * @param url url to fetch 507284900Sneel * @param len length of url 508284900Sneel * @param buf target buffer 509284900Sneel * @param buflen target length 510284900Sneel * @return 511284900Sneel */ 512284900Sneelstatic bool 513284900Sneelucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 514284900Sneel UT_string **err, bool must_exist) 515284900Sneel{ 516284900Sneel 517284900Sneel#ifdef HAVE_FETCH_H 518284900Sneel struct url *fetch_url; 519284900Sneel struct url_stat us; 520284900Sneel FILE *in; 521284900Sneel 522284900Sneel fetch_url = fetchParseURL (url); 523284900Sneel if (fetch_url == NULL) { 524284900Sneel ucl_create_err (err, "invalid URL %s: %s", 525 url, strerror (errno)); 526 return false; 527 } 528 if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 529 if (!must_exist) { 530 ucl_create_err (err, "cannot fetch URL %s: %s", 531 url, strerror (errno)); 532 } 533 fetchFreeURL (fetch_url); 534 return false; 535 } 536 537 *buflen = us.size; 538 *buf = malloc (*buflen); 539 if (*buf == NULL) { 540 ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 541 url, strerror (errno)); 542 fclose (in); 543 fetchFreeURL (fetch_url); 544 return false; 545 } 546 547 if (fread (*buf, *buflen, 1, in) != 1) { 548 ucl_create_err (err, "cannot read URL %s: %s", 549 url, strerror (errno)); 550 fclose (in); 551 fetchFreeURL (fetch_url); 552 return false; 553 } 554 555 fetchFreeURL (fetch_url); 556 return true; 557#elif defined(CURL_FOUND) 558 CURL *curl; 559 int r; 560 struct ucl_curl_cbdata cbdata; 561 562 curl = curl_easy_init (); 563 if (curl == NULL) { 564 ucl_create_err (err, "CURL interface is broken"); 565 return false; 566 } 567 if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 568 ucl_create_err (err, "invalid URL %s: %s", 569 url, curl_easy_strerror (r)); 570 curl_easy_cleanup (curl); 571 return false; 572 } 573 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 574 cbdata.buf = *buf; 575 cbdata.buflen = *buflen; 576 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 577 578 if ((r = curl_easy_perform (curl)) != CURLE_OK) { 579 if (!must_exist) { 580 ucl_create_err (err, "error fetching URL %s: %s", 581 url, curl_easy_strerror (r)); 582 } 583 curl_easy_cleanup (curl); 584 if (cbdata.buf) { 585 free (cbdata.buf); 586 } 587 return false; 588 } 589 *buf = cbdata.buf; 590 *buflen = cbdata.buflen; 591 592 return true; 593#else 594 ucl_create_err (err, "URL support is disabled"); 595 return false; 596#endif 597} 598 599/** 600 * Fetch a file and save results to the memory buffer 601 * @param filename filename to fetch 602 * @param len length of filename 603 * @param buf target buffer 604 * @param buflen target length 605 * @return 606 */ 607static bool 608ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 609 UT_string **err, bool must_exist) 610{ 611 int fd; 612 struct stat st; 613 614 if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 615 if (must_exist) { 616 ucl_create_err (err, "cannot stat file %s: %s", 617 filename, strerror (errno)); 618 } 619 return false; 620 } 621 if (st.st_size == 0) { 622 /* Do not map empty files */ 623 *buf = ""; 624 *buflen = 0; 625 } 626 else { 627 if ((fd = open (filename, O_RDONLY)) == -1) { 628 ucl_create_err (err, "cannot open file %s: %s", 629 filename, strerror (errno)); 630 return false; 631 } 632 if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 633 close (fd); 634 ucl_create_err (err, "cannot mmap file %s: %s", 635 filename, strerror (errno)); 636 return false; 637 } 638 *buflen = st.st_size; 639 close (fd); 640 } 641 642 return true; 643} 644 645 646#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 647static inline bool 648ucl_sig_check (const unsigned char *data, size_t datalen, 649 const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 650{ 651 struct ucl_pubkey *key; 652 char dig[EVP_MAX_MD_SIZE]; 653 unsigned int diglen; 654 EVP_PKEY_CTX *key_ctx; 655 EVP_MD_CTX *sign_ctx = NULL; 656 657 sign_ctx = EVP_MD_CTX_create (); 658 659 LL_FOREACH (parser->keys, key) { 660 key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 661 if (key_ctx != NULL) { 662 if (EVP_PKEY_verify_init (key_ctx) <= 0) { 663 EVP_PKEY_CTX_free (key_ctx); 664 continue; 665 } 666 if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 667 EVP_PKEY_CTX_free (key_ctx); 668 continue; 669 } 670 if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 671 EVP_PKEY_CTX_free (key_ctx); 672 continue; 673 } 674 EVP_DigestInit (sign_ctx, EVP_sha256 ()); 675 EVP_DigestUpdate (sign_ctx, data, datalen); 676 EVP_DigestFinal (sign_ctx, dig, &diglen); 677 678 if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 679 EVP_MD_CTX_destroy (sign_ctx); 680 EVP_PKEY_CTX_free (key_ctx); 681 return true; 682 } 683 684 EVP_PKEY_CTX_free (key_ctx); 685 } 686 } 687 688 EVP_MD_CTX_destroy (sign_ctx); 689 690 return false; 691} 692#endif 693 694/** 695 * Include an url to configuration 696 * @param data 697 * @param len 698 * @param parser 699 * @param err 700 * @return 701 */ 702static bool 703ucl_include_url (const unsigned char *data, size_t len, 704 struct ucl_parser *parser, bool check_signature, bool must_exist) 705{ 706 707 bool res; 708 unsigned char *buf = NULL; 709 size_t buflen = 0; 710 struct ucl_chunk *chunk; 711 char urlbuf[PATH_MAX]; 712 int prev_state; 713 714 snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 715 716 if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 717 return (!must_exist || false); 718 } 719 720 if (check_signature) { 721#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 722 unsigned char *sigbuf = NULL; 723 size_t siglen = 0; 724 /* We need to check signature first */ 725 snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 726 if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 727 return false; 728 } 729 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 730 ucl_create_err (&parser->err, "cannot verify url %s: %s", 731 urlbuf, 732 ERR_error_string (ERR_get_error (), NULL)); 733 if (siglen > 0) { 734 ucl_munmap (sigbuf, siglen); 735 } 736 return false; 737 } 738 if (siglen > 0) { 739 ucl_munmap (sigbuf, siglen); 740 } 741#endif 742 } 743 744 prev_state = parser->state; 745 parser->state = UCL_STATE_INIT; 746 747 res = ucl_parser_add_chunk (parser, buf, buflen); 748 if (res == true) { 749 /* Remove chunk from the stack */ 750 chunk = parser->chunks; 751 if (chunk != NULL) { 752 parser->chunks = chunk->next; 753 UCL_FREE (sizeof (struct ucl_chunk), chunk); 754 } 755 } 756 757 parser->state = prev_state; 758 free (buf); 759 760 return res; 761} 762 763/** 764 * Include a file to configuration 765 * @param data 766 * @param len 767 * @param parser 768 * @param err 769 * @return 770 */ 771static bool 772ucl_include_file (const unsigned char *data, size_t len, 773 struct ucl_parser *parser, bool check_signature, bool must_exist) 774{ 775 bool res; 776 struct ucl_chunk *chunk; 777 unsigned char *buf = NULL; 778 size_t buflen; 779 char filebuf[PATH_MAX], realbuf[PATH_MAX]; 780 int prev_state; 781 782 snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 783 if (ucl_realpath (filebuf, realbuf) == NULL) { 784 if (!must_exist) { 785 return true; 786 } 787 ucl_create_err (&parser->err, "cannot open file %s: %s", 788 filebuf, 789 strerror (errno)); 790 return false; 791 } 792 793 if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 794 return (!must_exist || false); 795 } 796 797 if (check_signature) { 798#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 799 unsigned char *sigbuf = NULL; 800 size_t siglen = 0; 801 /* We need to check signature first */ 802 snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 803 if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 804 return false; 805 } 806 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 807 ucl_create_err (&parser->err, "cannot verify file %s: %s", 808 filebuf, 809 ERR_error_string (ERR_get_error (), NULL)); 810 if (siglen > 0) { 811 ucl_munmap (sigbuf, siglen); 812 } 813 return false; 814 } 815 if (siglen > 0) { 816 ucl_munmap (sigbuf, siglen); 817 } 818#endif 819 } 820 821 ucl_parser_set_filevars (parser, realbuf, false); 822 823 prev_state = parser->state; 824 parser->state = UCL_STATE_INIT; 825 826 res = ucl_parser_add_chunk (parser, buf, buflen); 827 if (res == true) { 828 /* Remove chunk from the stack */ 829 chunk = parser->chunks; 830 if (chunk != NULL) { 831 parser->chunks = chunk->next; 832 UCL_FREE (sizeof (struct ucl_chunk), chunk); 833 } 834 } 835 836 parser->state = prev_state; 837 838 if (buflen > 0) { 839 ucl_munmap (buf, buflen); 840 } 841 842 return res; 843} 844 845/** 846 * Handle include macro 847 * @param data include data 848 * @param len length of data 849 * @param ud user data 850 * @param err error ptr 851 * @return 852 */ 853UCL_EXTERN bool 854ucl_include_handler (const unsigned char *data, size_t len, void* ud) 855{ 856 struct ucl_parser *parser = ud; 857 858 if (*data == '/' || *data == '.') { 859 /* Try to load a file */ 860 return ucl_include_file (data, len, parser, false, true); 861 } 862 863 return ucl_include_url (data, len, parser, false, true); 864} 865 866/** 867 * Handle includes macro 868 * @param data include data 869 * @param len length of data 870 * @param ud user data 871 * @param err error ptr 872 * @return 873 */ 874UCL_EXTERN bool 875ucl_includes_handler (const unsigned char *data, size_t len, void* ud) 876{ 877 struct ucl_parser *parser = ud; 878 879 if (*data == '/' || *data == '.') { 880 /* Try to load a file */ 881 return ucl_include_file (data, len, parser, true, true); 882 } 883 884 return ucl_include_url (data, len, parser, true, true); 885} 886 887 888UCL_EXTERN bool 889ucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 890{ 891 struct ucl_parser *parser = ud; 892 893 if (*data == '/' || *data == '.') { 894 /* Try to load a file */ 895 return ucl_include_file (data, len, parser, false, false); 896 } 897 898 return ucl_include_url (data, len, parser, false, false); 899} 900 901UCL_EXTERN bool 902ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 903{ 904 char realbuf[PATH_MAX], *curdir; 905 906 if (filename != NULL) { 907 if (need_expand) { 908 if (ucl_realpath (filename, realbuf) == NULL) { 909 return false; 910 } 911 } 912 else { 913 ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 914 } 915 916 /* Define variables */ 917 ucl_parser_register_variable (parser, "FILENAME", realbuf); 918 curdir = dirname (realbuf); 919 ucl_parser_register_variable (parser, "CURDIR", curdir); 920 } 921 else { 922 /* Set everything from the current dir */ 923 curdir = getcwd (realbuf, sizeof (realbuf)); 924 ucl_parser_register_variable (parser, "FILENAME", "undef"); 925 ucl_parser_register_variable (parser, "CURDIR", curdir); 926 } 927 928 return true; 929} 930 931UCL_EXTERN bool 932ucl_parser_add_file (struct ucl_parser *parser, const char *filename) 933{ 934 unsigned char *buf; 935 size_t len; 936 bool ret; 937 char realbuf[PATH_MAX]; 938 939 if (ucl_realpath (filename, realbuf) == NULL) { 940 ucl_create_err (&parser->err, "cannot open file %s: %s", 941 filename, 942 strerror (errno)); 943 return false; 944 } 945 946 if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 947 return false; 948 } 949 950 ucl_parser_set_filevars (parser, realbuf, false); 951 ret = ucl_parser_add_chunk (parser, buf, len); 952 953 if (len > 0) { 954 ucl_munmap (buf, len); 955 } 956 957 return ret; 958} 959 960size_t 961ucl_strlcpy (char *dst, const char *src, size_t siz) 962{ 963 char *d = dst; 964 const char *s = src; 965 size_t n = siz; 966 967 /* Copy as many bytes as will fit */ 968 if (n != 0) { 969 while (--n != 0) { 970 if ((*d++ = *s++) == '\0') { 971 break; 972 } 973 } 974 } 975 976 if (n == 0 && siz != 0) { 977 *d = '\0'; 978 } 979 980 return (s - src - 1); /* count does not include NUL */ 981} 982 983size_t 984ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 985{ 986 memcpy (dst, src, siz - 1); 987 dst[siz - 1] = '\0'; 988 989 return siz - 1; 990} 991 992size_t 993ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 994{ 995 char *d = dst; 996 const char *s = src; 997 size_t n = siz; 998 999 /* Copy as many bytes as will fit */ 1000 if (n != 0) { 1001 while (--n != 0) { 1002 if ((*d++ = tolower (*s++)) == '\0') { 1003 break; 1004 } 1005 } 1006 } 1007 1008 if (n == 0 && siz != 0) { 1009 *d = '\0'; 1010 } 1011 1012 return (s - src); /* count does not include NUL */ 1013} 1014 1015ucl_object_t * 1016ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1017{ 1018 ucl_object_t *obj; 1019 const char *start, *end, *p, *pos; 1020 char *dst, *d; 1021 size_t escaped_len; 1022 1023 if (str == NULL) { 1024 return NULL; 1025 } 1026 1027 obj = ucl_object_new (); 1028 if (obj) { 1029 if (len == 0) { 1030 len = strlen (str); 1031 } 1032 if (flags & UCL_STRING_TRIM) { 1033 /* Skip leading spaces */ 1034 for (start = str; (size_t)(start - str) < len; start ++) { 1035 if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1036 break; 1037 } 1038 } 1039 /* Skip trailing spaces */ 1040 for (end = str + len - 1; end > start; end --) { 1041 if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1042 break; 1043 } 1044 } 1045 end ++; 1046 } 1047 else { 1048 start = str; 1049 end = str + len; 1050 } 1051 1052 obj->type = UCL_STRING; 1053 if (flags & UCL_STRING_ESCAPE) { 1054 for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1055 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1056 escaped_len ++; 1057 } 1058 } 1059 dst = malloc (escaped_len + 1); 1060 if (dst != NULL) { 1061 for (p = start, d = dst; p < end; p ++, d ++) { 1062 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1063 switch (*p) { 1064 case '\n': 1065 *d++ = '\\'; 1066 *d = 'n'; 1067 break; 1068 case '\r': 1069 *d++ = '\\'; 1070 *d = 'r'; 1071 break; 1072 case '\b': 1073 *d++ = '\\'; 1074 *d = 'b'; 1075 break; 1076 case '\t': 1077 *d++ = '\\'; 1078 *d = 't'; 1079 break; 1080 case '\f': 1081 *d++ = '\\'; 1082 *d = 'f'; 1083 break; 1084 case '\\': 1085 *d++ = '\\'; 1086 *d = '\\'; 1087 break; 1088 case '"': 1089 *d++ = '\\'; 1090 *d = '"'; 1091 break; 1092 } 1093 } 1094 else { 1095 *d = *p; 1096 } 1097 } 1098 *d = '\0'; 1099 obj->value.sv = dst; 1100 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1101 obj->len = escaped_len; 1102 } 1103 } 1104 else { 1105 dst = malloc (end - start + 1); 1106 if (dst != NULL) { 1107 ucl_strlcpy_unsafe (dst, start, end - start + 1); 1108 obj->value.sv = dst; 1109 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1110 obj->len = end - start; 1111 } 1112 } 1113 if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1114 /* Parse what we have */ 1115 if (flags & UCL_STRING_PARSE_BOOLEAN) { 1116 if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1117 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1118 flags & UCL_STRING_PARSE_DOUBLE, 1119 flags & UCL_STRING_PARSE_BYTES, 1120 flags & UCL_STRING_PARSE_TIME); 1121 } 1122 } 1123 else { 1124 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1125 flags & UCL_STRING_PARSE_DOUBLE, 1126 flags & UCL_STRING_PARSE_BYTES, 1127 flags & UCL_STRING_PARSE_TIME); 1128 } 1129 } 1130 } 1131 1132 return obj; 1133} 1134 1135static bool 1136ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1137 const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1138{ 1139 ucl_object_t *found, *tmp; 1140 const ucl_object_t *cur; 1141 ucl_object_iter_t it = NULL; 1142 const char *p; 1143 int ret = true; 1144 1145 if (elt == NULL || key == NULL) { 1146 return false; 1147 } 1148 1149 if (top == NULL) { 1150 return false; 1151 } 1152 1153 if (top->type != UCL_OBJECT) { 1154 /* It is possible to convert NULL type to an object */ 1155 if (top->type == UCL_NULL) { 1156 top->type = UCL_OBJECT; 1157 } 1158 else { 1159 /* Refuse converting of other object types */ 1160 return false; 1161 } 1162 } 1163 1164 if (top->value.ov == NULL) { 1165 top->value.ov = ucl_hash_create (); 1166 } 1167 1168 if (keylen == 0) { 1169 keylen = strlen (key); 1170 } 1171 1172 for (p = key; p < key + keylen; p ++) { 1173 if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1174 elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1175 break; 1176 } 1177 } 1178 1179 elt->key = key; 1180 elt->keylen = keylen; 1181 1182 if (copy_key) { 1183 ucl_copy_key_trash (elt); 1184 } 1185 1186 found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 1187 1188 if (!found) { 1189 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1190 DL_APPEND (found, elt); 1191 top->len ++; 1192 if (replace) { 1193 ret = false; 1194 } 1195 } 1196 else { 1197 if (replace) { 1198 ucl_hash_delete (top->value.ov, found); 1199 ucl_object_unref (found); 1200 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1201 found = NULL; 1202 DL_APPEND (found, elt); 1203 } 1204 else if (merge) { 1205 if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1206 /* Insert old elt to new one */ 1207 ucl_object_insert_key_common (elt, found, found->key, 1208 found->keylen, copy_key, false, false); 1209 ucl_hash_delete (top->value.ov, found); 1210 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1211 } 1212 else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1213 /* Insert new to old */ 1214 ucl_object_insert_key_common (found, elt, elt->key, 1215 elt->keylen, copy_key, false, false); 1216 } 1217 else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1218 /* Mix two hashes */ 1219 while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1220 tmp = ucl_object_ref (cur); 1221 ucl_object_insert_key_common (found, tmp, cur->key, 1222 cur->keylen, copy_key, false, false); 1223 } 1224 ucl_object_unref (elt); 1225 } 1226 else { 1227 /* Just make a list of scalars */ 1228 DL_APPEND (found, elt); 1229 } 1230 } 1231 else { 1232 DL_APPEND (found, elt); 1233 } 1234 } 1235 1236 return ret; 1237} 1238 1239bool 1240ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 1241{ 1242 ucl_object_t *found; 1243 1244 if (top == NULL || key == NULL) { 1245 return false; 1246 } 1247 1248 found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); 1249 1250 if (found == NULL) { 1251 return false; 1252 } 1253 1254 ucl_hash_delete (top->value.ov, found); 1255 ucl_object_unref (found); 1256 top->len --; 1257 1258 return true; 1259} 1260 1261bool 1262ucl_object_delete_key (ucl_object_t *top, const char *key) 1263{ 1264 return ucl_object_delete_keyl (top, key, strlen(key)); 1265} 1266 1267ucl_object_t* 1268ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 1269{ 1270 const ucl_object_t *found; 1271 1272 if (top == NULL || key == NULL) { 1273 return false; 1274 } 1275 found = ucl_object_find_keyl (top, key, keylen); 1276 1277 if (found == NULL) { 1278 return NULL; 1279 } 1280 ucl_hash_delete (top->value.ov, found); 1281 top->len --; 1282 1283 return __DECONST (ucl_object_t *, found); 1284} 1285 1286ucl_object_t* 1287ucl_object_pop_key (ucl_object_t *top, const char *key) 1288{ 1289 return ucl_object_pop_keyl (top, key, strlen(key)); 1290} 1291 1292bool 1293ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1294 const char *key, size_t keylen, bool copy_key) 1295{ 1296 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1297} 1298 1299bool 1300ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1301 const char *key, size_t keylen, bool copy_key) 1302{ 1303 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1304} 1305 1306bool 1307ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1308 const char *key, size_t keylen, bool copy_key) 1309{ 1310 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1311} 1312 1313const ucl_object_t * 1314ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) 1315{ 1316 const ucl_object_t *ret; 1317 ucl_object_t srch; 1318 1319 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1320 return NULL; 1321 } 1322 1323 srch.key = key; 1324 srch.keylen = klen; 1325 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1326 1327 return ret; 1328} 1329 1330const ucl_object_t * 1331ucl_object_find_key (const ucl_object_t *obj, const char *key) 1332{ 1333 size_t klen; 1334 const ucl_object_t *ret; 1335 ucl_object_t srch; 1336 1337 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1338 return NULL; 1339 } 1340 1341 klen = strlen (key); 1342 srch.key = key; 1343 srch.keylen = klen; 1344 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1345 1346 return ret; 1347} 1348 1349const ucl_object_t* 1350ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1351{ 1352 const ucl_object_t *elt; 1353 1354 if (obj == NULL || iter == NULL) { 1355 return NULL; 1356 } 1357 1358 if (expand_values) { 1359 switch (obj->type) { 1360 case UCL_OBJECT: 1361 return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1362 break; 1363 case UCL_ARRAY: 1364 elt = *iter; 1365 if (elt == NULL) { 1366 elt = obj->value.av; 1367 if (elt == NULL) { 1368 return NULL; 1369 } 1370 } 1371 else if (elt == obj->value.av) { 1372 return NULL; 1373 } 1374 *iter = elt->next ? elt->next : obj->value.av; 1375 return elt; 1376 default: 1377 /* Go to linear iteration */ 1378 break; 1379 } 1380 } 1381 /* Treat everything as a linear list */ 1382 elt = *iter; 1383 if (elt == NULL) { 1384 elt = obj; 1385 if (elt == NULL) { 1386 return NULL; 1387 } 1388 } 1389 else if (elt == obj) { 1390 return NULL; 1391 } 1392 *iter = __DECONST (void *, elt->next ? elt->next : obj); 1393 return elt; 1394 1395 /* Not reached */ 1396 return NULL; 1397} 1398 1399 1400ucl_object_t * 1401ucl_object_new (void) 1402{ 1403 ucl_object_t *new; 1404 new = malloc (sizeof (ucl_object_t)); 1405 if (new != NULL) { 1406 memset (new, 0, sizeof (ucl_object_t)); 1407 new->ref = 1; 1408 new->type = UCL_NULL; 1409 } 1410 return new; 1411} 1412 1413ucl_object_t * 1414ucl_object_typed_new (unsigned int type) 1415{ 1416 ucl_object_t *new; 1417 new = malloc (sizeof (ucl_object_t)); 1418 if (new != NULL) { 1419 memset (new, 0, sizeof (ucl_object_t)); 1420 new->ref = 1; 1421 new->type = (type <= UCL_NULL ? type : UCL_NULL); 1422 } 1423 return new; 1424} 1425 1426ucl_object_t* 1427ucl_object_fromstring (const char *str) 1428{ 1429 return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 1430} 1431 1432ucl_object_t * 1433ucl_object_fromlstring (const char *str, size_t len) 1434{ 1435 return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 1436} 1437 1438ucl_object_t * 1439ucl_object_fromint (int64_t iv) 1440{ 1441 ucl_object_t *obj; 1442 1443 obj = ucl_object_new (); 1444 if (obj != NULL) { 1445 obj->type = UCL_INT; 1446 obj->value.iv = iv; 1447 } 1448 1449 return obj; 1450} 1451 1452ucl_object_t * 1453ucl_object_fromdouble (double dv) 1454{ 1455 ucl_object_t *obj; 1456 1457 obj = ucl_object_new (); 1458 if (obj != NULL) { 1459 obj->type = UCL_FLOAT; 1460 obj->value.dv = dv; 1461 } 1462 1463 return obj; 1464} 1465 1466ucl_object_t* 1467ucl_object_frombool (bool bv) 1468{ 1469 ucl_object_t *obj; 1470 1471 obj = ucl_object_new (); 1472 if (obj != NULL) { 1473 obj->type = UCL_BOOLEAN; 1474 obj->value.iv = bv; 1475 } 1476 1477 return obj; 1478} 1479 1480bool 1481ucl_array_append (ucl_object_t *top, ucl_object_t *elt) 1482{ 1483 ucl_object_t *head; 1484 1485 if (elt == NULL || top == NULL) { 1486 return false; 1487 } 1488 1489 head = top->value.av; 1490 if (head == NULL) { 1491 top->value.av = elt; 1492 elt->prev = elt; 1493 } 1494 else { 1495 elt->prev = head->prev; 1496 head->prev->next = elt; 1497 head->prev = elt; 1498 } 1499 elt->next = NULL; 1500 top->len ++; 1501 1502 return true; 1503} 1504 1505bool 1506ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 1507{ 1508 ucl_object_t *head; 1509 1510 if (elt == NULL || top == NULL) { 1511 return false; 1512 } 1513 1514 1515 head = top->value.av; 1516 if (head == NULL) { 1517 top->value.av = elt; 1518 elt->prev = elt; 1519 } 1520 else { 1521 elt->prev = head->prev; 1522 head->prev = elt; 1523 } 1524 elt->next = head; 1525 top->value.av = elt; 1526 top->len ++; 1527 1528 return true; 1529} 1530 1531ucl_object_t * 1532ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 1533{ 1534 ucl_object_t *head; 1535 1536 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1537 return NULL; 1538 } 1539 head = top->value.av; 1540 1541 if (elt->prev == elt) { 1542 top->value.av = NULL; 1543 } 1544 else if (elt == head) { 1545 elt->next->prev = elt->prev; 1546 top->value.av = elt->next; 1547 } 1548 else { 1549 elt->prev->next = elt->next; 1550 if (elt->next) { 1551 elt->next->prev = elt->prev; 1552 } 1553 else { 1554 head->prev = elt->prev; 1555 } 1556 } 1557 elt->next = NULL; 1558 elt->prev = elt; 1559 top->len --; 1560 1561 return elt; 1562} 1563 1564const ucl_object_t * 1565ucl_array_head (const ucl_object_t *top) 1566{ 1567 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1568 return NULL; 1569 } 1570 return top->value.av; 1571} 1572 1573const ucl_object_t * 1574ucl_array_tail (const ucl_object_t *top) 1575{ 1576 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1577 return NULL; 1578 } 1579 return top->value.av->prev; 1580} 1581 1582ucl_object_t * 1583ucl_array_pop_last (ucl_object_t *top) 1584{ 1585 return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top))); 1586} 1587 1588ucl_object_t * 1589ucl_array_pop_first (ucl_object_t *top) 1590{ 1591 return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top))); 1592} 1593 1594ucl_object_t * 1595ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 1596{ 1597 1598 if (head == NULL) { 1599 elt->next = NULL; 1600 elt->prev = elt; 1601 head = elt; 1602 } 1603 else { 1604 elt->prev = head->prev; 1605 head->prev->next = elt; 1606 head->prev = elt; 1607 elt->next = NULL; 1608 } 1609 1610 return head; 1611} 1612 1613bool 1614ucl_object_todouble_safe (const ucl_object_t *obj, double *target) 1615{ 1616 if (obj == NULL || target == NULL) { 1617 return false; 1618 } 1619 switch (obj->type) { 1620 case UCL_INT: 1621 *target = obj->value.iv; /* Probaly could cause overflow */ 1622 break; 1623 case UCL_FLOAT: 1624 case UCL_TIME: 1625 *target = obj->value.dv; 1626 break; 1627 default: 1628 return false; 1629 } 1630 1631 return true; 1632} 1633 1634double 1635ucl_object_todouble (const ucl_object_t *obj) 1636{ 1637 double result = 0.; 1638 1639 ucl_object_todouble_safe (obj, &result); 1640 return result; 1641} 1642 1643bool 1644ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 1645{ 1646 if (obj == NULL || target == NULL) { 1647 return false; 1648 } 1649 switch (obj->type) { 1650 case UCL_INT: 1651 *target = obj->value.iv; 1652 break; 1653 case UCL_FLOAT: 1654 case UCL_TIME: 1655 *target = obj->value.dv; /* Loosing of decimal points */ 1656 break; 1657 default: 1658 return false; 1659 } 1660 1661 return true; 1662} 1663 1664int64_t 1665ucl_object_toint (const ucl_object_t *obj) 1666{ 1667 int64_t result = 0; 1668 1669 ucl_object_toint_safe (obj, &result); 1670 return result; 1671} 1672 1673bool 1674ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 1675{ 1676 if (obj == NULL || target == NULL) { 1677 return false; 1678 } 1679 switch (obj->type) { 1680 case UCL_BOOLEAN: 1681 *target = (obj->value.iv == true); 1682 break; 1683 default: 1684 return false; 1685 } 1686 1687 return true; 1688} 1689 1690bool 1691ucl_object_toboolean (const ucl_object_t *obj) 1692{ 1693 bool result = false; 1694 1695 ucl_object_toboolean_safe (obj, &result); 1696 return result; 1697} 1698 1699bool 1700ucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 1701{ 1702 if (obj == NULL || target == NULL) { 1703 return false; 1704 } 1705 1706 switch (obj->type) { 1707 case UCL_STRING: 1708 *target = ucl_copy_value_trash (obj); 1709 break; 1710 default: 1711 return false; 1712 } 1713 1714 return true; 1715} 1716 1717const char * 1718ucl_object_tostring (const ucl_object_t *obj) 1719{ 1720 const char *result = NULL; 1721 1722 ucl_object_tostring_safe (obj, &result); 1723 return result; 1724} 1725 1726const char * 1727ucl_object_tostring_forced (const ucl_object_t *obj) 1728{ 1729 return ucl_copy_value_trash (obj); 1730} 1731 1732bool 1733ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 1734{ 1735 if (obj == NULL || target == NULL) { 1736 return false; 1737 } 1738 switch (obj->type) { 1739 case UCL_STRING: 1740 *target = obj->value.sv; 1741 if (tlen != NULL) { 1742 *tlen = obj->len; 1743 } 1744 break; 1745 default: 1746 return false; 1747 } 1748 1749 return true; 1750} 1751 1752const char * 1753ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 1754{ 1755 const char *result = NULL; 1756 1757 ucl_object_tolstring_safe (obj, &result, tlen); 1758 return result; 1759} 1760 1761const char * 1762ucl_object_key (const ucl_object_t *obj) 1763{ 1764 return ucl_copy_key_trash (obj); 1765} 1766 1767const char * 1768ucl_object_keyl (const ucl_object_t *obj, size_t *len) 1769{ 1770 if (len == NULL || obj == NULL) { 1771 return NULL; 1772 } 1773 *len = obj->keylen; 1774 return obj->key; 1775} 1776 1777ucl_object_t * 1778ucl_object_ref (const ucl_object_t *obj) 1779{ 1780 ucl_object_t *res = NULL; 1781 1782 if (obj != NULL) { 1783 res = __DECONST (ucl_object_t *, obj); 1784#ifdef HAVE_ATOMIC_BUILTINS 1785 (void)__sync_add_and_fetch (&res->ref, 1); 1786#else 1787 res->ref ++; 1788#endif 1789 } 1790 return res; 1791} 1792 1793void 1794ucl_object_unref (ucl_object_t *obj) 1795{ 1796 if (obj != NULL) { 1797#ifdef HAVE_ATOMIC_BUILTINS 1798 unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 1799 if (rc == 0) { 1800#else 1801 if (--obj->ref == 0) { 1802#endif 1803 ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 1804 } 1805 } 1806} 1807 1808int 1809ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 1810{ 1811 const ucl_object_t *it1, *it2; 1812 ucl_object_iter_t iter = NULL; 1813 int ret = 0; 1814 1815 if (o1->type != o2->type) { 1816 return (o1->type) - (o2->type); 1817 } 1818 1819 switch (o1->type) { 1820 case UCL_STRING: 1821 if (o1->len == o2->len) { 1822 ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 1823 } 1824 else { 1825 ret = o1->len - o2->len; 1826 } 1827 break; 1828 case UCL_FLOAT: 1829 case UCL_INT: 1830 case UCL_TIME: 1831 ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 1832 break; 1833 case UCL_BOOLEAN: 1834 ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 1835 break; 1836 case UCL_ARRAY: 1837 if (o1->len == o2->len) { 1838 it1 = o1->value.av; 1839 it2 = o2->value.av; 1840 /* Compare all elements in both arrays */ 1841 while (it1 != NULL && it2 != NULL) { 1842 ret = ucl_object_compare (it1, it2); 1843 if (ret != 0) { 1844 break; 1845 } 1846 it1 = it1->next; 1847 it2 = it2->next; 1848 } 1849 } 1850 else { 1851 ret = o1->len - o2->len; 1852 } 1853 break; 1854 case UCL_OBJECT: 1855 if (o1->len == o2->len) { 1856 while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 1857 it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 1858 if (it2 == NULL) { 1859 ret = 1; 1860 break; 1861 } 1862 ret = ucl_object_compare (it1, it2); 1863 if (ret != 0) { 1864 break; 1865 } 1866 } 1867 } 1868 else { 1869 ret = o1->len - o2->len; 1870 } 1871 break; 1872 default: 1873 ret = 0; 1874 break; 1875 } 1876 1877 return ret; 1878} 1879 1880void 1881ucl_object_array_sort (ucl_object_t *ar, 1882 int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2)) 1883{ 1884 if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 1885 return; 1886 } 1887 1888 DL_SORT (ar->value.av, cmp); 1889} 1890