feat(ltm): add file data support
parent
c26c8cf18a
commit
f37cfc30af
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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],
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue