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 #ifdef HAVE_CONFIG_H 25 #include "config.h" 26 #endif 27 28 #include "ucl.h" 29 #include "ucl_internal.h" 30 #include "ucl_chartable.h" 31 #ifdef HAVE_FLOAT_H 32 #include <float.h> 33 #endif 34 #ifdef HAVE_MATH_H 35 #include <math.h> 36 #endif 37 38 /** 39 * @file rcl_emitter.c 40 * Serialise UCL object to various of output formats 41 */ 42 43 44 static void ucl_obj_write_json (const ucl_object_t *obj, 45 struct ucl_emitter_functions *func, 46 unsigned int tabs, 47 bool start_tabs, 48 bool compact); 49 static void ucl_elt_write_json (const ucl_object_t *obj, 50 struct ucl_emitter_functions *func, 51 unsigned int tabs, 52 bool start_tabs, 53 bool compact); 54 static void ucl_elt_write_config (const 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); 60 static void ucl_elt_write_yaml (const 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); 66 static void ucl_elt_array_write_yaml (const 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 */ 77 static inline void 78 ucl_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 */ 90 static void 91 ucl_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 */ 146 static void 147 ucl_elt_obj_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func, 148 unsigned int tabs, bool start_tabs, bool compact) 149 { 150 const 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 */ 198 static void 199 ucl_elt_array_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func, 200 unsigned int tabs, bool start_tabs, bool compact) 201 { 202 const 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 */ 237 static void 238 ucl_elt_write_json (const 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 */ 297 static void 298 ucl_obj_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func, 299 unsigned int tabs, bool start_tabs, bool compact) 300 { 301 const 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 */ 341 static void 342 ucl_object_emit_json (const ucl_object_t *obj, bool compact, 343 struct ucl_emitter_functions *func) 344 { 345 ucl_obj_write_json (obj, func, 0, false, compact); 346 } 347 348 /** 349 * Write a single object to the buffer 350 * @param obj object to write 351 * @param buf target buffer 352 */ 353 static void 354 ucl_elt_obj_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func, 355 unsigned int tabs, bool start_tabs, bool is_top) 356 { 357 const ucl_object_t *cur, *cur_obj; 358 ucl_hash_iter_t it = NULL; 359 360 if (start_tabs) { 361 ucl_add_tabs (func, tabs, is_top); 362 } 363 if (!is_top) { 364 func->ucl_emitter_append_len ("{\n", 2, func->ud); 365 } 366 367 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 368 LL_FOREACH (cur, cur_obj) { 369 ucl_add_tabs (func, tabs + 1, is_top); 370 if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { 371 ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func); 372 } 373 else { 374 func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud); 375 } 376 if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 377 func->ucl_emitter_append_len (" = ", 3, func->ud); 378 } 379 else { 380 func->ucl_emitter_append_character (' ', 1, func->ud); 381 } 382 ucl_elt_write_config (cur_obj, func, 383 is_top ? tabs : tabs + 1, 384 false, false, false); 385 if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 386 func->ucl_emitter_append_len (";\n", 2, func->ud); 387 } 388 else { 389 func->ucl_emitter_append_character ('\n', 1, func->ud); 390 } 391 } 392 } 393 394 ucl_add_tabs (func, tabs, is_top); 395 if (!is_top) { 396 func->ucl_emitter_append_character ('}', 1, func->ud); 397 } 398 } 399 400 /** 401 * Write a single array to the buffer 402 * @param obj array to write 403 * @param buf target buffer 404 */ 405 static void 406 ucl_elt_array_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func, 407 unsigned int tabs, bool start_tabs, bool is_top) 408 { 409 const ucl_object_t *cur = obj; 410 411 if (start_tabs) { 412 ucl_add_tabs (func, tabs, false); 413 } 414 415 func->ucl_emitter_append_len ("[\n", 2, func->ud); 416 while (cur) { 417 ucl_elt_write_config (cur, func, tabs + 1, true, false, false); 418 func->ucl_emitter_append_len (",\n", 2, func->ud); 419 cur = cur->next; 420 } 421 ucl_add_tabs (func, tabs, false); 422 func->ucl_emitter_append_character (']', 1, func->ud); 423 } 424 425 /** 426 * Emit a single element 427 * @param obj object 428 * @param buf buffer 429 */ 430 static void 431 ucl_elt_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func, 432 unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 433 { 434 bool flag; 435 436 if (expand_array && obj->next != NULL) { 437 ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top); 438 } 439 else { 440 switch (obj->type) { 441 case UCL_INT: 442 if (start_tabs) { 443 ucl_add_tabs (func, tabs, false); 444 } 445 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 446 break; 447 case UCL_FLOAT: 448 case UCL_TIME: 449 if (start_tabs) { 450 ucl_add_tabs (func, tabs, false); 451 } 452 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 453 break; 454 case UCL_BOOLEAN: 455 if (start_tabs) { 456 ucl_add_tabs (func, tabs, false); 457 } 458 flag = ucl_object_toboolean (obj); 459 if (flag) { 460 func->ucl_emitter_append_len ("true", 4, func->ud); 461 } 462 else { 463 func->ucl_emitter_append_len ("false", 5, func->ud); 464 } 465 break; 466 case UCL_STRING: 467 if (start_tabs) { 468 ucl_add_tabs (func, tabs, false); 469 } 470 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 471 break; 472 case UCL_NULL: 473 if (start_tabs) { 474 ucl_add_tabs (func, tabs, false); 475 } 476 func->ucl_emitter_append_len ("null", 4, func->ud); 477 break; 478 case UCL_OBJECT: 479 ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top); 480 break; 481 case UCL_ARRAY: 482 ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top); 483 break; 484 case UCL_USERDATA: 485 break; 486 } 487 } 488 } 489 490 /** 491 * Emit an object to rcl 492 * @param obj object 493 * @return rcl output (should be freed after using) 494 */ 495 static void 496 ucl_object_emit_config (const ucl_object_t *obj, struct ucl_emitter_functions *func) 497 { 498 ucl_elt_write_config (obj, func, 0, false, true, true); 499 } 500 501 502 static void 503 ucl_obj_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func, 504 unsigned int tabs, bool start_tabs) 505 { 506 bool is_array = (obj->next != NULL); 507 508 if (is_array) { 509 ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false); 510 } 511 else { 512 ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true); 513 } 514 } 515 516 /** 517 * Write a single object to the buffer 518 * @param obj object to write 519 * @param buf target buffer 520 */ 521 static void 522 ucl_elt_obj_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func, 523 unsigned int tabs, bool start_tabs, bool is_top) 524 { 525 const ucl_object_t *cur; 526 ucl_hash_iter_t it = NULL; 527 528 if (start_tabs) { 529 ucl_add_tabs (func, tabs, is_top); 530 } 531 if (!is_top) { 532 func->ucl_emitter_append_len ("{\n", 2, func->ud); 533 } 534 535 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 536 ucl_add_tabs (func, tabs + 1, is_top); 537 if (cur->keylen > 0) { 538 ucl_elt_string_write_json (cur->key, cur->keylen, func); 539 } 540 else { 541 func->ucl_emitter_append_len ("null", 4, func->ud); 542 } 543 func->ucl_emitter_append_len (": ", 2, func->ud); 544 ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false); 545 if (ucl_hash_iter_has_next(it)) { 546 if (!is_top) { 547 func->ucl_emitter_append_len (",\n", 2, func->ud); 548 } 549 else { 550 func->ucl_emitter_append_character ('\n', 1, func->ud); 551 } 552 } 553 else { 554 func->ucl_emitter_append_character ('\n', 1, func->ud); 555 } 556 } 557 558 ucl_add_tabs (func, tabs, is_top); 559 if (!is_top) { 560 func->ucl_emitter_append_character ('}', 1, func->ud); 561 } 562 } 563 564 /** 565 * Write a single array to the buffer 566 * @param obj array to write 567 * @param buf target buffer 568 */ 569 static void 570 ucl_elt_array_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func, 571 unsigned int tabs, bool start_tabs, bool is_top) 572 { 573 const ucl_object_t *cur = obj; 574 575 if (start_tabs) { 576 ucl_add_tabs (func, tabs, false); 577 } 578 579 func->ucl_emitter_append_len ("[\n", 2, func->ud); 580 while (cur) { 581 ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false); 582 func->ucl_emitter_append_len (",\n", 2, func->ud); 583 cur = cur->next; 584 } 585 ucl_add_tabs (func, tabs, false); 586 func->ucl_emitter_append_character (']', 1, func->ud); 587 } 588 589 /** 590 * Emit a single element 591 * @param obj object 592 * @param buf buffer 593 */ 594 static void 595 ucl_elt_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func, 596 unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 597 { 598 bool flag; 599 600 if (expand_array && obj->next != NULL ) { 601 ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top); 602 } 603 else { 604 switch (obj->type) { 605 case UCL_INT: 606 if (start_tabs) { 607 ucl_add_tabs (func, tabs, false); 608 } 609 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 610 break; 611 case UCL_FLOAT: 612 case UCL_TIME: 613 if (start_tabs) { 614 ucl_add_tabs (func, tabs, false); 615 } 616 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 617 break; 618 case UCL_BOOLEAN: 619 if (start_tabs) { 620 ucl_add_tabs (func, tabs, false); 621 } 622 flag = ucl_object_toboolean (obj); 623 if (flag) { 624 func->ucl_emitter_append_len ("true", 4, func->ud); 625 } 626 else { 627 func->ucl_emitter_append_len ("false", 5, func->ud); 628 } 629 break; 630 case UCL_STRING: 631 if (start_tabs) { 632 ucl_add_tabs (func, tabs, false); 633 } 634 ucl_elt_string_write_json (obj->value.sv, obj->len, func); 635 break; 636 case UCL_NULL: 637 if (start_tabs) { 638 ucl_add_tabs (func, tabs, false); 639 } 640 func->ucl_emitter_append_len ("null", 4, func->ud); 641 break; 642 case UCL_OBJECT: 643 ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top); 644 break; 645 case UCL_ARRAY: 646 ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top); 647 break; 648 case UCL_USERDATA: 649 break; 650 } 651 } 652 } 653 654 /** 655 * Emit an object to rcl 656 * @param obj object 657 * @return rcl output (should be freed after using) 658 */ 659 static void 660 ucl_object_emit_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func) 661 { 662 ucl_elt_write_yaml (obj, func, 0, false, true, true); 663 } 664 665 /* 666 * Generic utstring output 667 */ 668 static int 669 ucl_utstring_append_character (unsigned char c, size_t len, void *ud) 670 { 671 UT_string *buf = ud; 672 673 if (len == 1) { 674 utstring_append_c (buf, c); 675 } 676 else { 677 utstring_reserve (buf, len); 678 memset (&buf->d[buf->i], c, len); 679 buf->i += len; 680 buf->d[buf->i] = '\0'; 681 } 682 683 return 0; 684 } 685 686 static int 687 ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud) 688 { 689 UT_string *buf = ud; 690 691 utstring_append_len (buf, str, len); 692 693 return 0; 694 } 695 696 static int 697 ucl_utstring_append_int (int64_t val, void *ud) 698 { 699 UT_string *buf = ud; 700 701 utstring_printf (buf, "%jd", (intmax_t)val); 702 return 0; 703 } 704 705 static int 706 ucl_utstring_append_double (double val, void *ud) 707 { 708 UT_string *buf = ud; 709 const double delta = 0.0000001; 710 711 if (val == (double)(int)val) { 712 utstring_printf (buf, "%.1lf", val); 713 } 714 else if (fabs (val - (double)(int)val) < delta) { 715 /* Write at maximum precision */ 716 utstring_printf (buf, "%.*lg", DBL_DIG, val); 717 } 718 else { 719 utstring_printf (buf, "%lf", val); 720 } 721 722 return 0; 723 } 724 725 726 unsigned char * 727 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type) 728 { 729 UT_string *buf = NULL; 730 unsigned char *res = NULL; 731 struct ucl_emitter_functions func = { 732 .ucl_emitter_append_character = ucl_utstring_append_character, 733 .ucl_emitter_append_len = ucl_utstring_append_len, 734 .ucl_emitter_append_int = ucl_utstring_append_int, 735 .ucl_emitter_append_double = ucl_utstring_append_double 736 }; 737 738 if (obj == NULL) { 739 return NULL; 740 } 741 742 utstring_new (buf); 743 func.ud = buf; 744 745 if (buf != NULL) { 746 if (emit_type == UCL_EMIT_JSON) { 747 ucl_object_emit_json (obj, false, &func); 748 } 749 else if (emit_type == UCL_EMIT_JSON_COMPACT) { 750 ucl_object_emit_json (obj, true, &func); 751 } 752 else if (emit_type == UCL_EMIT_YAML) { 753 ucl_object_emit_yaml (obj, &func); 754 } 755 else { 756 ucl_object_emit_config (obj, &func); 757 } 758 759 res = utstring_body (buf); 760 free (buf); 761 } 762 763 return res; 764 } 765 766 bool 767 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type, 768 struct ucl_emitter_functions *emitter) 769 { 770 if (emit_type == UCL_EMIT_JSON) { 771 ucl_object_emit_json (obj, false, emitter); 772 } 773 else if (emit_type == UCL_EMIT_JSON_COMPACT) { 774 ucl_object_emit_json (obj, true, emitter); 775 } 776 else if (emit_type == UCL_EMIT_YAML) { 777 ucl_object_emit_yaml (obj, emitter); 778 } 779 else { 780 ucl_object_emit_config (obj, emitter); 781 } 782 783 /* XXX: need some error checks here */ 784 return true; 785 } 786 787 788 unsigned char * 789 ucl_object_emit_single_json (const ucl_object_t *obj) 790 { 791 UT_string *buf = NULL; 792 unsigned char *res = NULL; 793 794 if (obj == NULL) { 795 return NULL; 796 } 797 798 utstring_new (buf); 799 800 if (buf != NULL) { 801 switch (obj->type) { 802 case UCL_OBJECT: 803 ucl_utstring_append_len ("object", 6, buf); 804 break; 805 case UCL_ARRAY: 806 ucl_utstring_append_len ("array", 5, buf); 807 break; 808 case UCL_INT: 809 ucl_utstring_append_int (obj->value.iv, buf); 810 break; 811 case UCL_FLOAT: 812 case UCL_TIME: 813 ucl_utstring_append_double (obj->value.dv, buf); 814 break; 815 case UCL_NULL: 816 ucl_utstring_append_len ("null", 4, buf); 817 break; 818 case UCL_BOOLEAN: 819 if (obj->value.iv) { 820 ucl_utstring_append_len ("true", 4, buf); 821 } 822 else { 823 ucl_utstring_append_len ("false", 5, buf); 824 } 825 break; 826 case UCL_STRING: 827 ucl_utstring_append_len (obj->value.sv, obj->len, buf); 828 break; 829 case UCL_USERDATA: 830 ucl_utstring_append_len ("userdata", 8, buf); 831 break; 832 } 833 res = utstring_body (buf); 834 free (buf); 835 } 836 837 return res; 838 } 839