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 ucl_emitter.c 40 * Serialise UCL object to various of output formats 41 */ 42 43 static void ucl_emitter_common_elt (struct ucl_emitter_context *ctx, 44 const ucl_object_t *obj, bool first, bool print_key, bool compact); 45 46 #define UCL_EMIT_TYPE_OPS(type) \ 47 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \ 48 const ucl_object_t *obj, bool first, bool print_key); \ 49 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \ 50 const ucl_object_t *obj, bool first, bool print_key); \ 51 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ 52 const ucl_object_t *obj, bool first, bool print_key); \ 53 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \ 54 const ucl_object_t *obj); \ 55 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \ 56 const ucl_object_t *obj) 57 58 /* 59 * JSON format operations 60 */ 61 UCL_EMIT_TYPE_OPS(json); 62 UCL_EMIT_TYPE_OPS(json_compact); 63 UCL_EMIT_TYPE_OPS(config); 64 UCL_EMIT_TYPE_OPS(yaml); 65 UCL_EMIT_TYPE_OPS(msgpack); 66 67 #define UCL_EMIT_TYPE_CONTENT(type) { \ 68 .ucl_emitter_write_elt = ucl_emit_ ## type ## _elt, \ 69 .ucl_emitter_start_object = ucl_emit_ ## type ##_start_obj, \ 70 .ucl_emitter_start_array = ucl_emit_ ## type ##_start_array, \ 71 .ucl_emitter_end_object = ucl_emit_ ## type ##_end_object, \ 72 .ucl_emitter_end_array = ucl_emit_ ## type ##_end_array \ 73 } 74 75 const struct ucl_emitter_operations ucl_standartd_emitter_ops[] = { 76 [UCL_EMIT_JSON] = UCL_EMIT_TYPE_CONTENT(json), 77 [UCL_EMIT_JSON_COMPACT] = UCL_EMIT_TYPE_CONTENT(json_compact), 78 [UCL_EMIT_CONFIG] = UCL_EMIT_TYPE_CONTENT(config), 79 [UCL_EMIT_YAML] = UCL_EMIT_TYPE_CONTENT(yaml), 80 [UCL_EMIT_MSGPACK] = UCL_EMIT_TYPE_CONTENT(msgpack) 81 }; 82 83 /* 84 * Utility to check whether we need a top object 85 */ 86 #define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \ 87 ((ctx)->id == UCL_EMIT_JSON_COMPACT || (ctx)->id == UCL_EMIT_JSON)) 88 89 90 /** 91 * Add tabulation to the output buffer 92 * @param buf target buffer 93 * @param tabs number of tabs to add 94 */ 95 static inline void 96 ucl_add_tabs (const struct ucl_emitter_functions *func, unsigned int tabs, 97 bool compact) 98 { 99 if (!compact && tabs > 0) { 100 func->ucl_emitter_append_character (' ', tabs * 4, func->ud); 101 } 102 } 103 104 /** 105 * Print key for the element 106 * @param ctx 107 * @param obj 108 */ 109 static void 110 ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx, 111 const ucl_object_t *obj, bool compact) 112 { 113 const struct ucl_emitter_functions *func = ctx->func; 114 115 if (!print_key) { 116 return; 117 } 118 119 if (ctx->id == UCL_EMIT_CONFIG) { 120 if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { 121 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 122 } 123 else { 124 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud); 125 } 126 127 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) { 128 func->ucl_emitter_append_len (" = ", 3, func->ud); 129 } 130 else { 131 func->ucl_emitter_append_character (' ', 1, func->ud); 132 } 133 } 134 else if (ctx->id == UCL_EMIT_YAML) { 135 if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) { 136 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 137 } 138 else if (obj->keylen > 0) { 139 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud); 140 } 141 else { 142 func->ucl_emitter_append_len ("null", 4, func->ud); 143 } 144 145 func->ucl_emitter_append_len (": ", 2, func->ud); 146 } 147 else { 148 if (obj->keylen > 0) { 149 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 150 } 151 else { 152 func->ucl_emitter_append_len ("null", 4, func->ud); 153 } 154 155 if (compact) { 156 func->ucl_emitter_append_character (':', 1, func->ud); 157 } 158 else { 159 func->ucl_emitter_append_len (": ", 2, func->ud); 160 } 161 } 162 } 163 164 static void 165 ucl_emitter_finish_object (struct ucl_emitter_context *ctx, 166 const ucl_object_t *obj, bool compact, bool is_array) 167 { 168 const struct ucl_emitter_functions *func = ctx->func; 169 170 if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) { 171 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) { 172 if (!is_array) { 173 /* Objects are split by ';' */ 174 func->ucl_emitter_append_len (";\n", 2, func->ud); 175 } 176 else { 177 /* Use commas for arrays */ 178 func->ucl_emitter_append_len (",\n", 2, func->ud); 179 } 180 } 181 else { 182 func->ucl_emitter_append_character ('\n', 1, func->ud); 183 } 184 } 185 } 186 187 /** 188 * End standard ucl object 189 * @param ctx emitter context 190 * @param compact compact flag 191 */ 192 static void 193 ucl_emitter_common_end_object (struct ucl_emitter_context *ctx, 194 const ucl_object_t *obj, bool compact) 195 { 196 const struct ucl_emitter_functions *func = ctx->func; 197 198 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) { 199 ctx->indent --; 200 if (compact) { 201 func->ucl_emitter_append_character ('}', 1, func->ud); 202 } 203 else { 204 if (ctx->id != UCL_EMIT_CONFIG) { 205 /* newline is already added for this format */ 206 func->ucl_emitter_append_character ('\n', 1, func->ud); 207 } 208 ucl_add_tabs (func, ctx->indent, compact); 209 func->ucl_emitter_append_character ('}', 1, func->ud); 210 } 211 } 212 213 ucl_emitter_finish_object (ctx, obj, compact, false); 214 } 215 216 /** 217 * End standard ucl array 218 * @param ctx emitter context 219 * @param compact compact flag 220 */ 221 static void 222 ucl_emitter_common_end_array (struct ucl_emitter_context *ctx, 223 const ucl_object_t *obj, bool compact) 224 { 225 const struct ucl_emitter_functions *func = ctx->func; 226 227 ctx->indent --; 228 if (compact) { 229 func->ucl_emitter_append_character (']', 1, func->ud); 230 } 231 else { 232 if (ctx->id != UCL_EMIT_CONFIG) { 233 /* newline is already added for this format */ 234 func->ucl_emitter_append_character ('\n', 1, func->ud); 235 } 236 ucl_add_tabs (func, ctx->indent, compact); 237 func->ucl_emitter_append_character (']', 1, func->ud); 238 } 239 240 ucl_emitter_finish_object (ctx, obj, compact, true); 241 } 242 243 /** 244 * Start emit standard UCL array 245 * @param ctx emitter context 246 * @param obj object to write 247 * @param compact compact flag 248 */ 249 static void 250 ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, 251 const ucl_object_t *obj, bool first, bool print_key, bool compact) 252 { 253 const ucl_object_t *cur; 254 ucl_object_iter_t iter = NULL; 255 const struct ucl_emitter_functions *func = ctx->func; 256 bool first_key = true; 257 258 if (ctx->id != UCL_EMIT_CONFIG && !first) { 259 if (compact) { 260 func->ucl_emitter_append_character (',', 1, func->ud); 261 } 262 else { 263 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { 264 func->ucl_emitter_append_len ("\n", 1, func->ud); 265 } else { 266 func->ucl_emitter_append_len (",\n", 2, func->ud); 267 } 268 } 269 ucl_add_tabs (func, ctx->indent, compact); 270 } 271 272 ucl_emitter_print_key (print_key, ctx, obj, compact); 273 274 if (compact) { 275 func->ucl_emitter_append_character ('[', 1, func->ud); 276 } 277 else { 278 func->ucl_emitter_append_len ("[\n", 2, func->ud); 279 } 280 281 ctx->indent ++; 282 283 if (obj->type == UCL_ARRAY) { 284 /* explicit array */ 285 while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) { 286 ucl_emitter_common_elt (ctx, cur, first_key, false, compact); 287 first_key = false; 288 } 289 } 290 else { 291 /* implicit array */ 292 cur = obj; 293 while (cur) { 294 ucl_emitter_common_elt (ctx, cur, first_key, false, compact); 295 first_key = false; 296 cur = cur->next; 297 } 298 } 299 300 301 } 302 303 /** 304 * Start emit standard UCL object 305 * @param ctx emitter context 306 * @param obj object to write 307 * @param compact compact flag 308 */ 309 static void 310 ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, 311 const ucl_object_t *obj, bool first, bool print_key, bool compact) 312 { 313 ucl_hash_iter_t it = NULL; 314 const ucl_object_t *cur, *elt; 315 const struct ucl_emitter_functions *func = ctx->func; 316 bool first_key = true; 317 318 if (ctx->id != UCL_EMIT_CONFIG && !first) { 319 if (compact) { 320 func->ucl_emitter_append_character (',', 1, func->ud); 321 } 322 else { 323 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { 324 func->ucl_emitter_append_len ("\n", 1, func->ud); 325 } else { 326 func->ucl_emitter_append_len (",\n", 2, func->ud); 327 } 328 } 329 ucl_add_tabs (func, ctx->indent, compact); 330 } 331 332 ucl_emitter_print_key (print_key, ctx, obj, compact); 333 /* 334 * Print <ident_level>{ 335 * <ident_level + 1><object content> 336 */ 337 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) { 338 if (compact) { 339 func->ucl_emitter_append_character ('{', 1, func->ud); 340 } 341 else { 342 func->ucl_emitter_append_len ("{\n", 2, func->ud); 343 } 344 ctx->indent ++; 345 } 346 347 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 348 349 if (ctx->id == UCL_EMIT_CONFIG) { 350 LL_FOREACH (cur, elt) { 351 ucl_emitter_common_elt (ctx, elt, first_key, true, compact); 352 } 353 } 354 else { 355 /* Expand implicit arrays */ 356 if (cur->next != NULL) { 357 if (!first_key) { 358 if (compact) { 359 func->ucl_emitter_append_character (',', 1, func->ud); 360 } 361 else { 362 func->ucl_emitter_append_len (",\n", 2, func->ud); 363 } 364 } 365 ucl_add_tabs (func, ctx->indent, compact); 366 ucl_emitter_common_start_array (ctx, cur, first_key, true, compact); 367 ucl_emitter_common_end_array (ctx, cur, compact); 368 } 369 else { 370 ucl_emitter_common_elt (ctx, cur, first_key, true, compact); 371 } 372 } 373 374 first_key = false; 375 } 376 } 377 378 /** 379 * Common choice of object emitting 380 * @param ctx emitter context 381 * @param obj object to print 382 * @param first flag to mark the first element 383 * @param print_key print key of an object 384 * @param compact compact output 385 */ 386 static void 387 ucl_emitter_common_elt (struct ucl_emitter_context *ctx, 388 const ucl_object_t *obj, bool first, bool print_key, bool compact) 389 { 390 const struct ucl_emitter_functions *func = ctx->func; 391 bool flag; 392 struct ucl_object_userdata *ud; 393 const ucl_object_t *comment = NULL, *cur_comment; 394 const char *ud_out = ""; 395 396 if (ctx->id != UCL_EMIT_CONFIG && !first) { 397 if (compact) { 398 func->ucl_emitter_append_character (',', 1, func->ud); 399 } 400 else { 401 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { 402 func->ucl_emitter_append_len ("\n", 1, func->ud); 403 } else { 404 func->ucl_emitter_append_len (",\n", 2, func->ud); 405 } 406 } 407 } 408 409 ucl_add_tabs (func, ctx->indent, compact); 410 411 if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) { 412 comment = ucl_object_lookup_len (ctx->comments, (const char *)&obj, 413 sizeof (void *)); 414 415 if (comment) { 416 if (!(comment->flags & UCL_OBJECT_INHERITED)) { 417 DL_FOREACH (comment, cur_comment) { 418 func->ucl_emitter_append_len (cur_comment->value.sv, 419 cur_comment->len, 420 func->ud); 421 func->ucl_emitter_append_character ('\n', 1, func->ud); 422 ucl_add_tabs (func, ctx->indent, compact); 423 } 424 425 comment = NULL; 426 } 427 } 428 } 429 430 switch (obj->type) { 431 case UCL_INT: 432 ucl_emitter_print_key (print_key, ctx, obj, compact); 433 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 434 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 435 break; 436 case UCL_FLOAT: 437 case UCL_TIME: 438 ucl_emitter_print_key (print_key, ctx, obj, compact); 439 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 440 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 441 break; 442 case UCL_BOOLEAN: 443 ucl_emitter_print_key (print_key, ctx, obj, compact); 444 flag = ucl_object_toboolean (obj); 445 if (flag) { 446 func->ucl_emitter_append_len ("true", 4, func->ud); 447 } 448 else { 449 func->ucl_emitter_append_len ("false", 5, func->ud); 450 } 451 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 452 break; 453 case UCL_STRING: 454 ucl_emitter_print_key (print_key, ctx, obj, compact); 455 if (ctx->id == UCL_EMIT_CONFIG) { 456 if (ucl_maybe_long_string (obj)) { 457 ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx); 458 } else { 459 if (obj->flags & UCL_OBJECT_SQUOTED) { 460 ucl_elt_string_write_squoted (obj->value.sv, obj->len, ctx); 461 } else { 462 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx); 463 } 464 } 465 } 466 else { 467 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx); 468 } 469 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 470 break; 471 case UCL_NULL: 472 ucl_emitter_print_key (print_key, ctx, obj, compact); 473 func->ucl_emitter_append_len ("null", 4, func->ud); 474 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 475 break; 476 case UCL_OBJECT: 477 ucl_emitter_common_start_object (ctx, obj, true, print_key, compact); 478 ucl_emitter_common_end_object (ctx, obj, compact); 479 break; 480 case UCL_ARRAY: 481 ucl_emitter_common_start_array (ctx, obj, true, print_key, compact); 482 ucl_emitter_common_end_array (ctx, obj, compact); 483 break; 484 case UCL_USERDATA: 485 ud = (struct ucl_object_userdata *)obj; 486 ucl_emitter_print_key (print_key, ctx, obj, compact); 487 if (ud->emitter) { 488 ud_out = ud->emitter (obj->value.ud); 489 if (ud_out == NULL) { 490 ud_out = "null"; 491 } 492 } 493 ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx); 494 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 495 break; 496 } 497 498 if (comment) { 499 DL_FOREACH (comment, cur_comment) { 500 func->ucl_emitter_append_len (cur_comment->value.sv, 501 cur_comment->len, 502 func->ud); 503 func->ucl_emitter_append_character ('\n', 1, func->ud); 504 505 if (cur_comment->next) { 506 ucl_add_tabs (func, ctx->indent, compact); 507 } 508 } 509 } 510 } 511 512 /* 513 * Specific standard implementations of the emitter functions 514 */ 515 #define UCL_EMIT_TYPE_IMPL(type, compact) \ 516 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \ 517 const ucl_object_t *obj, bool first, bool print_key) { \ 518 ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \ 519 } \ 520 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \ 521 const ucl_object_t *obj, bool first, bool print_key) { \ 522 ucl_emitter_common_start_object (ctx, obj, first, print_key, (compact)); \ 523 } \ 524 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ 525 const ucl_object_t *obj, bool first, bool print_key) { \ 526 ucl_emitter_common_start_array (ctx, obj, first, print_key, (compact)); \ 527 } \ 528 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \ 529 const ucl_object_t *obj) { \ 530 ucl_emitter_common_end_object (ctx, obj, (compact)); \ 531 } \ 532 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \ 533 const ucl_object_t *obj) { \ 534 ucl_emitter_common_end_array (ctx, obj, (compact)); \ 535 } 536 537 UCL_EMIT_TYPE_IMPL(json, false) 538 UCL_EMIT_TYPE_IMPL(json_compact, true) 539 UCL_EMIT_TYPE_IMPL(config, false) 540 UCL_EMIT_TYPE_IMPL(yaml, false) 541 542 static void 543 ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, 544 const ucl_object_t *obj, bool _first, bool print_key) 545 { 546 ucl_object_iter_t it; 547 struct ucl_object_userdata *ud; 548 const char *ud_out; 549 const ucl_object_t *cur, *celt; 550 551 switch (obj->type) { 552 case UCL_INT: 553 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 554 ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj)); 555 break; 556 557 case UCL_FLOAT: 558 case UCL_TIME: 559 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 560 ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj)); 561 break; 562 563 case UCL_BOOLEAN: 564 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 565 ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj)); 566 break; 567 568 case UCL_STRING: 569 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 570 571 if (obj->flags & UCL_OBJECT_BINARY) { 572 ucl_emitter_print_binary_string_msgpack (ctx, obj->value.sv, 573 obj->len); 574 } 575 else { 576 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len); 577 } 578 break; 579 580 case UCL_NULL: 581 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 582 ucl_emitter_print_null_msgpack (ctx); 583 break; 584 585 case UCL_OBJECT: 586 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 587 ucl_emit_msgpack_start_obj (ctx, obj, false, print_key); 588 it = NULL; 589 590 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { 591 LL_FOREACH (cur, celt) { 592 ucl_emit_msgpack_elt (ctx, celt, false, true); 593 /* XXX: 594 * in msgpack the length of objects is encoded within a single elt 595 * so in case of multi-value keys we are using merely the first 596 * element ignoring others 597 */ 598 break; 599 } 600 } 601 602 break; 603 604 case UCL_ARRAY: 605 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 606 ucl_emit_msgpack_start_array (ctx, obj, false, print_key); 607 it = NULL; 608 609 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { 610 ucl_emit_msgpack_elt (ctx, cur, false, false); 611 } 612 613 break; 614 615 case UCL_USERDATA: 616 ud = (struct ucl_object_userdata *)obj; 617 ucl_emitter_print_key_msgpack (print_key, ctx, obj); 618 619 if (ud->emitter) { 620 ud_out = ud->emitter (obj->value.ud); 621 if (ud_out == NULL) { 622 ud_out = "null"; 623 } 624 } 625 ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len); 626 break; 627 } 628 } 629 630 static void 631 ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx, 632 const ucl_object_t *obj, bool _first, bool _print_key) 633 { 634 ucl_emitter_print_object_msgpack (ctx, obj->len); 635 } 636 637 static void 638 ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx, 639 const ucl_object_t *obj, bool _first, bool _print_key) 640 { 641 ucl_emitter_print_array_msgpack (ctx, obj->len); 642 } 643 644 static void 645 ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx, 646 const ucl_object_t *obj) 647 { 648 649 } 650 651 static void 652 ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx, 653 const ucl_object_t *obj) 654 { 655 656 } 657 658 unsigned char * 659 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type) 660 { 661 return ucl_object_emit_len (obj, emit_type, NULL); 662 } 663 664 unsigned char * 665 ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type, 666 size_t *outlen) 667 { 668 unsigned char *res = NULL; 669 struct ucl_emitter_functions *func; 670 UT_string *s; 671 672 if (obj == NULL) { 673 return NULL; 674 } 675 676 func = ucl_object_emit_memory_funcs ((void **)&res); 677 678 if (func != NULL) { 679 s = func->ud; 680 ucl_object_emit_full (obj, emit_type, func, NULL); 681 682 if (outlen != NULL) { 683 *outlen = s->i; 684 } 685 686 ucl_object_emit_funcs_free (func); 687 } 688 689 return res; 690 } 691 692 bool 693 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type, 694 struct ucl_emitter_functions *emitter, 695 const ucl_object_t *comments) 696 { 697 const struct ucl_emitter_context *ctx; 698 struct ucl_emitter_context my_ctx; 699 bool res = false; 700 701 ctx = ucl_emit_get_standard_context (emit_type); 702 if (ctx != NULL) { 703 memcpy (&my_ctx, ctx, sizeof (my_ctx)); 704 my_ctx.func = emitter; 705 my_ctx.indent = 0; 706 my_ctx.top = obj; 707 my_ctx.comments = comments; 708 709 my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false); 710 res = true; 711 } 712 713 return res; 714 } 715