summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-03-18 13:14:51 +0100
committerChristian Grothoff <christian@grothoff.org>2024-03-18 13:30:24 +0100
commit9468d2a769c726c9612f383f785501933f330232 (patch)
tree7a4f0bedd2ed9ee18d56d2391991cf84f52bcbb7
parent8a6d67a3178bad3ae0c0d01bed8c36b3a1e9b7b8 (diff)
downloadexchange-9468d2a769c726c9612f383f785501933f330232.tar.gz
exchange-9468d2a769c726c9612f383f785501933f330232.tar.bz2
exchange-9468d2a769c726c9612f383f785501933f330232.zip
-update mustach
m---------contrib/gana0
-rwxr-xr-xcontrib/uncrustify_precommit2
m---------contrib/wallet-core0
-rw-r--r--src/templating/AUTHORS4
-rw-r--r--src/templating/CHANGELOG.md150
-rw-r--r--src/templating/README.md16
-rwxr-xr-xsrc/templating/dotest.sh20
-rw-r--r--src/templating/mustach-cjson.c35
-rw-r--r--src/templating/mustach-cjson.h2
-rw-r--r--src/templating/mustach-jansson.c36
-rw-r--r--src/templating/mustach-json-c.c37
-rw-r--r--src/templating/mustach-original-Makefile20
-rw-r--r--src/templating/mustach-tool.c2
-rw-r--r--src/templating/mustach-wrap.c48
-rw-r--r--src/templating/mustach.1.gzbin0 -> 742 bytes
-rw-r--r--src/templating/mustach.1.scd60
-rw-r--r--src/templating/mustach.c7
-rw-r--r--src/templating/pkgcfgs35
-rw-r--r--src/templating/test-specs/test-specs-cjson.ref425
-rw-r--r--src/templating/test-specs/test-specs-jansson.ref429
-rw-r--r--src/templating/test-specs/test-specs-json-c.ref425
-rw-r--r--src/templating/test-specs/test-specs.c520
-rw-r--r--src/templating/test1/Makefile7
-rw-r--r--src/templating/test1/must6
-rw-r--r--src/templating/test1/resu.ref41
-rw-r--r--src/templating/test1/vg.ref14
-rw-r--r--src/templating/test2/Makefile7
-rw-r--r--src/templating/test2/resu.ref7
-rw-r--r--src/templating/test2/vg.ref14
-rw-r--r--src/templating/test3/Makefile7
-rw-r--r--src/templating/test3/resu.ref13
-rw-r--r--src/templating/test3/vg.ref14
-rw-r--r--src/templating/test4/Makefile7
-rw-r--r--src/templating/test4/resu.ref50
-rw-r--r--src/templating/test4/vg.ref14
-rw-r--r--src/templating/test5/Makefile7
-rw-r--r--src/templating/test5/resu.ref38
-rw-r--r--src/templating/test5/vg.ref14
-rw-r--r--src/templating/test6/Makefile7
-rw-r--r--src/templating/test6/resu.ref93
-rw-r--r--src/templating/test6/test-custom-write.c2
-rw-r--r--src/templating/test6/vg.ref14
-rw-r--r--src/templating/test7/base.mustache2
-rw-r--r--src/templating/test7/json8
-rw-r--r--src/templating/test7/node.mustache4
-rw-r--r--src/templating/test7/resu.ref7
-rw-r--r--src/templating/test7/vg.ref14
-rw-r--r--src/templating/test8/.gitignore2
-rw-r--r--src/templating/test8/json8
-rw-r--r--src/templating/test8/must6
-rw-r--r--src/templating/test8/resu.ref6
-rw-r--r--src/templating/test8/vg.ref14
52 files changed, 2625 insertions, 95 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject 2b581279ae67a1068b07a8c010ac1ab7b85e18d
+Subproject 53d0992890e1ebb8f8c6bd747533abe157baec6
diff --git a/contrib/uncrustify_precommit b/contrib/uncrustify_precommit
index faffcec9c..d0a64ef72 100755
--- a/contrib/uncrustify_precommit
+++ b/contrib/uncrustify_precommit
@@ -4,7 +4,7 @@
exec 1>&2
RET=0
-changed=$(git diff --cached --name-only | grep -v mustach | grep -v templating/test./ | grep -v valgrind.h)
+changed=$(git diff --cached --name-only | grep -v mustach | grep -v templating/test | grep -v valgrind.h)
crustified=""
for f in $changed;
diff --git a/contrib/wallet-core b/contrib/wallet-core
-Subproject c0f3069970e24d1fa9e308347350d6e5221aed8
+Subproject 35212ac57bfe5625fcf574b0fd2d9baf395dc4c
diff --git a/src/templating/AUTHORS b/src/templating/AUTHORS
index b440c24ed..b2042848e 100644
--- a/src/templating/AUTHORS
+++ b/src/templating/AUTHORS
@@ -5,6 +5,7 @@ Contributors:
Abhishek Mishra
Atlas
Ben Beasley
+ Dominik Kummer
Gabriel Zachmann
Harold L Marzan
Kurt Jung
@@ -15,6 +16,7 @@ Contributors:
Ryan Fox
Sami Kerola
Sijmen J. Mulder
+ Steve-Chavez
Tomasz Sieprawski
Packagers:
@@ -27,6 +29,8 @@ Thanks to issue submitters:
@fabbe
Johann Oskarsson
Mark Bucciarelli
+ Nigel Hathaway
Paul Wisehart
+ Tarik @tr001
Thierry Fournier
SASU OKFT
diff --git a/src/templating/CHANGELOG.md b/src/templating/CHANGELOG.md
new file mode 100644
index 000000000..6024189ef
--- /dev/null
+++ b/src/templating/CHANGELOG.md
@@ -0,0 +1,150 @@
+next
+----
+
+Fix:
+ - selection of subitem by index (#47)
+ - get latest iterated key when getting key name (#52)
+ - allow tests without valgrind
+
+1.2.6 (2024-01-08)
+------------------
+
+Fix:
+ - improve naming (#42)
+ - magical spaces in recursive partials (#43)
+ - installation when tool isn't built
+ - correct detection of falsey values (#45)
+
+Minor:
+ - update to newer reference tests
+
+1.2.5 (2023-02-18)
+------------------
+Fix:
+ - Don't override CFLAGS in Makefile
+ - Use of $(INSTALL) in Makefile for setting options
+
+Minor:
+ - Orthograf of 'instantiate'
+
+1.2.4 (2023-01-02)
+------------------
+Fix:
+ - Latent SIGSEGV using cJSON
+
+1.2.3 (2022-12-21)
+------------------
+
+New:
+ - Flag Mustach_With_ErrorUndefined (and option --strict for the tool)
+ for returning a requested tag is not defined
+ - Test of specifications in separate directory
+
+Fix:
+ - Version printing is now okay
+ - Compiling libraries on Darwin (no soname but install_name)
+ - Compiling test6 with correct flags
+ - Update test from specifications
+ - Better use of valgrind reports
+
+1.2.2 (2021-10-28)
+------------------
+
+Fix:
+ - SONAME of libmustach-json-c.so
+
+1.2.1 (2021-10-19)
+------------------
+
+New:
+ - Add SONAME in libraries.
+ - Flag Mustach_With_PartialDataFirst to switch the
+ policy of resolving partials.
+
+Fix:
+ - Identification of types in cJSON
+
+1.2.0 (2021-08-24)
+------------------
+
+New:
+ - Add hook 'mustach_wrap_get_partial' for handling partials.
+ - Add test of mustache specifications https://github.com/mustache/spec.
+
+Changes:
+ - Mustach_With_SingleDot is always set.
+ - Mustach_With_IncPartial is always set.
+ - Mustach_With_AllExtensions is changed to use currently known extensions.
+ - Output of tests changed.
+ - Makefile improved.
+ - Partials are first searched as file then in current selection.
+ - Improved management of delimiters.
+
+Fixes:
+ - Improved output accordingly to https://github.com/mustache/spec:
+ - escaping of quote "
+ - interpolating null with empty string
+ - removal of empty lines with standalone tag
+ - don't enter section if null
+ - indentation of partials
+ - comment improved for get of mustach_wrap_itf.
+
+1.1.1 (2021-08-19)
+------------------
+Fixes:
+ - Avoid conflicting with getopt.
+ - Remove unexpected build artifact.
+ - Handle correctly a size of 0.
+
+1.1.0 (2021-05-01)
+------------------
+New:
+ - API refactored to take lengths to ease working with partial or
+ non-NULL-terminated strings. (ABI break)
+
+Fixes:
+ - Use correct int type for jansson (json_int_t instead of int64_t).
+ - JSON output of different backends is now the same.
+
+1.0 (2021-04-28, retracted)
+---------------------------
+Legal:
+ - License changed to ISC.
+
+Fixes:
+ - Possible data leak in memfile_open() by clearing buffers.
+ - Fix build on Solaris-likes by including alloca.h.
+ - Fix Windows build by including malloc.h, using size_t instead of
+ ssize_t, and using the standard ternary operator syntax.
+ - Fix JSON in test3 by using double quote characters.
+ - Fix installation in alternative directories such as
+ /opt/pkg/lib on macOS by setting install_name.
+ - Normalise return values in compare() implementations.
+
+New:
+ - Support for cJSON and jansson libraries.
+ - Version info now embedded at build time and shown with mustach(1)
+ usage.
+ - Versioned so-names (e.g. libxlsx.so.1.0).
+ - BINDIR, LIBDIR and INCLUDEDIR variables in Makefile.
+ - New mustach-wrap.{c,h} to ease implementation new libraries,
+ extracted and refactored from the existing implementations.
+ - Makefile now supports 3 modes: single libmustach (default), split
+ libmustache-core etc, and both.
+ - Any or all backends (json-c, jansson, etc) can be enabled at compile
+ time. By default, all available libraries are used.
+ - mustach(1) can use any JSON backend instead of only json-c.
+ - MUSTACH_COMPATIBLE_0_99 can be defined for backwards source
+ compatibility.
+ - 'No extensions' can now be set Mustach_With_NoExtensions instead of
+ passing 0.
+ - pkgconfig (.pc) file for library.
+ - Manual page for mustach(1).
+
+Changed:
+ - Many renames.
+ - Maximum tag length increased from 1024 to 4096.
+ - Other headers include json-c.h instead of using forward declarations.
+ - mustach(1) reads from /dev/stdin instead of fd 0.
+ - Several structures are now taken as const.
+ - New/changed Makefile targets.
diff --git a/src/templating/README.md b/src/templating/README.md
index 7034ef99f..324c9a862 100644
--- a/src/templating/README.md
+++ b/src/templating/README.md
@@ -5,7 +5,7 @@ template specification.
The main site for `mustach` is on [gitlab](https://gitlab.com/jobol/mustach).
-The simplest way to use mustach is to copy the files **mustach.h** and **mustach.c**
+The simpliest way to use mustach is to copy the files **mustach.h** and **mustach.c**
directly into your project and use it.
If you are using one of the JSON libraries listed below, you can get extended feature
@@ -85,7 +85,7 @@ It then outputs the result of applying the templates files to the JSON file.
### Portability
Some system does not provide *open_memstream*. In that case, tell your
-preferred compiler to declare the preprocessor symbol **NO_OPEN_MEMSTREAM**.
+prefered compiler to declare the preprocessor symbol **NO_OPEN_MEMSTREAM**.
Example:
CFLAGS=-DNO_OPEN_MEMSTREAM make
@@ -154,6 +154,13 @@ The libraries that can be produced are:
There is no dependencies of a library to an other. This is intended and doesn't
hurt today because the code is small.
+### Testing
+
+The makefile offers the way to execute basic tests. Just type `make test`.
+
+By default, if valgrind is available, tests are using it. It can be disabled
+by typing `make test valgrind=no` or `NOVALGRIND=1 make test`.
+
## Extensions
The current implementation provides extensions to specifications of **mustache**.
@@ -163,7 +170,7 @@ Here is the summary.
Flag name | Description
-------------------------------+------------------------------------------------
- Mustach_With_Colon | Explicit tag substitution with colon
+ Mustach_With_Colon | Explicit tag substition with colon
Mustach_With_EmptyTag | Empty Tag Allowed
-------------------------------+------------------------------------------------
Mustach_With_Equal | Value Testing Equality
@@ -180,7 +187,7 @@ For the details, see below.
### Explicit Tag Substitution With Colon (Mustach_With_Colon)
-In somecases the name of the key used for substitution begins with a
+In somecases the name of the key used for substition begins with a
character reserved for mustach: one of `#`, `^`, `/`, `&`, `{`, `>` and `=`.
This extension introduces the special character `:` to explicitly
@@ -311,3 +318,4 @@ The table below summarize the changes.
fdmustach_json_c | mustach_json_c_fd
mustach_json_c | mustach_json_c_mem
mustach_json_c | mustach_json_c_write
+
diff --git a/src/templating/dotest.sh b/src/templating/dotest.sh
new file mode 100755
index 000000000..99ff8b201
--- /dev/null
+++ b/src/templating/dotest.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+mustach=${mustach:-../mustach}
+echo starting test
+if test "$NOVALGRIND" = 1
+then
+ $mustach "$@" > resu.last
+else
+ valgrind $mustach "$@" > resu.last 2> vg.last
+ sed -i 's:^==[0-9]*== ::' vg.last
+ awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
+fi
+if diff -w resu.ref resu.last
+then
+ echo "result ok"
+else
+ echo "ERROR! Result differs"
+fi
+echo
+
diff --git a/src/templating/mustach-cjson.c b/src/templating/mustach-cjson.c
index 48b97e7df..ee65c8038 100644
--- a/src/templating/mustach-cjson.c
+++ b/src/templating/mustach-cjson.c
@@ -6,7 +6,9 @@
SPDX-License-Identifier: ISC
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdio.h>
#include <string.h>
@@ -90,11 +92,21 @@ static int sel(void *closure, const char *name)
static int subsel(void *closure, const char *name)
{
struct expl *e = closure;
- cJSON *o;
- int r;
+ cJSON *o = NULL;
+ int r = 0;
- o = cJSON_GetObjectItemCaseSensitive(e->selection, name);
- r = o != NULL;
+ if (cJSON_IsObject(e->selection)) {
+ o = cJSON_GetObjectItemCaseSensitive(e->selection, name);
+ r = o != NULL;
+ }
+ else if (cJSON_IsArray(e->selection) && *name) {
+ char *end;
+ int idx = (int)strtol(name, &end, 10);
+ if (!*end && idx >= 0 && idx < cJSON_GetArraySize(e->selection)) {
+ o = cJSON_GetArrayItem(e->selection, idx);
+ r = 1;
+ }
+ }
if (r)
e->selection = o;
return r;
@@ -125,7 +137,10 @@ static int enter(void *closure, int objiter)
e->stack[e->depth].obj = o->child;
e->stack[e->depth].next = o->child->next;
e->stack[e->depth].cont = o;
- } else if ((cJSON_IsObject(o) && o->child == NULL) || (! cJSON_IsFalse(o) && ! cJSON_IsNull(o))) {
+ } else if ((cJSON_IsObject(o) && o->child != NULL)
+ || cJSON_IsTrue(o)
+ || (cJSON_IsString(o) && cJSON_GetStringValue(o)[0] != '\0')
+ || (cJSON_IsNumber(o) && cJSON_GetNumberValue(o) != 0)) {
e->stack[e->depth].obj = o;
e->stack[e->depth].cont = NULL;
e->stack[e->depth].next = NULL;
@@ -170,11 +185,15 @@ static int get(void *closure, struct mustach_sbuf *sbuf, int key)
{
struct expl *e = closure;
const char *s;
+ int d;
if (key) {
- s = e->stack[e->depth].is_objiter
- ? e->stack[e->depth].obj->string
- : "";
+ s = "";
+ for (d = e->depth ; d >= 0 ; d--)
+ if (e->stack[d].is_objiter) {
+ s = e->stack[d].obj->string;
+ break;
+ }
}
else if (cJSON_IsString(e->selection))
s = e->selection->valuestring;
diff --git a/src/templating/mustach-cjson.h b/src/templating/mustach-cjson.h
index ae0d818cb..e049415f8 100644
--- a/src/templating/mustach-cjson.h
+++ b/src/templating/mustach-cjson.h
@@ -10,7 +10,7 @@
#define _mustach_cJSON_h_included_
/*
- * mustach-json-c is intended to make integration of cJSON
+ * mustach-cjson is intended to make integration of cJSON
* library by providing integrated functions.
*/
diff --git a/src/templating/mustach-jansson.c b/src/templating/mustach-jansson.c
index 3ce0e0a84..d9b50b57e 100644
--- a/src/templating/mustach-jansson.c
+++ b/src/templating/mustach-jansson.c
@@ -6,7 +6,9 @@
SPDX-License-Identifier: ISC
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdio.h>
#include <string.h>
@@ -94,11 +96,21 @@ static int sel(void *closure, const char *name)
static int subsel(void *closure, const char *name)
{
struct expl *e = closure;
- json_t *o;
- int r;
+ json_t *o = NULL;
+ int r = 0;
- o = json_object_get(e->selection, name);
- r = o != NULL;
+ if (json_is_object(e->selection)) {
+ o = json_object_get(e->selection, name);
+ r = o != NULL;
+ }
+ else if (json_is_array(e->selection)) {
+ char *end;
+ size_t idx = (size_t)strtol(name, &end, 10);
+ if (!*end && idx < json_array_size(e->selection)) {
+ o = json_array_get(e->selection, idx);
+ r = 1;
+ }
+ }
if (r)
e->selection = o;
return r;
@@ -130,7 +142,11 @@ static int enter(void *closure, int objiter)
e->stack[e->depth].cont = o;
e->stack[e->depth].obj = json_array_get(o, 0);
e->stack[e->depth].index = 0;
- } else if ((json_is_object(o) && json_object_size(0)) || (!json_is_false(o) && !json_is_null(o))) {
+ } else if ((json_is_object(o) && json_object_size(o))
+ || json_is_true(o)
+ || (json_is_string(o) && json_string_length(o) > 0)
+ || (json_is_integer(o) && json_integer_value(o) != 0)
+ || (json_is_real(o) && json_real_value(o) != 0)) {
e->stack[e->depth].count = 1;
e->stack[e->depth].cont = NULL;
e->stack[e->depth].obj = o;
@@ -182,11 +198,15 @@ static int get(void *closure, struct mustach_sbuf *sbuf, int key)
{
struct expl *e = closure;
const char *s;
+ int d;
if (key) {
- s = e->stack[e->depth].is_objiter
- ? json_object_iter_key(e->stack[e->depth].iter)
- : "";
+ s = "";
+ for (d = e->depth ; d >= 0 ; d--)
+ if (e->stack[d].is_objiter) {
+ s = json_object_iter_key(e->stack[d].iter);
+ break;
+ }
}
else if (json_is_string(e->selection))
s = json_string_value(e->selection);
diff --git a/src/templating/mustach-json-c.c b/src/templating/mustach-json-c.c
index a21a113fb..75251c07e 100644
--- a/src/templating/mustach-json-c.c
+++ b/src/templating/mustach-json-c.c
@@ -6,7 +6,9 @@
SPDX-License-Identifier: ISC
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdio.h>
#include <string.h>
@@ -87,10 +89,19 @@ static int sel(void *closure, const char *name)
static int subsel(void *closure, const char *name)
{
struct expl *e = closure;
- struct json_object *o;
- int r;
-
- r = json_object_object_get_ex(e->selection, name, &o);
+ struct json_object *o = NULL;
+ int r = 0;
+
+ if (json_object_is_type(e->selection, json_type_object))
+ r = json_object_object_get_ex(e->selection, name, &o);
+ else if (json_object_is_type(e->selection, json_type_array)) {
+ char *end;
+ size_t idx = (size_t)strtol(name, &end, 10);
+ if (!*end && idx < json_object_array_length(e->selection)) {
+ o = json_object_array_get_idx(e->selection, idx);
+ r = 1;
+ }
+ }
if (r)
e->selection = o;
return r;
@@ -124,7 +135,8 @@ static int enter(void *closure, int objiter)
e->stack[e->depth].cont = o;
e->stack[e->depth].obj = json_object_array_get_idx(o, 0);
e->stack[e->depth].index = 0;
- } else if (json_object_is_type(o, json_type_object) || json_object_get_boolean(o)) {
+ } else if ((json_object_is_type(o, json_type_object) && json_object_object_length(o) > 0)
+ || json_object_get_boolean(o)) {
e->stack[e->depth].count = 1;
e->stack[e->depth].cont = NULL;
e->stack[e->depth].obj = o;
@@ -176,11 +188,16 @@ static int get(void *closure, struct mustach_sbuf *sbuf, int key)
{
struct expl *e = closure;
const char *s;
-
- if (key)
- s = e->stack[e->depth].is_objiter
- ? json_object_iter_peek_name(&e->stack[e->depth].iter)
- : "";
+ int d;
+
+ if (key) {
+ s = "";
+ for (d = e->depth ; d >= 0 ; d--)
+ if (e->stack[d].is_objiter) {
+ s = json_object_iter_peek_name(&e->stack[d].iter);
+ break;
+ }
+ }
else
switch (json_object_get_type(e->selection)) {
case json_type_string:
diff --git a/src/templating/mustach-original-Makefile b/src/templating/mustach-original-Makefile
index e902b2c71..6d90f33d9 100644
--- a/src/templating/mustach-original-Makefile
+++ b/src/templating/mustach-original-Makefile
@@ -1,7 +1,7 @@
# version
MAJOR := 1
MINOR := 2
-REVIS := 4
+REVIS := 6
# installation settings
DESTDIR ?=
@@ -214,7 +214,9 @@ mustach-jansson.o: mustach-jansson.c mustach.h mustach-wrap.h mustach-jansson.h
.PHONY: install
install: all
$(INSTALL) -d $(DESTDIR)$(BINDIR)
- $(INSTALL) -m0755 mustach $(DESTDIR)$(BINDIR)/
+ if test "${tool}" != "none"; then \
+ $(INSTALL) -m0755 mustach $(DESTDIR)$(BINDIR)/; \
+ fi
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)/mustach
$(INSTALL) -m0644 $(HEADERS) $(DESTDIR)$(INCLUDEDIR)/mustach
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
@@ -236,6 +238,13 @@ uninstall:
rm -rf $(DESTDIR)$(INCLUDEDIR)/mustach
# testing
+ifeq ($(valgrind),no)
+ NOVALGRIND := 1
+else
+ NOVALGRIND := $(shell which -s valgrind && echo 0 || echo 1)
+endif
+export NOVALGRIND
+
.PHONY: test test-basic test-specs
test: basic-tests spec-tests
@@ -245,7 +254,9 @@ basic-tests: mustach
@$(MAKE) -C test3 test
@$(MAKE) -C test4 test
@$(MAKE) -C test5 test
-# @$(MAKE) -C test6 test
+ @$(MAKE) -C test6 test
+ @$(MAKE) -C test7 test
+ @$(MAKE) -C test8 test
spec-tests: $(TESTSPECS)
@@ -291,6 +302,8 @@ clean:
@$(MAKE) -C test4 clean
@$(MAKE) -C test5 clean
@$(MAKE) -C test6 clean
+ @$(MAKE) -C test7 clean
+ @$(MAKE) -C test8 clean
# manpage
.PHONY: manuals
@@ -298,3 +311,4 @@ manuals: mustach.1.gz
mustach.1.gz: mustach.1.scd
if which scdoc >/dev/null 2>&1; then scdoc < mustach.1.scd | gzip > mustach.1.gz; fi
+
diff --git a/src/templating/mustach-tool.c b/src/templating/mustach-tool.c
index 83a0813e5..e2a5c1f40 100644
--- a/src/templating/mustach-tool.c
+++ b/src/templating/mustach-tool.c
@@ -6,7 +6,9 @@
SPDX-License-Identifier: ISC
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdlib.h>
#include <stdio.h>
diff --git a/src/templating/mustach-wrap.c b/src/templating/mustach-wrap.c
index 75cc9d1f6..869713c86 100644
--- a/src/templating/mustach-wrap.c
+++ b/src/templating/mustach-wrap.c
@@ -6,7 +6,9 @@
SPDX-License-Identifier: ISC
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdlib.h>
#include <stdio.h>
@@ -227,20 +229,20 @@ static enum sel sel(struct wrap *w, const char *name)
return result;
}
-static int start(void *closure)
+static int start_callback(void *closure)
{
struct wrap *w = closure;
return w->itf->start ? w->itf->start(w->closure) : MUSTACH_OK;
}
-static void stop(void *closure, int status)
+static void stop_callback(void *closure, int status)
{
struct wrap *w = closure;
if (w->itf->stop)
w->itf->stop(w->closure, status);
}
-static int write(struct wrap *w, const char *buffer, size_t size, FILE *file)
+static int emit(struct wrap *w, const char *buffer, size_t size, FILE *file)
{
int r;
@@ -251,7 +253,7 @@ static int write(struct wrap *w, const char *buffer, size_t size, FILE *file)
return r;
}
-static int emit(void *closure, const char *buffer, size_t size, int escape, FILE *file)
+static int emit_callback(void *closure, const char *buffer, size_t size, int escape, FILE *file)
{
struct wrap *w = closure;
int r;
@@ -261,7 +263,7 @@ static int emit(void *closure, const char *buffer, size_t size, int escape, FILE
if (w->emitcb)
r = w->emitcb(file, buffer, size, escape);
else if (!escape)
- r = write(w, buffer, size, file);
+ r = emit(w, buffer, size, file);
else {
i = 0;
r = MUSTACH_OK;
@@ -270,13 +272,13 @@ static int emit(void *closure, const char *buffer, size_t size, int escape, FILE
while (i < size && (car = buffer[i]) != '<' && car != '>' && car != '&' && car != '"')
i++;
if (i != s)
- r = write(w, &buffer[s], i - s, file);
+ r = emit(w, &buffer[s], i - s, file);
if (i < size && r == MUSTACH_OK) {
switch(car) {
- case '<': r = write(w, "&lt;", 4, file); break;
- case '>': r = write(w, "&gt;", 4, file); break;
- case '&': r = write(w, "&amp;", 5, file); break;
- case '"': r = write(w, "&quot;", 6, file); break;
+ case '<': r = emit(w, "&lt;", 4, file); break;
+ case '>': r = emit(w, "&gt;", 4, file); break;
+ case '&': r = emit(w, "&amp;", 5, file); break;
+ case '"': r = emit(w, "&quot;", 6, file); break;
}
i++;
}
@@ -285,20 +287,20 @@ static int emit(void *closure, const char *buffer, size_t size, int escape, FILE
return r;
}
-static int enter(void *closure, const char *name)
+static int enter_callback(void *closure, const char *name)
{
struct wrap *w = closure;
enum sel s = sel(w, name);
return s == S_none ? 0 : w->itf->enter(w->closure, s & S_objiter);
}
-static int next(void *closure)
+static int next_callback(void *closure)
{
struct wrap *w = closure;
return w->itf->next(w->closure);
}
-static int leave(void *closure)
+static int leave_callback(void *closure)
{
struct wrap *w = closure;
return w->itf->leave(w->closure);
@@ -312,7 +314,7 @@ static int getoptional(struct wrap *w, const char *name, struct mustach_sbuf *sb
return w->itf->get(w->closure, sbuf, s & S_objiter);
}
-static int get(void *closure, const char *name, struct mustach_sbuf *sbuf)
+static int get_callback(void *closure, const char *name, struct mustach_sbuf *sbuf)
{
struct wrap *w = closure;
if (getoptional(w, name, sbuf) <= 0) {
@@ -374,7 +376,7 @@ static int get_partial_from_file(const char *name, struct mustach_sbuf *sbuf)
return MUSTACH_ERROR_SYSTEM;
}
-static int partial(void *closure, const char *name, struct mustach_sbuf *sbuf)
+static int partial_callback(void *closure, const char *name, struct mustach_sbuf *sbuf)
{
struct wrap *w = closure;
int rc;
@@ -397,15 +399,15 @@ static int partial(void *closure, const char *name, struct mustach_sbuf *sbuf)
}
const struct mustach_itf mustach_wrap_itf = {
- .start = start,
+ .start = start_callback,
.put = NULL,
- .enter = enter,
- .next = next,
- .leave = leave,
- .partial = partial,
- .get = get,
- .emit = emit,
- .stop = stop
+ .enter = enter_callback,
+ .next = next_callback,
+ .leave = leave_callback,
+ .partial = partial_callback,
+ .get = get_callback,
+ .emit = emit_callback,
+ .stop = stop_callback
};
static void wrap_init(struct wrap *wrap, const struct mustach_wrap_itf *itf, void *closure, int flags, mustach_emit_cb_t *emitcb, mustach_write_cb_t *writecb)
diff --git a/src/templating/mustach.1.gz b/src/templating/mustach.1.gz
new file mode 100644
index 000000000..15b8a9052
--- /dev/null
+++ b/src/templating/mustach.1.gz
Binary files differ
diff --git a/src/templating/mustach.1.scd b/src/templating/mustach.1.scd
new file mode 100644
index 000000000..af4f08ef2
--- /dev/null
+++ b/src/templating/mustach.1.scd
@@ -0,0 +1,60 @@
+mustach(1)
+
+# NAME
+
+mustach - Mustache templating command line engine
+
+# SYNOPSIS
+
+*mustach* [-s|--strict] JSON TEMPLATE...
+
+# DESCRIPTION
+
+Instanciate the TEMPLATE files accordingly to the JSON file.
+
+If one of the given files is *-*, the standard input is used.
+
+Option *--strict* make mustach fail if a tag is not found.
+
+# EXAMPLE
+
+A typical Mustache template file: *temp.must*
+
+```
+Hello {{name}}
+You have just won {{value}} dollars!
+{{#in_ca}}
+Well, {{taxed_value}} dollars, after taxes.
+{{/in_ca}}
+```
+
+Given a JSON file: *inst.json*
+
+```
+{
+ "name": "Chris",
+ "value": 10000,
+ "taxed_value": 6000,
+ "in_ca": true
+}
+```
+
+Calling the command *mustach inst.json temp.must*
+will produce the following output:
+
+```
+Hello Chris
+You have just won 10000 dollars!
+Well, 6000.0 dollars, after taxes.
+```
+
+# LINK
+
+Site of *mustach*, the *C* implementation: https://gitlab.com/jobol/mustach
+
+*Mustache format*: http://mustache.github.io/mustache.5.html
+
+Main site for *Mustache*: http://mustache.github.io/
+
+JSON: https://www.json.org/
+
diff --git a/src/templating/mustach.c b/src/templating/mustach.c
index 548c38224..9f992c737 100644
--- a/src/templating/mustach.c
+++ b/src/templating/mustach.c
@@ -6,7 +6,9 @@
SPDX-License-Identifier: ISC
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdlib.h>
#include <stdio.h>
@@ -272,6 +274,7 @@ static int process(const char *template, size_t length, struct iwrap *iwrap, FIL
template += l;
stdalone = 1;
pref.len = 0;
+ pref.prefix = prefix;
}
else if (!isspace(c)) {
if (stdalone == 2 && enabled) {
@@ -280,6 +283,7 @@ static int process(const char *template, size_t length, struct iwrap *iwrap, FIL
return rc;
pref.len = 0;
stdalone = 0;
+ pref.prefix = NULL;
}
if (c == *opstr && end - beg >= (ssize_t)oplen) {
for (l = 1 ; l < oplen && beg[l] == opstr[l] ; l++);
@@ -360,6 +364,7 @@ get_name:
if (rc < 0)
return rc;
pref.len = 0;
+ pref.prefix = NULL;
}
switch(c) {
case '!':
@@ -485,7 +490,7 @@ int mustach_file(const char *template, size_t length, const struct mustach_itf *
/* process */
rc = itf->start ? itf->start(closure) : 0;
if (rc == 0)
- rc = process(template, length, &iwrap, file, 0);
+ rc = process(template, length, &iwrap, file, NULL);
if (itf->stop)
itf->stop(closure, rc);
return rc;
diff --git a/src/templating/pkgcfgs b/src/templating/pkgcfgs
new file mode 100644
index 000000000..c3e84dc0e
--- /dev/null
+++ b/src/templating/pkgcfgs
@@ -0,0 +1,35 @@
+==libmustach.pc==
+Name: libmustach
+Version: VERSION
+Description: C Mustach single library
+Cflags: -Imustach
+Libs: -lmustach
+
+==libmustach-core.pc==
+Name: libmustach-core
+Version: VERSION
+Description: C Mustach core library
+Cflags: -Imustach
+Libs: -lmustach-core
+
+==libmustach-cjson.pc==
+Name: libmustach-cjson
+Version: VERSION
+Description: C Mustach library for cJSON
+Cflags: -Imustach
+Libs: -lmustach-cjson
+
+==libmustach-json-c.pc==
+Name: libmustach-json-c
+Version: VERSION
+Description: C Mustach library for json-c
+Cflags: -Imustach
+Libs: -lmustach-json-c
+
+==libmustach-jansson.pc==
+Name: libmustach-jansson
+Version: VERSION
+Description: C Mustach library for jansson
+Cflags: -Imustach
+Libs: -lmustach-jansson
+
diff --git a/src/templating/test-specs/test-specs-cjson.ref b/src/templating/test-specs/test-specs-cjson.ref
new file mode 100644
index 000000000..8897c66cc
--- /dev/null
+++ b/src/templating/test-specs/test-specs-cjson.ref
@@ -0,0 +1,425 @@
+
+loading test-specs/spec/specs/comments.json
+processing file test-specs/spec/specs/comments.json
+[0] Inline
+ Comment blocks should be removed from the template.
+ => SUCCESS
+[1] Multiline
+ Multiline comments should be permitted.
+ => SUCCESS
+[2] Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[3] Indented Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[4] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[5] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[6] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[7] Multiline Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[8] Indented Multiline Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[9] Indented Inline
+ Inline comments should not strip whitespace
+ => SUCCESS
+[10] Surrounding Whitespace
+ Comment removal should preserve surrounding whitespace.
+ => SUCCESS
+[11] Variable Name Collision
+ Comments must never render, even if variable with same name exists.
+ => SUCCESS
+
+loading test-specs/spec/specs/delimiters.json
+processing file test-specs/spec/specs/delimiters.json
+[0] Pair Behavior
+ The equals sign (used on both sides) should permit delimiter changes.
+ => SUCCESS
+[1] Special Characters
+ Characters with special meaning regexen should be valid delimiters.
+ => SUCCESS
+[2] Sections
+ Delimiters set outside sections should persist.
+ => SUCCESS
+[3] Inverted Sections
+ Delimiters set outside inverted sections should persist.
+ => SUCCESS
+[4] Partial Inheritence
+ Delimiters set in a parent template should not affect a partial.
+ => SUCCESS
+[5] Post-Partial Behavior
+ Delimiters set in a partial should not affect the parent template.
+ => SUCCESS
+[6] Surrounding Whitespace
+ Surrounding whitespace should be left untouched.
+ => SUCCESS
+[7] Outlying Whitespace (Inline)
+ Whitespace should be left untouched.
+ => SUCCESS
+[8] Standalone Tag
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[9] Indented Standalone Tag
+ Indented standalone lines should be removed from the template.
+ => SUCCESS
+[10] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[11] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[12] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[13] Pair with Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/interpolation.json
+processing file test-specs/spec/specs/interpolation.json
+[0] No Interpolation
+ Mustache-free templates should render as-is.
+ => SUCCESS
+[1] Basic Interpolation
+ Unadorned tags should interpolate content into the template.
+ => SUCCESS
+[2] HTML Escaping
+ Basic interpolation should be HTML escaped.
+ => SUCCESS
+[3] Triple Mustache
+ Triple mustaches should interpolate without HTML escaping.
+ => SUCCESS
+[4] Ampersand
+ Ampersand should interpolate without HTML escaping.
+ => SUCCESS
+[5] Basic Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[6] Triple Mustache Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[7] Ampersand Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[8] Basic Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[9] Triple Mustache Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[10] Ampersand Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[11] Basic Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[12] Triple Mustache Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[13] Ampersand Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[14] Basic Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[15] Triple Mustache Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[16] Ampersand Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[17] Dotted Names - Basic Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[18] Dotted Names - Triple Mustache Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[19] Dotted Names - Ampersand Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[20] Dotted Names - Arbitrary Depth
+ Dotted names should be functional to any level of nesting.
+ => SUCCESS
+[21] Dotted Names - Broken Chains
+ Any falsey value prior to the last part of the name should yield ''.
+ => SUCCESS
+[22] Dotted Names - Broken Chain Resolution
+ Each part of a dotted name should resolve only against its parent.
+ => SUCCESS
+[23] Dotted Names - Initial Resolution
+ The first part of a dotted name should resolve as any other name.
+ => SUCCESS
+[24] Dotted Names - Context Precedence
+ Dotted names should be resolved against former resolutions.
+ => SUCCESS
+[25] Implicit Iterators - Basic Interpolation
+ Unadorned tags should interpolate content into the template.
+ => SUCCESS
+[26] Implicit Iterators - HTML Escaping
+ Basic interpolation should be HTML escaped.
+ => SUCCESS
+[27] Implicit Iterators - Triple Mustache
+ Triple mustaches should interpolate without HTML escaping.
+ => SUCCESS
+[28] Implicit Iterators - Ampersand
+ Ampersand should interpolate without HTML escaping.
+ => SUCCESS
+[29] Implicit Iterators - Basic Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[30] Interpolation - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[31] Triple Mustache - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[32] Ampersand - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[33] Interpolation - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[34] Triple Mustache - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[35] Ampersand - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[36] Interpolation With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+[37] Triple Mustache With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+[38] Ampersand With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/inverted.json
+processing file test-specs/spec/specs/inverted.json
+[0] Falsey
+ Falsey sections should have their contents rendered.
+ => SUCCESS
+[1] Truthy
+ Truthy sections should have their contents omitted.
+ => SUCCESS
+[2] Null is falsey
+ Null is falsey.
+ => SUCCESS
+[3] Context
+ Objects and hashes should behave like truthy values.
+ => SUCCESS
+[4] List
+ Lists should behave like truthy values.
+ => SUCCESS
+[5] Empty List
+ Empty lists should behave like falsey values.
+ => SUCCESS
+[6] Doubled
+ Multiple inverted sections per template should be permitted.
+ => SUCCESS
+[7] Nested (Falsey)
+ Nested falsey sections should have their contents rendered.
+ => SUCCESS
+[8] Nested (Truthy)
+ Nested truthy sections should be omitted.
+ => SUCCESS
+[9] Context Misses
+ Failed context lookups should be considered falsey.
+ => SUCCESS
+[10] Dotted Names - Truthy
+ Dotted names should be valid for Inverted Section tags.
+ => SUCCESS
+[11] Dotted Names - Falsey
+ Dotted names should be valid for Inverted Section tags.
+ => SUCCESS
+[12] Dotted Names - Broken Chains
+ Dotted names that cannot be resolved should be considered falsey.
+ => SUCCESS
+[13] Surrounding Whitespace
+ Inverted sections should not alter surrounding whitespace.
+ => SUCCESS
+[14] Internal Whitespace
+ Inverted should not alter internal whitespace.
+ => SUCCESS
+[15] Indented Inline Sections
+ Single-line sections should not alter surrounding whitespace.
+ => SUCCESS
+[16] Standalone Lines
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[17] Standalone Indented Lines
+ Standalone indented lines should be removed from the template.
+ => SUCCESS
+[18] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[19] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[20] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[21] Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/partials.json
+processing file test-specs/spec/specs/partials.json
+[0] Basic Behavior
+ The greater-than operator should expand to the named partial.
+ => SUCCESS
+[1] Failed Lookup
+ The empty string should be used when the named partial is not found.
+ => SUCCESS
+[2] Context
+ The greater-than operator should operate within the current context.
+ => SUCCESS
+[3] Recursion
+ The greater-than operator should properly recurse.
+ => SUCCESS
+[4] Nested
+ The greater-than operator should work from within partials.
+ => SUCCESS
+[5] Surrounding Whitespace
+ The greater-than operator should not alter surrounding whitespace.
+ => SUCCESS
+[6] Inline Indentation
+ Whitespace should be left untouched.
+ => SUCCESS
+[7] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[8] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[9] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[10] Standalone Indentation
+ Each line of the partial should be indented before rendering.
+ => SUCCESS
+[11] Padding Whitespace
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/sections.json
+processing file test-specs/spec/specs/sections.json
+[0] Truthy
+ Truthy sections should have their contents rendered.
+ => SUCCESS
+[1] Falsey
+ Falsey sections should have their contents omitted.
+ => SUCCESS
+[2] Null is falsey
+ Null is falsey.
+ => SUCCESS
+[3] Context
+ Objects and hashes should be pushed onto the context stack.
+ => SUCCESS
+[4] Parent contexts
+ Names missing in the current context are looked up in the stack.
+ => SUCCESS
+[5] Variable test
+ Non-false sections have their value at the top of context,
+accessible as {{.}} or through the parent context. This gives
+a simple way to display content conditionally if a variable exists.
+
+ => SUCCESS
+[6] List Contexts
+ All elements on the context stack should be accessible within lists.
+ => SUCCESS
+[7] Deeply Nested Contexts
+ All elements on the context stack should be accessible.
+ => SUCCESS
+[8] List
+ Lists should be iterated; list items should visit the context stack.
+ => SUCCESS
+[9] Empty List
+ Empty lists should behave like falsey values.
+ => SUCCESS
+[10] Doubled
+ Multiple sections per template should be permitted.
+ => SUCCESS
+[11] Nested (Truthy)
+ Nested truthy sections should have their contents rendered.
+ => SUCCESS
+[12] Nested (Falsey)
+ Nested falsey sections should be omitted.
+ => SUCCESS
+[13] Context Misses
+ Failed context lookups should be considered falsey.
+ => SUCCESS
+[14] Implicit Iterator - String
+ Implicit iterators should directly interpolate strings.
+ => SUCCESS
+[15] Implicit Iterator - Integer
+ Implicit iterators should cast integers to strings and interpolate.
+ => SUCCESS
+[16] Implicit Iterator - Decimal
+ Implicit iterators should cast decimals to strings and interpolate.
+ => SUCCESS
+[17] Implicit Iterator - Array
+ Implicit iterators should allow iterating over nested arrays.
+ => SUCCESS
+[18] Implicit Iterator - HTML Escaping
+ Implicit iterators with basic interpolation should be HTML escaped.
+ => SUCCESS
+[19] Implicit Iterator - Triple mustache
+ Implicit iterators in triple mustache should interpolate without HTML escaping.
+ => SUCCESS
+[20] Implicit Iterator - Ampersand
+ Implicit iterators in an Ampersand tag should interpolate without HTML escaping.
+ => SUCCESS
+[21] Implicit Iterator - Root-level
+ Implicit iterators should work on root-level lists.
+ => SUCCESS
+[22] Dotted Names - Truthy
+ Dotted names should be valid for Section tags.
+ => SUCCESS
+[23] Dotted Names - Falsey
+ Dotted names should be valid for Section tags.
+ => SUCCESS
+[24] Dotted Names - Broken Chains
+ Dotted names that cannot be resolved should be considered falsey.
+ => SUCCESS
+[25] Surrounding Whitespace
+ Sections should not alter surrounding whitespace.
+ => SUCCESS
+[26] Internal Whitespace
+ Sections should not alter internal whitespace.
+ => SUCCESS
+[27] Indented Inline Sections
+ Single-line sections should not alter surrounding whitespace.
+ => SUCCESS
+[28] Standalone Lines
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[29] Indented Standalone Lines
+ Indented standalone lines should be removed from the template.
+ => SUCCESS
+[30] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[31] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[32] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[33] Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+summary:
+ error 0
+ differ 0
+ success 133
diff --git a/src/templating/test-specs/test-specs-jansson.ref b/src/templating/test-specs/test-specs-jansson.ref
new file mode 100644
index 000000000..a1cef19c1
--- /dev/null
+++ b/src/templating/test-specs/test-specs-jansson.ref
@@ -0,0 +1,429 @@
+
+loading test-specs/spec/specs/comments.json
+processing file test-specs/spec/specs/comments.json
+[0] Inline
+ Comment blocks should be removed from the template.
+ => SUCCESS
+[1] Multiline
+ Multiline comments should be permitted.
+ => SUCCESS
+[2] Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[3] Indented Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[4] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[5] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[6] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[7] Multiline Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[8] Indented Multiline Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[9] Indented Inline
+ Inline comments should not strip whitespace
+ => SUCCESS
+[10] Surrounding Whitespace
+ Comment removal should preserve surrounding whitespace.
+ => SUCCESS
+[11] Variable Name Collision
+ Comments must never render, even if variable with same name exists.
+ => SUCCESS
+
+loading test-specs/spec/specs/delimiters.json
+processing file test-specs/spec/specs/delimiters.json
+[0] Pair Behavior
+ The equals sign (used on both sides) should permit delimiter changes.
+ => SUCCESS
+[1] Special Characters
+ Characters with special meaning regexen should be valid delimiters.
+ => SUCCESS
+[2] Sections
+ Delimiters set outside sections should persist.
+ => SUCCESS
+[3] Inverted Sections
+ Delimiters set outside inverted sections should persist.
+ => SUCCESS
+[4] Partial Inheritence
+ Delimiters set in a parent template should not affect a partial.
+ => SUCCESS
+[5] Post-Partial Behavior
+ Delimiters set in a partial should not affect the parent template.
+ => SUCCESS
+[6] Surrounding Whitespace
+ Surrounding whitespace should be left untouched.
+ => SUCCESS
+[7] Outlying Whitespace (Inline)
+ Whitespace should be left untouched.
+ => SUCCESS
+[8] Standalone Tag
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[9] Indented Standalone Tag
+ Indented standalone lines should be removed from the template.
+ => SUCCESS
+[10] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[11] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[12] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[13] Pair with Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/interpolation.json
+processing file test-specs/spec/specs/interpolation.json
+[0] No Interpolation
+ Mustache-free templates should render as-is.
+ => SUCCESS
+[1] Basic Interpolation
+ Unadorned tags should interpolate content into the template.
+ => SUCCESS
+[2] HTML Escaping
+ Basic interpolation should be HTML escaped.
+ => SUCCESS
+[3] Triple Mustache
+ Triple mustaches should interpolate without HTML escaping.
+ => SUCCESS
+[4] Ampersand
+ Ampersand should interpolate without HTML escaping.
+ => SUCCESS
+[5] Basic Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[6] Triple Mustache Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[7] Ampersand Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[8] Basic Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[9] Triple Mustache Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[10] Ampersand Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[11] Basic Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[12] Triple Mustache Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[13] Ampersand Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[14] Basic Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[15] Triple Mustache Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[16] Ampersand Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[17] Dotted Names - Basic Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[18] Dotted Names - Triple Mustache Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[19] Dotted Names - Ampersand Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[20] Dotted Names - Arbitrary Depth
+ Dotted names should be functional to any level of nesting.
+ => SUCCESS
+[21] Dotted Names - Broken Chains
+ Any falsey value prior to the last part of the name should yield ''.
+ => SUCCESS
+[22] Dotted Names - Broken Chain Resolution
+ Each part of a dotted name should resolve only against its parent.
+ => SUCCESS
+[23] Dotted Names - Initial Resolution
+ The first part of a dotted name should resolve as any other name.
+ => SUCCESS
+[24] Dotted Names - Context Precedence
+ Dotted names should be resolved against former resolutions.
+ => SUCCESS
+[25] Implicit Iterators - Basic Interpolation
+ Unadorned tags should interpolate content into the template.
+ => SUCCESS
+[26] Implicit Iterators - HTML Escaping
+ Basic interpolation should be HTML escaped.
+ => SUCCESS
+[27] Implicit Iterators - Triple Mustache
+ Triple mustaches should interpolate without HTML escaping.
+ => SUCCESS
+[28] Implicit Iterators - Ampersand
+ Ampersand should interpolate without HTML escaping.
+ => SUCCESS
+[29] Implicit Iterators - Basic Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[30] Interpolation - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[31] Triple Mustache - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[32] Ampersand - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[33] Interpolation - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[34] Triple Mustache - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[35] Ampersand - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[36] Interpolation With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+[37] Triple Mustache With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+[38] Ampersand With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/inverted.json
+processing file test-specs/spec/specs/inverted.json
+[0] Falsey
+ Falsey sections should have their contents rendered.
+ => SUCCESS
+[1] Truthy
+ Truthy sections should have their contents omitted.
+ => SUCCESS
+[2] Null is falsey
+ Null is falsey.
+ => SUCCESS
+[3] Context
+ Objects and hashes should behave like truthy values.
+ => SUCCESS
+[4] List
+ Lists should behave like truthy values.
+ => SUCCESS
+[5] Empty List
+ Empty lists should behave like falsey values.
+ => SUCCESS
+[6] Doubled
+ Multiple inverted sections per template should be permitted.
+ => SUCCESS
+[7] Nested (Falsey)
+ Nested falsey sections should have their contents rendered.
+ => SUCCESS
+[8] Nested (Truthy)
+ Nested truthy sections should be omitted.
+ => SUCCESS
+[9] Context Misses
+ Failed context lookups should be considered falsey.
+ => SUCCESS
+[10] Dotted Names - Truthy
+ Dotted names should be valid for Inverted Section tags.
+ => SUCCESS
+[11] Dotted Names - Falsey
+ Dotted names should be valid for Inverted Section tags.
+ => SUCCESS
+[12] Dotted Names - Broken Chains
+ Dotted names that cannot be resolved should be considered falsey.
+ => SUCCESS
+[13] Surrounding Whitespace
+ Inverted sections should not alter surrounding whitespace.
+ => SUCCESS
+[14] Internal Whitespace
+ Inverted should not alter internal whitespace.
+ => SUCCESS
+[15] Indented Inline Sections
+ Single-line sections should not alter surrounding whitespace.
+ => SUCCESS
+[16] Standalone Lines
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[17] Standalone Indented Lines
+ Standalone indented lines should be removed from the template.
+ => SUCCESS
+[18] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[19] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[20] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[21] Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/partials.json
+processing file test-specs/spec/specs/partials.json
+[0] Basic Behavior
+ The greater-than operator should expand to the named partial.
+ => SUCCESS
+[1] Failed Lookup
+ The empty string should be used when the named partial is not found.
+ => SUCCESS
+[2] Context
+ The greater-than operator should operate within the current context.
+ => SUCCESS
+[3] Recursion
+ The greater-than operator should properly recurse.
+ => SUCCESS
+[4] Nested
+ The greater-than operator should work from within partials.
+ => SUCCESS
+[5] Surrounding Whitespace
+ The greater-than operator should not alter surrounding whitespace.
+ => SUCCESS
+[6] Inline Indentation
+ Whitespace should be left untouched.
+ => SUCCESS
+[7] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[8] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[9] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[10] Standalone Indentation
+ Each line of the partial should be indented before rendering.
+ => SUCCESS
+[11] Padding Whitespace
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/sections.json
+processing file test-specs/spec/specs/sections.json
+[0] Truthy
+ Truthy sections should have their contents rendered.
+ => SUCCESS
+[1] Falsey
+ Falsey sections should have their contents omitted.
+ => SUCCESS
+[2] Null is falsey
+ Null is falsey.
+ => SUCCESS
+[3] Context
+ Objects and hashes should be pushed onto the context stack.
+ => SUCCESS
+[4] Parent contexts
+ Names missing in the current context are looked up in the stack.
+ => SUCCESS
+[5] Variable test
+ Non-false sections have their value at the top of context,
+accessible as {{.}} or through the parent context. This gives
+a simple way to display content conditionally if a variable exists.
+
+ => SUCCESS
+[6] List Contexts
+ All elements on the context stack should be accessible within lists.
+ => SUCCESS
+[7] Deeply Nested Contexts
+ All elements on the context stack should be accessible.
+ => SUCCESS
+[8] List
+ Lists should be iterated; list items should visit the context stack.
+ => SUCCESS
+[9] Empty List
+ Empty lists should behave like falsey values.
+ => SUCCESS
+[10] Doubled
+ Multiple sections per template should be permitted.
+ => SUCCESS
+[11] Nested (Truthy)
+ Nested truthy sections should have their contents rendered.
+ => SUCCESS
+[12] Nested (Falsey)
+ Nested falsey sections should be omitted.
+ => SUCCESS
+[13] Context Misses
+ Failed context lookups should be considered falsey.
+ => SUCCESS
+[14] Implicit Iterator - String
+ Implicit iterators should directly interpolate strings.
+ => SUCCESS
+[15] Implicit Iterator - Integer
+ Implicit iterators should cast integers to strings and interpolate.
+ => SUCCESS
+[16] Implicit Iterator - Decimal
+ Implicit iterators should cast decimals to strings and interpolate.
+ => DIFFERS
+ .. DATA[{"list":[1.1000000000000001,2.2000000000000002,3.2999999999999998,4.4000000000000004,5.5]}]
+ .. TEMPLATE["{{#list}}({{.}}){{/list}}"]
+ .. EXPECTED["(1.1)(2.2)(3.3)(4.4)(5.5)"]
+ .. GOT["(1.1000000000000001)(2.2000000000000002)(3.2999999999999998)(4.4000000000000004)(5.5)"]
+[17] Implicit Iterator - Array
+ Implicit iterators should allow iterating over nested arrays.
+ => SUCCESS
+[18] Implicit Iterator - HTML Escaping
+ Implicit iterators with basic interpolation should be HTML escaped.
+ => SUCCESS
+[19] Implicit Iterator - Triple mustache
+ Implicit iterators in triple mustache should interpolate without HTML escaping.
+ => SUCCESS
+[20] Implicit Iterator - Ampersand
+ Implicit iterators in an Ampersand tag should interpolate without HTML escaping.
+ => SUCCESS
+[21] Implicit Iterator - Root-level
+ Implicit iterators should work on root-level lists.
+ => SUCCESS
+[22] Dotted Names - Truthy
+ Dotted names should be valid for Section tags.
+ => SUCCESS
+[23] Dotted Names - Falsey
+ Dotted names should be valid for Section tags.
+ => SUCCESS
+[24] Dotted Names - Broken Chains
+ Dotted names that cannot be resolved should be considered falsey.
+ => SUCCESS
+[25] Surrounding Whitespace
+ Sections should not alter surrounding whitespace.
+ => SUCCESS
+[26] Internal Whitespace
+ Sections should not alter internal whitespace.
+ => SUCCESS
+[27] Indented Inline Sections
+ Single-line sections should not alter surrounding whitespace.
+ => SUCCESS
+[28] Standalone Lines
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[29] Indented Standalone Lines
+ Indented standalone lines should be removed from the template.
+ => SUCCESS
+[30] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[31] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[32] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[33] Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+summary:
+ error 0
+ differ 1
+ success 132
diff --git a/src/templating/test-specs/test-specs-json-c.ref b/src/templating/test-specs/test-specs-json-c.ref
new file mode 100644
index 000000000..8897c66cc
--- /dev/null
+++ b/src/templating/test-specs/test-specs-json-c.ref
@@ -0,0 +1,425 @@
+
+loading test-specs/spec/specs/comments.json
+processing file test-specs/spec/specs/comments.json
+[0] Inline
+ Comment blocks should be removed from the template.
+ => SUCCESS
+[1] Multiline
+ Multiline comments should be permitted.
+ => SUCCESS
+[2] Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[3] Indented Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[4] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[5] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[6] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[7] Multiline Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[8] Indented Multiline Standalone
+ All standalone comment lines should be removed.
+ => SUCCESS
+[9] Indented Inline
+ Inline comments should not strip whitespace
+ => SUCCESS
+[10] Surrounding Whitespace
+ Comment removal should preserve surrounding whitespace.
+ => SUCCESS
+[11] Variable Name Collision
+ Comments must never render, even if variable with same name exists.
+ => SUCCESS
+
+loading test-specs/spec/specs/delimiters.json
+processing file test-specs/spec/specs/delimiters.json
+[0] Pair Behavior
+ The equals sign (used on both sides) should permit delimiter changes.
+ => SUCCESS
+[1] Special Characters
+ Characters with special meaning regexen should be valid delimiters.
+ => SUCCESS
+[2] Sections
+ Delimiters set outside sections should persist.
+ => SUCCESS
+[3] Inverted Sections
+ Delimiters set outside inverted sections should persist.
+ => SUCCESS
+[4] Partial Inheritence
+ Delimiters set in a parent template should not affect a partial.
+ => SUCCESS
+[5] Post-Partial Behavior
+ Delimiters set in a partial should not affect the parent template.
+ => SUCCESS
+[6] Surrounding Whitespace
+ Surrounding whitespace should be left untouched.
+ => SUCCESS
+[7] Outlying Whitespace (Inline)
+ Whitespace should be left untouched.
+ => SUCCESS
+[8] Standalone Tag
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[9] Indented Standalone Tag
+ Indented standalone lines should be removed from the template.
+ => SUCCESS
+[10] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[11] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[12] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[13] Pair with Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/interpolation.json
+processing file test-specs/spec/specs/interpolation.json
+[0] No Interpolation
+ Mustache-free templates should render as-is.
+ => SUCCESS
+[1] Basic Interpolation
+ Unadorned tags should interpolate content into the template.
+ => SUCCESS
+[2] HTML Escaping
+ Basic interpolation should be HTML escaped.
+ => SUCCESS
+[3] Triple Mustache
+ Triple mustaches should interpolate without HTML escaping.
+ => SUCCESS
+[4] Ampersand
+ Ampersand should interpolate without HTML escaping.
+ => SUCCESS
+[5] Basic Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[6] Triple Mustache Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[7] Ampersand Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[8] Basic Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[9] Triple Mustache Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[10] Ampersand Decimal Interpolation
+ Decimals should interpolate seamlessly with proper significance.
+ => SUCCESS
+[11] Basic Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[12] Triple Mustache Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[13] Ampersand Null Interpolation
+ Nulls should interpolate as the empty string.
+ => SUCCESS
+[14] Basic Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[15] Triple Mustache Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[16] Ampersand Context Miss Interpolation
+ Failed context lookups should default to empty strings.
+ => SUCCESS
+[17] Dotted Names - Basic Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[18] Dotted Names - Triple Mustache Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[19] Dotted Names - Ampersand Interpolation
+ Dotted names should be considered a form of shorthand for sections.
+ => SUCCESS
+[20] Dotted Names - Arbitrary Depth
+ Dotted names should be functional to any level of nesting.
+ => SUCCESS
+[21] Dotted Names - Broken Chains
+ Any falsey value prior to the last part of the name should yield ''.
+ => SUCCESS
+[22] Dotted Names - Broken Chain Resolution
+ Each part of a dotted name should resolve only against its parent.
+ => SUCCESS
+[23] Dotted Names - Initial Resolution
+ The first part of a dotted name should resolve as any other name.
+ => SUCCESS
+[24] Dotted Names - Context Precedence
+ Dotted names should be resolved against former resolutions.
+ => SUCCESS
+[25] Implicit Iterators - Basic Interpolation
+ Unadorned tags should interpolate content into the template.
+ => SUCCESS
+[26] Implicit Iterators - HTML Escaping
+ Basic interpolation should be HTML escaped.
+ => SUCCESS
+[27] Implicit Iterators - Triple Mustache
+ Triple mustaches should interpolate without HTML escaping.
+ => SUCCESS
+[28] Implicit Iterators - Ampersand
+ Ampersand should interpolate without HTML escaping.
+ => SUCCESS
+[29] Implicit Iterators - Basic Integer Interpolation
+ Integers should interpolate seamlessly.
+ => SUCCESS
+[30] Interpolation - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[31] Triple Mustache - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[32] Ampersand - Surrounding Whitespace
+ Interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[33] Interpolation - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[34] Triple Mustache - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[35] Ampersand - Standalone
+ Standalone interpolation should not alter surrounding whitespace.
+ => SUCCESS
+[36] Interpolation With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+[37] Triple Mustache With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+[38] Ampersand With Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/inverted.json
+processing file test-specs/spec/specs/inverted.json
+[0] Falsey
+ Falsey sections should have their contents rendered.
+ => SUCCESS
+[1] Truthy
+ Truthy sections should have their contents omitted.
+ => SUCCESS
+[2] Null is falsey
+ Null is falsey.
+ => SUCCESS
+[3] Context
+ Objects and hashes should behave like truthy values.
+ => SUCCESS
+[4] List
+ Lists should behave like truthy values.
+ => SUCCESS
+[5] Empty List
+ Empty lists should behave like falsey values.
+ => SUCCESS
+[6] Doubled
+ Multiple inverted sections per template should be permitted.
+ => SUCCESS
+[7] Nested (Falsey)
+ Nested falsey sections should have their contents rendered.
+ => SUCCESS
+[8] Nested (Truthy)
+ Nested truthy sections should be omitted.
+ => SUCCESS
+[9] Context Misses
+ Failed context lookups should be considered falsey.
+ => SUCCESS
+[10] Dotted Names - Truthy
+ Dotted names should be valid for Inverted Section tags.
+ => SUCCESS
+[11] Dotted Names - Falsey
+ Dotted names should be valid for Inverted Section tags.
+ => SUCCESS
+[12] Dotted Names - Broken Chains
+ Dotted names that cannot be resolved should be considered falsey.
+ => SUCCESS
+[13] Surrounding Whitespace
+ Inverted sections should not alter surrounding whitespace.
+ => SUCCESS
+[14] Internal Whitespace
+ Inverted should not alter internal whitespace.
+ => SUCCESS
+[15] Indented Inline Sections
+ Single-line sections should not alter surrounding whitespace.
+ => SUCCESS
+[16] Standalone Lines
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[17] Standalone Indented Lines
+ Standalone indented lines should be removed from the template.
+ => SUCCESS
+[18] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[19] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[20] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[21] Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/partials.json
+processing file test-specs/spec/specs/partials.json
+[0] Basic Behavior
+ The greater-than operator should expand to the named partial.
+ => SUCCESS
+[1] Failed Lookup
+ The empty string should be used when the named partial is not found.
+ => SUCCESS
+[2] Context
+ The greater-than operator should operate within the current context.
+ => SUCCESS
+[3] Recursion
+ The greater-than operator should properly recurse.
+ => SUCCESS
+[4] Nested
+ The greater-than operator should work from within partials.
+ => SUCCESS
+[5] Surrounding Whitespace
+ The greater-than operator should not alter surrounding whitespace.
+ => SUCCESS
+[6] Inline Indentation
+ Whitespace should be left untouched.
+ => SUCCESS
+[7] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[8] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[9] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[10] Standalone Indentation
+ Each line of the partial should be indented before rendering.
+ => SUCCESS
+[11] Padding Whitespace
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+loading test-specs/spec/specs/sections.json
+processing file test-specs/spec/specs/sections.json
+[0] Truthy
+ Truthy sections should have their contents rendered.
+ => SUCCESS
+[1] Falsey
+ Falsey sections should have their contents omitted.
+ => SUCCESS
+[2] Null is falsey
+ Null is falsey.
+ => SUCCESS
+[3] Context
+ Objects and hashes should be pushed onto the context stack.
+ => SUCCESS
+[4] Parent contexts
+ Names missing in the current context are looked up in the stack.
+ => SUCCESS
+[5] Variable test
+ Non-false sections have their value at the top of context,
+accessible as {{.}} or through the parent context. This gives
+a simple way to display content conditionally if a variable exists.
+
+ => SUCCESS
+[6] List Contexts
+ All elements on the context stack should be accessible within lists.
+ => SUCCESS
+[7] Deeply Nested Contexts
+ All elements on the context stack should be accessible.
+ => SUCCESS
+[8] List
+ Lists should be iterated; list items should visit the context stack.
+ => SUCCESS
+[9] Empty List
+ Empty lists should behave like falsey values.
+ => SUCCESS
+[10] Doubled
+ Multiple sections per template should be permitted.
+ => SUCCESS
+[11] Nested (Truthy)
+ Nested truthy sections should have their contents rendered.
+ => SUCCESS
+[12] Nested (Falsey)
+ Nested falsey sections should be omitted.
+ => SUCCESS
+[13] Context Misses
+ Failed context lookups should be considered falsey.
+ => SUCCESS
+[14] Implicit Iterator - String
+ Implicit iterators should directly interpolate strings.
+ => SUCCESS
+[15] Implicit Iterator - Integer
+ Implicit iterators should cast integers to strings and interpolate.
+ => SUCCESS
+[16] Implicit Iterator - Decimal
+ Implicit iterators should cast decimals to strings and interpolate.
+ => SUCCESS
+[17] Implicit Iterator - Array
+ Implicit iterators should allow iterating over nested arrays.
+ => SUCCESS
+[18] Implicit Iterator - HTML Escaping
+ Implicit iterators with basic interpolation should be HTML escaped.
+ => SUCCESS
+[19] Implicit Iterator - Triple mustache
+ Implicit iterators in triple mustache should interpolate without HTML escaping.
+ => SUCCESS
+[20] Implicit Iterator - Ampersand
+ Implicit iterators in an Ampersand tag should interpolate without HTML escaping.
+ => SUCCESS
+[21] Implicit Iterator - Root-level
+ Implicit iterators should work on root-level lists.
+ => SUCCESS
+[22] Dotted Names - Truthy
+ Dotted names should be valid for Section tags.
+ => SUCCESS
+[23] Dotted Names - Falsey
+ Dotted names should be valid for Section tags.
+ => SUCCESS
+[24] Dotted Names - Broken Chains
+ Dotted names that cannot be resolved should be considered falsey.
+ => SUCCESS
+[25] Surrounding Whitespace
+ Sections should not alter surrounding whitespace.
+ => SUCCESS
+[26] Internal Whitespace
+ Sections should not alter internal whitespace.
+ => SUCCESS
+[27] Indented Inline Sections
+ Single-line sections should not alter surrounding whitespace.
+ => SUCCESS
+[28] Standalone Lines
+ Standalone lines should be removed from the template.
+ => SUCCESS
+[29] Indented Standalone Lines
+ Indented standalone lines should be removed from the template.
+ => SUCCESS
+[30] Standalone Line Endings
+ "\r\n" should be considered a newline for standalone tags.
+ => SUCCESS
+[31] Standalone Without Previous Line
+ Standalone tags should not require a newline to precede them.
+ => SUCCESS
+[32] Standalone Without Newline
+ Standalone tags should not require a newline to follow them.
+ => SUCCESS
+[33] Padding
+ Superfluous in-tag whitespace should be ignored.
+ => SUCCESS
+
+summary:
+ error 0
+ differ 0
+ success 133
diff --git a/src/templating/test-specs/test-specs.c b/src/templating/test-specs/test-specs.c
new file mode 100644
index 000000000..15c94a80e
--- /dev/null
+++ b/src/templating/test-specs/test-specs.c
@@ -0,0 +1,520 @@
+/*
+ Author: José Bollo <jobol@nonadev.net>
+
+ https://gitlab.com/jobol/mustach
+
+ SPDX-License-Identifier: ISC
+*/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "mustach-wrap.h"
+
+#define TEST_JSON_C 1
+#define TEST_JANSSON 2
+#define TEST_CJSON 3
+
+static const char *errors[] = {
+ "??? unreferenced ???",
+ "system",
+ "unexpected end",
+ "empty tag",
+ "tag too long",
+ "bad separators",
+ "too depth",
+ "closing",
+ "bad unescape tag",
+ "invalid interface",
+ "item not found",
+ "partial not found"
+};
+
+const char *mustach_error_string(int status)
+{
+ return status >= 0 ? "no error"
+ : errors[status <= -(int)(sizeof errors / sizeof * errors) ? 0 : -status];
+}
+
+static const char *errmsg = 0;
+static int flags = 0;
+static FILE *output = 0;
+
+static void help(char *prog)
+{
+ char *name = basename(prog);
+#define STR(x) #x
+ printf("%s version %s\n", name, STR(VERSION));
+#undef STR
+ printf("usage: %s test-files...\n", name);
+ exit(0);
+}
+
+#if TEST == TEST_CJSON
+
+static const size_t BLOCKSIZE = 8192;
+
+static char *readfile(const char *filename, size_t *length)
+{
+ int f;
+ struct stat s;
+ char *result;
+ size_t size, pos;
+ ssize_t rc;
+
+ result = NULL;
+ if (filename[0] == '-' && filename[1] == 0)
+ f = dup(0);
+ else
+ f = open(filename, O_RDONLY);
+ if (f < 0) {
+ fprintf(stderr, "Can't open file: %s\n", filename);
+ exit(1);
+ }
+
+ fstat(f, &s);
+ switch (s.st_mode & S_IFMT) {
+ case S_IFREG:
+ size = s.st_size;
+ break;
+ case S_IFSOCK:
+ case S_IFIFO:
+ size = BLOCKSIZE;
+ break;
+ default:
+ fprintf(stderr, "Bad file: %s\n", filename);
+ exit(1);
+ }
+
+ pos = 0;
+ result = malloc(size + 1);
+ do {
+ if (result == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ rc = read(f, &result[pos], (size - pos) + 1);
+ if (rc < 0) {
+ fprintf(stderr, "Error while reading %s\n", filename);
+ exit(1);
+ }
+ if (rc > 0) {
+ pos += (size_t)rc;
+ if (pos > size) {
+ size = pos + BLOCKSIZE;
+ result = realloc(result, size + 1);
+ }
+ }
+ } while(rc > 0);
+
+ close(f);
+ if (length != NULL)
+ *length = pos;
+ result[pos] = 0;
+ return result;
+}
+#endif
+
+typedef struct {
+ unsigned nerror;
+ unsigned ndiffers;
+ unsigned nsuccess;
+ unsigned ninvalid;
+} counters;
+
+static int load_json(const char *filename);
+static int process(counters *c);
+static void close_json();
+static int get_partial(const char *name, struct mustach_sbuf *sbuf);
+
+int main(int ac, char **av)
+{
+ char *f;
+ char *prog = *av;
+ int s;
+ counters c;
+
+ (void)ac; /* unused */
+ flags = Mustach_With_SingleDot | Mustach_With_IncPartial;
+ output = stdout;
+ mustach_wrap_get_partial = get_partial;
+
+ memset(&c, 0, sizeof c);
+ while (*++av) {
+ if (!strcmp(*av, "-h") || !strcmp(*av, "--help"))
+ help(prog);
+ f = (av[0][0] == '-' && !av[0][1]) ? "/dev/stdin" : av[0];
+ fprintf(output, "\nloading %s\n", f);
+ s = load_json(f);
+ if (s < 0) {
+ fprintf(stderr, "error when loading %s!\n", f);
+ if(errmsg)
+ fprintf(stderr, " reason: %s\n", errmsg);
+ exit(1);
+ }
+ fprintf(output, "processing file %s\n", f);
+ s = process(&c);
+ if (s < 0) {
+ fprintf(stderr, "error bad test file %s!\n", f);
+ exit(1);
+ }
+ close_json();
+ }
+ fprintf(output, "\nsummary:\n");
+ if (c.ninvalid)
+ fprintf(output, " invalid %u\n", c.ninvalid);
+ fprintf(output, " error %u\n", c.nerror);
+ fprintf(output, " differ %u\n", c.ndiffers);
+ fprintf(output, " success %u\n", c.nsuccess);
+ if (c.nerror)
+ return 2;
+ if (c.ndiffers)
+ return 1;
+ return 0;
+}
+
+void emit(FILE *f, const char *s)
+{
+ for(;;s++) {
+ switch(*s) {
+ case 0: return;
+ case '\\': fprintf(f, "\\\\"); break;
+ case '\t': fprintf(f, "\\t"); break;
+ case '\n': fprintf(f, "\\n"); break;
+ case '\r': fprintf(f, "\\r"); break;
+ default: fprintf(f, "%c", *s); break;
+ }
+ }
+}
+
+#if TEST == TEST_JSON_C
+
+#include "mustach-json-c.h"
+
+static struct json_object *o;
+
+static struct json_object *partials;
+static int get_partial(const char *name, struct mustach_sbuf *sbuf)
+{
+ struct json_object *x;
+ if (partials == NULL || !json_object_object_get_ex(partials, name, &x))
+ return MUSTACH_ERROR_PARTIAL_NOT_FOUND;
+ sbuf->value = json_object_get_string(x);
+ return MUSTACH_OK;
+}
+
+static int load_json(const char *filename)
+{
+ o = json_object_from_file(filename);
+#if JSON_C_VERSION_NUM >= 0x000D00
+ errmsg = json_util_get_last_err();
+ if (errmsg != NULL)
+ return -1;
+#endif
+ if (o == NULL) {
+ errmsg = "null json";
+ return -1;
+ }
+ return 0;
+}
+static int process(counters *c)
+{
+ const char *t, *e;
+ char *got;
+ unsigned i, n;
+ size_t length;
+ int s;
+ json_object *tests, *unit, *name, *desc, *data, *template, *expected;
+
+ if (!json_object_object_get_ex(o, "tests", &tests) || json_object_get_type(tests) != json_type_array)
+ return -1;
+
+ i = 0;
+ n = (unsigned)json_object_array_length(tests);
+ while (i < n) {
+ unit = json_object_array_get_idx(tests, i);
+ if (json_object_get_type(unit) != json_type_object
+ || !json_object_object_get_ex(unit, "name", &name)
+ || !json_object_object_get_ex(unit, "desc", &desc)
+ || !json_object_object_get_ex(unit, "data", &data)
+ || !json_object_object_get_ex(unit, "template", &template)
+ || !json_object_object_get_ex(unit, "expected", &expected)
+ || json_object_get_type(name) != json_type_string
+ || json_object_get_type(desc) != json_type_string
+ || json_object_get_type(template) != json_type_string
+ || json_object_get_type(expected) != json_type_string) {
+ fprintf(stderr, "invalid test %u\n", i);
+ c->ninvalid++;
+ }
+ else {
+ fprintf(output, "[%u] %s\n", i, json_object_get_string(name));
+ fprintf(output, "\t%s\n", json_object_get_string(desc));
+ if (!json_object_object_get_ex(unit, "partials", &partials))
+ partials = NULL;
+ t = json_object_get_string(template);
+ e = json_object_get_string(expected);
+ s = mustach_json_c_mem(t, 0, data, flags, &got, &length);
+ if (s == 0 && strcmp(got, e) == 0) {
+ fprintf(output, "\t=> SUCCESS\n");
+ c->nsuccess++;
+ }
+ else {
+ if (s < 0) {
+ fprintf(output, "\t=> ERROR %s\n", mustach_error_string(s));
+ c->nerror++;
+ }
+ else {
+ fprintf(output, "\t=> DIFFERS\n");
+ c->ndiffers++;
+ }
+ if (partials)
+ fprintf(output, "\t.. PARTIALS[%s]\n", json_object_to_json_string_ext(partials, 0));
+ fprintf(output, "\t.. DATA[%s]\n", json_object_to_json_string_ext(data, 0));
+ fprintf(output, "\t.. TEMPLATE[");
+ emit(output, t);
+ fprintf(output, "]\n");
+ fprintf(output, "\t.. EXPECTED[");
+ emit(output, e);
+ fprintf(output, "]\n");
+ if (s == 0) {
+ fprintf(output, "\t.. GOT[");
+ emit(output, got);
+ fprintf(output, "]\n");
+ }
+ }
+ free(got);
+ }
+ i++;
+ }
+ return 0;
+}
+static void close_json()
+{
+ json_object_put(o);
+}
+
+#elif TEST == TEST_JANSSON
+
+#include "mustach-jansson.h"
+
+static json_t *o;
+static json_error_t e;
+
+static json_t *partials;
+static int get_partial(const char *name, struct mustach_sbuf *sbuf)
+{
+ json_t *x;
+ if (partials == NULL || !(x = json_object_get(partials, name)))
+ return MUSTACH_ERROR_PARTIAL_NOT_FOUND;
+ sbuf->value = json_string_value(x);
+ return MUSTACH_OK;
+}
+
+static int load_json(const char *filename)
+{
+ o = json_load_file(filename, JSON_DECODE_ANY, &e);
+ if (o == NULL) {
+ errmsg = e.text;
+ return -1;
+ }
+ return 0;
+}
+static int process(counters *c)
+{
+ const char *t, *e;
+ char *got, *tmp;
+ int i, n;
+ size_t length;
+ int s;
+ json_t *tests, *unit, *name, *desc, *data, *template, *expected;
+
+ tests = json_object_get(o, "tests");
+ if (!tests || json_typeof(tests) != JSON_ARRAY)
+ return -1;
+
+ i = 0;
+ n = json_array_size(tests);
+ while (i < n) {
+ unit = json_array_get(tests, i);
+ if (!unit || json_typeof(unit) != JSON_OBJECT
+ || !(name = json_object_get(unit, "name"))
+ || !(desc = json_object_get(unit, "desc"))
+ || !(data = json_object_get(unit, "data"))
+ || !(template = json_object_get(unit, "template"))
+ || !(expected = json_object_get(unit, "expected"))
+ || json_typeof(name) != JSON_STRING
+ || json_typeof(desc) != JSON_STRING
+ || json_typeof(template) != JSON_STRING
+ || json_typeof(expected) != JSON_STRING) {
+ fprintf(stderr, "invalid test %u\n", i);
+ c->ninvalid++;
+ }
+ else {
+ fprintf(output, "[%u] %s\n", i, json_string_value(name));
+ fprintf(output, "\t%s\n", json_string_value(desc));
+ partials = json_object_get(unit, "partials");
+ t = json_string_value(template);
+ e = json_string_value(expected);
+ s = mustach_jansson_mem(t, 0, data, flags, &got, &length);
+ if (s == 0 && strcmp(got, e) == 0) {
+ fprintf(output, "\t=> SUCCESS\n");
+ c->nsuccess++;
+ }
+ else {
+ if (s < 0) {
+ fprintf(output, "\t=> ERROR %s\n", mustach_error_string(s));
+ c->nerror++;
+ }
+ else {
+ fprintf(output, "\t=> DIFFERS\n");
+ c->ndiffers++;
+ }
+ if (partials) {
+ tmp = json_dumps(partials, JSON_ENCODE_ANY | JSON_COMPACT);
+ fprintf(output, "\t.. PARTIALS[%s]\n", tmp);
+ free(tmp);
+ }
+ tmp = json_dumps(data, JSON_ENCODE_ANY | JSON_COMPACT);
+ fprintf(output, "\t.. DATA[%s]\n", tmp);
+ free(tmp);
+ fprintf(output, "\t.. TEMPLATE[");
+ emit(output, t);
+ fprintf(output, "]\n");
+ fprintf(output, "\t.. EXPECTED[");
+ emit(output, e);
+ fprintf(output, "]\n");
+ if (s == 0) {
+ fprintf(output, "\t.. GOT[");
+ emit(output, got);
+ fprintf(output, "]\n");
+ }
+ }
+ free(got);
+ }
+ i++;
+ }
+ return 0;
+}
+static void close_json()
+{
+ json_decref(o);
+}
+
+#elif TEST == TEST_CJSON
+
+#include "mustach-cjson.h"
+
+static cJSON *o;
+static cJSON *partials;
+static int get_partial(const char *name, struct mustach_sbuf *sbuf)
+{
+ cJSON *x;
+ if (partials == NULL || !(x = cJSON_GetObjectItemCaseSensitive(partials, name)))
+ return MUSTACH_ERROR_PARTIAL_NOT_FOUND;
+ sbuf->value = x->valuestring;
+ return MUSTACH_OK;
+}
+
+static int load_json(const char *filename)
+{
+ char *t;
+ size_t length;
+
+ t = readfile(filename, &length);
+ o = t ? cJSON_ParseWithLength(t, length) : NULL;
+ free(t);
+ return -!o;
+}
+static int process(counters *c)
+{
+ const char *t, *e;
+ char *got, *tmp;
+ int i, n;
+ size_t length;
+ int s;
+ cJSON *tests, *unit, *name, *desc, *data, *template, *expected;
+
+ tests = cJSON_GetObjectItemCaseSensitive(o, "tests");
+ if (!tests || tests->type != cJSON_Array)
+ return -1;
+
+ i = 0;
+ n = cJSON_GetArraySize(tests);
+ while (i < n) {
+ unit = cJSON_GetArrayItem(tests, i);
+ if (!unit || unit->type != cJSON_Object
+ || !(name = cJSON_GetObjectItemCaseSensitive(unit, "name"))
+ || !(desc = cJSON_GetObjectItemCaseSensitive(unit, "desc"))
+ || !(data = cJSON_GetObjectItemCaseSensitive(unit, "data"))
+ || !(template = cJSON_GetObjectItemCaseSensitive(unit, "template"))
+ || !(expected = cJSON_GetObjectItemCaseSensitive(unit, "expected"))
+ || name->type != cJSON_String
+ || desc->type != cJSON_String
+ || template->type != cJSON_String
+ || expected->type != cJSON_String) {
+ fprintf(stderr, "invalid test %u\n", i);
+ c->ninvalid++;
+ }
+ else {
+ fprintf(output, "[%u] %s\n", i, name->valuestring);
+ fprintf(output, "\t%s\n", desc->valuestring);
+ partials = cJSON_GetObjectItemCaseSensitive(unit, "partials");
+ t = template->valuestring;
+ e = expected->valuestring;
+ s = mustach_cJSON_mem(t, 0, data, flags, &got, &length);
+ if (s == 0 && strcmp(got, e) == 0) {
+ fprintf(output, "\t=> SUCCESS\n");
+ c->nsuccess++;
+ }
+ else {
+ if (s < 0) {
+ fprintf(output, "\t=> ERROR %s\n", mustach_error_string(s));
+ c->nerror++;
+ }
+ else {
+ fprintf(output, "\t=> DIFFERS\n");
+ c->ndiffers++;
+ }
+ if (partials) {
+ tmp = cJSON_PrintUnformatted(partials);
+ fprintf(output, "\t.. PARTIALS[%s]\n", tmp);
+ free(tmp);
+ }
+ tmp = cJSON_PrintUnformatted(data);
+ fprintf(output, "\t.. DATA[%s]\n", tmp);
+ free(tmp);
+ fprintf(output, "\t.. TEMPLATE[");
+ emit(output, t);
+ fprintf(output, "]\n");
+ fprintf(output, "\t.. EXPECTED[");
+ emit(output, e);
+ fprintf(output, "]\n");
+ if (s == 0) {
+ fprintf(output, "\t.. GOT[");
+ emit(output, got);
+ fprintf(output, "]\n");
+ }
+ }
+ free(got);
+ }
+ i++;
+ }
+ return 0;
+}
+static void close_json()
+{
+ cJSON_Delete(o);
+}
+
+#else
+#error "no defined json library"
+#endif
diff --git a/src/templating/test1/Makefile b/src/templating/test1/Makefile
index bb96b3502..1a3e57914 100644
--- a/src/templating/test1/Makefile
+++ b/src/templating/test1/Makefile
@@ -1,12 +1,7 @@
.PHONY: test clean
test:
- @echo starting test
- @../mustach json must > resu.last 2> vg.last
- @sed -i 's:^==[0-9]*== ::' vg.last
- @diff -w resu.ref resu.last && echo "result ok" || echo "ERROR! Result differs"
- @awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
- @echo
+ @../dotest.sh json must
clean:
rm -f resu.last vg.last
diff --git a/src/templating/test1/must b/src/templating/test1/must
index 6df523669..92d30b0b2 100644
--- a/src/templating/test1/must
+++ b/src/templating/test1/must
@@ -41,3 +41,9 @@ end
{{:\=equal}}
{{::colon}}
{{:>greater}}
+
+{{#repo}}
+who 0 {{who.0}}
+who 1 {{who.1}}
+who 2 {{who.2}}
+{{/repo}}
diff --git a/src/templating/test1/resu.ref b/src/templating/test1/resu.ref
new file mode 100644
index 000000000..6cd11bb27
--- /dev/null
+++ b/src/templating/test1/resu.ref
@@ -0,0 +1,41 @@
+Hello Chris
+You have just won 10000 dollars!
+Well, 6000 dollars, after taxes.
+Shown.
+ No person
+
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+
+ Hi Jon!
+
+=====================================
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+=====================================
+ggggggggg
+----3.14159----
+jjjjjjjjj
+end
+
+#
+!
+~
+~
+/ see json pointers IETF RFC 6901
+^
+=
+:
+&gt;
+
+who 0 {&quot;commiter&quot;:&quot;joe&quot;}
+who 1 {&quot;reviewer&quot;:&quot;avrel&quot;}
+who 2 {&quot;commiter&quot;:&quot;william&quot;}
+who 0 {&quot;commiter&quot;:&quot;jack&quot;}
+who 1 {&quot;reviewer&quot;:&quot;avrel&quot;}
+who 2 {&quot;commiter&quot;:&quot;greg&quot;}
+who 0 {&quot;reviewer&quot;:&quot;joe&quot;}
+who 1 {&quot;reviewer&quot;:&quot;jack&quot;}
+who 2 {&quot;commiter&quot;:&quot;greg&quot;}
diff --git a/src/templating/test1/vg.ref b/src/templating/test1/vg.ref
new file mode 100644
index 000000000..d086e59c5
--- /dev/null
+++ b/src/templating/test1/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 111 allocs, 111 frees, 9,702 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test2/Makefile b/src/templating/test2/Makefile
index bb96b3502..1a3e57914 100644
--- a/src/templating/test2/Makefile
+++ b/src/templating/test2/Makefile
@@ -1,12 +1,7 @@
.PHONY: test clean
test:
- @echo starting test
- @../mustach json must > resu.last 2> vg.last
- @sed -i 's:^==[0-9]*== ::' vg.last
- @diff -w resu.ref resu.last && echo "result ok" || echo "ERROR! Result differs"
- @awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
- @echo
+ @../dotest.sh json must
clean:
rm -f resu.last vg.last
diff --git a/src/templating/test2/resu.ref b/src/templating/test2/resu.ref
new file mode 100644
index 000000000..5a200a9bf
--- /dev/null
+++ b/src/templating/test2/resu.ref
@@ -0,0 +1,7 @@
+<h1>Colors</h1>
+
+ <li><strong>red</strong></li>
+ <li><a href="#Green">green</a></li>
+ <li><a href="#Blue">blue</a></li>
+
+
diff --git a/src/templating/test2/vg.ref b/src/templating/test2/vg.ref
new file mode 100644
index 000000000..e4b4f6d37
--- /dev/null
+++ b/src/templating/test2/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 38 allocs, 38 frees, 5,712 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test3/Makefile b/src/templating/test3/Makefile
index bb96b3502..1a3e57914 100644
--- a/src/templating/test3/Makefile
+++ b/src/templating/test3/Makefile
@@ -1,12 +1,7 @@
.PHONY: test clean
test:
- @echo starting test
- @../mustach json must > resu.last 2> vg.last
- @sed -i 's:^==[0-9]*== ::' vg.last
- @diff -w resu.ref resu.last && echo "result ok" || echo "ERROR! Result differs"
- @awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
- @echo
+ @../dotest.sh json must
clean:
rm -f resu.last vg.last
diff --git a/src/templating/test3/resu.ref b/src/templating/test3/resu.ref
new file mode 100644
index 000000000..ee6dad3fb
--- /dev/null
+++ b/src/templating/test3/resu.ref
@@ -0,0 +1,13 @@
+* Chris
+* 18
+* &lt;b&gt;GitHub &amp; Co&lt;/b&gt;
+* <b>GitHub & Co</b>
+* <b>GitHub & Co</b>
+* &lt;b&gt;GitHub &amp; Co&lt;/b&gt;
+* <b>GitHub & Co</b>
+* <b>GitHub & Co</b>
+
+* <ul><li>Chris</li><li>Kross</li></ul>
+* skills: <ul><li>JavaScript</li><li>PHP</li><li>Java</li></ul>
+* age: 18
+
diff --git a/src/templating/test3/vg.ref b/src/templating/test3/vg.ref
new file mode 100644
index 000000000..21f7931eb
--- /dev/null
+++ b/src/templating/test3/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 30 allocs, 30 frees, 5,831 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test4/Makefile b/src/templating/test4/Makefile
index bb96b3502..1a3e57914 100644
--- a/src/templating/test4/Makefile
+++ b/src/templating/test4/Makefile
@@ -1,12 +1,7 @@
.PHONY: test clean
test:
- @echo starting test
- @../mustach json must > resu.last 2> vg.last
- @sed -i 's:^==[0-9]*== ::' vg.last
- @diff -w resu.ref resu.last && echo "result ok" || echo "ERROR! Result differs"
- @awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
- @echo
+ @../dotest.sh json must
clean:
rm -f resu.last vg.last
diff --git a/src/templating/test4/resu.ref b/src/templating/test4/resu.ref
new file mode 100644
index 000000000..8a71c4e82
--- /dev/null
+++ b/src/templating/test4/resu.ref
@@ -0,0 +1,50 @@
+This are extensions!!
+
+Jon
+25
+
+Fred
+The other Fred.
+
+Hello Jon
+
+
+No Harry? Hey Calahan...
+
+Hello Fred
+
+
+Hello Fred#2
+
+
+Hello Jon, 25 years
+
+Hello Henry, 27 years
+
+
+Salut Amed, 24 ans
+
+Jon: /25/25
+Henry: /27/
+Amed: 24/24/24
+
+Jon: /25/25
+Henry: /27/
+Amed: 24/24/24
+
+ (1) person: {&quot;name&quot;:&quot;Jon&quot;,&quot;age&quot;:25}
+ (2) name: Jon
+ (2) age: 25
+ (1) person.name: Fred
+ (1) person.name=Fred: The other Fred.
+ (1) persons: [{&quot;name&quot;:&quot;Jon&quot;,&quot;age&quot;:25,&quot;lang&quot;:&quot;en&quot;},{&quot;name&quot;:&quot;Henry&quot;,&quot;age&quot;:27,&quot;lang&quot;:&quot;en&quot;},{&quot;name&quot;:&quot;Amed&quot;,&quot;age&quot;:24,&quot;lang&quot;:&quot;fr&quot;}]
+ (1) fellows: {&quot;Jon&quot;:{&quot;age&quot;:25,&quot;lang&quot;:&quot;en&quot;},&quot;Henry&quot;:{&quot;age&quot;:27,&quot;lang&quot;:&quot;en&quot;},&quot;Amed&quot;:{&quot;age&quot;:24,&quot;lang&quot;:&quot;fr&quot;}}
+ (2) Jon: {&quot;age&quot;:25,&quot;lang&quot;:&quot;en&quot;}
+ (3) age: 25
+ (3) lang: en
+ (2) Henry: {&quot;age&quot;:27,&quot;lang&quot;:&quot;en&quot;}
+ (3) age: 27
+ (3) lang: en
+ (2) Amed: {&quot;age&quot;:24,&quot;lang&quot;:&quot;fr&quot;}
+ (3) age: 24
+ (3) lang: fr
diff --git a/src/templating/test4/vg.ref b/src/templating/test4/vg.ref
new file mode 100644
index 000000000..922b0676d
--- /dev/null
+++ b/src/templating/test4/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 121 allocs, 121 frees, 14,608 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test5/Makefile b/src/templating/test5/Makefile
index bb96b3502..1a3e57914 100644
--- a/src/templating/test5/Makefile
+++ b/src/templating/test5/Makefile
@@ -1,12 +1,7 @@
.PHONY: test clean
test:
- @echo starting test
- @../mustach json must > resu.last 2> vg.last
- @sed -i 's:^==[0-9]*== ::' vg.last
- @diff -w resu.ref resu.last && echo "result ok" || echo "ERROR! Result differs"
- @awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
- @echo
+ @../dotest.sh json must
clean:
rm -f resu.last vg.last
diff --git a/src/templating/test5/resu.ref b/src/templating/test5/resu.ref
new file mode 100644
index 000000000..f2a608568
--- /dev/null
+++ b/src/templating/test5/resu.ref
@@ -0,0 +1,38 @@
+=====================================
+from json
+----3.14159----
+=====================================
+not found
+=====================================
+without extension first
+must2 == BEGIN
+Hello Chris
+You have just won 10000 dollars!
+Well, 6000 dollars, after taxes.
+Shown.
+ No person
+must2 == END
+=====================================
+last with extension
+must3.mustache == BEGIN
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+
+ Hi Jon!
+
+=====================================
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+=====================================
+must3.mustache == END
+=====================================
+Ensure must3 didn't change specials
+
+ Hi Jon!
+
+%(%#person?%)%
+ Hi %(%name%)%!
+%(%/person?%)%
+
diff --git a/src/templating/test5/vg.ref b/src/templating/test5/vg.ref
new file mode 100644
index 000000000..89dc21bcb
--- /dev/null
+++ b/src/templating/test5/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 123 allocs, 123 frees, 20,610 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test6/Makefile b/src/templating/test6/Makefile
index 6178902c0..ea4f86e79 100644
--- a/src/templating/test6/Makefile
+++ b/src/templating/test6/Makefile
@@ -5,12 +5,7 @@ test-custom-write: test-custom-write.c ../mustach-json-c.h ../mustach-json-c.c .
$(CC) $(CFLAGS) $(LDFLAGS) -g -o test-custom-write test-custom-write.c ../mustach.c ../mustach-json-c.c ../mustach-wrap.c -ljson-c
test: test-custom-write
- @echo starting test
- @./test-custom-write json -U must -l must -x must > resu.last 2> vg.last
- @sed -i 's:^==[0-9]*== ::' vg.last
- @diff -w resu.ref resu.last && echo "result ok" || echo "ERROR! Result differs"
- @awk '/^ *total heap usage: .* allocs, .* frees,.*/{if($$4-$$6)exit(1)}' vg.last || echo "ERROR! Alloc/Free issue"
- @echo
+ @mustach=./test-custom-write ../dotest.sh json -U must -l must -x must
clean:
rm -f resu.last vg.last test-custom-write
diff --git a/src/templating/test6/resu.ref b/src/templating/test6/resu.ref
new file mode 100644
index 000000000..377eb11af
--- /dev/null
+++ b/src/templating/test6/resu.ref
@@ -0,0 +1,93 @@
+HELLO CHRIS
+YOU HAVE JUST WON 10000 DOLLARS!
+WELL, 6000 DOLLARS, AFTER TAXES.
+SHOWN.
+ NO PERSON
+
+ <B>RESQUE</B> REVIEWERS: AVREL COMMITERS: JOE WILLIAM
+ <B>HUB</B> REVIEWERS: AVREL COMMITERS: JACK GREG
+ <B>RIP</B> REVIEWERS: JOE JACK COMMITERS: GREG
+
+ HI JON!
+
+=====================================
+ <B>RESQUE</B> REVIEWERS: AVREL COMMITERS: JOE WILLIAM
+ <B>HUB</B> REVIEWERS: AVREL COMMITERS: JACK GREG
+ <B>RIP</B> REVIEWERS: JOE JACK COMMITERS: GREG
+=====================================
+GGGGGGGGG
+----3.14159----
+JJJJJJJJJ
+END
+
+#
+!
+~
+~
+/ SEE JSON POINTERS IETF RFC 6901
+^
+=
+:
+&GT;
+hello chris
+you have just won 10000 dollars!
+well, 6000 dollars, after taxes.
+shown.
+ no person
+
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+
+ hi jon!
+
+=====================================
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+=====================================
+ggggggggg
+----3.14159----
+jjjjjjjjj
+end
+
+#
+!
+~
+~
+/ see json pointers ietf rfc 6901
+^
+=
+:
+&gt;
+Hello Chris
+You have just won 10000 dollars!
+Well, 6000 dollars, after taxes.
+Shown.
+ No person
+
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+
+ Hi Jon!
+
+=====================================
+ <b>resque</b> reviewers: avrel commiters: joe william
+ <b>hub</b> reviewers: avrel commiters: jack greg
+ <b>rip</b> reviewers: joe jack commiters: greg
+=====================================
+ggggggggg
+----3.14159----
+jjjjjjjjj
+end
+
+#
+!
+~
+~
+/ see json pointers IETF RFC 6901
+^
+=
+:
+&gt;
diff --git a/src/templating/test6/test-custom-write.c b/src/templating/test6/test-custom-write.c
index 4ba953a85..20042c1ed 100644
--- a/src/templating/test6/test-custom-write.c
+++ b/src/templating/test6/test-custom-write.c
@@ -16,7 +16,9 @@
limitations under the License.
*/
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdlib.h>
#include <stdio.h>
diff --git a/src/templating/test6/vg.ref b/src/templating/test6/vg.ref
new file mode 100644
index 000000000..fb0e31bd8
--- /dev/null
+++ b/src/templating/test6/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ./test-custom-write json -U must -l must -x must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 174 allocs, 174 frees, 24,250 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test7/base.mustache b/src/templating/test7/base.mustache
new file mode 100644
index 000000000..f701e0c65
--- /dev/null
+++ b/src/templating/test7/base.mustache
@@ -0,0 +1,2 @@
+family:
+{{> node}}
diff --git a/src/templating/test7/json b/src/templating/test7/json
new file mode 100644
index 000000000..c9ee47150
--- /dev/null
+++ b/src/templating/test7/json
@@ -0,0 +1,8 @@
+{ "data": "grandparent", "children": [
+ { "data": "parent", "children": [
+ { "data": "child", "children": [] }
+ ]},
+ { "data": "parent2", "children": [
+ { "data": "child2", "children": [ { "data": "pet", "children": false } ]}
+ ]}
+]}
diff --git a/src/templating/test7/node.mustache b/src/templating/test7/node.mustache
new file mode 100644
index 000000000..4154b12ba
--- /dev/null
+++ b/src/templating/test7/node.mustache
@@ -0,0 +1,4 @@
+<{{data}}>
+{{#children}}
+ {{> node}}
+{{/children}}
diff --git a/src/templating/test7/resu.ref b/src/templating/test7/resu.ref
new file mode 100644
index 000000000..d02b24e11
--- /dev/null
+++ b/src/templating/test7/resu.ref
@@ -0,0 +1,7 @@
+family:
+<grandparent>
+ <parent>
+ <child>
+ <parent2>
+ <child2>
+ <pet>
diff --git a/src/templating/test7/vg.ref b/src/templating/test7/vg.ref
new file mode 100644
index 000000000..032e6c447
--- /dev/null
+++ b/src/templating/test7/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json base.mustache
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 69 allocs, 69 frees, 36,313 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/src/templating/test8/.gitignore b/src/templating/test8/.gitignore
new file mode 100644
index 000000000..4d897daa0
--- /dev/null
+++ b/src/templating/test8/.gitignore
@@ -0,0 +1,2 @@
+resu.last
+vg.last
diff --git a/src/templating/test8/json b/src/templating/test8/json
new file mode 100644
index 000000000..04a1e4aaa
--- /dev/null
+++ b/src/templating/test8/json
@@ -0,0 +1,8 @@
+{
+"val1": "",
+"val2": 0,
+"val3": false,
+"val4": null,
+"val5": [],
+"val6": 0.0
+}
diff --git a/src/templating/test8/must b/src/templating/test8/must
new file mode 100644
index 000000000..a22374438
--- /dev/null
+++ b/src/templating/test8/must
@@ -0,0 +1,6 @@
+x{{#val1}} {{.}} {{/val1}}x
+x{{#val2}} {{.}} {{/val2}}x
+x{{#val3}} {{.}} {{/val3}}x
+x{{#val4}} {{.}} {{/val4}}x
+x{{#val5}} {{.}} {{/val5}}x
+x{{#val6}} {{.}} {{/val6}}x
diff --git a/src/templating/test8/resu.ref b/src/templating/test8/resu.ref
new file mode 100644
index 000000000..e0c16e49a
--- /dev/null
+++ b/src/templating/test8/resu.ref
@@ -0,0 +1,6 @@
+xx
+xx
+xx
+xx
+xx
+xx
diff --git a/src/templating/test8/vg.ref b/src/templating/test8/vg.ref
new file mode 100644
index 000000000..b5b0235f9
--- /dev/null
+++ b/src/templating/test8/vg.ref
@@ -0,0 +1,14 @@
+Memcheck, a memory error detector
+Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
+Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
+Command: ../mustach json must
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 17 allocs, 17 frees, 4,832 bytes allocated
+
+All heap blocks were freed -- no leaks are possible
+
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)