18#define CWIST_TEMPLATE_MAX_DEPTH 32
23static void html_escape(
const char *value,
char *out,
size_t out_len) {
24 if (!value || out_len == 0)
return;
26 for (
i = 0,
j = 0; value[
i] &&
j < out_len - 1;
i++) {
29 case '&':
repl =
"&";
break;
30 case '<':
repl =
"<";
break;
31 case '>':
repl =
">";
break;
32 case '"':
repl =
""";
break;
33 case '\'':
repl =
"'";
break;
38 if (
j +
rlen >= out_len)
break;
56static void apply_filter(
const char *value,
const char *
filter,
char *out,
size_t out_len) {
57 if (!
filter || out_len == 0)
return;
60 for (
i = 0;
i < out_len - 1 && value && value[
i];
i++)
61 out[
i] = (
char)
toupper((
unsigned char)value[
i]);
65 for (
i = 0;
i < out_len - 1 && value && value[
i];
i++)
66 out[
i] = (
char)
tolower((
unsigned char)value[
i]);
69 html_escape(value, out, out_len);
71 if (!value || value[0] ==
'\0') {
75 const char *s = value;
76 while (
isspace((
unsigned char)*s)) s++;
80 const char *
e = value +
vlen - 1;
81 while (
e > s &&
isspace((
unsigned char)*
e))
e--;
82 size_t len = (s >
e) ? 0 : (
size_t)(
e - s + 1);
83 if (len >= out_len) len = out_len - 1;
89 const char *arg =
NULL;
95 if (value && value[0]) {
107 snprintf(out, out_len,
"%s", value);
120static const cJSON *get_value_from_context(
const cJSON *
context,
const char *key) {
124 if (
strcmp(key,
".") == 0) {
164 if (
p[0] ==
'{' &&
p[1] ==
'#') {
168 while (*
p && !(
p[0] ==
'#' &&
p[1] ==
'}'))
p++;
169 if (
p[0] ==
'#' &&
p[1] ==
'}')
p += 2;
173 if (
p[0] ==
'{' && (
p[1] ==
'{' ||
p[1] ==
'%')) {
180 while (*
p && (
p[0] !=
'}' ||
p[1] !=
'}'))
p++;
207 const char *raw =
NULL;
209 raw = value->valuestring;
231 }
else if (
p[1] ==
'%') {
234 while (*
p && (
p[0] !=
'%' ||
p[1] !=
'}'))
p++;
273 if (
scan[0] ==
'{' &&
scan[1] ==
'%') {
340 if (
scan[0] ==
'{' &&
scan[1] ==
'%') {
341 const char *tag =
scan + 2;
342 while (*tag ==
' ' || *tag ==
'\t' || *tag ==
'\n') tag++;
343 if (
strncmp(tag,
"for ", 4) == 0 ||
344 strncmp(tag,
"for\t", 4) == 0 ||
345 strncmp(tag,
"for\n", 4) == 0) {
347 }
else if (
strncmp(tag,
"endfor", 6) == 0) {
385 }
else if (
strcmp(
cmd,
"include") == 0) {
389 while (*path ==
' ' || *path ==
'\t' || *path ==
'\n') path++;
392 (*
end ==
' ' || *
end ==
'\t' || *
end ==
'\n' || *
end ==
'"'))
394 if (path[0] ==
'"') path++;
433 return render_internal(&
p,
context, 0);
446 perror(
"Failed to open template file");
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
char * cwist_strdup(const char *src)
Duplicate a string using libttak-backed storage.
#define CWIST_DEFER_FREE
Attach to a pointer variable's declaration to cwist_free() it automatically when that variable's encl...
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
cwist_error_t cwist_sstring_append_len(cwist_sstring *str, const char *data, size_t len)
Append raw bytes with length.
cwist_sstring * cwist_sstring_create(void)
Create a new sstring instance.
cwist_error_t cwist_sstring_append(cwist_sstring *str, const char *data)
Append a C string.
void cwist_sstring_destroy(cwist_sstring *str)
Destroy an sstring instance.
cwist_sstring * cwist_template_render(const char *template_str, const cJSON *context)
Render an in-memory template string against a JSON context object.
cwist_sstring * cwist_template_render_file(const char *file_path, const cJSON *context)
Load a template file from disk and render it against a JSON context.
#define CWIST_TEMPLATE_MAX_DEPTH
Maximum nesting depth for includes/control structures.