diff --git a/urmoms.c b/urmoms.c
@@ -0,0 +1,222 @@
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "git2.h"
+
+static const char *relpath = "";
+static const char *name = "";
+static const char *description = "";
+
+static const char *repodir = ".";
+
+static git_repository *repo;
+
+FILE *
+efopen(const char *name, const char *flags)
+{
+ FILE *fp;
+
+ fp = fopen(name, flags);
+ if (!fp)
+ err(1, "fopen");
+
+ return fp;
+}
+
+static void
+printtime(FILE *fp, const git_time * intime, const char *prefix)
+{
+ struct tm *intm;
+ time_t t;
+ int offset, hours, minutes;
+ char sign, out[32];
+
+ offset = intime->offset;
+ if (offset < 0) {
+ sign = '-';
+ offset = -offset;
+ } else {
+ sign = '+';
+ }
+
+ hours = offset / 60;
+ minutes = offset % 60;
+
+ t = (time_t) intime->time + (intime->offset * 60);
+
+ intm = gmtime(&t);
+ strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
+
+ fprintf(fp, "%s%s %c%02d%02d\n", prefix, out, sign, hours, minutes);
+}
+
+static void
+printcommit(FILE *fp, git_commit * commit)
+{
+ const git_signature *sig;
+ char buf[GIT_OID_HEXSZ + 1];
+ int i, count;
+ const char *scan, *eol;
+
+ git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
+ fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf);
+
+ if ((count = (int)git_commit_parentcount(commit)) > 1) {
+ fprintf(fp, "Merge:");
+ for (i = 0; i < count; ++i) {
+ git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
+ fprintf(fp, " %s", buf);
+ }
+ fprintf(fp, "\n");
+ }
+ if ((sig = git_commit_author(commit)) != NULL) {
+ fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n",
+ sig->name, sig->name, sig->email);
+ printtime(fp, &sig->when, "Date: ");
+ }
+ fprintf(fp, "\n");
+
+ for (scan = git_commit_message(commit); scan && *scan;) {
+ for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */
+ ;
+
+ fprintf(fp, " %.*s\n", (int) (eol - scan), scan);
+ scan = *eol ? eol + 1 : NULL;
+ }
+ fprintf(fp, "\n");
+}
+
+int
+writeheader(FILE *fp)
+{
+ fprintf(fp, "<!DOCTYPE HTML>"
+ "<html dir=\"ltr\" lang=\"en\"><head>"
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
+ "<meta http-equiv=\"Content-Language\" content=\"en\" />");
+ fprintf(fp, "<title>%s - %s</title>", name, description);
+ fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />"
+ "</head><body><center>");
+ fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath, name);
+ fprintf(fp, "<span class=\"desc\">%s</span><br/>", description);
+ fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath);
+ fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath);
+ fprintf(fp, "<a href=\"%sstats.html\">Stats</a> | ", relpath);
+ fprintf(fp, "<a href=\"%sreadme.html\">README</a> | ", relpath);
+ fprintf(fp, "<a href=\"%slicense.html\">LICENSE</a>", relpath);
+ fprintf(fp, "</center><hr/><pre>");
+
+ return 0;
+}
+
+int
+writefooter(FILE *fp)
+{
+ fprintf(fp, "</pre></body></html>");
+
+ return 0;
+}
+
+int
+writelog(FILE *fp)
+{
+ git_revwalk *w = NULL;
+ git_oid id;
+ git_commit *c = NULL;
+
+ git_revwalk_new(&w, repo);
+ git_revwalk_push_head(w);
+
+ while (!git_revwalk_next(&id, w)) {
+ if (git_commit_lookup(&c, repo, &id))
+ return 1;
+ printcommit(fp, c);
+ git_commit_free(c);
+ }
+ git_revwalk_free(w);
+
+ return 0;
+}
+
+int
+writefiles(FILE *fp)
+{
+ git_index *index;
+ const git_index_entry *entry;
+ size_t count, i;
+
+ git_repository_index(&index, repo);
+
+ count = git_index_entrycount(index);
+ for (i = 0; i < count; i++) {
+ entry = git_index_get_byindex(index, i);
+ fprintf(fp, "name: %s, size: %lu, mode: %lu\n",
+ entry->path, entry->file_size, entry->mode);
+ }
+
+ return 0;
+}
+
+#if 0
+int
+writebranches(FILE *fp)
+{
+ git_branch_iterator *branchit = NULL;
+ git_branch_t branchtype;
+ git_reference *branchref;
+ char branchbuf[BUFSIZ] = "";
+ int status;
+
+ git_branch_iterator_new(&branchit, repo, GIT_BRANCH_LOCAL);
+
+ while ((status = git_branch_next(&branchref, &branchtype, branchit)) == GIT_ITEROVER) {
+ git_reference_normalize_name(branchbuf, sizeof(branchbuf), git_reference_name(branchref), GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND);
+
+ /* fprintf(fp, "branch: |%s|\n", branchbuf); */
+ }
+
+ git_branch_iterator_free(branchit);
+
+ return 0;
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int status;
+ const git_error *e = NULL;
+ FILE *fp;
+
+ if (argc != 2) {
+ fprintf(stderr, "%s <repodir>\n", argv[0]);
+ return 1;
+ }
+ repodir = argv[1];
+
+ git_libgit2_init();
+
+ if ((status = git_repository_open(&repo, repodir)) < 0) {
+ e = giterr_last();
+ fprintf(stderr, "error %d/%d: %s\n", status, e->klass, e->message);
+ exit(status);
+ }
+
+ fp = efopen("logs.html", "w+b");
+ writeheader(fp);
+ writelog(fp);
+ writefooter(fp);
+ fclose(fp);
+
+ fp = efopen("files.html", "w+b");
+ writeheader(fp);
+ writefiles(fp);
+ writefooter(fp);
+ fclose(fp);
+
+ /* cleanup */
+ git_repository_free(repo);
+ git_libgit2_shutdown();
+
+ return 0;
+}