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 { 134 if (obj->keylen > 0) { 135 ucl_elt_string_write_json (obj->key, obj->keylen, ctx); 136 } 137 else { 138 func->ucl_emitter_append_len ("null", 4, func->ud); 139 } 140 141 if (compact) { 142 func->ucl_emitter_append_character (':', 1, func->ud); 143 } 144 else { 145 func->ucl_emitter_append_len (": ", 2, func->ud); 146 } 147 } 148 } 149 150 static void 151 ucl_emitter_finish_object (struct ucl_emitter_context *ctx, 152 const ucl_object_t *obj, bool compact, bool is_array) 153 { 154 const struct ucl_emitter_functions *func = ctx->func; 155 156 if (ctx->id == UCL_EMIT_CONFIG && obj != ctx->top) { 157 if (obj->type != UCL_OBJECT && obj->type != UCL_ARRAY) { 158 if (!is_array) { 159 /* Objects are split by ';' */ 160 func->ucl_emitter_append_len (";\n", 2, func->ud); 161 } 162 else { 163 /* Use commas for arrays */ 164 func->ucl_emitter_append_len (",\n", 2, func->ud); 165 } 166 } 167 else { 168 func->ucl_emitter_append_character ('\n', 1, func->ud); 169 } 170 } 171 } 172 173 /** 174 * End standard ucl object 175 * @param ctx emitter context 176 * @param compact compact flag 177 */ 178 static void 179 ucl_emitter_common_end_object (struct ucl_emitter_context *ctx, 180 const ucl_object_t *obj, bool compact) 181 { 182 const struct ucl_emitter_functions *func = ctx->func; 183 184 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) { 185 ctx->ident --; 186 if (compact) { 187 func->ucl_emitter_append_character ('}', 1, func->ud); 188 } 189 else { 190 if (ctx->id != UCL_EMIT_CONFIG) { 191 /* newline is already added for this format */ 192 func->ucl_emitter_append_character ('\n', 1, func->ud); 193 } 194 ucl_add_tabs (func, ctx->ident, compact); 195 func->ucl_emitter_append_character ('}', 1, func->ud); 196 } 197 } 198 199 ucl_emitter_finish_object (ctx, obj, compact, false); 200 } 201 202 /** 203 * End standard ucl array 204 * @param ctx emitter context 205 * @param compact compact flag 206 */ 207 static void 208 ucl_emitter_common_end_array (struct ucl_emitter_context *ctx, 209 const ucl_object_t *obj, bool compact) 210 { 211 const struct ucl_emitter_functions *func = ctx->func; 212 213 ctx->ident --; 214 if (compact) { 215 func->ucl_emitter_append_character (']', 1, func->ud); 216 } 217 else { 218 if (ctx->id != UCL_EMIT_CONFIG) { 219 /* newline is already added for this format */ 220 func->ucl_emitter_append_character ('\n', 1, func->ud); 221 } 222 ucl_add_tabs (func, ctx->ident, compact); 223 func->ucl_emitter_append_character (']', 1, func->ud); 224 } 225 226 ucl_emitter_finish_object (ctx, obj, compact, true); 227 } 228 229 /** 230 * Start emit standard UCL array 231 * @param ctx emitter context 232 * @param obj object to write 233 * @param compact compact flag 234 */ 235 static void 236 ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, 237 const ucl_object_t *obj, bool print_key, bool compact) 238 { 239 const ucl_object_t *cur; 240 const struct ucl_emitter_functions *func = ctx->func; 241 bool first = true; 242 243 ucl_emitter_print_key (print_key, ctx, obj, compact); 244 245 if (compact) { 246 func->ucl_emitter_append_character ('[', 1, func->ud); 247 } 248 else { 249 func->ucl_emitter_append_len ("[\n", 2, func->ud); 250 } 251 252 ctx->ident ++; 253 254 if (obj->type == UCL_ARRAY) { 255 /* explicit array */ 256 cur = obj->value.av; 257 } 258 else { 259 /* implicit array */ 260 cur = obj; 261 } 262 263 while (cur) { 264 ucl_emitter_common_elt (ctx, cur, first, false, compact); 265 first = false; 266 cur = cur->next; 267 } 268 } 269 270 /** 271 * Start emit standard UCL object 272 * @param ctx emitter context 273 * @param obj object to write 274 * @param compact compact flag 275 */ 276 static void 277 ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, 278 const ucl_object_t *obj, bool print_key, bool compact) 279 { 280 ucl_hash_iter_t it = NULL; 281 const ucl_object_t *cur, *elt; 282 const struct ucl_emitter_functions *func = ctx->func; 283 bool first = true; 284 285 ucl_emitter_print_key (print_key, ctx, obj, compact); 286 /* 287 * Print <ident_level>{ 288 * <ident_level + 1><object content> 289 */ 290 if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) { 291 if (compact) { 292 func->ucl_emitter_append_character ('{', 1, func->ud); 293 } 294 else { 295 func->ucl_emitter_append_len ("{\n", 2, func->ud); 296 } 297 ctx->ident ++; 298 } 299 300 while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 301 302 if (ctx->id == UCL_EMIT_CONFIG) { 303 LL_FOREACH (cur, elt) { 304 ucl_emitter_common_elt (ctx, elt, first, true, compact); 305 } 306 } 307 else { 308 /* Expand implicit arrays */ 309 if (cur->next != NULL) { 310 if (!first) { 311 if (compact) { 312 func->ucl_emitter_append_character (',', 1, func->ud); 313 } 314 else { 315 func->ucl_emitter_append_len (",\n", 2, func->ud); 316 } 317 } 318 ucl_add_tabs (func, ctx->ident, compact); 319 ucl_emitter_common_start_array (ctx, cur, true, compact); 320 ucl_emitter_common_end_array (ctx, cur, compact); 321 } 322 else { 323 ucl_emitter_common_elt (ctx, cur, first, true, compact); 324 } 325 } 326 327 first = false; 328 } 329 } 330 331 /** 332 * Common choice of object emitting 333 * @param ctx emitter context 334 * @param obj object to print 335 * @param first flag to mark the first element 336 * @param print_key print key of an object 337 * @param compact compact output 338 */ 339 static void 340 ucl_emitter_common_elt (struct ucl_emitter_context *ctx, 341 const ucl_object_t *obj, bool first, bool print_key, bool compact) 342 { 343 const struct ucl_emitter_functions *func = ctx->func; 344 bool flag; 345 346 if (ctx->id != UCL_EMIT_CONFIG && !first) { 347 if (compact) { 348 func->ucl_emitter_append_character (',', 1, func->ud); 349 } 350 else { 351 func->ucl_emitter_append_len (",\n", 2, func->ud); 352 } 353 } 354 355 ucl_add_tabs (func, ctx->ident, compact); 356 357 switch (obj->type) { 358 case UCL_INT: 359 ucl_emitter_print_key (print_key, ctx, obj, compact); 360 func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 361 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 362 break; 363 case UCL_FLOAT: 364 case UCL_TIME: 365 ucl_emitter_print_key (print_key, ctx, obj, compact); 366 func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 367 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 368 break; 369 case UCL_BOOLEAN: 370 ucl_emitter_print_key (print_key, ctx, obj, compact); 371 flag = ucl_object_toboolean (obj); 372 if (flag) { 373 func->ucl_emitter_append_len ("true", 4, func->ud); 374 } 375 else { 376 func->ucl_emitter_append_len ("false", 5, func->ud); 377 } 378 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 379 break; 380 case UCL_STRING: 381 ucl_emitter_print_key (print_key, ctx, obj, compact); 382 ucl_elt_string_write_json (obj->value.sv, obj->len, ctx); 383 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 384 break; 385 case UCL_NULL: 386 ucl_emitter_print_key (print_key, ctx, obj, compact); 387 func->ucl_emitter_append_len ("null", 4, func->ud); 388 ucl_emitter_finish_object (ctx, obj, compact, !print_key); 389 break; 390 case UCL_OBJECT: 391 ucl_emitter_common_start_object (ctx, obj, print_key, compact); 392 ucl_emitter_common_end_object (ctx, obj, compact); 393 break; 394 case UCL_ARRAY: 395 ucl_emitter_common_start_array (ctx, obj, print_key, compact); 396 ucl_emitter_common_end_array (ctx, obj, compact); 397 break; 398 case UCL_USERDATA: 399 break; 400 } 401 } 402 403 /* 404 * Specific standard implementations of the emitter functions 405 */ 406 #define UCL_EMIT_TYPE_IMPL(type, compact) \ 407 static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx, \ 408 const ucl_object_t *obj, bool first, bool print_key) { \ 409 ucl_emitter_common_elt (ctx, obj, first, print_key, (compact)); \ 410 } \ 411 static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx, \ 412 const ucl_object_t *obj, bool print_key) { \ 413 ucl_emitter_common_start_object (ctx, obj, print_key, (compact)); \ 414 } \ 415 static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx, \ 416 const ucl_object_t *obj, bool print_key) { \ 417 ucl_emitter_common_start_array (ctx, obj, print_key, (compact)); \ 418 } \ 419 static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx, \ 420 const ucl_object_t *obj) { \ 421 ucl_emitter_common_end_object (ctx, obj, (compact)); \ 422 } \ 423 static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx, \ 424 const ucl_object_t *obj) { \ 425 ucl_emitter_common_end_array (ctx, obj, (compact)); \ 426 } 427 428 UCL_EMIT_TYPE_IMPL(json, false); 429 UCL_EMIT_TYPE_IMPL(json_compact, true); 430 UCL_EMIT_TYPE_IMPL(config, false); 431 UCL_EMIT_TYPE_IMPL(yaml, false); 432 433 unsigned char * 434 ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type) 435 { 436 unsigned char *res = NULL; 437 struct ucl_emitter_functions *func; 438 if (obj == NULL) { 439 return NULL; 440 } 441 442 func = ucl_object_emit_memory_funcs ((void **)&res); 443 444 if (func != NULL) { 445 ucl_object_emit_full (obj, emit_type, func); 446 ucl_object_emit_funcs_free (func); 447 } 448 449 return res; 450 } 451 452 bool 453 ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type, 454 struct ucl_emitter_functions *emitter) 455 { 456 const struct ucl_emitter_context *ctx; 457 struct ucl_emitter_context my_ctx; 458 bool res = false; 459 460 ctx = ucl_emit_get_standard_context (emit_type); 461 if (ctx != NULL) { 462 memcpy (&my_ctx, ctx, sizeof (my_ctx)); 463 my_ctx.func = emitter; 464 my_ctx.ident = 0; 465 my_ctx.top = obj; 466 467 my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false); 468 res = true; 469 } 470 471 return res; 472 } 473