aboutsummaryrefslogtreecommitdiffstats
path: root/ste
diff options
context:
space:
mode:
Diffstat (limited to 'ste')
-rw-r--r--ste/.gitignore3
-rw-r--r--ste/README.md48
-rw-r--r--ste/example/Makefile14
-rw-r--r--ste/example/main.c15
-rw-r--r--ste/example/tmpl.c.ste11
-rw-r--r--ste/ste.c57
6 files changed, 148 insertions, 0 deletions
diff --git a/ste/.gitignore b/ste/.gitignore
new file mode 100644
index 0000000..953abb8
--- /dev/null
+++ b/ste/.gitignore
@@ -0,0 +1,3 @@
+tmpl.c
+main
+ste
diff --git a/ste/README.md b/ste/README.md
new file mode 100644
index 0000000..680f9a4
--- /dev/null
+++ b/ste/README.md
@@ -0,0 +1,48 @@
+# Simple Template Engine for C
+The idea is stolen from [Tsoding](https://github.com/tsoding).
+
+This is a template engine for the C programming language.
+A really simple one, to be honset. To see how it works, it's best to just check
+out examples, but in a nutshell: initially, everything is a string. After `%`
+sign, it becomes C source code. basically, `%` sign acts as a flip-flop switch
+between C and text. All of the text is wrapped inside the `OUT` macro, which
+must be defined in the source code (name may be customized via command-line
+arguments). To use the code, `#include generated.c` in the middle of function
+where you need this template.
+
+# Example
+`main.c`:
+```c
+#define STRINGBUILDER_IMPLEMENTATION
+#include "stringbuilder.h" /* refer to [c_headers](https://git.twistea.su/c_headers) */
+#include <stdio.h>
+
+int main(void) {
+ jac_sb sb = jac_sb_empty();
+ #define OUT(str) jac_sb_append_buf(&sb, str)
+ #define INT(i) jac_sb_snprintf(&sb, "%i", i); /* Note the semicolon */
+ #include "tmpl.c"
+ #undef OUT
+ printf("%s\n", sb.data);
+ jac_sb_free(sb);
+ return 727;
+}
+```
+
+template file (`tmpl.c.ste`):
+```html
+<!DOCTYPE html>
+<html>
+ <body>
+ %
+ for (int i = 0; i < 10; ++i) {
+ %<p>This is paragraph number % INT(i) %</p>%
+ }
+ %
+ </body>
+</html>
+```
+
+Build: `cc ste.c -o ste && ste tmpl.c.ste && cc main.c -o main`
+
+<!--vim:tw=80-->
diff --git a/ste/example/Makefile b/ste/example/Makefile
new file mode 100644
index 0000000..f8a6ef4
--- /dev/null
+++ b/ste/example/Makefile
@@ -0,0 +1,14 @@
+
+.SUFFIXES:
+
+all: main
+
+ste: ../ste.c
+ $(CC) -o $@ $<
+
+%.c: %.c.ste ste
+ ./ste -m OUTPUT $<
+
+main: main.c tmpl.c
+ $(CC) -o $@ $<
+
diff --git a/ste/example/main.c b/ste/example/main.c
new file mode 100644
index 0000000..18850d9
--- /dev/null
+++ b/ste/example/main.c
@@ -0,0 +1,15 @@
+#define STRINGBUILDER_IMPLEMENTATION
+#include "../../include/stringbuilder.h" /* refer to [c_headers](https://git.twistea.su/c_headers) */
+#include <stdio.h>
+
+int main(void) {
+ jac_sb sb = jac_sb_empty();
+ #define OUTPUT(str) jac_sb_append_buf(&sb, str)
+ #define INTEGER(i) jac_sb_snprintf(&sb, "%i", i); /* Note the semicolon */
+ # include "tmpl.c"
+ #undef OUTPUT
+ #undef INTEGER
+ printf("%s\n", sb.data);
+ jac_sb_free(sb);
+ return 727;
+}
diff --git a/ste/example/tmpl.c.ste b/ste/example/tmpl.c.ste
new file mode 100644
index 0000000..7f486cd
--- /dev/null
+++ b/ste/example/tmpl.c.ste
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ %
+ for (int i = 0; i < 10; ++i) {
+ %<p>This is paragraph number % INTEGER(i) %</p>%
+ }
+ %
+ </body>
+</html>
+
diff --git a/ste/ste.c b/ste/ste.c
new file mode 100644
index 0000000..43252b9
--- /dev/null
+++ b/ste/ste.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+
+void process_files(FILE* in, FILE* out, const char *macro) {
+ enum {MODESTR = 0, MODESRC = 1} a = MODESTR;
+ fprintf(out, "%s(\"", macro);
+ for (;;) {
+ int c = fgetc(in);
+ if (feof(in)) break;
+ if (c == '%') {
+ a = !a;
+ if (a == MODESTR) fprintf(out, " %s(\"", macro);
+ else fputs("\");", out);
+ continue;
+ }
+ if (a == MODESTR) fprintf(out, "\\x%02X", c);
+ else (fputc(c, out));
+ }
+ if (a == MODESTR) fputs("\");", out);
+}
+
+int main(int argc, char **argv) {
+ const char *macro = "OUT";
+ char *filename = NULL;
+ FILE *in, *out;
+
+ if (argc < 2) {
+ usage:
+ fprintf(stderr, "Usage: %s [-m name] <file.ste>\n", *argv);
+ return 1;
+ }
+
+ for (int i = 0; i < argc; ++i) {
+ if (!strcmp("-m", argv[i])) macro = argv[++i];
+ else filename = argv[i];
+ }
+ if (!filename || strlen(filename) <= 4) goto usage;
+
+ in = fopen(filename, "r");
+ for (char *fn = filename; fn[3]; ++fn) {
+ if (!strncmp(".ste", fn, 4)) {
+ *fn = '\0';
+ break;
+ }
+ }
+ out = fopen(filename, "w");
+ if (!in || !out) {
+ perror("fopen");
+ goto usage;
+ }
+
+ process_files(in, out, macro);
+
+ fclose(in);
+ fclose(out);
+ return 0;
+}