diff --git a/ltm/include/ltm/template.h b/ltm/include/ltm/template.h index 7a920fa..445fbf9 100644 --- a/ltm/include/ltm/template.h +++ b/ltm/include/ltm/template.h @@ -28,4 +28,33 @@ ltm_err ltm_template_compile(ltm_template **out, const char *template); ltm_err ltm_template_compile_n(ltm_template **out, const char *template, size_t len); +/** + * Represents a specific instance of a template. + */ +typedef struct ltm_instance ltm_instance; + +/** + * Create a new instance of the given template. + */ +ltm_err ltm_template_instantiate(ltm_instance **out, + const ltm_template *template); + +typedef enum ltm_instance_block_type { + ltm_instance_block_type_buf = 0, +} ltm_instance_block_type; + +/** + * Add a new variable to the template. + */ +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 nested instance to the instance, returning a handle to the nested + * instance. + */ +ltm_err ltm_instance_block_add_nested(ltm_instance **out, + ltm_instance *instance, const char *name); + #endif diff --git a/ltm/src/_include/ltm/template_internal.h b/ltm/src/_include/ltm/template_internal.h index 2511d13..2c750f8 100644 --- a/ltm/src/_include/ltm/template_internal.h +++ b/ltm/src/_include/ltm/template_internal.h @@ -6,8 +6,8 @@ typedef enum ltm_placeholder_type { ltm_placeholder_type_invalid = 0, ltm_placeholder_type_var, - ltm_placeholder_type_loop_start, - ltm_placeholder_type_loop_end, + ltm_placeholder_type_nested_start, + ltm_placeholder_type_nested_end, } ltm_placeholder_type; /** @@ -29,7 +29,7 @@ typedef struct ltm_placeholder { typedef enum ltm_template_block_type { ltm_template_block_type_literal = 0, ltm_template_block_type_var, - ltm_template_block_type_loop, + ltm_template_block_type_nested, } ltm_template_block_type; /** @@ -53,7 +53,7 @@ typedef struct ltm_template_block_name { /** * Represents a compiled template. A template consists of a list of blocks, of - * which some have names that can be indexed (e.g. variables, loops). + * which some have names that can be indexed (e.g. variables, nested templates). */ struct ltm_template { struct { @@ -66,13 +66,41 @@ struct ltm_template { } names; }; +/** + * Allocate a new `ltm_template`. + */ ltm_err ltm_template_init(ltm_template **out); +/** + * Append a name to the template's list. + */ ltm_err ltm_template_name_append(ltm_template *template, const char *s, size_t len, size_t index); +/** + * Append a block to the template's list. + */ ltm_err ltm_template_block_append(ltm_template *template, ltm_template_block_type type, void *data, size_t len); +typedef struct ltm_instance_block { + ltm_instance_block_type type; + struct { + void *ptr; + size_t len; + } data; + struct ltm_instance_block *next; +} ltm_instance_block; + +struct ltm_instance { + struct { + ltm_instance_block *head; + ltm_instance_block *tail; + ltm_instance_block *current; + } blocks; + // How many bytes of the current block have been written + size_t written; +}; + #endif diff --git a/ltm/src/ltm_template.c b/ltm/src/ltm_template.c index 4e7dbd0..13ab14a 100644 --- a/ltm/src/ltm_template.c +++ b/ltm/src/ltm_template.c @@ -55,7 +55,7 @@ ltm_err ltm_template_block_append(ltm_template *template, block->data.ptr = data; block->data.len = len; break; - case ltm_template_block_type_loop: + case ltm_template_block_type_nested: block->data.ptr = data; break; // For the other cases, we explicitely ignore the data and len arguments diff --git a/ltm/src/ltm_template_compile.c b/ltm/src/ltm_template_compile.c index 9a14608..7093093 100644 --- a/ltm/src/ltm_template_compile.c +++ b/ltm/src/ltm_template_compile.c @@ -79,9 +79,9 @@ static bool ltm_template_next_placeholder(ltm_placeholder *ph, const char *s, size_t ident_len = temp - ident; if (strncmp("start", ident, ident_len) == 0) { - ph->type = ltm_placeholder_type_loop_start; + ph->type = ltm_placeholder_type_nested_start; } else if (strncmp("end", ident, ident_len) == 0) { - ph->type = ltm_placeholder_type_loop_end; + ph->type = ltm_placeholder_type_nested_end; } else { ph->type = ltm_placeholder_type_invalid; } @@ -95,15 +95,15 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) { LTM_RES(ltm_template_init(&template)); ltm_placeholder ph; - bool in_loop = false; - const char *loop_start = NULL, *loop_name = NULL; - size_t loop_depth = 0, loop_name_len = 0; + bool in_nested = false; + const char *nested_start = NULL, *nested_name = NULL; + size_t nested_depth = 0, nested_name_len = 0; - size_t cur_loop_depth = 0; + size_t cur_nested_depth = 0; while (ltm_template_next_placeholder(&ph, s, len)) { // Add part before placeholder as literal - if (!in_loop && (ph.start != s)) { + if (!in_nested && (ph.start != s)) { LTM_RES(ltm_template_block_append( template, ltm_template_block_type_literal, (void *)s, ph.start - s)); } @@ -113,44 +113,45 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) { case ltm_placeholder_type_invalid: return ltm_err_invalid_template; case ltm_placeholder_type_var: - if (!in_loop) { + if (!in_nested) { LTM_RES(ltm_template_block_append(template, ltm_template_block_type_var, NULL, 0)); LTM_RES(ltm_template_name_append(template, ph.name.s, ph.name.len, template->blocks.len - 1)); } break; - case ltm_placeholder_type_loop_start: - if (!in_loop) { - loop_start = ph.end + 1; - loop_depth = cur_loop_depth; - loop_name = ph.name.s; - loop_name_len = ph.name.len; - in_loop = true; + case ltm_placeholder_type_nested_start: + if (!in_nested) { + nested_start = ph.end + 1; + nested_depth = cur_nested_depth; + nested_name = ph.name.s; + nested_name_len = ph.name.len; + in_nested = true; } - cur_loop_depth++; + cur_nested_depth++; break; - case ltm_placeholder_type_loop_end: - // This means there's more loop end placeholders than loop starts - if (cur_loop_depth == 0) { + case ltm_placeholder_type_nested_end: + // This means there's more nested end placeholders than nested starts + if (cur_nested_depth == 0) { return ltm_err_invalid_template; } - cur_loop_depth--; + cur_nested_depth--; - if (in_loop && (cur_loop_depth == loop_depth)) { - size_t loop_len = ph.start - loop_start; - ltm_template *loop_template; - LTM_RES(ltm_template_compile_n(&loop_template, loop_start, loop_len)); + if (in_nested && (cur_nested_depth == nested_depth)) { + size_t nested_len = ph.start - nested_start; + ltm_template *nested_template; + LTM_RES( + ltm_template_compile_n(&nested_template, nested_start, nested_len)); LTM_RES(ltm_template_block_append( - template, ltm_template_block_type_loop, loop_template, 0)); - LTM_RES(ltm_template_name_append(template, loop_name, loop_name_len, + template, ltm_template_block_type_nested, nested_template, 0)); + LTM_RES(ltm_template_name_append(template, nested_name, nested_name_len, template->blocks.len - 1)); - in_loop = false; + in_nested = false; } - // We encountered a loop end without a start - else if (!in_loop) { + // We encountered a nested end without a start + else if (!in_nested) { return ltm_err_invalid_template; } break; @@ -160,8 +161,8 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) { s = ph.end + 1; } - // Unfinished loop - if (in_loop) { + // Unfinished nested + if (in_nested) { return ltm_err_invalid_template; } diff --git a/ltm/test/compile.c b/ltm/test/compile.c index a982bdf..c7c7151 100644 --- a/ltm/test/compile.c +++ b/ltm/test/compile.c @@ -50,7 +50,7 @@ void test_single_placeholder_trailing() { TEST_CHECK(template->names.arr[0].index == 1); } -void test_single_loop() { +void test_single_nested() { const char *s = "abc {{ l start }}some content {{ var }} {{ l end }}"; ltm_template *template; @@ -67,22 +67,22 @@ void test_single_loop() { TEST_CHECK(template->blocks.arr[0].data.ptr == s); TEST_CHECK(template->blocks.arr[0].data.len == 4); - TEST_CHECK(template->blocks.arr[1].type == ltm_template_block_type_loop); - ltm_template *loop_template = template->blocks.arr[1].data.ptr; + TEST_CHECK(template->blocks.arr[1].type == ltm_template_block_type_nested); + ltm_template *nested_template = template->blocks.arr[1].data.ptr; - TEST_CHECK(loop_template->blocks.len == 3); - TEST_CHECK(loop_template->blocks.arr[0].type == ltm_template_block_type_literal); - TEST_CHECK(loop_template->blocks.arr[0].data.ptr == s + 17); - TEST_CHECK(loop_template->blocks.arr[0].data.len == 13); - TEST_CHECK(loop_template->blocks.arr[1].type == ltm_template_block_type_var); - TEST_CHECK(loop_template->blocks.arr[2].type == ltm_template_block_type_literal); - TEST_CHECK(loop_template->blocks.arr[2].data.ptr == s + 39); - TEST_CHECK(loop_template->blocks.arr[2].data.len == 1); + TEST_CHECK(nested_template->blocks.len == 3); + TEST_CHECK(nested_template->blocks.arr[0].type == ltm_template_block_type_literal); + TEST_CHECK(nested_template->blocks.arr[0].data.ptr == s + 17); + TEST_CHECK(nested_template->blocks.arr[0].data.len == 13); + TEST_CHECK(nested_template->blocks.arr[1].type == ltm_template_block_type_var); + TEST_CHECK(nested_template->blocks.arr[2].type == ltm_template_block_type_literal); + TEST_CHECK(nested_template->blocks.arr[2].data.ptr == s + 39); + TEST_CHECK(nested_template->blocks.arr[2].data.len == 1); - TEST_CHECK(loop_template->names.len == 1); - TEST_CHECK(loop_template->names.arr[0].name.s == s + 33); - TEST_CHECK(loop_template->names.arr[0].name.len == 3); - TEST_CHECK(loop_template->names.arr[0].index == 1); + TEST_CHECK(nested_template->names.len == 1); + TEST_CHECK(nested_template->names.arr[0].name.s == s + 33); + TEST_CHECK(nested_template->names.arr[0].name.len == 3); + TEST_CHECK(nested_template->names.arr[0].index == 1); } void test_unclosed_placeholder() { @@ -95,7 +95,7 @@ void test_unclosed_placeholder() { TEST_CHECK(ltm_template_compile(&template, s) == ltm_err_invalid_template); } -void test_unclosed_loop() { +void test_unclosed_nested() { ltm_template *template; const char *s = "abc {{ var start }} {{ hello }}"; @@ -105,8 +105,8 @@ void test_unclosed_loop() { TEST_LIST = { { "template single placeholder", test_single_placeholder }, { "template single placeholder trailing", test_single_placeholder_trailing }, - { "template single loop", test_single_loop }, + { "template single nested", test_single_nested }, { "template unclosed placeholder", test_unclosed_placeholder }, - { "template unclosed loop", test_unclosed_loop }, + { "template unclosed nested", test_unclosed_nested }, { NULL, NULL } };