diff --git a/ltm/example/test.c b/ltm/example/test.c index d37dd11..cff2922 100644 --- a/ltm/example/test.c +++ b/ltm/example/test.c @@ -3,9 +3,18 @@ #include "ltm/template.h" -const char *s = "
\n"
- "{{ paste }}\n"
- "
";
+const char *s = "\n"
+ "\n"
+ "\n"
+ "{{ paste }}
";
+
+ ltm_err reader(size_t *written, char *buf, size_t len, void *data) {
+ FILE *f = data;
+
+ *written = fread(buf, 1, len, f);
+
+ return ltm_err_ok;
+ }
int main() {
ltm_template *template;
@@ -13,17 +22,22 @@ int main() {
ltm_instance *instance;
ltm_template_instantiate(&instance, template);
+ const char *filename = "src/ltm_instance.c";
+
struct stat sb;
- stat("Makefile", &sb);
+ stat(filename, &sb);
- FILE *f = fopen("Makefile", "rb");
+ FILE *f = fopen(filename, "rb");
- ltm_instance_block_add_var(instance, "paste", ltm_instance_block_type_file_owned, f, sb.st_size);
+ ltm_instance_block_add_var_fn(instance, "paste", reader, f, sb.st_size);
+ /* ltm_instance_block_add_var(instance, "paste", ltm_instance_block_type_file_owned, f, sb.st_size); */
+ /* ltm_instance_block_add_var(instance, "paste", ltm_instance_block_type_buf, "hello\n", 6); */
+ /* ltm_instance_block_add_var(instance, "paste", ltm_instance_block_type_buf, "world\n", 6); */
- char buf[1024];
+ char buf[128];
size_t written = 0;
- while (ltm_instance_write(&written, buf, 1024, instance) != ltm_err_done) {
+ while (ltm_instance_write(&written, buf, 128, instance) != ltm_err_done) {
printf("%.*s", (int)written, buf);
}
diff --git a/ltm/include/ltm/template.h b/ltm/include/ltm/template.h
index 975b344..fc45c07 100644
--- a/ltm/include/ltm/template.h
+++ b/ltm/include/ltm/template.h
@@ -39,6 +39,9 @@ void ltm_template_free(ltm_template *template);
*/
typedef struct ltm_instance ltm_instance;
+typedef ltm_err (*ltm_data_fn)(size_t *written, char *buf, size_t len,
+ void *data);
+
/**
* Create a new instance of the given template.
*/
@@ -56,6 +59,7 @@ typedef enum ltm_instance_block_type {
ltm_instance_block_type_file,
ltm_instance_block_type_file_owned,
ltm_instance_block_type_nested,
+ ltm_instance_block_type_fn,
} ltm_instance_block_type;
/**
@@ -65,6 +69,12 @@ ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
ltm_instance_block_type type, void *data,
size_t len);
+/**
+ * Add a new variable to the template whose data is provided by a data function.
+ */
+ltm_err ltm_instance_block_add_var_fn(ltm_instance *instance, const char *name,
+ ltm_data_fn fn, void *data, size_t len);
+
/**
* Add a new nested instance to the instance, returning a handle to the nested
* instance.
diff --git a/ltm/src/_include/ltm/template_internal.h b/ltm/src/_include/ltm/template_internal.h
index cbac721..4c651ae 100644
--- a/ltm/src/_include/ltm/template_internal.h
+++ b/ltm/src/_include/ltm/template_internal.h
@@ -86,6 +86,7 @@ ltm_err ltm_template_block_append(ltm_template *template,
typedef struct ltm_instance_block {
ltm_instance_block_type type;
+ ltm_data_fn fn;
struct {
void *ptr;
size_t len;
diff --git a/ltm/src/ltm_instance.c b/ltm/src/ltm_instance.c
index 845b754..f0c27fa 100644
--- a/ltm/src/ltm_instance.c
+++ b/ltm/src/ltm_instance.c
@@ -49,6 +49,7 @@ void ltm_instance_free(ltm_instance *instance) {
ltm_instance_free(block->data.ptr);
break;
case ltm_instance_block_type_file:
+ case ltm_instance_block_type_fn:
case ltm_instance_block_type_buf:;
}
@@ -158,6 +159,48 @@ ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
return ltm_err_ok;
}
+ltm_err ltm_instance_block_add_var_fn(ltm_instance *instance, const char *name,
+ 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_RES(ltm_instance_block_init(&block));
+
+ block->type = ltm_instance_block_type_fn;
+ block->fn = fn;
+ block->data.ptr = data;
+ 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;
+}
+
ltm_err ltm_instance_block_add_nested(ltm_instance **out,
ltm_instance *instance,
const char *name) {
@@ -211,6 +254,7 @@ size_t ltm_instance_size(const ltm_instance *instance) {
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:
total += block->data.len;
break;
case ltm_instance_block_type_nested:
@@ -264,6 +308,19 @@ ltm_err ltm_instance_write(size_t *written, char *buf, size_t len,
instance->written = 0;
}
} break;
+ case ltm_instance_block_type_fn: {
+ size_t cap =
+ LTM_MIN(current->data.len - instance->written, len - *written);
+ size_t fn_written = 0;
+ LTM_RES(current->fn(&fn_written, &buf[*written], cap, current->data.ptr));
+ *written += fn_written;
+ instance->written += fn_written;
+
+ if (instance->written == current->data.len) {
+ instance->blocks.current = current->next;
+ instance->written = 0;
+ }
+ } break;
case ltm_instance_block_type_nested: {
size_t nested_written = 0;
ltm_err res = ltm_instance_write(&nested_written, &buf[*written],