ref: cbbeb61a6f8a34958c4eb9f88b9de034206fa6b7
author: Moody <j4kem00dy@gmail.com>
date: Mon Sep 21 05:40:06 EDT 2020
Initial commit
--- /dev/null
+++ b/atom.1
@@ -1,0 +1,45 @@
+.TH ATOM 1
+.SH NAME
+atom \- atom feed generator
+.SH SYNOPSIS
+.B atom
+[
+.B -n
+.I name
+] [
+.B -i
+.I id
+] title link path
+.SH DESCRIPTION
+.I Atom
+is a not quite RFC4287 compliant atom feed generator.
+.I Atom
+takes a feed title, base url, and directory path
+and creates one feed entry per file within the directory.
+The generated atom feed is printed on standard output.
+Each entry is expected to live at the concatination of
+the feed url and the last member of the files path. Entry
+titles are generated by stripping their file extension.
+The feed updated time is set to the current time, while
+each entry's udpated field is set to the files mtime.
+Each flag modifies the meta information of the feed,
+.I name
+and
+.I id
+default to glenda and '9front atom' respectively.
+.SH DIAGNOSTICS
+The ID for each entry is taken from its Qid path.
+All timestamps are reported in UTC.
+.br
+
+The lack of compliance is due to whitespace issues with how
+.IR xml(2)
+outputs, most atom implementations that use generic xml
+parsers seem to work fine.
+.SH SOURCE
+https://git.sr.ht/~moody/atom
+.SH BUGS
+You tell me.
+.SH SEE ALSO
+.IR xml(2),
+https://tools.ietf.org/html/rfc4287
--- /dev/null
+++ b/atom.c
@@ -1,0 +1,110 @@
+#include <u.h>
+#include <libc.h>
+#include <xml.h>
+
+Xml *x;
+Tzone *tz;
+Elem *feed;
+
+char*
+unix2date(vlong abs)
+{
+ Tm tm;
+
+ tmtime(&tm, abs, tz);
+ return smprint("%τ", tmfmt(&tm, "YYYY-MM-DDThh:mm:ssZ"));
+}
+
+void
+initmeta(char *title, char *link, char *author, char *id)
+{
+ Elem *e;
+
+ feed = xmlelem(x, &x->root, nil, "feed");
+ xmlattr(x, &feed->attrs, feed, "xmlns", "http://www.w3.org/2005/Atom");
+
+ e = xmlelem(x, &feed->child, feed, "title");
+ e->pcdata = title;
+
+ e = xmlelem(x, &feed->child, feed, "link");
+ xmlattr(x, &e->attrs, e, "href", link);
+
+ e = xmlelem(x, &feed->child, feed, "updated");
+ e->pcdata = unix2date(time(nil));
+
+ e = xmlelem(x, &feed->child, feed, "author");
+ e = xmlelem(x, &e->child, e, "name");
+ e->pcdata = author;
+
+ e = xmlelem(x, &feed->child, feed, "id");
+ e->pcdata = id;
+}
+
+void
+addentry(Dir *d, char *prefix)
+{
+ Elem *e, *entry;
+ char *dot;
+
+ entry = xmlelem(x, &feed->child, feed, "entry");
+
+ e = xmlelem(x, &entry->child, entry, "title");
+ e->pcdata = strdup(d->name);
+ if((dot = strrchr(e->pcdata, '.')) != nil)
+ *dot = '\0';
+
+ e = xmlelem(x, &entry->child, entry, "link");
+ xmlattr(x, &e->attrs, e, "href", smprint("%s/%s", prefix, d->name));
+
+ e = xmlelem(x, &entry->child, entry, "id");
+ e->pcdata = smprint("%ulld", d->qid.path);
+
+ e = xmlelem(x, &entry->child, entry, "updated");
+ e->pcdata = unix2date(d->mtime);
+}
+
+void
+usage(void)
+{
+ fprint(2, "Usage: %s [-n name] [-i id] title link dir\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *name, *id;
+ Dir *files;
+ long n, i;
+ int fd;
+
+ id = "9front atom";
+ name = "glenda";
+
+ ARGBEGIN {
+ case 'n':
+ name = EARGF(usage());
+ break;
+ case 'i':
+ id = EARGF(usage());
+ break;
+ } ARGEND
+
+ if(argc < 3)
+ usage();
+
+ tmfmtinstall();
+ tz = tzload(nil);
+ x = xmlnew(8192);
+
+ fd = open(argv[2], OREAD);
+ if(fd < 0)
+ sysfatal("failed to read dir: %r");
+
+ n = dirreadall(fd, &files);
+ initmeta(argv[0], argv[1], name, id);
+ for(i=0;i<n;i++)
+ addentry(files+i, argv[1]);
+
+ xmlprint(x, 1);
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+BIN=/usr/moody/bin/amd64
+
+TARG=atom
+OFILES=atom.$O
+
+</sys/src/cmd/mkone