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 (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 (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 (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 (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 (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 (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 */ 198 static void 199 ucl_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 */ 237 static void 238 ucl_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 */ 297 static void 298 ucl_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 */ 341 static void 342 ucl_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 */ 352 static void 353 ucl_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 */ 404 static void 405 ucl_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 */ 429 static void 430 ucl_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 */ 494 static void 495 ucl_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 501 static void 502 ucl_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 */ 520 static void 521 ucl_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 */ 568 static void 569 ucl_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 */ 593 static void 594 ucl_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 */ 658 static void 659 ucl_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 */ 667 static int 668 ucl_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 685 static int 686 ucl_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 695 static int 696 ucl_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 704 static int 705 ucl_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 725 unsigned char * 726 ucl_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 765 bool 766 ucl_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 787 unsigned char * 788 ucl_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 } 838