", out);
- writeescaped(data + start, end - start, out);
- fputs("", out);
- return end + ticklen;
-}
-
-static int writelink(char *data, int i, size_t len, FILE *out) {
- int textstart, textend, titlestart, titleend, linkstart, linkend;
- i = getlinkinfo(data, i, len, &textstart, &textend,
- &titlestart, &titleend,
- &linkstart, &linkend);
- if (i < 0)
- return -1;
- fputs("= 0) {
- fputs(" title='", out);
- writeescaped(data + titlestart, titleend - titlestart, out);
- fputc('\'', out);
- }
- fputc('>', out);
- writeescaped(data + textstart, textend - textstart, out);
- fputs("", out);
- return i;
-}
-
-static int writeimage(char *data, int i, size_t len, FILE *out) {
- int textstart, textend, titlestart, titleend, linkstart, linkend;
- if (data[i++] != '!')
- return -1;
- i = getlinkinfo(data, i, len, &textstart, &textend,
- &titlestart, &titleend,
- &linkstart, &linkend);
- if (i < 0)
- return -1;
- fputs("Chapter 1
", out);
- currstate->prev.type = FENCECODE;
- currstate->isfirst = 1;
- currstate->intensity = type.data.intensity;
- break;
- case SPACECODE:
- if (currstate->prev.type != SPACECODE) {
- endpara(currstate, out);
- currstate->prev.type = SPACECODE;
- fputs("", out);
- }
- else
- fputs("
", out);
- fputs(realcontent(line, &type), out);
- break;
- case HEADER:
- endpara(currstate, out);
- fprintf(out, "", type.data.intensity);
- writeline(realcontent(line, &type), out);
- fprintf(out, " ", type.data.intensity);
- currstate->prev.type = EMPTY;
- break;
- case HTMLCONCRETE:
- handlehtmlcase(&type, currstate, line, out);
- break;
- case COMMENTLONG:
- handlehtmlcase(&type, currstate, line, out);
- break;
- case PHP:
- handlehtmlcase(&type, currstate, line, out);
- break;
- case COMMENTSHORT:
- handlehtmlcase(&type, currstate, line, out);
- break;
- case CDATA:
- handlehtmlcase(&type, currstate, line, out);
- break;
- case SKELETON:
- handlehtmlcase(&type, currstate, line, out);
- break;
- case GENERICTAG:
- handlehtmlcase(&type, currstate, line, out);
- break;
- }
- return 0;
-}
-
-static int endpara(struct parsestate *state, FILE *out) {
- switch (state->prev.type) {
- case EMPTY: case HR:
- case HTMLCONCRETE: case COMMENTLONG: case PHP: case COMMENTSHORT:
- case CDATA: case SKELETON: case GENERICTAG:
- return 0;
- case PLAIN:
- fputs("", out);
- writedata(state->para->data, state->para->len, out);
- fputs("
", out);
- resetstring(state->para);
- return 0;
- case SPACECODE: case FENCECODE:
- fputs("", out);
- return 0;
- case HEADER:
- fprintf(out, "", state->prev.data.intensity);
- return 0;
- case SETEXT1:
- fputs("", out);
- break;
- case SETEXT2:
- fputs("", out);
- break;
- }
- return 1;
-}
-
-static void handlehtmlcase(struct linedata *data, struct parsestate *state,
- char *line, FILE *out) {
- endpara(state, out);
- fputs(line, out);
- fputc('\n', out);
- state->prev.type = data->type;
- if (state->prev.type == data->type && data->data.islast) {
- state->prev.type = EMPTY;
- return;
- }
-}
diff --git a/src/mdutil.c b/src/mdutil.c
deleted file mode 100644
index 40ed1bf..0000000
--- a/src/mdutil.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- ncdg - A program to help generate natechoe.dev
- Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
- */
-
-#include
-#include
-#include
-
-#include
-#include
-
-static char *truncate(char *str);
-static char *after(char *begin, char *str);
-static int isend(char *line, enum linetype prev);
-
-static char *concretetags[] = { "pre", "script", "style", "textarea" };
-static char *skeletontags[] = {
- "address", "article", "aside", "base", "basefont", "blockquote", "body",
- "caption", "center", "col", "colgroup", "dd", "details", "dialog",
- "dir", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer",
- "form", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head",
- "header", "hr", "html", "iframe", "legend", "li", "link", "main",
- "menu", "menuitem", "nav", "noframes", "ol", "optgroup", "option", "p",
- "param", "section", "source", "summary", "table", "tbody", "td",
- "tfoot", "th", "thead", "title", "tr", "track", "ul",
-};
-
-void identifyline(char *line, struct linedata *prev, struct linedata *ret) {
- int i;
- if (HTMLSTART <= prev->type && prev->type <= HTMLEND) {
- ret->type = prev->type;
- ret->data.islast = isend(truncate(line), prev->type);
- return;
- }
- if (prev->type != PLAIN) {
- for (i = 0; i < 4; ++i) {
- if (line[i] == '\t')
- break;
- if (line[i] != ' ')
- goto notspacecode;
- }
- ret->type = SPACECODE;
- return;
- }
-notspacecode:
- line = truncate(line);
- if (line[0] == '\0') {
- ret->type = EMPTY;
- return;
- }
- {
- int hrcount;
- if (strchr("-*_=", line[0]) == NULL)
- goto nothr;
- /* A delimiting line can only contain '-', '*', '_', and ' '. */
- hrcount = 0;
- for (i = 0; line[i]; ++i) {
- if (!isspace(line[i]) && line[i] != line[0])
- goto nothr;
- /* You can't mix delimiter characters, and you can't
- * have anything other than a delimiter character or
- * white space. */
- if (line[i] == line[0])
- ++hrcount;
- }
- if (hrcount >= 3) {
- switch (line[0]) {
- case '=':
- ret->type = SETEXT1;
- return;
- case '-':
- ret->type = SETEXT2;
- return;
- default:
- ret->type = HR;
- return;
- }
- }
- /* There has to be at least 3 delimiter characters */
- }
-nothr:
- for (i = 0; line[i] == '`'; ++i) ;
- if (i >= 3) {
- ret->type = FENCECODE;
- ret->data.intensity = i;
- /* The last line of a fenced code block must have at least the
- * same number of backticks as the first. */
- return;
- }
-/* notfencedcode: */
-
- if (line[0] == '#') {
- int pcount;
- for (pcount = 0; line[pcount] == '#'; ++pcount) ;
- if (line[pcount] != ' ' && line[pcount] != '\0')
- goto notheader;
- ret->type = HEADER;
- ret->data.intensity = pcount;
- return;
- }
-
-notheader:
-
-#define HTMLSTARTCASE(start, rettype) \
- if (after(start, line) != NULL) { \
- ret->type = rettype; \
- ret->data.islast = isend(line, rettype); \
- return; \
- }
- HTMLSTARTCASE("") != NULL;
- case PHP:
- return strstr(line, "?>") != NULL;
- case COMMENTSHORT:
- return strchr(line, '>') != NULL;
- case CDATA:
- return strstr(line, "]]>") != NULL;
- case SKELETON: case GENERICTAG:
- return line[0] == '\0';
- }
- return 1;
-}
diff --git a/src/parse.c b/src/parse.c
new file mode 100644
index 0000000..49587ee
--- /dev/null
+++ b/src/parse.c
@@ -0,0 +1,115 @@
+#include
+#include
+
+#include
+
+static int expandfile(struct string *expanded, char *filename, int level);
+static struct string *getstring(FILE *file, char end);
+
+int parsefile(char *template, FILE *out) {
+ struct string *expanded;
+ expanded = newstring();
+ if (expanded == NULL)
+ return 1;
+ if (expandfile(expanded, template, 0))
+ return 1;
+ fwrite(expanded->data, 1, expanded->len, stdout);
+ return 0;
+}
+
+static int expandfile(struct string *expanded, char *filename, int level) {
+ FILE *file;
+ int c, linenum;
+ file = fopen(filename, "r");
+ if (file == NULL) {
+ fprintf(stderr, "Failed to open file %s\n", filename);
+ return 1;
+ }
+ linenum = 1;
+ if (level >= MAX_INCLUDE_DEPTH) {
+ fprintf(stderr, "The include depth has reached %d, quitting\n",
+ level);
+ fclose(file);
+ return 1;
+ }
+ for (;;) {
+ c = fgetc(file);
+ switch (c) {
+ case ESCAPE_CHAR:
+ c = fgetc(file);
+ switch (c) {
+ case ESCAPE_CHAR:
+ if (appendchar(expanded, ESCAPE_CHAR))
+ goto error;
+ break;
+ case VAR_CHAR:
+ if (appendchar(expanded, ESCAPE_CHAR))
+ goto error;
+ for (;;) {
+ if (c == EOF)
+ goto error;
+ if (appendchar(expanded, c))
+ goto error;
+ if (c == ESCAPE_CHAR)
+ break;
+ c = fgetc(file);
+ }
+ break;
+ case INCLUDE_CHAR: {
+ struct string *inclname;
+ inclname = getstring(file, ESCAPE_CHAR);
+ if (inclname == NULL)
+ goto error;
+ if (expandfile(expanded, inclname->data,
+ level + 1))
+ return 1;
+ freestring(inclname);
+ break;
+ }
+ default:
+ fprintf(stderr, "Line %d: Invalid escape\n",
+ linenum);
+ goto error;
+ }
+ break;
+ case '\n':
+ ++linenum;
+ goto casedefault;
+ case EOF:
+ goto end;
+ default: casedefault:
+ if (appendchar(expanded, c))
+ goto error;
+ break;
+ }
+ }
+end:
+ fclose(file);
+ return 0;
+error:
+ fclose(file);
+ return 1;
+}
+
+static struct string *getstring(FILE *file, char end) {
+ struct string *ret;
+ int c;
+ ret = newstring();
+ if (ret == NULL)
+ return NULL;
+ for (;;) {
+ c = fgetc(file);
+ if (c == EOF)
+ goto error;
+ if (c == end) {
+ if (appendchar(ret, '\0'))
+ goto error;
+ return ret;
+ }
+ if (appendchar(ret, c))
+ goto error;
+ }
+error:
+ freestring(ret);
+ return NULL;
+}
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..8ee7f00
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,48 @@
+#include
+#include
+
+#include
+
+struct string *newstring() {
+ struct string *ret;
+ ret = malloc(sizeof *ret);
+ if (ret == NULL)
+ goto error1;
+ ret->len = 0;
+ ret->alloc = 5;
+ /* TODO: Change this to a far reasonable number */
+ ret->data = malloc(ret->alloc);
+ if (ret->data == NULL)
+ goto error2;
+ return ret;
+error2:
+ free(ret);
+error1:
+ return NULL;
+}
+
+int appendchar(struct string *string, char c) {
+ if (string->len >= string->alloc) {
+ char *newdata;
+ size_t newalloc;
+ newalloc = string->alloc;
+ while (string->len >= newalloc)
+ newalloc *= 2;
+ newdata = realloc(string->data, newalloc);
+ if (newdata == NULL)
+ return 1;
+ string->data = newdata;
+ string->alloc = newalloc;
+ }
+ string->data[string->len++] = c;
+ return 0;
+}
+
+void freestring(struct string *string) {
+ free(string->data);
+ free(string);
+}
+
+void resetstring(struct string *string) {
+ string->len = 0;
+}
diff --git a/src/util.c b/src/util.c
deleted file mode 100644
index d9dd686..0000000
--- a/src/util.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- ncdg - A program to help generate natechoe.dev
- Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
- */
-#include
-#include
-
-#include
-
-struct string *newstring() {
- struct string *ret;
- ret = malloc(sizeof *ret);
- if (ret == NULL)
- return NULL;
- ret->len = 0;
- ret->alloc = 20;
- ret->data = malloc(ret->alloc);
- if (ret->data == NULL)
- return NULL;
- return ret;
-}
-
-void freestring(struct string *str) {
- free(str->data);
- free(str);
-}
-
-int appendcharstring(struct string *str, char c) {
- if (str->len >= str->alloc) {
- char *newdata;
- size_t newalloc;
- newalloc = str->alloc * 2;
- newdata = realloc(str->data, newalloc);
- if (newdata == NULL) {
- return 1;
- }
- str->data = newdata;
- str->alloc = newalloc;
- }
- str->data[str->len++] = c;
- return 0;
-}
-
-int appendstrstring(struct string *str, char *s) {
- size_t len;
- len = strlen(s);
- if (str->len + len >= str->alloc) {
- char *newdata;
- size_t newalloc;
- newalloc = str->alloc;
- while (str->len + len >= newalloc)
- newalloc *= 2;
- newdata = realloc(str->data, newalloc);
- if (newdata == NULL)
- return 1;
- str->data = newdata;
- str->alloc = newalloc;
- }
- memcpy(str->data + str->len, s, len);
- str->len += len;
- return 0;
-}
-
-void resetstring(struct string *str) {
- str->len = 0;
-}
-
-int isctrl(int c) {
- return (0 <= c && c <= 0x1f) || c == 0x7f;
-}
-
-int ispunc(int c) {
- return strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", c) != NULL;
-}