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.
> --
> :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>
I'd move this below stdio.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') {
Should this include && !eb?
> + /* skip escaping '/' since our use case does not require it */
> + switch(c) {
> + case '"':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\\"") < 0;
It's fine as it is, but the repetition could be avoided by assigning the
escaped string or c to a temporary variable and do the printing after
the switch. Your call.
> + 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);
>