M .gitignore => .gitignore +2 -2
@@ 2,6 2,6 @@
/mkpage.o
/out
/darkhttpd*
+/tmp
+/aggregate
-/kethel.db
-/stage.sql
M Makefile => Makefile +15 -16
@@ 3,18 3,9 @@ CFLAGS=-Wall -Wextra -Werror -pedantic -O2 -std=c99
DEVSERVER='https://raw.githubusercontent.com/emikulic/darkhttpd/refs/heads/master/darkhttpd.c'
-.PHONY: all serve initdb commitdb
+.PHONY: all serve
-all: mkpage out/index.html out/colophon.html
-
-initdb:
- @echo "In the sql prompt, use '.read schemata.sql'"
- sqlite3 kethel.db
-
-commitdb:
- @echo "In the sql prompt, use '.read stage.sql'"
- sqlite3 kethel.db
- rm stage.sql
+all: mkpage aggregate out/index.html out/colophon.html out/thoughts.html
serve: all darkhttpd
./darkhttpd out
@@ 23,16 14,24 @@ darkhttpd:
curl $(DEVSERVER) > darkhttpd.c
$(CC) -O2 darkhttpd.c -o darkhttpd
-mkpage: mkpage.c
- $(CC) $(CFLAGS) -c mkpage.c -o mkpage.o
- $(CC) $(CFLAGS) mkpage.o -o mkpage
+mkpage: kethel2/mkpage.c
+ mkdir -p ./tmp
+ $(CC) $(CFLAGS) -c kethel2/mkpage.c -o tmp/mkpage.o
+ $(CC) $(CFLAGS) tmp/mkpage.o -o mkpage
-# list of all pages
+aggregate: kethel2/aggregate.c
+ $(CC) $(CFLAGS) -c kethel2/aggregate.c -o tmp/aggregate.o
+ $(CC) $(CFLAGS) tmp/aggregate.o -o aggregate
+
+# list of all pages
out/index.html: index.html
./mkpage index.html out/index.html
out/colophon.html: colophon.html
./mkpage colophon.html out/colophon.html
-out/thoughts/index.html: kethel.db
+out/thoughts.html: thoughts/data.tsv thoughts/item.html thoughts/index.html
+ mkdir -p ./tmp
+ ./aggregate thoughts/data.tsv thoughts/item.html thoughts/index.html tmp/thoughts.o.html
+ ./mkpage tmp/thoughts.o.html out/thoughts.html
D contrib/mkthought => contrib/mkthought +0 -8
@@ 1,8 0,0 @@
-#!/usr/bin/env bash
-
-echo -n "Title: "
-TITLE=$(cat)
-echo -n "Body: "
-BODY=$(cat)
-
-echo "INSERT INTO thoughts VALUES('$TITLE', '$BODY', '$(date "+%Y-%m-%d %H:%M:%S")');" >> ./stage.sql
M include/stdhead.html => include/stdhead.html +8 -1
@@ 1,3 1,10 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
-<style> p { width: max(50vw, 60rem); } </style>
+<style>
+p { width: max(50vw, 60rem); }
+blockquote { margin: 1em 0; }
+figcaption {
+ font-style: italic;
+ margin-left: 1em;
+}
+</style>
M include/stdnav.html => include/stdnav.html +1 -1
@@ 4,7 4,7 @@
<nav style="display: inline">
<a href="/">root</a> |
<a href="/blog/index.html">macroblog</a> |
- <a href="/thoughts/index.html">microblog</a> |
+ <a href="/thoughts.html">microblog</a> |
<a href="/review/index.html">media</a> |
</nav>
</header>
A kethel2/aggregate.c => kethel2/aggregate.c +136 -0
@@ 0,0 1,136 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char* read_to_string(const char* path) {
+ FILE* f = fopen(path, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "Failed to open %s in `rb` mode", path);
+ return NULL;
+ }
+ fseek(f, 0, SEEK_END);
+ unsigned long fileSize = ftell(f);
+ char* data = malloc(fileSize);
+ fseek(f, 0, SEEK_SET);
+ if (fread(data, fileSize, 1, f) <= 0) {
+ free(data);
+ fclose(f);
+ return NULL;
+ }
+ fclose(f);
+ return data;
+}
+
+int strfind(const char* haystack, char needle) {
+ int i = 1;
+ while ((haystack[i]) != needle) {
+ if (haystack[i] == '\0') return 0;
+ i++;
+ }
+ return i;
+}
+
+void write_item_data(char* restrict row, const char* restrict template, FILE* out) {
+ char* tok = strtok(row, "\t");
+ // TODO: generalise this
+ const char* pref = "thought-";
+ char* label = malloc(strlen(pref) + strlen(tok) + 2);
+ sprintf(label, "%s%s", pref, tok);
+ char* data[8];
+ data[0] = label;
+ int i = 1;
+ tok = strtok(NULL, "\t");
+ while (tok != NULL) {
+ data[i] = malloc(strlen(tok) + 1);
+ strcpy(data[i], tok);
+ tok = strtok(NULL, "\t");
+ i++;
+ }
+ int dataItems = i;
+ int lineSize = strfind(template, '\n');
+ int bufSize = lineSize + 1;
+ char* templateLine = malloc(bufSize);
+ strncpy(templateLine, template, lineSize);
+ int nextLine = lineSize;
+
+ const char magic[] = "<!-- ANCHOR";
+ if (strncmp(templateLine, magic, sizeof(magic) - 1) != 0) {
+ fprintf(stderr, "ERR: Invalid template provided!\n");
+ fprintf(stderr, "<template>:%i: %s\n", 1, templateLine);
+ return;
+ }
+ char* tagName = (templateLine + sizeof(magic));
+ tagName[strfind(tagName, ' ')] = '\0';
+ fprintf(out, "<%s id=\"%s\">\n", tagName, data[0]);
+ fflush(out);
+ int needlePos = strfind(template + nextLine, '\n');
+ while (needlePos != 0) {
+ if (bufSize <= needlePos) {
+ templateLine = realloc(templateLine, needlePos + 1);
+ }
+ strncpy(templateLine, template+nextLine+1, needlePos);
+ templateLine[needlePos] = '\0';
+ if (strncmp(templateLine, "<!-- PUT", strlen("<!-- PUT") - 1) == 0) {
+ // double digits are soo last year
+ int offset = strlen("<!-- PUT ");
+ unsigned char idx = templateLine[offset] - 0x30;
+ fputs(data[idx], out);
+ } else {
+ fputs(templateLine, out);
+ }
+ nextLine += needlePos;
+ needlePos = strfind(template + nextLine, '\n');
+ }
+
+ free(templateLine);
+ for (int i = 0; i < dataItems; i++) {
+ free(data[i]);
+ }
+
+ return;
+}
+
+/// aggregate - aggregates csv files into index.html, based on
+/// 1. the first csv element DESC. i.e. id #1 is the first, id #7 the latest
+/// 2. a schema, usually a <p> tag with replacers for csv items with idx > 0
+int main(int argc, char* argv[]) {
+ if (argc <= 4) {
+ fputs("usage: aggregate <data.csv> <item.html> <index.html> <output.html>\n", stderr);
+ return -1;
+ }
+
+ FILE* data = fopen(argv[1], "r");
+ char* itemTemplate = read_to_string(argv[2]);
+ FILE* index = fopen(argv[3], "r");
+ FILE* output = fopen(argv[4], "w");
+ char buf[512];
+ while (fgets(buf, sizeof(buf), index) != NULL) {
+ if (strncmp(buf, "<!-- PUT", 7) == 0) {
+ break;
+ } else {
+ fputs(buf, output);
+ }
+ }
+
+ if (fgets(buf, sizeof(buf), data) == NULL) {
+ fprintf(stderr, "could not read tsv header, bailing");
+ fclose(data);
+ free(itemTemplate);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), data) != NULL) {
+ write_item_data(buf, itemTemplate, output);
+ }
+
+ while (fgets(buf, sizeof(buf), index) != NULL) {
+ fputs(buf, output);
+ }
+
+ fclose(data);
+ fclose(index);
+ fclose(output);
+ free(itemTemplate);
+
+ return 0;
+}
R mkpage.c => kethel2/mkpage.c +11 -3
@@ 7,17 7,18 @@ int main(int argc, char* argv[]) {
if (argc <= 2) {
fprintf(stderr, "Usage: ./mkpage <input> <output>\n");
}
- FILE* input = fopen(argv[1], "r");
+ FILE* input = fopen(argv[1], "rb");
if (input == NULL) {
fprintf(stderr, "mkpage: fopen: %s does not exist!\n", argv[1]);
return -1;
}
FILE* output = fopen(argv[2], "w");
if (output == NULL) {
- fprintf(stderr, "mkpage: fopen: could not open %s for writing\n", argv[1]);
+ fprintf(stderr, "mkpage: fopen: could not open %s for writing\n", argv[2]);
fclose(input);
return -1;
}
+
uintptr_t lineno = 0;
char buf[256]; // ! NOTE: lines longer than 255 chars do not process correctly
@@ 49,7 50,14 @@ int main(int argc, char* argv[]) {
long file_size = ftell(load);
fseek(load, 0, SEEK_SET);
char* readBuf = malloc(file_size);
- fread(readBuf, file_size, 1, load);
+ size_t bytesRead = fread(readBuf, file_size, 1, load);
+ if (bytesRead <= 0) {
+ fputs("Failed to read from LOADed file\n", stderr);
+ fclose(load);
+ fclose(input);
+ fclose(output);
+ return -1;
+ }
fputs(readBuf, output);
free(readBuf);
fclose(load);
D schemata.sql => schemata.sql +0 -5
@@ 1,5 0,0 @@
-CREATE TABLE Thoughts (
- title VARCHAR(64),
- body TEXT,
- date TEXT
-);
A thoughts/data.tsv => thoughts/data.tsv +2 -0
@@ 0,0 1,2 @@
+rowid BODY AUTHOR DATE
+0 why are lecture halls always at an insane angle, while if you're at a concert (or other theatre show for that matter) the seats barely climb up ,, big lecture hall please contact me, mika 2026-09-14 17:40:58
A thoughts/index.html => thoughts/index.html +15 -0
@@ 0,0 1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+<!--LOAD include/stdhead.html -->
+ <title>microblog - m1kadev.nl</title>
+ </head>
+
+ <body>
+<!--LOAD include/stdnav.html -->
+ <main>
+<!-- PUT -->
+ </main>
+<!--LOAD include/stdfooter.html -->
+ </body>
+</html>
A thoughts/item.html => thoughts/item.html +10 -0
@@ 0,0 1,10 @@
+<!-- ANCHOR figure -->
+<blockquote>
+<!-- PUT 1 -->
+</blockquote>
+<figcaption>
+<!-- PUT 2 -->
+, at
+<!-- PUT 3 -->
+</figcaption>
+</figure>