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 #include <glob.h> 29 30 #ifdef HAVE_LIBGEN_H 31 #include <libgen.h> /* For dirname */ 32 #endif 33 34 #ifdef HAVE_OPENSSL 35 #include <openssl/err.h> 36 #include <openssl/sha.h> 37 #include <openssl/rsa.h> 38 #include <openssl/ssl.h> 39 #include <openssl/evp.h> 40 #endif 41 42 #ifdef CURL_FOUND 43 #include <curl/curl.h> 44 #endif 45 #ifdef HAVE_FETCH_H 46 #include <fetch.h> 47 #endif 48 49 #ifdef _WIN32 50 #include <windows.h> 51 52 #ifndef PROT_READ 53 #define PROT_READ 1 54 #endif 55 #ifndef PROT_WRITE 56 #define PROT_WRITE 2 57 #endif 58 #ifndef PROT_READWRITE 59 #define PROT_READWRITE 3 60 #endif 61 #ifndef MAP_SHARED 62 #define MAP_SHARED 1 63 #endif 64 #ifndef MAP_PRIVATE 65 #define MAP_PRIVATE 2 66 #endif 67 #ifndef MAP_FAILED 68 #define MAP_FAILED ((void *) -1) 69 #endif 70 71 static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 72 { 73 void *map = NULL; 74 HANDLE handle = INVALID_HANDLE_VALUE; 75 76 switch (prot) { 77 default: 78 case PROT_READ: 79 { 80 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 81 if (!handle) break; 82 map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 83 CloseHandle(handle); 84 break; 85 } 86 case PROT_WRITE: 87 { 88 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 89 if (!handle) break; 90 map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 91 CloseHandle(handle); 92 break; 93 } 94 case PROT_READWRITE: 95 { 96 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 97 if (!handle) break; 98 map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 99 CloseHandle(handle); 100 break; 101 } 102 } 103 if (map == (void *) NULL) { 104 return (void *) MAP_FAILED; 105 } 106 return (void *) ((char *) map + offset); 107 } 108 109 static int ucl_munmap(void *map,size_t length) 110 { 111 if (!UnmapViewOfFile(map)) { 112 return(-1); 113 } 114 return(0); 115 } 116 117 static char* ucl_realpath(const char *path, char *resolved_path) { 118 char *p; 119 char tmp[MAX_PATH + 1]; 120 strncpy(tmp, path, sizeof(tmp)-1); 121 p = tmp; 122 while(*p) { 123 if (*p == '/') *p = '\\'; 124 p++; 125 } 126 return _fullpath(resolved_path, tmp, MAX_PATH); 127 } 128 #else 129 #define ucl_mmap mmap 130 #define ucl_munmap munmap 131 #define ucl_realpath realpath 132 #endif 133 134 typedef void (*ucl_object_dtor) (ucl_object_t *obj); 135 static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 136 ucl_object_dtor dtor); 137 static void ucl_object_dtor_unref (ucl_object_t *obj); 138 139 static void 140 ucl_object_dtor_free (ucl_object_t *obj) 141 { 142 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 143 UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 144 } 145 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 146 UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 147 } 148 /* Do not free ephemeral objects */ 149 if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) { 150 if (obj->type != UCL_USERDATA) { 151 UCL_FREE (sizeof (ucl_object_t), obj); 152 } 153 else { 154 struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj; 155 if (ud->dtor) { 156 ud->dtor (obj->value.ud); 157 } 158 UCL_FREE (sizeof (*ud), obj); 159 } 160 } 161 } 162 163 /* 164 * This is a helper function that performs exactly the same as 165 * `ucl_object_unref` but it doesn't iterate over elements allowing 166 * to use it for individual elements of arrays and multiple values 167 */ 168 static void 169 ucl_object_dtor_unref_single (ucl_object_t *obj) 170 { 171 if (obj != NULL) { 172 #ifdef HAVE_ATOMIC_BUILTINS 173 unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 174 if (rc == 0) { 175 #else 176 if (--obj->ref == 0) { 177 #endif 178 ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 179 } 180 } 181 } 182 183 static void 184 ucl_object_dtor_unref (ucl_object_t *obj) 185 { 186 if (obj->ref == 0) { 187 ucl_object_dtor_free (obj); 188 } 189 else { 190 /* This may cause dtor unref being called one more time */ 191 ucl_object_dtor_unref_single (obj); 192 } 193 } 194 195 static void 196 ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 197 { 198 ucl_object_t *sub, *tmp; 199 200 while (obj != NULL) { 201 if (obj->type == UCL_ARRAY) { 202 sub = obj->value.av; 203 while (sub != NULL) { 204 tmp = sub->next; 205 dtor (sub); 206 sub = tmp; 207 } 208 } 209 else if (obj->type == UCL_OBJECT) { 210 if (obj->value.ov != NULL) { 211 ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); 212 } 213 } 214 tmp = obj->next; 215 dtor (obj); 216 obj = tmp; 217 218 if (!allow_rec) { 219 break; 220 } 221 } 222 } 223 224 void 225 ucl_object_free (ucl_object_t *obj) 226 { 227 ucl_object_free_internal (obj, true, ucl_object_dtor_free); 228 } 229 230 size_t 231 ucl_unescape_json_string (char *str, size_t len) 232 { 233 char *t = str, *h = str; 234 int i, uval; 235 236 if (len <= 1) { 237 return len; 238 } 239 /* t is target (tortoise), h is source (hare) */ 240 241 while (len) { 242 if (*h == '\\') { 243 h ++; 244 switch (*h) { 245 case 'n': 246 *t++ = '\n'; 247 break; 248 case 'r': 249 *t++ = '\r'; 250 break; 251 case 'b': 252 *t++ = '\b'; 253 break; 254 case 't': 255 *t++ = '\t'; 256 break; 257 case 'f': 258 *t++ = '\f'; 259 break; 260 case '\\': 261 *t++ = '\\'; 262 break; 263 case '"': 264 *t++ = '"'; 265 break; 266 case 'u': 267 /* Unicode escape */ 268 uval = 0; 269 if (len > 3) { 270 for (i = 0; i < 4; i++) { 271 uval <<= 4; 272 if (isdigit (h[i])) { 273 uval += h[i] - '0'; 274 } 275 else if (h[i] >= 'a' && h[i] <= 'f') { 276 uval += h[i] - 'a' + 10; 277 } 278 else if (h[i] >= 'A' && h[i] <= 'F') { 279 uval += h[i] - 'A' + 10; 280 } 281 else { 282 break; 283 } 284 } 285 h += 3; 286 len -= 3; 287 /* Encode */ 288 if(uval < 0x80) { 289 t[0] = (char)uval; 290 t ++; 291 } 292 else if(uval < 0x800) { 293 t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 294 t[1] = 0x80 + ((uval & 0x03F)); 295 t += 2; 296 } 297 else if(uval < 0x10000) { 298 t[0] = 0xE0 + ((uval & 0xF000) >> 12); 299 t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 300 t[2] = 0x80 + ((uval & 0x003F)); 301 t += 3; 302 } 303 else if(uval <= 0x10FFFF) { 304 t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 305 t[1] = 0x80 + ((uval & 0x03F000) >> 12); 306 t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 307 t[3] = 0x80 + ((uval & 0x00003F)); 308 t += 4; 309 } 310 else { 311 *t++ = '?'; 312 } 313 } 314 else { 315 *t++ = 'u'; 316 } 317 break; 318 default: 319 *t++ = *h; 320 break; 321 } 322 h ++; 323 len --; 324 } 325 else { 326 *t++ = *h++; 327 } 328 len --; 329 } 330 *t = '\0'; 331 332 return (t - str); 333 } 334 335 char * 336 ucl_copy_key_trash (const ucl_object_t *obj) 337 { 338 ucl_object_t *deconst; 339 340 if (obj == NULL) { 341 return NULL; 342 } 343 if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 344 deconst = __DECONST (ucl_object_t *, obj); 345 deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 346 if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 347 memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 348 deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 349 } 350 deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 351 deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 352 } 353 354 return obj->trash_stack[UCL_TRASH_KEY]; 355 } 356 357 char * 358 ucl_copy_value_trash (const ucl_object_t *obj) 359 { 360 ucl_object_t *deconst; 361 362 if (obj == NULL) { 363 return NULL; 364 } 365 if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 366 deconst = __DECONST (ucl_object_t *, obj); 367 if (obj->type == UCL_STRING) { 368 369 /* Special case for strings */ 370 deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 371 if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 372 memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 373 deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 374 deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 375 } 376 } 377 else { 378 /* Just emit value in json notation */ 379 deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 380 deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 381 } 382 deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 383 } 384 return obj->trash_stack[UCL_TRASH_VALUE]; 385 } 386 387 UCL_EXTERN ucl_object_t* 388 ucl_parser_get_object (struct ucl_parser *parser) 389 { 390 if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 391 return ucl_object_ref (parser->top_obj); 392 } 393 394 return NULL; 395 } 396 397 UCL_EXTERN void 398 ucl_parser_free (struct ucl_parser *parser) 399 { 400 struct ucl_stack *stack, *stmp; 401 struct ucl_macro *macro, *mtmp; 402 struct ucl_chunk *chunk, *ctmp; 403 struct ucl_pubkey *key, *ktmp; 404 struct ucl_variable *var, *vtmp; 405 406 if (parser == NULL) { 407 return; 408 } 409 410 if (parser->top_obj != NULL) { 411 ucl_object_unref (parser->top_obj); 412 } 413 414 LL_FOREACH_SAFE (parser->stack, stack, stmp) { 415 free (stack); 416 } 417 HASH_ITER (hh, parser->macroes, macro, mtmp) { 418 free (macro->name); 419 HASH_DEL (parser->macroes, macro); 420 UCL_FREE (sizeof (struct ucl_macro), macro); 421 } 422 LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 423 UCL_FREE (sizeof (struct ucl_chunk), chunk); 424 } 425 LL_FOREACH_SAFE (parser->keys, key, ktmp) { 426 UCL_FREE (sizeof (struct ucl_pubkey), key); 427 } 428 LL_FOREACH_SAFE (parser->variables, var, vtmp) { 429 free (var->value); 430 free (var->var); 431 UCL_FREE (sizeof (struct ucl_variable), var); 432 } 433 434 if (parser->err != NULL) { 435 utstring_free (parser->err); 436 } 437 438 if (parser->cur_file) { 439 free (parser->cur_file); 440 } 441 442 UCL_FREE (sizeof (struct ucl_parser), parser); 443 } 444 445 UCL_EXTERN const char * 446 ucl_parser_get_error(struct ucl_parser *parser) 447 { 448 if (parser == NULL) { 449 return NULL; 450 } 451 452 if (parser->err == NULL) 453 return NULL; 454 455 return utstring_body(parser->err); 456 } 457 458 UCL_EXTERN bool 459 ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 460 { 461 #ifndef HAVE_OPENSSL 462 ucl_create_err (&parser->err, "cannot check signatures without openssl"); 463 return false; 464 #else 465 # if (OPENSSL_VERSION_NUMBER < 0x10000000L) 466 ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 467 return EXIT_FAILURE; 468 # else 469 struct ucl_pubkey *nkey; 470 BIO *mem; 471 472 mem = BIO_new_mem_buf ((void *)key, len); 473 nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 474 if (nkey == NULL) { 475 ucl_create_err (&parser->err, "cannot allocate memory for key"); 476 return false; 477 } 478 nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 479 BIO_free (mem); 480 if (nkey->key == NULL) { 481 UCL_FREE (sizeof (struct ucl_pubkey), nkey); 482 ucl_create_err (&parser->err, "%s", 483 ERR_error_string (ERR_get_error (), NULL)); 484 return false; 485 } 486 LL_PREPEND (parser->keys, nkey); 487 # endif 488 #endif 489 return true; 490 } 491 492 #ifdef CURL_FOUND 493 struct ucl_curl_cbdata { 494 unsigned char *buf; 495 size_t buflen; 496 }; 497 498 static size_t 499 ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 500 { 501 struct ucl_curl_cbdata *cbdata = ud; 502 size_t realsize = size * nmemb; 503 504 cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 505 if (cbdata->buf == NULL) { 506 return 0; 507 } 508 509 memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 510 cbdata->buflen += realsize; 511 cbdata->buf[cbdata->buflen] = 0; 512 513 return realsize; 514 } 515 #endif 516 517 /** 518 * Fetch a url and save results to the memory buffer 519 * @param url url to fetch 520 * @param len length of url 521 * @param buf target buffer 522 * @param buflen target length 523 * @return 524 */ 525 static bool 526 ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 527 UT_string **err, bool must_exist) 528 { 529 530 #ifdef HAVE_FETCH_H 531 struct url *fetch_url; 532 struct url_stat us; 533 FILE *in; 534 535 fetch_url = fetchParseURL (url); 536 if (fetch_url == NULL) { 537 ucl_create_err (err, "invalid URL %s: %s", 538 url, strerror (errno)); 539 return false; 540 } 541 if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 542 if (!must_exist) { 543 ucl_create_err (err, "cannot fetch URL %s: %s", 544 url, strerror (errno)); 545 } 546 fetchFreeURL (fetch_url); 547 return false; 548 } 549 550 *buflen = us.size; 551 *buf = malloc (*buflen); 552 if (*buf == NULL) { 553 ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 554 url, strerror (errno)); 555 fclose (in); 556 fetchFreeURL (fetch_url); 557 return false; 558 } 559 560 if (fread (*buf, *buflen, 1, in) != 1) { 561 ucl_create_err (err, "cannot read URL %s: %s", 562 url, strerror (errno)); 563 fclose (in); 564 fetchFreeURL (fetch_url); 565 return false; 566 } 567 568 fetchFreeURL (fetch_url); 569 return true; 570 #elif defined(CURL_FOUND) 571 CURL *curl; 572 int r; 573 struct ucl_curl_cbdata cbdata; 574 575 curl = curl_easy_init (); 576 if (curl == NULL) { 577 ucl_create_err (err, "CURL interface is broken"); 578 return false; 579 } 580 if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 581 ucl_create_err (err, "invalid URL %s: %s", 582 url, curl_easy_strerror (r)); 583 curl_easy_cleanup (curl); 584 return false; 585 } 586 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 587 cbdata.buf = *buf; 588 cbdata.buflen = *buflen; 589 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 590 591 if ((r = curl_easy_perform (curl)) != CURLE_OK) { 592 if (!must_exist) { 593 ucl_create_err (err, "error fetching URL %s: %s", 594 url, curl_easy_strerror (r)); 595 } 596 curl_easy_cleanup (curl); 597 if (cbdata.buf) { 598 free (cbdata.buf); 599 } 600 return false; 601 } 602 *buf = cbdata.buf; 603 *buflen = cbdata.buflen; 604 605 return true; 606 #else 607 ucl_create_err (err, "URL support is disabled"); 608 return false; 609 #endif 610 } 611 612 /** 613 * Fetch a file and save results to the memory buffer 614 * @param filename filename to fetch 615 * @param len length of filename 616 * @param buf target buffer 617 * @param buflen target length 618 * @return 619 */ 620 static bool 621 ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 622 UT_string **err, bool must_exist) 623 { 624 int fd; 625 struct stat st; 626 627 if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 628 if (must_exist) { 629 ucl_create_err (err, "cannot stat file %s: %s", 630 filename, strerror (errno)); 631 } 632 return false; 633 } 634 if (st.st_size == 0) { 635 /* Do not map empty files */ 636 *buf = ""; 637 *buflen = 0; 638 } 639 else { 640 if ((fd = open (filename, O_RDONLY)) == -1) { 641 ucl_create_err (err, "cannot open file %s: %s", 642 filename, strerror (errno)); 643 return false; 644 } 645 if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 646 close (fd); 647 ucl_create_err (err, "cannot mmap file %s: %s", 648 filename, strerror (errno)); 649 return false; 650 } 651 *buflen = st.st_size; 652 close (fd); 653 } 654 655 return true; 656 } 657 658 659 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 660 static inline bool 661 ucl_sig_check (const unsigned char *data, size_t datalen, 662 const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 663 { 664 struct ucl_pubkey *key; 665 char dig[EVP_MAX_MD_SIZE]; 666 unsigned int diglen; 667 EVP_PKEY_CTX *key_ctx; 668 EVP_MD_CTX *sign_ctx = NULL; 669 670 sign_ctx = EVP_MD_CTX_create (); 671 672 LL_FOREACH (parser->keys, key) { 673 key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 674 if (key_ctx != NULL) { 675 if (EVP_PKEY_verify_init (key_ctx) <= 0) { 676 EVP_PKEY_CTX_free (key_ctx); 677 continue; 678 } 679 if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 680 EVP_PKEY_CTX_free (key_ctx); 681 continue; 682 } 683 if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 684 EVP_PKEY_CTX_free (key_ctx); 685 continue; 686 } 687 EVP_DigestInit (sign_ctx, EVP_sha256 ()); 688 EVP_DigestUpdate (sign_ctx, data, datalen); 689 EVP_DigestFinal (sign_ctx, dig, &diglen); 690 691 if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 692 EVP_MD_CTX_destroy (sign_ctx); 693 EVP_PKEY_CTX_free (key_ctx); 694 return true; 695 } 696 697 EVP_PKEY_CTX_free (key_ctx); 698 } 699 } 700 701 EVP_MD_CTX_destroy (sign_ctx); 702 703 return false; 704 } 705 #endif 706 707 /** 708 * Include an url to configuration 709 * @param data 710 * @param len 711 * @param parser 712 * @param err 713 * @return 714 */ 715 static bool 716 ucl_include_url (const unsigned char *data, size_t len, 717 struct ucl_parser *parser, bool check_signature, bool must_exist, 718 unsigned priority) 719 { 720 721 bool res; 722 unsigned char *buf = NULL; 723 size_t buflen = 0; 724 struct ucl_chunk *chunk; 725 char urlbuf[PATH_MAX]; 726 int prev_state; 727 728 snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 729 730 if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 731 return (!must_exist || false); 732 } 733 734 if (check_signature) { 735 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 736 unsigned char *sigbuf = NULL; 737 size_t siglen = 0; 738 /* We need to check signature first */ 739 snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 740 if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 741 return false; 742 } 743 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 744 ucl_create_err (&parser->err, "cannot verify url %s: %s", 745 urlbuf, 746 ERR_error_string (ERR_get_error (), NULL)); 747 if (siglen > 0) { 748 ucl_munmap (sigbuf, siglen); 749 } 750 return false; 751 } 752 if (siglen > 0) { 753 ucl_munmap (sigbuf, siglen); 754 } 755 #endif 756 } 757 758 prev_state = parser->state; 759 parser->state = UCL_STATE_INIT; 760 761 res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority); 762 if (res == true) { 763 /* Remove chunk from the stack */ 764 chunk = parser->chunks; 765 if (chunk != NULL) { 766 parser->chunks = chunk->next; 767 UCL_FREE (sizeof (struct ucl_chunk), chunk); 768 } 769 } 770 771 parser->state = prev_state; 772 free (buf); 773 774 return res; 775 } 776 777 /** 778 * Include a single file to the parser 779 * @param data 780 * @param len 781 * @param parser 782 * @param check_signature 783 * @param must_exist 784 * @param allow_glob 785 * @param priority 786 * @return 787 */ 788 static bool 789 ucl_include_file_single (const unsigned char *data, size_t len, 790 struct ucl_parser *parser, bool check_signature, bool must_exist, 791 unsigned priority) 792 { 793 bool res; 794 struct ucl_chunk *chunk; 795 unsigned char *buf = NULL; 796 char *old_curfile; 797 size_t buflen; 798 char filebuf[PATH_MAX], realbuf[PATH_MAX]; 799 int prev_state; 800 struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL, 801 *old_filename = NULL; 802 803 snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 804 if (ucl_realpath (filebuf, realbuf) == NULL) { 805 if (!must_exist) { 806 return true; 807 } 808 ucl_create_err (&parser->err, "cannot open file %s: %s", 809 filebuf, 810 strerror (errno)); 811 return false; 812 } 813 814 if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) { 815 /* We are likely including the file itself */ 816 ucl_create_err (&parser->err, "trying to include the file %s from itself", 817 realbuf); 818 return false; 819 } 820 821 if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 822 return (!must_exist || false); 823 } 824 825 if (check_signature) { 826 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 827 unsigned char *sigbuf = NULL; 828 size_t siglen = 0; 829 /* We need to check signature first */ 830 snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 831 if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 832 return false; 833 } 834 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 835 ucl_create_err (&parser->err, "cannot verify file %s: %s", 836 filebuf, 837 ERR_error_string (ERR_get_error (), NULL)); 838 if (siglen > 0) { 839 ucl_munmap (sigbuf, siglen); 840 } 841 return false; 842 } 843 if (siglen > 0) { 844 ucl_munmap (sigbuf, siglen); 845 } 846 #endif 847 } 848 849 old_curfile = parser->cur_file; 850 parser->cur_file = strdup (realbuf); 851 852 /* Store old file vars */ 853 DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 854 if (strcmp (cur_var->var, "CURDIR") == 0) { 855 old_curdir = cur_var; 856 DL_DELETE (parser->variables, cur_var); 857 } 858 else if (strcmp (cur_var->var, "FILENAME") == 0) { 859 old_filename = cur_var; 860 DL_DELETE (parser->variables, cur_var); 861 } 862 } 863 864 ucl_parser_set_filevars (parser, realbuf, false); 865 866 prev_state = parser->state; 867 parser->state = UCL_STATE_INIT; 868 869 res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority); 870 if (!res && !must_exist) { 871 /* Free error */ 872 utstring_free (parser->err); 873 parser->err = NULL; 874 parser->state = UCL_STATE_AFTER_VALUE; 875 } 876 877 /* Remove chunk from the stack */ 878 chunk = parser->chunks; 879 if (chunk != NULL) { 880 parser->chunks = chunk->next; 881 UCL_FREE (sizeof (struct ucl_chunk), chunk); 882 parser->recursion --; 883 } 884 885 /* Restore old file vars */ 886 parser->cur_file = old_curfile; 887 DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) { 888 if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) { 889 DL_DELETE (parser->variables, cur_var); 890 free (cur_var->var); 891 free (cur_var->value); 892 UCL_FREE (sizeof (struct ucl_variable), cur_var); 893 } 894 else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) { 895 DL_DELETE (parser->variables, cur_var); 896 free (cur_var->var); 897 free (cur_var->value); 898 UCL_FREE (sizeof (struct ucl_variable), cur_var); 899 } 900 } 901 if (old_filename) { 902 DL_APPEND (parser->variables, old_filename); 903 } 904 if (old_curdir) { 905 DL_APPEND (parser->variables, old_curdir); 906 } 907 if (old_curfile) { 908 free (old_curfile); 909 } 910 911 parser->state = prev_state; 912 913 if (buflen > 0) { 914 ucl_munmap (buf, buflen); 915 } 916 917 return res; 918 } 919 920 /** 921 * Include a file to configuration 922 * @param data 923 * @param len 924 * @param parser 925 * @param err 926 * @return 927 */ 928 static bool 929 ucl_include_file (const unsigned char *data, size_t len, 930 struct ucl_parser *parser, bool check_signature, bool must_exist, 931 bool allow_glob, unsigned priority) 932 { 933 const unsigned char *p = data, *end = data + len; 934 bool need_glob = false; 935 int cnt = 0; 936 glob_t globbuf; 937 char glob_pattern[PATH_MAX]; 938 size_t i; 939 940 if (!allow_glob) { 941 return ucl_include_file_single (data, len, parser, check_signature, 942 must_exist, priority); 943 } 944 else { 945 /* Check for special symbols in a filename */ 946 while (p != end) { 947 if (*p == '*' || *p == '?') { 948 need_glob = true; 949 break; 950 } 951 p ++; 952 } 953 if (need_glob) { 954 memset (&globbuf, 0, sizeof (globbuf)); 955 ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern)); 956 if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { 957 return (!must_exist || false); 958 } 959 for (i = 0; i < globbuf.gl_pathc; i ++) { 960 if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i], 961 strlen (globbuf.gl_pathv[i]), parser, check_signature, 962 must_exist, priority)) { 963 globfree (&globbuf); 964 return false; 965 } 966 cnt ++; 967 } 968 globfree (&globbuf); 969 970 if (cnt == 0 && must_exist) { 971 ucl_create_err (&parser->err, "cannot match any files for pattern %s", 972 glob_pattern); 973 return false; 974 } 975 } 976 else { 977 return ucl_include_file_single (data, len, parser, check_signature, 978 must_exist, priority); 979 } 980 } 981 982 return true; 983 } 984 985 /** 986 * Common function to handle .*include* macros 987 * @param data 988 * @param len 989 * @param args 990 * @param parser 991 * @param default_try 992 * @param default_sign 993 * @return 994 */ 995 static bool 996 ucl_include_common (const unsigned char *data, size_t len, 997 const ucl_object_t *args, struct ucl_parser *parser, 998 bool default_try, 999 bool default_sign) 1000 { 1001 bool try_load, allow_glob, allow_url, need_sign; 1002 unsigned priority; 1003 const ucl_object_t *param; 1004 ucl_object_iter_t it = NULL; 1005 1006 /* Default values */ 1007 try_load = default_try; 1008 allow_glob = false; 1009 allow_url = true; 1010 need_sign = default_sign; 1011 priority = 0; 1012 1013 /* Process arguments */ 1014 if (args != NULL && args->type == UCL_OBJECT) { 1015 while ((param = ucl_iterate_object (args, &it, true)) != NULL) { 1016 if (param->type == UCL_BOOLEAN) { 1017 if (strcmp (param->key, "try") == 0) { 1018 try_load = ucl_object_toboolean (param); 1019 } 1020 else if (strcmp (param->key, "sign") == 0) { 1021 need_sign = ucl_object_toboolean (param); 1022 } 1023 else if (strcmp (param->key, "glob") == 0) { 1024 allow_glob = ucl_object_toboolean (param); 1025 } 1026 else if (strcmp (param->key, "url") == 0) { 1027 allow_url = ucl_object_toboolean (param); 1028 } 1029 } 1030 else if (param->type == UCL_INT) { 1031 if (strcmp (param->key, "priority") == 0) { 1032 priority = ucl_object_toint (param); 1033 } 1034 } 1035 } 1036 } 1037 1038 if (*data == '/' || *data == '.') { 1039 /* Try to load a file */ 1040 return ucl_include_file (data, len, parser, need_sign, !try_load, 1041 allow_glob, priority); 1042 } 1043 else if (allow_url) { 1044 /* Globbing is not used for URL's */ 1045 return ucl_include_url (data, len, parser, need_sign, !try_load, 1046 priority); 1047 } 1048 1049 return false; 1050 } 1051 1052 /** 1053 * Handle include macro 1054 * @param data include data 1055 * @param len length of data 1056 * @param ud user data 1057 * @param err error ptr 1058 * @return 1059 */ 1060 UCL_EXTERN bool 1061 ucl_include_handler (const unsigned char *data, size_t len, 1062 const ucl_object_t *args, void* ud) 1063 { 1064 struct ucl_parser *parser = ud; 1065 1066 return ucl_include_common (data, len, args, parser, false, false); 1067 } 1068 1069 /** 1070 * Handle includes macro 1071 * @param data include data 1072 * @param len length of data 1073 * @param ud user data 1074 * @param err error ptr 1075 * @return 1076 */ 1077 UCL_EXTERN bool 1078 ucl_includes_handler (const unsigned char *data, size_t len, 1079 const ucl_object_t *args, void* ud) 1080 { 1081 struct ucl_parser *parser = ud; 1082 1083 return ucl_include_common (data, len, args, parser, false, true); 1084 } 1085 1086 1087 UCL_EXTERN bool 1088 ucl_try_include_handler (const unsigned char *data, size_t len, 1089 const ucl_object_t *args, void* ud) 1090 { 1091 struct ucl_parser *parser = ud; 1092 1093 return ucl_include_common (data, len, args, parser, true, false); 1094 } 1095 1096 UCL_EXTERN bool 1097 ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 1098 { 1099 char realbuf[PATH_MAX], *curdir; 1100 1101 if (filename != NULL) { 1102 if (need_expand) { 1103 if (ucl_realpath (filename, realbuf) == NULL) { 1104 return false; 1105 } 1106 } 1107 else { 1108 ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 1109 } 1110 1111 /* Define variables */ 1112 ucl_parser_register_variable (parser, "FILENAME", realbuf); 1113 curdir = dirname (realbuf); 1114 ucl_parser_register_variable (parser, "CURDIR", curdir); 1115 } 1116 else { 1117 /* Set everything from the current dir */ 1118 curdir = getcwd (realbuf, sizeof (realbuf)); 1119 ucl_parser_register_variable (parser, "FILENAME", "undef"); 1120 ucl_parser_register_variable (parser, "CURDIR", curdir); 1121 } 1122 1123 return true; 1124 } 1125 1126 UCL_EXTERN bool 1127 ucl_parser_add_file (struct ucl_parser *parser, const char *filename) 1128 { 1129 unsigned char *buf; 1130 size_t len; 1131 bool ret; 1132 char realbuf[PATH_MAX]; 1133 1134 if (ucl_realpath (filename, realbuf) == NULL) { 1135 ucl_create_err (&parser->err, "cannot open file %s: %s", 1136 filename, 1137 strerror (errno)); 1138 return false; 1139 } 1140 1141 if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 1142 return false; 1143 } 1144 1145 if (parser->cur_file) { 1146 free (parser->cur_file); 1147 } 1148 parser->cur_file = strdup (realbuf); 1149 ucl_parser_set_filevars (parser, realbuf, false); 1150 ret = ucl_parser_add_chunk (parser, buf, len); 1151 1152 if (len > 0) { 1153 ucl_munmap (buf, len); 1154 } 1155 1156 return ret; 1157 } 1158 1159 UCL_EXTERN bool 1160 ucl_parser_add_fd (struct ucl_parser *parser, int fd) 1161 { 1162 unsigned char *buf; 1163 size_t len; 1164 bool ret; 1165 struct stat st; 1166 1167 if (fstat (fd, &st) == -1) { 1168 ucl_create_err (&parser->err, "cannot stat fd %d: %s", 1169 fd, strerror (errno)); 1170 return false; 1171 } 1172 if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 1173 ucl_create_err (&parser->err, "cannot mmap fd %d: %s", 1174 fd, strerror (errno)); 1175 return false; 1176 } 1177 1178 if (parser->cur_file) { 1179 free (parser->cur_file); 1180 } 1181 parser->cur_file = NULL; 1182 len = st.st_size; 1183 ret = ucl_parser_add_chunk (parser, buf, len); 1184 1185 if (len > 0) { 1186 ucl_munmap (buf, len); 1187 } 1188 1189 return ret; 1190 } 1191 1192 size_t 1193 ucl_strlcpy (char *dst, const char *src, size_t siz) 1194 { 1195 char *d = dst; 1196 const char *s = src; 1197 size_t n = siz; 1198 1199 /* Copy as many bytes as will fit */ 1200 if (n != 0) { 1201 while (--n != 0) { 1202 if ((*d++ = *s++) == '\0') { 1203 break; 1204 } 1205 } 1206 } 1207 1208 if (n == 0 && siz != 0) { 1209 *d = '\0'; 1210 } 1211 1212 return (s - src - 1); /* count does not include NUL */ 1213 } 1214 1215 size_t 1216 ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 1217 { 1218 memcpy (dst, src, siz - 1); 1219 dst[siz - 1] = '\0'; 1220 1221 return siz - 1; 1222 } 1223 1224 size_t 1225 ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 1226 { 1227 char *d = dst; 1228 const char *s = src; 1229 size_t n = siz; 1230 1231 /* Copy as many bytes as will fit */ 1232 if (n != 0) { 1233 while (--n != 0) { 1234 if ((*d++ = tolower (*s++)) == '\0') { 1235 break; 1236 } 1237 } 1238 } 1239 1240 if (n == 0 && siz != 0) { 1241 *d = '\0'; 1242 } 1243 1244 return (s - src); /* count does not include NUL */ 1245 } 1246 1247 ucl_object_t * 1248 ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1249 { 1250 ucl_object_t *obj; 1251 const char *start, *end, *p, *pos; 1252 char *dst, *d; 1253 size_t escaped_len; 1254 1255 if (str == NULL) { 1256 return NULL; 1257 } 1258 1259 obj = ucl_object_new (); 1260 if (obj) { 1261 if (len == 0) { 1262 len = strlen (str); 1263 } 1264 if (flags & UCL_STRING_TRIM) { 1265 /* Skip leading spaces */ 1266 for (start = str; (size_t)(start - str) < len; start ++) { 1267 if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1268 break; 1269 } 1270 } 1271 /* Skip trailing spaces */ 1272 for (end = str + len - 1; end > start; end --) { 1273 if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1274 break; 1275 } 1276 } 1277 end ++; 1278 } 1279 else { 1280 start = str; 1281 end = str + len; 1282 } 1283 1284 obj->type = UCL_STRING; 1285 if (flags & UCL_STRING_ESCAPE) { 1286 for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1287 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1288 escaped_len ++; 1289 } 1290 } 1291 dst = malloc (escaped_len + 1); 1292 if (dst != NULL) { 1293 for (p = start, d = dst; p < end; p ++, d ++) { 1294 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1295 switch (*p) { 1296 case '\n': 1297 *d++ = '\\'; 1298 *d = 'n'; 1299 break; 1300 case '\r': 1301 *d++ = '\\'; 1302 *d = 'r'; 1303 break; 1304 case '\b': 1305 *d++ = '\\'; 1306 *d = 'b'; 1307 break; 1308 case '\t': 1309 *d++ = '\\'; 1310 *d = 't'; 1311 break; 1312 case '\f': 1313 *d++ = '\\'; 1314 *d = 'f'; 1315 break; 1316 case '\\': 1317 *d++ = '\\'; 1318 *d = '\\'; 1319 break; 1320 case '"': 1321 *d++ = '\\'; 1322 *d = '"'; 1323 break; 1324 } 1325 } 1326 else { 1327 *d = *p; 1328 } 1329 } 1330 *d = '\0'; 1331 obj->value.sv = dst; 1332 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1333 obj->len = escaped_len; 1334 } 1335 } 1336 else { 1337 dst = malloc (end - start + 1); 1338 if (dst != NULL) { 1339 ucl_strlcpy_unsafe (dst, start, end - start + 1); 1340 obj->value.sv = dst; 1341 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1342 obj->len = end - start; 1343 } 1344 } 1345 if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1346 /* Parse what we have */ 1347 if (flags & UCL_STRING_PARSE_BOOLEAN) { 1348 if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1349 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1350 flags & UCL_STRING_PARSE_DOUBLE, 1351 flags & UCL_STRING_PARSE_BYTES, 1352 flags & UCL_STRING_PARSE_TIME); 1353 } 1354 } 1355 else { 1356 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1357 flags & UCL_STRING_PARSE_DOUBLE, 1358 flags & UCL_STRING_PARSE_BYTES, 1359 flags & UCL_STRING_PARSE_TIME); 1360 } 1361 } 1362 } 1363 1364 return obj; 1365 } 1366 1367 static bool 1368 ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1369 const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1370 { 1371 ucl_object_t *found, *tmp; 1372 const ucl_object_t *cur; 1373 ucl_object_iter_t it = NULL; 1374 const char *p; 1375 int ret = true; 1376 1377 if (elt == NULL || key == NULL) { 1378 return false; 1379 } 1380 1381 if (top == NULL) { 1382 return false; 1383 } 1384 1385 if (top->type != UCL_OBJECT) { 1386 /* It is possible to convert NULL type to an object */ 1387 if (top->type == UCL_NULL) { 1388 top->type = UCL_OBJECT; 1389 } 1390 else { 1391 /* Refuse converting of other object types */ 1392 return false; 1393 } 1394 } 1395 1396 if (top->value.ov == NULL) { 1397 top->value.ov = ucl_hash_create (); 1398 } 1399 1400 if (keylen == 0) { 1401 keylen = strlen (key); 1402 } 1403 1404 for (p = key; p < key + keylen; p ++) { 1405 if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1406 elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1407 break; 1408 } 1409 } 1410 1411 /* workaround for some use cases */ 1412 if (elt->trash_stack[UCL_TRASH_KEY] != NULL && 1413 key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) { 1414 /* Remove copied key */ 1415 free (elt->trash_stack[UCL_TRASH_KEY]); 1416 elt->trash_stack[UCL_TRASH_KEY] = NULL; 1417 elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY; 1418 } 1419 1420 elt->key = key; 1421 elt->keylen = keylen; 1422 1423 if (copy_key) { 1424 ucl_copy_key_trash (elt); 1425 } 1426 1427 found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 1428 1429 if (found == NULL) { 1430 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1431 top->len ++; 1432 if (replace) { 1433 ret = false; 1434 } 1435 } 1436 else { 1437 if (replace) { 1438 ucl_hash_replace (top->value.ov, found, elt); 1439 ucl_object_unref (found); 1440 } 1441 else if (merge) { 1442 if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1443 /* Insert old elt to new one */ 1444 ucl_object_insert_key_common (elt, found, found->key, 1445 found->keylen, copy_key, false, false); 1446 ucl_hash_delete (top->value.ov, found); 1447 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1448 } 1449 else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1450 /* Insert new to old */ 1451 ucl_object_insert_key_common (found, elt, elt->key, 1452 elt->keylen, copy_key, false, false); 1453 } 1454 else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1455 /* Mix two hashes */ 1456 while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1457 tmp = ucl_object_ref (cur); 1458 ucl_object_insert_key_common (found, tmp, cur->key, 1459 cur->keylen, copy_key, false, false); 1460 } 1461 ucl_object_unref (elt); 1462 } 1463 else { 1464 /* Just make a list of scalars */ 1465 DL_APPEND (found, elt); 1466 } 1467 } 1468 else { 1469 DL_APPEND (found, elt); 1470 } 1471 } 1472 1473 return ret; 1474 } 1475 1476 bool 1477 ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 1478 { 1479 ucl_object_t *found; 1480 1481 if (top == NULL || key == NULL) { 1482 return false; 1483 } 1484 1485 found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); 1486 1487 if (found == NULL) { 1488 return false; 1489 } 1490 1491 ucl_hash_delete (top->value.ov, found); 1492 ucl_object_unref (found); 1493 top->len --; 1494 1495 return true; 1496 } 1497 1498 bool 1499 ucl_object_delete_key (ucl_object_t *top, const char *key) 1500 { 1501 return ucl_object_delete_keyl (top, key, strlen(key)); 1502 } 1503 1504 ucl_object_t* 1505 ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 1506 { 1507 const ucl_object_t *found; 1508 1509 if (top == NULL || key == NULL) { 1510 return false; 1511 } 1512 found = ucl_object_find_keyl (top, key, keylen); 1513 1514 if (found == NULL) { 1515 return NULL; 1516 } 1517 ucl_hash_delete (top->value.ov, found); 1518 top->len --; 1519 1520 return __DECONST (ucl_object_t *, found); 1521 } 1522 1523 ucl_object_t* 1524 ucl_object_pop_key (ucl_object_t *top, const char *key) 1525 { 1526 return ucl_object_pop_keyl (top, key, strlen(key)); 1527 } 1528 1529 bool 1530 ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1531 const char *key, size_t keylen, bool copy_key) 1532 { 1533 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1534 } 1535 1536 bool 1537 ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1538 const char *key, size_t keylen, bool copy_key) 1539 { 1540 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1541 } 1542 1543 bool 1544 ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1545 const char *key, size_t keylen, bool copy_key) 1546 { 1547 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1548 } 1549 1550 bool 1551 ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 1552 { 1553 ucl_object_t *cur = NULL, *cp = NULL, *found = NULL; 1554 ucl_object_iter_t iter = NULL; 1555 1556 if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) { 1557 return false; 1558 } 1559 1560 /* Mix two hashes */ 1561 while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) { 1562 if (copy) { 1563 cp = ucl_object_copy (cur); 1564 } 1565 else { 1566 cp = ucl_object_ref (cur); 1567 } 1568 found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen)); 1569 if (found == NULL) { 1570 /* The key does not exist */ 1571 top->value.ov = ucl_hash_insert_object (top->value.ov, cp); 1572 top->len ++; 1573 } 1574 else { 1575 /* The key already exists, replace it */ 1576 ucl_hash_replace (top->value.ov, found, cp); 1577 ucl_object_unref (found); 1578 } 1579 } 1580 1581 return true; 1582 } 1583 1584 const ucl_object_t * 1585 ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) 1586 { 1587 const ucl_object_t *ret; 1588 ucl_object_t srch; 1589 1590 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1591 return NULL; 1592 } 1593 1594 srch.key = key; 1595 srch.keylen = klen; 1596 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1597 1598 return ret; 1599 } 1600 1601 const ucl_object_t * 1602 ucl_object_find_key (const ucl_object_t *obj, const char *key) 1603 { 1604 if (key == NULL) 1605 return NULL; 1606 1607 return ucl_object_find_keyl (obj, key, strlen(key)); 1608 } 1609 1610 const ucl_object_t* 1611 ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1612 { 1613 const ucl_object_t *elt; 1614 1615 if (obj == NULL || iter == NULL) { 1616 return NULL; 1617 } 1618 1619 if (expand_values) { 1620 switch (obj->type) { 1621 case UCL_OBJECT: 1622 return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1623 break; 1624 case UCL_ARRAY: 1625 elt = *iter; 1626 if (elt == NULL) { 1627 elt = obj->value.av; 1628 if (elt == NULL) { 1629 return NULL; 1630 } 1631 } 1632 else if (elt == obj->value.av) { 1633 return NULL; 1634 } 1635 *iter = elt->next ? elt->next : obj->value.av; 1636 return elt; 1637 default: 1638 /* Go to linear iteration */ 1639 break; 1640 } 1641 } 1642 /* Treat everything as a linear list */ 1643 elt = *iter; 1644 if (elt == NULL) { 1645 elt = obj; 1646 } 1647 else if (elt == obj) { 1648 return NULL; 1649 } 1650 *iter = __DECONST (void *, elt->next ? elt->next : obj); 1651 return elt; 1652 1653 /* Not reached */ 1654 return NULL; 1655 } 1656 1657 const ucl_object_t * 1658 ucl_lookup_path (const ucl_object_t *top, const char *path_in) { 1659 const ucl_object_t *o = NULL, *found; 1660 const char *p, *c; 1661 char *err_str; 1662 unsigned index; 1663 1664 if (path_in == NULL || top == NULL) { 1665 return NULL; 1666 } 1667 1668 found = NULL; 1669 p = path_in; 1670 1671 /* Skip leading dots */ 1672 while (*p == '.') { 1673 p ++; 1674 } 1675 1676 c = p; 1677 while (*p != '\0') { 1678 p ++; 1679 if (*p == '.' || *p == '\0') { 1680 if (p > c) { 1681 switch (top->type) { 1682 case UCL_ARRAY: 1683 /* Key should be an int */ 1684 index = strtoul (c, &err_str, 10); 1685 if (err_str != NULL && (*err_str != '.' && *err_str != '\0')) { 1686 return NULL; 1687 } 1688 o = ucl_array_find_index (top, index); 1689 break; 1690 default: 1691 o = ucl_object_find_keyl (top, c, p - c); 1692 break; 1693 } 1694 if (o == NULL) { 1695 return NULL; 1696 } 1697 top = o; 1698 } 1699 if (*p != '\0') { 1700 c = p + 1; 1701 } 1702 } 1703 } 1704 found = o; 1705 1706 return found; 1707 } 1708 1709 1710 ucl_object_t * 1711 ucl_object_new (void) 1712 { 1713 return ucl_object_typed_new (UCL_NULL); 1714 } 1715 1716 ucl_object_t * 1717 ucl_object_typed_new (ucl_type_t type) 1718 { 1719 return ucl_object_new_full (type, 0); 1720 } 1721 1722 ucl_object_t * 1723 ucl_object_new_full (ucl_type_t type, unsigned priority) 1724 { 1725 ucl_object_t *new; 1726 1727 if (type != UCL_USERDATA) { 1728 new = UCL_ALLOC (sizeof (ucl_object_t)); 1729 if (new != NULL) { 1730 memset (new, 0, sizeof (ucl_object_t)); 1731 new->ref = 1; 1732 new->type = (type <= UCL_NULL ? type : UCL_NULL); 1733 new->next = NULL; 1734 new->prev = new; 1735 ucl_object_set_priority (new, priority); 1736 } 1737 } 1738 else { 1739 new = ucl_object_new_userdata (NULL, NULL); 1740 ucl_object_set_priority (new, priority); 1741 } 1742 1743 return new; 1744 } 1745 1746 ucl_object_t* 1747 ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter) 1748 { 1749 struct ucl_object_userdata *new; 1750 size_t nsize = sizeof (*new); 1751 1752 new = UCL_ALLOC (nsize); 1753 if (new != NULL) { 1754 memset (new, 0, nsize); 1755 new->obj.ref = 1; 1756 new->obj.type = UCL_USERDATA; 1757 new->obj.next = NULL; 1758 new->obj.prev = (ucl_object_t *)new; 1759 new->dtor = dtor; 1760 new->emitter = emitter; 1761 } 1762 1763 return (ucl_object_t *)new; 1764 } 1765 1766 ucl_type_t 1767 ucl_object_type (const ucl_object_t *obj) 1768 { 1769 return obj->type; 1770 } 1771 1772 ucl_object_t* 1773 ucl_object_fromstring (const char *str) 1774 { 1775 return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 1776 } 1777 1778 ucl_object_t * 1779 ucl_object_fromlstring (const char *str, size_t len) 1780 { 1781 return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 1782 } 1783 1784 ucl_object_t * 1785 ucl_object_fromint (int64_t iv) 1786 { 1787 ucl_object_t *obj; 1788 1789 obj = ucl_object_new (); 1790 if (obj != NULL) { 1791 obj->type = UCL_INT; 1792 obj->value.iv = iv; 1793 } 1794 1795 return obj; 1796 } 1797 1798 ucl_object_t * 1799 ucl_object_fromdouble (double dv) 1800 { 1801 ucl_object_t *obj; 1802 1803 obj = ucl_object_new (); 1804 if (obj != NULL) { 1805 obj->type = UCL_FLOAT; 1806 obj->value.dv = dv; 1807 } 1808 1809 return obj; 1810 } 1811 1812 ucl_object_t* 1813 ucl_object_frombool (bool bv) 1814 { 1815 ucl_object_t *obj; 1816 1817 obj = ucl_object_new (); 1818 if (obj != NULL) { 1819 obj->type = UCL_BOOLEAN; 1820 obj->value.iv = bv; 1821 } 1822 1823 return obj; 1824 } 1825 1826 bool 1827 ucl_array_append (ucl_object_t *top, ucl_object_t *elt) 1828 { 1829 ucl_object_t *head; 1830 1831 if (elt == NULL || top == NULL) { 1832 return false; 1833 } 1834 1835 head = top->value.av; 1836 if (head == NULL) { 1837 top->value.av = elt; 1838 elt->prev = elt; 1839 } 1840 else { 1841 elt->prev = head->prev; 1842 head->prev->next = elt; 1843 head->prev = elt; 1844 } 1845 elt->next = NULL; 1846 top->len ++; 1847 1848 return true; 1849 } 1850 1851 bool 1852 ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 1853 { 1854 ucl_object_t *head; 1855 1856 if (elt == NULL || top == NULL) { 1857 return false; 1858 } 1859 1860 1861 head = top->value.av; 1862 if (head == NULL) { 1863 top->value.av = elt; 1864 elt->prev = elt; 1865 } 1866 else { 1867 elt->prev = head->prev; 1868 head->prev = elt; 1869 } 1870 elt->next = head; 1871 top->value.av = elt; 1872 top->len ++; 1873 1874 return true; 1875 } 1876 1877 bool 1878 ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) 1879 { 1880 ucl_object_t *cur, *tmp, *cp; 1881 1882 if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { 1883 return false; 1884 } 1885 1886 DL_FOREACH_SAFE (elt->value.av, cur, tmp) { 1887 if (copy) { 1888 cp = ucl_object_copy (cur); 1889 } 1890 else { 1891 cp = ucl_object_ref (cur); 1892 } 1893 if (cp != NULL) { 1894 ucl_array_append (top, cp); 1895 } 1896 } 1897 1898 return true; 1899 } 1900 1901 ucl_object_t * 1902 ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 1903 { 1904 ucl_object_t *head; 1905 1906 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1907 return NULL; 1908 } 1909 head = top->value.av; 1910 1911 if (elt->prev == elt) { 1912 top->value.av = NULL; 1913 } 1914 else if (elt == head) { 1915 elt->next->prev = elt->prev; 1916 top->value.av = elt->next; 1917 } 1918 else { 1919 elt->prev->next = elt->next; 1920 if (elt->next) { 1921 elt->next->prev = elt->prev; 1922 } 1923 else { 1924 head->prev = elt->prev; 1925 } 1926 } 1927 elt->next = NULL; 1928 elt->prev = elt; 1929 top->len --; 1930 1931 return elt; 1932 } 1933 1934 const ucl_object_t * 1935 ucl_array_head (const ucl_object_t *top) 1936 { 1937 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1938 return NULL; 1939 } 1940 return top->value.av; 1941 } 1942 1943 const ucl_object_t * 1944 ucl_array_tail (const ucl_object_t *top) 1945 { 1946 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 1947 return NULL; 1948 } 1949 return top->value.av->prev; 1950 } 1951 1952 ucl_object_t * 1953 ucl_array_pop_last (ucl_object_t *top) 1954 { 1955 return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top))); 1956 } 1957 1958 ucl_object_t * 1959 ucl_array_pop_first (ucl_object_t *top) 1960 { 1961 return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top))); 1962 } 1963 1964 const ucl_object_t * 1965 ucl_array_find_index (const ucl_object_t *top, unsigned int index) 1966 { 1967 ucl_object_iter_t it = NULL; 1968 const ucl_object_t *ret; 1969 1970 if (top == NULL || top->type != UCL_ARRAY || top->len == 0 || 1971 (index + 1) > top->len) { 1972 return NULL; 1973 } 1974 1975 while ((ret = ucl_iterate_object (top, &it, true)) != NULL) { 1976 if (index == 0) { 1977 return ret; 1978 } 1979 --index; 1980 } 1981 1982 return NULL; 1983 } 1984 1985 ucl_object_t * 1986 ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt, 1987 unsigned int index) 1988 { 1989 ucl_object_t *cur, *tmp; 1990 1991 if (top == NULL || top->type != UCL_ARRAY || elt == NULL || 1992 top->len == 0 || (index + 1) > top->len) { 1993 return NULL; 1994 } 1995 1996 DL_FOREACH_SAFE (top->value.av, cur, tmp) { 1997 if (index == 0) { 1998 DL_REPLACE_ELEM (top->value.av, cur, elt); 1999 return cur; 2000 } 2001 --index; 2002 } 2003 2004 return NULL; 2005 } 2006 2007 ucl_object_t * 2008 ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 2009 { 2010 2011 if (head == NULL) { 2012 elt->next = NULL; 2013 elt->prev = elt; 2014 head = elt; 2015 } 2016 else { 2017 elt->prev = head->prev; 2018 head->prev->next = elt; 2019 head->prev = elt; 2020 elt->next = NULL; 2021 } 2022 2023 return head; 2024 } 2025 2026 bool 2027 ucl_object_todouble_safe (const ucl_object_t *obj, double *target) 2028 { 2029 if (obj == NULL || target == NULL) { 2030 return false; 2031 } 2032 switch (obj->type) { 2033 case UCL_INT: 2034 *target = obj->value.iv; /* Probaly could cause overflow */ 2035 break; 2036 case UCL_FLOAT: 2037 case UCL_TIME: 2038 *target = obj->value.dv; 2039 break; 2040 default: 2041 return false; 2042 } 2043 2044 return true; 2045 } 2046 2047 double 2048 ucl_object_todouble (const ucl_object_t *obj) 2049 { 2050 double result = 0.; 2051 2052 ucl_object_todouble_safe (obj, &result); 2053 return result; 2054 } 2055 2056 bool 2057 ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 2058 { 2059 if (obj == NULL || target == NULL) { 2060 return false; 2061 } 2062 switch (obj->type) { 2063 case UCL_INT: 2064 *target = obj->value.iv; 2065 break; 2066 case UCL_FLOAT: 2067 case UCL_TIME: 2068 *target = obj->value.dv; /* Loosing of decimal points */ 2069 break; 2070 default: 2071 return false; 2072 } 2073 2074 return true; 2075 } 2076 2077 int64_t 2078 ucl_object_toint (const ucl_object_t *obj) 2079 { 2080 int64_t result = 0; 2081 2082 ucl_object_toint_safe (obj, &result); 2083 return result; 2084 } 2085 2086 bool 2087 ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 2088 { 2089 if (obj == NULL || target == NULL) { 2090 return false; 2091 } 2092 switch (obj->type) { 2093 case UCL_BOOLEAN: 2094 *target = (obj->value.iv == true); 2095 break; 2096 default: 2097 return false; 2098 } 2099 2100 return true; 2101 } 2102 2103 bool 2104 ucl_object_toboolean (const ucl_object_t *obj) 2105 { 2106 bool result = false; 2107 2108 ucl_object_toboolean_safe (obj, &result); 2109 return result; 2110 } 2111 2112 bool 2113 ucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 2114 { 2115 if (obj == NULL || target == NULL) { 2116 return false; 2117 } 2118 2119 switch (obj->type) { 2120 case UCL_STRING: 2121 *target = ucl_copy_value_trash (obj); 2122 break; 2123 default: 2124 return false; 2125 } 2126 2127 return true; 2128 } 2129 2130 const char * 2131 ucl_object_tostring (const ucl_object_t *obj) 2132 { 2133 const char *result = NULL; 2134 2135 ucl_object_tostring_safe (obj, &result); 2136 return result; 2137 } 2138 2139 const char * 2140 ucl_object_tostring_forced (const ucl_object_t *obj) 2141 { 2142 return ucl_copy_value_trash (obj); 2143 } 2144 2145 bool 2146 ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 2147 { 2148 if (obj == NULL || target == NULL) { 2149 return false; 2150 } 2151 switch (obj->type) { 2152 case UCL_STRING: 2153 *target = obj->value.sv; 2154 if (tlen != NULL) { 2155 *tlen = obj->len; 2156 } 2157 break; 2158 default: 2159 return false; 2160 } 2161 2162 return true; 2163 } 2164 2165 const char * 2166 ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 2167 { 2168 const char *result = NULL; 2169 2170 ucl_object_tolstring_safe (obj, &result, tlen); 2171 return result; 2172 } 2173 2174 const char * 2175 ucl_object_key (const ucl_object_t *obj) 2176 { 2177 return ucl_copy_key_trash (obj); 2178 } 2179 2180 const char * 2181 ucl_object_keyl (const ucl_object_t *obj, size_t *len) 2182 { 2183 if (len == NULL || obj == NULL) { 2184 return NULL; 2185 } 2186 *len = obj->keylen; 2187 return obj->key; 2188 } 2189 2190 ucl_object_t * 2191 ucl_object_ref (const ucl_object_t *obj) 2192 { 2193 ucl_object_t *res = NULL; 2194 2195 if (obj != NULL) { 2196 if (obj->flags & UCL_OBJECT_EPHEMERAL) { 2197 /* 2198 * Use deep copy for ephemeral objects, note that its refcount 2199 * is NOT increased, since ephemeral objects does not need refcount 2200 * at all 2201 */ 2202 res = ucl_object_copy (obj); 2203 } 2204 else { 2205 res = __DECONST (ucl_object_t *, obj); 2206 #ifdef HAVE_ATOMIC_BUILTINS 2207 (void)__sync_add_and_fetch (&res->ref, 1); 2208 #else 2209 res->ref ++; 2210 #endif 2211 } 2212 } 2213 return res; 2214 } 2215 2216 static ucl_object_t * 2217 ucl_object_copy_internal (const ucl_object_t *other, bool allow_array) 2218 { 2219 2220 ucl_object_t *new; 2221 ucl_object_iter_t it = NULL; 2222 const ucl_object_t *cur; 2223 2224 new = malloc (sizeof (*new)); 2225 2226 if (new != NULL) { 2227 memcpy (new, other, sizeof (*new)); 2228 if (other->flags & UCL_OBJECT_EPHEMERAL) { 2229 /* Copied object is always non ephemeral */ 2230 new->flags &= ~UCL_OBJECT_EPHEMERAL; 2231 } 2232 new->ref = 1; 2233 /* Unlink from others */ 2234 new->next = NULL; 2235 new->prev = new; 2236 2237 /* deep copy of values stored */ 2238 if (other->trash_stack[UCL_TRASH_KEY] != NULL) { 2239 new->trash_stack[UCL_TRASH_KEY] = 2240 strdup (other->trash_stack[UCL_TRASH_KEY]); 2241 if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { 2242 new->key = new->trash_stack[UCL_TRASH_KEY]; 2243 } 2244 } 2245 if (other->trash_stack[UCL_TRASH_VALUE] != NULL) { 2246 new->trash_stack[UCL_TRASH_VALUE] = 2247 strdup (other->trash_stack[UCL_TRASH_VALUE]); 2248 if (new->type == UCL_STRING) { 2249 new->value.sv = new->trash_stack[UCL_TRASH_VALUE]; 2250 } 2251 } 2252 2253 if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) { 2254 /* reset old value */ 2255 memset (&new->value, 0, sizeof (new->value)); 2256 2257 while ((cur = ucl_iterate_object (other, &it, true)) != NULL) { 2258 if (other->type == UCL_ARRAY) { 2259 ucl_array_append (new, ucl_object_copy_internal (cur, false)); 2260 } 2261 else { 2262 ucl_object_t *cp = ucl_object_copy_internal (cur, true); 2263 if (cp != NULL) { 2264 ucl_object_insert_key (new, cp, cp->key, cp->keylen, 2265 false); 2266 } 2267 } 2268 } 2269 } 2270 else if (allow_array && other->next != NULL) { 2271 LL_FOREACH (other->next, cur) { 2272 ucl_object_t *cp = ucl_object_copy_internal (cur, false); 2273 if (cp != NULL) { 2274 DL_APPEND (new, cp); 2275 } 2276 } 2277 } 2278 } 2279 2280 return new; 2281 } 2282 2283 ucl_object_t * 2284 ucl_object_copy (const ucl_object_t *other) 2285 { 2286 return ucl_object_copy_internal (other, true); 2287 } 2288 2289 void 2290 ucl_object_unref (ucl_object_t *obj) 2291 { 2292 if (obj != NULL) { 2293 #ifdef HAVE_ATOMIC_BUILTINS 2294 unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 2295 if (rc == 0) { 2296 #else 2297 if (--obj->ref == 0) { 2298 #endif 2299 ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 2300 } 2301 } 2302 } 2303 2304 int 2305 ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 2306 { 2307 const ucl_object_t *it1, *it2; 2308 ucl_object_iter_t iter = NULL; 2309 int ret = 0; 2310 2311 if (o1->type != o2->type) { 2312 return (o1->type) - (o2->type); 2313 } 2314 2315 switch (o1->type) { 2316 case UCL_STRING: 2317 if (o1->len == o2->len) { 2318 ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 2319 } 2320 else { 2321 ret = o1->len - o2->len; 2322 } 2323 break; 2324 case UCL_FLOAT: 2325 case UCL_INT: 2326 case UCL_TIME: 2327 ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 2328 break; 2329 case UCL_BOOLEAN: 2330 ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 2331 break; 2332 case UCL_ARRAY: 2333 if (o1->len == o2->len) { 2334 it1 = o1->value.av; 2335 it2 = o2->value.av; 2336 /* Compare all elements in both arrays */ 2337 while (it1 != NULL && it2 != NULL) { 2338 ret = ucl_object_compare (it1, it2); 2339 if (ret != 0) { 2340 break; 2341 } 2342 it1 = it1->next; 2343 it2 = it2->next; 2344 } 2345 } 2346 else { 2347 ret = o1->len - o2->len; 2348 } 2349 break; 2350 case UCL_OBJECT: 2351 if (o1->len == o2->len) { 2352 while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 2353 it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 2354 if (it2 == NULL) { 2355 ret = 1; 2356 break; 2357 } 2358 ret = ucl_object_compare (it1, it2); 2359 if (ret != 0) { 2360 break; 2361 } 2362 } 2363 } 2364 else { 2365 ret = o1->len - o2->len; 2366 } 2367 break; 2368 default: 2369 ret = 0; 2370 break; 2371 } 2372 2373 return ret; 2374 } 2375 2376 void 2377 ucl_object_array_sort (ucl_object_t *ar, 2378 int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2)) 2379 { 2380 if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 2381 return; 2382 } 2383 2384 DL_SORT (ar->value.av, cmp); 2385 } 2386 2387 #define PRIOBITS 4 2388 2389 unsigned int 2390 ucl_object_get_priority (const ucl_object_t *obj) 2391 { 2392 if (obj == NULL) { 2393 return 0; 2394 } 2395 2396 return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS)); 2397 } 2398 2399 void 2400 ucl_object_set_priority (ucl_object_t *obj, 2401 unsigned int priority) 2402 { 2403 if (obj != NULL) { 2404 priority &= (0x1 << PRIOBITS) - 1; 2405 obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS); 2406 } 2407 } 2408