stagit-gopher

static git page generator for gopher
git clone git://git.2f30.org/stagit-gopher.git
Log | Files | Refs | README | LICENSE

commit de699c5afe2db575e0ac94ce7f64478a6427842b
parent aee984022be470e18b1b085703801ae842b4e24a
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Tue, 13 Jun 2017 21:07:49 +0200

wip

Diffstat:
TODO | 8++++++++
stagit-index.c | 115++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
stagit.c | 13++-----------
3 files changed, 74 insertions(+), 62 deletions(-)

diff --git a/TODO b/TODO @@ -1,3 +1,11 @@ +gopher: + +- align UTF-8 characters (and wide?). +- update documentation: + - document new gopher-specific options. + +=== + performance: - don't recreate files tree for HEAD each time: - idea: update files in tree and commit files with timestamp of commit and diff --git a/stagit-index.c b/stagit-index.c @@ -26,6 +26,34 @@ static char owner[255]; #endif void +trim(char *buf, size_t bufsiz, const char *src) +{ + size_t d = 0, i, len, s; + + len = strlen(src); + for (s = 0; s < len && d < bufsiz - 1; s++) { + switch (src[s]) { + case '\t': + if (d + 8 >= bufsiz - 1) + goto end; + for (i = 0; i < 8; i++) + buf[d++] = ' '; + break; + case '|': + case '\n': + case '\r': + buf[d++] = ' '; + break; + default: + buf[d++] = src[s]; + break; + } + } +end: + buf[d] = '\0'; +} + +void joinpath(char *buf, size_t bufsiz, const char *path, const char *path2) { int r; @@ -37,24 +65,6 @@ joinpath(char *buf, size_t bufsiz, const char *path, const char *path2) path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2); } -/* Escape characters below as HTML 2.0 / XML 1.0. */ -void -xmlencode(FILE *fp, const char *s, size_t len) -{ - size_t i; - - for (i = 0; *s && i < len; s++, i++) { - switch(*s) { - case '<': fputs("&lt;", fp); break; - case '>': fputs("&gt;", fp); break; - case '\'': fputs("&#39;" , fp); break; - case '&': fputs("&amp;", fp); break; - case '"': fputs("&quot;", fp); break; - default: fputc(*s, fp); - } - } -} - void printtimeshort(FILE *fp, const git_time *intime) { @@ -72,29 +82,22 @@ printtimeshort(FILE *fp, const git_time *intime) void writeheader(FILE *fp) { - fputs("<!DOCTYPE html>\n" - "<html>\n<head>\n" - "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" - "<title>", 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=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath); - fputs("</head>\n<body>\n", fp); - fprintf(fp, "<table>\n<tr><td><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></td>\n" - "<td><span class=\"desc\">", relpath); - xmlencode(fp, description, strlen(description)); - fputs("</span></td></tr><tr><td></td><td>\n" - "</td></tr>\n</table>\n<hr/>\n<div id=\"content\">\n" - "<table id=\"index\"><thead>\n" - "<tr><td><b>Name</b></td><td><b>Description</b></td><td><b>Owner</b></td>" - "<td><b>Last commit</b></td></tr>" - "</thead><tbody>\n", fp); + char buf[1024]; + + trim(buf, sizeof(buf), description); + if (buf[0] == 't') + fputc('t', fp); + fprintf(fp, "%s\n", buf); + + fprintf(fp, "%-25.25s ", "Name"); + fprintf(fp, "%-50.50s ", "Description"); + fprintf(fp, "%-25.25s ", "Owner"); + fprintf(fp, "%-16.16s\n", "Last commit"); } void writefooter(FILE *fp) { - fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp); } int @@ -105,6 +108,7 @@ writelog(FILE *fp) git_revwalk *w = NULL; git_oid id; char *stripped_name = NULL, *p; + char buf[1024]; int ret = 0; git_revwalk_new(&w, repo); @@ -127,18 +131,16 @@ writelog(FILE *fp) if (!strcmp(p, ".git")) *p = '\0'; - fputs("<tr><td><a href=\"", fp); - xmlencode(fp, stripped_name, strlen(stripped_name)); - fputs("/log.html\">", fp); - xmlencode(fp, stripped_name, strlen(stripped_name)); - fputs("</a></td><td>", fp); - xmlencode(fp, description, strlen(description)); - fputs("</td><td>", fp); - xmlencode(fp, owner, strlen(owner)); - fputs("</td><td>", fp); + trim(buf, sizeof(buf), stripped_name); + fprintf(fp, "[1|%-25.25s ", buf); + trim(buf, sizeof(buf), description); + fprintf(fp, "%-50.50s ", buf); + trim(buf, sizeof(buf), owner); + fprintf(fp, "%-25.25s ", buf); if (author) printtimeshort(fp, &(author->when)); - fputs("</td></tr>", fp); + trim(buf, sizeof(buf), stripped_name); + fprintf(fp, "|%s%s/log.gph|server|port]\n", relpath, buf); git_commit_free(commit); err: @@ -148,27 +150,38 @@ err: return ret; } +void +usage(const char *argv0) +{ + fprintf(stderr, "%s [repodir...]\n", argv0); + exit(1); +} + + int main(int argc, char *argv[]) { const git_error *e = NULL; FILE *fp; char path[PATH_MAX], repodirabs[PATH_MAX + 1]; - const char *repodir; + const char *repodir = NULL; int i, ret = 0; if (pledge("stdio rpath", NULL) == -1) err(1, "pledge"); - if (argc < 2) { - fprintf(stderr, "%s [repodir...]\n", argv[0]); - return 1; - } git_libgit2_init(); writeheader(stdout); for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (argv[i][1] != 'b' || i + 1 >= argc) + usage(argv[0]); + relpath = argv[++i]; + continue; + } + repodir = argv[i]; if (!realpath(repodir, repodirabs)) err(1, "realpath"); diff --git a/stagit.c b/stagit.c @@ -251,13 +251,10 @@ xmlencode(FILE *fp, const char *s, size_t len) void trim(char *buf, size_t bufsiz, const char *src) { - size_t d = 0, i, len, n = 0, s; + size_t d = 0, i, len, s; len = strlen(src); for (s = 0; s < len && d < bufsiz - 1; s++) { - if (src[s] == '\n') - n = 0; - switch (src[s]) { case '\t': if (d + 8 >= bufsiz - 1) @@ -266,20 +263,14 @@ trim(char *buf, size_t bufsiz, const char *src) buf[d++] = ' '; break; case '|': + case '\n': case '\r': buf[d++] = ' '; break; - case 't': - if (!n && src[s] == 't') { - if (d + 1 >= bufsiz - 1) - goto end; - buf[d++] = src[s]; - } default: buf[d++] = src[s]; break; } - n++; } end: buf[d] = '\0';