From 5a0dd9446d979e684da5b659d2d6011f4cbfc04c Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Thu, 13 Oct 2022 20:48:17 -0700 Subject: [PATCH] JSON plugin stoj: use a statically sized staging buffer instead of an agxbuf This removes some dynamic allocation, as well as making this function now thread safe. Note that the contained call to `latin1ToUTF8` still allocates. --- plugin/core/gvrender_core_json.c | 44 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/plugin/core/gvrender_core_json.c b/plugin/core/gvrender_core_json.c index 53d7b5dff..7ce4ace7c 100644 --- a/plugin/core/gvrender_core_json.c +++ b/plugin/core/gvrender_core_json.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include -#include #include #include #include @@ -87,7 +87,6 @@ static void json_begin_graph(GVJ_t *job) static void stoj(char *ins, state_t *sp, GVJ_t *job) { char* s; char* input; - static agxbuf xb; char c; if (sp->isLatin) @@ -95,44 +94,55 @@ static void stoj(char *ins, state_t *sp, GVJ_t *job) { else input = ins; - if (xb.buf == NULL) - agxbinit(&xb, BUFSIZ, NULL); + // a block of data we will accrue before periodically flushing to output + char chunk[BUFSIZ]; + size_t used = 0; + + gvputc(job, '"'); for (s = input; (c = *s); s++) { switch (c) { case '"' : - agxbput(&xb, "\\\""); - break; case '\\' : - agxbput(&xb, "\\\\"); - break; case '/' : - agxbput(&xb, "\\/"); + chunk[used++] = '\\'; + chunk[used++] = c; break; case '\b' : - agxbput(&xb, "\\b"); + chunk[used++] = '\\'; + chunk[used++] = 'b'; break; case '\f' : - agxbput(&xb, "\\f"); + chunk[used++] = '\\'; + chunk[used++] = 'f'; break; case '\n' : - agxbput(&xb, "\\n"); + chunk[used++] = '\\'; + chunk[used++] = 'n'; break; case '\r' : - agxbput(&xb, "\\r"); + chunk[used++] = '\\'; + chunk[used++] = 'r'; break; case '\t' : - agxbput(&xb, "\\t"); + chunk[used++] = '\\'; + chunk[used++] = 't'; break; default : - agxbputc(&xb, c); + chunk[used++] = c; break; } + + // if we are at the upper limit of our accrued chunk or if this is the last + // loop iteration, flush to the output stream + if (used > sizeof(chunk) - strlen("\\/") || *(s + 1) == '\0') { + gvwrite(job, chunk, used); + used = 0; + } } - s = agxbuse(&xb); + gvputc(job, '"'); if (sp->isLatin) free (input); - gvprintf(job, "\"%s\"", s); } static void indent(GVJ_t * job, int level) -- 2.40.0