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 --- 11 unchanged lines hidden (view full) --- 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 |
69static 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 { --- 21 unchanged lines hidden (view full) --- 99 } 100 } 101 if (map == (void *) NULL) { 102 return (void *) MAP_FAILED; 103 } 104 return (void *) ((char *) map + offset); 105} 106 |
107static int ucl_munmap(void *map,size_t length) |
108{ 109 if (!UnmapViewOfFile(map)) { 110 return(-1); 111 } 112 return(0); 113} 114 |
115static 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 --- 40 unchanged lines hidden (view full) --- 178} 179 180size_t 181ucl_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'; --- 14 unchanged lines hidden (view full) --- 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 --; --- 6 unchanged lines hidden (view full) --- 280 *t = '\0'; 281 282 return (t - str); 283} 284 285UCL_EXTERN char * 286ucl_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 304UCL_EXTERN char * 305ucl_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]; --- 23 unchanged lines hidden (view full) --- 341ucl_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) { --- 18 unchanged lines hidden (view full) --- 379 } 380 381 UCL_FREE (sizeof (struct ucl_parser), parser); 382} 383 384UCL_EXTERN const char * 385ucl_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 397UCL_EXTERN bool 398ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) --- 6 unchanged lines hidden (view full) --- 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 } --- 151 unchanged lines hidden (view full) --- 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 } --- 85 unchanged lines hidden (view full) --- 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); --- 27 unchanged lines hidden (view full) --- 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 } --- 11 unchanged lines hidden (view full) --- 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; --- 6 unchanged lines hidden (view full) --- 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 --- 52 unchanged lines hidden (view full) --- 852 853UCL_EXTERN bool 854ucl_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 */ --- 14 unchanged lines hidden (view full) --- 883UCL_EXTERN bool 884ucl_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 912size_t 913ucl_strlcpy (char *dst, const char *src, size_t siz) 914{ --- 148 unchanged lines hidden (view full) --- 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 1087static ucl_object_t * --- 46 unchanged lines hidden (view full) --- 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); --- 30 unchanged lines hidden (view full) --- 1181 return top; 1182} 1183 1184bool 1185ucl_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 1206bool 1207ucl_object_delete_key(ucl_object_t *top, const char *key) 1208{ 1209 return ucl_object_delete_keyl(top, key, 0); 1210} 1211 |
1212ucl_object_t* 1213ucl_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 1231ucl_object_t* 1232ucl_object_pop_key (ucl_object_t *top, const char *key) 1233{ 1234 return ucl_object_pop_keyl (top, key, 0); 1235} 1236 |
1237ucl_object_t * 1238ucl_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 1244ucl_object_t * --- 44 unchanged lines hidden (view full) --- 1289 return ret; 1290} 1291 1292ucl_object_t* 1293ucl_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) { --- 24 unchanged lines hidden (view full) --- 1333 return NULL; 1334 } 1335 *iter = elt->next ? elt->next : obj; 1336 return elt; 1337 1338 /* Not reached */ 1339 return NULL; 1340} |
1341 1342 1343ucl_object_t * 1344ucl_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 1356ucl_object_t * 1357ucl_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 1369ucl_object_t* 1370ucl_object_fromstring (const char *str) 1371{ 1372 return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 1373} 1374 1375ucl_object_t * 1376ucl_object_fromlstring (const char *str, size_t len) 1377{ 1378 return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 1379} 1380 1381ucl_object_t * 1382ucl_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 1395ucl_object_t * 1396ucl_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 1409ucl_object_t* 1410ucl_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 1423ucl_object_t * 1424ucl_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 1457ucl_object_t * 1458ucl_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 1491ucl_object_t * 1492ucl_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 1524ucl_object_t * 1525ucl_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 1533ucl_object_t * 1534ucl_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 1542ucl_object_t * 1543ucl_array_pop_last (ucl_object_t *top) 1544{ 1545 return ucl_array_delete (top, ucl_array_tail (top)); 1546} 1547 1548ucl_object_t * 1549ucl_array_pop_first (ucl_object_t *top) 1550{ 1551 return ucl_array_delete (top, ucl_array_head (top)); 1552} 1553 1554ucl_object_t * 1555ucl_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 1573bool 1574ucl_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 1594double 1595ucl_object_todouble (ucl_object_t *obj) 1596{ 1597 double result = 0.; 1598 1599 ucl_object_todouble_safe (obj, &result); 1600 return result; 1601} 1602 1603bool 1604ucl_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 1624int64_t 1625ucl_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 1633bool 1634ucl_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 1650bool 1651ucl_object_toboolean (ucl_object_t *obj) 1652{ 1653 bool result = false; 1654 1655 ucl_object_toboolean_safe (obj, &result); 1656 return result; 1657} 1658 1659bool 1660ucl_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 1677const char * 1678ucl_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 1686const char * 1687ucl_object_tostring_forced (ucl_object_t *obj) 1688{ 1689 return ucl_copy_value_trash (obj); 1690} 1691 1692bool 1693ucl_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 1712const char * 1713ucl_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 1721const char * 1722ucl_object_key (ucl_object_t *obj) 1723{ 1724 return ucl_copy_key_trash (obj); 1725} 1726 1727const char * 1728ucl_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 1737ucl_object_t * 1738ucl_object_ref (ucl_object_t *obj) 1739{ 1740 if (obj != NULL) { 1741 obj->ref ++; 1742 } 1743 return obj; 1744} 1745 1746void 1747ucl_object_unref (ucl_object_t *obj) 1748{ 1749 if (obj != NULL && --obj->ref <= 0) { 1750 ucl_object_free (obj); 1751 } 1752} 1753 1754int 1755ucl_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 1826void 1827ucl_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} |