diff options
-rw-r--r-- | input | 3 | ||||
-rw-r--r-- | main.c | 182 |
2 files changed, 185 insertions, 0 deletions
@@ -0,0 +1,3 @@ +Hello, {username}! +@articles{{title} by {author} +} @@ -0,0 +1,182 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + + +struct reus_list { + const char *name; + const char *data; + struct reus_list *list; + struct reus_list *next; +}; + +struct reus { + struct reus_list *variables; + char *name; + char *body; + int opened; +}; + +typedef void *(*reus_state)(struct reus *r, char c); + + +void reus_string_add(char **str, char c) +{ + int *header; + if (!*str) { + header = malloc(9); + *str = (char *) header + 8; + header[0] = 1; + header[1] = 0; + (*str)[0] = 0; + } else header = (int *)(*str - 8); + if (header[0] == ++header[1]) { + header = realloc(header, 8 + (header[0] <<= 1)); + *str = (char *) header + 8; + } + (*str)[header[1] - 1] = c; + (*str)[header[1]] = 0; +} + + +struct reus_list *reus_list_new(const char *name, + const char *data, + struct reus_list *list, + struct reus_list *next) +{ + struct reus_list *res = malloc(sizeof(*res)); + res->name = name; + res->data = data; + res->list = list; + res->next = next; + return res; +} + +struct reus_list *reus_list_union(struct reus_list *a, struct reus_list *b) +{ + if (!a) return b ? reus_list_union(b, 0) : 0; + return reus_list_new(a->name, a->data, + reus_list_union(a->list, 0), + reus_list_union(a->next, b)); +} + +struct reus_list *reus_list_get(struct reus_list *l, char *name) +{ + if (!l) return 0; + if (!strcmp(l->name, name)) return l; + return reus_list_get(l->next, name); +} + +void reus_list_free(struct reus_list *l) +{ + if (l->list) reus_list_free(l->list); + if (l->next) reus_list_free(l->next); + free(l); +} + + +void reus_init(struct reus *r) +{ + r->variables = 0; + r->name = 0; + r->body = 0; + r->opened = 0; +} + +void reus_free(struct reus *r) +{ + if (r->variables) reus_list_free(r->variables); + if (r->name) free(r->name - 8); + if (r->body) free(r->body - 8); +} + + +void *reus_state_at(struct reus *r, char c); +void *reus_state_subs(struct reus *r, char c); +void *reus_state_text(struct reus *r, char c) +{ + if (c == '@') return reus_state_at; + if (c == '{') return reus_state_subs; + putchar(c); + return reus_state_text; +} + +void *reus_state_subs(struct reus *r, char c) +{ + if (c == '}') { + struct reus_list *var = reus_list_get(r->variables, r->name); + if (var && var->data) { + printf("%s", var->data); + } + free(r->name - 8); + r->name = 0; + return reus_state_text; + } + reus_string_add(&r->name, c); + return reus_state_subs; +} + +void reus_at(struct reus *r) +{ + struct reus_list *var = reus_list_get(r->variables, r->name); + for (var = var->list; var; var = var->next) { + char *c; + struct reus sr; + reus_state s = reus_state_text; + reus_init(&sr); + sr.variables = reus_list_union(var->list, r->variables); + for (c = r->body; *c; ++c) { + s = s(&sr, *c); + } + reus_free(&sr); + } +} +void *reus_state_body(struct reus *r, char c); +void *reus_state_at(struct reus *r, char c) +{ + if (c == '{') return reus_state_body; + reus_string_add(&r->name, c); + return reus_state_at; +} + +void *reus_state_body(struct reus *r, char c) +{ + if (c == '{') ++r->opened; + if (c == '}' && !r->opened--) { + reus_at(r); + r->opened = 0; + free(r->name - 8); + r->name = 0; + free(r->body - 8); + r->body = 0; + return reus_state_text; + } + reus_string_add(&r->body, c); + return reus_state_body; +} + + +int main() +{ + int c; + struct reus r; + reus_state s = reus_state_text; + reus_init(&r); + r.variables = + reus_list_new("username", "aversey", 0, + reus_list_new("articles", 0, + reus_list_new(0, 0, + reus_list_new("title", "Smooth Sort", 0, + reus_list_new("author", "Edsger Dijkstra", 0, 0)), + reus_list_new(0, 0, + reus_list_new("title", "Your Own Site", 0, + reus_list_new("author", "Aleksey Veresov", 0, 0)), + reus_list_new(0, 0, + reus_list_new("title", "Bullshit", 0, + reus_list_new("author", "Ongo Gablogian", 0, 0)), 0))), 0)); + while ((c = getchar()) != EOF) { + s = s(&r, c); + } + reus_free(&r); + return 0; +} |