~mika/kethel2

55265d4f444ab0c9c8768cd9260de3711332cd59 — mika a month ago 1a34c65
atom feed support
8 files changed, 111 insertions(+), 61 deletions(-)

M .gitignore
M Makefile
D atom.xml
A feed.atom
M kethel2/aggregate.c
M kethel2/mkpage.c
M thoughts/data.tsv
A thoughts/feed.html
M .gitignore => .gitignore +1 -1
@@ 4,5 4,5 @@
/aggregate

/out/**/*
/tmp/**/*
/obj/**/*
/publish

M Makefile => Makefile +22 -10
@@ 11,38 11,50 @@ serve: all darkhttpd
	./darkhttpd out

darkhttpd:
	@mkdir -p out obj
	curl $(DEVSERVER) > darkhttpd.c
	$(CC) -O2 darkhttpd.c -o darkhttpd

mkpage: kethel2/mkpage.c include/stdhead.html include/stdnav.html include/stdfooter.html
	mkdir -p ./tmp
	$(CC) $(CFLAGS) -c kethel2/mkpage.c -o tmp/mkpage.o
	$(CC) $(CFLAGS) tmp/mkpage.o -o mkpage
	@mkdir -p out obj
	$(CC) $(CFLAGS) -c kethel2/mkpage.c -o obj/mkpage.o
	$(CC) $(CFLAGS) obj/mkpage.o -o mkpage

aggregate: kethel2/aggregate.c
	$(CC) $(CFLAGS) -c kethel2/aggregate.c -o tmp/aggregate.o
	$(CC) $(CFLAGS) tmp/aggregate.o -o aggregate
	@mkdir -p out obj
	$(CC) $(CFLAGS) -c kethel2/aggregate.c -o obj/aggregate.o
	$(CC) $(CFLAGS) obj/aggregate.o -o aggregate

# TODO: manage statics in a better way than `cp -r`
#static:
#	cp -r static out/static

# list of all pages
pages: out/index.html out/colophon.html out/thoughts.html out/blog/index.html out/blog/helloworld.html static
pages: out/index.html out/colophon.html out/thoughts.html out/blog/index.html out/blog/helloworld.html out/feed.atom

out/index.html: index.html mkpage
	@mkdir -p out
	./mkpage index.html out/index.html

out/colophon.html: colophon.html mkpage
	@mkdir -p out
	./mkpage colophon.html out/colophon.html

out/thoughts.html: thoughts/data.tsv thoughts/item.html thoughts/index.html aggregate mkpage
	./aggregate thoughts/data.tsv thoughts/item.html thoughts/index.html tmp/thoughts.o.html
	./mkpage tmp/thoughts.o.html out/thoughts.html
	@mkdir -p out obj
	./aggregate thoughts/data.tsv thoughts/item.html thoughts/index.html obj/thoughts.o.html
	./mkpage obj/thoughts.o.html out/thoughts.html

out/blog/index.html: blog/data.tsv blog/index.html blog/item.html aggregate mkpage
	./aggregate blog/data.tsv blog/item.html blog/index.html tmp/blogroll.o.html
	./mkpage tmp/blogroll.o.html out/blog/index.html
	@mkdir -p out obj
	./aggregate blog/data.tsv blog/item.html blog/index.html obj/blogroll.o.html
	./mkpage obj/blogroll.o.html out/blog/index.html

out/blog/helloworld.html: blog/helloworld.html mkpage
	@mkdir -p out
	./mkpage blog/helloworld.html out/blog/helloworld.html

out/feed.atom: thoughts/data.tsv
	@mkdir -p out obj
	./aggregate thoughts/data.tsv thoughts/feed.html NONE obj/thoughts.o.atom
	./mkpage feed.atom out/feed.atom

D atom.xml => atom.xml +0 -20
@@ 1,20 0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3c.org/2005/Atom">

	<title>mikadev.nl</title>
	<link href="https://www.m1kadev.nl/" />
	<updated>
<!-- RDATE -->
	</updated>
	<author>
		<name>mika</name>
		<uri>https://m1kadev.nl/me.html</uri>
	</author>
	<id>tag:february.m1kadev.nl,2026/www/feed#atom</id>
	<generator>
		mkpage.c
	</generator>

<!-- PUT -->

</feed>

A feed.atom => feed.atom +20 -0
@@ 0,0 1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title type="text">m1kaposting</title>
    <subtitle type="text">
        the greatest &lt;entry&gt; items of a generation
    </subtitle>
	<link rel="alternate" type="text/html" hreflang="en" href="https://www.m1kadev.nl/" />
	<link rel="self" type="application/atom+xml" href="https://www.m1kadev.nl/feed.atom" />
	<rights>Mika 2026, CC-BY-4.0</rights>
	<author>
		<name>mika</name>
		<uri>https://m1kadev.nl/me.html</uri>
	</author>
	<id>tag:february.m1kadev.nl,2026:feed</id>
	<generator uri="https://src.m1kadev.nl/~mika/kethel2/tree/main/item/kethel2" version="2">
	    Kethel 2
	</generator>
<!--STAMP -->
<!--LOAD obj/thoughts.o.atom -->
</feed>

M kethel2/aggregate.c => kethel2/aggregate.c +37 -21
@@ 1,3 1,4 @@
#include <_stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


@@ 31,10 32,9 @@ int strfind(const char* haystack, char needle) {
	return i;
}

void write_item_data(char* restrict row, const char* restrict template, FILE* out) {
void write_item_data(char* restrict row, const char* restrict template, FILE* out, const char* restrict pref) {
    char prettyDate[64];
	char* tok = strtok(row, "\t");
	const char* pref = "item-";
	char* label = malloc(strlen(pref) + strlen(tok) + 2);
	sprintf(label, "%s%s", pref, tok);
	char* data[8];


@@ 44,7 44,6 @@ void write_item_data(char* restrict row, const char* restrict template, FILE* ou
	struct tm bdate;
	strptime(date, "%Y-%m-%dT%H:%M:%S%z", &bdate);
	strftime(prettyDate, 64, "%H:%M", &bdate);
	//fprintf(stderr, "%s\n", prettyDate);

	tok = strtok(NULL, "\t");
	while (tok != NULL) {


@@ 62,14 61,16 @@ void write_item_data(char* restrict row, const char* restrict template, FILE* ou

	const char magic[] = "<!-- ANCHOR";
	if (strncmp(templateLine, magic, sizeof(magic) - 1) != 0) {
		fprintf(stderr, "ERR: Invalid template provided!\n");
		fprintf(stderr, "WARN: Indescriminate template provided!\n");
		fprintf(stderr, "<template>:%i: %s\n", 1, templateLine);
		return;
		nextLine = -1;
	} else {
    	char* tagName = (templateLine + sizeof(magic));
    	tagName[strfind(tagName, ' ')] = '\0';
    	fprintf(out, "<%s id=\"%s\">\n", tagName, data[0]);
    	fflush(out);
	}
	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) {


@@ 86,9 87,13 @@ void write_item_data(char* restrict row, const char* restrict template, FILE* ou
		    int offset = strlen("<!-- LINK ");
			unsigned char idx = templateLine[offset] - 0x30;
			fprintf(out, "<a href=\"%s\">", data[idx]);
		} else if (strncmp(templateLine, "<!-- DATE", strlen("<!-- DATE") - 1) == 0){
		} else if (strncmp(templateLine, "<!-- DATE", strlen("<!-- DATE") - 1) == 0) {
			fputs(prettyDate, out);
	    } else {
	    } else if (strncmp(templateLine, "<!-- ATOM", strlen("<!-- ATOM") - 1) == 0) {
		    fprintf(out, "<link rel=\"alternate\" type=\"text/html\" href=\"https://m1kadev.nl/%s#%s\" />", pref, data[0]);
    	    fprintf(out, "<id>tag:february.m1kadev.nl,2026:feed/%s</id>", data[0]);
            fprintf(out, "<updated>%s</updated>", date);
		} else {
			fputs(templateLine, out);
		}
		nextLine += needlePos;


@@ 114,17 119,22 @@ int main(int argc, char* argv[]) {

	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");
	FILE* index = NULL;

	char buf[512];
	while (fgets(buf, sizeof(buf), index) != NULL) {
		if (strncmp(buf, "<!-- PUT", 7) == 0) {
			break;
		} else {
			fputs(buf, output);
		}
	if (strncmp(argv[3], "NONE", strlen("NONE")) != 0) {
    	FILE* index = fopen(argv[3], "r");
    	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);


@@ 132,18 142,24 @@ int main(int argc, char* argv[]) {
		return -1;
	}

	const char* pCname = strtok(buf, "\t");
	char* cname = malloc(strlen(pCname) + 1);
	strcpy(cname, pCname);

	while (fgets(buf, sizeof(buf), data) != NULL) {
		write_item_data(buf, itemTemplate, output);
		write_item_data(buf, itemTemplate, output, cname);
	}

	while (fgets(buf, sizeof(buf), index) != NULL) {
	while (index != NULL && fgets(buf, sizeof(buf), index) != NULL) {
		fputs(buf, output);
	}

	fclose(data);
	fclose(index);
	if (index != NULL)
	    fclose(index);
	fclose(output);
	free(itemTemplate);
	free(cname);

	return 0;
}

M kethel2/mkpage.c => kethel2/mkpage.c +17 -7
@@ 2,10 2,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int main(int argc, char* argv[]) {
    if (argc <= 2) {
        fprintf(stderr, "Usage: ./mkpage <input> <output>\n");
        return -1;
    }
    FILE* input  = fopen(argv[1], "rb");
    if (input == NULL) {


@@ 51,16 53,24 @@ int main(int argc, char* argv[]) {
                fseek(load, 0, SEEK_SET);
                char* readBuf = malloc(file_size);
                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;
		}
                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);
            } else if (strncmp(commandPtr, "STAMP", 4) == 0) {
                time_t pTime;
                time(&pTime);
                struct tm* date;
                date = gmtime(&pTime);
                char strTime[64];
                strftime(strTime, sizeof(strTime), "%Y-%m-%dT%H:%M:%SZ", date);
                fprintf(output, "<updated>%s</updated>", strTime);
            }
        } else {
            fputs(buf, output);

M thoughts/data.tsv => thoughts/data.tsv +2 -2
@@ 1,2 1,2 @@
rowid	bdate	BODY	AUTHOR
0	2026-09-15T16:31:15+02:00	we always call it the 'fridge',, Howevere, why do we not call outside the 'warmdge' ?	mika
thought	bdate	BODY	AUTHOR
0	2026-09-15T18:31:15+02:00	we always call it the 'fridge',, Howevere, why do we not call outside the 'warmdge' ?	mika

A thoughts/feed.html => thoughts/feed.html +12 -0
@@ 0,0 1,12 @@
<entry>
    <title type="text">new thought!</title>
    <author>
        <name>m1ka</name>
        <uri>https://www.m1kadev.nl/</uri>
    </author>
    <summary>
<!-- PUT 1 -->
    </summary>
<!-- ATOMT -->

</entry>