BlogM4

Recently, I tore out all the perl and javascript hacks that allowed commenting and wiki-like linking on this blog since (a) they were not being used, and (b) I saw a post on blogging via m4, which made it look like a good exercise.

So the requirements are (a) an index page that is a big list of all posts, ie. no pagination, and (b) an RSS feed for everyone..

One nice thing about m4 is that you can redefine macros on the fly. So that a table-of-contents file (`toc.m4') can be used for both the index.html and the RSS feed, eg. `toc.m4' just looks like this:

article(`WorkClean',`Reviews Dan Charnas on mise-en-place')
article(`KaseyaMSP',`The Kaseya hack, and why they should be fired by their clients.')
...

where an `index.m4' defines article() as:

define(`article',`
<article>
<a href="data/$1.html">$1</a>
<span>$2</span>
</article>
')dnl
dnl begin html header
<html>
...
<body id="body" class="blog">

include(toc.m4)

while `rss.m4' defines article() as:

dnl init article() to print the rdf:Seq list items
dnl
define(`article', ` <rdf:li rdf:resource="https://blog.planhack.com/logs/data/$1.html" /> ')dnl
dnl
<items>
 <rdf:Seq>
esyscmd(head -5 toc.m4)dnl
 </rdf:Seq>
</items>
</channel>
dnl
dnl reset article() to output the blog entry item
dnl
define(`article', `
<item rdf:about="https://blog.planhack.com/logs/data/$1.html">
<title>$1</title>
<link>https://blog.planhack.com/logs/data/$1.html</link>
<description><![CDATA[
include($1.html)
]]></description>
</item>
')dnl
esyscmd(head -5 toc.m4)
</rdf:RDF>

Since the RSS feed is just the most recent 5 entries, use `esyscmd' to get the top five lines from the table of contents file `toc.m4', which will then be interpreted as m4 commands.

Altogether, Makefile recipes for generating RSS feed and the index.html then become:

index.html:
	m4 -P index.m4 > index.html

rss.xml:
	m4 -I data -P blog.m4 rss.m4 > rss.xml

`blog.m4' defines the `https://blog.planhack.com' macro and other niceties for writing blog entries, which `index.m4' does not need since it just uses the summaries provided by `toc.m4'. Finally, note that the `-P' flag forces all m4 macros require a prefix `m4_' so that writing the word `article' does not trigger interpretation by m4 (which means that all the above snippets have had their `m4_' prefixes removed).

Altogether, it is quite nice how quickly m4 can remove a bunch of cruft from a text generation pipeline.