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