aboutsummaryrefslogtreecommitdiff
path: root/lib/sg_pr2serr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sg_pr2serr.c')
-rw-r--r--lib/sg_pr2serr.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
new file mode 100644
index 00000000..5bb87acf
--- /dev/null
+++ b/lib/sg_pr2serr.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2022 Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "sg_pr2serr.h"
+#include "sg_json_builder.h"
+
+/*
+ * #define json_serialize_mode_multiline 0
+ * #define json_serialize_mode_single_line 1
+ * #define json_serialize_mode_packed 2
+ *
+ * #define json_serialize_opt_CRLF (1 << 1)
+ * #define json_serialize_opt_pack_brackets (1 << 2)
+ * #define json_serialize_opt_no_space_after_comma (1 << 3)
+ * #define json_serialize_opt_no_space_after_colon (1 << 4)
+ * #define json_serialize_opt_use_tabs (1 << 5)
+ */
+
+
+static const json_serialize_opts def_out_settings = {
+ json_serialize_mode_multiline, /* one of serialize_mode_* */
+ 0, /* serialize_opt_* OR-ed together */
+ 4 /* indent size */
+};
+
+/* Users of the sg_pr2serr.h header need this function definition */
+int
+pr2serr(const char * fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vfprintf(stderr, fmt, args);
+ va_end(args);
+ return n;
+}
+
+void
+sg_json_init_state(sg_json_state * jstp)
+{
+ jstp->pr_as_json = true;
+ jstp->pr_pretty = true;
+ jstp->pr_sorted = false;
+ jstp->pr_output = false;
+ jstp->pr_implemented = false;
+ jstp->pr_unimplemented = false;
+ jstp->pr_format = 0;
+ jstp->verbose = 0;
+ jstp->pr_indent_size = 4;
+ jstp->basep = NULL;
+ jstp->outputp = NULL;
+ jstp->userp = NULL;
+}
+
+sg_json_opaque_p
+sg_json_start(const char * util_name, const char * ver_str, int argc,
+ char *argv[], sg_json_state * jstp)
+{
+ int k;
+ json_value * jvp = json_object_new(0);
+ json_value * jv2p;
+ json_value * jap = json_array_new(0);
+
+ if ((NULL == jvp) || (NULL == jap)) {
+ if (jvp)
+ json_builder_free(jvp);
+ if (jap)
+ json_builder_free(jap);
+ return NULL;
+ }
+ jstp->basep = jvp;
+ json_array_push(jap, json_integer_new(1));
+ json_array_push(jap, json_integer_new(0));
+ json_object_push(jvp, "json_format_version", jap);
+ jap = json_array_new(0);
+ for (k = 0; k < argc; ++k)
+ json_array_push(jap, json_string_new(argv[k]));
+ jv2p = json_object_push(jvp, util_name, json_object_new(0));
+ if (ver_str)
+ json_object_push(jv2p, "version_date", json_string_new(ver_str));
+ else
+ json_object_push(jv2p, "version_date", json_string_new("0.0"));
+ json_object_push(jv2p, "argv", jap);
+ if (jstp->pr_output)
+ jstp->outputp = json_object_push(jv2p, "output", json_array_new(0));
+ return jvp;
+}
+
+void
+sgj_pr2file(sg_json_opaque_p jop, sg_json_state * jstp, FILE * fp)
+{
+ size_t len;
+ char * b;
+ json_value * jvp = (json_value *)jop;
+ json_serialize_opts out_settings;
+
+ memcpy(&out_settings, &def_out_settings, sizeof(out_settings));
+ if (jstp->pr_indent_size != def_out_settings.indent_size)
+ out_settings.indent_size = jstp->pr_indent_size;
+ if (! jstp->pr_pretty)
+ out_settings.mode = json_serialize_mode_single_line;
+
+ len = json_measure_ex(jvp, out_settings);
+ if (len < 1)
+ return;
+ if (jstp->verbose > 3)
+ fprintf(fp, "%s: serialization length: %zu bytes\n", __func__, len);
+ b = calloc(len, 1);
+ if (NULL == b) {
+ if (jstp->verbose > 3)
+ pr2serr("%s: unable to get %zu bytes on heap\n", __func__, len);
+ return;
+ }
+ json_serialize_ex(b, jvp, out_settings);
+ if (jstp->verbose > 3)
+ fprintf(fp, "json serialized:\n");
+ fprintf(fp, "%s\n", b);
+}
+
+void
+sg_json_free(sg_json_opaque_p jop)
+{
+ json_value * jvp = (json_value *)jop;
+
+ json_builder_free(jvp);
+}
+
+void
+sgj_pr_hr(sg_json_state * jsp, const char * fmt, ...)
+{
+ va_list args;
+
+ if (jsp->pr_as_json && jsp->pr_output) {
+ size_t len;
+ char b[256];
+
+ va_start(args, fmt);
+ len = vsnprintf(b, sizeof(b), fmt, args);
+ if ((len > 0) && (len < sizeof(b))) {
+ const char * cp = b;
+
+ if (b[len - 1] == '\n') {
+ b[len - 1] = '\0';
+ --len;
+ }
+ if ((len > 0) && ('\n' == b[0]))
+ ++cp;
+ json_array_push(jsp->outputp, json_string_new(cp));
+ }
+ va_end(args);
+ } else if (jsp->pr_as_json) {
+ va_start(args, fmt);
+ va_end(args);
+ } else {
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ va_end(args);
+ }
+}
+
+sg_json_opaque_p
+sgj_new_named_object(sg_json_state * jsp, sg_json_opaque_p jop,
+ const char * name)
+{
+ sg_json_opaque_p resp = NULL;
+
+ if (jsp->pr_as_json)
+ resp = json_object_push(jop, name, json_object_new(0));
+ return resp;
+}
+
+sg_json_opaque_p
+sgj_new_named_array(sg_json_state * jsp, sg_json_opaque_p jop,
+ const char * name)
+{
+ sg_json_opaque_p resp = NULL;
+
+ if (jsp->pr_as_json)
+ resp = json_object_push(jop, name, json_array_new(0));
+ return resp;
+}
+
+sg_json_opaque_p
+sgj_add_array_element(sg_json_state * jsp, sg_json_opaque_p jap,
+ sg_json_opaque_p ejop)
+{
+ if (jsp->pr_as_json)
+ return json_array_push(jap, ejop);
+ else
+ return NULL;
+}
+
+/* Newly created object is un-attached */
+sg_json_opaque_p
+sgj_new_object(sg_json_state * jsp)
+{
+ return jsp->pr_as_json ? json_object_new(0) : NULL;
+}
+
+sg_json_opaque_p
+sgj_add_name_vs(sg_json_state * jsp, sg_json_opaque_p jop, const char * name,
+ const char * value)
+{
+ if (jsp->pr_as_json)
+ return json_object_push(jop, name, json_string_new(value));
+ else
+ return NULL;
+}
+
+sg_json_opaque_p
+sgj_add_name_vi(sg_json_state * jsp, sg_json_opaque_p jop, const char * name,
+ int64_t value)
+{
+ if (jsp->pr_as_json)
+ return json_object_push(jop, name, json_integer_new(value));
+ else
+ return NULL;
+}
+
+sg_json_opaque_p
+sgj_add_name_vb(sg_json_state * jsp, sg_json_opaque_p jop, const char * name,
+ bool value)
+{
+ if (jsp->pr_as_json)
+ return json_object_push(jop, name, json_boolean_new(value));
+ else
+ return NULL;
+}