feat(ltm): support custom data reader functions
parent
f37cfc30af
commit
845ec95bf1
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in New Issue