A template engine written in C designed to be syntax-compatible with Google CTemplate, released under the MIT license
Version 0.1, so there's plenty more work to do. Please feel free to submit an issue or a pull request for bug fixes or more features.
ngtemplate is a small, fast template engine written in C. Like Google's CTemplate, it strives to be as simple as possible to shield developers from the temptation of embedding logic inside their templates. An example of an ngtemplate would be:
Hello, {{Name}}. You have read {{NumPosts}} posts on our blog today. Thank you for visiting!
When combined with the following dictionary:
Name=John
NumPosts=7
The engine will emit the following string as output:
Hello, John. You have read 7 posts on our blog today. Thank you for visiting!
To get a better idea of what you can do with ngtemplate, see Google's CTemplate howto
To use ngtemplate:
- Install CMake if you don't have it
- Clone the git repository
- cd ngtemplate
- git submodule init
- git submodule update
- mkdir build
- cd build
- cmake ../src
- make
- make test
If all went well you should have libngtemplate.a
and libuseful.a
in your build directory
NOTE: CMake-less compilation and binary distributions will come eventually
In a nutshell:
char* output;
const char* tplstring = "Here, have a {{Template}}!";
/* Init some structs */
ngt_template* template = ngt_new();
ngt_dictionary* dictionary = ngt_dictionary_new();
/* Set some stuff in the dictionary */
ngt_set_string(dictionary, "Template", "Beer");
/* Associate the template with the dictionary and template string and expand the template */
template->template = tplstring;
ngt_set_dictionary(template, dictionary);
ngt_expand(tpl, &output);
/* Should be "The template is: Here, have a Beer!" */
fprintf(stdout, "The template is: %s\n", output);
/* Clean stuff up */
free(output);
ngt_destroy(template);
ngt_dictionary_destroy(dictionary);
- ngtemplate is a little more dynamic than CTemplate. You are allowed to set
variable_missing
andmodifier_missing
callbacks to populate templates dynamically rather than stuffing variable values in a data dictionary ahead of time (or some combination of the two approaches). This allows neat tricks similar to the magic you can pull off with Ruby'smethod_missing
- Unlike in CTemplate, you can have as many
FOO_separator
sections as you like inside a template and they will all be expanded in the order in which the separators are placed - Block scope for marker identifiers works even for template includes. In other words, if an included template references a marker not in the include template's dictionary, it will be found if the including template has a dictionary entry with that name
- Includes a built-in modifier called
:cstring_escape
that turns newlines into \n, tabs into \t, quotes into ", and so forth - Modifier semantics are a little different than they are in CTemplate:
- Custom modifiers don't require an
x-
prefix - You can override the built-in modifiers
- Syntax for modifier arguments are more consistent: for all modifiers you must start an
arg list with
=
'. In CTemplate the semantics for custom modifiers are different than built-ins. For backward compatibility with CTemplate, modifiers that start withx-
treat the first thing following the next colon as modifier arguments, just like in CTemplate - You can chain custom modifiers together just like built-in modifiers
- Custom modifiers don't require an
- You cannot currently specify search directories for templates. Calls to
template_set_filename()
need to have absolute or resolvable relative paths to the template file - Probably not UTF-8/Unicode compatible
- Probably susceptible to buffer overruns. Haven't done a threat analysis yet.
AUTOESCAPE
is not supported, and probably won't be unless someone sends me a patch for itjson_escape
andjavascript_escape
modifiers are not supported- Modifiers are not yet supported on includes
- Per-expand-data and custom emitters are not currently supported
- Custom delimiters are supported (via
{{= =}}
), but they cannot be more than 8 characters long - Repeatedly generating output from the same template is slower than it needs to be, because we do not parse the source template into an internal data structure before processing