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 {
|
typedef enum ltm_err {
|
||||||
ltm_err_ok = 0,
|
ltm_err_ok = 0,
|
||||||
ltm_err_invalid_template,
|
ltm_err_invalid_template,
|
||||||
ltm_err_failed_alloc,
|
ltm_err_failed_alloc,
|
||||||
ltm_err_not_found,
|
ltm_err_not_found,
|
||||||
ltm_err_wrong_block_type,
|
ltm_err_wrong_block_type,
|
||||||
|
ltm_err_done,
|
||||||
} ltm_err;
|
} ltm_err;
|
||||||
|
|
||||||
#endif
|
#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_err ltm_instance_block_add_nested(ltm_instance **out,
|
||||||
ltm_instance *instance, const char *name);
|
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
|
#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,
|
ltm_instance_block_type type, void *data,
|
||||||
size_t len) {
|
size_t len) {
|
||||||
const ltm_template *template = instance->template;
|
const ltm_template *template = instance->template;
|
||||||
bool matched = false;
|
|
||||||
|
|
||||||
|
ltm_template_block_name *block_name = NULL;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (i = 0; i < template->names.len && !matched; i++) {
|
|
||||||
ltm_template_block_name *block_name = &template->names.arr[i];
|
for (i = 0; i < template->names.len; i++) {
|
||||||
matched = strncmp(name, block_name->name.s, block_name->name.len) == 0;
|
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;
|
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) {
|
if (template_block->type != ltm_template_block_type_var) {
|
||||||
return ltm_err_wrong_block_type;
|
return ltm_err_wrong_block_type;
|
||||||
|
@ -191,3 +195,66 @@ ltm_err ltm_instance_block_add_nested(ltm_instance **out,
|
||||||
|
|
||||||
return ltm_err_ok;
|
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 "test.h"
|
||||||
|
|
||||||
|
#include "ltm/common.h"
|
||||||
#include "ltm/template.h"
|
#include "ltm/template.h"
|
||||||
#include "ltm/template_internal.h"
|
#include "ltm/template_internal.h"
|
||||||
|
|
Loading…
Reference in New Issue