Compare commits
2 Commits
dae8a2f30e
...
9cd5d386cd
Author | SHA1 | Date |
---|---|---|
Jef Roosens | 9cd5d386cd | |
Jef Roosens | f781fbdb89 |
|
@ -0,0 +1,32 @@
|
||||||
|
# LTM - Lander Template Module
|
||||||
|
|
||||||
|
This module provides an interface for generating `char` streams from a given
|
||||||
|
template.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<body>
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
<ul>
|
||||||
|
{{ item start }}
|
||||||
|
<li><a href="{{ url }}">{{ name }}</a></li>
|
||||||
|
{{ item end }}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
```
|
||||||
|
|
||||||
|
The above snippet shows everything the templating language currently offers;
|
||||||
|
either singular variables (here: `title`) or nested templates (here: `item`).
|
||||||
|
Note the absence of a loop construct. This is because each variable and nested
|
||||||
|
template is implicitely already a loop; a variable or a nested template can be
|
||||||
|
added as many times as needed, and they will appear in the order they were
|
||||||
|
added.
|
||||||
|
|
||||||
|
Template strings are compiled into templates. From a template, an instance can
|
||||||
|
be created to which the required data can be added to fill in the template.
|
||||||
|
Instantiating a template does not modify the original template, meaning
|
||||||
|
templates can be safely used concurrently.
|
||||||
|
|
||||||
|
Each inserted variable can get its data from a variety of sources, namely
|
||||||
|
`char` buffers, files or a custom reader function. The resulting `char` stream
|
||||||
|
is never fully loaded into memory; an instance can stream its content to a
|
||||||
|
provided buffer to prevent unnecessary memory usage.
|
|
@ -96,6 +96,12 @@ typedef struct ltm_instance_block {
|
||||||
|
|
||||||
ltm_err ltm_instance_block_init(ltm_instance_block **out);
|
ltm_err ltm_instance_block_init(ltm_instance_block **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new block to the instance with the given type.
|
||||||
|
*/
|
||||||
|
ltm_err ltm_instance_block_add(ltm_instance_block **out, ltm_instance *instance,
|
||||||
|
const char *name, ltm_instance_block_type type);
|
||||||
|
|
||||||
struct ltm_instance {
|
struct ltm_instance {
|
||||||
const ltm_template *template;
|
const ltm_template *template;
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -106,7 +106,9 @@ ltm_err ltm_template_instantiate(ltm_instance **out,
|
||||||
} break;
|
} break;
|
||||||
case ltm_template_block_type_var:
|
case ltm_template_block_type_var:
|
||||||
case ltm_template_block_type_nested:
|
case ltm_template_block_type_nested:
|
||||||
*vars = &instance->blocks.tail->next;
|
// Account for the possibility a template starts with a placeholder
|
||||||
|
*vars = instance->blocks.tail != NULL ? &instance->blocks.tail->next
|
||||||
|
: &instance->blocks.head;
|
||||||
vars++;
|
vars++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -117,20 +119,21 @@ ltm_err ltm_template_instantiate(ltm_instance **out,
|
||||||
return ltm_err_ok;
|
return ltm_err_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
|
ltm_err ltm_instance_block_add(ltm_instance_block **out, ltm_instance *instance,
|
||||||
ltm_instance_block_type type, void *data,
|
const char *name, ltm_instance_block_type type) {
|
||||||
size_t len) {
|
|
||||||
const ltm_template *template = instance->template;
|
const ltm_template *template = instance->template;
|
||||||
|
|
||||||
ltm_template_block_name *block_name = NULL;
|
ltm_template_block_name *block_name = NULL;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for (i = 0; i < template->names.len; i++) {
|
while (i < template->names.len) {
|
||||||
block_name = &template->names.arr[i];
|
block_name = &template->names.arr[i];
|
||||||
|
|
||||||
if (strncmp(name, block_name->name.s, block_name->name.len) == 0) {
|
if (strncmp(name, block_name->name.s, block_name->name.len) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == template->names.len) {
|
if (i == template->names.len) {
|
||||||
|
@ -138,8 +141,22 @@ ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
ltm_template_block *template_block = &template->blocks.arr[block_name->index];
|
ltm_template_block *template_block = &template->blocks.arr[block_name->index];
|
||||||
|
bool correct_type = false;
|
||||||
|
|
||||||
if (template_block->type != ltm_template_block_type_var) {
|
switch (type) {
|
||||||
|
case ltm_instance_block_type_nested:
|
||||||
|
correct_type = template_block->type == ltm_template_block_type_nested;
|
||||||
|
break;
|
||||||
|
case ltm_instance_block_type_buf:
|
||||||
|
case ltm_instance_block_type_buf_owned:
|
||||||
|
case ltm_instance_block_type_file:
|
||||||
|
case ltm_instance_block_type_file_owned:
|
||||||
|
case ltm_instance_block_type_fn:
|
||||||
|
correct_type = template_block->type == ltm_template_block_type_var;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!correct_type) {
|
||||||
return ltm_err_wrong_block_type;
|
return ltm_err_wrong_block_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,57 +164,39 @@ ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
|
||||||
LTM_RES(ltm_instance_block_init(&block));
|
LTM_RES(ltm_instance_block_init(&block));
|
||||||
|
|
||||||
block->type = type;
|
block->type = type;
|
||||||
block->data.ptr = data;
|
|
||||||
block->data.len = len;
|
|
||||||
|
|
||||||
// We insert the block in the linked list and replace its next pointer as the
|
// Insert the block in the linked list
|
||||||
// new attachment point for this variable
|
|
||||||
block->next = *instance->vars[i];
|
block->next = *instance->vars[i];
|
||||||
*instance->vars[i] = block;
|
*instance->vars[i] = block;
|
||||||
instance->vars[i] = &block->next;
|
instance->vars[i] = &block->next;
|
||||||
|
|
||||||
|
*out = block;
|
||||||
|
|
||||||
|
return ltm_err_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
|
||||||
|
ltm_instance_block_type type, void *data,
|
||||||
|
size_t len) {
|
||||||
|
ltm_instance_block *block;
|
||||||
|
LTM_RES(ltm_instance_block_add(&block, instance, name, type));
|
||||||
|
|
||||||
|
block->data.ptr = data;
|
||||||
|
block->data.len = len;
|
||||||
|
|
||||||
return ltm_err_ok;
|
return ltm_err_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
ltm_err ltm_instance_block_add_var_fn(ltm_instance *instance, const char *name,
|
ltm_err ltm_instance_block_add_var_fn(ltm_instance *instance, const char *name,
|
||||||
ltm_data_fn fn, void *data, size_t len) {
|
ltm_data_fn fn, void *data, size_t len) {
|
||||||
const ltm_template *template = instance->template;
|
|
||||||
|
|
||||||
ltm_template_block_name *block_name = NULL;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < template->names.len; i++) {
|
|
||||||
block_name = &template->names.arr[i];
|
|
||||||
|
|
||||||
if (strncmp(name, block_name->name.s, block_name->name.len) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == template->names.len) {
|
|
||||||
return ltm_err_not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
ltm_template_block *template_block = &template->blocks.arr[block_name->index];
|
|
||||||
|
|
||||||
if (template_block->type != ltm_template_block_type_var) {
|
|
||||||
return ltm_err_wrong_block_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
ltm_instance_block *block;
|
ltm_instance_block *block;
|
||||||
LTM_RES(ltm_instance_block_init(&block));
|
LTM_RES(ltm_instance_block_add(&block, instance, name,
|
||||||
|
ltm_instance_block_type_fn));
|
||||||
|
|
||||||
block->type = ltm_instance_block_type_fn;
|
|
||||||
block->fn = fn;
|
block->fn = fn;
|
||||||
block->data.ptr = data;
|
block->data.ptr = data;
|
||||||
block->data.len = len;
|
block->data.len = len;
|
||||||
|
|
||||||
// We insert the block in the linked list and replace its next pointer as the
|
|
||||||
// new attachment point for this variable
|
|
||||||
block->next = *instance->vars[i];
|
|
||||||
*instance->vars[i] = block;
|
|
||||||
instance->vars[i] = &block->next;
|
|
||||||
|
|
||||||
return ltm_err_ok;
|
return ltm_err_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,19 +204,25 @@ ltm_err ltm_instance_block_add_nested(ltm_instance **out,
|
||||||
ltm_instance *instance,
|
ltm_instance *instance,
|
||||||
const char *name) {
|
const char *name) {
|
||||||
const ltm_template *template = instance->template;
|
const ltm_template *template = instance->template;
|
||||||
bool matched = false;
|
|
||||||
|
|
||||||
|
ltm_template_block_name *block_name = NULL;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (i = 0; i < template->names.len && !matched; i++) {
|
|
||||||
ltm_template_block_name *block_name = &template->names.arr[i];
|
while (i < template->names.len) {
|
||||||
matched = strncmp(name, block_name->name.s, block_name->name.len) == 0;
|
block_name = &template->names.arr[i];
|
||||||
|
|
||||||
|
if (strncmp(name, block_name->name.s, block_name->name.len) == 0) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matched) {
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == template->names.len) {
|
||||||
return ltm_err_not_found;
|
return ltm_err_not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
ltm_template_block *template_block = &template->blocks.arr[i];
|
ltm_template_block *template_block = &template->blocks.arr[block_name->index];
|
||||||
|
|
||||||
if (template_block->type != ltm_template_block_type_nested) {
|
if (template_block->type != ltm_template_block_type_nested) {
|
||||||
return ltm_err_wrong_block_type;
|
return ltm_err_wrong_block_type;
|
||||||
|
|
Loading…
Reference in New Issue