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" #include "ltm/template.h"
const char *s = "<body><pre><code>\n" const char *s = "<head><link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css\">\n"
"{{ paste }}\n" "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>\n"
"</code></pre></body>"; "<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() { int main() {
ltm_template *template; ltm_template *template;
@ -13,17 +22,22 @@ int main() {
ltm_instance *instance; ltm_instance *instance;
ltm_template_instantiate(&instance, template); ltm_template_instantiate(&instance, template);
const char *filename = "src/ltm_instance.c";
struct stat sb; 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; 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); 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 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. * 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,
ltm_instance_block_type_file_owned, ltm_instance_block_type_file_owned,
ltm_instance_block_type_nested, ltm_instance_block_type_nested,
ltm_instance_block_type_fn,
} ltm_instance_block_type; } 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, ltm_instance_block_type type, void *data,
size_t len); 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 * Add a new nested instance to the instance, returning a handle to the nested
* instance. * instance.

View File

@ -86,6 +86,7 @@ ltm_err ltm_template_block_append(ltm_template *template,
typedef struct ltm_instance_block { typedef struct ltm_instance_block {
ltm_instance_block_type type; ltm_instance_block_type type;
ltm_data_fn fn;
struct { struct {
void *ptr; void *ptr;
size_t len; size_t len;

View File

@ -49,6 +49,7 @@ void ltm_instance_free(ltm_instance *instance) {
ltm_instance_free(block->data.ptr); ltm_instance_free(block->data.ptr);
break; break;
case ltm_instance_block_type_file: case ltm_instance_block_type_file:
case ltm_instance_block_type_fn:
case ltm_instance_block_type_buf:; 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; 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_err ltm_instance_block_add_nested(ltm_instance **out,
ltm_instance *instance, ltm_instance *instance,
const char *name) { 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_buf_owned:
case ltm_instance_block_type_file: case ltm_instance_block_type_file:
case ltm_instance_block_type_file_owned: case ltm_instance_block_type_file_owned:
case ltm_instance_block_type_fn:
total += block->data.len; total += block->data.len;
break; break;
case ltm_instance_block_type_nested: 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; instance->written = 0;
} }
} break; } 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: { case ltm_instance_block_type_nested: {
size_t nested_written = 0; size_t nested_written = 0;
ltm_err res = ltm_instance_write(&nested_written, &buf[*written], ltm_err res = ltm_instance_write(&nested_written, &buf[*written],