changeset 19684:cecbfa036d9f

doveadm: Add JSON formatter support
author Aki Tuomi <aki.tuomi@dovecot.net>
date Thu, 21 Jan 2016 19:49:12 +0200
parents c020ef5e168a
children 71627df01608
files src/doveadm/Makefile.am src/doveadm/doveadm-print-json.c src/doveadm/doveadm-print-private.h src/doveadm/doveadm-print.h src/doveadm/doveadm.c src/doveadm/main.c
diffstat 6 files changed, 158 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/Makefile.am	Mon Jan 25 10:50:23 2016 +0200
+++ b/src/doveadm/Makefile.am	Thu Jan 21 19:49:12 2016 +0200
@@ -127,12 +127,14 @@
 	doveadm-print-pager.c \
 	doveadm-print-tab.c \
 	doveadm-print-table.c \
+	doveadm-print-json.c \
 	doveadm-pw.c
 
 doveadm_server_SOURCES = \
 	$(common) \
 	client-connection.c \
 	doveadm-print-server.c \
+	doveadm-print-json.c \
 	main.c
 
 pkginc_libdir = $(pkgincludedir)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/doveadm/doveadm-print-json.c	Thu Jan 21 19:49:12 2016 +0200
@@ -0,0 +1,152 @@
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "strescape.h"
+#include "ostream.h"
+#include "json-parser.h"
+#include "client-connection.h"
+#include "doveadm-server.h"
+#include "doveadm-print.h"
+#include "doveadm-print-private.h"
+
+struct doveadm_print_json_context {
+	unsigned int header_idx, header_count;
+	bool first_row;
+	ARRAY(struct doveadm_print_header) headers;
+	pool_t pool;
+	string_t *str;
+};
+
+static struct doveadm_print_json_context ctx;
+
+static void doveadm_print_json_flush_internal(void);
+
+static void doveadm_print_json_init(void)
+{
+	ctx.pool = pool_alloconly_create("doveadm json print", 1024);
+	ctx.str = str_new(ctx.pool, 256);
+	p_array_init(&ctx.headers, ctx.pool, 1);
+	ctx.first_row = TRUE;
+}
+
+static void
+doveadm_print_json_header(const struct doveadm_print_header *hdr)
+{
+	struct doveadm_print_header *lhdr;
+	lhdr = array_append_space(&ctx.headers);
+	lhdr->key = p_strdup(ctx.pool, hdr->key);
+	lhdr->flags = hdr->flags;
+	ctx.header_count++;
+}
+
+static void
+doveadm_print_json_value_header(const struct doveadm_print_header *hdr)
+{
+	// get header name
+	if (ctx.header_idx == 0) {
+		if (ctx.first_row == TRUE) {
+			ctx.first_row = FALSE;
+			str_append_c(ctx.str, '[');
+		} else {
+			str_append_c(ctx.str, ',');
+		}
+		str_append_c(ctx.str, '{');
+	} else {
+		str_append_c(ctx.str, ',');
+	}
+
+	str_append_c(ctx.str, '"');
+	json_append_escaped(ctx.str, hdr->key);
+	str_append_c(ctx.str, '"');
+	str_append_c(ctx.str, ':');
+}
+
+static void
+doveadm_print_json_value_footer(void) {
+	if (++ctx.header_idx == ctx.header_count) {
+		ctx.header_idx = 0;
+		str_append_c(ctx.str, '}');
+		doveadm_print_json_flush_internal();
+	}
+}
+
+static void doveadm_print_json_print(const char *value)
+{
+	const struct doveadm_print_header *hdr = array_idx(&ctx.headers, ctx.header_idx);
+
+	doveadm_print_json_value_header(hdr);
+
+	if (value == NULL) {
+		str_append(ctx.str, "null");
+	} else if ((hdr->flags & DOVEADM_PRINT_HEADER_FLAG_NUMBER) != 0) {
+		i_assert(str_is_float(value, '\0'));
+		str_append(ctx.str, value);
+	} else {
+		str_append_c(ctx.str, '"');
+		json_append_escaped(ctx.str, value);
+		str_append_c(ctx.str, '"');
+	}
+
+	doveadm_print_json_value_footer();
+}
+
+static void
+doveadm_print_json_print_stream(const unsigned char *value, size_t size)
+{
+	if (size == 0) {
+		doveadm_print_json_print("");
+		return;
+	}
+
+	const struct doveadm_print_header *hdr = array_idx(&ctx.headers, ctx.header_idx);
+
+	doveadm_print_json_value_header(hdr);
+
+	if ((hdr->flags & DOVEADM_PRINT_HEADER_FLAG_NUMBER) != 0) {
+		i_assert(str_is_float((const char*)value, (char)value[size]));
+		str_append_data(ctx.str, value, size);
+	} else {
+		str_append_c(ctx.str, '"');
+		json_append_escaped_data(ctx.str, value, size);
+		str_append_c(ctx.str, '"');
+	}
+
+	doveadm_print_json_value_footer();
+
+	if (str_len(ctx.str) >= IO_BLOCK_SIZE)
+		doveadm_print_json_flush_internal();
+}
+
+static void doveadm_print_json_flush_internal(void)
+{
+	o_stream_nsend(doveadm_print_ostream, str_data(ctx.str), str_len(ctx.str));
+	str_truncate(ctx.str, 0);
+}
+
+static void doveadm_print_json_flush(void)
+{
+	if (ctx.first_row == FALSE)
+		str_append_c(ctx.str,']');
+	else {
+		str_append_c(ctx.str,'[');
+		str_append_c(ctx.str,']');
+	}
+	doveadm_print_json_flush_internal();
+}
+
+static void doveadm_print_json_deinit(void)
+{
+	pool_unref(&ctx.pool);
+}
+
+struct doveadm_print_vfuncs doveadm_print_json_vfuncs = {
+	"json",
+
+	doveadm_print_json_init,
+	doveadm_print_json_deinit,
+	doveadm_print_json_header,
+	doveadm_print_json_print,
+	doveadm_print_json_print_stream,
+	doveadm_print_json_flush
+};
+
--- a/src/doveadm/doveadm-print-private.h	Mon Jan 25 10:50:23 2016 +0200
+++ b/src/doveadm/doveadm-print-private.h	Thu Jan 21 19:49:12 2016 +0200
@@ -25,5 +25,6 @@
 extern struct doveadm_print_vfuncs doveadm_print_tab_vfuncs;
 extern struct doveadm_print_vfuncs doveadm_print_table_vfuncs;
 extern struct doveadm_print_vfuncs doveadm_print_pager_vfuncs;
+extern struct doveadm_print_vfuncs doveadm_print_json_vfuncs;
 
 #endif
--- a/src/doveadm/doveadm-print.h	Mon Jan 25 10:50:23 2016 +0200
+++ b/src/doveadm/doveadm-print.h	Thu Jan 21 19:49:12 2016 +0200
@@ -5,6 +5,7 @@
 #define DOVEADM_PRINT_TYPE_FLOW "flow"
 #define DOVEADM_PRINT_TYPE_TABLE "table"
 #define DOVEADM_PRINT_TYPE_SERVER "server"
+#define DOVEADM_PRINT_TYPE_JSON "json"
 
 enum doveadm_print_header_flags {
 	DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY 	= 0x01,
--- a/src/doveadm/doveadm.c	Mon Jan 25 10:50:23 2016 +0200
+++ b/src/doveadm/doveadm.c	Thu Jan 21 19:49:12 2016 +0200
@@ -24,6 +24,7 @@
 	&doveadm_print_tab_vfuncs,
 	&doveadm_print_table_vfuncs,
 	&doveadm_print_pager_vfuncs,
+	&doveadm_print_json_vfuncs,
 	NULL
 };
 
--- a/src/doveadm/main.c	Mon Jan 25 10:50:23 2016 +0200
+++ b/src/doveadm/main.c	Thu Jan 21 19:49:12 2016 +0200
@@ -62,6 +62,7 @@
 	doveadm_mail_init();
 	doveadm_load_modules();
 	doveadm_print_init(DOVEADM_PRINT_TYPE_SERVER);
+        doveadm_print_init(DOVEADM_PRINT_TYPE_JSON);
 }
 
 static void main_deinit(void)