feat(ltm): initial write function
parent
750bee27c7
commit
c26c8cf18a
|
@ -17,12 +17,16 @@
|
|||
} \
|
||||
}
|
||||
|
||||
#define LTM_MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define LTM_MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
typedef enum ltm_err {
|
||||
ltm_err_ok = 0,
|
||||
ltm_err_invalid_template,
|
||||
ltm_err_failed_alloc,
|
||||
ltm_err_not_found,
|
||||
ltm_err_wrong_block_type,
|
||||
ltm_err_done,
|
||||
} ltm_err;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,4 +70,23 @@ ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
|
|||
ltm_err ltm_instance_block_add_nested(ltm_instance **out,
|
||||
ltm_instance *instance, const char *name);
|
||||
|
||||
/**
|
||||
* Calculate the size of the resulting output of this instance.
|
||||
*/
|
||||
size_t ltm_instance_size(const ltm_instance *instance);
|
||||
|
||||
/**
|
||||
* Write at most `len` bytes to the given buffer.
|
||||
*
|
||||
* @param written outputs how many bytes were written to `buf`
|
||||
* @param buf buffer to write to
|
||||
* @param len length of the buffer
|
||||
* @param instance instance to write
|
||||
* @return `ltm_err_ok` if write was successful but there's more to be written,
|
||||
* `ltm_err_done` if everything has been written successfully, or some other
|
||||
* error code
|
||||
*/
|
||||
ltm_err ltm_instance_write(size_t *written, char *buf, size_t len,
|
||||
ltm_instance *instance);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -115,19 +115,23 @@ ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
|
|||
ltm_instance_block_type type, void *data,
|
||||
size_t len) {
|
||||
const ltm_template *template = instance->template;
|
||||
bool matched = false;
|
||||
|
||||
ltm_template_block_name *block_name = NULL;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < template->names.len && !matched; i++) {
|
||||
ltm_template_block_name *block_name = &template->names.arr[i];
|
||||
matched = strncmp(name, block_name->name.s, block_name->name.len) == 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 (!matched) {
|
||||
if (i == template->names.len) {
|
||||
return ltm_err_not_found;
|
||||
}
|
||||
|
||||
ltm_template_block *template_block = &template->blocks.arr[i];
|
||||
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;
|
||||
|
@ -191,3 +195,66 @@ ltm_err ltm_instance_block_add_nested(ltm_instance **out,
|
|||
|
||||
return ltm_err_ok;
|
||||
}
|
||||
|
||||
size_t ltm_instance_size(const ltm_instance *instance) {
|
||||
size_t total = 0;
|
||||
ltm_instance_block *block = instance->blocks.head;
|
||||
|
||||
while (block != NULL) {
|
||||
switch (block->type) {
|
||||
case ltm_instance_block_type_buf:
|
||||
case ltm_instance_block_type_buf_owned:
|
||||
total += block->data.len;
|
||||
break;
|
||||
case ltm_instance_block_type_nested:
|
||||
total += ltm_instance_size(block->data.ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
ltm_err ltm_instance_write(size_t *written, char *buf, size_t len,
|
||||
ltm_instance *instance) {
|
||||
while ((*written < len) && (instance->blocks.current != NULL)) {
|
||||
ltm_instance_block *current = instance->blocks.current;
|
||||
|
||||
switch (current->type) {
|
||||
case ltm_instance_block_type_buf:
|
||||
case ltm_instance_block_type_buf_owned: {
|
||||
size_t cap =
|
||||
LTM_MIN(current->data.len - instance->written, len - *written);
|
||||
memcpy(&buf[*written], current->data.ptr, cap);
|
||||
*written += cap;
|
||||
instance->written += cap;
|
||||
|
||||
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],
|
||||
len - *written, current->data.ptr);
|
||||
*written += nested_written;
|
||||
|
||||
switch (res) {
|
||||
case ltm_err_done:
|
||||
instance->blocks.current = current->next;
|
||||
instance->written = 0;
|
||||
break;
|
||||
case ltm_err_ok:
|
||||
break;
|
||||
default:
|
||||
return res;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
return instance->blocks.current == NULL ? ltm_err_done : ltm_err_ok;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#include "test.h"
|
||||
|
||||
#include "ltm/common.h"
|
||||
#include "ltm/template.h"
|
||||
#include "ltm/template_internal.h"
|
||||
|
||||
void test_single_placeholder() {
|
||||
const char *s = "Hello, {{ world }}!";
|
||||
|
||||
ltm_template *template;
|
||||
TEST_ASSERT(ltm_template_compile(&template, s) == ltm_err_ok);
|
||||
|
||||
ltm_instance *instance;
|
||||
TEST_CHECK(ltm_template_instantiate(&instance, template) == ltm_err_ok);
|
||||
|
||||
TEST_CHECK(ltm_instance_block_add_var(instance, "world", ltm_instance_block_type_buf, "World", 5) == ltm_err_ok);
|
||||
|
||||
TEST_CHECK(ltm_instance_size(instance) == 13);
|
||||
|
||||
char buf[13];
|
||||
size_t written = 0;
|
||||
TEST_CHECK(ltm_instance_write(&written, buf, 13, instance) == ltm_err_done);
|
||||
TEST_CHECK(written == 13);
|
||||
TEST_CHECK(strncmp(buf, "Hello, World!", 13) == 0);
|
||||
|
||||
ltm_instance_free(instance);
|
||||
ltm_template_free(template);
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{ "instance single placeholder", test_single_placeholder },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
#include "ltm/common.h"
|
||||
#include "test.h"
|
||||
|
||||
#include "ltm/common.h"
|
||||
#include "ltm/template.h"
|
||||
#include "ltm/template_internal.h"
|
||||
|
Loading…
Reference in New Issue