From 749cdb81da654efad8e8b54c772f4c92b7330ed7 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 28 Aug 2020 09:07:08 +0300 Subject: Refactored. --- LICENSE | 9 +++ Makefile | 15 +++++ README | 29 +++++++++ input | 3 - input.ntl | 4 ++ main.c | 182 --------------------------------------------------- tl.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tl.h | 31 +++++++++ tl_example.c | 20 ++++++ 9 files changed, 318 insertions(+), 185 deletions(-) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README delete mode 100644 input create mode 100644 input.ntl delete mode 100644 main.c create mode 100644 tl.c create mode 100644 tl.h create mode 100644 tl_example.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4921ae2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +Copyright 2020 Aleksey Veresov + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1ddb25d --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +DEBUG ?= yes + +CFLAGS = -xc -ansi -Wall +ifeq '$(DEBUG)' 'yes' +CFLAGS += -g -O0 +else +CFLAGS += -O3 +endif + +tl_example: tl_example.c tl.c + gcc $(CFLAGS) $^ -I. -o $@ + +.PHONY: clean +clean: + rm -f tl_example diff --git a/README b/README new file mode 100644 index 0000000..6715d2c --- /dev/null +++ b/README @@ -0,0 +1,29 @@ + Description +Template language made simple. + + Overview +NewbieTL is FOSS: legal info is in the 'LICENSE' file. +It is written in ANSI C without dependencies except for C standard library. +NewbieTL is a module, not a library, so it is intended to be changed +as you wish and included directly into code of your project. + + Compiling +Compilation is described in Makefile, however it is mostly about flags, +since the thing is so simple. Type 'make' to produce working example. + + Example +Example sets some data and applies the translator. +Play with input.ntl, passing it to the example as './tl_example < input.ntl'. + + Usage +Form any data you want in tl_list with tl_new, tl_named_data, +tl_named_list and tl_plain_list and pass the data into tl_translate. +It will substitute any {name} with data of name, and any +@name{body} with body repeatedly translated for each element in list of name, +so the same rules as for whole text are applied for body, +but in context extended with the element named elements. +Also you can screen characters with \, so \@ is @ in output, +however newline character will disapear, you can output it with \n. + + Motivation +Templates can be fun and simple. diff --git a/input b/input deleted file mode 100644 index 9c1f87e..0000000 --- a/input +++ /dev/null @@ -1,3 +0,0 @@ -Hello, {username}! -@articles{{title} by {author} -} diff --git a/input.ntl b/input.ntl new file mode 100644 index 0000000..b6ba135 --- /dev/null +++ b/input.ntl @@ -0,0 +1,4 @@ +Hello, {username}! + +There are several artciles for you:\ +@articles{\n{title} by {author}} diff --git a/main.c b/main.c deleted file mode 100644 index 3fe5475..0000000 --- a/main.c +++ /dev/null @@ -1,182 +0,0 @@ -#include -#include -#include - - -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; -} diff --git a/tl.c b/tl.c new file mode 100644 index 0000000..c4bfc27 --- /dev/null +++ b/tl.c @@ -0,0 +1,210 @@ +#include "tl.h" + +#include +#include +#include + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * public list functions + */ +struct tl_list *tl_new(const char *name, + const char *data, + struct tl_list *list, + struct tl_list *next) +{ + struct tl_list *res = malloc(sizeof(*res)); + res->name = name; + res->data = data; + res->list = list; + res->next = next; + return res; +} + +struct tl_list *tl_plain_list(struct tl_list *list, struct tl_list *next) +{ + return tl_new(0, 0, list, next); +} + +struct tl_list *tl_named_list(const char *name, + struct tl_list *list, + struct tl_list *next) +{ + return tl_new(name, 0, list, next); +} + +struct tl_list *tl_named_data(const char *name, + const char *data, + struct tl_list *next) +{ + return tl_new(name, data, 0, next); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * internal list functions + */ +static struct tl_list *tl_list_union(struct tl_list *a, struct tl_list *b) +{ + if (!a) return b ? tl_list_union(b, 0) : 0; + return tl_new(a->name, a->data, + tl_list_union(a->list, 0), + tl_list_union(a->next, b)); +} + +static struct tl_list *tl_list_get(struct tl_list *l, char *name) +{ + if (!l) return 0; + if (!strcmp(l->name, name)) return l; + return tl_list_get(l->next, name); +} + +static void tl_list_free(struct tl_list *l) +{ + if (l->list) tl_list_free(l->list); + if (l->next) tl_list_free(l->next); + free(l); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * string + */ +static int *tl_string_size(char *str) { return ((int *) str) - 2; } +static int *tl_string_len(char *str) { return ((int *) str) - 1; } + +static void tl_string_add(char **str, char c) +{ + static const int shift = 2 * sizeof(int); + if (!*str) { + *str = malloc(shift + 1); + *str += shift; + *tl_string_size(*str) = 1; + *tl_string_len(*str) = 0; + (*str)[0] = 0; + } + ++*tl_string_len(*str); + if (*tl_string_size(*str) == *tl_string_len(*str)) { + *tl_string_size(*str) *= 2; + *str = realloc(*str - shift, shift + *tl_string_size(*str)); + *str += shift; + } + (*str)[*tl_string_len(*str) - 1] = c; + (*str)[*tl_string_len(*str)] = 0; +} + +static void tl_string_free(char *str) +{ + if (str) free(str - 2 * sizeof(int)); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * template language translator as automata + */ +struct tl { + struct tl_list *variables; + char *name; + char *body; + int opened; +}; +typedef void *(*tl_state)(struct tl *t, char c); + +static void tl_free(struct tl *t) +{ + if (t->variables) tl_list_free(t->variables); + if (t->name) tl_string_free(t->name); + if (t->body) tl_string_free(t->body); +} + +static void *tl_state_text(struct tl *t, char c); +void tl_translate(struct tl_list *l) +{ + int c; + tl_state state = tl_state_text; + struct tl automata = { l, 0, 0, 0 }; + while ((c = getchar()) != EOF) { + state = state(&automata, c); + } + tl_free(&automata); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * automata states + */ +static void *tl_state_backslash(struct tl *t, char c); +static void *tl_state_at(struct tl *t, char c); +static void *tl_state_subs(struct tl *t, char c); +static void *tl_state_text(struct tl *t, char c) +{ + if (c == '\\') return tl_state_backslash; + if (c == '@') return tl_state_at; + if (c == '{') return tl_state_subs; + putchar(c); + return tl_state_text; +} + +static void *tl_state_subs(struct tl *t, char c) +{ + if (c == '}') { + struct tl_list *var = tl_list_get(t->variables, t->name); + if (var && var->data) { + printf("%s", var->data); + } + tl_string_free(t->name); + t->name = 0; + return tl_state_text; + } + tl_string_add(&t->name, c); + return tl_state_subs; +} + +static void tl_at(struct tl *t) +{ + struct tl_list *var = tl_list_get(t->variables, t->name); + for (var = var->list; var; var = var->next) { + char *c; + tl_state state = tl_state_text; + struct tl automata = { 0, 0, 0, 0 }; + automata.variables = tl_list_union(var->list, t->variables); + for (c = t->body; *c; ++c) { + state = state(&automata, *c); + } + tl_free(&automata); + } +} +static void *tl_state_body(struct tl *t, char c); +static void *tl_state_at(struct tl *t, char c) +{ + if (c == '{') return tl_state_body; + tl_string_add(&t->name, c); + return tl_state_at; +} + +static void *tl_state_body(struct tl *t, char c) +{ + if (c == '{') ++t->opened; + if (c == '}' && !t->opened--) { + tl_at(t); + t->opened = 0; + free(t->name - 8); + t->name = 0; + free(t->body - 8); + t->body = 0; + return tl_state_text; + } + tl_string_add(&t->body, c); + return tl_state_body; +} + +static void *tl_state_backslash(struct tl *t, char c) +{ + if (c == '\n') return tl_state_text; + if (c == 'n') { + putchar('\n'); + return tl_state_text; + } + putchar(c); + return tl_state_text; +} diff --git a/tl.h b/tl.h new file mode 100644 index 0000000..a80d4b1 --- /dev/null +++ b/tl.h @@ -0,0 +1,31 @@ +#ifndef NEWBIETL_INCLUDED +#define NEWBIETL_INCLUDED + + +struct tl_list { + const char *name; + const char *data; + struct tl_list *list; + struct tl_list *next; +}; + +struct tl_list *tl_new(const char *name, + const char *data, + struct tl_list *list, + struct tl_list *next); + +struct tl_list *tl_plain_list(struct tl_list *list, struct tl_list *next); + +struct tl_list *tl_named_list(const char *name, + struct tl_list *list, + struct tl_list *next); + +struct tl_list *tl_named_data(const char *name, + const char *data, + struct tl_list *next); + + +void tl_translate(struct tl_list *l); + + +#endif diff --git a/tl_example.c b/tl_example.c new file mode 100644 index 0000000..b8f9779 --- /dev/null +++ b/tl_example.c @@ -0,0 +1,20 @@ +#include + + +int main() +{ + struct tl_list *l = + tl_named_data("username", "aversey", + tl_named_list("articles", + tl_plain_list( + tl_named_data("title", "Substitution Processes", + tl_named_data("author", "Edsger Dijkstra", 0)), + tl_plain_list( + tl_named_data("title", "NewbieTL", + tl_named_data("author", "Aleksey Veresov", 0)), + tl_plain_list( + tl_named_data("title", "Bullshit", + tl_named_data("author", "Ongo Gablogian", 0)), 0))), 0)); + tl_translate(l); + return 0; +} -- cgit v1.2.3