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 print_key); \ 51 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ 52 const ucl_object_t *obj, 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 66 #define UCL_EMIT_TYPE_CONTENT(type) { \ 67 .ucl_emitter_write_elt = ucl_emit_ ## type ## _elt, \ 68 .ucl_emitter_start_object = ucl_emit_ ## type ##_start_obj, \ 69 .ucl_emitter_start_array = ucl_emit_ ## type ##_start_array, \ 70 .ucl_emitter_end_object = ucl_emit_ ## type ##_end_object, \ 71 .ucl_emitter_end_array = ucl_emit_ ## type ##_end_array \ 72 } 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 }; 81 82 /* 83 * Utility to check whether we need a top object 84 */ 85 #define UCL_EMIT_IDENT_TOP_OBJ(ctx, obj) ((ctx)->top != (obj) || \ 86 ((ctx)->id == UCL_EMIT_JSON_COMPACT || (ctx)->id == UCL_EMIT_JSON)) 87 88 89 /** 90 * Add tabulation to the output buffer 91 * @param buf target buffer 92 * @param tabs number of tabs to add 93 */ 94 static inline void 95 ucl_add_tabs (const struct ucl_emitter_functions *func, unsigned int tabs, 96 bool compact) 97 { 98 if (!compact && tabs > 0) { 99 func->ucl_emitter_append_character (' ', tabs * 4, func->ud); 100 } 101 } 102 103 /** 104 * Print key for the element 105 * @param ctx 106 * @param obj 107 */ 108 static void 109 ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx, 110 const ucl_object_t *obj, bool compact) 111 { 112 const struct ucl_emitter_functions *func = ctx->func; 113 114 if (!print_key) { 115 return; 116 } 117 118 if (ctx->id == UCL_EMIT_CONFIG) { 119 if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { 120 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 121 } 122 else { 123 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud); 124 } 125 126 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) { 127 func->ucl_emitter_append_len (" = ", 3, func->ud); 128 } 129 else { 130 func->ucl_emitter_append_character (' ', 1, func->ud); 131 } 132 } 133 else if (ctx->id == UCL_EMIT_YAML) { 134 if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) { 135 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 136 } 137 else if (obj->keylen > 0) { 138 func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud); 139 } 140 else { 141 func->ucl_emitter_append_len ("null", 4, func->ud); 142 } 143 144 func->ucl_emitter_append_len (": ", 2, func->ud); 145 } 146 else { 147 if (obj->keylen > 0) { 148 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 149 } 150 else { 151 func->ucl_emitter_append_len ("null", 4, func->ud); 152 } 153 154 if (compact) { 155 func->ucl_emitter_append_character (':', 1, func->ud); 156 } 157 else { 158 func->ucl_emitter_append_len (": ", 2, func->ud); 159 } 160 } 161 } 162 163 static void 164 ucl_emitter_finish_object (struct ucl_emitter_context *ctx, 165 const ucl_object_t *obj, bool compact, bool is_array) 166 { 167 const struct ucl_emitter_functions *func = ctx->func; 168 169 if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) { 170 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) { 171 if (!is_array) { 172 /* Objects are split by ';' */ 173 func->ucl_emitter_append_len (";\n", 2, func->ud); 174 } 175 else { 176 /* Use commas for arrays */ 177 func->ucl_emitter_append_len (",\n", 2, func->ud); 178 } 179 } 180 else { 181 func->ucl_emitter_append_character ('\n', 1, func->ud); 182 } 183 } 184 } 185 186 /** 187 * End standard ucl object 188 * @param ctx emitter context 189 * @param compact compact flag 190 */ 191 static void 192 ucl_emitter_common_end_object (struct ucl_emitter_context *ctx, 193 const ucl_object_t *obj, bool compact) 194 { 195 const struct ucl_emitter_functions *func = ctx->func; 196 197 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) { 198 ctx->indent --; 199 if (compact) { 200 func->ucl_emitter_append_character ('}', 1, func->ud); 201 } 202 else { 203 if (ctx->id != UCL_EMIT_CONFIG) { 204 /* newline is already added for this format */ 205 func->ucl_emitter_append_character ('\n', 1, func->ud); 206 } 207 ucl_add_tabs (func, ctx->indent, compact); 208 func->ucl_emitter_append_character ('}', 1, func->ud); 209 } 210 } 211 212 ucl_emitter_finish_object (ctx, obj, compact, false); 213 } 214 215 /** 216 * End standard ucl array 217 * @param ctx emitter context 218 * @param compact compact flag 219 */ 220 static void 221 ucl_emitter_common_end_array (struct ucl_emitter_context *ctx, 222 const ucl_object_t *obj, bool compact) 223 { 224 const struct ucl_emitter_functions *func = ctx->func; 225 226 ctx->indent --; 227 if (compact) { 228 func->ucl_emitter_append_character (']', 1, func->ud); 229 } 230 else { 231 if (ctx->id != UCL_EMIT_CONFIG) { 232 /* newline is already added for this format */ 233 func->ucl_emitter_append_character ('\n', 1, func->ud); 234 } 235 ucl_add_tabs (func, ctx->indent, compact); 236 func->ucl_emitter_append_character (']', 1, func->ud); 237 } 238 239 ucl_emitter_finish_object (ctx, obj, compact, true); 240 } 241 242 /** 243 * Start emit standard UCL array 244 * @param ctx emitter context 245 * @param obj object to write 246 * @param compact compact flag 247 */ 248 static void 249 ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, 250 const ucl_object_t *obj, bool print_key, bool compact) 251 { 252 const ucl_object_t *cur; 253 ucl_object_iter_t iter = NULL; 254 const struct ucl_emitter_functions *func = ctx->func; 255 bool first = true; 256 257 ucl_emitter_print_key (print_key, ctx, obj, compact); 258 259 if (compact) { 260 func->ucl_emitter_append_character ('[', 1, func->ud); 261 } 262 else { 263 func->ucl_emitter_append_len ("[\n", 2, func->ud); 264 } 265 266 ctx->indent ++; 267 268 if (obj->type == UCL_ARRAY) { 269 /* explicit array */ 270 while ((cur = ucl_iterate_object (obj, &iter, true)) != NULL) { 271 ucl_emitter_common_elt (ctx, cur, first, false, compact); 272 first = false; 273 } 274 } 275 else { 276 /* implicit array */ 277 cur = obj; 278 while (cur) { 279 ucl_emitter_common_elt (ctx, cur, first, false, compact); 280 first = false; 281 cur = cur->next; 282 } 283 } 284 285 286 } 287 288 /** 289 * Start emit standard UCL object 290 * @param ctx emitter context 291 * @param obj object to write 292 * @param compact compact flag 293 */ 294 static void 295 ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, 296 const ucl_object_t *obj, bool print_key, bool compact) 297 { 298 ucl_hash_iter_t it = NULL; 299 const ucl_object_t *cur, *elt; 300 const struct ucl_emitter_functions *func = ctx->func; 301 bool first = true; 302 303 ucl_emitter_print_key (print_key, ctx, obj, compact); 304 /* 305 * Print <ident_level>{ 306 * <ident_level + 1><object content> 307 */ 308 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) { 309 if (compact) { 310 func->ucl_emitter_append_character ('{', 1, func->ud); 311 } 312 else { 313 func->ucl_emitter_append_len ("{\n", 2, func->ud); 314 } 315 ctx->indent ++; 316 } 317 318 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 319 320 if (ctx->id == UCL_EMIT_CONFIG) { 321 LL_FOREACH (cur, elt) { 322 ucl_emitter_common_elt (ctx, elt, first, true, compact); 323 } 324 } 325 else { 326 /* Expand implicit arrays */ 327 if (cur->next != NULL) { 328 if (!first) { 329 if (compact) { 330 func->ucl_emitter_append_character (',', 1, func->ud); 331 } 332 else { 333 func->ucl_emitter_append_len (",\n", 2, func->ud); 334 } 335 } 336 ucl_add_tabs (func, ctx->indent, compact); 337 ucl_emitter_common_start_array (ctx, cur, true, compact); 338 ucl_emitter_common_end_array (ctx, cur, compact); 339 } 340 else { 341 ucl_emitter_common_elt (ctx, cur, first, true, compact); 342 } 343 } 344 345 first = false; 346 } 347 } 348 349 /** 350 * Common choice of object emitting 351 * @param ctx emitter context 352 * @param obj object to print 353 * @param first flag to mark the first element 354 * @param print_key print key of an object 355 * @param compact compact output 356 */ 357 static void 358 ucl_emitter_common_elt (struct ucl_emitter_context *ctx, 359 const ucl_object_t *obj, bool first, bool print_key, bool compact) 360 { 361 const struct ucl_emitter_functions *func = ctx->func; 362 bool flag; 363 struct ucl_object_userdata *ud; 364 const char *ud_out = ""; 365 366 if (ctx->id != UCL_EMIT_CONFIG && !first) { 367 if (compact) { 368 func->ucl_emitter_append_character (',', 1, func->ud); 369 } 370 else { 371 if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { 372 func->ucl_emitter_append_len ("\n", 1, func->ud); 373 } else { 374 func->ucl_emitter_append_len (",\n", 2, func->ud); 375 } 376 } 377 } 378 379 ucl_add_tabs (func, ctx->indent, compact); 380 381 switch (obj->type) { 382 case UCL_INT: 383 ucl_emitter_print_key (print_key, ctx, obj, compact); 384 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 385 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 386 break; 387 case UCL_FLOAT: 388 case UCL_TIME: 389 ucl_emitter_print_key (print_key, ctx, obj, compact); 390 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 391 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 392 break; 393 case UCL_BOOLEAN: 394 ucl_emitter_print_key (print_key, ctx, obj, compact); 395 flag = ucl_object_toboolean (obj); 396 if (flag) { 397 func->ucl_emitter_append_len ("true", 4, func->ud); 398 } 399 else { 400 func->ucl_emitter_append_len ("false", 5, func->ud); 401 } 402 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 403 break; 404 case UCL_STRING: 405 ucl_emitter_print_key (print_key, ctx, obj, compact); 406 if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) { 407 ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx); 408 } 409 else { 410 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx); 411 } 412 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 413 break; 414 case UCL_NULL: 415 ucl_emitter_print_key (print_key, ctx, obj, compact); 416 func->ucl_emitter_append_len ("null", 4, func->ud); 417 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 418 break; 419 case UCL_OBJECT: 420 ucl_emitter_common_start_object (ctx, obj, print_key, compact); 421 ucl_emitter_common_end_object (ctx, obj, compact); 422 break; 423 case UCL_ARRAY: 424 ucl_emitter_common_start_array (ctx, obj, print_key, compact); 425 ucl_emitter_common_end_array (ctx, obj, compact); 426 break; 427 case UCL_USERDATA: 428 ud = (struct ucl_object_userdata *)obj; 429 ucl_emitter_print_key (print_key, ctx, obj, compact); 430 if (ud->emitter) { 431 ud_out = ud->emitter (obj->value.ud); 432 if (ud_out == NULL) { 433 ud_out = "null"; 434 } 435 } 436 ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx); 437 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 438 break; 439 } 440 } 441 442 /* 443 * Specific standard implementations of the emitter functions 444 */ 445 #define UCL_EMIT_TYPE_IMPL(type, compact) \ 446 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \ 447 const ucl_object_t *obj, bool first, bool print_key) { \ 448 ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \ 449 } \ 450 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \ 451 const ucl_object_t *obj, bool print_key) { \ 452 ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \ 453 } \ 454 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ 455 const ucl_object_t *obj, bool print_key) { \ 456 ucl_emitter_common_start_array (ctx, obj, print_key, (compact)); \ 457 } \ 458 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \ 459 const ucl_object_t *obj) { \ 460 ucl_emitter_common_end_object (ctx, obj, (compact)); \ 461 } \ 462 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \ 463 const ucl_object_t *obj) { \ 464 ucl_emitter_common_end_array (ctx, obj, (compact)); \ 465 } 466 467 UCL_EMIT_TYPE_IMPL(json, false) 468 UCL_EMIT_TYPE_IMPL(json_compact, true) 469 UCL_EMIT_TYPE_IMPL(config, false) 470 UCL_EMIT_TYPE_IMPL(yaml, false) 471 472 unsigned char * 473 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type) 474 { 475 unsigned char *res = NULL; 476 struct ucl_emitter_functions *func; 477 if (obj == NULL) { 478 return NULL; 479 } 480 481 func = ucl_object_emit_memory_funcs ((void **)&res); 482 483 if (func != NULL) { 484 ucl_object_emit_full (obj, emit_type, func); 485 ucl_object_emit_funcs_free (func); 486 } 487 488 return res; 489 } 490 491 bool 492 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type, 493 struct ucl_emitter_functions *emitter) 494 { 495 const struct ucl_emitter_context *ctx; 496 struct ucl_emitter_context my_ctx; 497 bool res = false; 498 499 ctx = ucl_emit_get_standard_context (emit_type); 500 if (ctx != NULL) { 501 memcpy (&my_ctx, ctx, sizeof (my_ctx)); 502 my_ctx.func = emitter; 503 my_ctx.indent = 0; 504 my_ctx.top = obj; 505 506 my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false); 507 res = true; 508 } 509 510 return res; 511 } 512