1 /* Copyright (c) 2013, Vsevolod Stakhov 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 */ 23 24 #include "ucl.h" 25 #include "ucl_internal.h" 26 #include "ucl_chartable.h" 27 28 #ifdef HAVE_LIBGEN_H 29 #include <libgen.h> /* For dirname */ 30 #endif 31 32 #ifdef HAVE_OPENSSL 33 #include <openssl/err.h> 34 #include <openssl/sha.h> 35 #include <openssl/rsa.h> 36 #include <openssl/ssl.h> 37 #include <openssl/evp.h> 38 #endif 39 40 #ifdef CURL_FOUND 41 #include <curl/curl.h> 42 #endif 43 #ifdef HAVE_FETCH_H 44 #include <fetch.h> 45 #endif 46 47 #ifdef _WIN32 48 #include <windows.h> 49 50 #ifndef PROT_READ 51 #define PROT_READ 1 52 #endif 53 #ifndef PROT_WRITE 54 #define PROT_WRITE 2 55 #endif 56 #ifndef PROT_READWRITE 57 #define PROT_READWRITE 3 58 #endif 59 #ifndef MAP_SHARED 60 #define MAP_SHARED 1 61 #endif 62 #ifndef MAP_PRIVATE 63 #define MAP_PRIVATE 2 64 #endif 65 #ifndef MAP_FAILED 66 #define MAP_FAILED ((void *) -1) 67 #endif 68 69 static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 70 { 71 void *map = NULL; 72 HANDLE handle = INVALID_HANDLE_VALUE; 73 74 switch (prot) { 75 default: 76 case PROT_READ: 77 { 78 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 79 if (!handle) break; 80 map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 81 CloseHandle(handle); 82 break; 83 } 84 case PROT_WRITE: 85 { 86 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 87 if (!handle) break; 88 map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 89 CloseHandle(handle); 90 break; 91 } 92 case PROT_READWRITE: 93 { 94 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 95 if (!handle) break; 96 map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 97 CloseHandle(handle); 98 break; 99 } 100 } 101 if (map == (void *) NULL) { 102 return (void *) MAP_FAILED; 103 } 104 return (void *) ((char *) map + offset); 105 } 106 107 static int ucl_munmap(void *map,size_t length) 108 { 109 if (!UnmapViewOfFile(map)) { 110 return(-1); 111 } 112 return(0); 113 } 114 115 static char* ucl_realpath(const char *path, char *resolved_path) { 116 char *p; 117 char tmp[MAX_PATH + 1]; 118 strncpy(tmp, path, sizeof(tmp)-1); 119 p = tmp; 120 while(*p) { 121 if (*p == '/') *p = '\\'; 122 p++; 123 } 124 return _fullpath(resolved_path, tmp, MAX_PATH); 125 } 126 #else 127 #define ucl_mmap mmap 128 #define ucl_munmap munmap 129 #define ucl_realpath realpath 130 #endif 131 132 /** 133 * @file rcl_util.c 134 * Utilities for rcl parsing 135 */ 136 137 138 static void 139 ucl_object_free_internal (ucl_object_t *obj, bool allow_rec) 140 { 141 ucl_object_t *sub, *tmp; 142 143 while (obj != NULL) { 144 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 145 UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 146 } 147 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 148 UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 149 } 150 151 if (obj->type == UCL_ARRAY) { 152 sub = obj->value.av; 153 while (sub != NULL) { 154 tmp = sub->next; 155 ucl_object_free_internal (sub, false); 156 sub = tmp; 157 } 158 } 159 else if (obj->type == UCL_OBJECT) { 160 if (obj->value.ov != NULL) { 161 ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref); 162 } 163 } 164 tmp = obj->next; 165 UCL_FREE (sizeof (ucl_object_t), obj); 166 obj = tmp; 167 168 if (!allow_rec) { 169 break; 170 } 171 } 172 } 173 174 void 175 ucl_object_free (ucl_object_t *obj) 176 { 177 ucl_object_free_internal (obj, true); 178 } 179 180 size_t 181 ucl_unescape_json_string (char *str, size_t len) 182 { 183 char *t = str, *h = str; 184 int i, uval; 185 186 if (len <= 1) { 187 return len; 188 } 189 /* t is target (tortoise), h is source (hare) */ 190 191 while (len) { 192 if (*h == '\\') { 193 h ++; 194 switch (*h) { 195 case 'n': 196 *t++ = '\n'; 197 break; 198 case 'r': 199 *t++ = '\r'; 200 break; 201 case 'b': 202 *t++ = '\b'; 203 break; 204 case 't': 205 *t++ = '\t'; 206 break; 207 case 'f': 208 *t++ = '\f'; 209 break; 210 case '\\': 211 *t++ = '\\'; 212 break; 213 case '"': 214 *t++ = '"'; 215 break; 216 case 'u': 217 /* Unicode escape */ 218 uval = 0; 219 if (len > 3) { 220 for (i = 0; i < 4; i++) { 221 uval <<= 4; 222 if (isdigit (h[i])) { 223 uval += h[i] - '0'; 224 } 225 else if (h[i] >= 'a' && h[i] <= 'f') { 226 uval += h[i] - 'a' + 10; 227 } 228 else if (h[i] >= 'A' && h[i] <= 'F') { 229 uval += h[i] - 'A' + 10; 230 } 231 else { 232 break; 233 } 234 } 235 h += 3; 236 len -= 3; 237 /* Encode */ 238 if(uval < 0x80) { 239 t[0] = (char)uval; 240 t ++; 241 } 242 else if(uval < 0x800) { 243 t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 244 t[1] = 0x80 + ((uval & 0x03F)); 245 t += 2; 246 } 247 else if(uval < 0x10000) { 248 t[0] = 0xE0 + ((uval & 0xF000) >> 12); 249 t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 250 t[2] = 0x80 + ((uval & 0x003F)); 251 t += 3; 252 } 253 else if(uval <= 0x10FFFF) { 254 t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 255 t[1] = 0x80 + ((uval & 0x03F000) >> 12); 256 t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 257 t[3] = 0x80 + ((uval & 0x00003F)); 258 t += 4; 259 } 260 else { 261 *t++ = '?'; 262 } 263 } 264 else { 265 *t++ = 'u'; 266 } 267 break; 268 default: 269 *t++ = *h; 270 break; 271 } 272 h ++; 273 len --; 274 } 275 else { 276 *t++ = *h++; 277 } 278 len --; 279 } 280 *t = '\0'; 281 282 return (t - str); 283 } 284 285 UCL_EXTERN char * 286 ucl_copy_key_trash (ucl_object_t *obj) 287 { 288 if (obj == NULL) { 289 return NULL; 290 } 291 if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 292 obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 293 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 294 memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 295 obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 296 } 297 obj->key = obj->trash_stack[UCL_TRASH_KEY]; 298 obj->flags |= UCL_OBJECT_ALLOCATED_KEY; 299 } 300 301 return obj->trash_stack[UCL_TRASH_KEY]; 302 } 303 304 UCL_EXTERN char * 305 ucl_copy_value_trash (ucl_object_t *obj) 306 { 307 if (obj == NULL) { 308 return NULL; 309 } 310 if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 311 if (obj->type == UCL_STRING) { 312 /* Special case for strings */ 313 obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 314 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 315 memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 316 obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 317 obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 318 } 319 } 320 else { 321 /* Just emit value in json notation */ 322 obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 323 obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 324 } 325 obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; 326 } 327 return obj->trash_stack[UCL_TRASH_VALUE]; 328 } 329 330 UCL_EXTERN ucl_object_t* 331 ucl_parser_get_object (struct ucl_parser *parser) 332 { 333 if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 334 return ucl_object_ref (parser->top_obj); 335 } 336 337 return NULL; 338 } 339 340 UCL_EXTERN void 341 ucl_parser_free (struct ucl_parser *parser) 342 { 343 struct ucl_stack *stack, *stmp; 344 struct ucl_macro *macro, *mtmp; 345 struct ucl_chunk *chunk, *ctmp; 346 struct ucl_pubkey *key, *ktmp; 347 struct ucl_variable *var, *vtmp; 348 349 if (parser == NULL) { 350 return; 351 } 352 353 if (parser->top_obj != NULL) { 354 ucl_object_unref (parser->top_obj); 355 } 356 357 LL_FOREACH_SAFE (parser->stack, stack, stmp) { 358 free (stack); 359 } 360 HASH_ITER (hh, parser->macroes, macro, mtmp) { 361 free (macro->name); 362 HASH_DEL (parser->macroes, macro); 363 UCL_FREE (sizeof (struct ucl_macro), macro); 364 } 365 LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 366 UCL_FREE (sizeof (struct ucl_chunk), chunk); 367 } 368 LL_FOREACH_SAFE (parser->keys, key, ktmp) { 369 UCL_FREE (sizeof (struct ucl_pubkey), key); 370 } 371 LL_FOREACH_SAFE (parser->variables, var, vtmp) { 372 free (var->value); 373 free (var->var); 374 UCL_FREE (sizeof (struct ucl_variable), var); 375 } 376 377 if (parser->err != NULL) { 378 utstring_free(parser->err); 379 } 380 381 UCL_FREE (sizeof (struct ucl_parser), parser); 382 } 383 384 UCL_EXTERN const char * 385 ucl_parser_get_error(struct ucl_parser *parser) 386 { 387 if (parser == NULL) { 388 return NULL; 389 } 390 391 if (parser->err == NULL) 392 return NULL; 393 394 return utstring_body(parser->err); 395 } 396 397 UCL_EXTERN bool 398 ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 399 { 400 #ifndef HAVE_OPENSSL 401 ucl_create_err (&parser->err, "cannot check signatures without openssl"); 402 return false; 403 #else 404 # if (OPENSSL_VERSION_NUMBER < 0x10000000L) 405 ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 406 return EXIT_FAILURE; 407 # else 408 struct ucl_pubkey *nkey; 409 BIO *mem; 410 411 mem = BIO_new_mem_buf ((void *)key, len); 412 nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 413 if (nkey == NULL) { 414 ucl_create_err (&parser->err, "cannot allocate memory for key"); 415 return false; 416 } 417 nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 418 BIO_free (mem); 419 if (nkey->key == NULL) { 420 UCL_FREE (sizeof (struct ucl_pubkey), nkey); 421 ucl_create_err (&parser->err, "%s", 422 ERR_error_string (ERR_get_error (), NULL)); 423 return false; 424 } 425 LL_PREPEND (parser->keys, nkey); 426 # endif 427 #endif 428 return true; 429 } 430 431 #ifdef CURL_FOUND 432 struct ucl_curl_cbdata { 433 unsigned char *buf; 434 size_t buflen; 435 }; 436 437 static size_t 438 ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 439 { 440 struct ucl_curl_cbdata *cbdata = ud; 441 size_t realsize = size * nmemb; 442 443 cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 444 if (cbdata->buf == NULL) { 445 return 0; 446 } 447 448 memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 449 cbdata->buflen += realsize; 450 cbdata->buf[cbdata->buflen] = 0; 451 452 return realsize; 453 } 454 #endif 455 456 /** 457 * Fetch a url and save results to the memory buffer 458 * @param url url to fetch 459 * @param len length of url 460 * @param buf target buffer 461 * @param buflen target length 462 * @return 463 */ 464 static bool 465 ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 466 UT_string **err, bool must_exist) 467 { 468 469 #ifdef HAVE_FETCH_H 470 struct url *fetch_url; 471 struct url_stat us; 472 FILE *in; 473 474 fetch_url = fetchParseURL (url); 475 if (fetch_url == NULL) { 476 ucl_create_err (err, "invalid URL %s: %s", 477 url, strerror (errno)); 478 return false; 479 } 480 if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 481 if (!must_exist) { 482 ucl_create_err (err, "cannot fetch URL %s: %s", 483 url, strerror (errno)); 484 } 485 fetchFreeURL (fetch_url); 486 return false; 487 } 488 489 *buflen = us.size; 490 *buf = malloc (*buflen); 491 if (*buf == NULL) { 492 ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 493 url, strerror (errno)); 494 fclose (in); 495 fetchFreeURL (fetch_url); 496 return false; 497 } 498 499 if (fread (*buf, *buflen, 1, in) != 1) { 500 ucl_create_err (err, "cannot read URL %s: %s", 501 url, strerror (errno)); 502 fclose (in); 503 fetchFreeURL (fetch_url); 504 return false; 505 } 506 507 fetchFreeURL (fetch_url); 508 return true; 509 #elif defined(CURL_FOUND) 510 CURL *curl; 511 int r; 512 struct ucl_curl_cbdata cbdata; 513 514 curl = curl_easy_init (); 515 if (curl == NULL) { 516 ucl_create_err (err, "CURL interface is broken"); 517 return false; 518 } 519 if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 520 ucl_create_err (err, "invalid URL %s: %s", 521 url, curl_easy_strerror (r)); 522 curl_easy_cleanup (curl); 523 return false; 524 } 525 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 526 cbdata.buf = *buf; 527 cbdata.buflen = *buflen; 528 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 529 530 if ((r = curl_easy_perform (curl)) != CURLE_OK) { 531 if (!must_exist) { 532 ucl_create_err (err, "error fetching URL %s: %s", 533 url, curl_easy_strerror (r)); 534 } 535 curl_easy_cleanup (curl); 536 if (cbdata.buf) { 537 free (cbdata.buf); 538 } 539 return false; 540 } 541 *buf = cbdata.buf; 542 *buflen = cbdata.buflen; 543 544 return true; 545 #else 546 ucl_create_err (err, "URL support is disabled"); 547 return false; 548 #endif 549 } 550 551 /** 552 * Fetch a file and save results to the memory buffer 553 * @param filename filename to fetch 554 * @param len length of filename 555 * @param buf target buffer 556 * @param buflen target length 557 * @return 558 */ 559 static bool 560 ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 561 UT_string **err, bool must_exist) 562 { 563 int fd; 564 struct stat st; 565 566 if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 567 if (must_exist) { 568 ucl_create_err (err, "cannot stat file %s: %s", 569 filename, strerror (errno)); 570 } 571 return false; 572 } 573 if (st.st_size == 0) { 574 /* Do not map empty files */ 575 *buf = ""; 576 *buflen = 0; 577 } 578 else { 579 if ((fd = open (filename, O_RDONLY)) == -1) { 580 ucl_create_err (err, "cannot open file %s: %s", 581 filename, strerror (errno)); 582 return false; 583 } 584 if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 585 close (fd); 586 ucl_create_err (err, "cannot mmap file %s: %s", 587 filename, strerror (errno)); 588 return false; 589 } 590 *buflen = st.st_size; 591 close (fd); 592 } 593 594 return true; 595 } 596 597 598 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 599 static inline bool 600 ucl_sig_check (const unsigned char *data, size_t datalen, 601 const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 602 { 603 struct ucl_pubkey *key; 604 char dig[EVP_MAX_MD_SIZE]; 605 unsigned int diglen; 606 EVP_PKEY_CTX *key_ctx; 607 EVP_MD_CTX *sign_ctx = NULL; 608 609 sign_ctx = EVP_MD_CTX_create (); 610 611 LL_FOREACH (parser->keys, key) { 612 key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 613 if (key_ctx != NULL) { 614 if (EVP_PKEY_verify_init (key_ctx) <= 0) { 615 EVP_PKEY_CTX_free (key_ctx); 616 continue; 617 } 618 if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 619 EVP_PKEY_CTX_free (key_ctx); 620 continue; 621 } 622 if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 623 EVP_PKEY_CTX_free (key_ctx); 624 continue; 625 } 626 EVP_DigestInit (sign_ctx, EVP_sha256 ()); 627 EVP_DigestUpdate (sign_ctx, data, datalen); 628 EVP_DigestFinal (sign_ctx, dig, &diglen); 629 630 if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 631 EVP_MD_CTX_destroy (sign_ctx); 632 EVP_PKEY_CTX_free (key_ctx); 633 return true; 634 } 635 636 EVP_PKEY_CTX_free (key_ctx); 637 } 638 } 639 640 EVP_MD_CTX_destroy (sign_ctx); 641 642 return false; 643 } 644 #endif 645 646 /** 647 * Include an url to configuration 648 * @param data 649 * @param len 650 * @param parser 651 * @param err 652 * @return 653 */ 654 static bool 655 ucl_include_url (const unsigned char *data, size_t len, 656 struct ucl_parser *parser, bool check_signature, bool must_exist) 657 { 658 659 bool res; 660 unsigned char *buf = NULL; 661 size_t buflen = 0; 662 struct ucl_chunk *chunk; 663 char urlbuf[PATH_MAX]; 664 int prev_state; 665 666 snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 667 668 if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 669 return (!must_exist || false); 670 } 671 672 if (check_signature) { 673 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 674 unsigned char *sigbuf = NULL; 675 size_t siglen = 0; 676 /* We need to check signature first */ 677 snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 678 if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 679 return false; 680 } 681 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 682 ucl_create_err (&parser->err, "cannot verify url %s: %s", 683 urlbuf, 684 ERR_error_string (ERR_get_error (), NULL)); 685 if (siglen > 0) { 686 ucl_munmap (sigbuf, siglen); 687 } 688 return false; 689 } 690 if (siglen > 0) { 691 ucl_munmap (sigbuf, siglen); 692 } 693 #endif 694 } 695 696 prev_state = parser->state; 697 parser->state = UCL_STATE_INIT; 698 699 res = ucl_parser_add_chunk (parser, buf, buflen); 700 if (res == true) { 701 /* Remove chunk from the stack */ 702 chunk = parser->chunks; 703 if (chunk != NULL) { 704 parser->chunks = chunk->next; 705 UCL_FREE (sizeof (struct ucl_chunk), chunk); 706 } 707 } 708 709 parser->state = prev_state; 710 free (buf); 711 712 return res; 713 } 714 715 /** 716 * Include a file to configuration 717 * @param data 718 * @param len 719 * @param parser 720 * @param err 721 * @return 722 */ 723 static bool 724 ucl_include_file (const unsigned char *data, size_t len, 725 struct ucl_parser *parser, bool check_signature, bool must_exist) 726 { 727 bool res; 728 struct ucl_chunk *chunk; 729 unsigned char *buf = NULL; 730 size_t buflen; 731 char filebuf[PATH_MAX], realbuf[PATH_MAX]; 732 int prev_state; 733 734 snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 735 if (ucl_realpath (filebuf, realbuf) == NULL) { 736 if (!must_exist) { 737 return true; 738 } 739 ucl_create_err (&parser->err, "cannot open file %s: %s", 740 filebuf, 741 strerror (errno)); 742 return false; 743 } 744 745 if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 746 return (!must_exist || false); 747 } 748 749 if (check_signature) { 750 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 751 unsigned char *sigbuf = NULL; 752 size_t siglen = 0; 753 /* We need to check signature first */ 754 snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 755 if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 756 return false; 757 } 758 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 759 ucl_create_err (&parser->err, "cannot verify file %s: %s", 760 filebuf, 761 ERR_error_string (ERR_get_error (), NULL)); 762 if (siglen > 0) { 763 ucl_munmap (sigbuf, siglen); 764 } 765 return false; 766 } 767 if (siglen > 0) { 768 ucl_munmap (sigbuf, siglen); 769 } 770 #endif 771 } 772 773 ucl_parser_set_filevars (parser, realbuf, false); 774 775 prev_state = parser->state; 776 parser->state = UCL_STATE_INIT; 777 778 res = ucl_parser_add_chunk (parser, buf, buflen); 779 if (res == true) { 780 /* Remove chunk from the stack */ 781 chunk = parser->chunks; 782 if (chunk != NULL) { 783 parser->chunks = chunk->next; 784 UCL_FREE (sizeof (struct ucl_chunk), chunk); 785 } 786 } 787 788 parser->state = prev_state; 789 790 if (buflen > 0) { 791 ucl_munmap (buf, buflen); 792 } 793 794 return res; 795 } 796 797 /** 798 * Handle include macro 799 * @param data include data 800 * @param len length of data 801 * @param ud user data 802 * @param err error ptr 803 * @return 804 */ 805 UCL_EXTERN bool 806 ucl_include_handler (const unsigned char *data, size_t len, void* ud) 807 { 808 struct ucl_parser *parser = ud; 809 810 if (*data == '/' || *data == '.') { 811 /* Try to load a file */ 812 return ucl_include_file (data, len, parser, false, true); 813 } 814 815 return ucl_include_url (data, len, parser, false, true); 816 } 817 818 /** 819 * Handle includes macro 820 * @param data include data 821 * @param len length of data 822 * @param ud user data 823 * @param err error ptr 824 * @return 825 */ 826 UCL_EXTERN bool 827 ucl_includes_handler (const unsigned char *data, size_t len, void* ud) 828 { 829 struct ucl_parser *parser = ud; 830 831 if (*data == '/' || *data == '.') { 832 /* Try to load a file */ 833 return ucl_include_file (data, len, parser, true, true); 834 } 835 836 return ucl_include_url (data, len, parser, true, true); 837 } 838 839 840 UCL_EXTERN bool 841 ucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 842 { 843 struct ucl_parser *parser = ud; 844 845 if (*data == '/' || *data == '.') { 846 /* Try to load a file */ 847 return ucl_include_file (data, len, parser, false, false); 848 } 849 850 return ucl_include_url (data, len, parser, false, false); 851 } 852 853 UCL_EXTERN bool 854 ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 855 { 856 char realbuf[PATH_MAX], *curdir; 857 858 if (filename != NULL) { 859 if (need_expand) { 860 if (ucl_realpath (filename, realbuf) == NULL) { 861 return false; 862 } 863 } 864 else { 865 ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 866 } 867 868 /* Define variables */ 869 ucl_parser_register_variable (parser, "FILENAME", realbuf); 870 curdir = dirname (realbuf); 871 ucl_parser_register_variable (parser, "CURDIR", curdir); 872 } 873 else { 874 /* Set everything from the current dir */ 875 curdir = getcwd (realbuf, sizeof (realbuf)); 876 ucl_parser_register_variable (parser, "FILENAME", "undef"); 877 ucl_parser_register_variable (parser, "CURDIR", curdir); 878 } 879 880 return true; 881 } 882 883 UCL_EXTERN bool 884 ucl_parser_add_file (struct ucl_parser *parser, const char *filename) 885 { 886 unsigned char *buf; 887 size_t len; 888 bool ret; 889 char realbuf[PATH_MAX]; 890 891 if (ucl_realpath (filename, realbuf) == NULL) { 892 ucl_create_err (&parser->err, "cannot open file %s: %s", 893 filename, 894 strerror (errno)); 895 return false; 896 } 897 898 if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 899 return false; 900 } 901 902 ucl_parser_set_filevars (parser, realbuf, false); 903 ret = ucl_parser_add_chunk (parser, buf, len); 904 905 if (len > 0) { 906 ucl_munmap (buf, len); 907 } 908 909 return ret; 910 } 911 912 size_t 913 ucl_strlcpy (char *dst, const char *src, size_t siz) 914 { 915 char *d = dst; 916 const char *s = src; 917 size_t n = siz; 918 919 /* Copy as many bytes as will fit */ 920 if (n != 0) { 921 while (--n != 0) { 922 if ((*d++ = *s++) == '\0') { 923 break; 924 } 925 } 926 } 927 928 if (n == 0 && siz != 0) { 929 *d = '\0'; 930 } 931 932 return (s - src - 1); /* count does not include NUL */ 933 } 934 935 size_t 936 ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 937 { 938 memcpy (dst, src, siz - 1); 939 dst[siz - 1] = '\0'; 940 941 return siz - 1; 942 } 943 944 size_t 945 ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 946 { 947 char *d = dst; 948 const char *s = src; 949 size_t n = siz; 950 951 /* Copy as many bytes as will fit */ 952 if (n != 0) { 953 while (--n != 0) { 954 if ((*d++ = tolower (*s++)) == '\0') { 955 break; 956 } 957 } 958 } 959 960 if (n == 0 && siz != 0) { 961 *d = '\0'; 962 } 963 964 return (s - src); /* count does not include NUL */ 965 } 966 967 ucl_object_t * 968 ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 969 { 970 ucl_object_t *obj; 971 const char *start, *end, *p, *pos; 972 char *dst, *d; 973 size_t escaped_len; 974 975 if (str == NULL) { 976 return NULL; 977 } 978 979 obj = ucl_object_new (); 980 if (obj) { 981 if (len == 0) { 982 len = strlen (str); 983 } 984 if (flags & UCL_STRING_TRIM) { 985 /* Skip leading spaces */ 986 for (start = str; (size_t)(start - str) < len; start ++) { 987 if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 988 break; 989 } 990 } 991 /* Skip trailing spaces */ 992 for (end = str + len - 1; end > start; end --) { 993 if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 994 break; 995 } 996 } 997 end ++; 998 } 999 else { 1000 start = str; 1001 end = str + len; 1002 } 1003 1004 obj->type = UCL_STRING; 1005 if (flags & UCL_STRING_ESCAPE) { 1006 for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1007 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1008 escaped_len ++; 1009 } 1010 } 1011 dst = malloc (escaped_len + 1); 1012 if (dst != NULL) { 1013 for (p = start, d = dst; p < end; p ++, d ++) { 1014 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1015 switch (*p) { 1016 case '\n': 1017 *d++ = '\\'; 1018 *d = 'n'; 1019 break; 1020 case '\r': 1021 *d++ = '\\'; 1022 *d = 'r'; 1023 break; 1024 case '\b': 1025 *d++ = '\\'; 1026 *d = 'b'; 1027 break; 1028 case '\t': 1029 *d++ = '\\'; 1030 *d = 't'; 1031 break; 1032 case '\f': 1033 *d++ = '\\'; 1034 *d = 'f'; 1035 break; 1036 case '\\': 1037 *d++ = '\\'; 1038 *d = '\\'; 1039 break; 1040 case '"': 1041 *d++ = '\\'; 1042 *d = '"'; 1043 break; 1044 } 1045 } 1046 else { 1047 *d = *p; 1048 } 1049 } 1050 *d = '\0'; 1051 obj->value.sv = dst; 1052 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1053 obj->len = escaped_len; 1054 } 1055 } 1056 else { 1057 dst = malloc (end - start + 1); 1058 if (dst != NULL) { 1059 ucl_strlcpy_unsafe (dst, start, end - start + 1); 1060 obj->value.sv = dst; 1061 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1062 obj->len = end - start; 1063 } 1064 } 1065 if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1066 /* Parse what we have */ 1067 if (flags & UCL_STRING_PARSE_BOOLEAN) { 1068 if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1069 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1070 flags & UCL_STRING_PARSE_DOUBLE, 1071 flags & UCL_STRING_PARSE_BYTES, 1072 flags & UCL_STRING_PARSE_TIME); 1073 } 1074 } 1075 else { 1076 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1077 flags & UCL_STRING_PARSE_DOUBLE, 1078 flags & UCL_STRING_PARSE_BYTES, 1079 flags & UCL_STRING_PARSE_TIME); 1080 } 1081 } 1082 } 1083 1084 return obj; 1085 } 1086 1087 static ucl_object_t * 1088 ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1089 const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1090 { 1091 ucl_object_t *found, *cur; 1092 ucl_object_iter_t it = NULL; 1093 const char *p; 1094 1095 if (elt == NULL || key == NULL) { 1096 return NULL; 1097 } 1098 1099 if (top == NULL) { 1100 top = ucl_object_new (); 1101 top->type = UCL_OBJECT; 1102 } 1103 1104 if (top->type != UCL_OBJECT) { 1105 /* It is possible to convert NULL type to an object */ 1106 if (top->type == UCL_NULL) { 1107 top->type = UCL_OBJECT; 1108 } 1109 else { 1110 /* Refuse converting of other object types */ 1111 return top; 1112 } 1113 } 1114 1115 if (top->value.ov == NULL) { 1116 top->value.ov = ucl_hash_create (); 1117 } 1118 1119 if (keylen == 0) { 1120 keylen = strlen (key); 1121 } 1122 1123 for (p = key; p < key + keylen; p ++) { 1124 if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1125 elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1126 break; 1127 } 1128 } 1129 1130 elt->key = key; 1131 elt->keylen = keylen; 1132 1133 if (copy_key) { 1134 ucl_copy_key_trash (elt); 1135 } 1136 1137 found = ucl_hash_search_obj (top->value.ov, elt); 1138 1139 if (!found) { 1140 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1141 DL_APPEND (found, elt); 1142 top->len ++; 1143 } 1144 else { 1145 if (replace) { 1146 ucl_hash_delete (top->value.ov, found); 1147 ucl_object_unref (found); 1148 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1149 found = NULL; 1150 DL_APPEND (found, elt); 1151 } 1152 else if (merge) { 1153 if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1154 /* Insert old elt to new one */ 1155 elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false); 1156 ucl_hash_delete (top->value.ov, found); 1157 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1158 } 1159 else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1160 /* Insert new to old */ 1161 found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false); 1162 } 1163 else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1164 /* Mix two hashes */ 1165 while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1166 ucl_object_ref (cur); 1167 found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false); 1168 } 1169 ucl_object_unref (elt); 1170 } 1171 else { 1172 /* Just make a list of scalars */ 1173 DL_APPEND (found, elt); 1174 } 1175 } 1176 else { 1177 DL_APPEND (found, elt); 1178 } 1179 } 1180 1181 return top; 1182 } 1183 1184 bool 1185 ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) 1186 { 1187 ucl_object_t *found; 1188 1189 if (top == NULL || key == NULL) { 1190 return false; 1191 } 1192 1193 found = ucl_object_find_keyl(top, key, keylen); 1194 1195 if (found == NULL) { 1196 return false; 1197 } 1198 1199 ucl_hash_delete(top->value.ov, found); 1200 ucl_object_unref (found); 1201 top->len --; 1202 1203 return true; 1204 } 1205 1206 bool 1207 ucl_object_delete_key(ucl_object_t *top, const char *key) 1208 { 1209 return ucl_object_delete_keyl(top, key, 0); 1210 } 1211 1212 ucl_object_t* 1213 ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 1214 { 1215 ucl_object_t *found; 1216 1217 if (top == NULL || key == NULL) { 1218 return false; 1219 } 1220 found = ucl_object_find_keyl(top, key, keylen); 1221 1222 if (found == NULL) { 1223 return NULL; 1224 } 1225 ucl_hash_delete(top->value.ov, found); 1226 top->len --; 1227 1228 return found; 1229 } 1230 1231 ucl_object_t* 1232 ucl_object_pop_key (ucl_object_t *top, const char *key) 1233 { 1234 return ucl_object_pop_keyl (top, key, 0); 1235 } 1236 1237 ucl_object_t * 1238 ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1239 const char *key, size_t keylen, bool copy_key) 1240 { 1241 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1242 } 1243 1244 ucl_object_t * 1245 ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1246 const char *key, size_t keylen, bool copy_key) 1247 { 1248 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1249 } 1250 1251 ucl_object_t * 1252 ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1253 const char *key, size_t keylen, bool copy_key) 1254 { 1255 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1256 } 1257 1258 ucl_object_t * 1259 ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) 1260 { 1261 ucl_object_t *ret, srch; 1262 1263 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1264 return NULL; 1265 } 1266 1267 srch.key = key; 1268 srch.keylen = klen; 1269 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1270 1271 return ret; 1272 } 1273 1274 ucl_object_t * 1275 ucl_object_find_key (ucl_object_t *obj, const char *key) 1276 { 1277 size_t klen; 1278 ucl_object_t *ret, srch; 1279 1280 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1281 return NULL; 1282 } 1283 1284 klen = strlen (key); 1285 srch.key = key; 1286 srch.keylen = klen; 1287 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1288 1289 return ret; 1290 } 1291 1292 ucl_object_t* 1293 ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1294 { 1295 ucl_object_t *elt; 1296 1297 if (obj == NULL || iter == NULL) { 1298 return NULL; 1299 } 1300 1301 if (expand_values) { 1302 switch (obj->type) { 1303 case UCL_OBJECT: 1304 return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1305 break; 1306 case UCL_ARRAY: 1307 elt = *iter; 1308 if (elt == NULL) { 1309 elt = obj->value.av; 1310 if (elt == NULL) { 1311 return NULL; 1312 } 1313 } 1314 else if (elt == obj->value.av) { 1315 return NULL; 1316 } 1317 *iter = elt->next ? elt->next : obj->value.av; 1318 return elt; 1319 default: 1320 /* Go to linear iteration */ 1321 break; 1322 } 1323 } 1324 /* Treat everything as a linear list */ 1325 elt = *iter; 1326 if (elt == NULL) { 1327 elt = obj; 1328 if (elt == NULL) { 1329 return NULL; 1330 } 1331 } 1332 else if (elt == obj) { 1333 return NULL; 1334 } 1335 *iter = elt->next ? elt->next : obj; 1336 return elt; 1337 1338 /* Not reached */ 1339 return NULL; 1340 } 1341 1342 1343 ucl_object_t * 1344 ucl_object_new (void) 1345 { 1346 ucl_object_t *new; 1347 new = malloc (sizeof (ucl_object_t)); 1348 if (new != NULL) { 1349 memset (new, 0, sizeof (ucl_object_t)); 1350 new->ref = 1; 1351 new->type = UCL_NULL; 1352 } 1353 return new; 1354 } 1355 1356 ucl_object_t * 1357 ucl_object_typed_new (unsigned int type) 1358 { 1359 ucl_object_t *new; 1360 new = malloc (sizeof (ucl_object_t)); 1361 if (new != NULL) { 1362 memset (new, 0, sizeof (ucl_object_t)); 1363 new->ref = 1; 1364 new->type = (type <= UCL_NULL ? type : UCL_NULL); 1365 } 1366 return new; 1367 } 1368 1369 ucl_object_t* 1370 ucl_object_fromstring (const char *str) 1371 { 1372 return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 1373 } 1374 1375 ucl_object_t * 1376 ucl_object_fromlstring (const char *str, size_t len) 1377 { 1378 return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 1379 } 1380 1381 ucl_object_t * 1382 ucl_object_fromint (int64_t iv) 1383 { 1384 ucl_object_t *obj; 1385 1386 obj = ucl_object_new (); 1387 if (obj != NULL) { 1388 obj->type = UCL_INT; 1389 obj->value.iv = iv; 1390 } 1391 1392 return obj; 1393 } 1394 1395 ucl_object_t * 1396 ucl_object_fromdouble (double dv) 1397 { 1398 ucl_object_t *obj; 1399 1400 obj = ucl_object_new (); 1401 if (obj != NULL) { 1402 obj->type = UCL_FLOAT; 1403 obj->value.dv = dv; 1404 } 1405 1406 return obj; 1407 } 1408 1409 ucl_object_t* 1410 ucl_object_frombool (bool bv) 1411 { 1412 ucl_object_t *obj; 1413 1414 obj = ucl_object_new (); 1415 if (obj != NULL) { 1416 obj->type = UCL_BOOLEAN; 1417 obj->value.iv = bv; 1418 } 1419 1420 return obj; 1421 } 1422 1423 ucl_object_t * 1424 ucl_array_append (ucl_object_t *top, ucl_object_t *elt) 1425 { 1426 ucl_object_t *head; 1427 1428 if (elt == NULL) { 1429 return NULL; 1430 } 1431 1432 if (top == NULL) { 1433 top = ucl_object_typed_new (UCL_ARRAY); 1434 top->value.av = elt; 1435 elt->next = NULL; 1436 elt->prev = elt; 1437 top->len = 1; 1438 } 1439 else { 1440 head = top->value.av; 1441 if (head == NULL) { 1442 top->value.av = elt; 1443 elt->prev = elt; 1444 } 1445 else { 1446 elt->prev = head->prev; 1447 head->prev->next = elt; 1448 head->prev = elt; 1449 } 1450 elt->next = NULL; 1451 top->len ++; 1452 } 1453 1454 return top; 1455 } 1456 1457 ucl_object_t * 1458 ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 1459 { 1460 ucl_object_t *head; 1461 1462 if (elt == NULL) { 1463 return NULL; 1464 } 1465 1466 if (top == NULL) { 1467 top = ucl_object_typed_new (UCL_ARRAY); 1468 top->value.av = elt; 1469 elt->next = NULL; 1470 elt->prev = elt; 1471 top->len = 1; 1472 } 1473 else { 1474 head = top->value.av; 1475 if (head == NULL) { 1476 top->value.av = elt; 1477 elt->prev = elt; 1478 } 1479 else { 1480 elt->prev = head->prev; 1481 head->prev = elt; 1482 } 1483 elt->next = head; 1484 top->value.av = elt; 1485 top->len ++; 1486 } 1487 1488 return top; 1489 } 1490 1491 ucl_object_t * 1492 ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 1493 { 1494 ucl_object_t *head; 1495 1496 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1497 return NULL; 1498 } 1499 head = top->value.av; 1500 1501 if (elt->prev == elt) { 1502 top->value.av = NULL; 1503 } 1504 else if (elt == head) { 1505 elt->next->prev = elt->prev; 1506 top->value.av = elt->next; 1507 } 1508 else { 1509 elt->prev->next = elt->next; 1510 if (elt->next) { 1511 elt->next->prev = elt->prev; 1512 } 1513 else { 1514 head->prev = elt->prev; 1515 } 1516 } 1517 elt->next = NULL; 1518 elt->prev = elt; 1519 top->len --; 1520 1521 return elt; 1522 } 1523 1524 ucl_object_t * 1525 ucl_array_head (ucl_object_t *top) 1526 { 1527 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1528 return NULL; 1529 } 1530 return top->value.av; 1531 } 1532 1533 ucl_object_t * 1534 ucl_array_tail (ucl_object_t *top) 1535 { 1536 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1537 return NULL; 1538 } 1539 return top->value.av->prev; 1540 } 1541 1542 ucl_object_t * 1543 ucl_array_pop_last (ucl_object_t *top) 1544 { 1545 return ucl_array_delete (top, ucl_array_tail (top)); 1546 } 1547 1548 ucl_object_t * 1549 ucl_array_pop_first (ucl_object_t *top) 1550 { 1551 return ucl_array_delete (top, ucl_array_head (top)); 1552 } 1553 1554 ucl_object_t * 1555 ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 1556 { 1557 1558 if (head == NULL) { 1559 elt->next = NULL; 1560 elt->prev = elt; 1561 head = elt; 1562 } 1563 else { 1564 elt->prev = head->prev; 1565 head->prev->next = elt; 1566 head->prev = elt; 1567 elt->next = NULL; 1568 } 1569 1570 return head; 1571 } 1572 1573 bool 1574 ucl_object_todouble_safe (ucl_object_t *obj, double *target) 1575 { 1576 if (obj == NULL || target == NULL) { 1577 return false; 1578 } 1579 switch (obj->type) { 1580 case UCL_INT: 1581 *target = obj->value.iv; /* Probaly could cause overflow */ 1582 break; 1583 case UCL_FLOAT: 1584 case UCL_TIME: 1585 *target = obj->value.dv; 1586 break; 1587 default: 1588 return false; 1589 } 1590 1591 return true; 1592 } 1593 1594 double 1595 ucl_object_todouble (ucl_object_t *obj) 1596 { 1597 double result = 0.; 1598 1599 ucl_object_todouble_safe (obj, &result); 1600 return result; 1601 } 1602 1603 bool 1604 ucl_object_toint_safe (ucl_object_t *obj, int64_t *target) 1605 { 1606 if (obj == NULL || target == NULL) { 1607 return false; 1608 } 1609 switch (obj->type) { 1610 case UCL_INT: 1611 *target = obj->value.iv; 1612 break; 1613 case UCL_FLOAT: 1614 case UCL_TIME: 1615 *target = obj->value.dv; /* Loosing of decimal points */ 1616 break; 1617 default: 1618 return false; 1619 } 1620 1621 return true; 1622 } 1623 1624 int64_t 1625 ucl_object_toint (ucl_object_t *obj) 1626 { 1627 int64_t result = 0; 1628 1629 ucl_object_toint_safe (obj, &result); 1630 return result; 1631 } 1632 1633 bool 1634 ucl_object_toboolean_safe (ucl_object_t *obj, bool *target) 1635 { 1636 if (obj == NULL || target == NULL) { 1637 return false; 1638 } 1639 switch (obj->type) { 1640 case UCL_BOOLEAN: 1641 *target = (obj->value.iv == true); 1642 break; 1643 default: 1644 return false; 1645 } 1646 1647 return true; 1648 } 1649 1650 bool 1651 ucl_object_toboolean (ucl_object_t *obj) 1652 { 1653 bool result = false; 1654 1655 ucl_object_toboolean_safe (obj, &result); 1656 return result; 1657 } 1658 1659 bool 1660 ucl_object_tostring_safe (ucl_object_t *obj, const char **target) 1661 { 1662 if (obj == NULL || target == NULL) { 1663 return false; 1664 } 1665 1666 switch (obj->type) { 1667 case UCL_STRING: 1668 *target = ucl_copy_value_trash (obj); 1669 break; 1670 default: 1671 return false; 1672 } 1673 1674 return true; 1675 } 1676 1677 const char * 1678 ucl_object_tostring (ucl_object_t *obj) 1679 { 1680 const char *result = NULL; 1681 1682 ucl_object_tostring_safe (obj, &result); 1683 return result; 1684 } 1685 1686 const char * 1687 ucl_object_tostring_forced (ucl_object_t *obj) 1688 { 1689 return ucl_copy_value_trash (obj); 1690 } 1691 1692 bool 1693 ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen) 1694 { 1695 if (obj == NULL || target == NULL) { 1696 return false; 1697 } 1698 switch (obj->type) { 1699 case UCL_STRING: 1700 *target = obj->value.sv; 1701 if (tlen != NULL) { 1702 *tlen = obj->len; 1703 } 1704 break; 1705 default: 1706 return false; 1707 } 1708 1709 return true; 1710 } 1711 1712 const char * 1713 ucl_object_tolstring (ucl_object_t *obj, size_t *tlen) 1714 { 1715 const char *result = NULL; 1716 1717 ucl_object_tolstring_safe (obj, &result, tlen); 1718 return result; 1719 } 1720 1721 const char * 1722 ucl_object_key (ucl_object_t *obj) 1723 { 1724 return ucl_copy_key_trash (obj); 1725 } 1726 1727 const char * 1728 ucl_object_keyl (ucl_object_t *obj, size_t *len) 1729 { 1730 if (len == NULL || obj == NULL) { 1731 return NULL; 1732 } 1733 *len = obj->keylen; 1734 return obj->key; 1735 } 1736 1737 ucl_object_t * 1738 ucl_object_ref (ucl_object_t *obj) 1739 { 1740 if (obj != NULL) { 1741 obj->ref ++; 1742 } 1743 return obj; 1744 } 1745 1746 void 1747 ucl_object_unref (ucl_object_t *obj) 1748 { 1749 if (obj != NULL && --obj->ref <= 0) { 1750 ucl_object_free (obj); 1751 } 1752 } 1753 1754 int 1755 ucl_object_compare (ucl_object_t *o1, ucl_object_t *o2) 1756 { 1757 ucl_object_t *it1, *it2; 1758 ucl_object_iter_t iter = NULL; 1759 int ret = 0; 1760 1761 if (o1->type != o2->type) { 1762 return (o1->type) - (o2->type); 1763 } 1764 1765 switch (o1->type) { 1766 case UCL_STRING: 1767 if (o1->len == o2->len) { 1768 ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 1769 } 1770 else { 1771 ret = o1->len - o2->len; 1772 } 1773 break; 1774 case UCL_FLOAT: 1775 case UCL_INT: 1776 case UCL_TIME: 1777 ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 1778 break; 1779 case UCL_BOOLEAN: 1780 ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 1781 break; 1782 case UCL_ARRAY: 1783 if (o1->len == o2->len) { 1784 it1 = o1->value.av; 1785 it2 = o2->value.av; 1786 /* Compare all elements in both arrays */ 1787 while (it1 != NULL && it2 != NULL) { 1788 ret = ucl_object_compare (it1, it2); 1789 if (ret != 0) { 1790 break; 1791 } 1792 it1 = it1->next; 1793 it2 = it2->next; 1794 } 1795 } 1796 else { 1797 ret = o1->len - o2->len; 1798 } 1799 break; 1800 case UCL_OBJECT: 1801 if (o1->len == o2->len) { 1802 while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 1803 it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 1804 if (it2 == NULL) { 1805 ret = 1; 1806 break; 1807 } 1808 ret = ucl_object_compare (it1, it2); 1809 if (ret != 0) { 1810 break; 1811 } 1812 } 1813 } 1814 else { 1815 ret = o1->len - o2->len; 1816 } 1817 break; 1818 default: 1819 ret = 0; 1820 break; 1821 } 1822 1823 return ret; 1824 } 1825 1826 void 1827 ucl_object_array_sort (ucl_object_t *ar, 1828 int (*cmp)(ucl_object_t *o1, ucl_object_t *o2)) 1829 { 1830 if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 1831 return; 1832 } 1833 1834 DL_SORT (ar->value.av, cmp); 1835 } 1836