From 87a93ed1607cdc5a5e3ec8e0e37d6c288d4cf5cc Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 21 Aug 2020 16:18:06 +0530 Subject: template bangs --- src/mustach/mustach-jansson.c | 167 ++++++++++++++++++++++++++++++------- src/mustach/test_mustach_jansson.c | 38 +++++++++ 2 files changed, 176 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/mustach/mustach-jansson.c b/src/mustach/mustach-jansson.c index afb8f823..2aed5829 100644 --- a/src/mustach/mustach-jansson.c +++ b/src/mustach/mustach-jansson.c @@ -53,6 +53,15 @@ struct Context bool is_objiter; }; +enum Bang +{ + BANG_NONE, + BANG_I18N, + BANG_STRINGIFY, + BANG_AMOUNT_CURRENCY, + BANG_AMOUNT_DECIMAL, +}; + struct JanssonClosure { json_t *root; @@ -68,16 +77,25 @@ struct JanssonClosure * The last object we found should be iterated over. */ bool found_iter; + + /** + * Last bang we found. + */ + enum Bang found_bang; + + /** + * Language for i18n lookups. + */ + const char *lang; }; + static json_t * -find (struct JanssonClosure *e, const char *name) +walk (json_t *obj, const char *path) { - json_t *obj = e->stack[e->depth].obj; - char *nd = GNUNET_strdup (name); - char *p = nd; char *saveptr = NULL; - + char *sp = GNUNET_strdup (path); + char *p = sp; while (true) { char *tok = strtok_r (p, ".", &saveptr); @@ -88,8 +106,51 @@ find (struct JanssonClosure *e, const char *name) break; p = NULL; } + GNUNET_free (sp); + return obj; +} + + +static json_t * +find (struct JanssonClosure *e, const char *name) +{ + json_t *obj = NULL; + char *path = GNUNET_strdup (name); + char *bang; + + bang = strchr (path, '!'); + + e->found_bang = BANG_NONE; + + if (NULL != bang) + { + *bang = 0; + bang++; + + if (0 == strcmp (bang, "i18n")) + e->found_bang = BANG_I18N; + else if (0 == strcmp(bang, "stringify")) + e->found_bang = BANG_STRINGIFY; + else if (0 == strcmp(bang, "amount_decimal")) + e->found_bang = BANG_AMOUNT_CURRENCY; + else if (0 == strcmp(bang, "amount_currency")) + e->found_bang = BANG_AMOUNT_DECIMAL; + } + + if (BANG_I18N == e->found_bang && NULL != e->lang) + { + char *aug_path; + GNUNET_asprintf (&aug_path, "%s_i18n.%s", path, e->lang); + obj = walk (e->stack[e->depth].obj, aug_path); + GNUNET_free (aug_path); + } + + if (NULL == obj) + { + obj = walk (e->stack[e->depth].obj, path); + } - GNUNET_free (nd); + GNUNET_free (path); return obj; } @@ -104,6 +165,7 @@ start(void *closure) e->stack[0].obj = e->root; e->stack[0].index = 0; e->stack[0].count = 1; + e->lang = json_string_value (json_object_get (e->root, "$language")); return MUSTACH_OK; } @@ -139,21 +201,6 @@ emituw (void *closure, const char *buffer, size_t size, int escape, FILE *file) } -static const char * -item (struct JanssonClosure *e, const char *name) -{ - json_t *obj; - - if ( (0 == strcmp (name, "*") ) && - (e->stack[e->depth].is_objiter ) ) - return json_object_iter_key (e->stack[e->depth].iter); - obj = find (e, name); - if (NULL != obj) - return json_string_value (obj); - return NULL; -} - - static int enter(void *closure, const char *name) { @@ -230,7 +277,8 @@ next (void *closure) return 1; } -static int leave (void *closure) +static int +leave (void *closure) { struct JanssonClosure *e = closure; if (e->depth <= 0) @@ -239,16 +287,77 @@ static int leave (void *closure) return 0; } -static int get (void *closure, const char *name, struct mustach_sbuf *sbuf) +static void +freecb (void *v) +{ + free (v); +} + +static int +get (void *closure, const char *name, struct mustach_sbuf *sbuf) { struct JanssonClosure *e = closure; - const char *s; + json_t *obj; - s = item (e, name); - if (s) - sbuf->value = s; - else - sbuf->value = ""; + if ( (0 == strcmp (name, "*") ) && + (e->stack[e->depth].is_objiter ) ) + { + sbuf->value = json_object_iter_key (e->stack[e->depth].iter); + return MUSTACH_OK; + } + obj = find (e, name); + if (NULL != obj) + { + switch (e->found_bang) + { + case BANG_I18N: + case BANG_NONE: + { + const char *s = json_string_value (obj); + if (NULL != s) + { + sbuf->value = s; + return MUSTACH_OK; + } + } + break; + case BANG_STRINGIFY: + sbuf->value = json_dumps (obj, JSON_INDENT (2)); + sbuf->freecb = freecb; + return MUSTACH_OK; + case BANG_AMOUNT_DECIMAL: + { + char *s; + char *c; + if (!json_is_string (obj)) + break; + s = strdup (json_string_value (obj)); + c = strchr (s, ':'); + if (NULL != c) + *c = 0; + sbuf->value = s; + sbuf->freecb = freecb; + return MUSTACH_OK; + } + break; + case BANG_AMOUNT_CURRENCY: + { + const char *s; + if (!json_is_string (obj)) + break; + s = json_string_value (obj); + s = strchr (s, ':'); + if (NULL == s) + break; + sbuf->value = s + 1; + return MUSTACH_OK; + } + break; + default: + break; + } + } + sbuf->value = ""; return MUSTACH_OK; } diff --git a/src/mustach/test_mustach_jansson.c b/src/mustach/test_mustach_jansson.c index 8f1e37b6..a211d87c 100644 --- a/src/mustach/test_mustach_jansson.c +++ b/src/mustach/test_mustach_jansson.c @@ -43,6 +43,7 @@ main (int argc, json_t *root = json_object (); json_t *arr = json_array (); json_t *obj = json_object(); + json_t *contract; /* test 1 */ char *t1 = "hello world"; char *x1 = "hello world"; @@ -58,22 +59,59 @@ main (int argc, /* test 5 */ char *t5 = "hello {{# v3 }}{{ y }}/{{ x }}{{ z }}{{/ v3 }}"; char *x5 = "hello quux/baz"; + /* test 6 */ + char *t6 = "hello {{ v2!stringify }}"; + char *x6 = "hello [\n \"foo\",\n \"bar\"\n]"; + /* test 7 */ + char *t7 = "amount: {{ amt!amount_decimal }} {{ amt!amount_currency }}"; + char *x7 = "amount: 123.00 EUR"; + + /* contract test 8 (contract) */ + char *tc = "summary: {{ summary!i18n }}"; + char *xc_en = "summary: ENGLISH"; + char *xc_de = "summary: DEUTSCH"; + char *xc_fr = "summary: FRANCAISE"; json_object_set_new (root, "v1", json_string ("world")); json_array_append_new (arr, json_string ("foo")); json_array_append_new (arr, json_string ("bar")); json_object_set_new (root, "v2", arr); json_object_set_new (root, "v3", obj); + json_object_set_new (root, "amt", json_string("EUR:123.00")); json_object_set_new (obj, "x", json_string ("baz")); json_object_set_new (obj, "y", json_string ("quux")); + contract = json_pack("{ s:s, s:{s:s, s:s}}", + "summary", + "ENGLISH", + "summary_i18n", + "de", + "DEUTSCH", + "fr", + "FRANCAISE"); + GNUNET_assert (NULL != contract); + assert_template (t1, root, x1); assert_template (t2, root, x2); assert_template (t3, root, x3); assert_template (t4, root, x4); assert_template (t5, root, x5); + assert_template (t6, root, x6); + assert_template (t7, root, x7); + + assert_template (tc, contract, xc_en); + + json_object_set_new (contract, "$language", json_string ("de")); + assert_template (tc, contract, xc_de); + + json_object_set_new (contract, "$language", json_string ("fr")); + assert_template (tc, contract, xc_fr); + + json_object_set_new (contract, "$language", json_string ("it")); + assert_template (tc, contract, xc_en); json_decref (root); + json_decref (contract); return 0; } -- cgit v1.2.3