29 30/** 31 * @file rcl_emitter.c 32 * Serialise UCL object to various of output formats 33 */ 34 35 36static void ucl_obj_write_json (ucl_object_t *obj, 37 struct ucl_emitter_functions *func, 38 unsigned int tabs, 39 bool start_tabs, 40 bool compact); 41static void ucl_elt_write_json (ucl_object_t *obj, 42 struct ucl_emitter_functions *func, 43 unsigned int tabs, 44 bool start_tabs, 45 bool compact); 46static void ucl_elt_write_config (ucl_object_t *obj, 47 struct ucl_emitter_functions *func, 48 unsigned int tabs, 49 bool start_tabs, 50 bool is_top, 51 bool expand_array); 52static void ucl_elt_write_yaml (ucl_object_t *obj, 53 struct ucl_emitter_functions *func, 54 unsigned int tabs, 55 bool start_tabs, 56 bool compact, 57 bool expand_array); 58static void ucl_elt_array_write_yaml (ucl_object_t *obj, 59 struct ucl_emitter_functions *func, 60 unsigned int tabs, 61 bool start_tabs, 62 bool is_top); 63 64/** 65 * Add tabulation to the output buffer 66 * @param buf target buffer 67 * @param tabs number of tabs to add 68 */ 69static inline void 70ucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact) 71{ 72 if (!compact) { 73 func->ucl_emitter_append_character (' ', tabs * 4, func->ud); 74 } 75} 76 77/** 78 * Serialise string 79 * @param str string to emit 80 * @param buf target buffer 81 */ 82static void 83ucl_elt_string_write_json (const char *str, size_t size, 84 struct ucl_emitter_functions *func) 85{ 86 const char *p = str, *c = str; 87 size_t len = 0; 88 89 func->ucl_emitter_append_character ('"', 1, func->ud); 90 while (size) { 91 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 92 if (len > 0) { 93 func->ucl_emitter_append_len (c, len, func->ud); 94 } 95 switch (*p) { 96 case '\n': 97 func->ucl_emitter_append_len ("\\n", 2, func->ud); 98 break; 99 case '\r': 100 func->ucl_emitter_append_len ("\\r", 2, func->ud); 101 break; 102 case '\b': 103 func->ucl_emitter_append_len ("\\b", 2, func->ud); 104 break; 105 case '\t': 106 func->ucl_emitter_append_len ("\\t", 2, func->ud); 107 break; 108 case '\f': 109 func->ucl_emitter_append_len ("\\f", 2, func->ud); 110 break; 111 case '\\': 112 func->ucl_emitter_append_len ("\\\\", 2, func->ud); 113 break; 114 case '"': 115 func->ucl_emitter_append_len ("\\\"", 2, func->ud); 116 break; 117 } 118 len = 0; 119 c = ++p; 120 } 121 else { 122 p ++; 123 len ++; 124 } 125 size --; 126 } 127 if (len > 0) { 128 func->ucl_emitter_append_len (c, len, func->ud); 129 } 130 func->ucl_emitter_append_character ('"', 1, func->ud); 131} 132 133/** 134 * Write a single object to the buffer 135 * @param obj object to write 136 * @param buf target buffer 137 */ 138static void 139ucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 140 unsigned int tabs, bool start_tabs, bool compact) 141{ 142 ucl_object_t *cur; 143 ucl_hash_iter_t it = NULL; 144 145 if (start_tabs) { 146 ucl_add_tabs (func, tabs, compact); 147 } 148 if (compact) { 149 func->ucl_emitter_append_character ('{', 1, func->ud); 150 } 151 else { 152 func->ucl_emitter_append_len ("{\n", 2, func->ud); 153 } 154 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 155 ucl_add_tabs (func, tabs + 1, compact); 156 if (cur->keylen > 0) { 157 ucl_elt_string_write_json (cur->key, cur->keylen, func); 158 } 159 else { 160 func->ucl_emitter_append_len ("null", 4, func->ud); 161 } 162 if (compact) { 163 func->ucl_emitter_append_character (':', 1, func->ud); 164 } 165 else { 166 func->ucl_emitter_append_len (": ", 2, func->ud); 167 } 168 ucl_obj_write_json (cur, func, tabs + 1, false, compact); 169 if (ucl_hash_iter_has_next (it)) { 170 if (compact) { 171 func->ucl_emitter_append_character (',', 1, func->ud); 172 } 173 else { 174 func->ucl_emitter_append_len (",\n", 2, func->ud); 175 } 176 } 177 else if (!compact) { 178 func->ucl_emitter_append_character ('\n', 1, func->ud); 179 } 180 } 181 ucl_add_tabs (func, tabs, compact); 182 func->ucl_emitter_append_character ('}', 1, func->ud); 183} 184 185/** 186 * Write a single array to the buffer 187 * @param obj array to write 188 * @param buf target buffer 189 */ 190static void 191ucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 192 unsigned int tabs, bool start_tabs, bool compact) 193{ 194 ucl_object_t *cur = obj; 195 196 if (start_tabs) { 197 ucl_add_tabs (func, tabs, compact); 198 } 199 if (compact) { 200 func->ucl_emitter_append_character ('[', 1, func->ud); 201 } 202 else { 203 func->ucl_emitter_append_len ("[\n", 2, func->ud); 204 } 205 while (cur) { 206 ucl_elt_write_json (cur, func, tabs + 1, true, compact); 207 if (cur->next != NULL) { 208 if (compact) { 209 func->ucl_emitter_append_character (',', 1, func->ud); 210 } 211 else { 212 func->ucl_emitter_append_len (",\n", 2, func->ud); 213 } 214 } 215 else if (!compact) { 216 func->ucl_emitter_append_character ('\n', 1, func->ud); 217 } 218 cur = cur->next; 219 } 220 ucl_add_tabs (func, tabs, compact); 221 func->ucl_emitter_append_character (']', 1, func->ud); 222} 223 224/** 225 * Emit a single element 226 * @param obj object 227 * @param buf buffer 228 */ 229static void 230ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 231 unsigned int tabs, bool start_tabs, bool compact) 232{ 233 bool flag; 234 235 switch (obj->type) { 236 case UCL_INT: 237 if (start_tabs) { 238 ucl_add_tabs (func, tabs, compact); 239 } 240 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 241 break; 242 case UCL_FLOAT: 243 case UCL_TIME: 244 if (start_tabs) { 245 ucl_add_tabs (func, tabs, compact); 246 } 247 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 248 break; 249 case UCL_BOOLEAN: 250 if (start_tabs) { 251 ucl_add_tabs (func, tabs, compact); 252 } 253 flag = ucl_object_toboolean (obj); 254 if (flag) { 255 func->ucl_emitter_append_len ("true", 4, func->ud); 256 } 257 else { 258 func->ucl_emitter_append_len ("false", 5, func->ud); 259 } 260 break; 261 case UCL_STRING: 262 if (start_tabs) { 263 ucl_add_tabs (func, tabs, compact); 264 } 265 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 266 break; 267 case UCL_NULL: 268 if (start_tabs) { 269 ucl_add_tabs (func, tabs, compact); 270 } 271 func->ucl_emitter_append_len ("null", 4, func->ud); 272 break; 273 case UCL_OBJECT: 274 ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact); 275 break; 276 case UCL_ARRAY: 277 ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact); 278 break; 279 case UCL_USERDATA: 280 break; 281 } 282} 283 284/** 285 * Write a single object to the buffer 286 * @param obj object 287 * @param buf target buffer 288 */ 289static void 290ucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 291 unsigned int tabs, bool start_tabs, bool compact) 292{ 293 ucl_object_t *cur; 294 bool is_array = (obj->next != NULL); 295 296 if (is_array) { 297 /* This is an array actually */ 298 if (start_tabs) { 299 ucl_add_tabs (func, tabs, compact); 300 } 301 302 if (compact) { 303 func->ucl_emitter_append_character ('[', 1, func->ud); 304 } 305 else { 306 func->ucl_emitter_append_len ("[\n", 2, func->ud); 307 } 308 cur = obj; 309 while (cur != NULL) { 310 ucl_elt_write_json (cur, func, tabs + 1, true, compact); 311 if (cur->next) { 312 func->ucl_emitter_append_character (',', 1, func->ud); 313 } 314 if (!compact) { 315 func->ucl_emitter_append_character ('\n', 1, func->ud); 316 } 317 cur = cur->next; 318 } 319 ucl_add_tabs (func, tabs, compact); 320 func->ucl_emitter_append_character (']', 1, func->ud); 321 } 322 else { 323 ucl_elt_write_json (obj, func, tabs, start_tabs, compact); 324 } 325 326} 327 328/** 329 * Emit an object to json 330 * @param obj object 331 * @return json output (should be freed after using) 332 */ 333static void 334ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func) 335{ 336 ucl_obj_write_json (obj, func, 0, false, compact); 337} 338 339/** 340 * Write a single object to the buffer 341 * @param obj object to write 342 * @param buf target buffer 343 */ 344static void 345ucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 346 unsigned int tabs, bool start_tabs, bool is_top) 347{ 348 ucl_object_t *cur, *cur_obj; 349 ucl_hash_iter_t it = NULL; 350 351 if (start_tabs) { 352 ucl_add_tabs (func, tabs, is_top); 353 } 354 if (!is_top) { 355 func->ucl_emitter_append_len ("{\n", 2, func->ud); 356 } 357 358 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 359 LL_FOREACH (cur, cur_obj) { 360 ucl_add_tabs (func, tabs + 1, is_top); 361 if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { 362 ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func); 363 } 364 else { 365 func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud); 366 } 367 if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 368 func->ucl_emitter_append_len (" = ", 3, func->ud); 369 } 370 else { 371 func->ucl_emitter_append_character (' ', 1, func->ud); 372 } 373 ucl_elt_write_config (cur_obj, func, 374 is_top ? tabs : tabs + 1, 375 false, false, false); 376 if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 377 func->ucl_emitter_append_len (";\n", 2, func->ud); 378 } 379 else { 380 func->ucl_emitter_append_character ('\n', 1, func->ud); 381 } 382 } 383 } 384 385 ucl_add_tabs (func, tabs, is_top); 386 if (!is_top) { 387 func->ucl_emitter_append_character ('}', 1, func->ud); 388 } 389} 390 391/** 392 * Write a single array to the buffer 393 * @param obj array to write 394 * @param buf target buffer 395 */ 396static void 397ucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 398 unsigned int tabs, bool start_tabs, bool is_top) 399{ 400 ucl_object_t *cur = obj; 401 402 if (start_tabs) { 403 ucl_add_tabs (func, tabs, false); 404 } 405 406 func->ucl_emitter_append_len ("[\n", 2, func->ud); 407 while (cur) { 408 ucl_elt_write_config (cur, func, tabs + 1, true, false, false); 409 func->ucl_emitter_append_len (",\n", 2, func->ud); 410 cur = cur->next; 411 } 412 ucl_add_tabs (func, tabs, false); 413 func->ucl_emitter_append_character (']', 1, func->ud); 414} 415 416/** 417 * Emit a single element 418 * @param obj object 419 * @param buf buffer 420 */ 421static void 422ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 423 unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 424{ 425 bool flag; 426 427 if (expand_array && obj->next != NULL) { 428 ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top); 429 } 430 else { 431 switch (obj->type) { 432 case UCL_INT: 433 if (start_tabs) { 434 ucl_add_tabs (func, tabs, false); 435 } 436 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 437 break; 438 case UCL_FLOAT: 439 case UCL_TIME: 440 if (start_tabs) { 441 ucl_add_tabs (func, tabs, false); 442 } 443 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 444 break; 445 case UCL_BOOLEAN: 446 if (start_tabs) { 447 ucl_add_tabs (func, tabs, false); 448 } 449 flag = ucl_object_toboolean (obj); 450 if (flag) { 451 func->ucl_emitter_append_len ("true", 4, func->ud); 452 } 453 else { 454 func->ucl_emitter_append_len ("false", 5, func->ud); 455 } 456 break; 457 case UCL_STRING: 458 if (start_tabs) { 459 ucl_add_tabs (func, tabs, false); 460 } 461 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 462 break; 463 case UCL_NULL: 464 if (start_tabs) { 465 ucl_add_tabs (func, tabs, false); 466 } 467 func->ucl_emitter_append_len ("null", 4, func->ud); 468 break; 469 case UCL_OBJECT: 470 ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top); 471 break; 472 case UCL_ARRAY: 473 ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top); 474 break; 475 case UCL_USERDATA: 476 break; 477 } 478 } 479} 480 481/** 482 * Emit an object to rcl 483 * @param obj object 484 * @return rcl output (should be freed after using) 485 */ 486static void 487ucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func) 488{ 489 ucl_elt_write_config (obj, func, 0, false, true, true); 490} 491 492 493static void 494ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 495 unsigned int tabs, bool start_tabs) 496{ 497 bool is_array = (obj->next != NULL); 498 499 if (is_array) { 500 ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false); 501 } 502 else { 503 ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true); 504 } 505} 506 507/** 508 * Write a single object to the buffer 509 * @param obj object to write 510 * @param buf target buffer 511 */ 512static void 513ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 514 unsigned int tabs, bool start_tabs, bool is_top) 515{ 516 ucl_object_t *cur; 517 ucl_hash_iter_t it = NULL; 518 519 if (start_tabs) { 520 ucl_add_tabs (func, tabs, is_top); 521 } 522 if (!is_top) { 523 func->ucl_emitter_append_len ("{\n", 2, func->ud); 524 } 525 526 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 527 ucl_add_tabs (func, tabs + 1, is_top); 528 if (cur->keylen > 0) { 529 ucl_elt_string_write_json (cur->key, cur->keylen, func); 530 } 531 else { 532 func->ucl_emitter_append_len ("null", 4, func->ud); 533 } 534 func->ucl_emitter_append_len (": ", 2, func->ud); 535 ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false); 536 if (ucl_hash_iter_has_next(it)) { 537 if (!is_top) { 538 func->ucl_emitter_append_len (",\n", 2, func->ud); 539 } 540 else { 541 func->ucl_emitter_append_character ('\n', 1, func->ud); 542 } 543 } 544 else { 545 func->ucl_emitter_append_character ('\n', 1, func->ud); 546 } 547 } 548 549 ucl_add_tabs (func, tabs, is_top); 550 if (!is_top) { 551 func->ucl_emitter_append_character ('}', 1, func->ud); 552 } 553} 554 555/** 556 * Write a single array to the buffer 557 * @param obj array to write 558 * @param buf target buffer 559 */ 560static void 561ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 562 unsigned int tabs, bool start_tabs, bool is_top) 563{ 564 ucl_object_t *cur = obj; 565 566 if (start_tabs) { 567 ucl_add_tabs (func, tabs, false); 568 } 569 570 func->ucl_emitter_append_len ("[\n", 2, func->ud); 571 while (cur) { 572 ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false); 573 func->ucl_emitter_append_len (",\n", 2, func->ud); 574 cur = cur->next; 575 } 576 ucl_add_tabs (func, tabs, false); 577 func->ucl_emitter_append_character (']', 1, func->ud); 578} 579 580/** 581 * Emit a single element 582 * @param obj object 583 * @param buf buffer 584 */ 585static void 586ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 587 unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 588{ 589 bool flag; 590 591 if (expand_array && obj->next != NULL ) { 592 ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top); 593 } 594 else { 595 switch (obj->type) { 596 case UCL_INT: 597 if (start_tabs) { 598 ucl_add_tabs (func, tabs, false); 599 } 600 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 601 break; 602 case UCL_FLOAT: 603 case UCL_TIME: 604 if (start_tabs) { 605 ucl_add_tabs (func, tabs, false); 606 } 607 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 608 break; 609 case UCL_BOOLEAN: 610 if (start_tabs) { 611 ucl_add_tabs (func, tabs, false); 612 } 613 flag = ucl_object_toboolean (obj); 614 if (flag) { 615 func->ucl_emitter_append_len ("true", 4, func->ud); 616 } 617 else { 618 func->ucl_emitter_append_len ("false", 5, func->ud); 619 } 620 break; 621 case UCL_STRING: 622 if (start_tabs) { 623 ucl_add_tabs (func, tabs, false); 624 } 625 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 626 break; 627 case UCL_NULL: 628 if (start_tabs) { 629 ucl_add_tabs (func, tabs, false); 630 } 631 func->ucl_emitter_append_len ("null", 4, func->ud); 632 break; 633 case UCL_OBJECT: 634 ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top); 635 break; 636 case UCL_ARRAY: 637 ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top); 638 break; 639 case UCL_USERDATA: 640 break; 641 } 642 } 643} 644 645/** 646 * Emit an object to rcl 647 * @param obj object 648 * @return rcl output (should be freed after using) 649 */ 650static void 651ucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func) 652{ 653 ucl_elt_write_yaml (obj, func, 0, false, true, true); 654} 655 656/* 657 * Generic utstring output 658 */ 659static int 660ucl_utstring_append_character (unsigned char c, size_t len, void *ud) 661{ 662 UT_string *buf = ud; 663 664 if (len == 1) { 665 utstring_append_c (buf, c); 666 } 667 else { 668 utstring_reserve (buf, len); 669 memset (&buf->d[buf->i], c, len); 670 buf->i += len; 671 buf->d[buf->i] = '\0'; 672 } 673 674 return 0; 675} 676 677static int 678ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud) 679{ 680 UT_string *buf = ud; 681 682 utstring_append_len (buf, str, len); 683 684 return 0; 685} 686 687static int 688ucl_utstring_append_int (int64_t val, void *ud) 689{ 690 UT_string *buf = ud; 691 692 utstring_printf (buf, "%jd", (intmax_t)val); 693 return 0; 694} 695 696static int 697ucl_utstring_append_double (double val, void *ud) 698{ 699 UT_string *buf = ud; 700 const double delta = 0.0000001; 701 702 if (val == (double)(int)val) { 703 utstring_printf (buf, "%.1lf", val); 704 } 705 else if (fabs (val - (double)(int)val) < delta) { 706 /* Write at maximum precision */ 707 utstring_printf (buf, "%.*lg", DBL_DIG, val); 708 } 709 else { 710 utstring_printf (buf, "%lf", val); 711 } 712 713 return 0; 714} 715 716 717unsigned char * 718ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type) 719{ 720 UT_string *buf = NULL; 721 unsigned char *res = NULL; 722 struct ucl_emitter_functions func = { 723 .ucl_emitter_append_character = ucl_utstring_append_character, 724 .ucl_emitter_append_len = ucl_utstring_append_len, 725 .ucl_emitter_append_int = ucl_utstring_append_int, 726 .ucl_emitter_append_double = ucl_utstring_append_double 727 }; 728 729 if (obj == NULL) { 730 return NULL; 731 } 732 733 utstring_new (buf); 734 func.ud = buf; 735 736 if (buf != NULL) { 737 if (emit_type == UCL_EMIT_JSON) { 738 ucl_object_emit_json (obj, false, &func); 739 } 740 else if (emit_type == UCL_EMIT_JSON_COMPACT) { 741 ucl_object_emit_json (obj, true, &func); 742 } 743 else if (emit_type == UCL_EMIT_YAML) { 744 ucl_object_emit_yaml (obj, &func); 745 } 746 else { 747 ucl_object_emit_config (obj, &func); 748 } 749 750 res = utstring_body (buf); 751 free (buf); 752 } 753 754 return res; 755} 756 757bool 758ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, 759 struct ucl_emitter_functions *emitter) 760{ 761 if (emit_type == UCL_EMIT_JSON) { 762 ucl_object_emit_json (obj, false, emitter); 763 } 764 else if (emit_type == UCL_EMIT_JSON_COMPACT) { 765 ucl_object_emit_json (obj, true, emitter); 766 } 767 else if (emit_type == UCL_EMIT_YAML) { 768 ucl_object_emit_yaml (obj, emitter); 769 } 770 else { 771 ucl_object_emit_config (obj, emitter); 772 } 773 774 /* XXX: need some error checks here */ 775 return true; 776} 777 778 779unsigned char * 780ucl_object_emit_single_json (ucl_object_t *obj) 781{ 782 UT_string *buf = NULL; 783 unsigned char *res = NULL; 784 785 if (obj == NULL) { 786 return NULL; 787 } 788 789 utstring_new (buf); 790 791 if (buf != NULL) { 792 switch (obj->type) { 793 case UCL_OBJECT: 794 ucl_utstring_append_len ("object", 6, buf); 795 break; 796 case UCL_ARRAY: 797 ucl_utstring_append_len ("array", 5, buf); 798 break; 799 case UCL_INT: 800 ucl_utstring_append_int (obj->value.iv, buf); 801 break; 802 case UCL_FLOAT: 803 case UCL_TIME: 804 ucl_utstring_append_double (obj->value.dv, buf); 805 break; 806 case UCL_NULL: 807 ucl_utstring_append_len ("null", 4, buf); 808 break; 809 case UCL_BOOLEAN: 810 if (obj->value.iv) { 811 ucl_utstring_append_len ("true", 4, buf); 812 } 813 else { 814 ucl_utstring_append_len ("false", 5, buf); 815 } 816 break; 817 case UCL_STRING: 818 ucl_utstring_append_len (obj->value.sv, obj->len, buf); 819 break; 820 case UCL_USERDATA: 821 ucl_utstring_append_len ("userdata", 8, buf); 822 break; 823 } 824 res = utstring_body (buf); 825 free (buf); 826 } 827 828 return res; 829}
| 37 38/** 39 * @file rcl_emitter.c 40 * Serialise UCL object to various of output formats 41 */ 42 43 44static void ucl_obj_write_json (ucl_object_t *obj, 45 struct ucl_emitter_functions *func, 46 unsigned int tabs, 47 bool start_tabs, 48 bool compact); 49static void ucl_elt_write_json (ucl_object_t *obj, 50 struct ucl_emitter_functions *func, 51 unsigned int tabs, 52 bool start_tabs, 53 bool compact); 54static void ucl_elt_write_config (ucl_object_t *obj, 55 struct ucl_emitter_functions *func, 56 unsigned int tabs, 57 bool start_tabs, 58 bool is_top, 59 bool expand_array); 60static void ucl_elt_write_yaml (ucl_object_t *obj, 61 struct ucl_emitter_functions *func, 62 unsigned int tabs, 63 bool start_tabs, 64 bool compact, 65 bool expand_array); 66static void ucl_elt_array_write_yaml (ucl_object_t *obj, 67 struct ucl_emitter_functions *func, 68 unsigned int tabs, 69 bool start_tabs, 70 bool is_top); 71 72/** 73 * Add tabulation to the output buffer 74 * @param buf target buffer 75 * @param tabs number of tabs to add 76 */ 77static inline void 78ucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact) 79{ 80 if (!compact) { 81 func->ucl_emitter_append_character (' ', tabs * 4, func->ud); 82 } 83} 84 85/** 86 * Serialise string 87 * @param str string to emit 88 * @param buf target buffer 89 */ 90static void 91ucl_elt_string_write_json (const char *str, size_t size, 92 struct ucl_emitter_functions *func) 93{ 94 const char *p = str, *c = str; 95 size_t len = 0; 96 97 func->ucl_emitter_append_character ('"', 1, func->ud); 98 while (size) { 99 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 100 if (len > 0) { 101 func->ucl_emitter_append_len (c, len, func->ud); 102 } 103 switch (*p) { 104 case '\n': 105 func->ucl_emitter_append_len ("\\n", 2, func->ud); 106 break; 107 case '\r': 108 func->ucl_emitter_append_len ("\\r", 2, func->ud); 109 break; 110 case '\b': 111 func->ucl_emitter_append_len ("\\b", 2, func->ud); 112 break; 113 case '\t': 114 func->ucl_emitter_append_len ("\\t", 2, func->ud); 115 break; 116 case '\f': 117 func->ucl_emitter_append_len ("\\f", 2, func->ud); 118 break; 119 case '\\': 120 func->ucl_emitter_append_len ("\\\\", 2, func->ud); 121 break; 122 case '"': 123 func->ucl_emitter_append_len ("\\\"", 2, func->ud); 124 break; 125 } 126 len = 0; 127 c = ++p; 128 } 129 else { 130 p ++; 131 len ++; 132 } 133 size --; 134 } 135 if (len > 0) { 136 func->ucl_emitter_append_len (c, len, func->ud); 137 } 138 func->ucl_emitter_append_character ('"', 1, func->ud); 139} 140 141/** 142 * Write a single object to the buffer 143 * @param obj object to write 144 * @param buf target buffer 145 */ 146static void 147ucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 148 unsigned int tabs, bool start_tabs, bool compact) 149{ 150 ucl_object_t *cur; 151 ucl_hash_iter_t it = NULL; 152 153 if (start_tabs) { 154 ucl_add_tabs (func, tabs, compact); 155 } 156 if (compact) { 157 func->ucl_emitter_append_character ('{', 1, func->ud); 158 } 159 else { 160 func->ucl_emitter_append_len ("{\n", 2, func->ud); 161 } 162 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 163 ucl_add_tabs (func, tabs + 1, compact); 164 if (cur->keylen > 0) { 165 ucl_elt_string_write_json (cur->key, cur->keylen, func); 166 } 167 else { 168 func->ucl_emitter_append_len ("null", 4, func->ud); 169 } 170 if (compact) { 171 func->ucl_emitter_append_character (':', 1, func->ud); 172 } 173 else { 174 func->ucl_emitter_append_len (": ", 2, func->ud); 175 } 176 ucl_obj_write_json (cur, func, tabs + 1, false, compact); 177 if (ucl_hash_iter_has_next (it)) { 178 if (compact) { 179 func->ucl_emitter_append_character (',', 1, func->ud); 180 } 181 else { 182 func->ucl_emitter_append_len (",\n", 2, func->ud); 183 } 184 } 185 else if (!compact) { 186 func->ucl_emitter_append_character ('\n', 1, func->ud); 187 } 188 } 189 ucl_add_tabs (func, tabs, compact); 190 func->ucl_emitter_append_character ('}', 1, func->ud); 191} 192 193/** 194 * Write a single array to the buffer 195 * @param obj array to write 196 * @param buf target buffer 197 */ 198static void 199ucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 200 unsigned int tabs, bool start_tabs, bool compact) 201{ 202 ucl_object_t *cur = obj; 203 204 if (start_tabs) { 205 ucl_add_tabs (func, tabs, compact); 206 } 207 if (compact) { 208 func->ucl_emitter_append_character ('[', 1, func->ud); 209 } 210 else { 211 func->ucl_emitter_append_len ("[\n", 2, func->ud); 212 } 213 while (cur) { 214 ucl_elt_write_json (cur, func, tabs + 1, true, compact); 215 if (cur->next != NULL) { 216 if (compact) { 217 func->ucl_emitter_append_character (',', 1, func->ud); 218 } 219 else { 220 func->ucl_emitter_append_len (",\n", 2, func->ud); 221 } 222 } 223 else if (!compact) { 224 func->ucl_emitter_append_character ('\n', 1, func->ud); 225 } 226 cur = cur->next; 227 } 228 ucl_add_tabs (func, tabs, compact); 229 func->ucl_emitter_append_character (']', 1, func->ud); 230} 231 232/** 233 * Emit a single element 234 * @param obj object 235 * @param buf buffer 236 */ 237static void 238ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 239 unsigned int tabs, bool start_tabs, bool compact) 240{ 241 bool flag; 242 243 switch (obj->type) { 244 case UCL_INT: 245 if (start_tabs) { 246 ucl_add_tabs (func, tabs, compact); 247 } 248 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 249 break; 250 case UCL_FLOAT: 251 case UCL_TIME: 252 if (start_tabs) { 253 ucl_add_tabs (func, tabs, compact); 254 } 255 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 256 break; 257 case UCL_BOOLEAN: 258 if (start_tabs) { 259 ucl_add_tabs (func, tabs, compact); 260 } 261 flag = ucl_object_toboolean (obj); 262 if (flag) { 263 func->ucl_emitter_append_len ("true", 4, func->ud); 264 } 265 else { 266 func->ucl_emitter_append_len ("false", 5, func->ud); 267 } 268 break; 269 case UCL_STRING: 270 if (start_tabs) { 271 ucl_add_tabs (func, tabs, compact); 272 } 273 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 274 break; 275 case UCL_NULL: 276 if (start_tabs) { 277 ucl_add_tabs (func, tabs, compact); 278 } 279 func->ucl_emitter_append_len ("null", 4, func->ud); 280 break; 281 case UCL_OBJECT: 282 ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact); 283 break; 284 case UCL_ARRAY: 285 ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact); 286 break; 287 case UCL_USERDATA: 288 break; 289 } 290} 291 292/** 293 * Write a single object to the buffer 294 * @param obj object 295 * @param buf target buffer 296 */ 297static void 298ucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 299 unsigned int tabs, bool start_tabs, bool compact) 300{ 301 ucl_object_t *cur; 302 bool is_array = (obj->next != NULL); 303 304 if (is_array) { 305 /* This is an array actually */ 306 if (start_tabs) { 307 ucl_add_tabs (func, tabs, compact); 308 } 309 310 if (compact) { 311 func->ucl_emitter_append_character ('[', 1, func->ud); 312 } 313 else { 314 func->ucl_emitter_append_len ("[\n", 2, func->ud); 315 } 316 cur = obj; 317 while (cur != NULL) { 318 ucl_elt_write_json (cur, func, tabs + 1, true, compact); 319 if (cur->next) { 320 func->ucl_emitter_append_character (',', 1, func->ud); 321 } 322 if (!compact) { 323 func->ucl_emitter_append_character ('\n', 1, func->ud); 324 } 325 cur = cur->next; 326 } 327 ucl_add_tabs (func, tabs, compact); 328 func->ucl_emitter_append_character (']', 1, func->ud); 329 } 330 else { 331 ucl_elt_write_json (obj, func, tabs, start_tabs, compact); 332 } 333 334} 335 336/** 337 * Emit an object to json 338 * @param obj object 339 * @return json output (should be freed after using) 340 */ 341static void 342ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func) 343{ 344 ucl_obj_write_json (obj, func, 0, false, compact); 345} 346 347/** 348 * Write a single object to the buffer 349 * @param obj object to write 350 * @param buf target buffer 351 */ 352static void 353ucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 354 unsigned int tabs, bool start_tabs, bool is_top) 355{ 356 ucl_object_t *cur, *cur_obj; 357 ucl_hash_iter_t it = NULL; 358 359 if (start_tabs) { 360 ucl_add_tabs (func, tabs, is_top); 361 } 362 if (!is_top) { 363 func->ucl_emitter_append_len ("{\n", 2, func->ud); 364 } 365 366 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 367 LL_FOREACH (cur, cur_obj) { 368 ucl_add_tabs (func, tabs + 1, is_top); 369 if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { 370 ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func); 371 } 372 else { 373 func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud); 374 } 375 if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 376 func->ucl_emitter_append_len (" = ", 3, func->ud); 377 } 378 else { 379 func->ucl_emitter_append_character (' ', 1, func->ud); 380 } 381 ucl_elt_write_config (cur_obj, func, 382 is_top ? tabs : tabs + 1, 383 false, false, false); 384 if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 385 func->ucl_emitter_append_len (";\n", 2, func->ud); 386 } 387 else { 388 func->ucl_emitter_append_character ('\n', 1, func->ud); 389 } 390 } 391 } 392 393 ucl_add_tabs (func, tabs, is_top); 394 if (!is_top) { 395 func->ucl_emitter_append_character ('}', 1, func->ud); 396 } 397} 398 399/** 400 * Write a single array to the buffer 401 * @param obj array to write 402 * @param buf target buffer 403 */ 404static void 405ucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 406 unsigned int tabs, bool start_tabs, bool is_top) 407{ 408 ucl_object_t *cur = obj; 409 410 if (start_tabs) { 411 ucl_add_tabs (func, tabs, false); 412 } 413 414 func->ucl_emitter_append_len ("[\n", 2, func->ud); 415 while (cur) { 416 ucl_elt_write_config (cur, func, tabs + 1, true, false, false); 417 func->ucl_emitter_append_len (",\n", 2, func->ud); 418 cur = cur->next; 419 } 420 ucl_add_tabs (func, tabs, false); 421 func->ucl_emitter_append_character (']', 1, func->ud); 422} 423 424/** 425 * Emit a single element 426 * @param obj object 427 * @param buf buffer 428 */ 429static void 430ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 431 unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 432{ 433 bool flag; 434 435 if (expand_array && obj->next != NULL) { 436 ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top); 437 } 438 else { 439 switch (obj->type) { 440 case UCL_INT: 441 if (start_tabs) { 442 ucl_add_tabs (func, tabs, false); 443 } 444 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 445 break; 446 case UCL_FLOAT: 447 case UCL_TIME: 448 if (start_tabs) { 449 ucl_add_tabs (func, tabs, false); 450 } 451 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 452 break; 453 case UCL_BOOLEAN: 454 if (start_tabs) { 455 ucl_add_tabs (func, tabs, false); 456 } 457 flag = ucl_object_toboolean (obj); 458 if (flag) { 459 func->ucl_emitter_append_len ("true", 4, func->ud); 460 } 461 else { 462 func->ucl_emitter_append_len ("false", 5, func->ud); 463 } 464 break; 465 case UCL_STRING: 466 if (start_tabs) { 467 ucl_add_tabs (func, tabs, false); 468 } 469 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 470 break; 471 case UCL_NULL: 472 if (start_tabs) { 473 ucl_add_tabs (func, tabs, false); 474 } 475 func->ucl_emitter_append_len ("null", 4, func->ud); 476 break; 477 case UCL_OBJECT: 478 ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top); 479 break; 480 case UCL_ARRAY: 481 ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top); 482 break; 483 case UCL_USERDATA: 484 break; 485 } 486 } 487} 488 489/** 490 * Emit an object to rcl 491 * @param obj object 492 * @return rcl output (should be freed after using) 493 */ 494static void 495ucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func) 496{ 497 ucl_elt_write_config (obj, func, 0, false, true, true); 498} 499 500 501static void 502ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 503 unsigned int tabs, bool start_tabs) 504{ 505 bool is_array = (obj->next != NULL); 506 507 if (is_array) { 508 ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false); 509 } 510 else { 511 ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true); 512 } 513} 514 515/** 516 * Write a single object to the buffer 517 * @param obj object to write 518 * @param buf target buffer 519 */ 520static void 521ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 522 unsigned int tabs, bool start_tabs, bool is_top) 523{ 524 ucl_object_t *cur; 525 ucl_hash_iter_t it = NULL; 526 527 if (start_tabs) { 528 ucl_add_tabs (func, tabs, is_top); 529 } 530 if (!is_top) { 531 func->ucl_emitter_append_len ("{\n", 2, func->ud); 532 } 533 534 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 535 ucl_add_tabs (func, tabs + 1, is_top); 536 if (cur->keylen > 0) { 537 ucl_elt_string_write_json (cur->key, cur->keylen, func); 538 } 539 else { 540 func->ucl_emitter_append_len ("null", 4, func->ud); 541 } 542 func->ucl_emitter_append_len (": ", 2, func->ud); 543 ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false); 544 if (ucl_hash_iter_has_next(it)) { 545 if (!is_top) { 546 func->ucl_emitter_append_len (",\n", 2, func->ud); 547 } 548 else { 549 func->ucl_emitter_append_character ('\n', 1, func->ud); 550 } 551 } 552 else { 553 func->ucl_emitter_append_character ('\n', 1, func->ud); 554 } 555 } 556 557 ucl_add_tabs (func, tabs, is_top); 558 if (!is_top) { 559 func->ucl_emitter_append_character ('}', 1, func->ud); 560 } 561} 562 563/** 564 * Write a single array to the buffer 565 * @param obj array to write 566 * @param buf target buffer 567 */ 568static void 569ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 570 unsigned int tabs, bool start_tabs, bool is_top) 571{ 572 ucl_object_t *cur = obj; 573 574 if (start_tabs) { 575 ucl_add_tabs (func, tabs, false); 576 } 577 578 func->ucl_emitter_append_len ("[\n", 2, func->ud); 579 while (cur) { 580 ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false); 581 func->ucl_emitter_append_len (",\n", 2, func->ud); 582 cur = cur->next; 583 } 584 ucl_add_tabs (func, tabs, false); 585 func->ucl_emitter_append_character (']', 1, func->ud); 586} 587 588/** 589 * Emit a single element 590 * @param obj object 591 * @param buf buffer 592 */ 593static void 594ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 595 unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 596{ 597 bool flag; 598 599 if (expand_array && obj->next != NULL ) { 600 ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top); 601 } 602 else { 603 switch (obj->type) { 604 case UCL_INT: 605 if (start_tabs) { 606 ucl_add_tabs (func, tabs, false); 607 } 608 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 609 break; 610 case UCL_FLOAT: 611 case UCL_TIME: 612 if (start_tabs) { 613 ucl_add_tabs (func, tabs, false); 614 } 615 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 616 break; 617 case UCL_BOOLEAN: 618 if (start_tabs) { 619 ucl_add_tabs (func, tabs, false); 620 } 621 flag = ucl_object_toboolean (obj); 622 if (flag) { 623 func->ucl_emitter_append_len ("true", 4, func->ud); 624 } 625 else { 626 func->ucl_emitter_append_len ("false", 5, func->ud); 627 } 628 break; 629 case UCL_STRING: 630 if (start_tabs) { 631 ucl_add_tabs (func, tabs, false); 632 } 633 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 634 break; 635 case UCL_NULL: 636 if (start_tabs) { 637 ucl_add_tabs (func, tabs, false); 638 } 639 func->ucl_emitter_append_len ("null", 4, func->ud); 640 break; 641 case UCL_OBJECT: 642 ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top); 643 break; 644 case UCL_ARRAY: 645 ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top); 646 break; 647 case UCL_USERDATA: 648 break; 649 } 650 } 651} 652 653/** 654 * Emit an object to rcl 655 * @param obj object 656 * @return rcl output (should be freed after using) 657 */ 658static void 659ucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func) 660{ 661 ucl_elt_write_yaml (obj, func, 0, false, true, true); 662} 663 664/* 665 * Generic utstring output 666 */ 667static int 668ucl_utstring_append_character (unsigned char c, size_t len, void *ud) 669{ 670 UT_string *buf = ud; 671 672 if (len == 1) { 673 utstring_append_c (buf, c); 674 } 675 else { 676 utstring_reserve (buf, len); 677 memset (&buf->d[buf->i], c, len); 678 buf->i += len; 679 buf->d[buf->i] = '\0'; 680 } 681 682 return 0; 683} 684 685static int 686ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud) 687{ 688 UT_string *buf = ud; 689 690 utstring_append_len (buf, str, len); 691 692 return 0; 693} 694 695static int 696ucl_utstring_append_int (int64_t val, void *ud) 697{ 698 UT_string *buf = ud; 699 700 utstring_printf (buf, "%jd", (intmax_t)val); 701 return 0; 702} 703 704static int 705ucl_utstring_append_double (double val, void *ud) 706{ 707 UT_string *buf = ud; 708 const double delta = 0.0000001; 709 710 if (val == (double)(int)val) { 711 utstring_printf (buf, "%.1lf", val); 712 } 713 else if (fabs (val - (double)(int)val) < delta) { 714 /* Write at maximum precision */ 715 utstring_printf (buf, "%.*lg", DBL_DIG, val); 716 } 717 else { 718 utstring_printf (buf, "%lf", val); 719 } 720 721 return 0; 722} 723 724 725unsigned char * 726ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type) 727{ 728 UT_string *buf = NULL; 729 unsigned char *res = NULL; 730 struct ucl_emitter_functions func = { 731 .ucl_emitter_append_character = ucl_utstring_append_character, 732 .ucl_emitter_append_len = ucl_utstring_append_len, 733 .ucl_emitter_append_int = ucl_utstring_append_int, 734 .ucl_emitter_append_double = ucl_utstring_append_double 735 }; 736 737 if (obj == NULL) { 738 return NULL; 739 } 740 741 utstring_new (buf); 742 func.ud = buf; 743 744 if (buf != NULL) { 745 if (emit_type == UCL_EMIT_JSON) { 746 ucl_object_emit_json (obj, false, &func); 747 } 748 else if (emit_type == UCL_EMIT_JSON_COMPACT) { 749 ucl_object_emit_json (obj, true, &func); 750 } 751 else if (emit_type == UCL_EMIT_YAML) { 752 ucl_object_emit_yaml (obj, &func); 753 } 754 else { 755 ucl_object_emit_config (obj, &func); 756 } 757 758 res = utstring_body (buf); 759 free (buf); 760 } 761 762 return res; 763} 764 765bool 766ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, 767 struct ucl_emitter_functions *emitter) 768{ 769 if (emit_type == UCL_EMIT_JSON) { 770 ucl_object_emit_json (obj, false, emitter); 771 } 772 else if (emit_type == UCL_EMIT_JSON_COMPACT) { 773 ucl_object_emit_json (obj, true, emitter); 774 } 775 else if (emit_type == UCL_EMIT_YAML) { 776 ucl_object_emit_yaml (obj, emitter); 777 } 778 else { 779 ucl_object_emit_config (obj, emitter); 780 } 781 782 /* XXX: need some error checks here */ 783 return true; 784} 785 786 787unsigned char * 788ucl_object_emit_single_json (ucl_object_t *obj) 789{ 790 UT_string *buf = NULL; 791 unsigned char *res = NULL; 792 793 if (obj == NULL) { 794 return NULL; 795 } 796 797 utstring_new (buf); 798 799 if (buf != NULL) { 800 switch (obj->type) { 801 case UCL_OBJECT: 802 ucl_utstring_append_len ("object", 6, buf); 803 break; 804 case UCL_ARRAY: 805 ucl_utstring_append_len ("array", 5, buf); 806 break; 807 case UCL_INT: 808 ucl_utstring_append_int (obj->value.iv, buf); 809 break; 810 case UCL_FLOAT: 811 case UCL_TIME: 812 ucl_utstring_append_double (obj->value.dv, buf); 813 break; 814 case UCL_NULL: 815 ucl_utstring_append_len ("null", 4, buf); 816 break; 817 case UCL_BOOLEAN: 818 if (obj->value.iv) { 819 ucl_utstring_append_len ("true", 4, buf); 820 } 821 else { 822 ucl_utstring_append_len ("false", 5, buf); 823 } 824 break; 825 case UCL_STRING: 826 ucl_utstring_append_len (obj->value.sv, obj->len, buf); 827 break; 828 case UCL_USERDATA: 829 ucl_utstring_append_len ("userdata", 8, buf); 830 break; 831 } 832 res = utstring_body (buf); 833 free (buf); 834 } 835 836 return res; 837}
|