From 03f06b947205d2d7d4a067a297271debd973f342 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Sat, 1 Oct 2022 00:12:09 -0500 Subject: [PATCH] base: Prettier JSON output / options - Add flags for indenting with 2, 4, or 8 spaces, still defaulting to tabs if none of those are set. - Don't emit a newline before emitting scalar values in dicts. --- lib/base/heimbase.h | 6 ++++- lib/base/json.c | 60 +++++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/base/heimbase.h b/lib/base/heimbase.h index 3706fc871..76af38f94 100644 --- a/lib/base/heimbase.h +++ b/lib/base/heimbase.h @@ -463,7 +463,11 @@ typedef enum heim_json_flags { HEIM_JSON_F_STRICT = 31, HEIM_JSON_F_CNULL2JSNULL = 32, HEIM_JSON_F_TRY_DECODE_DATA = 64, - HEIM_JSON_F_ONE_LINE = 128 + HEIM_JSON_F_ONE_LINE = 128, + /* The default is to indent with one tab */ + HEIM_JSON_F_INDENT2 = 256, + HEIM_JSON_F_INDENT4 = 512, + HEIM_JSON_F_INDENT8 = 1024, } heim_json_flags_t; heim_object_t heim_json_create(const char *, size_t, heim_json_flags_t, diff --git a/lib/base/json.c b/lib/base/json.c index cf69e4b00..605d34a6d 100644 --- a/lib/base/json.c +++ b/lib/base/json.c @@ -66,7 +66,7 @@ struct heim_strbuf { }; static int -base2json(heim_object_t, struct twojson *); +base2json(heim_object_t, struct twojson *, int); static void indent(struct twojson *j) @@ -74,8 +74,18 @@ indent(struct twojson *j) size_t i = j->indent; if (j->flags & HEIM_JSON_F_ONE_LINE) return; - while (i--) - j->out(j->ctx, "\t"); + if (j->flags & HEIM_JSON_F_INDENT2) + while (i--) + j->out(j->ctx, " "); + else if (j->flags & HEIM_JSON_F_INDENT4) + while (i--) + j->out(j->ctx, " "); + else if (j->flags & HEIM_JSON_F_INDENT8) + while (i--) + j->out(j->ctx, " "); + else + while (i--) + j->out(j->ctx, "\t"); } static void @@ -90,7 +100,7 @@ array2json(heim_object_t value, void *ctx, int *stop) j->out(j->ctx, NULL); /* eat previous '\n' if possible */ j->out(j->ctx, ",\n"); } - j->ret = base2json(value, j); + j->ret = base2json(value, j, 0); } static void @@ -105,19 +115,29 @@ dict2json(heim_object_t key, heim_object_t value, void *ctx) j->out(j->ctx, NULL); /* eat previous '\n' if possible */ j->out(j->ctx, ",\n"); } - j->ret = base2json(key, j); + j->ret = base2json(key, j, 0); if (j->ret) return; - j->out(j->ctx, " : \n"); - j->indent++; - j->ret = base2json(value, j); - if (j->ret) - return; - j->indent--; + switch (heim_get_tid(value)) { + case HEIM_TID_ARRAY: + case HEIM_TID_DICT: + case HEIM_TID_DATA: + j->out(j->ctx, ":\n"); + j->indent++; + j->ret = base2json(value, j, 0); + if (j->ret) + return; + j->indent--; + break; + default: + j->out(j->ctx, ": "); + j->ret = base2json(value, j, 1); + break; + } } static int -base2json(heim_object_t obj, struct twojson *j) +base2json(heim_object_t obj, struct twojson *j, int skip_indent) { heim_tid_t type; int first = 0; @@ -174,7 +194,8 @@ base2json(heim_object_t obj, struct twojson *j) int good; size_t i; - indent(j); + if (!skip_indent) + indent(j); j->out(j->ctx, "\""); for (p = s; (c = *p); p++) { switch (c) { @@ -383,7 +404,7 @@ base2json(heim_object_t obj, struct twojson *j) heim_release(d); return ENOMEM; } - ret = base2json(d, j); + ret = base2json(d, j, 0); heim_release(d); if (ret) return ret; @@ -393,17 +414,20 @@ base2json(heim_object_t obj, struct twojson *j) case HEIM_TID_NUMBER: { char num[32]; - indent(j); + if (!skip_indent) + indent(j); snprintf(num, sizeof (num), "%d", heim_number_get_int(obj)); j->out(j->ctx, num); break; } case HEIM_TID_NULL: - indent(j); + if (!skip_indent) + indent(j); j->out(j->ctx, "null"); break; case HEIM_TID_BOOL: - indent(j); + if (!skip_indent) + indent(j); j->out(j->ctx, heim_bool_val(obj) ? "true" : "false"); break; default: @@ -427,7 +451,7 @@ heim_base2json(heim_object_t obj, void *ctx, heim_json_flags_t flags, j.ret = 0; j.first = 1; - return base2json(obj, &j); + return base2json(obj, &j, 0); }