On Tue, May 02, 2023 at 02:29:20PM +0200, Theo Buehler wrote:
> On Tue, May 02, 2023 at 02:13:27PM +0200, Claudio Jeker wrote:
> > Add a json_do_string() a function to print a JSON string.
> > This function does the needed encoding of control chars and escape chars.
> > I skipped the optional encoding of the forward slash (/) since this is
> > only needed if the json output is embedded in HTML/SGML/XML.
> > People putting JSON into such documents need to pass this through an extra
> > step.
> > 
> > This implements json_do_printf() now as a wrapper around json_do_string().
> > All users of json_do_printf(name, "%s", value) can be converted to
> > json_do_string(). I will do this is a subsequent step.
> 
> I'm ok with this. Some comments below.

How about this version? By moving the !eb check into the while loop the
if checks fall away and so it is just one fprintf() per case. I think
trying to optimize this further is not that benefitial. I wonder if the
compiler wont do that better anyway.

-- 
:wq Claudio

Index: json.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/json.c,v
retrieving revision 1.1
diff -u -p -r1.1 json.c
--- json.c      27 Apr 2023 07:57:25 -0000      1.1
+++ json.c      2 May 2023 12:39:36 -0000
@@ -20,6 +20,7 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "json.h"
@@ -179,16 +180,56 @@ void
 json_do_printf(const char *name, const char *fmt, ...)
 {
        va_list ap;
+       char *str;
 
-       do_comma_indent();
+       va_start(ap, fmt);
+       if (!eb) {
+               if (vasprintf(&str, fmt, ap) == -1)
+                       errx(1, "json printf failed");
+               json_do_string(name, str);
+               free(str);
+       }
+       va_end(ap);
+}
 
+void
+json_do_string(const char *name, const char *v)
+{
+       int c;
+
+       do_comma_indent();
        do_name(name);
        if (!eb)
                eb = fprintf(jsonfh, "\"") < 0;
-       va_start(ap, fmt);
-       if (!eb)
-               eb = vfprintf(jsonfh, fmt, ap) < 0;
-       va_end(ap);
+       while ((c = *v++) != '\0' && !eb) {
+               /* skip escaping '/' since our use case does not require it */
+               switch(c) {
+               case '"':
+                       eb = fprintf(jsonfh, "\\\"") < 0;
+                       break;
+               case '\\':
+                       eb = fprintf(jsonfh, "\\\\") < 0;
+                       break;
+               case '\b':
+                       eb = fprintf(jsonfh, "\\b") < 0;
+                       break;
+               case '\f':
+                       eb = fprintf(jsonfh, "\\f") < 0;
+                       break;
+               case '\n':
+                       eb = fprintf(jsonfh, "\\n") < 0;
+                       break;
+               case '\r':
+                       eb = fprintf(jsonfh, "\\r") < 0;
+                       break;
+               case '\t':
+                       eb = fprintf(jsonfh, "\\t") < 0;
+                       break;
+               default:
+                       eb = putc(c, jsonfh) == EOF;
+                       break;
+               }
+       }
        if (!eb)
                eb = fprintf(jsonfh, "\"") < 0;
 }
Index: json.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/json.h,v
retrieving revision 1.1
diff -u -p -r1.1 json.h
--- json.h      27 Apr 2023 07:57:25 -0000      1.1
+++ json.h      30 Apr 2023 15:11:36 -0000
@@ -26,6 +26,7 @@ void  json_do_object(const char *);
 void   json_do_end(void);
 void   json_do_printf(const char *, const char *, ...)
            __attribute__((__format__ (printf, 2, 3)));
+void   json_do_string(const char *, const char *);
 void   json_do_hexdump(const char *, void *, size_t);
 void   json_do_bool(const char *, int);
 void   json_do_uint(const char *, unsigned long long);

Reply via email to