From 0a5308e71e7f65a9921d74e8d55b389654defca6 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 20 Aug 2020 23:08:13 +0530 Subject: jansson adapter for mustache templates --- src/mustach/.gitignore | 1 + src/mustach/Makefile.am | 12 +- src/mustach/mustach-jansson.c | 308 ++++++++++++++++++++++ src/mustach/mustach-jansson.h | 82 ++++++ src/mustach/mustach-json-c.c | 526 ------------------------------------- src/mustach/mustach-json-c.h | 78 ------ src/mustach/test_mustach_jansson.c | 80 ++++++ 7 files changed, 482 insertions(+), 605 deletions(-) create mode 100644 src/mustach/.gitignore create mode 100644 src/mustach/mustach-jansson.c create mode 100644 src/mustach/mustach-jansson.h delete mode 100644 src/mustach/mustach-json-c.c delete mode 100644 src/mustach/mustach-json-c.h create mode 100644 src/mustach/test_mustach_jansson.c diff --git a/src/mustach/.gitignore b/src/mustach/.gitignore new file mode 100644 index 00000000..b2bf6ef9 --- /dev/null +++ b/src/mustach/.gitignore @@ -0,0 +1 @@ +test_mustach_jansson diff --git a/src/mustach/Makefile.am b/src/mustach/Makefile.am index a39a28d0..ac9f2842 100644 --- a/src/mustach/Makefile.am +++ b/src/mustach/Makefile.am @@ -11,7 +11,17 @@ lib_LIBRARIES = \ libmustach.a libmustach_a_SOURCES = \ - mustach.c mustach.h + mustach.c mustach.h \ + mustach-jansson.c mustach-jansson.h + +test_mustach_jansson_SOURCES = \ + test_mustach_jansson.c +test_mustach_jansson_LDADD = \ + -lgnunetutil \ + libmustach.a + +check_PROGRAMS = \ + test_mustach_jansson check_SCRIPTS = \ run-original-tests.sh diff --git a/src/mustach/mustach-jansson.c b/src/mustach/mustach-jansson.c new file mode 100644 index 00000000..afb8f823 --- /dev/null +++ b/src/mustach/mustach-jansson.c @@ -0,0 +1,308 @@ +/* + Copyright (C) 2020 Taler Systems SA + + Original license: + Author: José Bollo + Author: José Bollo + + https://gitlab.com/jobol/mustach + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "platform.h" +#include "mustach-jansson.h" + +struct Context +{ + /** + * Context object. + */ + json_t *cont; + + /** + * Current object. + */ + json_t *obj; + + /** + * Opaque object iterator. + */ + void *iter; + + /** + * Current index when iterating over an array. + */ + unsigned int index; + + /** + * Count when iterating over an array. + */ + unsigned int count; + + bool is_objiter; +}; + +struct JanssonClosure +{ + json_t *root; + mustach_jansson_write_cb writecb; + int depth; + + /** + * Did the last find(..) call result in an iterable? + */ + struct Context stack[MUSTACH_MAX_DEPTH]; + + /** + * The last object we found should be iterated over. + */ + bool found_iter; +}; + +static json_t * +find (struct JanssonClosure *e, const char *name) +{ + json_t *obj = e->stack[e->depth].obj; + char *nd = GNUNET_strdup (name); + char *p = nd; + char *saveptr = NULL; + + while (true) + { + char *tok = strtok_r (p, ".", &saveptr); + if (tok == NULL) + break; + obj = json_object_get (obj, tok); + if (obj == NULL) + break; + p = NULL; + } + + GNUNET_free (nd); + + return obj; +} + + +static int +start(void *closure) +{ + struct JanssonClosure *e = closure; + e->depth = 0; + e->stack[0].cont = NULL; + e->stack[0].obj = e->root; + e->stack[0].index = 0; + e->stack[0].count = 1; + return MUSTACH_OK; +} + + +static int +emituw (void *closure, const char *buffer, size_t size, int escape, FILE *file) +{ + struct JanssonClosure *e = closure; + if (!escape) + e->writecb (file, buffer, size); + else + do + { + switch (*buffer) + { + case '<': + e->writecb (file, "<", 4); + break; + case '>': + e->writecb (file, ">", 4); + break; + case '&': + e->writecb (file, "&", 5); + break; + default: + e->writecb (file, buffer, 1); + break; + } + buffer++; + } + while(--size); + return MUSTACH_OK; +} + + +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) +{ + struct JanssonClosure *e = closure; + json_t *o = find(e, name); + if (++e->depth >= MUSTACH_MAX_DEPTH) + return MUSTACH_ERROR_TOO_DEEP; + + if (json_is_object (o)) + { + if (e->found_iter) + { + void *iter = json_object_iter (o); + if (NULL == iter) + { + e->depth--; + return 0; + } + e->stack[e->depth].is_objiter = 1; + e->stack[e->depth].iter = iter; + e->stack[e->depth].obj = json_object_iter_value (iter); + e->stack[e->depth].cont = o; + } + else + { + e->stack[e->depth].is_objiter = 0; + e->stack[e->depth].obj = o; + e->stack[e->depth].cont = o; + } + return 1; + } + + if (json_is_array (o)) + { + unsigned int size = json_array_size (o); + if (size == 0) + { + e->depth--; + return 0; + } + e->stack[e->depth].count = size; + e->stack[e->depth].cont = o; + e->stack[e->depth].obj = json_array_get (o, 0); + e->stack[e->depth].index = 0; + e->stack[e->depth].is_objiter = 0; + return 1; + } + + e->depth--; + return 0; +} + + +static int +next (void *closure) +{ + struct JanssonClosure *e = closure; + struct Context *ctx; + if (e->depth <= 0) + return MUSTACH_ERROR_CLOSING; + ctx = &e->stack[e->depth]; + if (ctx->is_objiter) + { + ctx->iter = json_object_iter_next (ctx->obj, ctx->iter); + if (NULL == ctx->iter) + return 0; + ctx->obj = json_object_iter_value (ctx->iter); + return 1; + } + ctx->index++; + if (ctx->index >= ctx->count) + return 0; + ctx->obj = json_array_get (ctx->cont, ctx->index); + return 1; +} + +static int leave (void *closure) +{ + struct JanssonClosure *e = closure; + if (e->depth <= 0) + return MUSTACH_ERROR_CLOSING; + e->depth--; + return 0; +} + +static int get (void *closure, const char *name, struct mustach_sbuf *sbuf) +{ + struct JanssonClosure *e = closure; + const char *s; + + s = item (e, name); + if (s) + sbuf->value = s; + else + sbuf->value = ""; + return MUSTACH_OK; +} + +static struct mustach_itf itf = { + .start = start, + .put = NULL, + .enter = enter, + .next = next, + .leave = leave, + .partial =NULL, + .get = get, + .emit = NULL, + .stop = NULL +}; + +static struct mustach_itf itfuw = { + .start = start, + .put = NULL, + .enter = enter, + .next = next, + .leave = leave, + .partial = NULL, + .get = get, + .emit = emituw, + .stop = NULL +}; + +int fmustach_jansson (const char *template, json_t *root, FILE *file) +{ + struct JanssonClosure e = { 0 }; + e.root = root; + return fmustach(template, &itf, &e, file); +} + +int fdmustach_jansson (const char *template, json_t *root, int fd) +{ + struct JanssonClosure e = { 0 }; + e.root = root; + return fdmustach(template, &itf, &e, fd); +} + +int mustach_jansson (const char *template, json_t *root, char **result, size_t *size) +{ + struct JanssonClosure e = { 0 }; + e.root = root; + e.writecb = NULL; + return mustach(template, &itf, &e, result, size); +} + +int umustach_jansson (const char *template, json_t *root, mustach_jansson_write_cb writecb, void *closure) +{ + struct JanssonClosure e = { 0 }; + e.root = root; + e.writecb = writecb; + return fmustach(template, &itfuw, &e, closure); +} + diff --git a/src/mustach/mustach-jansson.h b/src/mustach/mustach-jansson.h new file mode 100644 index 00000000..f1a1b761 --- /dev/null +++ b/src/mustach/mustach-jansson.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2020 Taler Systems SA + + Original license: + Author: José Bollo + Author: José Bollo + + https://gitlab.com/jobol/mustach + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _mustach_jansson_h_included_ +#define _mustach_jansson_h_included_ + +#include +#include "mustach.h" + +/** + * fmustach_jansson - Renders the mustache 'template' in 'file' for 'root'. + * + * @template: the template string to instanciate + * @root: the root json object to render + * @file: the file where to write the result + * + * Returns 0 in case of success, -1 with errno set in case of system error + * a other negative value in case of error. + */ +extern int fmustach_jansson(const char *template, json_t *root, FILE *file); + +/** + * fmustach_jansson - Renders the mustache 'template' in 'fd' for 'root'. + * + * @template: the template string to instanciate + * @root: the root json object to render + * @fd: the file descriptor number where to write the result + * + * Returns 0 in case of success, -1 with errno set in case of system error + * a other negative value in case of error. + */ +extern int fdmustach_jansson(const char *template, json_t *root, int fd); + + +/** + * fmustach_jansson - Renders the mustache 'template' in 'result' for 'root'. + * + * @template: the template string to instanciate + * @root: the root json object to render + * @result: the pointer receiving the result when 0 is returned + * @size: the size of the returned result + * + * Returns 0 in case of success, -1 with errno set in case of system error + * a other negative value in case of error. + */ +extern int mustach_jansson(const char *template, json_t *root, char **result, size_t *size); + +/** + * umustach_jansson - Renders the mustache 'template' for 'root' to custom writer 'writecb' with 'closure'. + * + * @template: the template string to instanciate + * @root: the root json object to render + * @writecb: the function that write values + * @closure: the closure for the write function + * + * Returns 0 in case of success, -1 with errno set in case of system error + * a other negative value in case of error. + */ +typedef int (*mustach_jansson_write_cb)(void *closure, const char *buffer, size_t size); +extern int umustach_jansson(const char *template, json_t *root, mustach_jansson_write_cb writecb, void *closure); + +#endif + diff --git a/src/mustach/mustach-json-c.c b/src/mustach/mustach-json-c.c deleted file mode 100644 index df901dcd..00000000 --- a/src/mustach/mustach-json-c.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - Author: José Bollo - Author: José Bollo - - https://gitlab.com/jobol/mustach - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#define _GNU_SOURCE - -#include -#include -#ifdef _WIN32 -#include -#endif -#ifdef __sun -# include -#endif - -#include "mustach.h" -#include "mustach-json-c.h" - -#if defined(NO_EXTENSION_FOR_MUSTACH) -# undef NO_SINGLE_DOT_EXTENSION_FOR_MUSTACH -# define NO_SINGLE_DOT_EXTENSION_FOR_MUSTACH -# undef NO_EQUAL_VALUE_EXTENSION_FOR_MUSTACH -# define NO_EQUAL_VALUE_EXTENSION_FOR_MUSTACH -# undef NO_COMPARE_VALUE_EXTENSION_FOR_MUSTACH -# define NO_COMPARE_VALUE_EXTENSION_FOR_MUSTACH -# undef NO_JSON_POINTER_EXTENSION_FOR_MUSTACH -# define NO_JSON_POINTER_EXTENSION_FOR_MUSTACH -# undef NO_OBJECT_ITERATION_FOR_MUSTACH -# define NO_OBJECT_ITERATION_FOR_MUSTACH -# undef NO_INCLUDE_PARTIAL_FALLBACK -# define NO_INCLUDE_PARTIAL_FALLBACK -#endif - -#if !defined(NO_INCLUDE_PARTIAL_FALLBACK) \ - && !defined(INCLUDE_PARTIAL_EXTENSION) -# define INCLUDE_PARTIAL_EXTENSION ".mustache" -#endif - -#if !defined(NO_COMPARE_VALUE_EXTENSION_FOR_MUSTACH) -# undef NO_EQUAL_VALUE_EXTENSION_FOR_MUSTACH -#endif - -struct expl { - struct json_object *root; - mustach_json_c_write_cb writecb; - int depth; -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - int found_objiter; -#endif - struct { - struct json_object *cont; - struct json_object *obj; -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - struct json_object_iterator biter, eiter; - int is_objiter; -#endif - int index, count; - } stack[MUSTACH_MAX_DEPTH]; -}; - -enum comp { - C_no = 0, - C_eq = 1, - C_lt = 5, - C_le = 6, - C_gt = 9, - C_ge = 10 -}; - -#if !defined(NO_EQUAL_VALUE_EXTENSION_FOR_MUSTACH) -static enum comp getcomp(char *head) -{ - return head[0] == '=' ? C_eq -#if !defined(NO_COMPARE_VALUE_EXTENSION_FOR_MUSTACH) - : head[0] == '<' ? (head[1] == '=' ? C_le : C_lt) - : head[0] == '>' ? (head[1] == '=' ? C_ge : C_gt) -#endif - : C_no; -} - -static char *keyval(char *head, int isptr, enum comp *comp) -{ - char *w, c, s; - enum comp k; - - k = C_no; -#if !defined(NO_USE_VALUE_ESCAPE_FIRST_EXTENSION_FOR_MUSTACH) - s = getcomp(head) != C_no; -#else - s = 0; -#endif - c = *(w = head); - while (c && (s || (k = getcomp(head)) == C_no)) { - if (s) - s = 0; - else - s = (isptr ? c == '~' : c == '\\') - && (getcomp(head + 1) != C_no); - if (!s) - *w++ = c; - c = *++head; - } - *w = 0; - *comp = k; - return k == C_no ? NULL : &head[k & 3]; -} - -static int compare(struct json_object *o, const char *value) -{ - switch (json_object_get_type(o)) { - case json_type_double: - return json_object_get_double(o) - atof(value); - case json_type_int: - return json_object_get_int64(o) - (int64_t)atoll(value); - default: - return strcmp(json_object_get_string(o), value); - } -} - -static int evalcomp(struct json_object *o, char *value, enum comp k) -{ - int r, c; - - c = compare(o, value); - switch (k) { - case C_eq: r = c == 0; break; -#if !defined(NO_COMPARE_VALUE_EXTENSION_FOR_MUSTACH) - case C_lt: r = c < 0; break; - case C_le: r = c <= 0; break; - case C_gt: r = c > 0; break; - case C_ge: r = c >= 0; break; -#endif - default: r = 0; break; - } - return r; -} -#else -static inline char *keyval(char *head, int isptr, enum comp *comp) -{ - *comp = C_no; - return NULL; -} -static inline int compare(struct json_object *o, char *value, enum comp k) -{ - return 0; -} -#endif - -static char *key(char **head, int isptr) -{ - char *r, *i, *w, c; - - c = *(i = *head); - if (!c) - r = NULL; - else { - r = w = i; -#if !defined(NO_JSON_POINTER_EXTENSION_FOR_MUSTACH) - if (isptr) - while (c && c != '/') { - if (c == '~') - switch (i[1]) { - case '1': c = '/'; /*@fallthrough@*/ - case '0': i++; - } - *w++ = c; - c = *++i; - } - else -#endif - while (c && c != '.') { - if (c == '\\' && (i[1] == '.' || i[1] == '\\')) - c = *++i; - *w++ = c; - c = *++i; - } - *w = 0; - *head = i + !!c; - } - return r; -} - -static struct json_object *find(struct expl *e, const char *name) -{ - int i, isptr; - struct json_object *o, *no; - char *n, *c, *v; - enum comp k; - - n = alloca(1 + strlen(name)); - strcpy(n, name); - isptr = 0; -#if !defined(NO_JSON_POINTER_EXTENSION_FOR_MUSTACH) - isptr = n[0] == '/'; - n += isptr; -#endif - - v = keyval(n, isptr, &k); -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - e->found_objiter = 0; -#endif -#if !defined(NO_SINGLE_DOT_EXTENSION_FOR_MUSTACH) - if (n[0] == '.' && !n[1]) { - /* case of . alone */ - o = e->stack[e->depth].obj; - } else -#endif - { - c = key(&n, isptr); - if (c == NULL) - return NULL; - o = NULL; - i = e->depth; - while (i >= 0 && !json_object_object_get_ex(e->stack[i].obj, c, &o)) - i--; - if (i < 0) { -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - o = e->stack[e->depth].obj; - if (c[0] == '*' && !c[1] && !v && !key(&n, isptr) && json_object_is_type(o, json_type_object)) { - e->found_objiter = 1; - return o; - } -#endif - return NULL; - } - c = key(&n, isptr); - while(c) { - if (!json_object_object_get_ex(o, c, &no)) { -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - if (c[0] == '*' && !c[1] && !v && !key(&n, isptr) && json_object_is_type(o, json_type_object)) { - e->found_objiter = 1; - return o; - } -#endif - return NULL; - } - o = no; - c = key(&n, isptr); - } - } - if (v) { - i = v[0] == '!'; - if (i == evalcomp(o, &v[i], k)) - o = NULL; - } - return o; -} - -static int start(void *closure) -{ - struct expl *e = closure; - e->depth = 0; - e->stack[0].cont = NULL; - e->stack[0].obj = e->root; - e->stack[0].index = 0; - e->stack[0].count = 1; - return MUSTACH_OK; -} - -static int write(struct expl *e, const char *buffer, size_t size, FILE *file) -{ - return e->writecb(file, buffer, size); -} - -static int emituw(void *closure, const char *buffer, size_t size, int escape, FILE *file) -{ - struct expl *e = closure; - if (!escape) - write(e, buffer, size, file); - else - do { - switch(*buffer) { - case '<': write(e, "<", 4, file); break; - case '>': write(e, ">", 4, file); break; - case '&': write(e, "&", 5, file); break; - default: write(e, buffer, 1, file); break; - } - buffer++; - } while(--size); - return MUSTACH_OK; -} - -static const char *item(struct expl *e, const char *name) -{ - struct json_object *o; - const char *s; - -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - if (name[0] == '*' && !name[1] && e->stack[e->depth].is_objiter) - s = json_object_iter_peek_name(&e->stack[e->depth].biter); - else - s = (o = find(e, name)) && !e->found_objiter ? json_object_get_string(o) : NULL; -#else - s = (o = find(e, name)) ? json_object_get_string(o) : NULL; -#endif - return s; -} - -static int enter(void *closure, const char *name) -{ - struct expl *e = closure; - struct json_object *o = find(e, name); - if (++e->depth >= MUSTACH_MAX_DEPTH) - return MUSTACH_ERROR_TOO_DEEP; - if (json_object_is_type(o, json_type_array)) { - e->stack[e->depth].count = json_object_array_length(o); - if (e->stack[e->depth].count == 0) { - e->depth--; - return 0; - } - e->stack[e->depth].cont = o; - e->stack[e->depth].obj = json_object_array_get_idx(o, 0); - e->stack[e->depth].index = 0; -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - e->stack[e->depth].is_objiter = 0; - } else if (json_object_is_type(o, json_type_object) && e->found_objiter) { - e->stack[e->depth].biter = json_object_iter_begin(o); - e->stack[e->depth].eiter = json_object_iter_end(o); - if (json_object_iter_equal(&e->stack[e->depth].biter, &e->stack[e->depth].eiter)) { - e->depth--; - return 0; - } - e->stack[e->depth].obj = json_object_iter_peek_value(&e->stack[e->depth].biter); - e->stack[e->depth].cont = o; - e->stack[e->depth].is_objiter = 1; -#endif - } else if (json_object_is_type(o, json_type_object) || json_object_get_boolean(o)) { - e->stack[e->depth].count = 1; - e->stack[e->depth].cont = NULL; - e->stack[e->depth].obj = o; - e->stack[e->depth].index = 0; -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - e->stack[e->depth].is_objiter = 0; -#endif - } else { - e->depth--; - return 0; - } - return 1; -} - -static int next(void *closure) -{ - struct expl *e = closure; - if (e->depth <= 0) - return MUSTACH_ERROR_CLOSING; -#if !defined(NO_OBJECT_ITERATION_FOR_MUSTACH) - if (e->stack[e->depth].is_objiter) { - json_object_iter_next(&e->stack[e->depth].biter); - if (json_object_iter_equal(&e->stack[e->depth].biter, &e->stack[e->depth].eiter)) - return 0; - e->stack[e->depth].obj = json_object_iter_peek_value(&e->stack[e->depth].biter); - return 1; - } -#endif - e->stack[e->depth].index++; - if (e->stack[e->depth].index >= e->stack[e->depth].count) - return 0; - e->stack[e->depth].obj = json_object_array_get_idx(e->stack[e->depth].cont, e->stack[e->depth].index); - return 1; -} - -static int leave(void *closure) -{ - struct expl *e = closure; - if (e->depth <= 0) - return MUSTACH_ERROR_CLOSING; - e->depth--; - return 0; -} - -#if !defined(NO_INCLUDE_PARTIAL_FALLBACK) -static int get_partial_from_file(const char *name, struct mustach_sbuf *sbuf) -{ - static char extension[] = INCLUDE_PARTIAL_EXTENSION; - size_t s; - long pos; - FILE *file; - char *path, *buffer; - - /* allocate path */ - s = strlen(name); - path = malloc(s + sizeof extension); - if (path == NULL) - return MUSTACH_ERROR_SYSTEM; - - /* try without extension first */ - memcpy(path, name, s + 1); - file = fopen(path, "r"); - if (file == NULL) { - memcpy(&path[s], extension, sizeof extension); - file = fopen(path, "r"); - } - free(path); - - /* if file opened */ - if (file != NULL) { - /* compute file size */ - if (fseek(file, 0, SEEK_END) >= 0 - && (pos = ftell(file)) >= 0 - && fseek(file, 0, SEEK_SET) >= 0) { - /* allocate value */ - s = (size_t)pos; - buffer = malloc(s + 1); - if (buffer != NULL) { - /* read value */ - if (1 == fread(buffer, s, 1, file)) { - /* force zero at end */ - sbuf->value = buffer; - buffer[s] = 0; - sbuf->freecb = free; - fclose(file); - return MUSTACH_OK; - } - free(buffer); - } - } - fclose(file); - } - return MUSTACH_ERROR_SYSTEM; -} - -static int partial(void *closure, const char *name, struct mustach_sbuf *sbuf) -{ - struct expl *e = closure; - const char *s; - - s = item(e, name); - if (s) - sbuf->value = s; - else if (get_partial_from_file(name, sbuf) < 0) - sbuf->value = ""; - return MUSTACH_OK; -} -#endif - -static int get(void *closure, const char *name, struct mustach_sbuf *sbuf) -{ - struct expl *e = closure; - const char *s; - - s = item(e, name); - if (s) - sbuf->value = s; - else - sbuf->value = ""; - return MUSTACH_OK; -} - -static struct mustach_itf itf = { - .start = start, - .put = NULL, - .enter = enter, - .next = next, - .leave = leave, -#if !defined(NO_INCLUDE_PARTIAL_FALLBACK) - .partial = partial, -#else - .partial =NULL, -#endif - .get = get, - .emit = NULL, - .stop = NULL -}; - -static struct mustach_itf itfuw = { - .start = start, - .put = NULL, - .enter = enter, - .next = next, - .leave = leave, -#if !defined(NO_INCLUDE_PARTIAL_FALLBACK) - .partial = partial, -#else - .partial =NULL, -#endif - .get = get, - .emit = emituw, - .stop = NULL -}; - -int fmustach_json_c(const char *template, struct json_object *root, FILE *file) -{ - struct expl e; - e.root = root; - return fmustach(template, &itf, &e, file); -} - -int fdmustach_json_c(const char *template, struct json_object *root, int fd) -{ - struct expl e; - e.root = root; - return fdmustach(template, &itf, &e, fd); -} - -int mustach_json_c(const char *template, struct json_object *root, char **result, size_t *size) -{ - struct expl e; - e.root = root; - e.writecb = NULL; - return mustach(template, &itf, &e, result, size); -} - -int umustach_json_c(const char *template, struct json_object *root, mustach_json_c_write_cb writecb, void *closure) -{ - struct expl e; - e.root = root; - e.writecb = writecb; - return fmustach(template, &itfuw, &e, closure); -} - diff --git a/src/mustach/mustach-json-c.h b/src/mustach/mustach-json-c.h deleted file mode 100644 index 3dfa228b..00000000 --- a/src/mustach/mustach-json-c.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - Author: José Bollo - Author: José Bollo - - https://gitlab.com/jobol/mustach - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef _mustach_json_c_h_included_ -#define _mustach_json_c_h_included_ - -#include - -/** - * fmustach_json_c - Renders the mustache 'template' in 'file' for 'root'. - * - * @template: the template string to instanciate - * @root: the root json object to render - * @file: the file where to write the result - * - * Returns 0 in case of success, -1 with errno set in case of system error - * a other negative value in case of error. - */ -extern int fmustach_json_c(const char *template, struct json_object *root, FILE *file); - -/** - * fmustach_json_c - Renders the mustache 'template' in 'fd' for 'root'. - * - * @template: the template string to instanciate - * @root: the root json object to render - * @fd: the file descriptor number where to write the result - * - * Returns 0 in case of success, -1 with errno set in case of system error - * a other negative value in case of error. - */ -extern int fdmustach_json_c(const char *template, struct json_object *root, int fd); - - -/** - * fmustach_json_c - Renders the mustache 'template' in 'result' for 'root'. - * - * @template: the template string to instanciate - * @root: the root json object to render - * @result: the pointer receiving the result when 0 is returned - * @size: the size of the returned result - * - * Returns 0 in case of success, -1 with errno set in case of system error - * a other negative value in case of error. - */ -extern int mustach_json_c(const char *template, struct json_object *root, char **result, size_t *size); - -/** - * umustach_json_c - Renders the mustache 'template' for 'root' to custom writer 'writecb' with 'closure'. - * - * @template: the template string to instanciate - * @root: the root json object to render - * @writecb: the function that write values - * @closure: the closure for the write function - * - * Returns 0 in case of success, -1 with errno set in case of system error - * a other negative value in case of error. - */ -typedef int (*mustach_json_c_write_cb)(void*closure, const char*buffer, size_t size); -extern int umustach_json_c(const char *template, struct json_object *root, mustach_json_c_write_cb writecb, void *closure); - -#endif - diff --git a/src/mustach/test_mustach_jansson.c b/src/mustach/test_mustach_jansson.c new file mode 100644 index 00000000..8f1e37b6 --- /dev/null +++ b/src/mustach/test_mustach_jansson.c @@ -0,0 +1,80 @@ +/* + This file is part of TALER + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file mustac/test_mustach_jansson.c + * @brief testcase to test the mustach/jansson integration + * @author Florian Dold + */ +#include "platform.h" +#include "mustach-jansson.h" + +void +assert_template (const char *template, json_t *root, const char *expected) +{ + char *r; + size_t sz; + + GNUNET_assert (0 == mustach_jansson (template, root, &r, &sz)); + GNUNET_assert (0 == strcmp (r, expected)); + GNUNET_free (r); +} + +int +main (int argc, + char *const *argv) +{ + json_t *root = json_object (); + json_t *arr = json_array (); + json_t *obj = json_object(); + /* test 1 */ + char *t1 = "hello world"; + char *x1 = "hello world"; + /* test 2 */ + char *t2 = "hello {{ v1 }}"; + char *x2 = "hello world"; + /* test 3 */ + char *t3 = "hello {{ v3.x }}"; + char *x3 = "hello baz"; + /* test 4 */ + char *t4 = "hello {{# v2 }}{{ . }}{{/ v2 }}"; + char *x4 = "hello foobar"; + /* test 5 */ + char *t5 = "hello {{# v3 }}{{ y }}/{{ x }}{{ z }}{{/ v3 }}"; + char *x5 = "hello quux/baz"; + + 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 (obj, "x", json_string ("baz")); + json_object_set_new (obj, "y", json_string ("quux")); + + 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); + + json_decref (root); + + return 0; +} + -- cgit v1.2.3