1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov 2262395Sbapt * All rights reserved. 3262395Sbapt * 4262395Sbapt * Redistribution and use in source and binary forms, with or without 5262395Sbapt * modification, are permitted provided that the following conditions are met: 6262395Sbapt * * Redistributions of source code must retain the above copyright 7262395Sbapt * notice, this list of conditions and the following disclaimer. 8262395Sbapt * * Redistributions in binary form must reproduce the above copyright 9262395Sbapt * notice, this list of conditions and the following disclaimer in the 10262395Sbapt * documentation and/or other materials provided with the distribution. 11262395Sbapt * 12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22262395Sbapt */ 23262395Sbapt 24262395Sbapt#include <float.h> 25262395Sbapt#include <math.h> 26262395Sbapt#include "ucl.h" 27262395Sbapt#include "ucl_internal.h" 28262395Sbapt#include "ucl_chartable.h" 29262395Sbapt 30262395Sbapt/** 31262395Sbapt * @file rcl_emitter.c 32262395Sbapt * Serialise UCL object to various of output formats 33262395Sbapt */ 34262395Sbapt 35262395Sbapt 36262395Sbaptstatic void ucl_obj_write_json (ucl_object_t *obj, 37262395Sbapt struct ucl_emitter_functions *func, 38262395Sbapt unsigned int tabs, 39262395Sbapt bool start_tabs, 40262395Sbapt bool compact); 41262395Sbaptstatic void ucl_elt_write_json (ucl_object_t *obj, 42262395Sbapt struct ucl_emitter_functions *func, 43262395Sbapt unsigned int tabs, 44262395Sbapt bool start_tabs, 45262395Sbapt bool compact); 46262395Sbaptstatic void ucl_elt_write_config (ucl_object_t *obj, 47262395Sbapt struct ucl_emitter_functions *func, 48262395Sbapt unsigned int tabs, 49262395Sbapt bool start_tabs, 50262395Sbapt bool is_top, 51262395Sbapt bool expand_array); 52262395Sbaptstatic void ucl_elt_write_yaml (ucl_object_t *obj, 53262395Sbapt struct ucl_emitter_functions *func, 54262395Sbapt unsigned int tabs, 55262395Sbapt bool start_tabs, 56262395Sbapt bool compact, 57262395Sbapt bool expand_array); 58262395Sbaptstatic void ucl_elt_array_write_yaml (ucl_object_t *obj, 59262395Sbapt struct ucl_emitter_functions *func, 60262395Sbapt unsigned int tabs, 61262395Sbapt bool start_tabs, 62262395Sbapt bool is_top); 63262395Sbapt 64262395Sbapt/** 65262395Sbapt * Add tabulation to the output buffer 66262395Sbapt * @param buf target buffer 67262395Sbapt * @param tabs number of tabs to add 68262395Sbapt */ 69262395Sbaptstatic inline void 70262395Sbaptucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact) 71262395Sbapt{ 72262395Sbapt if (!compact) { 73262395Sbapt func->ucl_emitter_append_character (' ', tabs * 4, func->ud); 74262395Sbapt } 75262395Sbapt} 76262395Sbapt 77262395Sbapt/** 78262395Sbapt * Serialise string 79262395Sbapt * @param str string to emit 80262395Sbapt * @param buf target buffer 81262395Sbapt */ 82262395Sbaptstatic void 83262395Sbaptucl_elt_string_write_json (const char *str, size_t size, 84262395Sbapt struct ucl_emitter_functions *func) 85262395Sbapt{ 86262395Sbapt const char *p = str, *c = str; 87262395Sbapt size_t len = 0; 88262395Sbapt 89262395Sbapt func->ucl_emitter_append_character ('"', 1, func->ud); 90262395Sbapt while (size) { 91262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 92262395Sbapt if (len > 0) { 93262395Sbapt func->ucl_emitter_append_len (c, len, func->ud); 94262395Sbapt } 95262395Sbapt switch (*p) { 96262395Sbapt case '\n': 97262395Sbapt func->ucl_emitter_append_len ("\\n", 2, func->ud); 98262395Sbapt break; 99262395Sbapt case '\r': 100262395Sbapt func->ucl_emitter_append_len ("\\r", 2, func->ud); 101262395Sbapt break; 102262395Sbapt case '\b': 103262395Sbapt func->ucl_emitter_append_len ("\\b", 2, func->ud); 104262395Sbapt break; 105262395Sbapt case '\t': 106262395Sbapt func->ucl_emitter_append_len ("\\t", 2, func->ud); 107262395Sbapt break; 108262395Sbapt case '\f': 109262395Sbapt func->ucl_emitter_append_len ("\\f", 2, func->ud); 110262395Sbapt break; 111262395Sbapt case '\\': 112262395Sbapt func->ucl_emitter_append_len ("\\\\", 2, func->ud); 113262395Sbapt break; 114262395Sbapt case '"': 115262395Sbapt func->ucl_emitter_append_len ("\\\"", 2, func->ud); 116262395Sbapt break; 117262395Sbapt } 118262395Sbapt len = 0; 119262395Sbapt c = ++p; 120262395Sbapt } 121262395Sbapt else { 122262395Sbapt p ++; 123262395Sbapt len ++; 124262395Sbapt } 125262395Sbapt size --; 126262395Sbapt } 127262395Sbapt if (len > 0) { 128262395Sbapt func->ucl_emitter_append_len (c, len, func->ud); 129262395Sbapt } 130262395Sbapt func->ucl_emitter_append_character ('"', 1, func->ud); 131262395Sbapt} 132262395Sbapt 133262395Sbapt/** 134262395Sbapt * Write a single object to the buffer 135262395Sbapt * @param obj object to write 136262395Sbapt * @param buf target buffer 137262395Sbapt */ 138262395Sbaptstatic void 139262395Sbaptucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 140262395Sbapt unsigned int tabs, bool start_tabs, bool compact) 141262395Sbapt{ 142262395Sbapt ucl_object_t *cur; 143262395Sbapt ucl_hash_iter_t it = NULL; 144262395Sbapt 145262395Sbapt if (start_tabs) { 146262395Sbapt ucl_add_tabs (func, tabs, compact); 147262395Sbapt } 148262395Sbapt if (compact) { 149262395Sbapt func->ucl_emitter_append_character ('{', 1, func->ud); 150262395Sbapt } 151262395Sbapt else { 152262395Sbapt func->ucl_emitter_append_len ("{\n", 2, func->ud); 153262395Sbapt } 154262395Sbapt while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 155262395Sbapt ucl_add_tabs (func, tabs + 1, compact); 156262395Sbapt if (cur->keylen > 0) { 157262395Sbapt ucl_elt_string_write_json (cur->key, cur->keylen, func); 158262395Sbapt } 159262395Sbapt else { 160262395Sbapt func->ucl_emitter_append_len ("null", 4, func->ud); 161262395Sbapt } 162262395Sbapt if (compact) { 163262395Sbapt func->ucl_emitter_append_character (':', 1, func->ud); 164262395Sbapt } 165262395Sbapt else { 166262395Sbapt func->ucl_emitter_append_len (": ", 2, func->ud); 167262395Sbapt } 168262395Sbapt ucl_obj_write_json (cur, func, tabs + 1, false, compact); 169262395Sbapt if (ucl_hash_iter_has_next (it)) { 170262395Sbapt if (compact) { 171262395Sbapt func->ucl_emitter_append_character (',', 1, func->ud); 172262395Sbapt } 173262395Sbapt else { 174262395Sbapt func->ucl_emitter_append_len (",\n", 2, func->ud); 175262395Sbapt } 176262395Sbapt } 177262395Sbapt else if (!compact) { 178262395Sbapt func->ucl_emitter_append_character ('\n', 1, func->ud); 179262395Sbapt } 180262395Sbapt } 181262395Sbapt ucl_add_tabs (func, tabs, compact); 182262395Sbapt func->ucl_emitter_append_character ('}', 1, func->ud); 183262395Sbapt} 184262395Sbapt 185262395Sbapt/** 186262395Sbapt * Write a single array to the buffer 187262395Sbapt * @param obj array to write 188262395Sbapt * @param buf target buffer 189262395Sbapt */ 190262395Sbaptstatic void 191262395Sbaptucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 192262395Sbapt unsigned int tabs, bool start_tabs, bool compact) 193262395Sbapt{ 194262395Sbapt ucl_object_t *cur = obj; 195262395Sbapt 196262395Sbapt if (start_tabs) { 197262395Sbapt ucl_add_tabs (func, tabs, compact); 198262395Sbapt } 199262395Sbapt if (compact) { 200262395Sbapt func->ucl_emitter_append_character ('[', 1, func->ud); 201262395Sbapt } 202262395Sbapt else { 203262395Sbapt func->ucl_emitter_append_len ("[\n", 2, func->ud); 204262395Sbapt } 205262395Sbapt while (cur) { 206262395Sbapt ucl_elt_write_json (cur, func, tabs + 1, true, compact); 207262395Sbapt if (cur->next != NULL) { 208262395Sbapt if (compact) { 209262395Sbapt func->ucl_emitter_append_character (',', 1, func->ud); 210262395Sbapt } 211262395Sbapt else { 212262395Sbapt func->ucl_emitter_append_len (",\n", 2, func->ud); 213262395Sbapt } 214262395Sbapt } 215262395Sbapt else if (!compact) { 216262395Sbapt func->ucl_emitter_append_character ('\n', 1, func->ud); 217262395Sbapt } 218262395Sbapt cur = cur->next; 219262395Sbapt } 220262395Sbapt ucl_add_tabs (func, tabs, compact); 221262395Sbapt func->ucl_emitter_append_character (']', 1, func->ud); 222262395Sbapt} 223262395Sbapt 224262395Sbapt/** 225262395Sbapt * Emit a single element 226262395Sbapt * @param obj object 227262395Sbapt * @param buf buffer 228262395Sbapt */ 229262395Sbaptstatic void 230262395Sbaptucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 231262395Sbapt unsigned int tabs, bool start_tabs, bool compact) 232262395Sbapt{ 233262395Sbapt bool flag; 234262395Sbapt 235262395Sbapt switch (obj->type) { 236262395Sbapt case UCL_INT: 237262395Sbapt if (start_tabs) { 238262395Sbapt ucl_add_tabs (func, tabs, compact); 239262395Sbapt } 240262395Sbapt func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 241262395Sbapt break; 242262395Sbapt case UCL_FLOAT: 243262395Sbapt case UCL_TIME: 244262395Sbapt if (start_tabs) { 245262395Sbapt ucl_add_tabs (func, tabs, compact); 246262395Sbapt } 247262395Sbapt func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 248262395Sbapt break; 249262395Sbapt case UCL_BOOLEAN: 250262395Sbapt if (start_tabs) { 251262395Sbapt ucl_add_tabs (func, tabs, compact); 252262395Sbapt } 253262395Sbapt flag = ucl_object_toboolean (obj); 254262395Sbapt if (flag) { 255262395Sbapt func->ucl_emitter_append_len ("true", 4, func->ud); 256262395Sbapt } 257262395Sbapt else { 258262395Sbapt func->ucl_emitter_append_len ("false", 5, func->ud); 259262395Sbapt } 260262395Sbapt break; 261262395Sbapt case UCL_STRING: 262262395Sbapt if (start_tabs) { 263262395Sbapt ucl_add_tabs (func, tabs, compact); 264262395Sbapt } 265262395Sbapt ucl_elt_string_write_json (obj->value.sv, obj->len, func); 266262395Sbapt break; 267262395Sbapt case UCL_NULL: 268262395Sbapt if (start_tabs) { 269262395Sbapt ucl_add_tabs (func, tabs, compact); 270262395Sbapt } 271262395Sbapt func->ucl_emitter_append_len ("null", 4, func->ud); 272262395Sbapt break; 273262395Sbapt case UCL_OBJECT: 274262395Sbapt ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact); 275262395Sbapt break; 276262395Sbapt case UCL_ARRAY: 277262395Sbapt ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact); 278262395Sbapt break; 279262395Sbapt case UCL_USERDATA: 280262395Sbapt break; 281262395Sbapt } 282262395Sbapt} 283262395Sbapt 284262395Sbapt/** 285262395Sbapt * Write a single object to the buffer 286262395Sbapt * @param obj object 287262395Sbapt * @param buf target buffer 288262395Sbapt */ 289262395Sbaptstatic void 290262395Sbaptucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, 291262395Sbapt unsigned int tabs, bool start_tabs, bool compact) 292262395Sbapt{ 293262395Sbapt ucl_object_t *cur; 294262395Sbapt bool is_array = (obj->next != NULL); 295262395Sbapt 296262395Sbapt if (is_array) { 297262395Sbapt /* This is an array actually */ 298262395Sbapt if (start_tabs) { 299262395Sbapt ucl_add_tabs (func, tabs, compact); 300262395Sbapt } 301262395Sbapt 302262395Sbapt if (compact) { 303262395Sbapt func->ucl_emitter_append_character ('[', 1, func->ud); 304262395Sbapt } 305262395Sbapt else { 306262395Sbapt func->ucl_emitter_append_len ("[\n", 2, func->ud); 307262395Sbapt } 308262395Sbapt cur = obj; 309262395Sbapt while (cur != NULL) { 310262395Sbapt ucl_elt_write_json (cur, func, tabs + 1, true, compact); 311262395Sbapt if (cur->next) { 312262395Sbapt func->ucl_emitter_append_character (',', 1, func->ud); 313262395Sbapt } 314262395Sbapt if (!compact) { 315262395Sbapt func->ucl_emitter_append_character ('\n', 1, func->ud); 316262395Sbapt } 317262395Sbapt cur = cur->next; 318262395Sbapt } 319262395Sbapt ucl_add_tabs (func, tabs, compact); 320262395Sbapt func->ucl_emitter_append_character (']', 1, func->ud); 321262395Sbapt } 322262395Sbapt else { 323262395Sbapt ucl_elt_write_json (obj, func, tabs, start_tabs, compact); 324262395Sbapt } 325262395Sbapt 326262395Sbapt} 327262395Sbapt 328262395Sbapt/** 329262395Sbapt * Emit an object to json 330262395Sbapt * @param obj object 331262395Sbapt * @return json output (should be freed after using) 332262395Sbapt */ 333262395Sbaptstatic void 334262395Sbaptucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func) 335262395Sbapt{ 336262395Sbapt ucl_obj_write_json (obj, func, 0, false, compact); 337262395Sbapt} 338262395Sbapt 339262395Sbapt/** 340262395Sbapt * Write a single object to the buffer 341262395Sbapt * @param obj object to write 342262395Sbapt * @param buf target buffer 343262395Sbapt */ 344262395Sbaptstatic void 345262395Sbaptucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 346262395Sbapt unsigned int tabs, bool start_tabs, bool is_top) 347262395Sbapt{ 348262395Sbapt ucl_object_t *cur, *cur_obj; 349262395Sbapt ucl_hash_iter_t it = NULL; 350262395Sbapt 351262395Sbapt if (start_tabs) { 352262395Sbapt ucl_add_tabs (func, tabs, is_top); 353262395Sbapt } 354262395Sbapt if (!is_top) { 355262395Sbapt func->ucl_emitter_append_len ("{\n", 2, func->ud); 356262395Sbapt } 357262395Sbapt 358262395Sbapt while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 359262395Sbapt LL_FOREACH (cur, cur_obj) { 360262395Sbapt ucl_add_tabs (func, tabs + 1, is_top); 361262395Sbapt if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { 362262395Sbapt ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func); 363262395Sbapt } 364262395Sbapt else { 365262395Sbapt func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud); 366262395Sbapt } 367262395Sbapt if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 368262395Sbapt func->ucl_emitter_append_len (" = ", 3, func->ud); 369262395Sbapt } 370262395Sbapt else { 371262395Sbapt func->ucl_emitter_append_character (' ', 1, func->ud); 372262395Sbapt } 373262395Sbapt ucl_elt_write_config (cur_obj, func, 374262395Sbapt is_top ? tabs : tabs + 1, 375262395Sbapt false, false, false); 376262395Sbapt if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { 377262395Sbapt func->ucl_emitter_append_len (";\n", 2, func->ud); 378262395Sbapt } 379262395Sbapt else { 380262395Sbapt func->ucl_emitter_append_character ('\n', 1, func->ud); 381262395Sbapt } 382262395Sbapt } 383262395Sbapt } 384262395Sbapt 385262395Sbapt ucl_add_tabs (func, tabs, is_top); 386262395Sbapt if (!is_top) { 387262395Sbapt func->ucl_emitter_append_character ('}', 1, func->ud); 388262395Sbapt } 389262395Sbapt} 390262395Sbapt 391262395Sbapt/** 392262395Sbapt * Write a single array to the buffer 393262395Sbapt * @param obj array to write 394262395Sbapt * @param buf target buffer 395262395Sbapt */ 396262395Sbaptstatic void 397262395Sbaptucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 398262395Sbapt unsigned int tabs, bool start_tabs, bool is_top) 399262395Sbapt{ 400262395Sbapt ucl_object_t *cur = obj; 401262395Sbapt 402262395Sbapt if (start_tabs) { 403262395Sbapt ucl_add_tabs (func, tabs, false); 404262395Sbapt } 405262395Sbapt 406262395Sbapt func->ucl_emitter_append_len ("[\n", 2, func->ud); 407262395Sbapt while (cur) { 408262395Sbapt ucl_elt_write_config (cur, func, tabs + 1, true, false, false); 409262395Sbapt func->ucl_emitter_append_len (",\n", 2, func->ud); 410262395Sbapt cur = cur->next; 411262395Sbapt } 412262395Sbapt ucl_add_tabs (func, tabs, false); 413262395Sbapt func->ucl_emitter_append_character (']', 1, func->ud); 414262395Sbapt} 415262395Sbapt 416262395Sbapt/** 417262395Sbapt * Emit a single element 418262395Sbapt * @param obj object 419262395Sbapt * @param buf buffer 420262395Sbapt */ 421262395Sbaptstatic void 422262395Sbaptucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, 423262395Sbapt unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 424262395Sbapt{ 425262395Sbapt bool flag; 426262395Sbapt 427262395Sbapt if (expand_array && obj->next != NULL) { 428262395Sbapt ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top); 429262395Sbapt } 430262395Sbapt else { 431262395Sbapt switch (obj->type) { 432262395Sbapt case UCL_INT: 433262395Sbapt if (start_tabs) { 434262395Sbapt ucl_add_tabs (func, tabs, false); 435262395Sbapt } 436262395Sbapt func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 437262395Sbapt break; 438262395Sbapt case UCL_FLOAT: 439262395Sbapt case UCL_TIME: 440262395Sbapt if (start_tabs) { 441262395Sbapt ucl_add_tabs (func, tabs, false); 442262395Sbapt } 443262395Sbapt func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 444262395Sbapt break; 445262395Sbapt case UCL_BOOLEAN: 446262395Sbapt if (start_tabs) { 447262395Sbapt ucl_add_tabs (func, tabs, false); 448262395Sbapt } 449262395Sbapt flag = ucl_object_toboolean (obj); 450262395Sbapt if (flag) { 451262395Sbapt func->ucl_emitter_append_len ("true", 4, func->ud); 452262395Sbapt } 453262395Sbapt else { 454262395Sbapt func->ucl_emitter_append_len ("false", 5, func->ud); 455262395Sbapt } 456262395Sbapt break; 457262395Sbapt case UCL_STRING: 458262395Sbapt if (start_tabs) { 459262395Sbapt ucl_add_tabs (func, tabs, false); 460262395Sbapt } 461262395Sbapt ucl_elt_string_write_json (obj->value.sv, obj->len, func); 462262395Sbapt break; 463262395Sbapt case UCL_NULL: 464262395Sbapt if (start_tabs) { 465262395Sbapt ucl_add_tabs (func, tabs, false); 466262395Sbapt } 467262395Sbapt func->ucl_emitter_append_len ("null", 4, func->ud); 468262395Sbapt break; 469262395Sbapt case UCL_OBJECT: 470262395Sbapt ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top); 471262395Sbapt break; 472262395Sbapt case UCL_ARRAY: 473262395Sbapt ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top); 474262395Sbapt break; 475262395Sbapt case UCL_USERDATA: 476262395Sbapt break; 477262395Sbapt } 478262395Sbapt } 479262395Sbapt} 480262395Sbapt 481262395Sbapt/** 482262395Sbapt * Emit an object to rcl 483262395Sbapt * @param obj object 484262395Sbapt * @return rcl output (should be freed after using) 485262395Sbapt */ 486262395Sbaptstatic void 487262395Sbaptucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func) 488262395Sbapt{ 489262395Sbapt ucl_elt_write_config (obj, func, 0, false, true, true); 490262395Sbapt} 491262395Sbapt 492262395Sbapt 493262395Sbaptstatic void 494262395Sbaptucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 495262395Sbapt unsigned int tabs, bool start_tabs) 496262395Sbapt{ 497262395Sbapt bool is_array = (obj->next != NULL); 498262395Sbapt 499262395Sbapt if (is_array) { 500262395Sbapt ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false); 501262395Sbapt } 502262395Sbapt else { 503262395Sbapt ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true); 504262395Sbapt } 505262395Sbapt} 506262395Sbapt 507262395Sbapt/** 508262395Sbapt * Write a single object to the buffer 509262395Sbapt * @param obj object to write 510262395Sbapt * @param buf target buffer 511262395Sbapt */ 512262395Sbaptstatic void 513262395Sbaptucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 514262395Sbapt unsigned int tabs, bool start_tabs, bool is_top) 515262395Sbapt{ 516262395Sbapt ucl_object_t *cur; 517262395Sbapt ucl_hash_iter_t it = NULL; 518262395Sbapt 519262395Sbapt if (start_tabs) { 520262395Sbapt ucl_add_tabs (func, tabs, is_top); 521262395Sbapt } 522262395Sbapt if (!is_top) { 523262395Sbapt func->ucl_emitter_append_len ("{\n", 2, func->ud); 524262395Sbapt } 525262395Sbapt 526262395Sbapt while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { 527262395Sbapt ucl_add_tabs (func, tabs + 1, is_top); 528262395Sbapt if (cur->keylen > 0) { 529262395Sbapt ucl_elt_string_write_json (cur->key, cur->keylen, func); 530262395Sbapt } 531262395Sbapt else { 532262395Sbapt func->ucl_emitter_append_len ("null", 4, func->ud); 533262395Sbapt } 534262395Sbapt func->ucl_emitter_append_len (": ", 2, func->ud); 535262395Sbapt ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false); 536262395Sbapt if (ucl_hash_iter_has_next(it)) { 537262395Sbapt if (!is_top) { 538262395Sbapt func->ucl_emitter_append_len (",\n", 2, func->ud); 539262395Sbapt } 540262395Sbapt else { 541262395Sbapt func->ucl_emitter_append_character ('\n', 1, func->ud); 542262395Sbapt } 543262395Sbapt } 544262395Sbapt else { 545262395Sbapt func->ucl_emitter_append_character ('\n', 1, func->ud); 546262395Sbapt } 547262395Sbapt } 548262395Sbapt 549262395Sbapt ucl_add_tabs (func, tabs, is_top); 550262395Sbapt if (!is_top) { 551262395Sbapt func->ucl_emitter_append_character ('}', 1, func->ud); 552262395Sbapt } 553262395Sbapt} 554262395Sbapt 555262395Sbapt/** 556262395Sbapt * Write a single array to the buffer 557262395Sbapt * @param obj array to write 558262395Sbapt * @param buf target buffer 559262395Sbapt */ 560262395Sbaptstatic void 561262395Sbaptucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 562262395Sbapt unsigned int tabs, bool start_tabs, bool is_top) 563262395Sbapt{ 564262395Sbapt ucl_object_t *cur = obj; 565262395Sbapt 566262395Sbapt if (start_tabs) { 567262395Sbapt ucl_add_tabs (func, tabs, false); 568262395Sbapt } 569262395Sbapt 570262395Sbapt func->ucl_emitter_append_len ("[\n", 2, func->ud); 571262395Sbapt while (cur) { 572262395Sbapt ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false); 573262395Sbapt func->ucl_emitter_append_len (",\n", 2, func->ud); 574262395Sbapt cur = cur->next; 575262395Sbapt } 576262395Sbapt ucl_add_tabs (func, tabs, false); 577262395Sbapt func->ucl_emitter_append_character (']', 1, func->ud); 578262395Sbapt} 579262395Sbapt 580262395Sbapt/** 581262395Sbapt * Emit a single element 582262395Sbapt * @param obj object 583262395Sbapt * @param buf buffer 584262395Sbapt */ 585262395Sbaptstatic void 586262395Sbaptucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, 587262395Sbapt unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) 588262395Sbapt{ 589262395Sbapt bool flag; 590262395Sbapt 591262395Sbapt if (expand_array && obj->next != NULL ) { 592262395Sbapt ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top); 593262395Sbapt } 594262395Sbapt else { 595262395Sbapt switch (obj->type) { 596262395Sbapt case UCL_INT: 597262395Sbapt if (start_tabs) { 598262395Sbapt ucl_add_tabs (func, tabs, false); 599262395Sbapt } 600262395Sbapt func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); 601262395Sbapt break; 602262395Sbapt case UCL_FLOAT: 603262395Sbapt case UCL_TIME: 604262395Sbapt if (start_tabs) { 605262395Sbapt ucl_add_tabs (func, tabs, false); 606262395Sbapt } 607262395Sbapt func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); 608262395Sbapt break; 609262395Sbapt case UCL_BOOLEAN: 610262395Sbapt if (start_tabs) { 611262395Sbapt ucl_add_tabs (func, tabs, false); 612262395Sbapt } 613262395Sbapt flag = ucl_object_toboolean (obj); 614262395Sbapt if (flag) { 615262395Sbapt func->ucl_emitter_append_len ("true", 4, func->ud); 616262395Sbapt } 617262395Sbapt else { 618262395Sbapt func->ucl_emitter_append_len ("false", 5, func->ud); 619262395Sbapt } 620262395Sbapt break; 621262395Sbapt case UCL_STRING: 622262395Sbapt if (start_tabs) { 623262395Sbapt ucl_add_tabs (func, tabs, false); 624262395Sbapt } 625262395Sbapt ucl_elt_string_write_json (obj->value.sv, obj->len, func); 626262395Sbapt break; 627262395Sbapt case UCL_NULL: 628262395Sbapt if (start_tabs) { 629262395Sbapt ucl_add_tabs (func, tabs, false); 630262395Sbapt } 631262395Sbapt func->ucl_emitter_append_len ("null", 4, func->ud); 632262395Sbapt break; 633262395Sbapt case UCL_OBJECT: 634262395Sbapt ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top); 635262395Sbapt break; 636262395Sbapt case UCL_ARRAY: 637262395Sbapt ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top); 638262395Sbapt break; 639262395Sbapt case UCL_USERDATA: 640262395Sbapt break; 641262395Sbapt } 642262395Sbapt } 643262395Sbapt} 644262395Sbapt 645262395Sbapt/** 646262395Sbapt * Emit an object to rcl 647262395Sbapt * @param obj object 648262395Sbapt * @return rcl output (should be freed after using) 649262395Sbapt */ 650262395Sbaptstatic void 651262395Sbaptucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func) 652262395Sbapt{ 653262395Sbapt ucl_elt_write_yaml (obj, func, 0, false, true, true); 654262395Sbapt} 655262395Sbapt 656262395Sbapt/* 657262395Sbapt * Generic utstring output 658262395Sbapt */ 659262395Sbaptstatic int 660262395Sbaptucl_utstring_append_character (unsigned char c, size_t len, void *ud) 661262395Sbapt{ 662262395Sbapt UT_string *buf = ud; 663262395Sbapt 664262395Sbapt if (len == 1) { 665262395Sbapt utstring_append_c (buf, c); 666262395Sbapt } 667262395Sbapt else { 668262395Sbapt utstring_reserve (buf, len); 669262395Sbapt memset (&buf->d[buf->i], c, len); 670262395Sbapt buf->i += len; 671262395Sbapt buf->d[buf->i] = '\0'; 672262395Sbapt } 673262395Sbapt 674262395Sbapt return 0; 675262395Sbapt} 676262395Sbapt 677262395Sbaptstatic int 678262395Sbaptucl_utstring_append_len (const unsigned char *str, size_t len, void *ud) 679262395Sbapt{ 680262395Sbapt UT_string *buf = ud; 681262395Sbapt 682262395Sbapt utstring_append_len (buf, str, len); 683262395Sbapt 684262395Sbapt return 0; 685262395Sbapt} 686262395Sbapt 687262395Sbaptstatic int 688262395Sbaptucl_utstring_append_int (int64_t val, void *ud) 689262395Sbapt{ 690262395Sbapt UT_string *buf = ud; 691262395Sbapt 692262395Sbapt utstring_printf (buf, "%jd", (intmax_t)val); 693262395Sbapt return 0; 694262395Sbapt} 695262395Sbapt 696262395Sbaptstatic int 697262395Sbaptucl_utstring_append_double (double val, void *ud) 698262395Sbapt{ 699262395Sbapt UT_string *buf = ud; 700262395Sbapt const double delta = 0.0000001; 701262395Sbapt 702262395Sbapt if (val == (double)(int)val) { 703262395Sbapt utstring_printf (buf, "%.1lf", val); 704262395Sbapt } 705262395Sbapt else if (fabs (val - (double)(int)val) < delta) { 706262395Sbapt /* Write at maximum precision */ 707262395Sbapt utstring_printf (buf, "%.*lg", DBL_DIG, val); 708262395Sbapt } 709262395Sbapt else { 710262395Sbapt utstring_printf (buf, "%lf", val); 711262395Sbapt } 712262395Sbapt 713262395Sbapt return 0; 714262395Sbapt} 715262395Sbapt 716262395Sbapt 717262395Sbaptunsigned char * 718262395Sbaptucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type) 719262395Sbapt{ 720262395Sbapt UT_string *buf = NULL; 721262395Sbapt unsigned char *res = NULL; 722262395Sbapt struct ucl_emitter_functions func = { 723262395Sbapt .ucl_emitter_append_character = ucl_utstring_append_character, 724262395Sbapt .ucl_emitter_append_len = ucl_utstring_append_len, 725262395Sbapt .ucl_emitter_append_int = ucl_utstring_append_int, 726262395Sbapt .ucl_emitter_append_double = ucl_utstring_append_double 727262395Sbapt }; 728262395Sbapt 729262395Sbapt if (obj == NULL) { 730262395Sbapt return NULL; 731262395Sbapt } 732262395Sbapt 733262395Sbapt utstring_new (buf); 734262395Sbapt func.ud = buf; 735262395Sbapt 736262395Sbapt if (buf != NULL) { 737262395Sbapt if (emit_type == UCL_EMIT_JSON) { 738262395Sbapt ucl_object_emit_json (obj, false, &func); 739262395Sbapt } 740262395Sbapt else if (emit_type == UCL_EMIT_JSON_COMPACT) { 741262395Sbapt ucl_object_emit_json (obj, true, &func); 742262395Sbapt } 743262395Sbapt else if (emit_type == UCL_EMIT_YAML) { 744262395Sbapt ucl_object_emit_yaml (obj, &func); 745262395Sbapt } 746262395Sbapt else { 747262395Sbapt ucl_object_emit_config (obj, &func); 748262395Sbapt } 749262395Sbapt 750262395Sbapt res = utstring_body (buf); 751262395Sbapt free (buf); 752262395Sbapt } 753262395Sbapt 754262395Sbapt return res; 755262395Sbapt} 756262395Sbapt 757262395Sbaptbool 758262395Sbaptucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, 759262395Sbapt struct ucl_emitter_functions *emitter) 760262395Sbapt{ 761262395Sbapt if (emit_type == UCL_EMIT_JSON) { 762262395Sbapt ucl_object_emit_json (obj, false, emitter); 763262395Sbapt } 764262395Sbapt else if (emit_type == UCL_EMIT_JSON_COMPACT) { 765262395Sbapt ucl_object_emit_json (obj, true, emitter); 766262395Sbapt } 767262395Sbapt else if (emit_type == UCL_EMIT_YAML) { 768262395Sbapt ucl_object_emit_yaml (obj, emitter); 769262395Sbapt } 770262395Sbapt else { 771262395Sbapt ucl_object_emit_config (obj, emitter); 772262395Sbapt } 773262395Sbapt 774262395Sbapt /* XXX: need some error checks here */ 775262395Sbapt return true; 776262395Sbapt} 777262395Sbapt 778262395Sbapt 779262395Sbaptunsigned char * 780262395Sbaptucl_object_emit_single_json (ucl_object_t *obj) 781262395Sbapt{ 782262395Sbapt UT_string *buf = NULL; 783262395Sbapt unsigned char *res = NULL; 784262395Sbapt 785262395Sbapt if (obj == NULL) { 786262395Sbapt return NULL; 787262395Sbapt } 788262395Sbapt 789262395Sbapt utstring_new (buf); 790262395Sbapt 791262395Sbapt if (buf != NULL) { 792262395Sbapt switch (obj->type) { 793262395Sbapt case UCL_OBJECT: 794262395Sbapt ucl_utstring_append_len ("object", 6, buf); 795262395Sbapt break; 796262395Sbapt case UCL_ARRAY: 797262395Sbapt ucl_utstring_append_len ("array", 5, buf); 798262395Sbapt break; 799262395Sbapt case UCL_INT: 800262395Sbapt ucl_utstring_append_int (obj->value.iv, buf); 801262395Sbapt break; 802262395Sbapt case UCL_FLOAT: 803262395Sbapt case UCL_TIME: 804262395Sbapt ucl_utstring_append_double (obj->value.dv, buf); 805262395Sbapt break; 806262395Sbapt case UCL_NULL: 807262395Sbapt ucl_utstring_append_len ("null", 4, buf); 808262395Sbapt break; 809262395Sbapt case UCL_BOOLEAN: 810262395Sbapt if (obj->value.iv) { 811262395Sbapt ucl_utstring_append_len ("true", 4, buf); 812262395Sbapt } 813262395Sbapt else { 814262395Sbapt ucl_utstring_append_len ("false", 5, buf); 815262395Sbapt } 816262395Sbapt break; 817262395Sbapt case UCL_STRING: 818262395Sbapt ucl_utstring_append_len (obj->value.sv, obj->len, buf); 819262395Sbapt break; 820262395Sbapt case UCL_USERDATA: 821262395Sbapt ucl_utstring_append_len ("userdata", 8, buf); 822262395Sbapt break; 823262395Sbapt } 824262395Sbapt res = utstring_body (buf); 825262395Sbapt free (buf); 826262395Sbapt } 827262395Sbapt 828262395Sbapt return res; 829262395Sbapt} 830