gopher version (WIP) - stagit-gopher - A git gopher frontend. (mirror)
 (HTM) git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit caa55f2bb419bd2f5327a779fe9afe13f7b4ed38
 (DIR) parent 54a8a7c1533ce60e3cbe8539bf1e801225d0fabd
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sun, 11 Jun 2017 18:42:03 +0200
       
       gopher version (WIP)
       
       Diffstat:
         M stagit.c                            |     329 ++++++++++++++++---------------
       
       1 file changed, 165 insertions(+), 164 deletions(-)
       ---
 (DIR) diff --git a/stagit.c b/stagit.c
       @@ -248,6 +248,56 @@ xmlencode(FILE *fp, const char *s, size_t len)
                }
        }
        
       +/* Escape characters in text in geomyidae .gph format */
       +void
       +gphtext(FILE *fp, const char *s, size_t len)
       +{
       +        size_t i, n = 0;
       +
       +        for (i = 0; *s && i < len; i++) {
       +                if (s[i] == '\n')
       +                        n = 0;
       +
       +                /* escape 't' at the start of a line */
       +                if (!n && s[i] == 't') {
       +                        fputc('t', fp);
       +                        n = 1;
       +                }
       +
       +                if (s[i] == '\t') {
       +                        fputs("        ", fp);
       +                } else {
       +                        fputc(s[i], fp);
       +                }
       +                n++;
       +        }
       +}
       +
       +/* Escape characters in links in geomyidae .gph format */
       +void
       +gphlink(FILE *fp, const char *s, size_t len)
       +{
       +        size_t i;
       +
       +        for (i = 0; *s && i < len; i++) {
       +                switch (s[i]) {
       +                case '\n':
       +                        /* in this context replace newline with space */
       +                        fputc(' ', fp);
       +                        break;
       +                case '\r': /* ignore CR */
       +                case '|': /* ignore separators for now */
       +                        break;
       +                case '\t':
       +                        fputs("        ", fp);
       +                        break;
       +                default:
       +                        fputc(s[i], fp);
       +                        break;
       +                }
       +        }
       +}
       +
        int
        mkdirp(const char *path)
        {
       @@ -318,111 +368,102 @@ printtimeshort(FILE *fp, const git_time *intime)
        void
        writeheader(FILE *fp, const char *title)
        {
       -        fputs("<!DOCTYPE html>\n"
       -                "<html>\n<head>\n"
       -                "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
       -                "<title>", fp);
       -        xmlencode(fp, title, strlen(title));
       +        gphtext(fp, title, strlen(title));
                if (title[0] && strippedname[0])
                        fputs(" - ", fp);
       -        xmlencode(fp, strippedname, strlen(strippedname));
       +        gphtext(fp, strippedname, strlen(strippedname));
                if (description[0])
                        fputs(" - ", fp);
       -        xmlencode(fp, description, strlen(description));
       -        fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", relpath);
       -        fprintf(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"%s Atom Feed\" href=\"%satom.xml\" />\n",
       -                name, relpath);
       -        fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath);
       -        fputs("</head>\n<body>\n<table><tr><td>", fp);
       -        fprintf(fp, "<a href=\"../%s\"><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></a>",
       -                relpath, relpath);
       -        fputs("</td><td><h1>", fp);
       -        xmlencode(fp, strippedname, strlen(strippedname));
       -        fputs("</h1><span class=\"desc\">", fp);
       -        xmlencode(fp, description, strlen(description));
       -        fputs("</span></td></tr>", fp);
       +        gphtext(fp, description, strlen(description));
       +        fputs("\n", fp);
                if (cloneurl[0]) {
       -                fputs("<tr class=\"url\"><td></td><td>git clone <a href=\"", fp);
       -                xmlencode(fp, cloneurl, strlen(cloneurl));
       -                fputs("\">", fp);
       -                xmlencode(fp, cloneurl, strlen(cloneurl));
       -                fputs("</a></td></tr>", fp);
       +                fputs("[1|git clone ", fp);
       +                gphlink(fp, cloneurl, strlen(cloneurl));
       +                fputs("|", fp);
       +                gphlink(fp, cloneurl, strlen(cloneurl));
       +                fputs("|server|port]\n", fp);
                }
       -        fputs("<tr><td></td><td>\n", fp);
       -        fprintf(fp, "<a href=\"%slog.html\">Log</a> | ", relpath);
       -        fprintf(fp, "<a href=\"%sfiles.html\">Files</a> | ", relpath);
       -        fprintf(fp, "<a href=\"%srefs.html\">Refs</a>", relpath);
       +        fprintf(fp, "[1|Log|%slog.gph|server|port]\n", relpath);
       +        fprintf(fp, "[1|Files|%sfiles.gph|server|port]\n", relpath);
       +        fprintf(fp, "[1|Refs|%srefs.gph|server|port]\n", relpath);
                if (hassubmodules)
       -                fprintf(fp, " | <a href=\"%sfile/.gitmodules.html\">Submodules</a>", relpath);
       +                fprintf(fp, "[1|Submodules|%sfile/.gitmodules.gph|server|port]\n", relpath);
                if (hasreadme)
       -                fprintf(fp, " | <a href=\"%sfile/README.html\">README</a>", relpath);
       +                fprintf(fp, "[1|README|%sfile/README.gph|server|port]\n", relpath);
                if (haslicense)
       -                fprintf(fp, " | <a href=\"%sfile/LICENSE.html\">LICENSE</a>", relpath);
       -        fputs("</td></tr></table>\n<hr/>\n<div id=\"content\">\n", fp);
       +                fprintf(fp, "[1|LICENSE|%sfile/LICENSE.gph|server|port]\n", relpath);
       +        fputs("===\n", fp);
        }
        
        void
        writefooter(FILE *fp)
        {
       -        fputs("</div>\n</body>\n</html>\n", fp);
        }
        
        int
       -writeblobhtml(FILE *fp, const git_blob *blob)
       +writeblobgph(FILE *fp, const git_blob *blob)
        {
       -        size_t n = 0, i, prev;
       -        const char *nfmt = "<a href=\"#l%d\" class=\"line\" id=\"l%d\">%7d</a> ";
       +        size_t n = 0, i, j, prev;
       +        const char *nfmt = "%8d ";
                const char *s = git_blob_rawcontent(blob);
                git_off_t len = git_blob_rawsize(blob);
        
       -        fputs("<pre id=\"blob\">\n", fp);
       -
                if (len > 0) {
                        for (i = 0, prev = 0; i < (size_t)len; i++) {
                                if (s[i] != '\n')
                                        continue;
                                n++;
                                fprintf(fp, nfmt, n, n, n);
       -                        xmlencode(fp, &s[prev], i - prev + 1);
       +                        for (j = prev; s[j] && j <= i; j++) {
       +                                if (s[j] == '\t')
       +                                        fputs("        ", fp);
       +                                else
       +                                        fputc(s[j], fp);
       +                        }
                                prev = i + 1;
                        }
                        /* trailing data */
                        if ((len - prev) > 0) {
                                n++;
                                fprintf(fp, nfmt, n, n, n);
       -                        xmlencode(fp, &s[prev], len - prev);
       +                        for (j = prev; s[j] && j < len - prev; j++) {
       +                                if (s[j] == '\t')
       +                                        fputs("        ", fp);
       +                                else
       +                                        fputc(s[j], fp);
       +                        }
                        }
                }
        
       -        fputs("</pre>\n", fp);
       -
                return n;
        }
        
        void
        printcommit(FILE *fp, struct commitinfo *ci)
        {
       -        fprintf(fp, "<b>commit</b> <a href=\"%scommit/%s.html\">%s</a>\n",
       -                relpath, ci->oid, ci->oid);
       +        fprintf(fp, "[1|commit %s|%scommit/%s.gph|server|port]\n",
       +                ci->oid, relpath, ci->oid);
        
                if (ci->parentoid[0])
       -                fprintf(fp, "<b>parent</b> <a href=\"%scommit/%s.html\">%s</a>\n",
       -                        relpath, ci->parentoid, ci->parentoid);
       +                fprintf(fp, "[1|parent %s|%scommit/%s.gph|server|port]\n",
       +                        ci->parentoid, relpath, ci->parentoid);
        
                if (ci->author) {
       -                fputs("<b>Author:</b> ", fp);
       -                xmlencode(fp, ci->author->name, strlen(ci->author->name));
       -                fputs(" &lt;<a href=\"mailto:", fp);
       -                xmlencode(fp, ci->author->email, strlen(ci->author->email));
       -                fputs("\">", fp);
       -                xmlencode(fp, ci->author->email, strlen(ci->author->email));
       -                fputs("</a>&gt;\n<b>Date:</b>   ", fp);
       +                /* TODO: fix author email link to redirect as mailto: */
       +                fputs("[1|Author: ", fp);
       +                gphlink(fp, ci->author->name, strlen(ci->author->name));
       +                fputs(" <", fp);
       +                gphlink(fp, ci->author->email, strlen(ci->author->email));
       +                fputs(">|mailto:", fp);
       +                gphlink(fp, ci->author->email, strlen(ci->author->email));
       +                fputs("|server|port]\n", fp);
       +                fputs("Date:   ", fp);
                        printtime(fp, &(ci->author->when));
                        fputc('\n', fp);
                }
                if (ci->msg) {
                        fputc('\n', fp);
       -                xmlencode(fp, ci->msg, strlen(ci->msg));
       +                gphtext(fp, ci->msg, strlen(ci->msg));
                        fputc('\n', fp);
                }
        }
       @@ -446,19 +487,19 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                    ci->ndeltas   > 1000   ||
                    ci->addcount  > 100000 ||
                    ci->delcount  > 100000) {
       -                fputs("Diff is too large, output suppressed.\n", fp);
       +                fputs("\nDiff is too large, output suppressed.\n", fp);
                        return;
                }
        
                /* diff stat */
       -        fputs("<b>Diffstat:</b>\n<table>", fp);
       +        fputs("Diffstat:\n", fp);
                for (i = 0; i < ci->ndeltas; i++) {
                        delta = git_patch_get_delta(ci->deltas[i]->patch);
       -                fprintf(fp, "<tr><td><a href=\"#h%zu\">", i);
       -                xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));
       +                /* TODO: make file linkable */
       +                gphtext(fp, delta->old_file.path, strlen(delta->old_file.path));
                        if (strcmp(delta->old_file.path, delta->new_file.path)) {
       -                        fputs(" -&gt; ", fp);
       -                        xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));
       +                        fputs(" -> ", fp);
       +                        gphtext(fp, delta->new_file.path, strlen(delta->new_file.path));
                        }
        
                        add = ci->deltas[i]->addcount;
       @@ -474,26 +515,26 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                        memset(&linestr, '+', add);
                        memset(&linestr[add], '-', del);
        
       -                fprintf(fp, "</a></td><td> | </td><td class=\"num\">%zu</td><td><span class=\"i\">",
       +                fprintf(fp, " | %zu ",
                                ci->deltas[i]->addcount + ci->deltas[i]->delcount);
                        fwrite(&linestr, 1, add, fp);
       -                fputs("</span><span class=\"d\">", fp);
                        fwrite(&linestr[add], 1, del, fp);
       -                fputs("</span></td></tr>\n", fp);
       +                fputs("\n", fp);
                }
       -        fprintf(fp, "</table></pre><pre>%zu file%s changed, %zu insertion%s(+), %zu deletion%s(-)\n",
       +        fprintf(fp, "\n%zu file%s changed, %zu insertion%s(+), %zu deletion%s(-)\n",
                        ci->filecount, ci->filecount == 1 ? "" : "s",
                        ci->addcount,  ci->addcount  == 1 ? "" : "s",
                        ci->delcount,  ci->delcount  == 1 ? "" : "s");
        
       -        fputs("<hr/>", fp);
       +        fputs("===\n", fp);
        
                for (i = 0; i < ci->ndeltas; i++) {
                        patch = ci->deltas[i]->patch;
                        delta = git_patch_get_delta(patch);
       -                fprintf(fp, "<b>diff --git a/<a id=\"h%zu\" href=\"%sfile/%s.html\">%s</a> b/<a href=\"%sfile/%s.html\">%s</a></b>\n",
       -                        i, relpath, delta->old_file.path, delta->old_file.path,
       -                        relpath, delta->new_file.path, delta->new_file.path);
       +                /* NOTE: only links to new path */
       +                fprintf(fp, "[1|diff --git a/%s b/%s",
       +                        delta->old_file.path, delta->new_file.path);
       +                fprintf(fp, "|%sfile/%s.gph|server|port]\n", relpath, delta->new_file.path);
        
                        /* check binary data */
                        if (delta->flags & GIT_DIFF_FLAG_BINARY) {
       @@ -506,24 +547,18 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                                if (git_patch_get_hunk(&hunk, &nhunklines, patch, j))
                                        break;
        
       -                        fprintf(fp, "<a href=\"#h%zu-%zu\" id=\"h%zu-%zu\" class=\"h\">", i, j, i, j);
       -                        xmlencode(fp, hunk->header, hunk->header_len);
       -                        fputs("</a>", fp);
       +                        gphtext(fp, hunk->header, hunk->header_len);
        
                                for (k = 0; ; k++) {
                                        if (git_patch_get_line_in_hunk(&line, patch, j, k))
                                                break;
                                        if (line->old_lineno == -1)
       -                                        fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"i\">+",
       -                                                i, j, k, i, j, k);
       +                                        fputs("+", fp);
                                        else if (line->new_lineno == -1)
       -                                        fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"d\">-",
       -                                                i, j, k, i, j, k);
       +                                        fputs("-", fp);
                                        else
       -                                        fputc(' ', fp);
       -                                xmlencode(fp, line->content, line->content_len);
       -                                if (line->old_lineno == -1 || line->new_lineno == -1)
       -                                        fputs("</a>", fp);
       +                                        fputs(" ", fp);
       +                                gphtext(fp, line->content, line->content_len);
                                }
                        }
                }
       @@ -532,25 +567,20 @@ printshowfile(FILE *fp, struct commitinfo *ci)
        void
        writelogline(FILE *fp, struct commitinfo *ci)
        {
       -        fputs("<tr><td>", fp);
       +        fputs("[1|", fp);
                if (ci->author)
                        printtimeshort(fp, &(ci->author->when));
       -        fputs("</td><td>", fp);
       -        if (ci->summary) {
       -                fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid);
       -                xmlencode(fp, ci->summary, strlen(ci->summary));
       -                fputs("</a>", fp);
       -        }
       -        fputs("</td><td>", fp);
       +        fputs("  ", fp);
       +        if (ci->summary)
       +                gphlink(fp, ci->summary, strlen(ci->summary));
       +        fputs("  ", fp);
                if (ci->author)
       -                xmlencode(fp, ci->author->name, strlen(ci->author->name));
       -        fputs("</td><td class=\"num\" align=\"right\">", fp);
       -        fprintf(fp, "%zu", ci->filecount);
       -        fputs("</td><td class=\"num\" align=\"right\">", fp);
       -        fprintf(fp, "+%zu", ci->addcount);
       -        fputs("</td><td class=\"num\" align=\"right\">", fp);
       -        fprintf(fp, "-%zu", ci->delcount);
       -        fputs("</td></tr>\n", fp);
       +                gphlink(fp, ci->author->name, strlen(ci->author->name));
       +        fprintf(fp, "  %zu", ci->filecount);
       +        fprintf(fp, "  +%zu", ci->addcount);
       +        fprintf(fp, "  -%zu", ci->delcount);
       +        fprintf(fp, "|%scommit/%s.gph", relpath, ci->oid);
       +        fputs("|server|port]\n", fp);
        }
        
        int
       @@ -569,8 +599,6 @@ writelog(FILE *fp, const git_oid *oid)
                git_revwalk_simplify_first_parent(w);
        
                while (!git_revwalk_next(&id, w)) {
       -                relpath = "";
       -
                        if (cachefile && !memcmp(&id, &lastoid, sizeof(id)))
                                break;
                        if (!(ci = commitinfo_getbyoid(&id)))
       @@ -580,19 +608,15 @@ writelog(FILE *fp, const git_oid *oid)
                        if (cachefile)
                                writelogline(wcachefp, ci);
        
       -                relpath = "../";
       -
       -                r = snprintf(path, sizeof(path), "commit/%s.html", ci->oid);
       +                r = snprintf(path, sizeof(path), "commit/%s.gph", ci->oid);
                        if (r == -1 || (size_t)r >= sizeof(path))
       -                        errx(1, "path truncated: 'commit/%s.html'", ci->oid);
       +                        errx(1, "path truncated: 'commit/%s.gph'", ci->oid);
        
                        /* check if file exists if so skip it */
                        if (access(path, F_OK)) {
                                fpfile = efopen(path, "w");
                                writeheader(fpfile, ci->summary);
       -                        fputs("<pre>", fpfile);
                                printshowfile(fpfile, ci);
       -                        fputs("</pre>\n", fpfile);
                                writefooter(fpfile);
                                fclose(fpfile);
                        }
       @@ -600,8 +624,6 @@ writelog(FILE *fp, const git_oid *oid)
                }
                git_revwalk_free(w);
        
       -        relpath = "";
       -
                return 0;
        }
        
       @@ -626,7 +648,7 @@ printcommitatom(FILE *fp, struct commitinfo *ci)
                        xmlencode(fp, ci->summary, strlen(ci->summary));
                        fputs("</title>\n", fp);
                }
       -        fprintf(fp, "<link rel=\"alternate\" type=\"text/html\" href=\"commit/%s.html\" />",
       +        fprintf(fp, "<link rel=\"alternate\" type=\"text/html\" href=\"commit/%s.gph\" />",
                        ci->oid);
        
                if (ci->author) {
       @@ -694,7 +716,6 @@ int
        writeblob(git_object *obj, const char *fpath, const char *filename, git_off_t filesize)
        {
                char tmp[PATH_MAX] = "", *d;
       -        const char *p;
                int lc = 0;
                FILE *fp;
        
       @@ -705,31 +726,22 @@ writeblob(git_object *obj, const char *fpath, const char *filename, git_off_t fi
                if (mkdirp(d))
                        return -1;
        
       -        for (p = fpath, tmp[0] = '\0'; *p; p++) {
       -                if (*p == '/' && strlcat(tmp, "../", sizeof(tmp)) >= sizeof(tmp))
       -                        errx(1, "path truncated: '../%s'", tmp);
       -        }
       -        relpath = tmp;
       -
                fp = efopen(fpath, "w");
                writeheader(fp, filename);
       -        fputs("<p> ", fp);
       -        xmlencode(fp, filename, strlen(filename));
       -        fprintf(fp, " (%juB)", (uintmax_t)filesize);
       -        fputs("</p><hr/>", fp);
       +        gphtext(fp, filename, strlen(filename));
       +        fprintf(fp, " (%juB)\n", (uintmax_t)filesize);
       +        fputs("===\n", fp);
        
                if (git_blob_is_binary((git_blob *)obj)) {
       -                fputs("<p>Binary file.</p>\n", fp);
       +                fputs("Binary file.\n", fp);
                } else {
       -                lc = writeblobhtml(fp, (git_blob *)obj);
       +                lc = writeblobgph(fp, (git_blob *)obj);
                        if (ferror(fp))
                                err(1, "fwrite");
                }
                writefooter(fp);
                fclose(fp);
        
       -        relpath = "";
       -
                return lc;
        }
        
       @@ -794,10 +806,10 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
                                return -1;
                        joinpath(entrypath, sizeof(entrypath), path, entryname);
        
       -                r = snprintf(filepath, sizeof(filepath), "file/%s.html",
       +                r = snprintf(filepath, sizeof(filepath), "file/%s.gph",
                                 entrypath);
                        if (r == -1 || (size_t)r >= sizeof(filepath))
       -                        errx(1, "path truncated: 'file/%s.html'", entrypath);
       +                        errx(1, "path truncated: 'file/%s.gph'", entrypath);
        
                        if (!git_tree_entry_to_object(&obj, repo, entry)) {
                                switch (git_object_type(obj)) {
       @@ -819,23 +831,24 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
                                filesize = git_blob_rawsize((git_blob *)obj);
                                lc = writeblob(obj, filepath, entryname, filesize);
        
       -                        fputs("<tr><td>", fp);
       +                        fputs("[1|", fp);
                                fputs(filemode(git_tree_entry_filemode(entry)), fp);
       -                        fprintf(fp, "</td><td><a href=\"%s%s\">", relpath, filepath);
       -                        xmlencode(fp, entrypath, strlen(entrypath));
       -                        fputs("</a></td><td class=\"num\" align=\"right\">", fp);
       +                        fputs("  ", fp);
       +                        gphlink(fp, entrypath, strlen(entrypath));
       +                        fputs("  ", fp);
                                if (lc > 0)
                                        fprintf(fp, "%dL", lc);
                                else
                                        fprintf(fp, "%juB", (uintmax_t)filesize);
       -                        fputs("</td></tr>\n", fp);
       +                        fprintf(fp, "|%s%s", relpath, filepath);
       +                        fputs("|server|port]\n", fp);
                                git_object_free(obj);
                        } else if (!git_submodule_lookup(&module, repo, entryname)) {
       -                        fprintf(fp, "<tr><td>m---------</td><td><a href=\"%sfile/.gitmodules.html\">",
       -                                relpath);
       -                        xmlencode(fp, entrypath, strlen(entrypath));
       +                        fputs("[1|m---------  ", fp);
       +                        gphlink(fp, entrypath, strlen(entrypath));
       +                        fprintf(fp, "|%sfile/.gitmodules.gph|server|port]\n", relpath);
       +                        /* NOTE: linecount omitted */
                                git_submodule_free(module);
       -                        fputs("</a></td><td class=\"num\" align=\"right\"></td></tr>\n", fp);
                        }
                }
        
       @@ -849,17 +862,12 @@ writefiles(FILE *fp, const git_oid *id)
                git_commit *commit = NULL;
                int ret = -1;
        
       -        fputs("<table id=\"files\"><thead>\n<tr>"
       -              "<td><b>Mode</b></td><td><b>Name</b></td>"
       -              "<td class=\"num\" align=\"right\"><b>Size</b></td>"
       -              "</tr>\n</thead><tbody>\n", fp);
       +        fputs("Mode  Name  Size\n", fp);
        
                if (!git_commit_lookup(&commit, repo, id) &&
                    !git_commit_tree(&tree, commit))
                        ret = writefilestree(fp, tree, "");
        
       -        fputs("</tbody></table>", fp);
       -
                git_commit_free(commit);
                git_tree_free(tree);
        
       @@ -935,28 +943,21 @@ writerefs(FILE *fp)
        
                                /* print header if it has an entry (first). */
                                if (++count == 1) {
       -                                fprintf(fp, "<h2>%s</h2><table id=\"%s\">"
       -                                        "<thead>\n<tr><td><b>Name</b></td>"
       -                                        "<td><b>Last commit date</b></td>"
       -                                        "<td><b>Author</b></td>\n</tr>\n"
       -                                        "</thead><tbody>\n",
       -                                         titles[j], ids[j]);
       +                                gphtext(fp, titles[j], strlen(titles[j]));
       +                                fputs("Name  Last commit date  Author\n\n", fp);
                                }
        
       -                        relpath = "";
                                name = git_reference_shorthand(r);
        
       -                        fputs("<tr><td>", fp);
       +                        fputs("  ", fp);
                                xmlencode(fp, name, strlen(name));
       -                        fputs("</td><td>", fp);
       +                        fputs("  ", fp);
                                if (ci->author)
                                        printtimeshort(fp, &(ci->author->when));
       -                        fputs("</td><td>", fp);
       +                        fputs("  ", fp);
                                if (ci->author)
                                        xmlencode(fp, ci->author->name, strlen(ci->author->name));
       -                        fputs("</td></tr>\n", fp);
       -
       -                        relpath = "../";
       +                        fputs("\n", fp);
        
                                commitinfo_free(ci);
                                git_object_free(obj);
       @@ -966,7 +967,7 @@ writerefs(FILE *fp)
                        }
                        /* table footer */
                        if (count)
       -                        fputs("</tbody></table><br/>", fp);
       +                        fputs("\n", fp);
                }
        
        err:
       @@ -987,6 +988,7 @@ usage(char *argv0)
                exit(1);
        }
        
       +/* TODO: add base argument, gopher does not support relative urls, document it too */
        int
        main(int argc, char *argv[])
        {
       @@ -1011,6 +1013,10 @@ main(int argc, char *argv[])
                                if (i + 1 >= argc)
                                        usage(argv[0]);
                                cachefile = argv[++i];
       +                } else if (argv[i][1] == 'b') {
       +                        if (i + 1 >= argc)
       +                                usage(argv[0]);
       +                        relpath = argv[++i];
                        }
                }
                if (!repodir)
       @@ -1090,15 +1096,12 @@ main(int argc, char *argv[])
                git_object_free(obj);
        
                /* log for HEAD */
       -        fp = efopen("log.html", "w");
       -        relpath = "";
       +        fp = efopen("log.gph", "w");
                mkdir("commit", 0755);
                writeheader(fp, "Log");
       -        fputs("<table id=\"log\"><thead>\n<tr><td><b>Date</b></td>"
       -              "<td><b>Commit message</b></td>"
       -              "<td><b>Author</b></td><td class=\"num\" align=\"right\"><b>Files</b></td>"
       -              "<td class=\"num\" align=\"right\"><b>+</b></td>"
       -              "<td class=\"num\" align=\"right\"><b>-</b></td></tr>\n</thead><tbody>\n", fp);
       +        fputs("Date  "
       +              "Commit message  "
       +              "Author  Files  +  -\n", fp);
        
                if (cachefile) {
                        /* read from cache file (does not need to exist) */
       @@ -1121,7 +1124,7 @@ main(int argc, char *argv[])
                        writelog(fp, head);
        
                        if (rcachefp) {
       -                        /* append previous log to log.html and the new cache */
       +                        /* append previous log to log.gph and the new cache */
                                while (!feof(rcachefp)) {
                                        n = fread(buf, 1, sizeof(buf), rcachefp);
                                        if (ferror(rcachefp))
       @@ -1137,13 +1140,11 @@ main(int argc, char *argv[])
                        if (head)
                                writelog(fp, head);
                }
       -
       -        fputs("</tbody></table>", fp);
                writefooter(fp);
                fclose(fp);
        
                /* files for HEAD */
       -        fp = efopen("files.html", "w");
       +        fp = efopen("files.gph", "w");
                writeheader(fp, "Files");
                if (head)
                        writefiles(fp, head);
       @@ -1151,7 +1152,7 @@ main(int argc, char *argv[])
                fclose(fp);
        
                /* summary page with branches and tags */
       -        fp = efopen("refs.html", "w");
       +        fp = efopen("refs.gph", "w");
                writeheader(fp, "Refs");
                writerefs(fp);
                writefooter(fp);