feat(ltm): support custom data reader functions

ltm
Jef Roosens 2023-12-16 23:00:00 +01:00
parent f37cfc30af
commit 845ec95bf1
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 90 additions and 8 deletions

View File

@ -3,9 +3,18 @@
#include "ltm/template.h"
const char *s = "<body><pre><code>\n"
"{{ paste }}\n"
"</code></pre></body>";
const char *s = "<head><link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css\">\n"
"<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n"
"<script>hljs.highlightAll();</script></head>\n"
"<body><pre><code>{{ paste }}</code></pre></body>";
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);
}

View File

@ -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.

View File

@ -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;

View File

@ -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],