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.

-- 
: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      1 May 2023 20:07:26 -0000
@@ -19,6 +19,7 @@
 #include <err.h>
 #include <stdarg.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -179,16 +180,64 @@ 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') {
+               /* skip escaping '/' since our use case does not require it */
+               switch(c) {
+               case '"':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\\"") < 0;
+                       break;
+               case '\\':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\\\") < 0;
+                       break;
+               case '\b':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\b") < 0;
+                       break;
+               case '\f':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\f") < 0;
+                       break;
+               case '\n':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\n") < 0;
+                       break;
+               case '\r':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\r") < 0;
+                       break;
+               case '\t':
+                       if (!eb)
+                               eb = fprintf(jsonfh, "\\t") < 0;
+                       break;
+               default:
+                       if (!eb)
+                               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