From dae8a2f30e5089af7f34db5f35143b9b183b6009 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sat, 16 Dec 2023 23:00:00 +0100 Subject: [PATCH] feat(ltm): support custom data reader functions --- ltm/example/test.c | 30 +++++++++---- ltm/include/ltm/template.h | 10 +++++ ltm/src/_include/ltm/template_internal.h | 1 + ltm/src/ltm_instance.c | 57 ++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 8 deletions(-) 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],