aboutsummaryrefslogtreecommitdiff
path: root/src/template.c
diff options
context:
space:
mode:
authorYaroslav de la Peña Smirnov <yps@yaroslavps.com>2021-11-07 00:59:26 +0300
committerYaroslav de la Peña Smirnov <yps@yaroslavps.com>2021-11-07 00:59:26 +0300
commit8a5405629f7dcbc2504ac55f57775180a011b846 (patch)
treed5009f3bce187a92386148b633b59787d6499244 /src/template.c
parent33bdfde2be7e1c568d5e12ad1b27b7023dbd1b1b (diff)
downloadunja-8a5405629f7dcbc2504ac55f57775180a011b846.tar.gz
unja-8a5405629f7dcbc2504ac55f57775180a011b846.zip
Fixes and improvements
* Fix heap corruption on buffer growth. * Define as static functions that are not used outside a TU. * Other minor changes.
Diffstat (limited to 'src/template.c')
-rw-r--r--src/template.c158
1 files changed, 114 insertions, 44 deletions
diff --git a/src/template.c b/src/template.c
index a92edd6..f73ca1d 100644
--- a/src/template.c
+++ b/src/template.c
@@ -44,22 +44,34 @@ struct template {
};
/* ensure buffer has room for a string sized l, grows buffer capacity if needed */
-void buffer_reserve(struct buffer *buf, int l) {
+static void
+buffer_reserve(struct buffer *buf, size_t l)
+{
int req_size = buf->size + l;
if (req_size >= buf->cap) {
while (req_size >= buf->cap) {
buf->cap *= 2;
}
- buf->string = realloc(buf->string, buf->cap * sizeof *buf->string);
+ buf->string = realloc(buf->string, buf->cap);
if (!buf->string) {
errx(EXIT_FAILURE, "out of memory");
}
}
}
+static void
+buffer_cat(struct buffer *buf, const char *str)
+{
+ size_t l = strlen(str);
+ buffer_reserve(buf, l);
+ strcat(buf->string, str);
+ buf->size += l;
+}
-mpc_parser_t *parser_init() {
+static mpc_parser_t *
+parser_init()
+{
static mpc_parser_t *template;
if (template != NULL) {
return template;
@@ -144,7 +156,9 @@ mpc_parser_t *parser_init() {
return template;
}
-mpc_ast_t *parse(char *tmpl) {
+static mpc_ast_t *
+parse(char *tmpl)
+{
mpc_parser_t *parser = parser_init();
mpc_result_t r;
@@ -158,7 +172,9 @@ mpc_ast_t *parse(char *tmpl) {
return r.output;
}
-struct hashmap *find_blocks_in_ast(mpc_ast_t *node, struct hashmap *map) {
+static struct hashmap *
+find_blocks_in_ast(mpc_ast_t *node, struct hashmap *map)
+{
if (strstr(node->tag, "content|statement|block")) {
char *name = node->children[2]->contents;
hashmap_insert(map, name, node);
@@ -171,17 +187,19 @@ struct hashmap *find_blocks_in_ast(mpc_ast_t *node, struct hashmap *map) {
return map;
}
-struct env *env_new(char *dirname) {
+struct env *
+env_new(const char *dirname)
+{
/* store current working dir so we can revert to it after reading templates */
char working_dir[256];
getcwd(working_dir, 255);
DIR *dr = opendir(dirname);
- if (dr == NULL) {
- errx(EXIT_FAILURE, "could not open directory \"%s\"", dirname);
- }
+ if (dr == NULL) return NULL;
struct env *env = malloc(sizeof *env);
+ if (env == NULL) return NULL;
+
env->templates = hashmap_new();
chdir(dirname);
@@ -221,21 +239,27 @@ struct env *env_new(char *dirname) {
return env;
}
-void template_free(void *v) {
- struct template *t = (struct template *)v;
+static void
+template_free(const void *k, void *v)
+{
+ struct template *t = v;
hashmap_free(t->blocks);
mpc_ast_delete(t->ast);
free(t->name);
free(t);
}
-void env_free(struct env *env) {
+void
+env_free(struct env *env)
+{
hashmap_walk(env->templates, template_free);
hashmap_free(env->templates);
free(env);
}
-char *read_file(char *filename) {
+char *
+read_file(char *filename)
+{
char *input = malloc(BUFSIZ);
unsigned int size = 0;
@@ -256,14 +280,18 @@ char *read_file(char *filename) {
return input;
}
-char *trim_trailing_whitespace(char *str) {
+static char *
+trim_trailing_whitespace(char *str)
+{
for (int i=strlen(str)-1; i >= 0 && isspace(str[i]); i--) {
str[i] = '\0';
}
return str;
}
-char *trim_leading_whitespace(char *str) {
+static char *
+trim_leading_whitespace(char *str)
+{
while (isspace(*str)) {
str++;
}
@@ -271,7 +299,9 @@ char *trim_leading_whitespace(char *str) {
return str;
}
-struct unja_object *make_string_object(char *value, char *value2) {
+static struct unja_object *
+make_string_object(char *value, char *value2)
+{
struct unja_object *obj = malloc(sizeof *obj);
obj->type = OBJ_STRING;
int l = strlen(value) + 1;
@@ -290,7 +320,9 @@ struct unja_object *make_string_object(char *value, char *value2) {
return obj;
}
-struct unja_object *make_int_object(int value) {
+static struct unja_object *
+make_int_object(int value)
+{
struct unja_object *obj = malloc(sizeof *obj);
obj->type = OBJ_INT;
obj->integer = value;
@@ -298,25 +330,27 @@ struct unja_object *make_int_object(int value) {
}
-void eval_object(struct buffer *buf, struct unja_object *obj) {
+static void
+eval_object(struct buffer *buf, struct unja_object *obj)
+{
char tmp[64];
switch (obj->type) {
case OBJ_NULL:
break;
case OBJ_STRING:
- buffer_reserve(buf, strlen(obj->string));
- strcat(buf->string, obj->string);
+ buffer_cat(buf, obj->string);
break;
case OBJ_INT:
sprintf(tmp, "%d", obj->integer);
- buffer_reserve(buf, strlen(tmp));
- strcat(buf->string, tmp);
+ buffer_cat(buf, tmp);
break;
}
}
-int object_to_int(struct unja_object *obj) {
+static int
+object_to_int(struct unja_object *obj)
+{
switch (obj->type) {
case OBJ_NULL: return 0;
case OBJ_STRING: return atoi(obj->string);
@@ -326,7 +360,9 @@ int object_to_int(struct unja_object *obj) {
return 0;
}
-void object_free(struct unja_object *obj) {
+static void
+object_free(struct unja_object *obj)
+{
switch(obj->type) {
case OBJ_NULL: return;
case OBJ_STRING:
@@ -338,7 +374,9 @@ void object_free(struct unja_object *obj) {
free(obj);
}
-int object_is_truthy(struct unja_object *obj) {
+static int
+object_is_truthy(struct unja_object *obj)
+{
switch (obj->type) {
case OBJ_NULL: return 0;
case OBJ_STRING: return strlen(obj->string) > 0 && strcmp(obj->string, "0") != 0;
@@ -355,7 +393,9 @@ struct context {
struct template *current_template;
};
-struct unja_object *eval_expression_value(mpc_ast_t* node, struct context *ctx) {
+static struct unja_object *
+eval_expression_value(mpc_ast_t* node, struct context *ctx)
+{
if (strstr(node->tag, "symbol|")) {
/* Return empty string if no vars were passed. Should probably signal error here. */
if (ctx->vars == NULL) {
@@ -380,7 +420,9 @@ struct unja_object *eval_expression_value(mpc_ast_t* node, struct context *ctx)
return &null_object;
}
-struct unja_object *eval_string_infix_expression(struct unja_object *left, char *op, struct unja_object *right) {
+static struct unja_object *
+eval_string_infix_expression(struct unja_object *left, char *op, struct unja_object *right)
+{
struct unja_object *result;
if (strcmp(op, "+") == 0) {
@@ -398,7 +440,9 @@ struct unja_object *eval_string_infix_expression(struct unja_object *left, char
return result;
}
-struct unja_object *eval_infix_expression(struct unja_object *left, char *op, struct unja_object *right) {
+static struct unja_object *
+eval_infix_expression(struct unja_object *left, char *op, struct unja_object *right)
+{
/* if operator is + and either left or right node is of type string: concat */
if (left->type == OBJ_STRING && right->type == OBJ_STRING) {
return eval_string_infix_expression(left, op, right);
@@ -446,7 +490,9 @@ struct unja_object *eval_infix_expression(struct unja_object *left, char *op, st
return make_int_object(result);
}
-struct unja_object *eval_expression(mpc_ast_t* expr, struct context *ctx) {
+static struct unja_object *
+eval_expression(mpc_ast_t* expr, struct context *ctx)
+{
/* singular term */
if (expr->children_num == 0 || strstr(expr->tag, "string|")) {
@@ -495,7 +541,9 @@ struct unja_object *eval_expression(mpc_ast_t* expr, struct context *ctx) {
}
-int eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx) {
+static int
+eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx)
+{
static int trim_whitespace = 0;
// maybe eat whitespace going backward
@@ -510,8 +558,7 @@ int eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx) {
trim_whitespace = 0;
}
- buffer_reserve(buf, strlen(str));
- strcat(buf->string, str);
+ buffer_cat(buf, str);
return 0;
}
@@ -534,7 +581,9 @@ int eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx) {
eval(buf, t->children[4], ctx);
}
- trim_whitespace = strstr(t->children[7]->contents, "-") ? 1 : 0;
+ if (t->children_num == 8) {
+ trim_whitespace = strstr(t->children[7]->contents, "-") ? 1 : 0;
+ }
return 0;
}
@@ -627,7 +676,9 @@ int eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx) {
return 0;
}
-char *render_ast(mpc_ast_t *ast, struct context *ctx) {
+static char *
+render_ast(mpc_ast_t *ast, struct context *ctx)
+{
#if DEBUG
printf("AST: \n");
mpc_ast_print(ast);
@@ -643,14 +694,18 @@ char *render_ast(mpc_ast_t *ast, struct context *ctx) {
return buf.string;
}
-struct unja_object *filter_trim(struct unja_object *obj) {
+static struct unja_object *
+filter_trim(struct unja_object *obj)
+{
assert(obj->type == OBJ_STRING);
obj->string = trim_leading_whitespace(obj->string);
trim_trailing_whitespace(obj->string);
return obj;
}
-struct unja_object *filter_lower(struct unja_object *obj) {
+static struct unja_object *
+filter_lower(struct unja_object *obj)
+{
assert(obj->type == OBJ_STRING);
int len = strlen(obj->string);
for (int i=0; i < len; i++) {
@@ -659,7 +714,9 @@ struct unja_object *filter_lower(struct unja_object *obj) {
return obj;
}
-struct unja_object *filter_wordcount(struct unja_object *obj) {
+static struct unja_object *
+filter_wordcount(struct unja_object *obj)
+{
assert(obj->type == OBJ_STRING);
int len = strlen(obj->string);
int word_count = 1;
@@ -674,14 +731,18 @@ struct unja_object *filter_wordcount(struct unja_object *obj) {
}
-struct unja_object *filter_length(struct unja_object *obj) {
+static struct unja_object *
+filter_length(struct unja_object *obj)
+{
assert(obj->type == OBJ_STRING);
int len = strlen(obj->string);
object_free(obj);
return make_int_object(len);
}
-struct hashmap *default_filters() {
+static struct hashmap *
+default_filters()
+{
struct hashmap *filters = hashmap_new();
hashmap_insert(filters, "trim", filter_trim);
hashmap_insert(filters, "lower", filter_lower);
@@ -690,7 +751,9 @@ struct hashmap *default_filters() {
return filters;
}
-struct context context_new(struct hashmap *vars, struct env *env, struct template *current_tmpl) {
+static struct context
+context_new(struct hashmap *vars, struct env *env, struct template *current_tmpl)
+{
struct context ctx;
ctx.filters = default_filters();
ctx.vars = vars;
@@ -699,11 +762,15 @@ struct context context_new(struct hashmap *vars, struct env *env, struct templat
return ctx;
}
-void context_free(struct context ctx) {
+static void
+context_free(struct context ctx)
+{
hashmap_free(ctx.filters);
}
-char *template_string(char *tmpl, struct hashmap *vars) {
+char *
+template_string(char *tmpl, struct hashmap *vars)
+{
#if DEBUG
printf("Template: %s\n", tmpl);
#endif
@@ -715,8 +782,11 @@ char *template_string(char *tmpl, struct hashmap *vars) {
return output;
}
-char *template(struct env *env, char *template_name, struct hashmap *vars) {
+char *
+template(struct env *env, const char *template_name, struct hashmap *vars)
+{
struct template *t = hashmap_get(env->templates, template_name);
+ /* TODO: handle template not found */
#if DEBUG
printf("Template name: %s\n", t->name);
printf("Parent: %s\n", t->parent ? t->parent : "None");
@@ -739,4 +809,4 @@ char *template(struct env *env, char *template_name, struct hashmap *vars) {
char *output = render_ast(t->ast, &ctx);
context_free(ctx);
return output;
-} \ No newline at end of file
+}