C99 golang-style template engine
Be careful with untrusted input!
cgotpl comes with a simple CLI.
cgotpl [TEMPLATE] [DATA]
Here TEMPLATE
refers to a golang-style template string and DATA
to a serialized JSON string.
For instance:
cgotpl '{{ range . -}} {{.}} {{- end }}' '["h", "e", "ll", "o"]'
Will print hello
on stdout.
There's a single central function defined in template.h
:
// tpl is a pointer to a template string from which up to n bytes are read.
// dot is the inital dot value. out will be filled with the result of templating
// and needs to be freed by the caller. Returns 0 on success.
int template_eval(const char* tpl, size_t n, json_value* dot, char** out);
An initalized json_value
can be obtained from:
// Consumes an abitrary amount of bytes from st to parse a single JSON value
// into val. Returns 0 on success.
int json_parse(stream* st, json_value* val);
A json_value
needs to be freed with:
void json_value_free(json_value* val);
A stream
can be created with:
// Opens stream backed by data up to len bytes.
void stream_open_memory(stream* stream, const void* data, size_t len);
// Opens stream on the file referenced by filename. Returns 0 on success.
int stream_open_file(stream* stream, const char* filename);
A stream
needs be closed with:
// Closes stream. Returns 0 on success.
int stream_close(stream* stream);
See cli/main.c
for a complete example.
cmake version 3.16 or greater is required. Initialize cmake with:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
The following will produce the cgotpl CLI in build/cli/cgotpl
:
cmake --build build --target cli
The library can be build with:
cmake --build build --target cgotpl
For development a check
(requires a go compiler) and fuzz
(requires CC=clang
) target exist.
Currently, basic control-flow and data access is implemented.
Feature | State |
---|---|
Trim whitespace {{- and -}} |
✅ |
{{/* comments */}} |
❌ |
Default Textual Representation {{pipeline}} |
✅ |
Literals | 🚧 (Some escape sequences are missing) |
{{if pipeline}} T1 {{end}} |
✅ |
{{if pipeline}} T1 {{else}} T0 {{end}} |
✅ |
{{if p}} T1 {{else if p}} T0 {{end}} |
❌ |
{{range pipeline}} T1 {{end}} |
✅ |
{{range pipeline}} T1 {{else}} T0 {{end}} |
✅ |
{{break}} |
✅ |
{{continue}} |
✅ |
{{define}} |
❌ |
{{template "name" pipeline}} |
❌ |
{{block "name" pipeline}} T1 {{end}} |
❌ |
{{with pipeline}} T1 {{end}} |
❌ |
Field access .a.b.c |
✅ |
Variables | ❌ |
Functions (e.g. printf , not , and , ...) |
❌ |
The c and go standard library may disagree on certain formatting (printf
) corner-cases.
cgotpl parses non-executed templates sloppy.
Syntactical issues in non-executed branches may not lead to an error.
I wanted to make something in C.