saait

Simple static page generator
git clone https://git.sinitax.com/codemadness/saait
Log | Files | Refs | README | LICENSE | Upstream | sfeed.txt

commit ffdca76fc49e952a455ff10a449ddef03fc1ede7
parent 38b3bc3800cf2c61fe2bd2ec5e80ef65cbad4201
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sat, 26 Nov 2016 18:49:17 +0100

remove data parsing, item time, RSS feed

this simplifies the code and removes some features

Diffstat:
MMakefile | 3++-
MREADME | 4----
Mconfig.h | 7-------
Msaait.c | 249++++++-------------------------------------------------------------------------
Mtemplates/atom.xml/header.xml | 2+-
Mtemplates/atom.xml/item.xml | 4++--
Mtemplates/index.html/header.html | 2--
Mtemplates/index.html/item.html | 2+-
Mtemplates/page/header.html | 2--
Mtemplates/page/item.html | 2+-
Dtemplates/rss.xml/footer.xml | 2--
Dtemplates/rss.xml/header.xml | 7-------
Dtemplates/rss.xml/item.xml | 8--------
13 files changed, 25 insertions(+), 269 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,8 +1,9 @@ test: build + mkdir -p output ./saait build: clean - cc -ggdb saait.c -o saait -Wall -std=c99 -Wextra -pedantic + cc -ggdb saait.c -o saait -Wall -std=c99 clean: rm -f saait diff --git a/README b/README @@ -57,7 +57,3 @@ Variables: ${} escaped HTML/XML string. #{} literal string. %{} insert contents of file of variable value. - -Date format: -${value@date format} -#{value@date format} diff --git a/config.h b/config.h @@ -37,13 +37,6 @@ static struct { } }, { - .name = "rss.xml", .blocks = { - { .name = "header.xml" }, - { .name = "item.xml" }, - { .name = "footer.xml" } - } - }, - { .name = "sitemap.xml", .blocks = { { .name = "header.xml" }, { .name = "item.xml" }, diff --git a/saait.c b/saait.c @@ -8,7 +8,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> #include <unistd.h> /* string and byte-length */ @@ -98,194 +97,6 @@ efopen(const char *path, const char *mode) return fp; } -long long -datetounix(long long year, int mon, int day, int hour, int min, int sec) -{ - static const int secs_through_month[] = { - 0, 31 * 86400, 59 * 86400, 90 * 86400, - 120 * 86400, 151 * 86400, 181 * 86400, 212 * 86400, - 243 * 86400, 273 * 86400, 304 * 86400, 334 * 86400 }; - int is_leap = 0, cycles, centuries = 0, leaps = 0, rem; - long long t; - - if (year - 2ULL <= 136) { - leaps = (year - 68) >> 2; - if (!((year - 68) & 3)) { - leaps--; - is_leap = 1; - } else { - is_leap = 0; - } - t = 31536000 * (year - 70) + 86400 * leaps; - } else { - cycles = (year - 100) / 400; - rem = (year - 100) % 400; - if (rem < 0) { - cycles--; - rem += 400; - } - if (!rem) { - is_leap = 1; - } else { - if (rem >= 300) - centuries = 3, rem -= 300; - else if (rem >= 200) - centuries = 2, rem -= 200; - else if (rem >= 100) - centuries = 1, rem -= 100; - if (rem) { - leaps = rem / 4U; - rem %= 4U; - is_leap = !rem; - } - } - leaps += 97 * cycles + 24 * centuries - is_leap; - t = (year - 100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; - } - t += secs_through_month[mon]; - if (is_leap && mon >= 2) - t += 86400; - t += 86400LL * (day - 1); - t += 3600LL * hour; - t += 60LL * min; - t += sec; - - return t; -} - -/* Get timezone from string, return time offset in seconds from UTC. - * NOTE: only parses timezones in RFC-822, other timezones are ambiguous - * anyway. If needed you can add some yourself, like "cest", "cet" etc. */ -int -gettzoffset(const char *s, long *off) -{ - static struct { - char *name; - size_t len; - int offhour; - } tzones[] = { - { STRP("A"), -1 * 3600 }, - { STRP("CDT"), -5 * 3600 }, - { STRP("CST"), -6 * 3600 }, - { STRP("EDT"), -4 * 3600 }, - { STRP("EST"), -5 * 3600 }, - { STRP("GMT"), 0 }, - { STRP("M"), -2 * 3600 }, - { STRP("MDT"), -6 * 3600 }, - { STRP("MST"), -7 * 3600 }, - { STRP("N"), 1 * 3600 }, - { STRP("PDT"), -7 * 3600 }, - { STRP("PST"), -8 * 3600 }, - { STRP("UT"), 0 }, - { STRP("UTC"), 0 }, - { STRP("Y"), 12 * 3600 }, - { STRP("Z"), 0 }, - }; - const char *p; - int tzhour = 0, tzmin = 0; - size_t i, namelen; - - for (; *s && isspace((int)*s); s++) - ; - switch (*s) { - case '-': /* offset */ - case '+': - for (i = 0, p = s + 1; i < 2 && *p && isdigit(*p); i++, p++) - tzhour = (tzhour * 10) + (*p - '0'); - if (*p && !isdigit(*p)) - p++; - for (i = 0; i < 2 && *p && isdigit(*p); i++, p++) - tzmin = (tzmin * 10) + (*p - '0'); - *off = ((tzhour * 3600) + (tzmin * 60)) * (s[0] == '-' ? -1 : 1); - return 1; - default: /* timezone name */ - for (i = 0; *s && isalpha((int)s[i]); i++) - ; - namelen = i; /* end of name */ - /* optimization: these are always non-matching */ - if (namelen < 1 || namelen > 3) - return 0; - /* compare tz and adjust offset relative to UTC */ - for (i = 0; i < LEN(tzones); i++) { - if (tzones[i].len == namelen && - !strncmp(s, tzones[i].name, namelen)) { - *off = tzones[i].offhour; - return 1; - } - } - } - return 0; -} - -int -parsetime(const char *s, time_t *tp, struct tm *tm, long *tzoff) -{ - const char *end = NULL; - int va[6] = { 0 }, i, v, vi; - long long l; - long off = 0; - struct tm tmp; - time_t t; - - for (; *s && isspace((int)*s); s++) - ; - if (!isdigit((int)*s)) - return -1; - - /* format "%Y-%m-%d %H:%M:%S" or "%Y-%m-%dT%H:%M:%S" */ - vi = 0; - for (; *s && vi < 6; vi++) { - for (i = 0, v = 0; *s && i < 4 && isdigit((int)*s); s++, i++) - v = (v * 10) + (*s - '0'); - va[vi] = v; - if ((vi < 2 && *s == '-') || - (vi == 2 && (*s == 'T' || isspace((int)*s))) || - (vi > 2 && *s == ':')) - s++; - } - /* TODO: only if seconds are parsed (vi == 5)? */ - /* skip milliseconds for: %Y-%m-%dT%H:%M:%S.000Z */ - if (*s == '.') { - for (s++; *s && isdigit((int)*s); s++) - ; - } - end = s; - - /* invalid range */ - if (va[0] < 0 || va[0] > 9999 || - va[1] < 1 || va[1] > 12 || - va[2] < 1 || va[2] > 31 || - va[3] < 0 || va[3] > 23 || - va[4] < 0 || va[4] > 59 || - va[5] < 0 || va[5] > 59) - return -1; - - l = datetounix(va[0] - 1900, va[1] - 1, va[2], va[3], va[4], va[5]); - t = (time_t)l; /* TODO: bug if sizeof(time_t) != sizeof(long long) ? */ - - /* if no timezone found use localtime */ - if (!gettzoffset(end, &off)) { - if (!localtime_r(&t, &tmp)) { - fprintf(stderr, "localtime_r: %s\n", strerror(errno)); - exit(1); - } - off = tmp.tm_gmtoff; - } - if (!gmtime_r(&t, &tmp)) { - fprintf(stderr, "gmtime_r: %s\n", strerror(errno)); - exit(1); - } - tmp.tm_gmtoff = off; - - if (tp) - *tp = l; - if (tm) - memcpy(tm, &tmp, sizeof(*tm)); - if (tzoff) - *tzoff = off; - return 0; -} - char * readfile(const char *file) { @@ -460,16 +271,14 @@ void writepage(FILE *fp, const char *filename, struct config *c, char *s) { struct variable *var, *v; - struct tm tm; - time_t t; - int op, tmp; - char *key, escape, *e, *value, outtime[256]; + char *key, escape, *e, *value; size_t keylen, line = 0; + int op; for (; *s; s++) { /* TODO: error if unterminated */ op = *s; - switch (op) { + switch (*s) { case '%': /* insert contents of filename set in variable */ case '#': /* insert value non-escaped */ case '$': /* insert value escaped */ @@ -491,11 +300,8 @@ writepage(FILE *fp, const char *filename, struct config *c, char *s) for (; *s && isspace(*s); s++) ; key = s; - for (keylen = 0; *s; s++) { - if (*s == '}' || *s == '@') - break; + for (keylen = 0; *s && *s != '}'; s++) keylen++; - } /* trim right whitespace */ for (; keylen && isspace(key[keylen - 1]); ) keylen--; @@ -533,26 +339,6 @@ writepage(FILE *fp, const char *filename, struct config *c, char *s) continue; } - /* format date */ - if (*s == '@') { - for (e = ++s; *e && *e != '}'; e++) - ; - - parsetime(v->value, &t, &tm, NULL); - /* temporary NUL terminate */ - tmp = *e; - *e = '\0'; - - if (!strftime(outtime, sizeof(outtime), s, &tm)) { - fprintf(stderr, "strftime: %s\n", strerror(errno)); - exit(1); - } - *e = tmp; - - value = outtime; - s = e; - } - if (escape) xmlencode(value, fp); else @@ -561,14 +347,19 @@ writepage(FILE *fp, const char *filename, struct config *c, char *s) } int -revalphasort(const struct dirent **d1, const struct dirent **d2) { +revalphasort(const struct dirent **d1, const struct dirent **d2) +{ return -alphasort(d1, d2); } int selectcfgfile(const struct dirent *d) { - return (d->d_name[0] != '.' && d->d_namlen > 4 && - !strcmp(&d->d_name[d->d_namlen - 4], ".cfg")); + size_t namelen; + + namelen = strlen(d->d_name); + + return (d->d_name[0] != '.' && namelen > 4 && + !strcmp(&d->d_name[namelen - 4], ".cfg")); } void @@ -584,8 +375,7 @@ main(int argc, char *argv[]) struct config *c; char *p, *base, *basefile, file[PATH_MAX], outputfile[PATH_MAX]; struct dirent **namelist = NULL; - int entries; - int i, j, r; + int entries, c, i, j, r; #ifdef __OpenBSD__ if (pledge("stdio cpath rpath wpath", NULL) == -1) { @@ -627,8 +417,6 @@ main(int argc, char *argv[]) } } - mkdir(outputdir, 0755); - /* header */ for (i = 0; i < LEN(templates); i++) { if (!strcmp(templates[i].name, "page")) @@ -642,7 +430,6 @@ main(int argc, char *argv[]) writepage(templates[i].fp, "", NULL, templates[i].blocks[BlockHeader].data); } - if ((entries = scandir(pagesdir, &namelist, selectcfgfile, revalphasort)) < 0) { fprintf(stderr, "scandir: %s\n", strerror(errno)); exit(1); @@ -661,11 +448,6 @@ main(int argc, char *argv[]) else base = estrdup(file); - if ((p = strrchr(base, '/'))) - basefile = estrdup(&base[p - base + 1]); - else - basefile = estrdup(base); - /* read config */ c = readconfig(file); @@ -690,6 +472,11 @@ main(int argc, char *argv[]) for (j = 0; j < LEN(templates); j++) { /* TODO: page is a special case for now */ if (!strcmp(templates[j].name, "page")) { + if ((p = strrchr(base, '/'))) + basefile = estrdup(&base[p - base + 1]); + else + basefile = estrdup(base); + /* output file */ r = snprintf(outputfile, sizeof(outputfile), "%s/%s.html", outputdir, basefile); if (r < 0 || (size_t)r >= sizeof(file)) { diff --git a/templates/atom.xml/header.xml b/templates/atom.xml/header.xml @@ -2,7 +2,7 @@ <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="${lang}"> <title type="text">${sitetitle}</title> <subtitle type="text">${description}</subtitle> - <updated>${siteupdated@%Y-%m-%dT%H:%M:%S%z}</updated> + <updated>${siteupdated}T00:00:00Z</updated> <link rel="alternate" type="text/html" href="${siteurl}" /> <id>${siteurl}/atom.xml</id> <link rel="self" type="application/atom+xml" href="${siteurl}/atom.xml" /> diff --git a/templates/atom.xml/item.xml b/templates/atom.xml/item.xml @@ -2,8 +2,8 @@ <title type="html">${title}</title> <link rel="alternate" type="text/html" href="${siteurl}/${filename}" /> <id>${siteurl}/${filename}</id> - <updated>${updated@%Y-%m-%dT%H:%M:%S%z}</updated> - <published>${created@%Y-%m-%dT%H:%M:%S%z}</published> + <updated>${updated}T00:00:00Z</updated> + <published>${created}T00:00:00Z</published> <author> <name>${author}</name> <uri>${siteurl}</uri> diff --git a/templates/index.html/header.html b/templates/index.html/header.html @@ -4,7 +4,6 @@ <title>${title} - ${sitetitle}</title> <link rel="stylesheet" href="style.css" type="text/css" media="screen" /> <link rel="stylesheet" href="print.css" type="text/css" media="print" /> - <link rel="alternate" type="application/rss+xml" title="${sitetitle} RSS Feed" href="rss.xml" /> <link rel="alternate" type="application/atom+xml" title="${sitetitle} Atom Feed" href="atom.xml" /> <link rel="icon" type="image/png" href="/favicon.png" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> @@ -24,7 +23,6 @@ </span> <span id="links-contact"> <span class="hidden"> | </span> - <a href="rss.xml" title="RSS feed">RSS</a> | <a href="atom.xml" title="Atom feed">Atom</a> | <a href="mailto:${sitemail}" title="Mail me">Mail</a> </span> diff --git a/templates/index.html/item.html b/templates/index.html/item.html @@ -1,4 +1,4 @@ <tr> - <td>${updated@%Y-%m-%d}</td> + <td>${updated}</td> <td><a href="${filename}" title="${description}">${title}</a></td> </tr> diff --git a/templates/page/header.html b/templates/page/header.html @@ -4,7 +4,6 @@ <title>${title} - ${sitetitle}</title> <link rel="stylesheet" href="style.css" type="text/css" media="screen" /> <link rel="stylesheet" href="print.css" type="text/css" media="print" /> - <link rel="alternate" type="application/rss+xml" title="${sitetitle} RSS Feed" href="rss.xml" /> <link rel="alternate" type="application/atom+xml" title="${sitetitle} Atom Feed" href="atom.xml" /> <link rel="icon" type="image/png" href="/favicon.png" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> @@ -24,7 +23,6 @@ </span> <span id="links-contact"> <span class="hidden"> | </span> - <a href="rss.xml" title="RSS feed">RSS</a> | <a href="atom.xml" title="Atom feed">Atom</a> | <a href="mailto:${sitemail}" title="Mail me">Mail</a> </span> diff --git a/templates/page/item.html b/templates/page/item.html @@ -1,3 +1,3 @@ <h1><a href="">${title}</a></h1> - <em><strong>Written:</strong> ${created@%Y-%m-%d}</em> + <em><strong>Written:</strong> ${created}</em> %{file} diff --git a/templates/rss.xml/footer.xml b/templates/rss.xml/footer.xml @@ -1,2 +0,0 @@ - </channel> -</rss> diff --git a/templates/rss.xml/header.xml b/templates/rss.xml/header.xml @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<rss version="2.0"> - <channel> - <title>${sitetitle}</title> - <link>${siteurl}</link> - <description>${description}</description> - <language>${lang}</language> diff --git a/templates/rss.xml/item.xml b/templates/rss.xml/item.xml @@ -1,8 +0,0 @@ -<item> - <title>${title}</title> - <link>${siteurl}/${filename}</link> - <pubDate>${updated@%a, %d %b %Y %H:%M:%S %z}</pubDate> - <author>${author}</author> - <guid isPermaLink="false">${siteurl}/${filename}</guid> - <description><![CDATA[${description}]]></description> -</item>