Path: blob/main/contrib/libucl/src/ucl_emitter_utils.c
39483 views
/* Copyright (c) 2014, Vsevolod Stakhov1* All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions are met:5* * Redistributions of source code must retain the above copyright6* notice, this list of conditions and the following disclaimer.7* * Redistributions in binary form must reproduce the above copyright8* notice, this list of conditions and the following disclaimer in the9* documentation and/or other materials provided with the distribution.10*11* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY12* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED13* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE14* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY15* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES16* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;17* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND18* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT19* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS20* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.21*/2223#ifdef HAVE_CONFIG_H24#include "config.h"25#endif2627#include "ucl.h"28#include "ucl_internal.h"29#include "ucl_chartable.h"3031#ifdef HAVE_FLOAT_H32#include <float.h>33#endif34#ifdef HAVE_MATH_H35#include <math.h>36#endif3738extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];3940static const struct ucl_emitter_context ucl_standard_emitters[] = {41[UCL_EMIT_JSON] = {42.name = "json",43.id = UCL_EMIT_JSON,44.func = NULL,45.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]46},47[UCL_EMIT_JSON_COMPACT] = {48.name = "json_compact",49.id = UCL_EMIT_JSON_COMPACT,50.func = NULL,51.ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]52},53[UCL_EMIT_CONFIG] = {54.name = "config",55.id = UCL_EMIT_CONFIG,56.func = NULL,57.ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]58},59[UCL_EMIT_YAML] = {60.name = "yaml",61.id = UCL_EMIT_YAML,62.func = NULL,63.ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]64},65[UCL_EMIT_MSGPACK] = {66.name = "msgpack",67.id = UCL_EMIT_MSGPACK,68.func = NULL,69.ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]70}71};7273static inline void74_ucl_emitter_free(void *p)75{7677free(p);78}7980/**81* Get standard emitter context for a specified emit_type82* @param emit_type type of emitter83* @return context or NULL if input is invalid84*/85const struct ucl_emitter_context *86ucl_emit_get_standard_context (enum ucl_emitter emit_type)87{88if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {89return &ucl_standard_emitters[emit_type];90}9192return NULL;93}9495/**96* Serialise string97* @param str string to emit98* @param buf target buffer99*/100void101ucl_elt_string_write_json (const char *str, size_t size,102struct ucl_emitter_context *ctx)103{104const char *p = str, *c = str;105size_t len = 0;106const struct ucl_emitter_functions *func = ctx->func;107108func->ucl_emitter_append_character ('"', 1, func->ud);109110while (size) {111if (ucl_test_character (*p, (UCL_CHARACTER_JSON_UNSAFE|112UCL_CHARACTER_DENIED|113UCL_CHARACTER_WHITESPACE_UNSAFE))) {114if (len > 0) {115func->ucl_emitter_append_len (c, len, func->ud);116}117switch (*p) {118case '\n':119func->ucl_emitter_append_len ("\\n", 2, func->ud);120break;121case '\r':122func->ucl_emitter_append_len ("\\r", 2, func->ud);123break;124case '\b':125func->ucl_emitter_append_len ("\\b", 2, func->ud);126break;127case '\t':128func->ucl_emitter_append_len ("\\t", 2, func->ud);129break;130case '\f':131func->ucl_emitter_append_len ("\\f", 2, func->ud);132break;133case '\v':134func->ucl_emitter_append_len ("\\u000B", 6, func->ud);135break;136case '\\':137func->ucl_emitter_append_len ("\\\\", 2, func->ud);138break;139case ' ':140func->ucl_emitter_append_character (' ', 1, func->ud);141break;142case '"':143func->ucl_emitter_append_len ("\\\"", 2, func->ud);144break;145default:146/* Emit unicode unknown character */147func->ucl_emitter_append_len ("\\uFFFD", 6, func->ud);148break;149}150len = 0;151c = ++p;152}153else {154p ++;155len ++;156}157size --;158}159160if (len > 0) {161func->ucl_emitter_append_len (c, len, func->ud);162}163164func->ucl_emitter_append_character ('"', 1, func->ud);165}166167void168ucl_elt_string_write_squoted (const char *str, size_t size,169struct ucl_emitter_context *ctx)170{171const char *p = str, *c = str;172size_t len = 0;173const struct ucl_emitter_functions *func = ctx->func;174175func->ucl_emitter_append_character ('\'', 1, func->ud);176177while (size) {178if (*p == '\'') {179if (len > 0) {180func->ucl_emitter_append_len (c, len, func->ud);181}182183len = 0;184c = ++p;185func->ucl_emitter_append_len ("\\\'", 2, func->ud);186}187else {188p ++;189len ++;190}191size --;192}193194if (len > 0) {195func->ucl_emitter_append_len (c, len, func->ud);196}197198func->ucl_emitter_append_character ('\'', 1, func->ud);199}200201void202ucl_elt_string_write_multiline (const char *str, size_t size,203struct ucl_emitter_context *ctx)204{205const struct ucl_emitter_functions *func = ctx->func;206207func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud);208func->ucl_emitter_append_len (str, size, func->ud);209func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud);210}211212/*213* Generic utstring output214*/215static int216ucl_utstring_append_character (unsigned char c, size_t len, void *ud)217{218UT_string *buf = ud;219220if (len == 1) {221utstring_append_c (buf, c);222}223else {224utstring_reserve (buf, len + 1);225memset (&buf->d[buf->i], c, len);226buf->i += len;227buf->d[buf->i] = '\0';228}229230return 0;231}232233static int234ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)235{236UT_string *buf = ud;237238utstring_append_len (buf, str, len);239240return 0;241}242243static int244ucl_utstring_append_int (int64_t val, void *ud)245{246UT_string *buf = ud;247248utstring_printf (buf, "%jd", (intmax_t)val);249return 0;250}251252static int253ucl_utstring_append_double (double val, void *ud)254{255UT_string *buf = ud;256const double delta = 0.0000001;257258if (val == (double)(int)val) {259utstring_printf (buf, "%.1lf", val);260}261else if (fabs (val - (double)(int)val) < delta) {262/* Write at maximum precision */263utstring_printf (buf, "%.*lg", DBL_DIG, val);264}265else {266utstring_printf (buf, "%lf", val);267}268269return 0;270}271272/*273* Generic file output274*/275static int276ucl_file_append_character (unsigned char c, size_t len, void *ud)277{278FILE *fp = ud;279280while (len --) {281fputc (c, fp);282}283284return 0;285}286287static int288ucl_file_append_len (const unsigned char *str, size_t len, void *ud)289{290FILE *fp = ud;291292fwrite (str, len, 1, fp);293294return 0;295}296297static int298ucl_file_append_int (int64_t val, void *ud)299{300FILE *fp = ud;301302fprintf (fp, "%jd", (intmax_t)val);303304return 0;305}306307static int308ucl_file_append_double (double val, void *ud)309{310FILE *fp = ud;311const double delta = 0.0000001;312313if (val == (double)(int)val) {314fprintf (fp, "%.1lf", val);315}316else if (fabs (val - (double)(int)val) < delta) {317/* Write at maximum precision */318fprintf (fp, "%.*lg", DBL_DIG, val);319}320else {321fprintf (fp, "%lf", val);322}323324return 0;325}326327/*328* Generic file descriptor writing functions329*/330static int331ucl_fd_append_character (unsigned char c, size_t len, void *ud)332{333int fd = *(int *)ud;334unsigned char *buf;335336if (len == 1) {337return write (fd, &c, 1);338}339else {340buf = malloc (len);341if (buf == NULL) {342/* Fallback */343while (len --) {344if (write (fd, &c, 1) == -1) {345return -1;346}347}348}349else {350memset (buf, c, len);351if (write (fd, buf, len) == -1) {352free(buf);353return -1;354}355free (buf);356}357}358359return 0;360}361362static int363ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)364{365int fd = *(int *)ud;366367return write (fd, str, len);368}369370static int371ucl_fd_append_int (int64_t val, void *ud)372{373int fd = *(int *)ud;374char intbuf[64];375376snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);377return write (fd, intbuf, strlen (intbuf));378}379380static int381ucl_fd_append_double (double val, void *ud)382{383int fd = *(int *)ud;384const double delta = 0.0000001;385char nbuf[64];386387if (val == (double)(int)val) {388snprintf (nbuf, sizeof (nbuf), "%.1lf", val);389}390else if (fabs (val - (double)(int)val) < delta) {391/* Write at maximum precision */392snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);393}394else {395snprintf (nbuf, sizeof (nbuf), "%lf", val);396}397398return write (fd, nbuf, strlen (nbuf));399}400401struct ucl_emitter_functions*402ucl_object_emit_memory_funcs (void **pmem)403{404struct ucl_emitter_functions *f;405UT_string *s;406407f = calloc (1, sizeof (*f));408409if (f != NULL) {410f->ucl_emitter_append_character = ucl_utstring_append_character;411f->ucl_emitter_append_double = ucl_utstring_append_double;412f->ucl_emitter_append_int = ucl_utstring_append_int;413f->ucl_emitter_append_len = ucl_utstring_append_len;414f->ucl_emitter_free_func = _ucl_emitter_free;415utstring_new (s);416f->ud = s;417*pmem = s->d;418s->pd = pmem;419}420421return f;422}423424struct ucl_emitter_functions*425ucl_object_emit_file_funcs (FILE *fp)426{427struct ucl_emitter_functions *f;428429f = calloc (1, sizeof (*f));430431if (f != NULL) {432f->ucl_emitter_append_character = ucl_file_append_character;433f->ucl_emitter_append_double = ucl_file_append_double;434f->ucl_emitter_append_int = ucl_file_append_int;435f->ucl_emitter_append_len = ucl_file_append_len;436f->ucl_emitter_free_func = NULL;437f->ud = fp;438}439440return f;441}442443struct ucl_emitter_functions*444ucl_object_emit_fd_funcs (int fd)445{446struct ucl_emitter_functions *f;447int *ip;448449f = calloc (1, sizeof (*f));450451if (f != NULL) {452ip = malloc (sizeof (fd));453if (ip == NULL) {454free (f);455return NULL;456}457458memcpy (ip, &fd, sizeof (fd));459f->ucl_emitter_append_character = ucl_fd_append_character;460f->ucl_emitter_append_double = ucl_fd_append_double;461f->ucl_emitter_append_int = ucl_fd_append_int;462f->ucl_emitter_append_len = ucl_fd_append_len;463f->ucl_emitter_free_func = _ucl_emitter_free;464f->ud = ip;465}466467return f;468}469470void471ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)472{473if (f != NULL) {474if (f->ucl_emitter_free_func != NULL) {475f->ucl_emitter_free_func (f->ud);476}477free (f);478}479}480481482unsigned char *483ucl_object_emit_single_json (const ucl_object_t *obj)484{485UT_string *buf = NULL;486unsigned char *res = NULL;487488if (obj == NULL) {489return NULL;490}491492utstring_new (buf);493494if (buf != NULL) {495switch (obj->type) {496case UCL_OBJECT:497ucl_utstring_append_len ("object", 6, buf);498break;499case UCL_ARRAY:500ucl_utstring_append_len ("array", 5, buf);501break;502case UCL_INT:503ucl_utstring_append_int (obj->value.iv, buf);504break;505case UCL_FLOAT:506case UCL_TIME:507ucl_utstring_append_double (obj->value.dv, buf);508break;509case UCL_NULL:510ucl_utstring_append_len ("null", 4, buf);511break;512case UCL_BOOLEAN:513if (obj->value.iv) {514ucl_utstring_append_len ("true", 4, buf);515}516else {517ucl_utstring_append_len ("false", 5, buf);518}519break;520case UCL_STRING:521ucl_utstring_append_len (obj->value.sv, obj->len, buf);522break;523case UCL_USERDATA:524ucl_utstring_append_len ("userdata", 8, buf);525break;526}527res = utstring_body (buf);528free (buf);529}530531return res;532}533534#define LONG_STRING_LIMIT 80535536bool537ucl_maybe_long_string (const ucl_object_t *obj)538{539if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {540/* String is long enough, so search for newline characters in it */541if (memchr (obj->value.sv, '\n', obj->len) != NULL) {542return true;543}544}545546return false;547}548549550