feat(ltm): add file data support

ltm
Jef Roosens 2023-12-16 22:15:21 +01:00
parent c26c8cf18a
commit f37cfc30af
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
7 changed files with 86 additions and 4 deletions

View File

@ -9,14 +9,19 @@ SRCS != find '$(SRC_DIR)' -iname '*.c'
SRCS_H != find include -iname '*.h' SRCS_H != find include -iname '*.h'
SRCS_H_INTERNAL != find $(SRC_DIR) -iname '*.h' SRCS_H_INTERNAL != find $(SRC_DIR) -iname '*.h'
SRCS_TEST != find '$(TEST_DIR)' -iname '*.c' SRCS_TEST != find '$(TEST_DIR)' -iname '*.c'
SRCS_EXAMPLE != find '$(EXAMPLE_DIR)' -iname '*.c'
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
OBJS_TEST := $(SRCS_TEST:%=$(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) DEPS := $(SRCS:%=$(BUILD_DIR)/%.d) $(SRCS_TEST:%=$(BUILD_DIR)/%.d)
BINS_TEST := $(OBJS_TEST:%.c.o=%) BINS_TEST := $(OBJS_TEST:%.c.o=%)
BINS_EXAMPLE := $(OBJS_EXAMPLE:%.c.o=%)
TARGETS_TEST := $(BINS_TEST:%=test-%) TARGETS_TEST := $(BINS_TEST:%=test-%)
TARGETS_MEM_TEST := $(BINS_TEST:%=test-mem-%) TARGETS_MEM_TEST := $(BINS_TEST:%=test-mem-%)
TARGETS_EXAMPLE := $(BINS_EXAMPLE:%=test-%)
_CFLAGS := $(addprefix -I,$(INC_DIRS)) $(CFLAGS) -Wall -Wextra _CFLAGS := $(addprefix -I,$(INC_DIRS)) $(CFLAGS) -Wall -Wextra

View File

@ -3,6 +3,7 @@ LIB_FILENAME = libltm.a
BUILD_DIR = build BUILD_DIR = build
SRC_DIR = src SRC_DIR = src
TEST_DIR = test TEST_DIR = test
EXAMPLE_DIR = example
THIRDPARTY = THIRDPARTY =
PUB_INC_DIR = include 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. # 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 # -MP: generate a dummy target for every header file (according to the docs it
# prevents some errors when removing header files) # prevents some errors when removing header files)
CFLAGS ?= -MMD -MP -g CFLAGS ?= -MMD -MP -g -Wall -Werror

34
ltm/example/test.c 100644
View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include <sys/stat.h>
#include "ltm/template.h"
const char *s = "<body><pre><code>\n"
"{{ paste }}\n"
"</code></pre></body>";
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);
}

View File

@ -24,6 +24,7 @@ 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_failed_io,
ltm_err_not_found, ltm_err_not_found,
ltm_err_wrong_block_type, ltm_err_wrong_block_type,
ltm_err_done, ltm_err_done,

View File

@ -53,6 +53,8 @@ void ltm_instance_free(ltm_instance *instance);
typedef enum ltm_instance_block_type { typedef enum ltm_instance_block_type {
ltm_instance_block_type_buf = 0, ltm_instance_block_type_buf = 0,
ltm_instance_block_type_buf_owned, 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_nested,
} ltm_instance_block_type; } ltm_instance_block_type;

View File

@ -1,4 +1,5 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include "ltm/common.h" #include "ltm/common.h"
@ -41,9 +42,13 @@ void ltm_instance_free(ltm_instance *instance) {
case ltm_instance_block_type_buf_owned: case ltm_instance_block_type_buf_owned:
free(block->data.ptr); free(block->data.ptr);
break; break;
case ltm_instance_block_type_file_owned:
fclose(block->data.ptr);
break;
case ltm_instance_block_type_nested: case ltm_instance_block_type_nested:
ltm_instance_free(block->data.ptr); ltm_instance_free(block->data.ptr);
break; break;
case ltm_instance_block_type_file:
case ltm_instance_block_type_buf:; case ltm_instance_block_type_buf:;
} }
@ -204,6 +209,8 @@ size_t ltm_instance_size(const ltm_instance *instance) {
switch (block->type) { switch (block->type) {
case ltm_instance_block_type_buf: case ltm_instance_block_type_buf:
case ltm_instance_block_type_buf_owned: case ltm_instance_block_type_buf_owned:
case ltm_instance_block_type_file:
case ltm_instance_block_type_file_owned:
total += block->data.len; total += block->data.len;
break; break;
case ltm_instance_block_type_nested: 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_err ltm_instance_write(size_t *written, char *buf, size_t len,
ltm_instance *instance) { ltm_instance *instance) {
*written = 0;
while ((*written < len) && (instance->blocks.current != NULL)) { while ((*written < len) && (instance->blocks.current != NULL)) {
ltm_instance_block *current = instance->blocks.current; 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: { case ltm_instance_block_type_buf_owned: {
size_t cap = size_t cap =
LTM_MIN(current->data.len - instance->written, len - *written); 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; *written += cap;
instance->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; instance->written = 0;
} }
} break; } 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: { case ltm_instance_block_type_nested: {
size_t nested_written = 0; size_t nested_written = 0;
ltm_err res = ltm_instance_write(&nested_written, &buf[*written], ltm_err res = ltm_instance_write(&nested_written, &buf[*written],

View File

@ -18,10 +18,21 @@ void test_single_placeholder() {
TEST_CHECK(ltm_instance_size(instance) == 13); TEST_CHECK(ltm_instance_size(instance) == 13);
char buf[13]; char buf[13];
size_t written = 0; size_t written = 0;
TEST_CHECK(ltm_instance_write(&written, buf, 13, instance) == ltm_err_done); TEST_CHECK(ltm_instance_write(&written, buf, 5, instance) == ltm_err_ok);
TEST_CHECK(written == 13); 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_CHECK(strncmp(buf, "Hello, World!", 13) == 0);
TEST_DUMP("buf", buf, 13);
ltm_instance_free(instance); ltm_instance_free(instance);
ltm_template_free(template); ltm_template_free(template);