From 5e4d58a12e3b4c4fa97fe47195d61022784d02b2 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 13 Aug 2013 01:00:57 +0100 Subject: [PATCH] Add compacted json and config rcl emitters. --- src/rcl/rcl.h | 1 + src/rcl/rcl_emitter.c | 253 +++++++++++++++++++++++++++++++++++------- 2 files changed, 216 insertions(+), 38 deletions(-) diff --git a/src/rcl/rcl.h b/src/rcl/rcl.h index 545dd19f9..8d49cc8ad 100644 --- a/src/rcl/rcl.h +++ b/src/rcl/rcl.h @@ -54,6 +54,7 @@ enum rspamd_cl_type { enum rspamd_cl_emitter { RSPAMD_CL_EMIT_JSON = 0, + RSPAMD_CL_EMIT_JSON_COMPACT, RSPAMD_CL_EMIT_CONFIG }; diff --git a/src/rcl/rcl_emitter.c b/src/rcl/rcl_emitter.c index c8edf0d9e..05ca87da6 100644 --- a/src/rcl/rcl_emitter.c +++ b/src/rcl/rcl_emitter.c @@ -31,8 +31,9 @@ */ -static void rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs); -static void rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs); +static void rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact); +static void rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact); +static void rspamd_cl_elt_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean is_top); /** * Add tabulation to the output buffer @@ -40,9 +41,9 @@ static void rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, gui * @param tabs number of tabs to add */ static inline void -rspamd_cl_add_tabs (GString *buf, guint tabs) +rspamd_cl_add_tabs (GString *buf, guint tabs, gboolean compact) { - while (tabs--) { + while (!compact && tabs--) { g_string_append_len (buf, " ", 4); } } @@ -96,27 +97,42 @@ rspamd_cl_elt_string_write_json (const gchar *str, GString *buf) * @param buf target buffer */ static void -rspamd_cl_elt_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs) +rspamd_cl_elt_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact) { rspamd_cl_object_t *cur, *tmp; if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); + } + if (compact) { + g_string_append_c (buf, '{'); + } + else { + g_string_append_len (buf, "{\n", 2); } - g_string_append_len (buf, "{\n", 2); HASH_ITER (hh, obj, cur, tmp) { - rspamd_cl_add_tabs (buf, tabs + 1); + rspamd_cl_add_tabs (buf, tabs + 1, compact); rspamd_cl_elt_string_write_json (cur->key, buf); - g_string_append_len (buf, ": ", 2); - rspamd_cl_obj_write_json (cur, buf, tabs + 1, FALSE); - if (cur->hh.next != NULL) { - g_string_append_len (buf, ",\n", 2); + if (compact) { + g_string_append_c (buf, ':'); } else { + g_string_append_len (buf, ": ", 2); + } + rspamd_cl_obj_write_json (cur, buf, tabs + 1, FALSE, compact); + if (cur->hh.next != NULL) { + if (compact) { + g_string_append_c (buf, ','); + } + else { + g_string_append_len (buf, ",\n", 2); + } + } + else if (!compact) { g_string_append_c (buf, '\n'); } } - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); g_string_append_c (buf, '}'); } @@ -126,25 +142,35 @@ rspamd_cl_elt_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, * @param buf target buffer */ static void -rspamd_cl_elt_array_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs) +rspamd_cl_elt_array_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact) { rspamd_cl_object_t *cur = obj; if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); + } + if (compact) { + g_string_append_c (buf, '['); + } + else { + g_string_append_len (buf, "[\n", 2); } - g_string_append_len (buf, "[\n", 2); while (cur) { - rspamd_cl_elt_write_json (cur, buf, tabs + 1, TRUE); + rspamd_cl_elt_write_json (cur, buf, tabs + 1, TRUE, compact); if (cur->next != NULL) { - g_string_append_len (buf, ",\n", 2); + if (compact) { + g_string_append_c (buf, ','); + } + else { + g_string_append_len (buf, ",\n", 2); + } } - else { + else if (!compact) { g_string_append_c (buf, '\n'); } cur = cur->next; } - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); g_string_append_c (buf, ']'); } @@ -154,44 +180,44 @@ rspamd_cl_elt_array_write_json (rspamd_cl_object_t *obj, GString *buf, guint tab * @param buf buffer */ static void -rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs) +rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact) { switch (obj->type) { case RSPAMD_CL_INT: if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); } g_string_append_printf (buf, "%ld", (long int)rspamd_cl_obj_toint (obj)); break; case RSPAMD_CL_FLOAT: if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); } g_string_append_printf (buf, "%lf", rspamd_cl_obj_todouble (obj)); break; case RSPAMD_CL_TIME: if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); } g_string_append_printf (buf, "%lf", rspamd_cl_obj_todouble (obj)); break; case RSPAMD_CL_BOOLEAN: if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); } g_string_append_printf (buf, "%s", rspamd_cl_obj_toboolean (obj) ? "true" : "false"); break; case RSPAMD_CL_STRING: if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); } rspamd_cl_elt_string_write_json (rspamd_cl_obj_tostring (obj), buf); break; case RSPAMD_CL_OBJECT: - rspamd_cl_elt_obj_write_json (obj->value.ov, buf, tabs, start_tabs); + rspamd_cl_elt_obj_write_json (obj->value.ov, buf, tabs, start_tabs, compact); break; case RSPAMD_CL_ARRAY: - rspamd_cl_elt_array_write_json (obj->value.ov, buf, tabs, start_tabs); + rspamd_cl_elt_array_write_json (obj->value.ov, buf, tabs, start_tabs, compact); break; } } @@ -202,7 +228,7 @@ rspamd_cl_elt_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gbo * @param buf target buffer */ static void -rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs) +rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean compact) { rspamd_cl_object_t *cur; gboolean is_array = (obj->next != NULL); @@ -210,23 +236,31 @@ rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gbo if (is_array) { /* This is an array actually */ if (start_tabs) { - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); + } + + if (compact) { + g_string_append_c (buf, '['); + } + else { + g_string_append_len (buf, "[\n", 2); } - g_string_append_len (buf, "[\n", 2); cur = obj; while (cur != NULL) { - rspamd_cl_elt_write_json (cur, buf, tabs + 1, TRUE); + rspamd_cl_elt_write_json (cur, buf, tabs + 1, TRUE, compact); if (cur->next) { g_string_append_c (buf, ','); } - g_string_append_c (buf, '\n'); + if (!compact) { + g_string_append_c (buf, '\n'); + } cur = cur->next; } - rspamd_cl_add_tabs (buf, tabs); + rspamd_cl_add_tabs (buf, tabs, compact); g_string_append_c (buf, ']'); } else { - rspamd_cl_elt_write_json (obj, buf, tabs, start_tabs); + rspamd_cl_elt_write_json (obj, buf, tabs, start_tabs, compact); } } @@ -237,7 +271,144 @@ rspamd_cl_obj_write_json (rspamd_cl_object_t *obj, GString *buf, guint tabs, gbo * @return json output (should be freed after using) */ static guchar * -rspamd_cl_object_emit_json (rspamd_cl_object_t *obj) +rspamd_cl_object_emit_json (rspamd_cl_object_t *obj, gboolean compact) +{ + GString *buf; + guchar *res; + + /* Allocate large enough buffer */ + buf = g_string_sized_new (BUFSIZ); + + rspamd_cl_obj_write_json (obj, buf, 0, FALSE, compact); + + res = buf->str; + g_string_free (buf, FALSE); + + return res; +} + +/** + * Write a single object to the buffer + * @param obj object to write + * @param buf target buffer + */ +static void +rspamd_cl_elt_obj_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean is_top) +{ + rspamd_cl_object_t *cur, *tmp; + + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, is_top); + } + if (!is_top) { + g_string_append_len (buf, "{\n", 2); + } + + while (obj) { + HASH_ITER (hh, obj, cur, tmp) { + rspamd_cl_add_tabs (buf, tabs + 1, is_top); + g_string_append (buf, cur->key); + if (cur->type != RSPAMD_CL_OBJECT && cur->type != RSPAMD_CL_ARRAY) { + g_string_append_len (buf, " = ", 3); + } + else { + g_string_append_c (buf, ' '); + } + rspamd_cl_elt_write_rcl (cur, buf, is_top ? tabs : tabs + 1, FALSE, FALSE); + if (cur->type != RSPAMD_CL_OBJECT && cur->type != RSPAMD_CL_ARRAY) { + g_string_append_len (buf, ";\n", 2); + } + else { + g_string_append_c (buf, '\n'); + } + } + obj = obj->next; + } + rspamd_cl_add_tabs (buf, tabs, is_top); + if (!is_top) { + g_string_append_c (buf, '}'); + } +} + +/** + * Write a single array to the buffer + * @param obj array to write + * @param buf target buffer + */ +static void +rspamd_cl_elt_array_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean is_top) +{ + rspamd_cl_object_t *cur = obj; + + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + + g_string_append_len (buf, "[\n", 2); + while (cur) { + rspamd_cl_elt_write_rcl (cur, buf, tabs + 1, TRUE, FALSE); + g_string_append_len (buf, ",\n", 2); + cur = cur->next; + } + rspamd_cl_add_tabs (buf, tabs, FALSE); + g_string_append_c (buf, ']'); +} + +/** + * Emit a single element + * @param obj object + * @param buf buffer + */ +static void +rspamd_cl_elt_write_rcl (rspamd_cl_object_t *obj, GString *buf, guint tabs, gboolean start_tabs, gboolean is_top) +{ + switch (obj->type) { + case RSPAMD_CL_INT: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%ld", (long int)rspamd_cl_obj_toint (obj)); + break; + case RSPAMD_CL_FLOAT: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%.4lf", rspamd_cl_obj_todouble (obj)); + break; + case RSPAMD_CL_TIME: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%.4lf", rspamd_cl_obj_todouble (obj)); + break; + case RSPAMD_CL_BOOLEAN: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + g_string_append_printf (buf, "%s", rspamd_cl_obj_toboolean (obj) ? "true" : "false"); + break; + case RSPAMD_CL_STRING: + if (start_tabs) { + rspamd_cl_add_tabs (buf, tabs, FALSE); + } + rspamd_cl_elt_string_write_json (rspamd_cl_obj_tostring (obj), buf); + break; + case RSPAMD_CL_OBJECT: + rspamd_cl_elt_obj_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top); + break; + case RSPAMD_CL_ARRAY: + rspamd_cl_elt_array_write_rcl (obj->value.ov, buf, tabs, start_tabs, is_top); + break; + } +} + +/** + * Emit an object to rcl + * @param obj object + * @return rcl output (should be freed after using) + */ +static guchar * +rspamd_cl_object_emit_rcl (rspamd_cl_object_t *obj) { GString *buf; guchar *res; @@ -245,7 +416,7 @@ rspamd_cl_object_emit_json (rspamd_cl_object_t *obj) /* Allocate large enough buffer */ buf = g_string_sized_new (BUFSIZ); - rspamd_cl_obj_write_json (obj, buf, 0, FALSE); + rspamd_cl_elt_write_rcl (obj, buf, 0, FALSE, TRUE); res = buf->str; g_string_free (buf, FALSE); @@ -257,7 +428,13 @@ guchar * rspamd_cl_object_emit (rspamd_cl_object_t *obj, enum rspamd_cl_emitter emit_type) { if (emit_type == RSPAMD_CL_EMIT_JSON) { - return rspamd_cl_object_emit_json (obj); + return rspamd_cl_object_emit_json (obj, FALSE); + } + else if (emit_type == RSPAMD_CL_EMIT_JSON_COMPACT) { + return rspamd_cl_object_emit_json (obj, TRUE); + } + else { + return rspamd_cl_object_emit_rcl (obj); } return NULL; -- 2.39.5