~foura/biobuf.link

ee5d8b0267591dd2a3575ab3b92b6455e99b24a8 — james palmer 17 days ago
init
10 files changed, 585 insertions(+), 0 deletions(-)

A db/index
A db/now
A media/img/001.png
A media/style.css
A mkfile
A src/list.c
A src/list.h
A src/main.c
A src/text.c
A src/text.h
A  => db/index +18 -0
@@ 1,18 @@
| desc welcome to biobuf.link
| pict 001.png a dithered view
| date 2020-09-07

& hey there, welcome to my site :)
  this wiki serves as a home for my projects, notes,
  logs and whatever else i feel like really :P
  it's compiled with a c program from a custom markup format.

* external
> https://mastodon.org/@foura mastodon
> https://sr.ht/~foura sourcehut
> mailto:james@biobuf.link email

* license
& the generator for this site is available under the mit license.
  the assets and text content are available under the
  creative commons by-nc-sa 4.0 license.

A  => db/now +9 -0
@@ 1,9 @@
| desc i am currently...
| date 2020-09-07

- programming the static site builder for this wiki
  and playing with the design and layout of the pages.
  it needs a lot of work but the data formats are done.

- procrastinating on all my other projects :/
  i have too many things i want to try.

A  => media/img/001.png +0 -0
A  => media/style.css +27 -0
@@ 1,27 @@
* { margin: 0; padding: 0; box-sizing: border-box; }

html { font-family: "Ubuntu"; }

body { max-width: 40rem; margin: 2rem; }
body > * { margin-bottom: 1.5rem; }

main { line-height: 1.4; }
main > * { margin-bottom: 1rem; width: 80%; }
main > * > * { margin-bottom: 0.5rem; }

main figure { width: 100%; }
main figure img { max-width: 100%; }

nav > * { margin-bottom: 1rem; }
nav > * > * { margin-bottom: 0.5rem; }

nav ul { list-style: none; }

a { color: black; padding: 0.1rem; }
a:hover { color: white; background: black; }

pre { padding: 1em; background: #efefef; }
pre { font-family: "Ubuntu Mono" }

::selection { color: white; background: black; }
::-moz-selection { color: white; background: black; }

A  => mkfile +27 -0
@@ 1,27 @@
</$objtype/mkfile

TARG=sitemk
HFILES=\
	src/text.h\
	src/list.h
OFILES=\
	src/main.$O\
	src/text.$O\
	src/list.$O

all:V: $TARG
	$TARG

src/%.$0: $HFILES

src/%.$O: src/%.c
	$CC $CFLAGS -o $target $prereq

$TARG: $OFILES
	$LD $LDFLAGS -o $target $prereq

clean:V:
	rm -rf src/*.[$OS] $TARG

nuke:V:
	rm -rf src/*.[$OS] out/*.html

A  => src/list.c +44 -0
@@ 1,44 @@
#include <u.h>
#include <libc.h>

#include "list.h"

void
listinit(List *l, usize sz)
{
	l->len = 0;
	l->max = sz;
	l->elem = malloc(sz * sizeof(void*));
	if(!l->elem)
		sysfatal("listinit: %r");
}

void
listgrow(List *l, usize inc)
{
	void *e;
	usize sz;

	sz = l->max;
	sz += (sz/2 < inc) ? inc : sz/2;
	e = realloc(l->elem, sz * sizeof(void*));
	if(!e)
		sysfatal("listgrow: %r");

	l->max = sz;
	l->elem = e;
}

void
listpush(List *l, void *p)
{
	if(l->len == l->max)
		listgrow(l, 1);
	l->elem[l->len++] = p;
}

void
listfree(List *l)
{
	free(l->elem);
}

A  => src/list.h +12 -0
@@ 1,12 @@
typedef struct List List;
struct List {
	usize len, max;
	void **elem;
};

void listinit(List*, usize);

void listgrow(List*, usize);
void listpush(List*, void*);

void listfree(List*);

A  => src/main.c +332 -0
@@ 1,332 @@
#include <u.h>
#include <libc.h>
#include <bio.h>

#include "text.h"
#include "list.h"

typedef struct Tag Tag;
typedef struct Page Page;

enum {
	Tmeta,
	Thead,
	Tpara,
	Timage,
	Tlink,
	Tlist,
};

struct Tag {
	char type;
	Text *url;
	Text *text;
};

struct Page {
	Text *path;

	Text *desc;
	Text *date;
	Tag *pict;

	List tags;
};

Tag*
tagalloc(char type)
{
	Tag *t;
	
	t = malloc(sizeof(Tag));
	if(!t)
		sysfatal("newtag: %r");

	t->type = type;
	t->url = txtnew();
	t->text = txtnew();

	return t;
}

Page*
pagealloc(char *name)
{
	Page *p;

	p = malloc(sizeof(Page));
	if(!p)
		sysfatal("%r");

	p->path = txtcopy(name);
	p->desc = txtnew();
	p->date = txtnew();
	p->pict = tagalloc('i');

	listinit(&p->tags, 64);

	return p;
}

void
parseurltag(Tag *t, char *text)
{
	char *s;

	s = strchr(text, ' ');
	if(!s) return;
	*s++ = 0;
	
	txtcat(t->url, text);
	txtcat(t->text, s);
}

void
parsemetatag(Page *p, char *text)
{
	char *s;

	s = strchr(text, ' ');
	if(!s) return;
	*s++ = 0;

	if(strcmp(text, "desc") == 0)
		txtcat(p->desc, s);
	if(strcmp(text, "date") == 0)
		txtcat(p->date, s);
	if(strcmp(text, "pict") == 0)
		parseurltag(p->pict, s);
}

void
parsepage(List *pages, char *name)
{
	Page *p;
	Biobuf *bio;
	char *path, *line, *text;
	usize len;
	Tag *t;

	p = pagealloc(name);
	path = smprint("db/%s", name);
	bio = Bopen(path, OREAD);
	t = nil;

	while(line = Brdstr(bio, '\n', 1)) {
		/* lines shorter than 3 cannot be valid tags */
		len = strlen(line);
		if(len < 3) {
			free(line);
			continue;
		}

		/* if we aren't continuing, push */
		if(t && line[0] != ' ') {
			listpush(&p->tags, t);
			t = nil;
		}

		text = line + 2;
		switch(line[0]) {
		case '|':
			parsemetatag(p, text);
			break;
		case 'i':
		case '>':
			t = tagalloc(line[0]);
			parseurltag(t, text);
			break;
		case '*':
		case '&':
		case '-':
			t = tagalloc(line[0]);
			txtcat(t->text, text);
			break;
		case ' ':
			if(!t) break;
			txtputc(t->text, '\n');
			txtcat(t->text, text);
			break;
		}

		free(line);
	}


	if(t) listpush(&p->tags, t);
	listpush(pages, p);

	Bterm(bio);
	free(path);
}

void
parse(List *pages)
{
	int fd;
	long ndirs, i;
	Dir *dirs;

	USED(pages);

	fd = open("db", OREAD);
	if(fd < 0)
		sysfatal("missing database");

	ndirs = dirreadall(fd, &dirs);
	for(i = 0; i < ndirs; i++) {
		if(dirs[i].mode & DMDIR)
			continue;
		parsepage(pages, dirs[i].name);
	}
	
	close(fd);
	free(dirs);
}

void
fmtheader(Biobuf *bio, Page *p)
{
	Bprint(bio, "<html lang='en'>\n"
		"<head>\n"
		"<meta charset='utf-8'>\n"
		"<meta name='viewport' content='width=device-width,initial-scale=1'>\n"
		"<link rel='stylesheet' href='media/style.css'>\n"
		"<title>biobuf.link / %s</title>\n"
		"</head>\n"
		"<body>\n", txtstr(p->path));
}

void
fmtnav(Biobuf *bio, Page*)
{
	Bprint(bio, "<nav>\n"
		"<ul>\n"
		"<li><a href='index.html'>home</a></li>\n"
		"<li><a href='now.html'>now</a></li>\n"
		"</ul>"
		"</nav>\n");
}

void
fmtfigure(Biobuf *bio, Tag *t, char *tag)
{
	Bprint(bio, "<figure>\n"
		"<%s src='media/%s/%s'>\n"
		"<figcaption>%s</figcaption>\n"
		"</figure>\n",
		tag, tag, txtstr(t->url), txtstr(t->text));
}

void
fmtmain(Biobuf *bio, Page *p)
{
	int i;
	Tag *t;

	Bprint(bio, "<main>\n");

	if(txtlen(p->pict->url) > 0)
		fmtfigure(bio, p->pict, "img");
	if(txtlen(p->desc) > 0)
		Bprint(bio, "<h1>%s</h1>\n", txtstr(p->desc));

	for(i = 0; i < p->tags.len; i++) {
		t = p->tags.elem[i];
		switch(t->type) {
		case 'i':
			fmtfigure(bio, t, "img");
			break;
		case '>':
			Bprint(bio, "<ul>\n");

			while(i < p->tags.len && t->type == '>') {
				Bprint(bio, "<li><a href='%s'>%s</a></li>\n",
					txtstr(t->url), txtstr(t->text));
				t = p->tags.elem[++i];
			}

			i--;
			Bprint(bio, "</ul>\n");
			break;
		case '*':
			Bprint(bio, "<h2>%s</h2>\n", txtstr(t->text));
			break;
		case '&':
			Bprint(bio, "<p>%s</p>\n", txtstr(t->text));
			break;
		case '-':
			Bprint(bio, "<ul>\n");

			while(i < p->tags.len && t->type == '-') {
				Bprint(bio, "<li>%s</li>\n", txtstr(t->text));
				t = p->tags.elem[++i];
			}
			
			i--;
			Bprint(bio, "</ul>\n");
			break;
		}
	}

	Bprint(bio, "</main>\n");
}

void
fmtfooter(Biobuf *bio, Page*)
{
	Bprint(bio, "</body>\n</html>\n");
}

void
mkdir(char *name)
{
	int fd;
	
	if(access(name, AEXIST) < 0) {
		fd = create(name, OREAD, DMDIR | 0777);
		if(fd < 0)
			sysfatal("couldn't mkdir %s: %r", name);
		close(fd);
	}
}

void
format(List *pages)
{
	int i;
	Page *p;
	char *path;
	Biobuf *bio;

	mkdir("out");
	mkdir("out/media");
	for(i = 0; i < pages->len; i++) {
		p = pages->elem[i];
		path = smprint("out/%s.html", txtstr(p->path));
		bio = Bopen(path, OWRITE);
		if(!bio)
			sysfatal("couldn't create %s: %r", path);
	
		fmtheader(bio, p);
		fmtnav(bio, p);
		fmtmain(bio, p);
		fmtfooter(bio, p);

		Bterm(bio);
		free(path);
	}
}

void
main(int argc, char *argv[])
{
	List pages;

	ARGBEGIN {} ARGEND

	parse(&pages);
	format(&pages);

	exits(nil);
}

A  => src/text.c +97 -0
@@ 1,97 @@
#include <u.h>
#include <libc.h>

#include "text.h"

Text*
txtalloc(usize sz)
{
	Text *txt;

	txt = malloc(sizeof(Text));
	if(!txt)
		sysfatal("%r");

	txt->start = malloc(sz);
	txt->end = txt->start + sz;
	txt->ptr = txt->start;

	*txt->ptr = 0;

	return txt;
}

Text*
txtnew(void)
{
	return txtalloc(128);
}

Text*
txtcopy(char *s)
{
	Text *txt;

	txt = txtnew();
	txtcat(txt, s);

	return txt;
}

Text *
txtmove(char *s)
{
	Text *txt;

	txt = txtcopy(s);
	free(s);

	return txt;
}

void
txtgrow(Text *txt, usize inc)
{
	usize sz;
	char *s;
	
	sz = (txt->end - txt->start) + inc;
	s = realloc(txt->start, sz);
	if(!s)
		sysfatal("%r");

	txt->ptr = (txt->ptr - txt->start) + s;
	txt->start = s;
	txt->end = txt->start + sz;
}

void
txtputc(Text *txt, char c)
{
	if(txt->ptr >= txt->end)
		txtgrow(txt, 128);
	*txt->ptr++ = c;
}

void
txtterm(Text *txt)
{
	if(txt->ptr >= txt->end)
		txtgrow(txt, 128);
	*txt->ptr = 0;
}

void
txtcat(Text *txt, char *s)
{
	while(*s)
		txtputc(txt, *s++);
	txtterm(txt);
}

void
txtfree(Text *txt)
{
	free(txt->start);
	free(txt);
}

A  => src/text.h +19 -0
@@ 1,19 @@
typedef struct Text Text;
struct Text {
	char *start;
	char *end;
	char *ptr;
};

Text *txtnew(void);
Text *txtcopy(char*);
Text *txtmove(char*);

void txtgrow(Text*, usize);
void txtputc(Text*, char);
void txtcat(Text*, char*);

void txtfree(Text*);

#define txtlen(t) ((t)->ptr - (t)->start)
#define txtstr(t) ((t)->start)