Unfortunately, format-json does not use the yacc grammar to parse its options, so we have to implement our own: this is what value_pairs_parse_type() does, conveniently hidden, so that value_pairs_new_from_cmdline() will do the right thing, and annotate the constructed templates with type hints. The assumption made here is that if a template string has '(' and a ')' after, then it is a type-hinted template. This may be refined later to be stricter (for example, to require the closing parens to be at the end). And since we can construct type-hinted templates from the command-line, we can teach $(format-json) to handle these types too! Signed-off-by: Gergely Nagy <algernon@balabit.hu> --- lib/value-pairs.c | 32 ++++++++++++++++++++++++++++++-- modules/json/format-json.c | 35 ++++++++++++++++++++++++++++++----- modules/json/tests/test_json.c | 12 ++++++++++++ 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/lib/value-pairs.c b/lib/value-pairs.c index da2e391..a8511fd 100644 --- a/lib/value-pairs.c +++ b/lib/value-pairs.c @@ -151,6 +151,32 @@ value_pairs_add_glob_pattern(ValuePairs *vp, const gchar *pattern, vp->patterns[i] = p; } +static void +value_pairs_parse_type(gchar *spec, gchar **value, gchar **type) +{ + char *sp, *ep; + + *type = NULL; + + sp = strchr(spec, '('); + if (sp == NULL) + { + *value = spec; + return; + } + ep = strchr(sp, ')'); + if (ep == NULL) + { + *value = spec; + return; + } + + *value = sp + 1; + *type = spec; + sp[0] = '\0'; + ep[0] = '\0'; +} + gboolean value_pairs_add_pair_with_type(ValuePairs *vp, GlobalConfig *cfg, const gchar *key, const gchar *type, @@ -770,7 +796,7 @@ vp_cmdline_parse_pair (const gchar *option_name, const gchar *value, gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; GlobalConfig *cfg = (GlobalConfig *) args[0]; - gchar **kv; + gchar **kv, *v, *t; vp_cmdline_parse_rekey_finish (data); if (!g_strstr_len (value, strlen (value), "=")) @@ -781,7 +807,9 @@ vp_cmdline_parse_pair (const gchar *option_name, const gchar *value, } kv = g_strsplit(value, "=", 2); - value_pairs_add_pair (vp, cfg, kv[0], kv[1]); + value_pairs_parse_type(kv[1], &v, &t); + + value_pairs_add_pair_with_type(vp, cfg, kv[0], t, v, NULL); g_free (kv[0]); g_free (kv[1]); diff --git a/modules/json/format-json.c b/modules/json/format-json.c index 4b79701..cbdb513 100644 --- a/modules/json/format-json.c +++ b/modules/json/format-json.c @@ -172,11 +172,36 @@ tf_json_value(const gchar *name, const gchar *prefix, if (state->need_comma) g_string_append_c(state->buffer, ','); - g_string_append_c(state->buffer, '"'); - g_string_append_escaped(state->buffer, name); - g_string_append(state->buffer, "\":\""); - g_string_append_escaped(state->buffer, value); - g_string_append_c(state->buffer, '"'); + switch (type) + { + case TEMPLATE_TYPE_STRING: + case TEMPLATE_TYPE_DATETIME: + default: + g_string_append_c(state->buffer, '"'); + g_string_append_escaped(state->buffer, name); + g_string_append(state->buffer, "\":\""); + g_string_append_escaped(state->buffer, value); + g_string_append_c(state->buffer, '"'); + break; + case TEMPLATE_TYPE_INT32: + case TEMPLATE_TYPE_INT64: + g_string_append_c(state->buffer, '"'); + g_string_append_escaped(state->buffer, name); + g_string_append(state->buffer, "\":"); + g_string_append(state->buffer, value); + break; + case TEMPLATE_TYPE_BOOLEAN: + { + g_string_append_c(state->buffer, '"'); + g_string_append_escaped(state->buffer, name); + g_string_append(state->buffer, "\":"); + if (value[0] == 't' || value[0] == 'T' || value[0] == '1') + g_string_append(state->buffer, "true"); + else + g_string_append(state->buffer, "false"); + break; + } + } state->need_comma = TRUE; diff --git a/modules/json/tests/test_json.c b/modules/json/tests/test_json.c index 8087c3e..ada48b6 100644 --- a/modules/json/tests/test_json.c +++ b/modules/json/tests/test_json.c @@ -23,6 +23,17 @@ test_format_json_rekey(void) "{\"_msg\":{\"text\":\"dotted\"}}"); } +void +test_format_json_with_type_hints(void) +{ + assert_template_format("$(format-json i32=int32(1234))", + "{\"i32\":1234}"); + assert_template_format("$(format-json \"i=ifoo(\")", + "{\"i\":\"ifoo(\"}"); + assert_template_format("$(format-json b=boolean(TRUE))", + "{\"b\":true}"); +} + int main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED) { @@ -34,6 +45,7 @@ main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED) test_format_json(); test_format_json_rekey(); + test_format_json_with_type_hints(); deinit_template_tests(); app_shutdown(); -- 1.7.10.4