ucl_util.c revision 263648
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 28263648Sbapt#ifdef HAVE_LIBGEN_H 29262395Sbapt#include <libgen.h> /* For dirname */ 30263648Sbapt#endif 31262395Sbapt 32262395Sbapt#ifdef HAVE_OPENSSL 33262395Sbapt#include <openssl/err.h> 34262395Sbapt#include <openssl/sha.h> 35262395Sbapt#include <openssl/rsa.h> 36262395Sbapt#include <openssl/ssl.h> 37262395Sbapt#include <openssl/evp.h> 38262395Sbapt#endif 39262395Sbapt 40263648Sbapt#ifdef CURL_FOUND 41263648Sbapt#include <curl/curl.h> 42263648Sbapt#endif 43263648Sbapt#ifdef HAVE_FETCH_H 44263648Sbapt#include <fetch.h> 45263648Sbapt#endif 46263648Sbapt 47262975Sbapt#ifdef _WIN32 48262975Sbapt#include <windows.h> 49262975Sbapt 50263648Sbapt#ifndef PROT_READ 51262975Sbapt#define PROT_READ 1 52263648Sbapt#endif 53263648Sbapt#ifndef PROT_WRITE 54262975Sbapt#define PROT_WRITE 2 55263648Sbapt#endif 56263648Sbapt#ifndef PROT_READWRITE 57262975Sbapt#define PROT_READWRITE 3 58263648Sbapt#endif 59263648Sbapt#ifndef MAP_SHARED 60262975Sbapt#define MAP_SHARED 1 61263648Sbapt#endif 62263648Sbapt#ifndef MAP_PRIVATE 63262975Sbapt#define MAP_PRIVATE 2 64263648Sbapt#endif 65263648Sbapt#ifndef MAP_FAILED 66262975Sbapt#define MAP_FAILED ((void *) -1) 67263648Sbapt#endif 68262975Sbapt 69263648Sbaptstatic void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 70262975Sbapt{ 71262975Sbapt void *map = NULL; 72262975Sbapt HANDLE handle = INVALID_HANDLE_VALUE; 73262975Sbapt 74262975Sbapt switch (prot) { 75262975Sbapt default: 76262975Sbapt case PROT_READ: 77262975Sbapt { 78262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 79262975Sbapt if (!handle) break; 80262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 81262975Sbapt CloseHandle(handle); 82262975Sbapt break; 83262975Sbapt } 84262975Sbapt case PROT_WRITE: 85262975Sbapt { 86262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 87262975Sbapt if (!handle) break; 88262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 89262975Sbapt CloseHandle(handle); 90262975Sbapt break; 91262975Sbapt } 92262975Sbapt case PROT_READWRITE: 93262975Sbapt { 94262975Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 95262975Sbapt if (!handle) break; 96262975Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 97262975Sbapt CloseHandle(handle); 98262975Sbapt break; 99262975Sbapt } 100262975Sbapt } 101262975Sbapt if (map == (void *) NULL) { 102262975Sbapt return (void *) MAP_FAILED; 103262975Sbapt } 104262975Sbapt return (void *) ((char *) map + offset); 105262975Sbapt} 106262975Sbapt 107263648Sbaptstatic int ucl_munmap(void *map,size_t length) 108262975Sbapt{ 109262975Sbapt if (!UnmapViewOfFile(map)) { 110262975Sbapt return(-1); 111262975Sbapt } 112262975Sbapt return(0); 113262975Sbapt} 114262975Sbapt 115263648Sbaptstatic char* ucl_realpath(const char *path, char *resolved_path) { 116262975Sbapt char *p; 117262975Sbapt char tmp[MAX_PATH + 1]; 118262975Sbapt strncpy(tmp, path, sizeof(tmp)-1); 119262975Sbapt p = tmp; 120262975Sbapt while(*p) { 121262975Sbapt if (*p == '/') *p = '\\'; 122262975Sbapt p++; 123262975Sbapt } 124262975Sbapt return _fullpath(resolved_path, tmp, MAX_PATH); 125262975Sbapt} 126263648Sbapt#else 127263648Sbapt#define ucl_mmap mmap 128263648Sbapt#define ucl_munmap munmap 129263648Sbapt#define ucl_realpath realpath 130262975Sbapt#endif 131262975Sbapt 132262395Sbapt/** 133262395Sbapt * @file rcl_util.c 134262395Sbapt * Utilities for rcl parsing 135262395Sbapt */ 136262395Sbapt 137262395Sbapt 138262395Sbaptstatic void 139262395Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec) 140262395Sbapt{ 141262395Sbapt ucl_object_t *sub, *tmp; 142262395Sbapt 143262395Sbapt while (obj != NULL) { 144262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 145262395Sbapt UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 146262395Sbapt } 147262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 148262395Sbapt UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 149262395Sbapt } 150262395Sbapt 151262395Sbapt if (obj->type == UCL_ARRAY) { 152262395Sbapt sub = obj->value.av; 153262395Sbapt while (sub != NULL) { 154262395Sbapt tmp = sub->next; 155262395Sbapt ucl_object_free_internal (sub, false); 156262395Sbapt sub = tmp; 157262395Sbapt } 158262395Sbapt } 159262395Sbapt else if (obj->type == UCL_OBJECT) { 160262395Sbapt if (obj->value.ov != NULL) { 161262395Sbapt ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref); 162262395Sbapt } 163262395Sbapt } 164262395Sbapt tmp = obj->next; 165262395Sbapt UCL_FREE (sizeof (ucl_object_t), obj); 166262395Sbapt obj = tmp; 167262395Sbapt 168262395Sbapt if (!allow_rec) { 169262395Sbapt break; 170262395Sbapt } 171262395Sbapt } 172262395Sbapt} 173262395Sbapt 174262395Sbaptvoid 175262395Sbaptucl_object_free (ucl_object_t *obj) 176262395Sbapt{ 177262395Sbapt ucl_object_free_internal (obj, true); 178262395Sbapt} 179262395Sbapt 180262395Sbaptsize_t 181262395Sbaptucl_unescape_json_string (char *str, size_t len) 182262395Sbapt{ 183262395Sbapt char *t = str, *h = str; 184262395Sbapt int i, uval; 185262395Sbapt 186263648Sbapt if (len <= 1) { 187263648Sbapt return len; 188263648Sbapt } 189262395Sbapt /* t is target (tortoise), h is source (hare) */ 190262395Sbapt 191262395Sbapt while (len) { 192262395Sbapt if (*h == '\\') { 193262395Sbapt h ++; 194262395Sbapt switch (*h) { 195262395Sbapt case 'n': 196262395Sbapt *t++ = '\n'; 197262395Sbapt break; 198262395Sbapt case 'r': 199262395Sbapt *t++ = '\r'; 200262395Sbapt break; 201262395Sbapt case 'b': 202262395Sbapt *t++ = '\b'; 203262395Sbapt break; 204262395Sbapt case 't': 205262395Sbapt *t++ = '\t'; 206262395Sbapt break; 207262395Sbapt case 'f': 208262395Sbapt *t++ = '\f'; 209262395Sbapt break; 210262395Sbapt case '\\': 211262395Sbapt *t++ = '\\'; 212262395Sbapt break; 213262395Sbapt case '"': 214262395Sbapt *t++ = '"'; 215262395Sbapt break; 216262395Sbapt case 'u': 217262395Sbapt /* Unicode escape */ 218262395Sbapt uval = 0; 219263648Sbapt if (len > 3) { 220263648Sbapt for (i = 0; i < 4; i++) { 221263648Sbapt uval <<= 4; 222263648Sbapt if (isdigit (h[i])) { 223263648Sbapt uval += h[i] - '0'; 224263648Sbapt } 225263648Sbapt else if (h[i] >= 'a' && h[i] <= 'f') { 226263648Sbapt uval += h[i] - 'a' + 10; 227263648Sbapt } 228263648Sbapt else if (h[i] >= 'A' && h[i] <= 'F') { 229263648Sbapt uval += h[i] - 'A' + 10; 230263648Sbapt } 231263648Sbapt else { 232263648Sbapt break; 233263648Sbapt } 234262395Sbapt } 235263648Sbapt h += 3; 236263648Sbapt len -= 3; 237263648Sbapt /* Encode */ 238263648Sbapt if(uval < 0x80) { 239263648Sbapt t[0] = (char)uval; 240263648Sbapt t ++; 241262395Sbapt } 242263648Sbapt else if(uval < 0x800) { 243263648Sbapt t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 244263648Sbapt t[1] = 0x80 + ((uval & 0x03F)); 245263648Sbapt t += 2; 246262395Sbapt } 247263648Sbapt else if(uval < 0x10000) { 248263648Sbapt t[0] = 0xE0 + ((uval & 0xF000) >> 12); 249263648Sbapt t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 250263648Sbapt t[2] = 0x80 + ((uval & 0x003F)); 251263648Sbapt t += 3; 252263648Sbapt } 253263648Sbapt else if(uval <= 0x10FFFF) { 254263648Sbapt t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 255263648Sbapt t[1] = 0x80 + ((uval & 0x03F000) >> 12); 256263648Sbapt t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 257263648Sbapt t[3] = 0x80 + ((uval & 0x00003F)); 258263648Sbapt t += 4; 259263648Sbapt } 260263648Sbapt else { 261263648Sbapt *t++ = '?'; 262263648Sbapt } 263262395Sbapt } 264262395Sbapt else { 265263648Sbapt *t++ = 'u'; 266262395Sbapt } 267262395Sbapt break; 268262395Sbapt default: 269262395Sbapt *t++ = *h; 270262395Sbapt break; 271262395Sbapt } 272262395Sbapt h ++; 273262395Sbapt len --; 274262395Sbapt } 275262395Sbapt else { 276262395Sbapt *t++ = *h++; 277262395Sbapt } 278262395Sbapt len --; 279262395Sbapt } 280262395Sbapt *t = '\0'; 281262395Sbapt 282262395Sbapt return (t - str); 283262395Sbapt} 284262395Sbapt 285262975SbaptUCL_EXTERN char * 286262395Sbaptucl_copy_key_trash (ucl_object_t *obj) 287262395Sbapt{ 288263648Sbapt if (obj == NULL) { 289263648Sbapt return NULL; 290263648Sbapt } 291262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 292262395Sbapt obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 293262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 294262395Sbapt memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 295262395Sbapt obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 296262395Sbapt } 297262395Sbapt obj->key = obj->trash_stack[UCL_TRASH_KEY]; 298262395Sbapt obj->flags |= UCL_OBJECT_ALLOCATED_KEY; 299262395Sbapt } 300262395Sbapt 301262395Sbapt return obj->trash_stack[UCL_TRASH_KEY]; 302262395Sbapt} 303262395Sbapt 304262975SbaptUCL_EXTERN char * 305262395Sbaptucl_copy_value_trash (ucl_object_t *obj) 306262395Sbapt{ 307263648Sbapt if (obj == NULL) { 308263648Sbapt return NULL; 309263648Sbapt } 310262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 311262395Sbapt if (obj->type == UCL_STRING) { 312262395Sbapt /* Special case for strings */ 313262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 314262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 315262395Sbapt memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 316262395Sbapt obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 317262395Sbapt obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 318262395Sbapt } 319262395Sbapt } 320262395Sbapt else { 321262395Sbapt /* Just emit value in json notation */ 322262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 323262395Sbapt obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 324262395Sbapt } 325262395Sbapt obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; 326262395Sbapt } 327262395Sbapt return obj->trash_stack[UCL_TRASH_VALUE]; 328262395Sbapt} 329262395Sbapt 330262975SbaptUCL_EXTERN ucl_object_t* 331262395Sbaptucl_parser_get_object (struct ucl_parser *parser) 332262395Sbapt{ 333262395Sbapt if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 334262395Sbapt return ucl_object_ref (parser->top_obj); 335262395Sbapt } 336262395Sbapt 337262395Sbapt return NULL; 338262395Sbapt} 339262395Sbapt 340262975SbaptUCL_EXTERN void 341262395Sbaptucl_parser_free (struct ucl_parser *parser) 342262395Sbapt{ 343262395Sbapt struct ucl_stack *stack, *stmp; 344262395Sbapt struct ucl_macro *macro, *mtmp; 345262395Sbapt struct ucl_chunk *chunk, *ctmp; 346262395Sbapt struct ucl_pubkey *key, *ktmp; 347262395Sbapt struct ucl_variable *var, *vtmp; 348262395Sbapt 349263648Sbapt if (parser == NULL) { 350263648Sbapt return; 351263648Sbapt } 352263648Sbapt 353262395Sbapt if (parser->top_obj != NULL) { 354262395Sbapt ucl_object_unref (parser->top_obj); 355262395Sbapt } 356262395Sbapt 357262395Sbapt LL_FOREACH_SAFE (parser->stack, stack, stmp) { 358262395Sbapt free (stack); 359262395Sbapt } 360262395Sbapt HASH_ITER (hh, parser->macroes, macro, mtmp) { 361262395Sbapt free (macro->name); 362262395Sbapt HASH_DEL (parser->macroes, macro); 363262395Sbapt UCL_FREE (sizeof (struct ucl_macro), macro); 364262395Sbapt } 365262395Sbapt LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 366262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 367262395Sbapt } 368262395Sbapt LL_FOREACH_SAFE (parser->keys, key, ktmp) { 369262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), key); 370262395Sbapt } 371262395Sbapt LL_FOREACH_SAFE (parser->variables, var, vtmp) { 372262395Sbapt free (var->value); 373262395Sbapt free (var->var); 374262395Sbapt UCL_FREE (sizeof (struct ucl_variable), var); 375262395Sbapt } 376262395Sbapt 377262395Sbapt if (parser->err != NULL) { 378262395Sbapt utstring_free(parser->err); 379262395Sbapt } 380262395Sbapt 381262395Sbapt UCL_FREE (sizeof (struct ucl_parser), parser); 382262395Sbapt} 383262395Sbapt 384262975SbaptUCL_EXTERN const char * 385262395Sbaptucl_parser_get_error(struct ucl_parser *parser) 386262395Sbapt{ 387263648Sbapt if (parser == NULL) { 388263648Sbapt return NULL; 389263648Sbapt } 390263648Sbapt 391262395Sbapt if (parser->err == NULL) 392262395Sbapt return NULL; 393262395Sbapt 394262395Sbapt return utstring_body(parser->err); 395262395Sbapt} 396262395Sbapt 397262975SbaptUCL_EXTERN bool 398262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 399262395Sbapt{ 400262395Sbapt#ifndef HAVE_OPENSSL 401262395Sbapt ucl_create_err (&parser->err, "cannot check signatures without openssl"); 402262395Sbapt return false; 403262395Sbapt#else 404262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 405262395Sbapt ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 406262395Sbapt return EXIT_FAILURE; 407262395Sbapt# else 408262395Sbapt struct ucl_pubkey *nkey; 409262395Sbapt BIO *mem; 410262395Sbapt 411262395Sbapt mem = BIO_new_mem_buf ((void *)key, len); 412262395Sbapt nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 413263648Sbapt if (nkey == NULL) { 414263648Sbapt ucl_create_err (&parser->err, "cannot allocate memory for key"); 415263648Sbapt return false; 416263648Sbapt } 417262395Sbapt nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 418262395Sbapt BIO_free (mem); 419262395Sbapt if (nkey->key == NULL) { 420262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), nkey); 421262395Sbapt ucl_create_err (&parser->err, "%s", 422262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 423262395Sbapt return false; 424262395Sbapt } 425262395Sbapt LL_PREPEND (parser->keys, nkey); 426262395Sbapt# endif 427262395Sbapt#endif 428262395Sbapt return true; 429262395Sbapt} 430262395Sbapt 431262395Sbapt#ifdef CURL_FOUND 432262395Sbaptstruct ucl_curl_cbdata { 433262395Sbapt unsigned char *buf; 434262395Sbapt size_t buflen; 435262395Sbapt}; 436262395Sbapt 437262395Sbaptstatic size_t 438262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 439262395Sbapt{ 440262395Sbapt struct ucl_curl_cbdata *cbdata = ud; 441262395Sbapt size_t realsize = size * nmemb; 442262395Sbapt 443262395Sbapt cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 444262395Sbapt if (cbdata->buf == NULL) { 445262395Sbapt return 0; 446262395Sbapt } 447262395Sbapt 448262395Sbapt memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 449262395Sbapt cbdata->buflen += realsize; 450262395Sbapt cbdata->buf[cbdata->buflen] = 0; 451262395Sbapt 452262395Sbapt return realsize; 453262395Sbapt} 454262395Sbapt#endif 455262395Sbapt 456262395Sbapt/** 457262395Sbapt * Fetch a url and save results to the memory buffer 458262395Sbapt * @param url url to fetch 459262395Sbapt * @param len length of url 460262395Sbapt * @param buf target buffer 461262395Sbapt * @param buflen target length 462262395Sbapt * @return 463262395Sbapt */ 464262395Sbaptstatic bool 465262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 466262395Sbapt UT_string **err, bool must_exist) 467262395Sbapt{ 468262395Sbapt 469262395Sbapt#ifdef HAVE_FETCH_H 470262395Sbapt struct url *fetch_url; 471262395Sbapt struct url_stat us; 472262395Sbapt FILE *in; 473262395Sbapt 474262395Sbapt fetch_url = fetchParseURL (url); 475262395Sbapt if (fetch_url == NULL) { 476262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 477262395Sbapt url, strerror (errno)); 478262395Sbapt return false; 479262395Sbapt } 480262395Sbapt if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 481262395Sbapt if (!must_exist) { 482262395Sbapt ucl_create_err (err, "cannot fetch URL %s: %s", 483262395Sbapt url, strerror (errno)); 484262395Sbapt } 485262395Sbapt fetchFreeURL (fetch_url); 486262395Sbapt return false; 487262395Sbapt } 488262395Sbapt 489262395Sbapt *buflen = us.size; 490262395Sbapt *buf = malloc (*buflen); 491262395Sbapt if (*buf == NULL) { 492262395Sbapt ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 493262395Sbapt url, strerror (errno)); 494262395Sbapt fclose (in); 495262395Sbapt fetchFreeURL (fetch_url); 496262395Sbapt return false; 497262395Sbapt } 498262395Sbapt 499262395Sbapt if (fread (*buf, *buflen, 1, in) != 1) { 500262395Sbapt ucl_create_err (err, "cannot read URL %s: %s", 501262395Sbapt url, strerror (errno)); 502262395Sbapt fclose (in); 503262395Sbapt fetchFreeURL (fetch_url); 504262395Sbapt return false; 505262395Sbapt } 506262395Sbapt 507262395Sbapt fetchFreeURL (fetch_url); 508262395Sbapt return true; 509262395Sbapt#elif defined(CURL_FOUND) 510262395Sbapt CURL *curl; 511262395Sbapt int r; 512262395Sbapt struct ucl_curl_cbdata cbdata; 513262395Sbapt 514262395Sbapt curl = curl_easy_init (); 515262395Sbapt if (curl == NULL) { 516262395Sbapt ucl_create_err (err, "CURL interface is broken"); 517262395Sbapt return false; 518262395Sbapt } 519262395Sbapt if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 520262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 521262395Sbapt url, curl_easy_strerror (r)); 522262395Sbapt curl_easy_cleanup (curl); 523262395Sbapt return false; 524262395Sbapt } 525262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 526262395Sbapt cbdata.buf = *buf; 527262395Sbapt cbdata.buflen = *buflen; 528262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 529262395Sbapt 530262395Sbapt if ((r = curl_easy_perform (curl)) != CURLE_OK) { 531262395Sbapt if (!must_exist) { 532262395Sbapt ucl_create_err (err, "error fetching URL %s: %s", 533262395Sbapt url, curl_easy_strerror (r)); 534262395Sbapt } 535262395Sbapt curl_easy_cleanup (curl); 536262395Sbapt if (cbdata.buf) { 537262395Sbapt free (cbdata.buf); 538262395Sbapt } 539262395Sbapt return false; 540262395Sbapt } 541262395Sbapt *buf = cbdata.buf; 542262395Sbapt *buflen = cbdata.buflen; 543262395Sbapt 544262395Sbapt return true; 545262395Sbapt#else 546262395Sbapt ucl_create_err (err, "URL support is disabled"); 547262395Sbapt return false; 548262395Sbapt#endif 549262395Sbapt} 550262395Sbapt 551262395Sbapt/** 552262395Sbapt * Fetch a file and save results to the memory buffer 553262395Sbapt * @param filename filename to fetch 554262395Sbapt * @param len length of filename 555262395Sbapt * @param buf target buffer 556262395Sbapt * @param buflen target length 557262395Sbapt * @return 558262395Sbapt */ 559262395Sbaptstatic bool 560262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 561262395Sbapt UT_string **err, bool must_exist) 562262395Sbapt{ 563262395Sbapt int fd; 564262395Sbapt struct stat st; 565262395Sbapt 566262395Sbapt if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 567262395Sbapt if (must_exist) { 568262395Sbapt ucl_create_err (err, "cannot stat file %s: %s", 569262395Sbapt filename, strerror (errno)); 570262395Sbapt } 571262395Sbapt return false; 572262395Sbapt } 573262395Sbapt if (st.st_size == 0) { 574262395Sbapt /* Do not map empty files */ 575262395Sbapt *buf = ""; 576262395Sbapt *buflen = 0; 577262395Sbapt } 578262395Sbapt else { 579262395Sbapt if ((fd = open (filename, O_RDONLY)) == -1) { 580262395Sbapt ucl_create_err (err, "cannot open file %s: %s", 581262395Sbapt filename, strerror (errno)); 582262395Sbapt return false; 583262395Sbapt } 584263648Sbapt if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 585262395Sbapt close (fd); 586262395Sbapt ucl_create_err (err, "cannot mmap file %s: %s", 587262395Sbapt filename, strerror (errno)); 588262395Sbapt return false; 589262395Sbapt } 590262395Sbapt *buflen = st.st_size; 591262395Sbapt close (fd); 592262395Sbapt } 593262395Sbapt 594262395Sbapt return true; 595262395Sbapt} 596262395Sbapt 597262395Sbapt 598262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 599262395Sbaptstatic inline bool 600262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen, 601262395Sbapt const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 602262395Sbapt{ 603262395Sbapt struct ucl_pubkey *key; 604262395Sbapt char dig[EVP_MAX_MD_SIZE]; 605262395Sbapt unsigned int diglen; 606262395Sbapt EVP_PKEY_CTX *key_ctx; 607262395Sbapt EVP_MD_CTX *sign_ctx = NULL; 608262395Sbapt 609262395Sbapt sign_ctx = EVP_MD_CTX_create (); 610262395Sbapt 611262395Sbapt LL_FOREACH (parser->keys, key) { 612262395Sbapt key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 613262395Sbapt if (key_ctx != NULL) { 614262395Sbapt if (EVP_PKEY_verify_init (key_ctx) <= 0) { 615262395Sbapt EVP_PKEY_CTX_free (key_ctx); 616262395Sbapt continue; 617262395Sbapt } 618262395Sbapt if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 619262395Sbapt EVP_PKEY_CTX_free (key_ctx); 620262395Sbapt continue; 621262395Sbapt } 622262395Sbapt if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 623262395Sbapt EVP_PKEY_CTX_free (key_ctx); 624262395Sbapt continue; 625262395Sbapt } 626262395Sbapt EVP_DigestInit (sign_ctx, EVP_sha256 ()); 627262395Sbapt EVP_DigestUpdate (sign_ctx, data, datalen); 628262395Sbapt EVP_DigestFinal (sign_ctx, dig, &diglen); 629262395Sbapt 630262395Sbapt if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 631262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 632262395Sbapt EVP_PKEY_CTX_free (key_ctx); 633262395Sbapt return true; 634262395Sbapt } 635262395Sbapt 636262395Sbapt EVP_PKEY_CTX_free (key_ctx); 637262395Sbapt } 638262395Sbapt } 639262395Sbapt 640262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 641262395Sbapt 642262395Sbapt return false; 643262395Sbapt} 644262395Sbapt#endif 645262395Sbapt 646262395Sbapt/** 647262395Sbapt * Include an url to configuration 648262395Sbapt * @param data 649262395Sbapt * @param len 650262395Sbapt * @param parser 651262395Sbapt * @param err 652262395Sbapt * @return 653262395Sbapt */ 654262395Sbaptstatic bool 655262395Sbaptucl_include_url (const unsigned char *data, size_t len, 656262395Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist) 657262395Sbapt{ 658262395Sbapt 659262395Sbapt bool res; 660262395Sbapt unsigned char *buf = NULL; 661262395Sbapt size_t buflen = 0; 662262395Sbapt struct ucl_chunk *chunk; 663262395Sbapt char urlbuf[PATH_MAX]; 664262395Sbapt int prev_state; 665262395Sbapt 666262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 667262395Sbapt 668262395Sbapt if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 669262395Sbapt return (!must_exist || false); 670262395Sbapt } 671262395Sbapt 672262395Sbapt if (check_signature) { 673262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 674262395Sbapt unsigned char *sigbuf = NULL; 675262395Sbapt size_t siglen = 0; 676262395Sbapt /* We need to check signature first */ 677262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 678262395Sbapt if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 679262395Sbapt return false; 680262395Sbapt } 681262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 682262395Sbapt ucl_create_err (&parser->err, "cannot verify url %s: %s", 683262395Sbapt urlbuf, 684262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 685262395Sbapt if (siglen > 0) { 686263648Sbapt ucl_munmap (sigbuf, siglen); 687262395Sbapt } 688262395Sbapt return false; 689262395Sbapt } 690262395Sbapt if (siglen > 0) { 691263648Sbapt ucl_munmap (sigbuf, siglen); 692262395Sbapt } 693262395Sbapt#endif 694262395Sbapt } 695262395Sbapt 696262395Sbapt prev_state = parser->state; 697262395Sbapt parser->state = UCL_STATE_INIT; 698262395Sbapt 699262395Sbapt res = ucl_parser_add_chunk (parser, buf, buflen); 700262395Sbapt if (res == true) { 701262395Sbapt /* Remove chunk from the stack */ 702262395Sbapt chunk = parser->chunks; 703262395Sbapt if (chunk != NULL) { 704262395Sbapt parser->chunks = chunk->next; 705262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 706262395Sbapt } 707262395Sbapt } 708262395Sbapt 709262395Sbapt parser->state = prev_state; 710262395Sbapt free (buf); 711262395Sbapt 712262395Sbapt return res; 713262395Sbapt} 714262395Sbapt 715262395Sbapt/** 716262395Sbapt * Include a file to configuration 717262395Sbapt * @param data 718262395Sbapt * @param len 719262395Sbapt * @param parser 720262395Sbapt * @param err 721262395Sbapt * @return 722262395Sbapt */ 723262395Sbaptstatic bool 724262395Sbaptucl_include_file (const unsigned char *data, size_t len, 725262395Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist) 726262395Sbapt{ 727262395Sbapt bool res; 728262395Sbapt struct ucl_chunk *chunk; 729262395Sbapt unsigned char *buf = NULL; 730262395Sbapt size_t buflen; 731262395Sbapt char filebuf[PATH_MAX], realbuf[PATH_MAX]; 732262395Sbapt int prev_state; 733262395Sbapt 734262395Sbapt snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 735263648Sbapt if (ucl_realpath (filebuf, realbuf) == NULL) { 736262395Sbapt if (!must_exist) { 737262395Sbapt return true; 738262395Sbapt } 739262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 740262395Sbapt filebuf, 741262395Sbapt strerror (errno)); 742262395Sbapt return false; 743262395Sbapt } 744262395Sbapt 745262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 746262395Sbapt return (!must_exist || false); 747262395Sbapt } 748262395Sbapt 749262395Sbapt if (check_signature) { 750262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 751262395Sbapt unsigned char *sigbuf = NULL; 752262395Sbapt size_t siglen = 0; 753262395Sbapt /* We need to check signature first */ 754262395Sbapt snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 755262395Sbapt if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 756262395Sbapt return false; 757262395Sbapt } 758262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 759262395Sbapt ucl_create_err (&parser->err, "cannot verify file %s: %s", 760262395Sbapt filebuf, 761262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 762262395Sbapt if (siglen > 0) { 763263648Sbapt ucl_munmap (sigbuf, siglen); 764262395Sbapt } 765262395Sbapt return false; 766262395Sbapt } 767262395Sbapt if (siglen > 0) { 768263648Sbapt ucl_munmap (sigbuf, siglen); 769262395Sbapt } 770262395Sbapt#endif 771262395Sbapt } 772262395Sbapt 773262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 774262395Sbapt 775262395Sbapt prev_state = parser->state; 776262395Sbapt parser->state = UCL_STATE_INIT; 777262395Sbapt 778262395Sbapt res = ucl_parser_add_chunk (parser, buf, buflen); 779262395Sbapt if (res == true) { 780262395Sbapt /* Remove chunk from the stack */ 781262395Sbapt chunk = parser->chunks; 782262395Sbapt if (chunk != NULL) { 783262395Sbapt parser->chunks = chunk->next; 784262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 785262395Sbapt } 786262395Sbapt } 787262395Sbapt 788262395Sbapt parser->state = prev_state; 789262395Sbapt 790262395Sbapt if (buflen > 0) { 791263648Sbapt ucl_munmap (buf, buflen); 792262395Sbapt } 793262395Sbapt 794262395Sbapt return res; 795262395Sbapt} 796262395Sbapt 797262395Sbapt/** 798262395Sbapt * Handle include macro 799262395Sbapt * @param data include data 800262395Sbapt * @param len length of data 801262395Sbapt * @param ud user data 802262395Sbapt * @param err error ptr 803262395Sbapt * @return 804262395Sbapt */ 805262975SbaptUCL_EXTERN bool 806262395Sbaptucl_include_handler (const unsigned char *data, size_t len, void* ud) 807262395Sbapt{ 808262395Sbapt struct ucl_parser *parser = ud; 809262395Sbapt 810262395Sbapt if (*data == '/' || *data == '.') { 811262395Sbapt /* Try to load a file */ 812262395Sbapt return ucl_include_file (data, len, parser, false, true); 813262395Sbapt } 814262395Sbapt 815262395Sbapt return ucl_include_url (data, len, parser, false, true); 816262395Sbapt} 817262395Sbapt 818262395Sbapt/** 819262395Sbapt * Handle includes macro 820262395Sbapt * @param data include data 821262395Sbapt * @param len length of data 822262395Sbapt * @param ud user data 823262395Sbapt * @param err error ptr 824262395Sbapt * @return 825262395Sbapt */ 826262975SbaptUCL_EXTERN bool 827262395Sbaptucl_includes_handler (const unsigned char *data, size_t len, void* ud) 828262395Sbapt{ 829262395Sbapt struct ucl_parser *parser = ud; 830262395Sbapt 831262395Sbapt if (*data == '/' || *data == '.') { 832262395Sbapt /* Try to load a file */ 833262395Sbapt return ucl_include_file (data, len, parser, true, true); 834262395Sbapt } 835262395Sbapt 836262395Sbapt return ucl_include_url (data, len, parser, true, true); 837262395Sbapt} 838262395Sbapt 839262395Sbapt 840262975SbaptUCL_EXTERN bool 841262395Sbaptucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 842262395Sbapt{ 843262395Sbapt struct ucl_parser *parser = ud; 844262395Sbapt 845262395Sbapt if (*data == '/' || *data == '.') { 846262395Sbapt /* Try to load a file */ 847262395Sbapt return ucl_include_file (data, len, parser, false, false); 848262395Sbapt } 849262395Sbapt 850262395Sbapt return ucl_include_url (data, len, parser, false, false); 851262395Sbapt} 852262395Sbapt 853262975SbaptUCL_EXTERN bool 854262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 855262395Sbapt{ 856262395Sbapt char realbuf[PATH_MAX], *curdir; 857262395Sbapt 858262395Sbapt if (filename != NULL) { 859262395Sbapt if (need_expand) { 860263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 861262395Sbapt return false; 862262395Sbapt } 863262395Sbapt } 864262395Sbapt else { 865262395Sbapt ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 866262395Sbapt } 867262395Sbapt 868262395Sbapt /* Define variables */ 869262395Sbapt ucl_parser_register_variable (parser, "FILENAME", realbuf); 870262395Sbapt curdir = dirname (realbuf); 871262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 872262395Sbapt } 873262395Sbapt else { 874262395Sbapt /* Set everything from the current dir */ 875262395Sbapt curdir = getcwd (realbuf, sizeof (realbuf)); 876262395Sbapt ucl_parser_register_variable (parser, "FILENAME", "undef"); 877262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 878262395Sbapt } 879262395Sbapt 880262395Sbapt return true; 881262395Sbapt} 882262395Sbapt 883262975SbaptUCL_EXTERN bool 884262395Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename) 885262395Sbapt{ 886262395Sbapt unsigned char *buf; 887262395Sbapt size_t len; 888262395Sbapt bool ret; 889262395Sbapt char realbuf[PATH_MAX]; 890262395Sbapt 891263648Sbapt if (ucl_realpath (filename, realbuf) == NULL) { 892262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 893262395Sbapt filename, 894262395Sbapt strerror (errno)); 895262395Sbapt return false; 896262395Sbapt } 897262395Sbapt 898262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 899262395Sbapt return false; 900262395Sbapt } 901262395Sbapt 902262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 903262395Sbapt ret = ucl_parser_add_chunk (parser, buf, len); 904262395Sbapt 905262395Sbapt if (len > 0) { 906263648Sbapt ucl_munmap (buf, len); 907262395Sbapt } 908262395Sbapt 909262395Sbapt return ret; 910262395Sbapt} 911262395Sbapt 912262395Sbaptsize_t 913262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz) 914262395Sbapt{ 915262395Sbapt char *d = dst; 916262395Sbapt const char *s = src; 917262395Sbapt size_t n = siz; 918262395Sbapt 919262395Sbapt /* Copy as many bytes as will fit */ 920262395Sbapt if (n != 0) { 921262395Sbapt while (--n != 0) { 922262395Sbapt if ((*d++ = *s++) == '\0') { 923262395Sbapt break; 924262395Sbapt } 925262395Sbapt } 926262395Sbapt } 927262395Sbapt 928262395Sbapt if (n == 0 && siz != 0) { 929262395Sbapt *d = '\0'; 930262395Sbapt } 931262395Sbapt 932262395Sbapt return (s - src - 1); /* count does not include NUL */ 933262395Sbapt} 934262395Sbapt 935262395Sbaptsize_t 936262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 937262395Sbapt{ 938262395Sbapt memcpy (dst, src, siz - 1); 939262395Sbapt dst[siz - 1] = '\0'; 940262395Sbapt 941262395Sbapt return siz - 1; 942262395Sbapt} 943262395Sbapt 944262395Sbaptsize_t 945262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 946262395Sbapt{ 947262395Sbapt char *d = dst; 948262395Sbapt const char *s = src; 949262395Sbapt size_t n = siz; 950262395Sbapt 951262395Sbapt /* Copy as many bytes as will fit */ 952262395Sbapt if (n != 0) { 953262395Sbapt while (--n != 0) { 954262395Sbapt if ((*d++ = tolower (*s++)) == '\0') { 955262395Sbapt break; 956262395Sbapt } 957262395Sbapt } 958262395Sbapt } 959262395Sbapt 960262395Sbapt if (n == 0 && siz != 0) { 961262395Sbapt *d = '\0'; 962262395Sbapt } 963262395Sbapt 964262395Sbapt return (s - src); /* count does not include NUL */ 965262395Sbapt} 966262395Sbapt 967262395Sbaptucl_object_t * 968262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 969262395Sbapt{ 970262395Sbapt ucl_object_t *obj; 971262395Sbapt const char *start, *end, *p, *pos; 972262395Sbapt char *dst, *d; 973262395Sbapt size_t escaped_len; 974262395Sbapt 975262395Sbapt if (str == NULL) { 976262395Sbapt return NULL; 977262395Sbapt } 978262395Sbapt 979262395Sbapt obj = ucl_object_new (); 980262395Sbapt if (obj) { 981262395Sbapt if (len == 0) { 982262395Sbapt len = strlen (str); 983262395Sbapt } 984262395Sbapt if (flags & UCL_STRING_TRIM) { 985262395Sbapt /* Skip leading spaces */ 986262395Sbapt for (start = str; (size_t)(start - str) < len; start ++) { 987262395Sbapt if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 988262395Sbapt break; 989262395Sbapt } 990262395Sbapt } 991262395Sbapt /* Skip trailing spaces */ 992262395Sbapt for (end = str + len - 1; end > start; end --) { 993262395Sbapt if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 994262395Sbapt break; 995262395Sbapt } 996262395Sbapt } 997262395Sbapt end ++; 998262395Sbapt } 999262395Sbapt else { 1000262395Sbapt start = str; 1001262395Sbapt end = str + len; 1002262395Sbapt } 1003262395Sbapt 1004262395Sbapt obj->type = UCL_STRING; 1005262395Sbapt if (flags & UCL_STRING_ESCAPE) { 1006262395Sbapt for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1007262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1008262395Sbapt escaped_len ++; 1009262395Sbapt } 1010262395Sbapt } 1011262395Sbapt dst = malloc (escaped_len + 1); 1012262395Sbapt if (dst != NULL) { 1013262395Sbapt for (p = start, d = dst; p < end; p ++, d ++) { 1014262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1015262395Sbapt switch (*p) { 1016262395Sbapt case '\n': 1017262395Sbapt *d++ = '\\'; 1018262395Sbapt *d = 'n'; 1019262395Sbapt break; 1020262395Sbapt case '\r': 1021262395Sbapt *d++ = '\\'; 1022262395Sbapt *d = 'r'; 1023262395Sbapt break; 1024262395Sbapt case '\b': 1025262395Sbapt *d++ = '\\'; 1026262395Sbapt *d = 'b'; 1027262395Sbapt break; 1028262395Sbapt case '\t': 1029262395Sbapt *d++ = '\\'; 1030262395Sbapt *d = 't'; 1031262395Sbapt break; 1032262395Sbapt case '\f': 1033262395Sbapt *d++ = '\\'; 1034262395Sbapt *d = 'f'; 1035262395Sbapt break; 1036262395Sbapt case '\\': 1037262395Sbapt *d++ = '\\'; 1038262395Sbapt *d = '\\'; 1039262395Sbapt break; 1040262395Sbapt case '"': 1041262395Sbapt *d++ = '\\'; 1042262395Sbapt *d = '"'; 1043262395Sbapt break; 1044262395Sbapt } 1045262395Sbapt } 1046262395Sbapt else { 1047262395Sbapt *d = *p; 1048262395Sbapt } 1049262395Sbapt } 1050262395Sbapt *d = '\0'; 1051262395Sbapt obj->value.sv = dst; 1052262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1053262395Sbapt obj->len = escaped_len; 1054262395Sbapt } 1055262395Sbapt } 1056262395Sbapt else { 1057262395Sbapt dst = malloc (end - start + 1); 1058262395Sbapt if (dst != NULL) { 1059262395Sbapt ucl_strlcpy_unsafe (dst, start, end - start + 1); 1060262395Sbapt obj->value.sv = dst; 1061262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1062262395Sbapt obj->len = end - start; 1063262395Sbapt } 1064262395Sbapt } 1065262395Sbapt if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1066262395Sbapt /* Parse what we have */ 1067262395Sbapt if (flags & UCL_STRING_PARSE_BOOLEAN) { 1068262395Sbapt if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1069262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1070262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1071263648Sbapt flags & UCL_STRING_PARSE_BYTES, 1072263648Sbapt flags & UCL_STRING_PARSE_TIME); 1073262395Sbapt } 1074262395Sbapt } 1075262395Sbapt else { 1076262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1077262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1078263648Sbapt flags & UCL_STRING_PARSE_BYTES, 1079263648Sbapt flags & UCL_STRING_PARSE_TIME); 1080262395Sbapt } 1081262395Sbapt } 1082262395Sbapt } 1083262395Sbapt 1084262395Sbapt return obj; 1085262395Sbapt} 1086262395Sbapt 1087262395Sbaptstatic ucl_object_t * 1088262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1089262395Sbapt const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1090262395Sbapt{ 1091262395Sbapt ucl_object_t *found, *cur; 1092262395Sbapt ucl_object_iter_t it = NULL; 1093262395Sbapt const char *p; 1094262395Sbapt 1095262395Sbapt if (elt == NULL || key == NULL) { 1096262395Sbapt return NULL; 1097262395Sbapt } 1098262395Sbapt 1099262395Sbapt if (top == NULL) { 1100262395Sbapt top = ucl_object_new (); 1101262395Sbapt top->type = UCL_OBJECT; 1102262395Sbapt } 1103262395Sbapt 1104262395Sbapt if (top->type != UCL_OBJECT) { 1105262395Sbapt /* It is possible to convert NULL type to an object */ 1106262395Sbapt if (top->type == UCL_NULL) { 1107262395Sbapt top->type = UCL_OBJECT; 1108262395Sbapt } 1109262395Sbapt else { 1110262395Sbapt /* Refuse converting of other object types */ 1111262395Sbapt return top; 1112262395Sbapt } 1113262395Sbapt } 1114262395Sbapt 1115262395Sbapt if (top->value.ov == NULL) { 1116262395Sbapt top->value.ov = ucl_hash_create (); 1117262395Sbapt } 1118262395Sbapt 1119262395Sbapt if (keylen == 0) { 1120262395Sbapt keylen = strlen (key); 1121262395Sbapt } 1122262395Sbapt 1123262395Sbapt for (p = key; p < key + keylen; p ++) { 1124262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1125262395Sbapt elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1126262395Sbapt break; 1127262395Sbapt } 1128262395Sbapt } 1129262395Sbapt 1130262395Sbapt elt->key = key; 1131262395Sbapt elt->keylen = keylen; 1132262395Sbapt 1133262395Sbapt if (copy_key) { 1134262395Sbapt ucl_copy_key_trash (elt); 1135262395Sbapt } 1136262395Sbapt 1137262395Sbapt found = ucl_hash_search_obj (top->value.ov, elt); 1138262395Sbapt 1139262395Sbapt if (!found) { 1140262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1141262395Sbapt DL_APPEND (found, elt); 1142263648Sbapt top->len ++; 1143262395Sbapt } 1144262395Sbapt else { 1145262395Sbapt if (replace) { 1146262395Sbapt ucl_hash_delete (top->value.ov, found); 1147262395Sbapt ucl_object_unref (found); 1148262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1149262395Sbapt found = NULL; 1150262395Sbapt DL_APPEND (found, elt); 1151262395Sbapt } 1152262395Sbapt else if (merge) { 1153262395Sbapt if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1154262395Sbapt /* Insert old elt to new one */ 1155262395Sbapt elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false); 1156262395Sbapt ucl_hash_delete (top->value.ov, found); 1157262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1158262395Sbapt } 1159262395Sbapt else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1160262395Sbapt /* Insert new to old */ 1161262395Sbapt found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false); 1162262395Sbapt } 1163262395Sbapt else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1164262395Sbapt /* Mix two hashes */ 1165262395Sbapt while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1166262395Sbapt ucl_object_ref (cur); 1167262395Sbapt found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false); 1168262395Sbapt } 1169262395Sbapt ucl_object_unref (elt); 1170262395Sbapt } 1171262395Sbapt else { 1172262395Sbapt /* Just make a list of scalars */ 1173262395Sbapt DL_APPEND (found, elt); 1174262395Sbapt } 1175262395Sbapt } 1176262395Sbapt else { 1177262395Sbapt DL_APPEND (found, elt); 1178262395Sbapt } 1179262395Sbapt } 1180262395Sbapt 1181262395Sbapt return top; 1182262395Sbapt} 1183262395Sbapt 1184262975Sbaptbool 1185262975Sbaptucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) 1186262975Sbapt{ 1187262975Sbapt ucl_object_t *found; 1188262975Sbapt 1189263648Sbapt if (top == NULL || key == NULL) { 1190263648Sbapt return false; 1191263648Sbapt } 1192263648Sbapt 1193262975Sbapt found = ucl_object_find_keyl(top, key, keylen); 1194262975Sbapt 1195263648Sbapt if (found == NULL) { 1196262975Sbapt return false; 1197263648Sbapt } 1198262975Sbapt 1199262975Sbapt ucl_hash_delete(top->value.ov, found); 1200262975Sbapt ucl_object_unref (found); 1201262975Sbapt top->len --; 1202262975Sbapt 1203262975Sbapt return true; 1204262975Sbapt} 1205262975Sbapt 1206262975Sbaptbool 1207262975Sbaptucl_object_delete_key(ucl_object_t *top, const char *key) 1208262975Sbapt{ 1209262975Sbapt return ucl_object_delete_keyl(top, key, 0); 1210262975Sbapt} 1211262975Sbapt 1212263648Sbaptucl_object_t* 1213263648Sbaptucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 1214263648Sbapt{ 1215263648Sbapt ucl_object_t *found; 1216263648Sbapt 1217263648Sbapt if (top == NULL || key == NULL) { 1218263648Sbapt return false; 1219263648Sbapt } 1220263648Sbapt found = ucl_object_find_keyl(top, key, keylen); 1221263648Sbapt 1222263648Sbapt if (found == NULL) { 1223263648Sbapt return NULL; 1224263648Sbapt } 1225263648Sbapt ucl_hash_delete(top->value.ov, found); 1226263648Sbapt top->len --; 1227263648Sbapt 1228263648Sbapt return found; 1229263648Sbapt} 1230263648Sbapt 1231263648Sbaptucl_object_t* 1232263648Sbaptucl_object_pop_key (ucl_object_t *top, const char *key) 1233263648Sbapt{ 1234263648Sbapt return ucl_object_pop_keyl (top, key, 0); 1235263648Sbapt} 1236263648Sbapt 1237262395Sbaptucl_object_t * 1238262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1239262395Sbapt const char *key, size_t keylen, bool copy_key) 1240262395Sbapt{ 1241262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1242262395Sbapt} 1243262395Sbapt 1244262395Sbaptucl_object_t * 1245262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1246262395Sbapt const char *key, size_t keylen, bool copy_key) 1247262395Sbapt{ 1248262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1249262395Sbapt} 1250262395Sbapt 1251262395Sbaptucl_object_t * 1252262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1253262395Sbapt const char *key, size_t keylen, bool copy_key) 1254262395Sbapt{ 1255262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1256262395Sbapt} 1257262395Sbapt 1258262395Sbaptucl_object_t * 1259262395Sbaptucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) 1260262395Sbapt{ 1261262395Sbapt ucl_object_t *ret, srch; 1262262395Sbapt 1263262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1264262395Sbapt return NULL; 1265262395Sbapt } 1266262395Sbapt 1267262395Sbapt srch.key = key; 1268262395Sbapt srch.keylen = klen; 1269262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1270262395Sbapt 1271262395Sbapt return ret; 1272262395Sbapt} 1273262395Sbapt 1274262395Sbaptucl_object_t * 1275262395Sbaptucl_object_find_key (ucl_object_t *obj, const char *key) 1276262395Sbapt{ 1277262395Sbapt size_t klen; 1278262395Sbapt ucl_object_t *ret, srch; 1279262395Sbapt 1280262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1281262395Sbapt return NULL; 1282262395Sbapt } 1283262395Sbapt 1284262395Sbapt klen = strlen (key); 1285262395Sbapt srch.key = key; 1286262395Sbapt srch.keylen = klen; 1287262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1288262395Sbapt 1289262395Sbapt return ret; 1290262395Sbapt} 1291262395Sbapt 1292262395Sbaptucl_object_t* 1293262395Sbaptucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1294262395Sbapt{ 1295262395Sbapt ucl_object_t *elt; 1296262395Sbapt 1297263648Sbapt if (obj == NULL || iter == NULL) { 1298263648Sbapt return NULL; 1299263648Sbapt } 1300263648Sbapt 1301262395Sbapt if (expand_values) { 1302262395Sbapt switch (obj->type) { 1303262395Sbapt case UCL_OBJECT: 1304262395Sbapt return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1305262395Sbapt break; 1306262395Sbapt case UCL_ARRAY: 1307262395Sbapt elt = *iter; 1308262395Sbapt if (elt == NULL) { 1309262395Sbapt elt = obj->value.av; 1310262395Sbapt if (elt == NULL) { 1311262395Sbapt return NULL; 1312262395Sbapt } 1313262395Sbapt } 1314262395Sbapt else if (elt == obj->value.av) { 1315262395Sbapt return NULL; 1316262395Sbapt } 1317262395Sbapt *iter = elt->next ? elt->next : obj->value.av; 1318262395Sbapt return elt; 1319262395Sbapt default: 1320262395Sbapt /* Go to linear iteration */ 1321262395Sbapt break; 1322262395Sbapt } 1323262395Sbapt } 1324262395Sbapt /* Treat everything as a linear list */ 1325262395Sbapt elt = *iter; 1326262395Sbapt if (elt == NULL) { 1327262395Sbapt elt = obj; 1328262395Sbapt if (elt == NULL) { 1329262395Sbapt return NULL; 1330262395Sbapt } 1331262395Sbapt } 1332262395Sbapt else if (elt == obj) { 1333262395Sbapt return NULL; 1334262395Sbapt } 1335262395Sbapt *iter = elt->next ? elt->next : obj; 1336262395Sbapt return elt; 1337262395Sbapt 1338262395Sbapt /* Not reached */ 1339262395Sbapt return NULL; 1340262395Sbapt} 1341263648Sbapt 1342263648Sbapt 1343263648Sbaptucl_object_t * 1344263648Sbaptucl_object_new (void) 1345263648Sbapt{ 1346263648Sbapt ucl_object_t *new; 1347263648Sbapt new = malloc (sizeof (ucl_object_t)); 1348263648Sbapt if (new != NULL) { 1349263648Sbapt memset (new, 0, sizeof (ucl_object_t)); 1350263648Sbapt new->ref = 1; 1351263648Sbapt new->type = UCL_NULL; 1352263648Sbapt } 1353263648Sbapt return new; 1354263648Sbapt} 1355263648Sbapt 1356263648Sbaptucl_object_t * 1357263648Sbaptucl_object_typed_new (unsigned int type) 1358263648Sbapt{ 1359263648Sbapt ucl_object_t *new; 1360263648Sbapt new = malloc (sizeof (ucl_object_t)); 1361263648Sbapt if (new != NULL) { 1362263648Sbapt memset (new, 0, sizeof (ucl_object_t)); 1363263648Sbapt new->ref = 1; 1364263648Sbapt new->type = (type <= UCL_NULL ? type : UCL_NULL); 1365263648Sbapt } 1366263648Sbapt return new; 1367263648Sbapt} 1368263648Sbapt 1369263648Sbaptucl_object_t* 1370263648Sbaptucl_object_fromstring (const char *str) 1371263648Sbapt{ 1372263648Sbapt return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 1373263648Sbapt} 1374263648Sbapt 1375263648Sbaptucl_object_t * 1376263648Sbaptucl_object_fromlstring (const char *str, size_t len) 1377263648Sbapt{ 1378263648Sbapt return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 1379263648Sbapt} 1380263648Sbapt 1381263648Sbaptucl_object_t * 1382263648Sbaptucl_object_fromint (int64_t iv) 1383263648Sbapt{ 1384263648Sbapt ucl_object_t *obj; 1385263648Sbapt 1386263648Sbapt obj = ucl_object_new (); 1387263648Sbapt if (obj != NULL) { 1388263648Sbapt obj->type = UCL_INT; 1389263648Sbapt obj->value.iv = iv; 1390263648Sbapt } 1391263648Sbapt 1392263648Sbapt return obj; 1393263648Sbapt} 1394263648Sbapt 1395263648Sbaptucl_object_t * 1396263648Sbaptucl_object_fromdouble (double dv) 1397263648Sbapt{ 1398263648Sbapt ucl_object_t *obj; 1399263648Sbapt 1400263648Sbapt obj = ucl_object_new (); 1401263648Sbapt if (obj != NULL) { 1402263648Sbapt obj->type = UCL_FLOAT; 1403263648Sbapt obj->value.dv = dv; 1404263648Sbapt } 1405263648Sbapt 1406263648Sbapt return obj; 1407263648Sbapt} 1408263648Sbapt 1409263648Sbaptucl_object_t* 1410263648Sbaptucl_object_frombool (bool bv) 1411263648Sbapt{ 1412263648Sbapt ucl_object_t *obj; 1413263648Sbapt 1414263648Sbapt obj = ucl_object_new (); 1415263648Sbapt if (obj != NULL) { 1416263648Sbapt obj->type = UCL_BOOLEAN; 1417263648Sbapt obj->value.iv = bv; 1418263648Sbapt } 1419263648Sbapt 1420263648Sbapt return obj; 1421263648Sbapt} 1422263648Sbapt 1423263648Sbaptucl_object_t * 1424263648Sbaptucl_array_append (ucl_object_t *top, ucl_object_t *elt) 1425263648Sbapt{ 1426263648Sbapt ucl_object_t *head; 1427263648Sbapt 1428263648Sbapt if (elt == NULL) { 1429263648Sbapt return NULL; 1430263648Sbapt } 1431263648Sbapt 1432263648Sbapt if (top == NULL) { 1433263648Sbapt top = ucl_object_typed_new (UCL_ARRAY); 1434263648Sbapt top->value.av = elt; 1435263648Sbapt elt->next = NULL; 1436263648Sbapt elt->prev = elt; 1437263648Sbapt top->len = 1; 1438263648Sbapt } 1439263648Sbapt else { 1440263648Sbapt head = top->value.av; 1441263648Sbapt if (head == NULL) { 1442263648Sbapt top->value.av = elt; 1443263648Sbapt elt->prev = elt; 1444263648Sbapt } 1445263648Sbapt else { 1446263648Sbapt elt->prev = head->prev; 1447263648Sbapt head->prev->next = elt; 1448263648Sbapt head->prev = elt; 1449263648Sbapt } 1450263648Sbapt elt->next = NULL; 1451263648Sbapt top->len ++; 1452263648Sbapt } 1453263648Sbapt 1454263648Sbapt return top; 1455263648Sbapt} 1456263648Sbapt 1457263648Sbaptucl_object_t * 1458263648Sbaptucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 1459263648Sbapt{ 1460263648Sbapt ucl_object_t *head; 1461263648Sbapt 1462263648Sbapt if (elt == NULL) { 1463263648Sbapt return NULL; 1464263648Sbapt } 1465263648Sbapt 1466263648Sbapt if (top == NULL) { 1467263648Sbapt top = ucl_object_typed_new (UCL_ARRAY); 1468263648Sbapt top->value.av = elt; 1469263648Sbapt elt->next = NULL; 1470263648Sbapt elt->prev = elt; 1471263648Sbapt top->len = 1; 1472263648Sbapt } 1473263648Sbapt else { 1474263648Sbapt head = top->value.av; 1475263648Sbapt if (head == NULL) { 1476263648Sbapt top->value.av = elt; 1477263648Sbapt elt->prev = elt; 1478263648Sbapt } 1479263648Sbapt else { 1480263648Sbapt elt->prev = head->prev; 1481263648Sbapt head->prev = elt; 1482263648Sbapt } 1483263648Sbapt elt->next = head; 1484263648Sbapt top->value.av = elt; 1485263648Sbapt top->len ++; 1486263648Sbapt } 1487263648Sbapt 1488263648Sbapt return top; 1489263648Sbapt} 1490263648Sbapt 1491263648Sbaptucl_object_t * 1492263648Sbaptucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 1493263648Sbapt{ 1494263648Sbapt ucl_object_t *head; 1495263648Sbapt 1496263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1497263648Sbapt return NULL; 1498263648Sbapt } 1499263648Sbapt head = top->value.av; 1500263648Sbapt 1501263648Sbapt if (elt->prev == elt) { 1502263648Sbapt top->value.av = NULL; 1503263648Sbapt } 1504263648Sbapt else if (elt == head) { 1505263648Sbapt elt->next->prev = elt->prev; 1506263648Sbapt top->value.av = elt->next; 1507263648Sbapt } 1508263648Sbapt else { 1509263648Sbapt elt->prev->next = elt->next; 1510263648Sbapt if (elt->next) { 1511263648Sbapt elt->next->prev = elt->prev; 1512263648Sbapt } 1513263648Sbapt else { 1514263648Sbapt head->prev = elt->prev; 1515263648Sbapt } 1516263648Sbapt } 1517263648Sbapt elt->next = NULL; 1518263648Sbapt elt->prev = elt; 1519263648Sbapt top->len --; 1520263648Sbapt 1521263648Sbapt return elt; 1522263648Sbapt} 1523263648Sbapt 1524263648Sbaptucl_object_t * 1525263648Sbaptucl_array_head (ucl_object_t *top) 1526263648Sbapt{ 1527263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1528263648Sbapt return NULL; 1529263648Sbapt } 1530263648Sbapt return top->value.av; 1531263648Sbapt} 1532263648Sbapt 1533263648Sbaptucl_object_t * 1534263648Sbaptucl_array_tail (ucl_object_t *top) 1535263648Sbapt{ 1536263648Sbapt if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1537263648Sbapt return NULL; 1538263648Sbapt } 1539263648Sbapt return top->value.av->prev; 1540263648Sbapt} 1541263648Sbapt 1542263648Sbaptucl_object_t * 1543263648Sbaptucl_array_pop_last (ucl_object_t *top) 1544263648Sbapt{ 1545263648Sbapt return ucl_array_delete (top, ucl_array_tail (top)); 1546263648Sbapt} 1547263648Sbapt 1548263648Sbaptucl_object_t * 1549263648Sbaptucl_array_pop_first (ucl_object_t *top) 1550263648Sbapt{ 1551263648Sbapt return ucl_array_delete (top, ucl_array_head (top)); 1552263648Sbapt} 1553263648Sbapt 1554263648Sbaptucl_object_t * 1555263648Sbaptucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 1556263648Sbapt{ 1557263648Sbapt 1558263648Sbapt if (head == NULL) { 1559263648Sbapt elt->next = NULL; 1560263648Sbapt elt->prev = elt; 1561263648Sbapt head = elt; 1562263648Sbapt } 1563263648Sbapt else { 1564263648Sbapt elt->prev = head->prev; 1565263648Sbapt head->prev->next = elt; 1566263648Sbapt head->prev = elt; 1567263648Sbapt elt->next = NULL; 1568263648Sbapt } 1569263648Sbapt 1570263648Sbapt return head; 1571263648Sbapt} 1572263648Sbapt 1573263648Sbaptbool 1574263648Sbaptucl_object_todouble_safe (ucl_object_t *obj, double *target) 1575263648Sbapt{ 1576263648Sbapt if (obj == NULL || target == NULL) { 1577263648Sbapt return false; 1578263648Sbapt } 1579263648Sbapt switch (obj->type) { 1580263648Sbapt case UCL_INT: 1581263648Sbapt *target = obj->value.iv; /* Probaly could cause overflow */ 1582263648Sbapt break; 1583263648Sbapt case UCL_FLOAT: 1584263648Sbapt case UCL_TIME: 1585263648Sbapt *target = obj->value.dv; 1586263648Sbapt break; 1587263648Sbapt default: 1588263648Sbapt return false; 1589263648Sbapt } 1590263648Sbapt 1591263648Sbapt return true; 1592263648Sbapt} 1593263648Sbapt 1594263648Sbaptdouble 1595263648Sbaptucl_object_todouble (ucl_object_t *obj) 1596263648Sbapt{ 1597263648Sbapt double result = 0.; 1598263648Sbapt 1599263648Sbapt ucl_object_todouble_safe (obj, &result); 1600263648Sbapt return result; 1601263648Sbapt} 1602263648Sbapt 1603263648Sbaptbool 1604263648Sbaptucl_object_toint_safe (ucl_object_t *obj, int64_t *target) 1605263648Sbapt{ 1606263648Sbapt if (obj == NULL || target == NULL) { 1607263648Sbapt return false; 1608263648Sbapt } 1609263648Sbapt switch (obj->type) { 1610263648Sbapt case UCL_INT: 1611263648Sbapt *target = obj->value.iv; 1612263648Sbapt break; 1613263648Sbapt case UCL_FLOAT: 1614263648Sbapt case UCL_TIME: 1615263648Sbapt *target = obj->value.dv; /* Loosing of decimal points */ 1616263648Sbapt break; 1617263648Sbapt default: 1618263648Sbapt return false; 1619263648Sbapt } 1620263648Sbapt 1621263648Sbapt return true; 1622263648Sbapt} 1623263648Sbapt 1624263648Sbaptint64_t 1625263648Sbaptucl_object_toint (ucl_object_t *obj) 1626263648Sbapt{ 1627263648Sbapt int64_t result = 0; 1628263648Sbapt 1629263648Sbapt ucl_object_toint_safe (obj, &result); 1630263648Sbapt return result; 1631263648Sbapt} 1632263648Sbapt 1633263648Sbaptbool 1634263648Sbaptucl_object_toboolean_safe (ucl_object_t *obj, bool *target) 1635263648Sbapt{ 1636263648Sbapt if (obj == NULL || target == NULL) { 1637263648Sbapt return false; 1638263648Sbapt } 1639263648Sbapt switch (obj->type) { 1640263648Sbapt case UCL_BOOLEAN: 1641263648Sbapt *target = (obj->value.iv == true); 1642263648Sbapt break; 1643263648Sbapt default: 1644263648Sbapt return false; 1645263648Sbapt } 1646263648Sbapt 1647263648Sbapt return true; 1648263648Sbapt} 1649263648Sbapt 1650263648Sbaptbool 1651263648Sbaptucl_object_toboolean (ucl_object_t *obj) 1652263648Sbapt{ 1653263648Sbapt bool result = false; 1654263648Sbapt 1655263648Sbapt ucl_object_toboolean_safe (obj, &result); 1656263648Sbapt return result; 1657263648Sbapt} 1658263648Sbapt 1659263648Sbaptbool 1660263648Sbaptucl_object_tostring_safe (ucl_object_t *obj, const char **target) 1661263648Sbapt{ 1662263648Sbapt if (obj == NULL || target == NULL) { 1663263648Sbapt return false; 1664263648Sbapt } 1665263648Sbapt 1666263648Sbapt switch (obj->type) { 1667263648Sbapt case UCL_STRING: 1668263648Sbapt *target = ucl_copy_value_trash (obj); 1669263648Sbapt break; 1670263648Sbapt default: 1671263648Sbapt return false; 1672263648Sbapt } 1673263648Sbapt 1674263648Sbapt return true; 1675263648Sbapt} 1676263648Sbapt 1677263648Sbaptconst char * 1678263648Sbaptucl_object_tostring (ucl_object_t *obj) 1679263648Sbapt{ 1680263648Sbapt const char *result = NULL; 1681263648Sbapt 1682263648Sbapt ucl_object_tostring_safe (obj, &result); 1683263648Sbapt return result; 1684263648Sbapt} 1685263648Sbapt 1686263648Sbaptconst char * 1687263648Sbaptucl_object_tostring_forced (ucl_object_t *obj) 1688263648Sbapt{ 1689263648Sbapt return ucl_copy_value_trash (obj); 1690263648Sbapt} 1691263648Sbapt 1692263648Sbaptbool 1693263648Sbaptucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen) 1694263648Sbapt{ 1695263648Sbapt if (obj == NULL || target == NULL) { 1696263648Sbapt return false; 1697263648Sbapt } 1698263648Sbapt switch (obj->type) { 1699263648Sbapt case UCL_STRING: 1700263648Sbapt *target = obj->value.sv; 1701263648Sbapt if (tlen != NULL) { 1702263648Sbapt *tlen = obj->len; 1703263648Sbapt } 1704263648Sbapt break; 1705263648Sbapt default: 1706263648Sbapt return false; 1707263648Sbapt } 1708263648Sbapt 1709263648Sbapt return true; 1710263648Sbapt} 1711263648Sbapt 1712263648Sbaptconst char * 1713263648Sbaptucl_object_tolstring (ucl_object_t *obj, size_t *tlen) 1714263648Sbapt{ 1715263648Sbapt const char *result = NULL; 1716263648Sbapt 1717263648Sbapt ucl_object_tolstring_safe (obj, &result, tlen); 1718263648Sbapt return result; 1719263648Sbapt} 1720263648Sbapt 1721263648Sbaptconst char * 1722263648Sbaptucl_object_key (ucl_object_t *obj) 1723263648Sbapt{ 1724263648Sbapt return ucl_copy_key_trash (obj); 1725263648Sbapt} 1726263648Sbapt 1727263648Sbaptconst char * 1728263648Sbaptucl_object_keyl (ucl_object_t *obj, size_t *len) 1729263648Sbapt{ 1730263648Sbapt if (len == NULL || obj == NULL) { 1731263648Sbapt return NULL; 1732263648Sbapt } 1733263648Sbapt *len = obj->keylen; 1734263648Sbapt return obj->key; 1735263648Sbapt} 1736263648Sbapt 1737263648Sbaptucl_object_t * 1738263648Sbaptucl_object_ref (ucl_object_t *obj) 1739263648Sbapt{ 1740263648Sbapt if (obj != NULL) { 1741263648Sbapt obj->ref ++; 1742263648Sbapt } 1743263648Sbapt return obj; 1744263648Sbapt} 1745263648Sbapt 1746263648Sbaptvoid 1747263648Sbaptucl_object_unref (ucl_object_t *obj) 1748263648Sbapt{ 1749263648Sbapt if (obj != NULL && --obj->ref <= 0) { 1750263648Sbapt ucl_object_free (obj); 1751263648Sbapt } 1752263648Sbapt} 1753263648Sbapt 1754263648Sbaptint 1755263648Sbaptucl_object_compare (ucl_object_t *o1, ucl_object_t *o2) 1756263648Sbapt{ 1757263648Sbapt ucl_object_t *it1, *it2; 1758263648Sbapt ucl_object_iter_t iter = NULL; 1759263648Sbapt int ret = 0; 1760263648Sbapt 1761263648Sbapt if (o1->type != o2->type) { 1762263648Sbapt return (o1->type) - (o2->type); 1763263648Sbapt } 1764263648Sbapt 1765263648Sbapt switch (o1->type) { 1766263648Sbapt case UCL_STRING: 1767263648Sbapt if (o1->len == o2->len) { 1768263648Sbapt ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 1769263648Sbapt } 1770263648Sbapt else { 1771263648Sbapt ret = o1->len - o2->len; 1772263648Sbapt } 1773263648Sbapt break; 1774263648Sbapt case UCL_FLOAT: 1775263648Sbapt case UCL_INT: 1776263648Sbapt case UCL_TIME: 1777263648Sbapt ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 1778263648Sbapt break; 1779263648Sbapt case UCL_BOOLEAN: 1780263648Sbapt ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 1781263648Sbapt break; 1782263648Sbapt case UCL_ARRAY: 1783263648Sbapt if (o1->len == o2->len) { 1784263648Sbapt it1 = o1->value.av; 1785263648Sbapt it2 = o2->value.av; 1786263648Sbapt /* Compare all elements in both arrays */ 1787263648Sbapt while (it1 != NULL && it2 != NULL) { 1788263648Sbapt ret = ucl_object_compare (it1, it2); 1789263648Sbapt if (ret != 0) { 1790263648Sbapt break; 1791263648Sbapt } 1792263648Sbapt it1 = it1->next; 1793263648Sbapt it2 = it2->next; 1794263648Sbapt } 1795263648Sbapt } 1796263648Sbapt else { 1797263648Sbapt ret = o1->len - o2->len; 1798263648Sbapt } 1799263648Sbapt break; 1800263648Sbapt case UCL_OBJECT: 1801263648Sbapt if (o1->len == o2->len) { 1802263648Sbapt while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 1803263648Sbapt it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 1804263648Sbapt if (it2 == NULL) { 1805263648Sbapt ret = 1; 1806263648Sbapt break; 1807263648Sbapt } 1808263648Sbapt ret = ucl_object_compare (it1, it2); 1809263648Sbapt if (ret != 0) { 1810263648Sbapt break; 1811263648Sbapt } 1812263648Sbapt } 1813263648Sbapt } 1814263648Sbapt else { 1815263648Sbapt ret = o1->len - o2->len; 1816263648Sbapt } 1817263648Sbapt break; 1818263648Sbapt default: 1819263648Sbapt ret = 0; 1820263648Sbapt break; 1821263648Sbapt } 1822263648Sbapt 1823263648Sbapt return ret; 1824263648Sbapt} 1825263648Sbapt 1826263648Sbaptvoid 1827263648Sbaptucl_object_array_sort (ucl_object_t *ar, 1828263648Sbapt int (*cmp)(ucl_object_t *o1, ucl_object_t *o2)) 1829263648Sbapt{ 1830263648Sbapt if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 1831263648Sbapt return; 1832263648Sbapt } 1833263648Sbapt 1834263648Sbapt DL_SORT (ar->value.av, cmp); 1835263648Sbapt} 1836