diff --git a/ltm/Makefile b/ltm/Makefile index 38b2b4a..44b2073 100644 --- a/ltm/Makefile +++ b/ltm/Makefile @@ -9,14 +9,19 @@ SRCS != find '$(SRC_DIR)' -iname '*.c' SRCS_H != find include -iname '*.h' SRCS_H_INTERNAL != find $(SRC_DIR) -iname '*.h' SRCS_TEST != find '$(TEST_DIR)' -iname '*.c' +SRCS_EXAMPLE != find '$(EXAMPLE_DIR)' -iname '*.c' OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) OBJS_TEST := $(SRCS_TEST:%=$(BUILD_DIR)/%.o) +OBJS_EXAMPLE := $(SRCS_EXAMPLE:%=$(BUILD_DIR)/%.o) DEPS := $(SRCS:%=$(BUILD_DIR)/%.d) $(SRCS_TEST:%=$(BUILD_DIR)/%.d) BINS_TEST := $(OBJS_TEST:%.c.o=%) +BINS_EXAMPLE := $(OBJS_EXAMPLE:%.c.o=%) + TARGETS_TEST := $(BINS_TEST:%=test-%) TARGETS_MEM_TEST := $(BINS_TEST:%=test-mem-%) +TARGETS_EXAMPLE := $(BINS_EXAMPLE:%=test-%) _CFLAGS := $(addprefix -I,$(INC_DIRS)) $(CFLAGS) -Wall -Wextra diff --git a/ltm/config.mk b/ltm/config.mk index 55bfdf7..b950e29 100644 --- a/ltm/config.mk +++ b/ltm/config.mk @@ -3,6 +3,7 @@ LIB_FILENAME = libltm.a BUILD_DIR = build SRC_DIR = src TEST_DIR = test +EXAMPLE_DIR = example THIRDPARTY = PUB_INC_DIR = include @@ -13,4 +14,4 @@ INC_DIRS = $(PUB_INC_DIR) src/_include # object file is also recompiled if only a header is changed. # -MP: generate a dummy target for every header file (according to the docs it # prevents some errors when removing header files) -CFLAGS ?= -MMD -MP -g +CFLAGS ?= -MMD -MP -g -Wall -Werror diff --git a/ltm/example/test.c b/ltm/example/test.c new file mode 100644 index 0000000..d37dd11 --- /dev/null +++ b/ltm/example/test.c @@ -0,0 +1,34 @@ +#include +#include + +#include "ltm/template.h" + +const char *s = "
\n"
+  "{{ paste }}\n"
+  "
"; + +int main() { + ltm_template *template; + ltm_template_compile(&template, s); + ltm_instance *instance; + ltm_template_instantiate(&instance, template); + + struct stat sb; + stat("Makefile", &sb); + + FILE *f = fopen("Makefile", "rb"); + + ltm_instance_block_add_var(instance, "paste", ltm_instance_block_type_file_owned, f, sb.st_size); + + char buf[1024]; + size_t written = 0; + + while (ltm_instance_write(&written, buf, 1024, instance) != ltm_err_done) { + printf("%.*s", (int)written, buf); + } + + printf("%.*s", (int)written, buf); + + ltm_instance_free(instance); + ltm_template_free(template); +} diff --git a/ltm/include/ltm/common.h b/ltm/include/ltm/common.h index 6851359..ab028af 100644 --- a/ltm/include/ltm/common.h +++ b/ltm/include/ltm/common.h @@ -24,6 +24,7 @@ typedef enum ltm_err { ltm_err_ok = 0, ltm_err_invalid_template, ltm_err_failed_alloc, + ltm_err_failed_io, ltm_err_not_found, ltm_err_wrong_block_type, ltm_err_done, diff --git a/ltm/include/ltm/template.h b/ltm/include/ltm/template.h index ed802f1..975b344 100644 --- a/ltm/include/ltm/template.h +++ b/ltm/include/ltm/template.h @@ -53,6 +53,8 @@ void ltm_instance_free(ltm_instance *instance); typedef enum ltm_instance_block_type { ltm_instance_block_type_buf = 0, ltm_instance_block_type_buf_owned, + ltm_instance_block_type_file, + ltm_instance_block_type_file_owned, ltm_instance_block_type_nested, } ltm_instance_block_type; diff --git a/ltm/src/ltm_instance.c b/ltm/src/ltm_instance.c index 0db85c2..845b754 100644 --- a/ltm/src/ltm_instance.c +++ b/ltm/src/ltm_instance.c @@ -1,4 +1,5 @@ #include +#include #include #include "ltm/common.h" @@ -41,9 +42,13 @@ void ltm_instance_free(ltm_instance *instance) { case ltm_instance_block_type_buf_owned: free(block->data.ptr); break; + case ltm_instance_block_type_file_owned: + fclose(block->data.ptr); + break; case ltm_instance_block_type_nested: ltm_instance_free(block->data.ptr); break; + case ltm_instance_block_type_file: case ltm_instance_block_type_buf:; } @@ -204,6 +209,8 @@ size_t ltm_instance_size(const ltm_instance *instance) { switch (block->type) { case ltm_instance_block_type_buf: case ltm_instance_block_type_buf_owned: + case ltm_instance_block_type_file: + case ltm_instance_block_type_file_owned: total += block->data.len; break; case ltm_instance_block_type_nested: @@ -219,6 +226,8 @@ size_t ltm_instance_size(const ltm_instance *instance) { ltm_err ltm_instance_write(size_t *written, char *buf, size_t len, ltm_instance *instance) { + *written = 0; + while ((*written < len) && (instance->blocks.current != NULL)) { ltm_instance_block *current = instance->blocks.current; @@ -227,7 +236,8 @@ ltm_err ltm_instance_write(size_t *written, char *buf, size_t len, 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); + memcpy(&buf[*written], &((char *)current->data.ptr)[instance->written], + cap); *written += cap; instance->written += cap; @@ -236,6 +246,24 @@ ltm_err ltm_instance_write(size_t *written, char *buf, size_t len, instance->written = 0; } } break; + case ltm_instance_block_type_file: + case ltm_instance_block_type_file_owned: { + size_t cap = + LTM_MIN(current->data.len - instance->written, len - *written); + size_t read = fread(&buf[*written], 1, cap, current->data.ptr); + + if ((read == 0) && (ferror(current->data.ptr) != 0)) { + return ltm_err_failed_io; + } + + *written += read; + instance->written += read; + + 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], diff --git a/ltm/test/instance.c b/ltm/test/instance.c index b2a978b..3ea46f5 100644 --- a/ltm/test/instance.c +++ b/ltm/test/instance.c @@ -18,10 +18,21 @@ void test_single_placeholder() { 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(ltm_instance_write(&written, buf, 5, instance) == ltm_err_ok); + TEST_CHECK(written == 5); + + written = 0; + TEST_CHECK(ltm_instance_write(&written, buf + 5, 5, instance) == ltm_err_ok); + TEST_CHECK(written == 5); + + written = 0; + TEST_CHECK(ltm_instance_write(&written, buf + 10, 5, instance) == ltm_err_done); + TEST_CHECK(written == 3); + TEST_CHECK(strncmp(buf, "Hello, World!", 13) == 0); + TEST_DUMP("buf", buf, 13); ltm_instance_free(instance); ltm_template_free(template);