1 /* Copyright (c) 2014, 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 32 #ifdef HAVE_FLOAT_H 33 #include <float.h> 34 #endif 35 #ifdef HAVE_MATH_H 36 #include <math.h> 37 #endif 38 39 extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[]; 40 41 static const struct ucl_emitter_context ucl_standard_emitters[] = { 42 [UCL_EMIT_JSON] = { 43 .name = "json", 44 .id = UCL_EMIT_JSON, 45 .func = NULL, 46 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON] 47 }, 48 [UCL_EMIT_JSON_COMPACT] = { 49 .name = "json_compact", 50 .id = UCL_EMIT_JSON_COMPACT, 51 .func = NULL, 52 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT] 53 }, 54 [UCL_EMIT_CONFIG] = { 55 .name = "config", 56 .id = UCL_EMIT_CONFIG, 57 .func = NULL, 58 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG] 59 }, 60 [UCL_EMIT_YAML] = { 61 .name = "yaml", 62 .id = UCL_EMIT_YAML, 63 .func = NULL, 64 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML] 65 }, 66 [UCL_EMIT_MSGPACK] = { 67 .name = "msgpack", 68 .id = UCL_EMIT_MSGPACK, 69 .func = NULL, 70 .ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK] 71 } 72 }; 73 74 /** 75 * Get standard emitter context for a specified emit_type 76 * @param emit_type type of emitter 77 * @return context or NULL if input is invalid 78 */ 79 const struct ucl_emitter_context * 80 ucl_emit_get_standard_context (enum ucl_emitter emit_type) 81 { 82 if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) { 83 return &ucl_standard_emitters[emit_type]; 84 } 85 86 return NULL; 87 } 88 89 /** 90 * Serialise string 91 * @param str string to emit 92 * @param buf target buffer 93 */ 94 void 95 ucl_elt_string_write_json (const char *str, size_t size, 96 struct ucl_emitter_context *ctx) 97 { 98 const char *p = str, *c = str; 99 size_t len = 0; 100 const struct ucl_emitter_functions *func = ctx->func; 101 102 func->ucl_emitter_append_character ('"', 1, func->ud); 103 104 while (size) { 105 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 106 if (len > 0) { 107 func->ucl_emitter_append_len (c, len, func->ud); 108 } 109 switch (*p) { 110 case '\n': 111 func->ucl_emitter_append_len ("\\n", 2, func->ud); 112 break; 113 case '\r': 114 func->ucl_emitter_append_len ("\\r", 2, func->ud); 115 break; 116 case '\b': 117 func->ucl_emitter_append_len ("\\b", 2, func->ud); 118 break; 119 case '\t': 120 func->ucl_emitter_append_len ("\\t", 2, func->ud); 121 break; 122 case '\f': 123 func->ucl_emitter_append_len ("\\f", 2, func->ud); 124 break; 125 case '\\': 126 func->ucl_emitter_append_len ("\\\\", 2, func->ud); 127 break; 128 case '"': 129 func->ucl_emitter_append_len ("\\\"", 2, func->ud); 130 break; 131 } 132 len = 0; 133 c = ++p; 134 } 135 else { 136 p ++; 137 len ++; 138 } 139 size --; 140 } 141 if (len > 0) { 142 func->ucl_emitter_append_len (c, len, func->ud); 143 } 144 func->ucl_emitter_append_character ('"', 1, func->ud); 145 } 146 147 void 148 ucl_elt_string_write_multiline (const char *str, size_t size, 149 struct ucl_emitter_context *ctx) 150 { 151 const struct ucl_emitter_functions *func = ctx->func; 152 153 func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud); 154 func->ucl_emitter_append_len (str, size, func->ud); 155 func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud); 156 } 157 158 /* 159 * Generic utstring output 160 */ 161 static int 162 ucl_utstring_append_character (unsigned char c, size_t len, void *ud) 163 { 164 UT_string *buf = ud; 165 166 if (len == 1) { 167 utstring_append_c (buf, c); 168 } 169 else { 170 utstring_reserve (buf, len + 1); 171 memset (&buf->d[buf->i], c, len); 172 buf->i += len; 173 buf->d[buf->i] = '\0'; 174 } 175 176 return 0; 177 } 178 179 static int 180 ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud) 181 { 182 UT_string *buf = ud; 183 184 utstring_append_len (buf, str, len); 185 186 return 0; 187 } 188 189 static int 190 ucl_utstring_append_int (int64_t val, void *ud) 191 { 192 UT_string *buf = ud; 193 194 utstring_printf (buf, "%jd", (intmax_t)val); 195 return 0; 196 } 197 198 static int 199 ucl_utstring_append_double (double val, void *ud) 200 { 201 UT_string *buf = ud; 202 const double delta = 0.0000001; 203 204 if (val == (double)(int)val) { 205 utstring_printf (buf, "%.1lf", val); 206 } 207 else if (fabs (val - (double)(int)val) < delta) { 208 /* Write at maximum precision */ 209 utstring_printf (buf, "%.*lg", DBL_DIG, val); 210 } 211 else { 212 utstring_printf (buf, "%lf", val); 213 } 214 215 return 0; 216 } 217 218 /* 219 * Generic file output 220 */ 221 static int 222 ucl_file_append_character (unsigned char c, size_t len, void *ud) 223 { 224 FILE *fp = ud; 225 226 while (len --) { 227 fputc (c, fp); 228 } 229 230 return 0; 231 } 232 233 static int 234 ucl_file_append_len (const unsigned char *str, size_t len, void *ud) 235 { 236 FILE *fp = ud; 237 238 fwrite (str, len, 1, fp); 239 240 return 0; 241 } 242 243 static int 244 ucl_file_append_int (int64_t val, void *ud) 245 { 246 FILE *fp = ud; 247 248 fprintf (fp, "%jd", (intmax_t)val); 249 250 return 0; 251 } 252 253 static int 254 ucl_file_append_double (double val, void *ud) 255 { 256 FILE *fp = ud; 257 const double delta = 0.0000001; 258 259 if (val == (double)(int)val) { 260 fprintf (fp, "%.1lf", val); 261 } 262 else if (fabs (val - (double)(int)val) < delta) { 263 /* Write at maximum precision */ 264 fprintf (fp, "%.*lg", DBL_DIG, val); 265 } 266 else { 267 fprintf (fp, "%lf", val); 268 } 269 270 return 0; 271 } 272 273 /* 274 * Generic file descriptor writing functions 275 */ 276 static int 277 ucl_fd_append_character (unsigned char c, size_t len, void *ud) 278 { 279 int fd = *(int *)ud; 280 unsigned char *buf; 281 282 if (len == 1) { 283 return write (fd, &c, 1); 284 } 285 else { 286 buf = malloc (len); 287 if (buf == NULL) { 288 /* Fallback */ 289 while (len --) { 290 if (write (fd, &c, 1) == -1) { 291 return -1; 292 } 293 } 294 } 295 else { 296 memset (buf, c, len); 297 if (write (fd, buf, len) == -1) { 298 free(buf); 299 return -1; 300 } 301 free (buf); 302 } 303 } 304 305 return 0; 306 } 307 308 static int 309 ucl_fd_append_len (const unsigned char *str, size_t len, void *ud) 310 { 311 int fd = *(int *)ud; 312 313 return write (fd, str, len); 314 } 315 316 static int 317 ucl_fd_append_int (int64_t val, void *ud) 318 { 319 int fd = *(int *)ud; 320 char intbuf[64]; 321 322 snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val); 323 return write (fd, intbuf, strlen (intbuf)); 324 } 325 326 static int 327 ucl_fd_append_double (double val, void *ud) 328 { 329 int fd = *(int *)ud; 330 const double delta = 0.0000001; 331 char nbuf[64]; 332 333 if (val == (double)(int)val) { 334 snprintf (nbuf, sizeof (nbuf), "%.1lf", val); 335 } 336 else if (fabs (val - (double)(int)val) < delta) { 337 /* Write at maximum precision */ 338 snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val); 339 } 340 else { 341 snprintf (nbuf, sizeof (nbuf), "%lf", val); 342 } 343 344 return write (fd, nbuf, strlen (nbuf)); 345 } 346 347 struct ucl_emitter_functions* 348 ucl_object_emit_memory_funcs (void **pmem) 349 { 350 struct ucl_emitter_functions *f; 351 UT_string *s; 352 353 f = calloc (1, sizeof (*f)); 354 355 if (f != NULL) { 356 f->ucl_emitter_append_character = ucl_utstring_append_character; 357 f->ucl_emitter_append_double = ucl_utstring_append_double; 358 f->ucl_emitter_append_int = ucl_utstring_append_int; 359 f->ucl_emitter_append_len = ucl_utstring_append_len; 360 f->ucl_emitter_free_func = free; 361 utstring_new (s); 362 f->ud = s; 363 *pmem = s->d; 364 s->pd = pmem; 365 } 366 367 return f; 368 } 369 370 struct ucl_emitter_functions* 371 ucl_object_emit_file_funcs (FILE *fp) 372 { 373 struct ucl_emitter_functions *f; 374 375 f = calloc (1, sizeof (*f)); 376 377 if (f != NULL) { 378 f->ucl_emitter_append_character = ucl_file_append_character; 379 f->ucl_emitter_append_double = ucl_file_append_double; 380 f->ucl_emitter_append_int = ucl_file_append_int; 381 f->ucl_emitter_append_len = ucl_file_append_len; 382 f->ucl_emitter_free_func = NULL; 383 f->ud = fp; 384 } 385 386 return f; 387 } 388 389 struct ucl_emitter_functions* 390 ucl_object_emit_fd_funcs (int fd) 391 { 392 struct ucl_emitter_functions *f; 393 int *ip; 394 395 f = calloc (1, sizeof (*f)); 396 397 if (f != NULL) { 398 ip = malloc (sizeof (fd)); 399 if (ip == NULL) { 400 free (f); 401 return NULL; 402 } 403 404 memcpy (ip, &fd, sizeof (fd)); 405 f->ucl_emitter_append_character = ucl_fd_append_character; 406 f->ucl_emitter_append_double = ucl_fd_append_double; 407 f->ucl_emitter_append_int = ucl_fd_append_int; 408 f->ucl_emitter_append_len = ucl_fd_append_len; 409 f->ucl_emitter_free_func = free; 410 f->ud = ip; 411 } 412 413 return f; 414 } 415 416 void 417 ucl_object_emit_funcs_free (struct ucl_emitter_functions *f) 418 { 419 if (f != NULL) { 420 if (f->ucl_emitter_free_func != NULL) { 421 f->ucl_emitter_free_func (f->ud); 422 } 423 free (f); 424 } 425 } 426 427 428 unsigned char * 429 ucl_object_emit_single_json (const ucl_object_t *obj) 430 { 431 UT_string *buf = NULL; 432 unsigned char *res = NULL; 433 434 if (obj == NULL) { 435 return NULL; 436 } 437 438 utstring_new (buf); 439 440 if (buf != NULL) { 441 switch (obj->type) { 442 case UCL_OBJECT: 443 ucl_utstring_append_len ("object", 6, buf); 444 break; 445 case UCL_ARRAY: 446 ucl_utstring_append_len ("array", 5, buf); 447 break; 448 case UCL_INT: 449 ucl_utstring_append_int (obj->value.iv, buf); 450 break; 451 case UCL_FLOAT: 452 case UCL_TIME: 453 ucl_utstring_append_double (obj->value.dv, buf); 454 break; 455 case UCL_NULL: 456 ucl_utstring_append_len ("null", 4, buf); 457 break; 458 case UCL_BOOLEAN: 459 if (obj->value.iv) { 460 ucl_utstring_append_len ("true", 4, buf); 461 } 462 else { 463 ucl_utstring_append_len ("false", 5, buf); 464 } 465 break; 466 case UCL_STRING: 467 ucl_utstring_append_len (obj->value.sv, obj->len, buf); 468 break; 469 case UCL_USERDATA: 470 ucl_utstring_append_len ("userdata", 8, buf); 471 break; 472 } 473 res = utstring_body (buf); 474 free (buf); 475 } 476 477 return res; 478 } 479 480 #define LONG_STRING_LIMIT 80 481 482 bool 483 ucl_maybe_long_string (const ucl_object_t *obj) 484 { 485 if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) { 486 /* String is long enough, so search for newline characters in it */ 487 if (memchr (obj->value.sv, '\n', obj->len) != NULL) { 488 return true; 489 } 490 } 491 492 return false; 493 } 494