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 <float.h> 25 #include <math.h> 26 #include "ucl.h" 27 #include "ucl_internal.h" 28 #include "ucl_chartable.h" 29 30 /** 31 * @file rcl_emitter.c 32 * Serialise UCL object to various of output formats 33 */ 34 35 36 static 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); 41 static 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); 46 static 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); 52 static 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); 58 static 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 */ 69 static inline void 70 ucl_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 */ 82 static void 83 ucl_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 */ 138 static void 139 ucl_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 */ 190 static void 191 ucl_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 */ 229 static void 230 ucl_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 */ 289 static void 290 ucl_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 */ 333 static void 334 ucl_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 */ 344 static void 345 ucl_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 */ 396 static void 397 ucl_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 */ 421 static void 422 ucl_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 */ 486 static void 487 ucl_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 493 static void 494 ucl_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 */ 512 static void 513 ucl_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 */ 560 static void 561 ucl_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 */ 585 static void 586 ucl_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 */ 650 static void 651 ucl_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 */ 659 static int 660 ucl_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 677 static int 678 ucl_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 687 static int 688 ucl_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 696 static int 697 ucl_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 717 unsigned char * 718 ucl_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 757 bool 758 ucl_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 779 unsigned char * 780 ucl_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 } 830