Commit Diff


commit - ba63ab46fb6570dd4cfacb1643a3a8fe5c68b835
commit + 85c360aaa1efe49063956a1fdfd7e46d8e5a92b3
blob - 6e6a2e8391b5ff02c1bdb7753f0ec1b51a1ff8a9
blob + cb4f8f8e680b39482cbb9ddec60bee5c76db72a6
--- README
+++ README
@@ -79,28 +79,24 @@ See the following manual page files for information ab
 See regress/gotd/README for information about running the server test suite.
 
 
-Game of Trees Web (Gotweb) is a CGI program which displays repository data
-and is designed to work with httpd(8) and slowcgi(8). It requires the Kristaps
-Dzonsons kcgi library, version 0.12.0 or greater.
+Game of Trees Daemon (gotwebd) is a FastCGI program which displays repository
+data and is designed to work with httpd(8).
 
-To compile gotweb on OpenBSD, run:
+To compile gotwebd on OpenBSD, run:
 
- # pkg_add kcgi
- $ make web
- # make web-install
+ $ make webd
+ # make webd-install
 
 This will create the following files:
-  the CGI program /var/www/cgi-bin/gotweb/gotweb
-  helper programs from the libexec directory in /var/www/cgi-bin/gotweb/libexec
-  several template files in /var/www/cgi-bin/gw_tmpl/
-  html, css, and image files in /var/www/htdocs/gotweb/
-  the directory /var/www/got/tmp/
+  the daemon program /usr/local/sbin/gotwebd
+  css and image files in /var/www/htdocs/gotwebd
+  the gotwebd init script in /etc/rc.d
   man pages (only installed if building sources from a Got release tarball)
 
 Documentation is available in manual pages:
 
- $ man -l gotweb/gotweb.8
- $ man -l gotweb/gotweb.conf.5
+ $ man -l gotwebd/gotwebd.8
+ $ man -l gotwebd/gotwebd.conf.5
 
 
 Got can be built with profiling enabled to debug performance issues.
@@ -123,26 +119,7 @@ The gprof2dot program can be used to generate a profil
   $ doas pkg_add gprof2dot graphviz
   $ gprof ~/bin/got-read-pack gmon.out | gprof2dot | dot -T png > profile.png
 
-As another example, to compile gotweb with profiling enabled:
 
-  $ cd gotweb
-  $ make clean
-  $ make PROFILE=1 gotweb
-  $ make # compile remaining gotweb binaries as usual
-  $ doas make install
-  $ doas chown www /var/www/cgi-bin/gotweb/
-
-After loading a gotweb page in the browser, there should now
-be a gmon.out file next to the gotweb binary:
-
-$ ls -l /var/www/cgi-bin/gotweb/
-total 6088
--rw-r--r--  1 www   daemon   427642 Jun 17 22:04 gmon.out
--rwxr-xr-x  1 www   www     2630488 Jun 17 22:03 gotweb
-drwxr-xr-x  2 root  daemon      512 Jun 17 22:03 gw_tmpl
-drwxr-xr-x  2 root  daemon      512 Jun 17 22:03 libexec
-
-
 Guidelines for reporting problems:
 
 All problem/bug reports should include a reproduction recipe in form of a
blob - ae4b3d19d689e504703a7a34bf04a9ba4607fde8
blob + e754777a9202afca9a7b80dfd634b3c605d8a5cd
--- got/got.1
+++ got/got.1
@@ -3453,7 +3453,7 @@ create a pull request.
 .Xr git-repository 5 ,
 .Xr got-worktree 5 ,
 .Xr got.conf 5 ,
-.Xr gotweb 8
+.Xr gotwebd 8
 .Sh AUTHORS
 .An Anthony J. Bentley Aq Mt bentley@openbsd.org
 .An Christian Weisgerber Aq Mt naddy@openbsd.org
@@ -3477,7 +3477,7 @@ Parts of
 .Nm ,
 .Xr tog 1 ,
 and
-.Xr gotweb 8
+.Xr gotwebd 8
 were derived from code under copyright by:
 .Pp
 .An Caldera International
blob - e85f3f4271c437daae68be411b08e6808d317293
blob + 1ead58d255acf59cc3547c69f091a88b2a8e2102
--- got-dist.txt
+++ got-dist.txt
@@ -41,62 +41,6 @@
 /gotsh/Makefile
 /gotsh/gotsh.1
 /gotsh/gotsh.c
-/gotweb
-/gotweb/Makefile
-/gotweb/Makefile.inc
-/gotweb/files
-/gotweb/files/cgi-bin
-/gotweb/files/cgi-bin/gw_tmpl
-/gotweb/files/cgi-bin/gw_tmpl/blame.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/briefs.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/commit.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/diff.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/err.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/index.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/summry.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/tag.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/tags.tmpl
-/gotweb/files/cgi-bin/gw_tmpl/tree.tmpl
-/gotweb/files/htdocs
-/gotweb/files/htdocs/gotweb
-/gotweb/files/htdocs/gotweb/android-chrome-192x192.png
-/gotweb/files/htdocs/gotweb/android-chrome-384x384.png
-/gotweb/files/htdocs/gotweb/apple-touch-icon.png
-/gotweb/files/htdocs/gotweb/browserconfig.xml
-/gotweb/files/htdocs/gotweb/favicon-16x16.png
-/gotweb/files/htdocs/gotweb/favicon-32x32.png
-/gotweb/files/htdocs/gotweb/favicon.ico
-/gotweb/files/htdocs/gotweb/got.png
-/gotweb/files/htdocs/gotweb/got_large.png
-/gotweb/files/htdocs/gotweb/gotweb.css
-/gotweb/files/htdocs/gotweb/index.html
-/gotweb/files/htdocs/gotweb/mstile-150x150.png
-/gotweb/files/htdocs/gotweb/safari-pinned-tab.svg
-/gotweb/files/htdocs/gotweb/site.webmanifest
-/gotweb/gotweb.8
-/gotweb/gotweb.c
-/gotweb/gotweb.conf.5
-/gotweb/gotweb.h
-/gotweb/libexec
-/gotweb/libexec/Makefile
-/gotweb/libexec/Makefile.inc
-/gotweb/libexec/got-read-blob
-/gotweb/libexec/got-read-blob/Makefile
-/gotweb/libexec/got-read-commit
-/gotweb/libexec/got-read-commit/Makefile
-/gotweb/libexec/got-read-gitconfig
-/gotweb/libexec/got-read-gitconfig/Makefile
-/gotweb/libexec/got-read-gotconfig
-/gotweb/libexec/got-read-gotconfig/Makefile
-/gotweb/libexec/got-read-object
-/gotweb/libexec/got-read-object/Makefile
-/gotweb/libexec/got-read-pack
-/gotweb/libexec/got-read-pack/Makefile
-/gotweb/libexec/got-read-tag
-/gotweb/libexec/got-read-tag/Makefile
-/gotweb/libexec/got-read-tree
-/gotweb/libexec/got-read-tree/Makefile
-/gotweb/parse.y
 /gotwebd
 /gotwebd/Makefile
 /gotwebd/Makefile.inc
blob - 3f9b3180520b398deed0f58abea911812958de70 (mode 644)
blob + /dev/null
--- gotweb/Makefile
+++ /dev/null
@@ -1,58 +0,0 @@
-.PATH:${.CURDIR}/../lib
-
-SUBDIR = libexec
-
-.include "../got-version.mk"
-.include "Makefile.inc"
-
-PROG =		gotweb
-SRCS =		gotweb.c parse.y blame.c commit_graph.c delta.c diff.c \
-		diffreg.c error.c object.c object_cache.c \
-		object_idset.c object_parse.c opentemp.c path.c pack.c \
-		privsep.c reference.c repository.c sha1.c \
-		inflate.c buf.c rcsutil.c diff3.c lockfile.c \
-		deflate.c object_create.c delta_cache.c gotconfig.c \
-		diff_main.c diff_atomize_text.c diff_myers.c diff_output.c \
-		diff_output_plain.c diff_output_unidiff.c \
-		diff_output_edscript.c diff_patience.c \
-		bloom.c murmurhash2.c sigs.c date.c object_open_privsep.c \
-		read_gitconfig_privsep.c read_gotconfig_privsep.c \
-		pollfd.c reference_parse.c
-MAN =		${PROG}.conf.5 ${PROG}.8
-
-CPPFLAGS +=	-I${.CURDIR}/../include -I${.CURDIR}/../lib -I${.CURDIR} \
-		-I${KCGIBASE}/include
-LDADD +=	-L${KCGIBASE}/lib -lkcgihtml -lkcgi -lz -lm
-LDSTATIC =	${STATIC}
-
-.if ${GOT_RELEASE} != "Yes"
-NOMAN = Yes
-.endif
-
-realinstall:
-	if [ ! -d ${DESTDIR}${CGI_DIR}/. ]; then \
-		${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${CGI_DIR}; \
-	fi
-	if [ ! -d ${DESTDIR}${PUB_REPOS_DIR}/. ]; then \
-		${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PUB_REPOS_DIR}; \
-	fi
-	${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 ${PROG} \
-	    ${DESTDIR}${CGI_DIR}/${PROG}
-	if [ ! -d ${DESTDIR}${TMPL_DIR}/. ]; then \
-		${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${TMPL_DIR}; \
-	fi
-	${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \
-	    ${.CURDIR}/files/cgi-bin/gw_tmpl/* ${DESTDIR}${TMPL_DIR}
-	if [ ! -d ${DESTDIR}${HTTPD_DIR}/. ]; then \
-		${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${HTTPD_DIR}; \
-	fi
-	if [ ! -d ${DESTDIR}${TMP_DIR}/. ]; then \
-		${INSTALL} -d -o ${WWWUSR} -g ${WWWGRP} -m 755 ${DESTDIR}${TMP_DIR}; \
-	fi
-	if [ ! -d ${DESTDIR}${PROG_DIR}/. ]; then \
-		${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PROG_DIR}; \
-	fi
-	${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \
-	    ${.CURDIR}/files/htdocs/${PROG}/* ${DESTDIR}${PROG_DIR}
-
-.include <bsd.prog.mk>
blob - f6a499dbd885b285605963a25b23076855a8786f (mode 644)
blob + /dev/null
--- gotweb/Makefile.inc
+++ /dev/null
@@ -1,26 +0,0 @@
-KCGIBASE ?=	/usr/local
-LDADD +=	-lz -lutil
-LDSTATIC =	${STATIC}
-CHROOT_DIR ?=	/var/www
-GOTWEB_DIR =	/cgi-bin/gotweb
-LIBEXECDIR =	${GOTWEB_DIR}/libexec
-LIBEXEC_DIR =	${CHROOT_DIR}${LIBEXECDIR}
-ETC_DIR =	${CHROOT_DIR}/etc
-HTTPD_DIR =	${CHROOT_DIR}/htdocs
-GOTWEB_TMP_DIR ?=	/got/tmp
-TMP_DIR =	${CHROOT_DIR}${GOTWEB_TMP_DIR}
-PROG_DIR =	${HTTPD_DIR}/${PROG}
-CGI_DIR =	${CHROOT_DIR}${GOTWEB_DIR}
-TMPL_DIR =	${CGI_DIR}/gw_tmpl
-PUB_REPOS_DIR =	${CHROOT_DIR}/got/public
-WWWUSR ?=	www
-WWWGRP ?=	www
-
-CPPFLAGS +=	-DGOT_TMPDIR=${GOTWEB_TMP_DIR}
-
-.if defined(PROFILE)
-CPPFLAGS += -DPROFILE
-DEBUG = -O0 -pg -g -static
-.else
-DEBUG = -O0 -g
-.endif
blob - 64237d2f0dec8688ccd27965e4b944d1a3ca6d8e (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/blame.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='blame_title_wrapper'>
-				<div id='blame_title'>Blame</div>
-			</div>
-			<div id='blame_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 53d8e825b7ea9995ba68ecbc6a02e8a75f0ced59 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/briefs.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='briefs_title_wrapper'>
-				<div id='briefs_title'>Commit Briefs</div>
-			</div>
-			<div id='briefs_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - ef504f03cfeb9e20af5a92e2c4d3801ee5cb9650 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/commit.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='commits_title_wrapper'>
-				<div id='commits_title'>Commits</div>
-			</div>
-			<div id='commits_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 6a466f25e20dd30349a4913eab6019f62fbfe04a (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/diff.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='diff_title_wrapper'>
-				<div id='diff_title'>Commit Diff</div>
-			</div>
-			<div id='diff_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 52b2cb624d22803080950f1af69d72ea818f9fd8 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/err.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='err_title_wrapper'>
-				<div id='err_title'>Error</div>
-			</div>
-			<div id='err_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 12819268eddbfa9b3a5d68d8897c937bb20f7cd4 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/index.tmpl
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			@@content@@
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 12819268eddbfa9b3a5d68d8897c937bb20f7cd4 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/summry.tmpl
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			@@content@@
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 1867b81cba52c7f0a18b2b931b0d91b92ad52a85 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/tag.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='tag_title_wrapper'>
-				<div id='tag_title'>Tag</div>
-			</div>
-			<div id='tag_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - 12819268eddbfa9b3a5d68d8897c937bb20f7cd4 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/tags.tmpl
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			@@content@@
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - f7c5a935c98101e547c6c513143bf0096ae1c610 (mode 644)
blob + /dev/null
--- gotweb/files/cgi-bin/gw_tmpl/tree.tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>@@title@@</title>
-		@@head@@
-	</head>
-	<body>
-	<div id="gw_body">
-		<div id="header">
-			@@header@@
-		</div>
-		<div id="site_path">
-			@@sitepath@@
-			@@search@@
-		</div>
-		<div id="content">
-			<div id='tree_title_wrapper'>
-				<div id='tree_title'>Tree</div>
-			</div>
-			<div id='tree_content'>
-				@@content@@
-			</div>
-		</div>
-		@@siteowner@@
-	</div>
-	</body>
-</html>
blob - f841f054bc2941b0cdca7e496ea69621671d6766 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/android-chrome-192x192.png and /dev/null differ
blob - 653a1510ce933f7fe9fbab2fcd171f04fa0b24cc (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/android-chrome-384x384.png and /dev/null differ
blob - 460aa1299f8e9f37773618bcab2619794416fb49 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/apple-touch-icon.png and /dev/null differ
blob - b3930d0f047184047cb81d620436d91653438b8b (mode 644)
blob + /dev/null
--- gotweb/files/htdocs/gotweb/browserconfig.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<browserconfig>
-    <msapplication>
-        <tile>
-            <square150x150logo src="/mstile-150x150.png"/>
-            <TileColor>#da532c</TileColor>
-        </tile>
-    </msapplication>
-</browserconfig>
blob - f6c1a7c289faa4a48e03c97e68b1ba7a11dfddd1 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/favicon-16x16.png and /dev/null differ
blob - 0ceea8c0eabe73e8d12cf106d73c34abb1999cb2 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/favicon-32x32.png and /dev/null differ
blob - ee414573031ea5b310539196d2530a1e52d49b64 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/favicon.ico and /dev/null differ
blob - 33933f80ee46217039804bc96672ede12b352b93 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/got.png and /dev/null differ
blob - 97ace786464b193baf1cd51e54016aea3016e62f (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/got_large.png and /dev/null differ
blob - eb7e67f6b7ca0ddd442d0f8f38810ba7846efae1 (mode 644)
blob + /dev/null
--- gotweb/files/htdocs/gotweb/gotweb.css
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- * Copyright (c) 2019 Jerome Kasper <neon.king.fr@gmail.com>
- * Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/* general sections */
-
-a {
-	color: #444444;
-	text-decoration: none;
-}
-a:hover {
-	color: Gold;
-	text-decoration: none;
-}
-body {
-	background-color: #ffffff;
-	color: #000000;
-	margin: 0;
-	padding: 0;
-	font-family: Arial, sans-serif;
-}
-
-.diff_minus, .diff_submodule {
-	color: magenta;
-}
-.diff_plus, .diff_symlink, .diff_author {
-	color: darkcyan;
-}
-.diff_chunk_header, .diff_date {
-	background-color: LightSlateGray;
-	color: yellow;
-}
-.diff_meta, .diff_executable, .diff_commit {
-	color: green;
-}
-.diff_directory {
-	color: blue;
-}
-
-.back_white {
-	background-color: #ffffff;
-}
-.back_lightgray {
-	background-color: #d8f3ef;
-}
-
-#refs_str {
-	background-color: #243647;
-	color: #ffffff;
-	font-style: italic;
-}
-#dotted_line {
-	clear: left;
-	float: left;
-	width: 100%;
-	border-top: 1px dotted #444444;
-}
-#solid_line {
-	clear: left;
-	float: left;
-	width: 100%;
-	border-top: 1px solid #444444;
-}
-#header {
-	overflow: auto;
-	width: 100%;
-	background-image: linear-gradient(to right, White, LightSlateGray);
-}
-#header a {
-	color: #ffffff;
-	font-size: 1.2em;
-	text-decoration: none;
-}
-#header a:hover {
-	color: Gold;
-	font-size: 1.2em;
-	text-decoration: none;
-}
-#site_path {
-	clear: left;
-	float: left;
-	overflow: auto;
-	width: 100%;
-	background-color: #243647;
-}
-#site_link {
-	float: left;
-	width: 40%;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	color: #ffffff;
-	overflow: hidden;
-}
-#site_link a {
-	color: #ffffff;
-	text-decoration: none;
-}
-#search {
-	float: right;
-	padding-right: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#got_link {
-	float: left;
-	padding-bottom: 10px;
-	padding-top: 10px;
-}
-#content {
-	width: 100%;
-}
-#np_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	border-bottom: 1px dotted #444444;
-	background-color: #f5fcfb;
-	overflow: hidden;
-}
-#nav_prev {
-	float: left;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	overflow: visible;
-}
-#nav_next {
-	padding-right: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	text-align: right;
-	overflow: hidden;
-}
-#navs_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: #ced7e0;
-}
-#navs {
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-	font-size: .8em;
-}
-#site_owner_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#site_owner {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#description_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#description {
-	float: left;
-	width: 72%;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#repo_owner_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#repo_owner {
-	float: left;
-	width: 72%;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#last_change_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#last_change {
-	float: left;
-	width: 72%;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#cloneurl_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#cloneurl {
-	float: left;
-	width: 72%;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	overflow: auto;
-	white-space: pre-wrap;
-}
-#tmpl_err {
-	clear: left;
-	float: left;
-	padding-left: 20px;
-	padding-top: 20px;
-	padding-bottom: 20px;
-	white-space: pre-wrap;
-}
-
-/* headers */
-
-#header_commit_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_commit {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_diff_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_diff {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_author_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_author {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_committer_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_committer {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_age_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_age {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_commit_msg_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_commit_msg {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-	white-space: pre-wrap;
-}
-#header_tree_title {
-	clear: left;
-	float: left;
-	width: 6.5em;
-	padding-left: 10px;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-#header_tree {
-	float: left;
-	width: 72%;
-	padding-top: 2px;
-	padding-bottom: 2px;
-}
-
-/* heads.tmpl */
-
-#heads_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#heads_age {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	float: left;
-	width: 7.5em;
-	overflow: auto;
-}
-#heads_space {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	float: left;
-	width: 8.5em;
-	overflow: auto;
-}
-#head {
-	float: left;
-	padding-right: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-
-/* err.tmpl */
-
-#err_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#err_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#err_content {
-	clear: left;
-	float: left;
-	width: 100%;
-	padding-left: 20px;
-	padding-top: 20px;
-	padding-bottom: 20px;
-}
-
-/* briefs.tmpl */
-
-#briefs_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#briefs_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#briefs_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#briefs_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#briefs_age {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	float: left;
-	width: 7.5em;
-	overflow: auto;
-}
-#briefs_author {
-	float: left;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	width: 8.5em;
-	font-style: italic;
-	overflow: auto;
-}
-#briefs_log {
-	float: left;
-	padding-left: 10px;
-	padding-right: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	width: 65%;
-}
-/* index.tmpl */
-
-#index_header {
-	clear: left;
-	float: left;
-	overflow: auto;
-	width: 100%;
-	background-color: Khaki;
-}
-#index_header_project {
-	clear: left;
-	float: left;
-	width: 20%;
-	padding: 10px;
-}
-#index_header_description {
-	float: left;
-	width: 30%;
-	padding: 10px;
-}
-#index_header_owner {
-	float: left;
-	width: 12%;
-	padding: 10px;
-}
-#index_header_age {
-	padding: 10px;
-	overflow: hidden;
-}
-#index_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#index_project {
-	float: left;
-	width: 20%;
-	padding: 10px;
-	overflow: hidden;
-}
-#index_project_description {
-	float: left;
-	width: 30%;
-	padding: 10px;
-	overflow: auto;
-}
-#index_project_owner {
-	float: left;
-	width: 12%;
-	padding: 10px;
-	overflow: hidden;
-}
-#index_project_age {
-	float: left;
-	width: 14%;
-	padding: 10px;
-	overflow: visible;
-}
-#index_project a {
-	color: #444444;
-	text-decoration: none;
-}
-#index_project a:hover {
-	color: SteelBlue;
-	text-decoration: none;
-}
-#index_project_navs a {
-	color: #444444;
-	text-decoration: none;
-}
-#index_project_navs a:hover {
-	color: SteelBlue;
-	text-decoration: none;
-}
-#index_next a {
-	color: #444444;
-	text-decoration: none;
-}
-#index_next a:hover {
-	color: SteelBlue;
-	text-decoration: none;
-}
-#index_prev a {
-	color: #444444;
-	text-decoration: none;
-}
-#index_prev a:hover {
-	color: SteelBlue;
-	text-decoration: none;
-}
-
-/* commit.tmpl */
-
-#commits_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#commits_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#commits_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#commits_line_wrapper {
-	clear: left;
-	float: left;
-	background-color: #f5fcfb;
-	padding-top: 3px;
-	padding-bottom: 3px;
-	width: 100%;
-}
-#commit {
-	clear: left;
-	float: left;
-	padding-left: 20px;
-	padding-top: 20px;
-	padding-bottom: 20px;
-	white-space: pre-wrap;
-}
-
-/* blame.tmpl */
-
-#blame_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#blame_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#blame_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#blame_header_wrapper {
-	float: left;
-	background-color: #f5fcfb;
-	width: 100%;
-}
-#blame_header {
-	float: left;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 2px;
-	width: 80%;
-}
-#blame {
-	clear: left;
-	float: left;
-	margin-left: 20px;
-	margin-top: 20px;
-	margin-bottom: 20px;
-	font-family: monospace;
-	white-space: pre;
-	overflow: auto;
-}
-#blame_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#blame_number {
-	float: left;
-	width: 3em;
-	overflow: hidden;
-}
-#blame_hash {
-	float: left;
-	width: 6em;
-	overflow: auto;
-}
-#blame_date {
-	float: left;
-	width: 7em;
-	overflow: auto;
-}
-#blame_author {
-	float: left;
-	width: 6em;
-	overflow: hidden;
-}
-#blame_code {
-	float:left;
-	width: 50%;
-	overflow: visible;
-}
-
-/* tree.tmpl */
-
-#tree_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#tree_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#tree_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#tree_header_wrapper {
-	clear: left;
-	float: left;
-	background-color: #f5fcfb;
-	width: 100%;
-}
-#tree_header {
-	float: left;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 2px;
-	width: 80%;
-}
-#tree {
-	clear: left;
-	float: left;
-	margin-left: 20px;
-	margin-top: 20px;
-	margin-bottom: 20px;
-	font-family: monospace;
-}
-#tree_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#tree_line {
-	clear: left;
-	float: left;
-	width: 20em;
-	padding: 1px;
-}
-#tree_line_blank {
-	float: left;
-	padding: 1px;
-	width: 8em;
-}
-#tree_line_navs {
-	float: left;
-	text-align: right;
-	padding: 1px;
-	width: 8em;
-}
-
-/* tag.tmpl */
-
-#tag_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#tag_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#tag_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#tag_header_wrapper {
-	clear: left;
-	float: left;
-	background-color: #f5fcfb;
-	width: 100%;
-}
-#tag_header {
-	float: left;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 2px;
-	width: 80%;
-}
-#tag_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#tag_age {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-	float: left;
-	width: 7.5em;
-	overflow: auto;
-}
-#tag {
-	float: left;
-	width: 8.5em;
-	font-style: italic;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#tag_name {
-	float: left;
-	padding-left: 10px;
-	padding-right: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#tag_info_date_title {
-	clear: left;
-	float: left;
-	width: 7.5em;
-}
-#tag_info_date {
-	float: left;
-}
-#tag_info_tagger_title {
-	clear: left;
-	float: left;
-	width: 7.5em;
-}
-#tag_info_tagger {
-	float: left;
-}
-#tag_info {
-	clear: left;
-	float: left;
-	margin-top: 25px;
-	white-space: pre-wrap;
-}
-
-/* tags.tmpl */
-#tags_info {
-	clear: left;
-	float: left;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-
-
-/* diff.tmpl */
-
-#diff_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#diff_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#diff_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#diff_header_wrapper {
-	float: left;
-	background-color: #f5fcfb;
-	width: 100%;
-}
-#diff_header {
-	float: left;
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 2px;
-	width: 80%;
-}
-#diff {
-	clear: left;
-	float: left;
-	margin-left: 20px;
-	margin-top: 20px;
-	margin-bottom: 20px;
-	font-family: monospace;
-	white-space: pre;
-}
-
-/* summary.tmpl */
-
-#summary_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: Khaki;
-}
-#summary_tags_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#summary_tags_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#summary_tags_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
-#summary_heads_title_wrapper {
-	clear: left;
-	float: left;
-	width: 100%;
-	background-color: LightSlateGray;
-	color: #ffffff;
-}
-#summary_heads_title {
-	padding-left: 10px;
-	padding-top: 5px;
-	padding-bottom: 5px;
-}
-#summary_heads_content {
-	clear: left;
-	float: left;
-	width: 100%;
-}
blob - 791e49544c8c5f82a710137fee5a2a4becaad616 (mode 644)
blob + /dev/null
--- gotweb/files/htdocs/gotweb/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<meta http-equiv="Refresh" content="0; url=/cgi-bin/gotweb/gotweb" />
-	</head>
-	<body>
-		<p><a href="/cgi-bin/gotweb/gotweb">gotweb</a></p>
-	</body>
-</html>
\ No newline at end of file
blob - 0c47027971e9e0a5060e23fe73e7cb0399eacea8 (mode 644)
blob + /dev/null
Binary files gotweb/files/htdocs/gotweb/mstile-150x150.png and /dev/null differ
blob - 96e67c7c4b7cb9b1b395281fae8d7cffa834a991 (mode 644)
blob + /dev/null
--- gotweb/files/htdocs/gotweb/safari-pinned-tab.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
- "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
- width="400.000000pt" height="400.000000pt" viewBox="0 0 400.000000 400.000000"
- preserveAspectRatio="xMidYMid meet">
-<metadata>
-Created by potrace 1.11, written by Peter Selinger 2001-2013
-</metadata>
-<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)"
-fill="#000000" stroke="none">
-<path d="M0 1995 l0 -1215 2000 0 2000 0 0 1215 0 1215 -2000 0 -2000 0 0
--1215z"/>
-</g>
-</svg>
blob - a1553eb86b573da072c732c9aabac5a80968461f (mode 644)
blob + /dev/null
--- gotweb/files/htdocs/gotweb/site.webmanifest
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "name": "",
-    "short_name": "",
-    "icons": [
-        {
-            "src": "/android-chrome-192x192.png",
-            "sizes": "192x192",
-            "type": "image/png"
-        },
-        {
-            "src": "/android-chrome-384x384.png",
-            "sizes": "384x384",
-            "type": "image/png"
-        }
-    ],
-    "theme_color": "#ffffff",
-    "background_color": "#ffffff",
-    "display": "standalone"
-}
blob - df516d6285a1ca6f473e533e05556b5395d506fe (mode 644)
blob + /dev/null
--- gotweb/gotweb.8
+++ /dev/null
@@ -1,155 +0,0 @@
-.\"
-.\" Copyright (c) 2020 Stefan Sperling
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.Dd $Mdocdate$
-.Dt GOTWEB 8
-.Os
-.Sh NAME
-.Nm gotweb
-.Nd Game of Trees Git repository server for web browsers
-.Sh SYNOPSIS
-.Nm
-.Sh DESCRIPTION
-.Nm
-provides a web interface allowing Git repository contents to be viewed
-with a web browser.
-.Pp
-.Nm
-is a CGI program based on
-.Xr got 1
-and
-.Xr kcgi 3
-which is intended to run in a
-.Xr chroot 2
-environment in
-.Pa /var/www .
-The program has been designed to work out of the box with
-the
-.Xr httpd 8
-web server in conjunction with
-.Xr slowcgi 8 .
-.Pp
-Enabling
-.Nm
-requires the following steps:
-.Bl -enum
-.It
-The
-.Xr httpd.conf 5
-configuration file must be adjusted to run
-.Nm
-as a CGI program with
-.Xr slowcgi 8 .
-The
-.Sx EXAMPLES
-section below contains an appropriate configuration file sample.
-.It
-httpd(8) and slowcgi(8) must be enabled and started:
-.Bd -literal -offset indent
-  # rcctl enable httpd slowcgi
-  # rcctl start httpd slowcgi
-.Ed
-.It
-Optionally, the run-time behaviour of
-.Nm
-can be configured via the
-.Xr gotweb.conf 5
-configuration file.
-.It
-Git repositories must be created at a suitable location inside the
-web server's
-.Xr chroot 2
-environment.
-These repositories should
-.Em not
-be writable by the user ID of the
-.Xr httpd 8
-server.
-The default location for repositories published by
-.Nm
-is
-.Pa /var/www/got/public .
-.It
-Git repositories served by
-.Nm
-should be kept up-to-date with a mechanism such as
-.Cm got fetch ,
-.Xr git-fetch 1 ,
-or
-.Xr rsync 1 ,
-scheduled by
-.Xr cron 8 .
-.El
-.Sh FILES
-.Bl -tag -width /var/www/got/public/ -compact
-.It Pa /var/www/got/public/
-Default location for Git repositories served by
-.Nm .
-This location can be adjusted in the
-.Xr gotweb.conf 5
-configuration file.
-.It Pa /var/www/cgi-bin/gotweb/gotweb
-The
-.Nm
-CGI program, statically linked for use in a
-.Xr chroot 2
-environment.
-.It Pa /var/www/cgi-bin/gotweb/gw_tmpl/
-Directory for template files used by
-.Nm .
-.It Pa /var/www/cgi-bin/gotweb/libexec/
-Directory containing statically linked
-.Xr got 1
-helper programs which are run by
-.Nm
-to read Git repositories.
-.It Pa /var/www/htdocs/gotweb/
-Directory containing HTML, CSS, and image files used by
-.Nm .
-.It Pa /var/www/got/tmp/
-Directory for temporary files created by
-.Nm .
-.El
-.Sh EXAMPLES
-Example configuration for httpd.conf:
-.Bd -literal -offset indent
-
-  types { include "/usr/share/misc/mime.types" }
-  server "gotweb.example.com" {
-  	listen on * port 80
-  	root "/htdocs/gotweb"
-  	location "/cgi-bin/*" {
-  		root "/"
-  		fastcgi
-  	}
-  	location "/*" {
-  		directory index "index.html"
-  	}
-  }
-.Ed
-.Sh SEE ALSO
-.Xr got 1 ,
-.Xr kcgi 3 ,
-.Xr git-repository 5 ,
-.Xr gotweb.conf 5 ,
-.Xr httpd 8 ,
-.Xr slowcgi 8
-.Sh AUTHORS
-.An Christian Weisgerber Aq Mt naddy@openbsd.org
-.An Jerome Kasper Aq Mt neon.king.fr@gmail.com
-.An Josh Rickmar Aq Mt jrick@zettaport.com
-.An Omar Polo Aq Mt op@openbsd.org
-.An Stefan Sperling Aq Mt stsp@openbsd.org
-.An Tracey Emery Aq Mt tracey@traceyemery.net
blob - 0580992091e15b774b51ac00db28f4d691a4b1a0 (mode 644)
blob + /dev/null
--- gotweb/gotweb.c
+++ /dev/null
@@ -1,4989 +0,0 @@
-/*
- * Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net>
- * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/queue.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <regex.h>
-#include <sha1.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <got_error.h>
-#include <got_object.h>
-#include <got_reference.h>
-#include <got_repository.h>
-#include <got_path.h>
-#include <got_cancel.h>
-#include <got_worktree.h>
-#include <got_diff.h>
-#include <got_commit_graph.h>
-#include <got_blame.h>
-#include <got_privsep.h>
-#include <got_opentemp.h>
-
-#include <kcgi.h>
-#include <kcgihtml.h>
-
-#include "gotweb.h"
-
-#ifndef nitems
-#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
-#endif
-
-struct gw_trans {
-	TAILQ_HEAD(headers, gw_header)	 gw_headers;
-	TAILQ_HEAD(dirs, gw_dir)	 gw_dirs;
-	struct got_repository	*repo;
-	struct gw_dir		*gw_dir;
-	struct gotweb_config	*gw_conf;
-	struct ktemplate	*gw_tmpl;
-	struct khtmlreq		*gw_html_req;
-	struct kreq		*gw_req;
-	const struct got_error	*error;
-	const char		*repo_name;
-	char			*repo_path;
-	char			*commit_id;
-	char			*next_id;
-	char			*prev_id;
-	const char		*repo_file;
-	char			*repo_folder;
-	const char		*headref;
-	unsigned int		 action;
-	unsigned int		 page;
-	unsigned int		 repos_total;
-	enum kmime		 mime;
-	int			*pack_fds;
-};
-
-struct gw_header {
-	TAILQ_ENTRY(gw_header)		 entry;
-	struct got_reflist_head		 refs;
-	char				*path;
-
-	char			*refs_str;
-	char			*commit_id; /* id_str1 */
-	char			*parent_id; /* id_str2 */
-	char			*tree_id;
-	char			*author;
-	char			*committer;
-	char			*commit_msg;
-	time_t			 committer_time;
-};
-
-struct gw_dir {
-	TAILQ_ENTRY(gw_dir)	 entry;
-	char			*name;
-	char			*owner;
-	char			*description;
-	char			*url;
-	char			*age;
-	char			*path;
-};
-
-enum gw_key {
-	KEY_ACTION,
-	KEY_COMMIT_ID,
-	KEY_FILE,
-	KEY_FOLDER,
-	KEY_HEADREF,
-	KEY_PAGE,
-	KEY_PATH,
-	KEY_PREV_ID,
-	KEY__ZMAX
-};
-
-enum gw_tmpl {
-	TEMPL_CONTENT,
-	TEMPL_HEAD,
-	TEMPL_HEADER,
-	TEMPL_SEARCH,
-	TEMPL_SITEPATH,
-	TEMPL_SITEOWNER,
-	TEMPL_TITLE,
-	TEMPL__MAX
-};
-
-enum gw_ref_tm {
-	TM_DIFF,
-	TM_LONG,
-};
-
-enum gw_tags_type {
-	TAGBRIEF,
-	TAGFULL,
-};
-
-static const char *const gw_templs[TEMPL__MAX] = {
-	"content",
-	"head",
-	"header",
-	"search",
-	"sitepath",
-	"siteowner",
-	"title",
-};
-
-static const struct kvalid gw_keys[KEY__ZMAX] = {
-	{ kvalid_stringne,	"action" },
-	{ kvalid_stringne,	"commit" },
-	{ kvalid_stringne,	"file" },
-	{ kvalid_stringne,	"folder" },
-	{ kvalid_stringne,	"headref" },
-	{ kvalid_int,		"page" },
-	{ kvalid_stringne,	"path" },
-	{ kvalid_stringne,	"prev" },
-};
-
-static struct gw_header		*gw_init_header(void);
-
-static void			 gw_free_header(struct gw_header *);
-
-static int			 gw_template(size_t, void *);
-
-static const struct got_error	*gw_error(struct gw_trans *);
-static const struct got_error	*gw_init_gw_dir(struct gw_dir **, const char *);
-static const struct got_error	*gw_get_repo_description(char **,
-				    struct gw_trans *, char *);
-static const struct got_error	*gw_get_repo_owner(char **, struct gw_trans *,
-				    char *);
-static const struct got_error	*gw_get_time_str(char **, time_t, int);
-static const struct got_error	*gw_get_repo_age(char **, struct gw_trans *,
-				    char *, const char *, int);
-static const struct got_error	*gw_output_file_blame(struct gw_trans *,
-				    struct gw_header *);
-static const struct got_error	*gw_output_blob_buf(struct gw_trans *,
-				    struct gw_header *);
-static const struct got_error	*gw_output_repo_tree(struct gw_trans *,
-				    struct gw_header *);
-static const struct got_error	*gw_output_diff(struct gw_trans *,
-				    struct gw_header *);
-static const struct got_error	*gw_output_repo_tags(struct gw_trans *,
-				    struct gw_header *, int, int);
-static const struct got_error	*gw_output_repo_heads(struct gw_trans *);
-static const struct got_error	*gw_output_site_link(struct gw_trans *);
-static const struct got_error	*gw_get_clone_url(char **, struct gw_trans *,
-				    char *);
-static const struct got_error	*gw_colordiff_line(struct gw_trans *, char *);
-
-static const struct got_error	*gw_gen_commit_header(struct gw_trans *, char *,
-				    char*);
-static const struct got_error	*gw_gen_diff_header(struct gw_trans *, char *,
-				    char*);
-static const struct got_error	*gw_gen_author_header(struct gw_trans *,
-				    const char *);
-static const struct got_error	*gw_gen_age_header(struct gw_trans *,
-				    const char *);
-static const struct got_error	*gw_gen_committer_header(struct gw_trans *,
-				    const char *);
-static const struct got_error	*gw_gen_commit_msg_header(struct gw_trans*,
-				    char *);
-static const struct got_error	*gw_gen_tree_header(struct gw_trans *, char *);
-static const struct got_error	*gw_display_open(struct gw_trans *, enum khttp,
-				    enum kmime);
-static const struct got_error	*gw_display_index(struct gw_trans *);
-static const struct got_error	*gw_get_header(struct gw_trans *,
-				    struct gw_header *, int);
-static const struct got_error	*gw_get_commits(struct gw_trans *,
-				    struct gw_header *, int,
-				    struct got_object_id *);
-static const struct got_error	*gw_get_commit(struct gw_trans *,
-				    struct gw_header *,
-				    struct got_commit_object *,
-				    struct got_object_id *);
-static const struct got_error	*gw_apply_unveil(const char *);
-static const struct got_error	*gw_blame_cb(void *, int, int,
-				    struct got_commit_object *,
-				    struct got_object_id *);
-static const struct got_error	*gw_load_got_paths(struct gw_trans *);
-static const struct got_error	*gw_load_got_path(struct gw_trans *,
-				    struct gw_dir *);
-static const struct got_error	*gw_parse_querystring(struct gw_trans *);
-static const struct got_error	*gw_blame(struct gw_trans *);
-static const struct got_error	*gw_blob(struct gw_trans *);
-static const struct got_error	*gw_diff(struct gw_trans *);
-static const struct got_error	*gw_index(struct gw_trans *);
-static const struct got_error	*gw_commits(struct gw_trans *);
-static const struct got_error	*gw_briefs(struct gw_trans *);
-static const struct got_error	*gw_summary(struct gw_trans *);
-static const struct got_error	*gw_tree(struct gw_trans *);
-static const struct got_error	*gw_tag(struct gw_trans *);
-static const struct got_error	*gw_tags(struct gw_trans *);
-
-struct gw_query_action {
-	unsigned int		 func_id;
-	const char		*func_name;
-	const struct got_error	*(*func_main)(struct gw_trans *);
-	const char		*template;
-};
-
-enum gw_query_actions {
-	GW_BLAME,
-	GW_BLOB,
-	GW_BRIEFS,
-	GW_COMMITS,
-	GW_DIFF,
-	GW_ERR,
-	GW_INDEX,
-	GW_SUMMARY,
-	GW_TAG,
-	GW_TAGS,
-	GW_TREE,
-};
-
-static const struct gw_query_action gw_query_funcs[] = {
-	{ GW_BLAME,	"blame",	gw_blame,	"gw_tmpl/blame.tmpl" },
-	{ GW_BLOB,	"blob",		NULL,		NULL },
-	{ GW_BRIEFS,	"briefs",	gw_briefs,	"gw_tmpl/briefs.tmpl" },
-	{ GW_COMMITS,	"commits",	gw_commits,	"gw_tmpl/commit.tmpl" },
-	{ GW_DIFF,	"diff",		gw_diff,	"gw_tmpl/diff.tmpl" },
-	{ GW_ERR,	"error",	gw_error,	"gw_tmpl/err.tmpl" },
-	{ GW_INDEX,	"index",	gw_index,	"gw_tmpl/index.tmpl" },
-	{ GW_SUMMARY,	"summary",	gw_summary,	"gw_tmpl/summry.tmpl" },
-	{ GW_TAG,	"tag",		gw_tag,		"gw_tmpl/tag.tmpl" },
-	{ GW_TAGS,	"tags",		gw_tags,	"gw_tmpl/tags.tmpl" },
-	{ GW_TREE,	"tree",		gw_tree,	"gw_tmpl/tree.tmpl" },
-};
-
-static const char *
-gw_get_action_name(struct gw_trans *gw_trans)
-{
-	return gw_query_funcs[gw_trans->action].func_name;
-}
-
-static const struct got_error *
-gw_kcgi_error(enum kcgi_err kerr)
-{
-	if (kerr == KCGI_OK)
-		return NULL;
-
-	if (kerr == KCGI_EXIT || kerr == KCGI_HUP)
-		return got_error(GOT_ERR_CANCELLED);
-
-	if (kerr == KCGI_ENOMEM)
-		return got_error_set_errno(ENOMEM,
-		    kcgi_strerror(kerr));
-
-	if (kerr == KCGI_ENFILE)
-		return got_error_set_errno(ENFILE,
-		    kcgi_strerror(kerr));
-
-	if (kerr == KCGI_EAGAIN)
-		return got_error_set_errno(EAGAIN,
-		    kcgi_strerror(kerr));
-
-	if (kerr == KCGI_FORM)
-		return got_error_msg(GOT_ERR_IO,
-		    kcgi_strerror(kerr));
-
-	return got_error_from_errno(kcgi_strerror(kerr));
-}
-
-static const struct got_error *
-gw_apply_unveil(const char *repo_path)
-{
-	const struct got_error *err;
-
-#ifdef PROFILE
-	if (unveil("gmon.out", "rwc") != 0)
-		return got_error_from_errno2("unveil", "gmon.out");
-#endif
-	if (repo_path && unveil(repo_path, "r") != 0)
-		return got_error_from_errno2("unveil", repo_path);
-
-	if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
-		return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
-
-	err = got_privsep_unveil_exec_helpers();
-	if (err != NULL)
-		return err;
-
-	if (unveil(NULL, NULL) != 0)
-		return got_error_from_errno("unveil");
-
-	return NULL;
-}
-
-static int
-isbinary(const uint8_t *buf, size_t n)
-{
-	size_t i;
-
-	for (i = 0; i < n; i++)
-		if (buf[i] == 0)
-			return 1;
-	return 0;
-}
-
-static const struct got_error *
-gw_blame(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL;
-	char *age = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	/* check querystring */
-	if (gw_trans->repo_file == NULL) {
-		error = got_error_msg(GOT_ERR_QUERYSTRING,
-		    "file required in querystring");
-		goto done;
-	}
-	if (gw_trans->commit_id == NULL) {
-		error = got_error_msg(GOT_ERR_QUERYSTRING,
-		    "commit required in querystring");
-		goto done;
-	}
-
-	error = gw_get_header(gw_trans, header, 1);
-	if (error)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "blame_header_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "blame_header", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_get_time_str(&age, header->committer_time,
-	    TM_LONG);
-	if (error)
-		goto done;
-	error = gw_gen_age_header(gw_trans, age ?age : "");
-	if (error)
-		goto done;
-	error = gw_gen_commit_msg_header(gw_trans, header->commit_msg);
-	if (error)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "dotted_line", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "blame", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_output_file_blame(gw_trans, header);
-	if (error)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-done:
-	gw_free_header(header);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_blob(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL, *err = NULL;
-	struct gw_header *header = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	/* check querystring */
-	if (gw_trans->repo_file == NULL) {
-		error = got_error_msg(GOT_ERR_QUERYSTRING,
-		    "file required in querystring");
-		goto done;
-	}
-	if (gw_trans->commit_id == NULL) {
-		error = got_error_msg(GOT_ERR_QUERYSTRING,
-		    "commit required in querystring");
-		goto done;
-	}
-	error = gw_get_header(gw_trans, header, 1);
-	if (error)
-		goto done;
-
-	error = gw_output_blob_buf(gw_trans, header);
-done:
-	if (error) {
-		gw_trans->mime = KMIME_TEXT_PLAIN;
-		err = gw_display_index(gw_trans);
-		if (err) {
-			error = err;
-			goto errored;
-		}
-		kerr = khttp_puts(gw_trans->gw_req, error->msg);
-	}
-errored:
-	gw_free_header(header);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_diff(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL;
-	char *age = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	error = gw_get_header(gw_trans, header, 1);
-	if (error)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "diff_header_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "diff_header", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_gen_diff_header(gw_trans, header->parent_id,
-	    header->commit_id);
-	if (error)
-		goto done;
-	error = gw_gen_commit_header(gw_trans, header->commit_id,
-	    header->refs_str);
-	if (error)
-		goto done;
-	error = gw_gen_tree_header(gw_trans, header->tree_id);
-	if (error)
-		goto done;
-	error = gw_gen_author_header(gw_trans, header->author);
-	if (error)
-		goto done;
-	error = gw_gen_committer_header(gw_trans, header->author);
-	if (error)
-		goto done;
-	error = gw_get_time_str(&age, header->committer_time,
-	    TM_LONG);
-	if (error)
-		goto done;
-	error = gw_gen_age_header(gw_trans, age ?age : "");
-	if (error)
-		goto done;
-	error = gw_gen_commit_msg_header(gw_trans, header->commit_msg);
-	if (error)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "dotted_line", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "diff", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_output_diff(gw_trans, header);
-	if (error)
-		goto done;
-
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	gw_free_header(header);
-	free(age);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_index(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_dir *gw_dir = NULL;
-	char *href_next = NULL, *href_prev = NULL, *href_summary = NULL;
-	char *href_briefs = NULL, *href_commits = NULL, *href_tree = NULL;
-	char *href_tags = NULL;
-	unsigned int prev_disp = 0, next_disp = 1, dir_c = 0;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1) {
-		error = got_error_from_errno("pledge");
-		return error;
-	}
-#endif
-	error = gw_apply_unveil(gw_trans->gw_conf->got_repos_path);
-	if (error)
-		return error;
-
-	error = gw_load_got_paths(gw_trans);
-	if (error)
-		return error;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "index_header", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "index_header_project", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khtml_puts(gw_trans->gw_html_req, "Project");
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-
-	if (gw_trans->gw_conf->got_show_repo_description) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "index_header_description", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_puts(gw_trans->gw_html_req, "Description");
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	if (gw_trans->gw_conf->got_show_repo_owner) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "index_header_owner", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_puts(gw_trans->gw_html_req, "Owner");
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	if (gw_trans->gw_conf->got_show_repo_age) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "index_header_age", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_puts(gw_trans->gw_html_req, "Last Change");
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-
-	if (TAILQ_EMPTY(&gw_trans->gw_dirs)) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "index_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_printf(gw_trans->gw_html_req,
-		    "No repositories found in %s",
-		    gw_trans->gw_conf->got_repos_path);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "dotted_line", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-		return error;
-	}
-
-	TAILQ_FOREACH(gw_dir, &gw_trans->gw_dirs, entry)
-		dir_c++;
-
-	TAILQ_FOREACH(gw_dir, &gw_trans->gw_dirs, entry) {
-		if (gw_trans->page > 0 && (gw_trans->page *
-		    gw_trans->gw_conf->got_max_repos_display) > prev_disp) {
-			prev_disp++;
-			continue;
-		}
-
-		prev_disp++;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "index_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_summary = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_dir->name, "action", "summary", NULL);
-		if (href_summary == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "index_project", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_summary, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, gw_dir->name);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-		if (gw_trans->gw_conf->got_show_repo_description) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "index_project_description", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    gw_dir->description ? gw_dir->description : "");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-		if (gw_trans->gw_conf->got_show_repo_owner) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "index_project_owner", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    gw_dir->owner ? gw_dir->owner : "");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-		if (gw_trans->gw_conf->got_show_repo_age) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "index_project_age", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    gw_dir->age ? gw_dir->age : "");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "navs_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "navs", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_summary, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "summary");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_briefs = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_dir->name, "action", "briefs", NULL);
-		if (href_briefs == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_briefs, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "commit briefs");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			error = gw_kcgi_error(kerr);
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_commits = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_dir->name, "action", "commits", NULL);
-		if (href_commits == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_commits, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "commits");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_tags = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_dir->name, "action", "tags", NULL);
-		if (href_tags == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_tags, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "tags");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_tree = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_dir->name, "action", "tree", NULL);
-		if (href_tree == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_tree, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "tree");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 4);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "dotted_line", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		free(href_summary);
-		href_summary = NULL;
-		free(href_briefs);
-		href_briefs = NULL;
-		free(href_commits);
-		href_commits = NULL;
-		free(href_tags);
-		href_tags = NULL;
-		free(href_tree);
-		href_tree = NULL;
-
-		if (gw_trans->gw_conf->got_max_repos_display == 0)
-			continue;
-
-		if ((next_disp == gw_trans->gw_conf->got_max_repos_display) ||
-		    ((gw_trans->gw_conf->got_max_repos_display > 0) &&
-		    (gw_trans->page > 0) &&
-		    (next_disp == gw_trans->gw_conf->got_max_repos_display ||
-		    prev_disp == gw_trans->repos_total))) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "np_wrapper", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "nav_prev", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-
-		if ((gw_trans->gw_conf->got_max_repos_display > 0) &&
-		    (gw_trans->page > 0) &&
-		    (next_disp == gw_trans->gw_conf->got_max_repos_display ||
-		    prev_disp == gw_trans->repos_total)) {
-			href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "page",
-			    KATTRX_INT, (int64_t)(gw_trans->page - 1), NULL);
-			if (href_prev == NULL) {
-				error = got_error_from_errno("khttp_urlpartx");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_prev, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "Previous");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-
-		if (gw_trans->gw_conf->got_max_repos_display > 0 &&
-		    next_disp == gw_trans->gw_conf->got_max_repos_display &&
-		    dir_c != (gw_trans->page + 1) *
-		    gw_trans->gw_conf->got_max_repos_display) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "nav_next", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			href_next = khttp_urlpartx(NULL, NULL, "gotweb", "page",
-			    KATTRX_INT, (int64_t)(gw_trans->page + 1), NULL);
-			if (href_next == NULL) {
-				error = got_error_from_errno("khttp_urlpartx");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_next, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "Next");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-			if (kerr != KCGI_OK)
-				goto done;
-			next_disp = 0;
-			break;
-		}
-
-		if ((gw_trans->gw_conf->got_max_repos_display > 0) &&
-		    (gw_trans->page > 0) &&
-		    (next_disp == gw_trans->gw_conf->got_max_repos_display ||
-		    prev_disp == gw_trans->repos_total)) {
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-		next_disp++;
-	}
-done:
-	free(href_prev);
-	free(href_next);
-	free(href_summary);
-	free(href_briefs);
-	free(href_commits);
-	free(href_tags);
-	free(href_tree);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_commits(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL, *n_header = NULL;
-	char *age = NULL, *href_diff = NULL, *href_tree = NULL;
-	char *href_prev = NULL, *href_next = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-	int commit_found = 0;
-
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1) {
-		error = got_error_from_errno("pledge");
-		goto done;
-	}
-#endif
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	error = gw_get_header(gw_trans, header,
-	    gw_trans->gw_conf->got_max_commits_display);
-	if (error)
-		goto done;
-
-	TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry) {
-		if (commit_found == 0 && gw_trans->commit_id != NULL) {
-			if (strcmp(gw_trans->commit_id,
-			    n_header->commit_id) != 0)
-				continue;
-			else
-				commit_found = 1;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "commits_line_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		error = gw_gen_commit_header(gw_trans, n_header->commit_id,
-		    n_header->refs_str);
-		if (error)
-			goto done;
-		error = gw_gen_author_header(gw_trans, n_header->author);
-		if (error)
-			goto done;
-		error = gw_gen_committer_header(gw_trans, n_header->author);
-		if (error)
-			goto done;
-		error = gw_get_time_str(&age, n_header->committer_time,
-		    TM_LONG);
-		if (error)
-			goto done;
-		error = gw_gen_age_header(gw_trans, age ?age : "");
-		if (error)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "dotted_line", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "commit", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khttp_puts(gw_trans->gw_req, n_header->commit_msg);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_diff = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "diff", "commit",
-		    n_header->commit_id, NULL);
-		if (href_diff == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "navs_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "navs", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_diff, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "diff");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_tree = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "tree", "commit",
-		    n_header->commit_id, NULL);
-		if (href_tree == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_tree, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		khtml_puts(gw_trans->gw_html_req, "tree");
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "solid_line", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		free(age);
-		age = NULL;
-	}
-
-	if (gw_trans->next_id || gw_trans->prev_id) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "np_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "nav_prev", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->prev_id) {
-		href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "path",
-		    KATTRX_STRING, gw_trans->repo_name, "page",
-		    KATTRX_INT, (int64_t) (gw_trans->page - 1), "action",
-		    KATTRX_STRING, "commits", "commit", KATTRX_STRING,
-		    gw_trans->prev_id ? gw_trans->prev_id : "", NULL);
-		if (href_prev == NULL) {
-			error = got_error_from_errno("khttp_urlpartx");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_prev, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Previous");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	if (gw_trans->next_id) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "nav_next", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		href_next = khttp_urlpartx(NULL, NULL, "gotweb", "path",
-		    KATTRX_STRING, gw_trans->repo_name, "page",
-		    KATTRX_INT, (int64_t) (gw_trans->page + 1), "action",
-		    KATTRX_STRING, "commits", "commit", KATTRX_STRING,
-		    gw_trans->next_id, NULL);
-		if (href_next == NULL) {
-			error = got_error_from_errno("khttp_urlpartx");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_next, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Next");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-done:
-	gw_free_header(header);
-	TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry)
-		gw_free_header(n_header);
-	free(age);
-	free(href_next);
-	free(href_prev);
-	free(href_diff);
-	free(href_tree);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_briefs(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL, *n_header = NULL;
-	char *age = NULL, *href_diff = NULL, *href_tree = NULL;
-	char *href_prev = NULL, *href_next = NULL;
-	char *newline, *smallerthan;
-	enum kcgi_err kerr = KCGI_OK;
-	int commit_found = 0;
-
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1) {
-		error = got_error_from_errno("pledge");
-		goto done;
-	}
-#endif
-	if (gw_trans->action != GW_SUMMARY) {
-		error = gw_apply_unveil(gw_trans->gw_dir->path);
-		if (error)
-			goto done;
-	}
-
-	if (gw_trans->action == GW_SUMMARY)
-		error = gw_get_header(gw_trans, header, D_MAXSLCOMMDISP);
-	else
-		error = gw_get_header(gw_trans, header,
-		    gw_trans->gw_conf->got_max_commits_display);
-	if (error)
-		goto done;
-
-	TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry) {
-		if (commit_found == 0 && gw_trans->commit_id != NULL) {
-			if (strcmp(gw_trans->commit_id,
-			    n_header->commit_id) != 0)
-				continue;
-			else
-				commit_found = 1;
-		}
-		error = gw_get_time_str(&age, n_header->committer_time,
-		    TM_DIFF);
-		if (error)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "briefs_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "briefs_age", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, age ? age : "");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "briefs_author", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		smallerthan = strchr(n_header->author, '<');
-		if (smallerthan)
-			*smallerthan = '\0';
-		kerr = khtml_puts(gw_trans->gw_html_req, n_header->author);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_diff = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "diff", "commit",
-		    n_header->commit_id, NULL);
-		if (href_diff == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "briefs_log", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		newline = strchr(n_header->commit_msg, '\n');
-		if (newline)
-			*newline = '\0';
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_diff, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, n_header->commit_msg);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		if (n_header->refs_str) {
-			kerr = khtml_puts(gw_trans->gw_html_req, " ");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_SPAN,
-			    KATTR_ID, "refs_str", KATTR__MAX);
-			if (kerr != KCGI_OK)
-			goto done;
-			kerr = khtml_printf(gw_trans->gw_html_req, "(%s)",
-			    n_header->refs_str);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "navs_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "navs", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_diff, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "diff");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_tree = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "tree", "commit",
-		    n_header->commit_id, NULL);
-		if (href_tree == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_tree, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		khtml_puts(gw_trans->gw_html_req, "tree");
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "dotted_line", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		free(age);
-		age = NULL;
-		free(href_diff);
-		href_diff = NULL;
-		free(href_tree);
-		href_tree = NULL;
-	}
-
-	if (gw_trans->next_id || gw_trans->prev_id) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "np_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "nav_prev", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->prev_id) {
-		href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "path",
-		    KATTRX_STRING, gw_trans->repo_name, "page",
-		    KATTRX_INT, (int64_t) (gw_trans->page - 1), "action",
-		    KATTRX_STRING, "briefs", "commit", KATTRX_STRING,
-		    gw_trans->prev_id ? gw_trans->prev_id : "", NULL);
-		if (href_prev == NULL) {
-			error = got_error_from_errno("khttp_urlpartx");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_prev, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Previous");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	if (gw_trans->next_id) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "nav_next", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_next = khttp_urlpartx(NULL, NULL, "gotweb", "path",
-		    KATTRX_STRING, gw_trans->repo_name, "page",
-		    KATTRX_INT, (int64_t) (gw_trans->page + 1), "action",
-		    KATTRX_STRING, "briefs", "commit", KATTRX_STRING,
-		    gw_trans->next_id, NULL);
-		if (href_next == NULL) {
-			error = got_error_from_errno("khttp_urlpartx");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_next, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Next");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-done:
-	gw_free_header(header);
-	TAILQ_FOREACH(n_header, &gw_trans->gw_headers, entry)
-		gw_free_header(n_header);
-	free(age);
-	free(href_next);
-	free(href_prev);
-	free(href_diff);
-	free(href_tree);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_summary(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	char *age = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "summary_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-
-	if (gw_trans->gw_conf->got_show_repo_description &&
-	    gw_trans->gw_dir->description != NULL &&
-	    (strcmp(gw_trans->gw_dir->description, "") != 0)) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "description_title", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Description: ");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "description", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req,
-		    gw_trans->gw_dir->description);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->gw_conf->got_show_repo_owner &&
-	    gw_trans->gw_dir->owner != NULL &&
-	    (strcmp(gw_trans->gw_dir->owner, "") != 0)) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "repo_owner_title", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Owner: ");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "repo_owner", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req,
-		    gw_trans->gw_dir->owner);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->gw_conf->got_show_repo_age) {
-		error = gw_get_repo_age(&age, gw_trans, gw_trans->gw_dir->path,
-		    NULL, TM_LONG);
-		if (error)
-			goto done;
-		if (age != NULL) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "last_change_title", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    "Last Change: ");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "last_change", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, age);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-	}
-
-	if (gw_trans->gw_conf->got_show_repo_cloneurl &&
-	    gw_trans->gw_dir->url != NULL &&
-	    (strcmp(gw_trans->gw_dir->url, "") != 0)) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "cloneurl_title", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Clone URL: ");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "cloneurl", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, gw_trans->gw_dir->url);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "briefs_title_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "briefs_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Commit Briefs");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_briefs(gw_trans);
-	if (error)
-		goto done;
-
-	error = gw_tags(gw_trans);
-	if (error)
-		goto done;
-
-	error = gw_output_repo_heads(gw_trans);
-done:
-	free(age);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_tree(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL;
-	char *tree = NULL, *tree_html = NULL, *tree_html_disp = NULL;
-	char *age = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	error = gw_get_header(gw_trans, header, 1);
-	if (error)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "tree_header_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "tree_header", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_gen_tree_header(gw_trans, header->tree_id);
-	if (error)
-		goto done;
-	error = gw_get_time_str(&age, header->committer_time,
-	    TM_LONG);
-	if (error)
-		goto done;
-	error = gw_gen_age_header(gw_trans, age ?age : "");
-	if (error)
-		goto done;
-	error = gw_gen_commit_msg_header(gw_trans, header->commit_msg);
-	if (error)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "dotted_line", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "tree", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_output_repo_tree(gw_trans, header);
-	if (error)
-		goto done;
-
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	gw_free_header(header);
-	free(tree_html_disp);
-	free(tree_html);
-	free(tree);
-	free(age);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_tags(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL;
-	char *href_next = NULL, *href_prev = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
-	    NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-	if (gw_trans->action != GW_SUMMARY) {
-		error = gw_apply_unveil(gw_trans->gw_dir->path);
-		if (error)
-			goto done;
-	}
-
-	error = gw_get_header(gw_trans, header, 1);
-	if (error)
-		goto done;
-
-	if (gw_trans->action == GW_SUMMARY) {
-		gw_trans->next_id = NULL;
-		error = gw_output_repo_tags(gw_trans, header,
-		    D_MAXSLCOMMDISP, TAGBRIEF);
-		if (error)
-			goto done;
-	} else {
-		error = gw_output_repo_tags(gw_trans, header,
-		    gw_trans->gw_conf->got_max_commits_display, TAGBRIEF);
-		if (error)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "np_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "nav_prev", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->prev_id) {
-		href_prev = khttp_urlpartx(NULL, NULL, "gotweb", "path",
-		    KATTRX_STRING, gw_trans->repo_name, "page",
-		    KATTRX_INT, (int64_t) (gw_trans->page - 1), "action",
-		    KATTRX_STRING, "tags", "commit", KATTRX_STRING,
-		    gw_trans->prev_id ? gw_trans->prev_id : "", NULL);
-		if (href_prev == NULL) {
-			error = got_error_from_errno("khttp_urlpartx");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_prev, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Previous");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	if (gw_trans->next_id) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "nav_next", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		href_next = khttp_urlpartx(NULL, NULL, "gotweb", "path",
-		    KATTRX_STRING, gw_trans->repo_name, "page",
-		    KATTRX_INT, (int64_t) (gw_trans->page + 1), "action",
-		    KATTRX_STRING, "tags", "commit", KATTRX_STRING,
-		    gw_trans->next_id, NULL);
-		if (href_next == NULL) {
-			error = got_error_from_errno("khttp_urlpartx");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_next, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Next");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	if (gw_trans->next_id || gw_trans->page > 0) {
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-done:
-	gw_free_header(header);
-	free(href_next);
-	free(href_prev);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_tag(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct gw_header *header = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-#ifndef PROFILE
-	if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", NULL) == -1)
-		return got_error_from_errno("pledge");
-#endif
-	if ((header = gw_init_header()) == NULL)
-		return got_error_from_errno("malloc");
-
-	error = gw_apply_unveil(gw_trans->gw_dir->path);
-	if (error)
-		goto done;
-
-	if (gw_trans->commit_id == NULL) {
-		error = got_error_msg(GOT_ERR_QUERYSTRING,
-		    "commit required in querystring");
-		goto done;
-	}
-
-	error = gw_get_header(gw_trans, header, 1);
-	if (error)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "tag_header_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "tag_header", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	error = gw_gen_commit_header(gw_trans, header->commit_id,
-	    header->refs_str);
-	if (error)
-		goto done;
-	error = gw_gen_commit_msg_header(gw_trans, header->commit_msg);
-	if (error)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "dotted_line", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "tree", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	error = gw_output_repo_tags(gw_trans, header, 1, TAGFULL);
-	if (error)
-		goto done;
-
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	gw_free_header(header);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_load_got_path(struct gw_trans *gw_trans, struct gw_dir *gw_dir)
-{
-	const struct got_error *error = NULL;
-	DIR *dt;
-	char *dir_test;
-	int opened = 0;
-
-	if (asprintf(&dir_test, "%s/%s/%s",
-	    gw_trans->gw_conf->got_repos_path, gw_dir->name,
-	    GOTWEB_GIT_DIR) == -1)
-		return got_error_from_errno("asprintf");
-
-	dt = opendir(dir_test);
-	if (dt == NULL) {
-		free(dir_test);
-	} else {
-		gw_dir->path = strdup(dir_test);
-		if (gw_dir->path == NULL) {
-			opened = 1;
-			error = got_error_from_errno("strdup");
-			goto errored;
-		}
-		opened = 1;
-		goto done;
-	}
-
-	if (asprintf(&dir_test, "%s/%s/%s",
-	    gw_trans->gw_conf->got_repos_path, gw_dir->name,
-	    GOTWEB_GOT_DIR) == -1) {
-		dir_test = NULL;
-		error = got_error_from_errno("asprintf");
-		goto errored;
-	}
-
-	dt = opendir(dir_test);
-	if (dt == NULL)
-		free(dir_test);
-	else {
-		opened = 1;
-		error = got_error(GOT_ERR_NOT_GIT_REPO);
-		goto errored;
-	}
-
-	if (asprintf(&dir_test, "%s/%s",
-	    gw_trans->gw_conf->got_repos_path, gw_dir->name) == -1) {
-		error = got_error_from_errno("asprintf");
-		dir_test = NULL;
-		goto errored;
-	}
-
-	gw_dir->path = strdup(dir_test);
-	if (gw_dir->path == NULL) {
-		opened = 1;
-		error = got_error_from_errno("strdup");
-		goto errored;
-	}
-
-	dt = opendir(dir_test);
-	if (dt == NULL) {
-		error = got_error_path(gw_dir->name, GOT_ERR_NOT_GIT_REPO);
-		goto errored;
-	} else
-		opened = 1;
-done:
-	error = gw_get_repo_description(&gw_dir->description, gw_trans,
-	    gw_dir->path);
-	if (error)
-		goto errored;
-	error = gw_get_repo_owner(&gw_dir->owner, gw_trans, gw_dir->path);
-	if (error)
-		goto errored;
-	error = gw_get_repo_age(&gw_dir->age, gw_trans, gw_dir->path,
-	    NULL, TM_DIFF);
-	if (error)
-		goto errored;
-	error = gw_get_clone_url(&gw_dir->url, gw_trans, gw_dir->path);
-errored:
-	free(dir_test);
-	if (opened)
-		if (dt && closedir(dt) == -1 && error == NULL)
-			error = got_error_from_errno("closedir");
-	return error;
-}
-
-static const struct got_error *
-gw_load_got_paths(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	DIR *d;
-	struct dirent **sd_dent;
-	struct gw_dir *gw_dir;
-	struct stat st;
-	unsigned int d_cnt, d_i;
-
-	d = opendir(gw_trans->gw_conf->got_repos_path);
-	if (d == NULL) {
-		error = got_error_from_errno2("opendir",
-		    gw_trans->gw_conf->got_repos_path);
-		return error;
-	}
-
-	d_cnt = scandir(gw_trans->gw_conf->got_repos_path, &sd_dent, NULL,
-	    alphasort);
-	if (d_cnt == -1) {
-		error = got_error_from_errno2("scandir",
-		    gw_trans->gw_conf->got_repos_path);
-		goto done;
-	}
-
-	for (d_i = 0; d_i < d_cnt; d_i++) {
-		if (gw_trans->gw_conf->got_max_repos > 0 &&
-		    (d_i - 2) == gw_trans->gw_conf->got_max_repos)
-			break; /* account for parent and self */
-
-		if (strcmp(sd_dent[d_i]->d_name, ".") == 0 ||
-		    strcmp(sd_dent[d_i]->d_name, "..") == 0)
-			continue;
-
-		error = gw_init_gw_dir(&gw_dir, sd_dent[d_i]->d_name);
-		if (error)
-			goto done;
-
-		error = gw_load_got_path(gw_trans, gw_dir);
-		if (error && error->code == GOT_ERR_NOT_GIT_REPO) {
-			error = NULL;
-			continue;
-		} else if (error && error->code != GOT_ERR_LONELY_PACKIDX)
-			goto done;
-
-		if (lstat(gw_dir->path, &st) == 0 && S_ISDIR(st.st_mode) &&
-		    !got_path_dir_is_empty(gw_dir->path)) {
-			TAILQ_INSERT_TAIL(&gw_trans->gw_dirs, gw_dir,
-			    entry);
-			gw_trans->repos_total++;
-		}
-	}
-done:
-	if (d && closedir(d) == -1 && error == NULL)
-		error = got_error_from_errno("closedir");
-	return error;
-}
-
-static const struct got_error *
-gw_parse_querystring(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct kpair *p;
-	const struct gw_query_action *action = NULL;
-	unsigned int i;
-
-	if (gw_trans->gw_req->fieldnmap[0]) {
-		return got_error(GOT_ERR_QUERYSTRING);
-	} else if ((p = gw_trans->gw_req->fieldmap[KEY_PATH])) {
-		/* define gw_trans->repo_path */
-		gw_trans->repo_name = p->parsed.s;
-
-		if (asprintf(&gw_trans->repo_path, "%s/%s",
-		    gw_trans->gw_conf->got_repos_path, p->parsed.s) == -1)
-			return got_error_from_errno("asprintf");
-
-		/* get action and set function */
-		if ((p = gw_trans->gw_req->fieldmap[KEY_ACTION])) {
-			for (i = 0; i < nitems(gw_query_funcs); i++) {
-				action = &gw_query_funcs[i];
-				if (action->func_name == NULL)
-					continue;
-				if (strcmp(action->func_name,
-				    p->parsed.s) == 0) {
-					gw_trans->action = i;
-					break;
-				}
-			}
-		}
-		if (gw_trans->action == -1) {
-			gw_trans->action = GW_ERR;
-			gw_trans->error = got_error_msg(GOT_ERR_QUERYSTRING,
-			    p != NULL ? "bad action in querystring" :
-			    "no action in querystring");
-			return error;
-		}
-
-		if ((p = gw_trans->gw_req->fieldmap[KEY_COMMIT_ID])) {
-			if (asprintf(&gw_trans->commit_id, "%s",
-			    p->parsed.s) == -1)
-				return got_error_from_errno("asprintf");
-		}
-
-		if ((p = gw_trans->gw_req->fieldmap[KEY_FILE]))
-			gw_trans->repo_file = p->parsed.s;
-
-		if ((p = gw_trans->gw_req->fieldmap[KEY_FOLDER])) {
-			if (asprintf(&gw_trans->repo_folder, "%s",
-			    p->parsed.s) == -1)
-				return got_error_from_errno("asprintf");
-		}
-
-		if ((p = gw_trans->gw_req->fieldmap[KEY_PREV_ID])) {
-			if (asprintf(&gw_trans->prev_id, "%s",
-			    p->parsed.s) == -1)
-				return got_error_from_errno("asprintf");
-		}
-
-		if ((p = gw_trans->gw_req->fieldmap[KEY_HEADREF]))
-			gw_trans->headref = p->parsed.s;
-
-		error = gw_init_gw_dir(&gw_trans->gw_dir, gw_trans->repo_name);
-		if (error)
-			return error;
-
-		gw_trans->error = gw_load_got_path(gw_trans, gw_trans->gw_dir);
-	} else
-		gw_trans->action = GW_INDEX;
-
-	if ((p = gw_trans->gw_req->fieldmap[KEY_PAGE]))
-		gw_trans->page = p->parsed.i;
-
-	return error;
-}
-
-static const struct got_error *
-gw_init_gw_dir(struct gw_dir **gw_dir, const char *dir)
-{
-	const struct got_error *error;
-
-	*gw_dir = malloc(sizeof(**gw_dir));
-	if (*gw_dir == NULL)
-		return got_error_from_errno("malloc");
-
-	if (asprintf(&(*gw_dir)->name, "%s", dir) == -1) {
-		error = got_error_from_errno("asprintf");
-		free(*gw_dir);
-		*gw_dir = NULL;
-		return error;
-	}
-
-	return NULL;
-}
-
-static const struct got_error *
-gw_display_open(struct gw_trans *gw_trans, enum khttp code, enum kmime mime)
-{
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khttp_head(gw_trans->gw_req, kresps[KRESP_ALLOW], "GET");
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khttp_head(gw_trans->gw_req, kresps[KRESP_STATUS], "%s",
-	    khttps[code]);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khttp_head(gw_trans->gw_req, kresps[KRESP_CONTENT_TYPE], "%s",
-	    kmimetypes[mime]);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khttp_head(gw_trans->gw_req, "X-Content-Type-Options",
-	    "nosniff");
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khttp_head(gw_trans->gw_req, "X-Frame-Options", "DENY");
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-	kerr = khttp_head(gw_trans->gw_req, "X-XSS-Protection",
-	    "1; mode=block");
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-
-	if (gw_trans->mime == KMIME_APP_OCTET_STREAM) {
-		kerr = khttp_head(gw_trans->gw_req,
-		    kresps[KRESP_CONTENT_DISPOSITION],
-		    "attachment; filename=%s", gw_trans->repo_file);
-		if (kerr != KCGI_OK)
-			return gw_kcgi_error(kerr);
-	}
-
-	kerr = khttp_body(gw_trans->gw_req);
-	return gw_kcgi_error(kerr);
-}
-
-static const struct got_error *
-gw_display_index(struct gw_trans *gw_trans)
-{
-	const struct got_error *error;
-	enum kcgi_err kerr = KCGI_OK;
-
-	/* catch early querystring errors */
-	if (gw_trans->error)
-		gw_trans->action = GW_ERR;
-
-	error = gw_display_open(gw_trans, KHTTP_200, gw_trans->mime);
-	if (error)
-		return error;
-
-	kerr = khtml_open(gw_trans->gw_html_req, gw_trans->gw_req, 0);
-	if (kerr != KCGI_OK)
-		return gw_kcgi_error(kerr);
-
-	if (gw_trans->action != GW_BLOB) {
-		kerr = khttp_template(gw_trans->gw_req, gw_trans->gw_tmpl,
-		    gw_query_funcs[gw_trans->action].template);
-		if (kerr != KCGI_OK) {
-			khtml_close(gw_trans->gw_html_req);
-			return gw_kcgi_error(kerr);
-		}
-	}
-
-	return gw_kcgi_error(khtml_close(gw_trans->gw_html_req));
-}
-
-static const struct got_error *
-gw_error(struct gw_trans *gw_trans)
-{
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_puts(gw_trans->gw_html_req, gw_trans->error->msg);
-
-	return gw_kcgi_error(kerr);
-}
-
-static int
-gw_template(size_t key, void *arg)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-	struct gw_trans *gw_trans = arg;
-	char *ati = NULL, *fic32 = NULL, *fic16 = NULL;
-	char *swm = NULL, *spt = NULL, *css = NULL, *logo = NULL;
-
-	if (asprintf(&ati, "%s%s", gw_trans->gw_conf->got_www_path,
-	    "/apple-touch-icon.png") == -1)
-		goto err;
-	if (asprintf(&fic32, "%s%s", gw_trans->gw_conf->got_www_path,
-	    "/favicon-32x32.png") == -1)
-		goto err;
-	if (asprintf(&fic16, "%s%s", gw_trans->gw_conf->got_www_path,
-	    "/favicon-16x16.png") == -1)
-		goto err;
-	if (asprintf(&swm, "%s%s", gw_trans->gw_conf->got_www_path,
-	    "/site.webmanifest") == -1)
-		goto err;
-	if (asprintf(&spt, "%s%s", gw_trans->gw_conf->got_www_path,
-	    "/safari-pinned-tab.svg") == -1)
-		goto err;
-	if (asprintf(&css, "%s%s", gw_trans->gw_conf->got_www_path,
-	    "/gotweb.css") == -1)
-		goto err;
-	if (asprintf(&logo, "%s%s%s", gw_trans->gw_conf->got_www_path,
-	    gw_trans->gw_conf->got_www_path ? "/" : "",
-	    gw_trans->gw_conf->got_logo) == -1)
-		goto err;
-
-	switch (key) {
-	case (TEMPL_HEAD):
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META,
-		    KATTR_NAME, "viewport",
-		    KATTR_CONTENT, "initial-scale=.75, user-scalable=yes",
-		    KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META,
-		    KATTR_CHARSET, "utf-8",
-		    KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META,
-		    KATTR_NAME, "msapplication-TileColor",
-		    KATTR_CONTENT, "#da532c", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_META,
-		    KATTR_NAME, "theme-color",
-		    KATTR_CONTENT, "#ffffff", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK,
-		    KATTR_REL, "apple-touch-icon", KATTR_SIZES, "180x180",
-		    KATTR_HREF, ati, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK,
-		    KATTR_REL, "icon", KATTR_TYPE, "image/png", KATTR_SIZES,
-		    "32x32", KATTR_HREF, fic32, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK,
-		    KATTR_REL, "icon", KATTR_TYPE, "image/png", KATTR_SIZES,
-		    "16x16", KATTR_HREF, fic16, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK,
-		    KATTR_REL, "manifest", KATTR_HREF, swm,
-		    KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK,
-		    KATTR_REL, "mask-icon", KATTR_HREF,
-		    spt, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_LINK,
-		    KATTR_REL, "stylesheet", KATTR_TYPE, "text/css",
-		    KATTR_HREF, css, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			return 0;
-		break;
-	case(TEMPL_HEADER):
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "got_link", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF,  gw_trans->gw_conf->got_logo_url,
-		    KATTR_TARGET, "_sotd", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_IMG,
-		    KATTR_SRC, logo, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			return 0;
-		break;
-	case (TEMPL_SITEPATH):
-		error = gw_output_site_link(gw_trans);
-		if (error)
-			return 0;
-		break;
-	case(TEMPL_TITLE):
-		if (gw_trans->gw_conf->got_site_name != NULL) {
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    gw_trans->gw_conf->got_site_name);
-			if (kerr != KCGI_OK)
-				return 0;
-		}
-		break;
-	case (TEMPL_SEARCH):
-		break;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "search", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_FORM,
-			    KATTR_METHOD, "POST", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_INPUT, KATTR_ID,
-		    "got-search", KATTR_NAME, "got-search", KATTR_SIZE, "15",
-		    KATTR_MAXLENGTH, "50", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_BUTTON,
-		    KATTR__MAX);
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Search");
-		if (kerr != KCGI_OK)
-			return 0;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 4);
-		if (kerr != KCGI_OK)
-			return 0;
-		break;
-	case(TEMPL_SITEOWNER):
-		if (gw_trans->gw_conf->got_site_owner != NULL &&
-		    gw_trans->gw_conf->got_show_site_owner) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "site_owner_wrapper", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				return 0;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "site_owner", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				return 0;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    gw_trans->gw_conf->got_site_owner);
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-			if (kerr != KCGI_OK)
-				return 0;
-		}
-		break;
-	case(TEMPL_CONTENT):
-		error = gw_query_funcs[gw_trans->action].func_main(gw_trans);
-		if (error) {
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tmpl_err", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				return 0;
-			kerr = khttp_printf(gw_trans->gw_req, "Error: %s",
-			    error->msg);
-			if (kerr != KCGI_OK)
-				return 0;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				return 0;
-		}
-		break;
-	default:
-		return 0;
-	}
-	free(ati);
-	free(fic32);
-	free(fic16);
-	free(swm);
-	free(spt);
-	free(css);
-	free(logo);
-	return 1;
-err:
-	free(ati);
-	free(fic32);
-	free(fic16);
-	free(swm);
-	free(spt);
-	free(css);
-	free(logo);
-	return 0;
-}
-
-static const struct got_error *
-gw_gen_commit_header(struct gw_trans *gw_trans, char *str1, char *str2)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_commit_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Commit: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_commit", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_printf(gw_trans->gw_html_req, "%s ", str1);
-	if (kerr != KCGI_OK)
-		goto done;
-	if (str2 != NULL) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_SPAN,
-		    KATTR_ID, "refs_str", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_printf(gw_trans->gw_html_req, "(%s)", str2);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_gen_diff_header(struct gw_trans *gw_trans, char *str1, char *str2)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_diff_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Diff: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_diff", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	if (str1 != NULL) {
-		kerr = khtml_puts(gw_trans->gw_html_req, str1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_BR, KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, str2);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_gen_age_header(struct gw_trans *gw_trans, const char *str)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_age_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Date: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_age", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, str);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_gen_author_header(struct gw_trans *gw_trans, const char *str)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_author_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Author: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_author", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, str);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_gen_committer_header(struct gw_trans *gw_trans, const char *str)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_committer_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Committer: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_committer", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, str);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_gen_commit_msg_header(struct gw_trans *gw_trans, char *str)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_commit_msg_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Message: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_commit_msg", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khttp_puts(gw_trans->gw_req, str);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_gen_tree_header(struct gw_trans *gw_trans, char *str)
-{
-	const struct got_error *error = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_tree_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Tree: ");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "header_tree", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, str);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-done:
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_get_repo_description(char **description, struct gw_trans *gw_trans,
-    char *dir)
-{
-	const struct got_error *error = NULL;
-	FILE *f = NULL;
-	char *d_file = NULL;
-	unsigned int len;
-	size_t n;
-
-	*description = NULL;
-	if (gw_trans->gw_conf->got_show_repo_description == 0)
-		return NULL;
-
-	if (asprintf(&d_file, "%s/description", dir) == -1)
-		return got_error_from_errno("asprintf");
-
-	f = fopen(d_file, "re");
-	if (f == NULL) {
-		if (errno == ENOENT || errno == EACCES)
-			return NULL;
-		error = got_error_from_errno2("fopen", d_file);
-		goto done;
-	}
-
-	if (fseek(f, 0, SEEK_END) == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-	len = ftell(f);
-	if (len == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-	if (fseek(f, 0, SEEK_SET) == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-	*description = calloc(len + 1, sizeof(**description));
-	if (*description == NULL) {
-		error = got_error_from_errno("calloc");
-		goto done;
-	}
-
-	n = fread(*description, 1, len, f);
-	if (n == 0 && ferror(f))
-		error = got_ferror(f, GOT_ERR_IO);
-done:
-	if (f != NULL && fclose(f) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-	free(d_file);
-	return error;
-}
-
-static const struct got_error *
-gw_get_time_str(char **repo_age, time_t committer_time, int ref_tm)
-{
-	struct tm tm;
-	time_t diff_time;
-	const char *years = "years ago", *months = "months ago";
-	const char *weeks = "weeks ago", *days = "days ago", *hours = "hours ago";
-	const char *minutes = "minutes ago", *seconds = "seconds ago";
-	const char *now = "right now";
-	const char *s;
-	char datebuf[29];
-
-	*repo_age = NULL;
-
-	switch (ref_tm) {
-	case TM_DIFF:
-		diff_time = time(NULL) - committer_time;
-		if (diff_time > 60 * 60 * 24 * 365 * 2) {
-			if (asprintf(repo_age, "%lld %s",
-			    (diff_time / 60 / 60 / 24 / 365), years) == -1)
-				return got_error_from_errno("asprintf");
-		} else if (diff_time > 60 * 60 * 24 * (365 / 12) * 2) {
-			if (asprintf(repo_age, "%lld %s",
-			    (diff_time / 60 / 60 / 24 / (365 / 12)),
-			    months) == -1)
-				return got_error_from_errno("asprintf");
-		} else if (diff_time > 60 * 60 * 24 * 7 * 2) {
-			if (asprintf(repo_age, "%lld %s",
-			    (diff_time / 60 / 60 / 24 / 7), weeks) == -1)
-				return got_error_from_errno("asprintf");
-		} else if (diff_time > 60 * 60 * 24 * 2) {
-			if (asprintf(repo_age, "%lld %s",
-			    (diff_time / 60 / 60 / 24), days) == -1)
-				return got_error_from_errno("asprintf");
-		} else if (diff_time > 60 * 60 * 2) {
-			if (asprintf(repo_age, "%lld %s",
-			    (diff_time / 60 / 60), hours) == -1)
-				return got_error_from_errno("asprintf");
-		} else if (diff_time > 60 * 2) {
-			if (asprintf(repo_age, "%lld %s", (diff_time / 60),
-			    minutes) == -1)
-				return got_error_from_errno("asprintf");
-		} else if (diff_time > 2) {
-			if (asprintf(repo_age, "%lld %s", diff_time,
-			    seconds) == -1)
-				return got_error_from_errno("asprintf");
-		} else {
-			if (asprintf(repo_age, "%s", now) == -1)
-				return got_error_from_errno("asprintf");
-		}
-		break;
-	case TM_LONG:
-		if (gmtime_r(&committer_time, &tm) == NULL)
-			return got_error_from_errno("gmtime_r");
-
-		s = asctime_r(&tm, datebuf);
-		if (s == NULL)
-			return got_error_from_errno("asctime_r");
-
-		if (asprintf(repo_age, "%s UTC", datebuf) == -1)
-			return got_error_from_errno("asprintf");
-		break;
-	}
-	return NULL;
-}
-
-static const struct got_error *
-gw_get_repo_age(char **repo_age, struct gw_trans *gw_trans, char *dir,
-    const char *refname, int ref_tm)
-{
-	const struct got_error *error = NULL;
-	struct got_repository *repo = NULL;
-	struct got_commit_object *commit = NULL;
-	struct got_reflist_head refs;
-	struct got_reflist_entry *re;
-	time_t committer_time = 0, cmp_time = 0;
-
-	*repo_age = NULL;
-	TAILQ_INIT(&refs);
-
-	if (gw_trans->gw_conf->got_show_repo_age == 0)
-		return NULL;
-
-	if (gw_trans->repo)
-		repo = gw_trans->repo;
-	else {
-		error = got_repo_open(&repo, dir, NULL, gw_trans->pack_fds);
-		if (error)
-			return error;
-	}
-
-	error = got_ref_list(&refs, repo, "refs/heads",
-	    got_ref_cmp_by_name, NULL);
-	if (error)
-		goto done;
-
-	/*
-	 * Find the youngest branch tip in the repository, or the age of
-	 * the a specific branch tip if a name was provided by the caller.
-	 */
-	TAILQ_FOREACH(re, &refs, entry) {
-		struct got_object_id *id = NULL;
-
-		if (refname && strcmp(got_ref_get_name(re->ref), refname) != 0)
-			continue;
-
-		error = got_ref_resolve(&id, repo, re->ref);
-		if (error)
-			goto done;
-
-		error = got_object_open_as_commit(&commit, repo, id);
-		free(id);
-		if (error)
-			goto done;
-
-		committer_time =
-		    got_object_commit_get_committer_time(commit);
-		got_object_commit_close(commit);
-		if (cmp_time < committer_time)
-			cmp_time = committer_time;
-
-		if (refname)
-			break;
-	}
-
-	if (cmp_time != 0) {
-		committer_time = cmp_time;
-		error = gw_get_time_str(repo_age, committer_time, ref_tm);
-	}
-done:
-	got_ref_list_free(&refs);
-	if (gw_trans->repo == NULL) {
-		const struct got_error *close_err = got_repo_close(repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	return error;
-}
-
-static const struct got_error *
-gw_output_diff(struct gw_trans *gw_trans, struct gw_header *header)
-{
-	const struct got_error *error;
-	FILE *f = NULL, *f1 = NULL, *f2 = NULL;
-	int fd1 = -1, fd2 = -1;
-	struct got_object_id *id1 = NULL, *id2 = NULL;
-	char *label1 = NULL, *label2 = NULL, *line = NULL;
-	int obj_type;
-	size_t linesize = 0;
-	ssize_t linelen;
-	enum kcgi_err kerr = KCGI_OK;
-
-	f = got_opentemp();
-	if (f == NULL)
-		return NULL;
-
-	f1 = got_opentemp();
-	if (f1 == NULL) {
-		error = got_error_from_errno("got_opentemp");
-		goto done;
-	}
-
-	f2 = got_opentemp();
-	if (f2 == NULL) {
-		error = got_error_from_errno("got_opentemp");
-		goto done;
-	}
-
-	fd1 = got_opentempfd();
-	if (fd1 == -1) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-
-	fd2 = got_opentempfd();
-	if (fd2 == -1) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-
-	if (header->parent_id != NULL &&
-	    strncmp(header->parent_id, "/dev/null", 9) != 0) {
-		error = got_repo_match_object_id(&id1, &label1,
-			header->parent_id, GOT_OBJ_TYPE_ANY,
-			&header->refs, gw_trans->repo);
-		if (error)
-			goto done;
-	}
-
-	error = got_repo_match_object_id(&id2, &label2,
-	    header->commit_id, GOT_OBJ_TYPE_ANY, &header->refs,
-	    gw_trans->repo);
-	if (error)
-		goto done;
-
-	error = got_object_get_type(&obj_type, gw_trans->repo, id2);
-	if (error)
-		goto done;
-	switch (obj_type) {
-	case GOT_OBJ_TYPE_BLOB:
-		error = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
-		    fd1, fd2, id1, id2, NULL, NULL, GOT_DIFF_ALGORITHM_PATIENCE,
-		    3, 0, 0, gw_trans->repo, f);
-		break;
-	case GOT_OBJ_TYPE_TREE:
-		error = got_diff_objects_as_trees(NULL, NULL, f1, f2,
-		    fd1, fd2, id1, id2, NULL, "", "",
-		    GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, gw_trans->repo, f);
-		break;
-	case GOT_OBJ_TYPE_COMMIT:
-		error = got_diff_objects_as_commits(NULL, NULL, f1, f2,
-		    fd1, fd2, id1, id2, NULL, GOT_DIFF_ALGORITHM_PATIENCE,
-		    3, 0, 0, gw_trans->repo, f);
-		break;
-	default:
-		error = got_error(GOT_ERR_OBJ_TYPE);
-	}
-	if (error)
-		goto done;
-
-	if (fseek(f, 0, SEEK_SET) == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-
-	while ((linelen = getline(&line, &linesize, f)) != -1) {
-		error = gw_colordiff_line(gw_trans, line);
-		if (error)
-			goto done;
-		/* XXX: KHTML_PRETTY breaks this */
-		kerr = khtml_puts(gw_trans->gw_html_req, line);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-	if (linelen == -1 && ferror(f))
-		error = got_error_from_errno("getline");
-done:
-	if (f && fclose(f) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-	if (f1 && fclose(f1) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-	if (f2 && fclose(f2) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-	if (fd1 != -1 && close(fd1) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	if (fd2 != -1 && close(fd2) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	free(line);
-	free(label1);
-	free(label2);
-	free(id1);
-	free(id2);
-
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_get_repo_owner(char **owner, struct gw_trans *gw_trans, char *dir)
-{
-	const struct got_error *error = NULL, *close_err;
-	struct got_repository *repo;
-	const char *gitconfig_owner;
-
-	*owner = NULL;
-
-	if (gw_trans->gw_conf->got_show_repo_owner == 0)
-		return NULL;
-
-	error = got_repo_open(&repo, dir, NULL, gw_trans->pack_fds);
-	if (error)
-		return error;
-
-	gitconfig_owner = got_repo_get_gitconfig_owner(repo);
-	if (gitconfig_owner) {
-		*owner = strdup(gitconfig_owner);
-		if (*owner == NULL)
-			error = got_error_from_errno("strdup");
-	}
-	close_err = got_repo_close(repo);
-	if (error == NULL)
-		error = close_err;
-	return error;
-}
-
-static const struct got_error *
-gw_get_clone_url(char **url, struct gw_trans *gw_trans, char *dir)
-{
-	const struct got_error *error = NULL;
-	FILE *f;
-	char *d_file = NULL;
-	unsigned int len;
-	size_t n;
-
-	*url = NULL;
-
-	if (asprintf(&d_file, "%s/cloneurl", dir) == -1)
-		return got_error_from_errno("asprintf");
-
-	f = fopen(d_file, "re");
-	if (f == NULL) {
-		if (errno != ENOENT && errno != EACCES)
-			error = got_error_from_errno2("fopen", d_file);
-		goto done;
-	}
-
-	if (fseek(f, 0, SEEK_END) == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-	len = ftell(f);
-	if (len == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-	if (fseek(f, 0, SEEK_SET) == -1) {
-		error = got_ferror(f, GOT_ERR_IO);
-		goto done;
-	}
-
-	*url = calloc(len + 1, sizeof(**url));
-	if (*url == NULL) {
-		error = got_error_from_errno("calloc");
-		goto done;
-	}
-
-	n = fread(*url, 1, len, f);
-	if (n == 0 && ferror(f))
-		error = got_ferror(f, GOT_ERR_IO);
-done:
-	if (f && fclose(f) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-	free(d_file);
-	return NULL;
-}
-
-static const struct got_error *
-gw_output_repo_tags(struct gw_trans *gw_trans, struct gw_header *header,
-    int limit, int tag_type)
-{
-	const struct got_error *error = NULL;
-	struct got_reflist_head refs;
-	struct got_reflist_entry *re;
-	char *age = NULL;
-	char *id_str = NULL, *newline, *href_commits = NULL;
-	char *tag_commit0 = NULL, *href_tag = NULL, *href_briefs = NULL;
-	struct got_tag_object *tag = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-	int summary_header_displayed = 0, chk_next = 0;
-	int tag_count = 0, commit_found = 0, c_cnt = 0;
-
-	TAILQ_INIT(&refs);
-
-	error = got_ref_list(&refs, gw_trans->repo, "refs/tags",
-	    got_ref_cmp_tags, gw_trans->repo);
-	if (error)
-		goto done;
-
-	TAILQ_FOREACH(re, &refs, entry) {
-		const char *refname;
-		const char *tagger;
-		const char *tag_commit;
-		time_t tagger_time;
-		struct got_object_id *id;
-		struct got_commit_object *commit = NULL;
-
-		refname = got_ref_get_name(re->ref);
-		if (strncmp(refname, "refs/tags/", 10) != 0)
-			continue;
-		refname += 10;
-
-		error = got_ref_resolve(&id, gw_trans->repo, re->ref);
-		if (error)
-			goto done;
-
-		error = got_object_open_as_tag(&tag, gw_trans->repo, id);
-		if (error) {
-			if (error->code != GOT_ERR_OBJ_TYPE) {
-				free(id);
-				goto done;
-			}
-			/* "lightweight" tag */
-			error = got_object_open_as_commit(&commit,
-			    gw_trans->repo, id);
-			if (error) {
-				free(id);
-				goto done;
-			}
-			tagger = got_object_commit_get_committer(commit);
-			tagger_time =
-			    got_object_commit_get_committer_time(commit);
-			error = got_object_id_str(&id_str, id);
-			free(id);
-		} else {
-			free(id);
-			tagger = got_object_tag_get_tagger(tag);
-			tagger_time = got_object_tag_get_tagger_time(tag);
-			error = got_object_id_str(&id_str,
-			    got_object_tag_get_object_id(tag));
-		}
-		if (error)
-			goto done;
-
-		if (tag_type == TAGFULL && strncmp(id_str, header->commit_id,
-		    strlen(id_str)) != 0)
-			continue;
-
-		if (tag_type == TAGBRIEF && gw_trans->commit_id &&
-		    commit_found == 0 && strncmp(id_str, gw_trans->commit_id,
-		    strlen(id_str)) != 0)
-			continue;
-		else
-			commit_found = 1;
-
-		tag_count++;
-
-		if (chk_next) {
-			gw_trans->next_id = strdup(id_str);
-			if (gw_trans->next_id == NULL)
-				error = got_error_from_errno("strdup");
-			goto prev;
-		}
-
-		if (commit) {
-			error = got_object_commit_get_logmsg(&tag_commit0,
-			    commit);
-			if (error)
-				goto done;
-			got_object_commit_close(commit);
-		} else {
-			tag_commit0 = strdup(got_object_tag_get_message(tag));
-			if (tag_commit0 == NULL) {
-				error = got_error_from_errno("strdup");
-				goto done;
-			}
-		}
-
-		tag_commit = tag_commit0;
-		while (*tag_commit == '\n')
-			tag_commit++;
-
-		switch (tag_type) {
-		case TAGBRIEF:
-			newline = strchr(tag_commit, '\n');
-			if (newline)
-				*newline = '\0';
-
-			if (summary_header_displayed == 0) {
-				kerr = khtml_attr(gw_trans->gw_html_req,
-				    KELEM_DIV, KATTR_ID,
-				    "summary_tags_title_wrapper", KATTR__MAX);
-				if (kerr != KCGI_OK)
-					goto done;
-				kerr = khtml_attr(gw_trans->gw_html_req,
-				    KELEM_DIV, KATTR_ID,
-				    "summary_tags_title", KATTR__MAX);
-				if (kerr != KCGI_OK)
-					goto done;
-				kerr = khtml_puts(gw_trans->gw_html_req,
-				    "Tags");
-				if (kerr != KCGI_OK)
-					goto done;
-				kerr = khtml_closeelem(gw_trans->gw_html_req,
-				    2);
-				if (kerr != KCGI_OK)
-					goto done;
-				kerr = khtml_attr(gw_trans->gw_html_req,
-				    KELEM_DIV, KATTR_ID,
-				    "summary_tags_content", KATTR__MAX);
-				if (kerr != KCGI_OK)
-					goto done;
-				summary_header_displayed = 1;
-			}
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_wrapper", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_age", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			error = gw_get_time_str(&age, tagger_time, TM_DIFF);
-			if (error)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    age ? age : "");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, refname);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_name", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			href_tag = khttp_urlpart(NULL, NULL, "gotweb", "path",
-			    gw_trans->repo_name, "action", "tag", "commit",
-			    id_str, NULL);
-			if (href_tag == NULL) {
-				error = got_error_from_errno("khttp_urlpart");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_tag, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, tag_commit);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "navs_wrapper", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "navs", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_tag, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "tag");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-			if (kerr != KCGI_OK)
-				goto done;
-
-			href_briefs = khttp_urlpart(NULL, NULL, "gotweb",
-			    "path", gw_trans->repo_name, "action", "briefs",
-			    "commit", id_str, NULL);
-			if (href_briefs == NULL) {
-				error = got_error_from_errno("khttp_urlpart");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_briefs, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    "commit briefs");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-			if (kerr != KCGI_OK)
-				goto done;
-
-			href_commits = khttp_urlpart(NULL, NULL, "gotweb",
-			    "path", gw_trans->repo_name, "action", "commits",
-			    "commit", id_str, NULL);
-			if (href_commits == NULL) {
-				error = got_error_from_errno("khttp_urlpart");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_commits, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "commits");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "dotted_line", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-			if (kerr != KCGI_OK)
-				goto done;
-			break;
-		case TAGFULL:
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_info_date_title", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "Tag Date:");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_info_date", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			error = gw_get_time_str(&age, tagger_time, TM_LONG);
-			if (error)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req,
-			    age ? age : "");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_info_tagger_title", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "Tagger:");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_info_date", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, tagger);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tag_info", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khttp_puts(gw_trans->gw_req, tag_commit);
-			if (kerr != KCGI_OK)
-				goto done;
-			break;
-		default:
-			break;
-		}
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		if (limit && --limit == 0)
-			chk_next = 1;
-
-		if (tag)
-			got_object_tag_close(tag);
-		tag = NULL;
-		free(id_str);
-		id_str = NULL;
-		free(age);
-		age = NULL;
-		free(tag_commit0);
-		tag_commit0 = NULL;
-		free(href_tag);
-		href_tag = NULL;
-		free(href_briefs);
-		href_briefs = NULL;
-		free(href_commits);
-		href_commits = NULL;
-	}
-	if (tag_count == 0) {
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "summary_tags_title_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "summary_tags_title", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "Tags");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "summary_tags_content", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "tags_info", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khttp_puts(gw_trans->gw_req,
-		    "There are no tags for this repo.");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		goto done;
-	}
-prev:
-	commit_found = 0;
-	TAILQ_FOREACH_REVERSE(re, &refs, got_reflist_head, entry) {
-		const char *refname;
-		struct got_object_id *id;
-		struct got_commit_object *commit = NULL;
-
-		refname = got_ref_get_name(re->ref);
-		if (strncmp(refname, "refs/tags/", 10) != 0)
-			continue;
-		refname += 10;
-
-		error = got_ref_resolve(&id, gw_trans->repo, re->ref);
-		if (error)
-			goto done;
-
-		error = got_object_open_as_tag(&tag, gw_trans->repo, id);
-		if (error) {
-			if (error->code != GOT_ERR_OBJ_TYPE) {
-				free(id);
-				goto done;
-			}
-			/* "lightweight" tag */
-			error = got_object_open_as_commit(&commit,
-			    gw_trans->repo, id);
-			if (error) {
-				free(id);
-				goto done;
-			}
-			error = got_object_id_str(&id_str, id);
-			free(id);
-		} else {
-			free(id);
-			error = got_object_id_str(&id_str,
-			    got_object_tag_get_object_id(tag));
-		}
-		if (error)
-			goto done;
-
-		if (tag_type == TAGFULL && strncmp(id_str, header->commit_id,
-		    strlen(id_str)) != 0)
-			continue;
-
-		if (commit_found == 0 && tag_type == TAGBRIEF &&
-		    gw_trans->commit_id  != NULL &&
-		    strncmp(id_str, gw_trans->commit_id, strlen(id_str)) != 0)
-			continue;
-		else
-			commit_found = 1;
-
-		if (gw_trans->commit_id != NULL &&
-		    strcmp(id_str, gw_trans->commit_id) != 0 &&
-		    (re == TAILQ_FIRST(&refs) ||
-		    c_cnt == gw_trans->gw_conf->got_max_commits_display)) {
-			gw_trans->prev_id = strdup(id_str);
-			if (gw_trans->prev_id == NULL) {
-				error = got_error_from_errno("strdup");
-				goto done;
-			}
-			break;
-		}
-		c_cnt++;
-	}
-done:
-	if (tag)
-		got_object_tag_close(tag);
-	free(id_str);
-	free(age);
-	free(tag_commit0);
-	free(href_tag);
-	free(href_briefs);
-	free(href_commits);
-	got_ref_list_free(&refs);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static void
-gw_free_header(struct gw_header *header)
-{
-	free(header->path);
-	free(header->author);
-	free(header->committer);
-	free(header->refs_str);
-	free(header->commit_id);
-	free(header->parent_id);
-	free(header->tree_id);
-	free(header->commit_msg);
-}
-
-static struct gw_header *
-gw_init_header()
-{
-	struct gw_header *header;
-
-	header = malloc(sizeof(*header));
-	if (header == NULL)
-		return NULL;
-
-	header->path = NULL;
-	TAILQ_INIT(&header->refs);
-
-	header->refs_str = NULL;
-	header->commit_id = NULL;
-	header->committer = NULL;
-	header->author = NULL;
-	header->parent_id = NULL;
-	header->tree_id = NULL;
-	header->commit_msg = NULL;
-
-	return header;
-}
-
-static const struct got_error *
-gw_get_commits(struct gw_trans * gw_trans, struct gw_header *header,
-    int limit, struct got_object_id *iter_start_id)
-{
-	const struct got_error *error = NULL;
-	struct got_commit_graph *graph = NULL;
-	struct got_commit_object *commit = NULL;
-	int chk_next = 0, chk_multi = 0, c_cnt = 0, commit_found = 0;
-	struct gw_header *t_header = NULL;
-
-	error = got_commit_graph_open(&graph, header->path, 0);
-	if (error)
-		return error;
-
-	error = got_commit_graph_iter_start(graph, iter_start_id,
-	    gw_trans->repo, NULL, NULL);
-	if (error)
-		goto err;
-
-	for (;;) {
-		struct got_object_id id;
-
-		error = got_commit_graph_iter_next(&id, graph, gw_trans->repo,
-		    NULL, NULL);
-		if (error) {
-			if (error->code == GOT_ERR_ITER_COMPLETED)
-				error = NULL;
-			goto done;
-		}
-
-		error = got_object_open_as_commit(&commit, gw_trans->repo, &id);
-		if (error)
-			goto err;
-		if (limit == 1 && chk_multi == 0 &&
-		    gw_trans->gw_conf->got_max_commits_display != 1) {
-			error = gw_get_commit(gw_trans, header, commit, &id);
-			if (error)
-				goto err;
-			commit_found = 1;
-		} else {
-			chk_multi = 1;
-			struct gw_header *n_header = NULL;
-			if ((n_header = gw_init_header()) == NULL) {
-				error = got_error_from_errno("malloc");
-				goto err;
-			}
-			TAILQ_INSERT_TAIL(&gw_trans->gw_headers, n_header,
-			    entry);
-			error = got_ref_list(&n_header->refs, gw_trans->repo,
-			    NULL, got_ref_cmp_by_name, NULL);
-			if (error)
-				goto err;
-
-			error = gw_get_commit(gw_trans, n_header, commit, &id);
-			if (error)
-				goto err;
-			got_ref_list_free(&n_header->refs);
-
-			if (gw_trans->commit_id != NULL) {
-				if (strcmp(gw_trans->commit_id,
-				    n_header->commit_id) == 0)
-					commit_found = 1;
-			} else
-				commit_found = 1;
-
-			/*
-			 * check for one more commit before breaking,
-			 * so we know whether to navigate through gw_briefs
-			 * gw_commits and gw_summary
-			 */
-			if (chk_next && (gw_trans->action == GW_BRIEFS ||
-			    gw_trans->action == GW_COMMITS ||
-			    gw_trans->action == GW_SUMMARY)) {
-				gw_trans->next_id = strdup(n_header->commit_id);
-				if (gw_trans->next_id == NULL)
-					error = got_error_from_errno("strdup");
-				TAILQ_REMOVE(&gw_trans->gw_headers, n_header,
-				    entry);
-				goto done;
-			}
-
-		}
-		if (commit_found == 1 && (error || (limit && --limit == 0))) {
-			if (chk_multi == 0)
-				break;
-			chk_next = 1;
-		}
-	}
-done:
-	if (gw_trans->prev_id == NULL && gw_trans->commit_id != NULL &&
-	    (gw_trans->action == GW_BRIEFS || gw_trans->action == GW_COMMITS)) {
-		commit_found = 0;
-		TAILQ_FOREACH_REVERSE(t_header, &gw_trans->gw_headers,
-		    headers, entry) {
-			if (commit_found == 0 &&
-			    strcmp(gw_trans->commit_id,
-			    t_header->commit_id) != 0)
-				continue;
-			else
-				commit_found = 1;
-			if (gw_trans->commit_id != NULL &&
-			    strcmp(gw_trans->commit_id,
-			    t_header->commit_id) != 0 &&
-			    (c_cnt == gw_trans->gw_conf->got_max_commits_display
-			    || t_header ==
-			    TAILQ_FIRST(&gw_trans->gw_headers))) {
-				gw_trans->prev_id = strdup(t_header->commit_id);
-				if (gw_trans->prev_id == NULL)
-					error = got_error_from_errno("strdup");
-				break;
-			}
-			c_cnt++;
-		}
-	}
-err:
-	if (commit != NULL)
-		got_object_commit_close(commit);
-	if (graph)
-		got_commit_graph_close(graph);
-	return error;
-}
-
-static const struct got_error *
-gw_get_commit(struct gw_trans *gw_trans, struct gw_header *header,
-    struct got_commit_object *commit, struct got_object_id *id)
-{
-	const struct got_error *error = NULL;
-	struct got_reflist_entry *re;
-	struct got_object_id *id2 = NULL;
-	struct got_object_qid *parent_id;
-	char *commit_msg = NULL, *commit_msg0;
-
-	/*print commit*/
-	TAILQ_FOREACH(re, &header->refs, entry) {
-		char *s;
-		const char *name;
-		struct got_tag_object *tag = NULL;
-		struct got_object_id *ref_id;
-		int cmp;
-
-		if (got_ref_is_symbolic(re->ref))
-			continue;
-
-		name = got_ref_get_name(re->ref);
-		if (strncmp(name, "refs/", 5) == 0)
-			name += 5;
-		if (strncmp(name, "got/", 4) == 0)
-			continue;
-		if (strncmp(name, "heads/", 6) == 0)
-			name += 6;
-		if (strncmp(name, "remotes/", 8) == 0) {
-			name += 8;
-			s = strstr(name, "/" GOT_REF_HEAD);
-			if (s != NULL && s[strlen(s)] == '\0')
-				continue;
-		}
-		error = got_ref_resolve(&ref_id, gw_trans->repo, re->ref);
-		if (error)
-			return error;
-		if (strncmp(name, "tags/", 5) == 0) {
-			error = got_object_open_as_tag(&tag, gw_trans->repo,
-			    ref_id);
-			if (error) {
-				if (error->code != GOT_ERR_OBJ_TYPE) {
-					free(ref_id);
-					continue;
-				}
-				/*
-				 * Ref points at something other
-				 * than a tag.
-				 */
-				error = NULL;
-				tag = NULL;
-			}
-		}
-		cmp = got_object_id_cmp(tag ?
-		    got_object_tag_get_object_id(tag) : ref_id, id);
-		free(ref_id);
-		if (tag)
-			got_object_tag_close(tag);
-		if (cmp != 0)
-			continue;
-		s = header->refs_str;
-		if (asprintf(&header->refs_str, "%s%s%s", s ? s : "",
-		    s ? ", " : "", name) == -1) {
-			error = got_error_from_errno("asprintf");
-			free(s);
-			header->refs_str = NULL;
-			return error;
-		}
-		free(s);
-	}
-
-	error = got_object_id_str(&header->commit_id, id);
-	if (error)
-		return error;
-
-	error = got_object_id_str(&header->tree_id,
-	    got_object_commit_get_tree_id(commit));
-	if (error)
-		return error;
-
-	if (gw_trans->action == GW_DIFF) {
-		parent_id = STAILQ_FIRST(
-		    got_object_commit_get_parent_ids(commit));
-		if (parent_id != NULL) {
-			id2 = got_object_id_dup(&parent_id->id);
-			free (parent_id);
-			error = got_object_id_str(&header->parent_id, id2);
-			if (error)
-				return error;
-			free(id2);
-		} else {
-			header->parent_id = strdup("/dev/null");
-			if (header->parent_id == NULL) {
-				error = got_error_from_errno("strdup");
-				return error;
-			}
-		}
-	}
-
-	header->committer_time =
-	    got_object_commit_get_committer_time(commit);
-
-	header->author =
-	    strdup(got_object_commit_get_author(commit));
-	if (header->author == NULL) {
-		error = got_error_from_errno("strdup");
-		return error;
-	}
-	header->committer =
-	    strdup(got_object_commit_get_committer(commit));
-	if (header->committer == NULL) {
-		error = got_error_from_errno("strdup");
-		return error;
-	}
-	error = got_object_commit_get_logmsg(&commit_msg0, commit);
-	if (error)
-		return error;
-
-	commit_msg = commit_msg0;
-	while (*commit_msg == '\n')
-		commit_msg++;
-
-	header->commit_msg = strdup(commit_msg);
-	if (header->commit_msg == NULL)
-		error = got_error_from_errno("strdup");
-	free(commit_msg0);
-	return error;
-}
-
-static const struct got_error *
-gw_get_header(struct gw_trans *gw_trans, struct gw_header *header, int limit)
-{
-	const struct got_error *error = NULL;
-	char *in_repo_path = NULL;
-	struct got_object_id *id = NULL;
-	struct got_reference *ref;
-
-	error = got_repo_open(&gw_trans->repo, gw_trans->repo_path, NULL,
-	    gw_trans->pack_fds);
-	if (error)
-		return error;
-
-	if (gw_trans->commit_id == NULL || gw_trans->action == GW_COMMITS ||
-	    gw_trans->action == GW_BRIEFS || gw_trans->action == GW_SUMMARY ||
-	    gw_trans->action == GW_TAGS) {
-		error = got_ref_open(&ref, gw_trans->repo,
-		    gw_trans->headref, 0);
-		if (error)
-			return error;
-
-		error = got_ref_resolve(&id, gw_trans->repo, ref);
-		got_ref_close(ref);
-		if (error)
-			return error;
-	} else {
-		error = got_ref_open(&ref, gw_trans->repo,
-		    gw_trans->commit_id, 0);
-		if (error == NULL) {
-			int obj_type;
-			error = got_ref_resolve(&id, gw_trans->repo, ref);
-			got_ref_close(ref);
-			if (error)
-				return error;
-			error = got_object_get_type(&obj_type, gw_trans->repo,
-			    id);
-			if (error)
-				goto done;
-			if (obj_type == GOT_OBJ_TYPE_TAG) {
-				struct got_tag_object *tag;
-				error = got_object_open_as_tag(&tag,
-				    gw_trans->repo, id);
-				if (error)
-					goto done;
-				if (got_object_tag_get_object_type(tag) !=
-				    GOT_OBJ_TYPE_COMMIT) {
-					got_object_tag_close(tag);
-					error = got_error(GOT_ERR_OBJ_TYPE);
-					goto done;
-				}
-				free(id);
-				id = got_object_id_dup(
-				    got_object_tag_get_object_id(tag));
-				if (id == NULL)
-					error = got_error_from_errno(
-					    "got_object_id_dup");
-				got_object_tag_close(tag);
-				if (error)
-					goto done;
-			} else if (obj_type != GOT_OBJ_TYPE_COMMIT) {
-				error = got_error(GOT_ERR_OBJ_TYPE);
-				goto done;
-			}
-		}
-		error = got_repo_match_object_id_prefix(&id,
-			    gw_trans->commit_id, GOT_OBJ_TYPE_COMMIT,
-			    gw_trans->repo);
-		if (error)
-			goto done;
-	}
-
-	error = got_repo_map_path(&in_repo_path, gw_trans->repo,
-	    gw_trans->repo_path);
-	if (error)
-		goto done;
-
-	if (in_repo_path) {
-		header->path = strdup(in_repo_path);
-		if (header->path == NULL) {
-			error = got_error_from_errno("strdup");
-			goto done;
-		}
-	}
-
-	error = got_ref_list(&header->refs, gw_trans->repo, NULL,
-	    got_ref_cmp_by_name, NULL);
-	if (error)
-		goto done;
-
-	error = gw_get_commits(gw_trans, header, limit, id);
-done:
-	free(id);
-	free(in_repo_path);
-	return error;
-}
-
-struct blame_line {
-	int annotated;
-	char *id_str;
-	char *committer;
-	char datebuf[11]; /* YYYY-MM-DD + NUL */
-};
-
-struct gw_blame_cb_args {
-	struct blame_line *lines;
-	int nlines;
-	int nlines_prec;
-	int lineno_cur;
-	off_t *line_offsets;
-	FILE *f;
-	struct got_repository *repo;
-	struct gw_trans *gw_trans;
-};
-
-static const struct got_error *
-gw_blame_cb(void *arg, int nlines, int lineno,
-    struct got_commit_object *commit, struct got_object_id *id)
-{
-	const struct got_error *err = NULL;
-	struct gw_blame_cb_args *a = arg;
-	struct blame_line *bline;
-	char *line = NULL;
-	size_t linesize = 0;
-	off_t offset;
-	struct tm tm;
-	time_t committer_time;
-	enum kcgi_err kerr = KCGI_OK;
-
-	if (nlines != a->nlines ||
-	    (lineno != -1 && lineno < 1) || lineno > a->nlines)
-		return got_error(GOT_ERR_RANGE);
-
-	if (lineno == -1)
-		return NULL; /* no change in this commit */
-
-	/* Annotate this line. */
-	bline = &a->lines[lineno - 1];
-	if (bline->annotated)
-		return NULL;
-	err = got_object_id_str(&bline->id_str, id);
-	if (err)
-		return err;
-
-	bline->committer = strdup(got_object_commit_get_committer(commit));
-	if (bline->committer == NULL) {
-		err = got_error_from_errno("strdup");
-		goto done;
-	}
-
-	committer_time = got_object_commit_get_committer_time(commit);
-	if (gmtime_r(&committer_time, &tm) == NULL)
-		return got_error_from_errno("gmtime_r");
-	if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
-	    &tm) == 0) {
-		err = got_error(GOT_ERR_NO_SPACE);
-		goto done;
-	}
-	bline->annotated = 1;
-
-	/* Print lines annotated so far. */
-	bline = &a->lines[a->lineno_cur - 1];
-	if (!bline->annotated)
-		goto done;
-
-	offset = a->line_offsets[a->lineno_cur - 1];
-	if (fseeko(a->f, offset, SEEK_SET) == -1) {
-		err = got_error_from_errno("fseeko");
-		goto done;
-	}
-
-	while (a->lineno_cur <= a->nlines && bline->annotated) {
-		char *smallerthan, *at, *nl, *committer;
-		char *href_diff = NULL;
-		size_t len;
-
-		if (getline(&line, &linesize, a->f) == -1) {
-			if (ferror(a->f))
-				err = got_error_from_errno("getline");
-			break;
-		}
-
-		committer = bline->committer;
-		smallerthan = strchr(committer, '<');
-		if (smallerthan && smallerthan[1] != '\0')
-			committer = smallerthan + 1;
-		at = strchr(committer, '@');
-		if (at)
-			*at = '\0';
-		len = strlen(committer);
-		if (len >= 9)
-			committer[8] = '\0';
-
-		nl = strchr(line, '\n');
-		if (nl)
-			*nl = '\0';
-
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "blame_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "blame_number", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_printf(a->gw_trans->gw_html_req, "%.*d",
-		    a->nlines_prec, a->lineno_cur);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "blame_hash", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		href_diff = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    a->gw_trans->repo_name, "action", "diff", "commit",
-		    bline->id_str, NULL);
-		if (href_diff == NULL) {
-			err = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_A,
-		    KATTR_HREF, href_diff, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_printf(a->gw_trans->gw_html_req, "%.8s",
-		    bline->id_str);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_closeelem(a->gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "blame_date", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_puts(a->gw_trans->gw_html_req, bline->datebuf);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "blame_author", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_puts(a->gw_trans->gw_html_req, committer);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		kerr = khtml_attr(a->gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "blame_code", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_puts(a->gw_trans->gw_html_req, line);
-		if (kerr != KCGI_OK)
-			goto err;
-		kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		kerr = khtml_closeelem(a->gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto err;
-
-		a->lineno_cur++;
-		bline = &a->lines[a->lineno_cur - 1];
-err:
-		free(href_diff);
-	}
-done:
-	free(line);
-	if (err == NULL && kerr != KCGI_OK)
-		err = gw_kcgi_error(kerr);
-	return err;
-}
-
-static const struct got_error *
-gw_output_file_blame(struct gw_trans *gw_trans, struct gw_header *header)
-{
-	const struct got_error *error = NULL;
-	struct got_object_id *obj_id = NULL;
-	struct got_object_id *commit_id = NULL;
-	struct got_commit_object *commit = NULL;
-	struct got_blob_object *blob = NULL;
-	char *path = NULL, *in_repo_path = NULL;
-	struct gw_blame_cb_args bca;
-	int i, obj_type, fd1 = -1, fd2 = -1, fd3 = -1;
-	off_t filesize;
-	FILE *f1 = NULL, *f2 = NULL;
-
-	fd1 = got_opentempfd();
-	if (fd1 == -1)
-		return got_error_from_errno("got_opentempfd");
-	fd2 = got_opentempfd();
-	if (fd2 == -1) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-	fd3 = got_opentempfd();
-	if (fd3 == -1) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-
-	memset(&bca, 0, sizeof(bca));
-
-	if (asprintf(&path, "%s%s%s",
-	    gw_trans->repo_folder ? gw_trans->repo_folder : "",
-	    gw_trans->repo_folder ? "/" : "",
-	    gw_trans->repo_file) == -1) {
-		error = got_error_from_errno("asprintf");
-		goto done;
-	}
-
-	error = got_repo_map_path(&in_repo_path, gw_trans->repo, path);
-	if (error)
-		goto done;
-
-	error = got_repo_match_object_id(&commit_id, NULL, gw_trans->commit_id,
-	    GOT_OBJ_TYPE_COMMIT, &header->refs, gw_trans->repo);
-	if (error)
-		goto done;
-
-	error = got_object_open_as_commit(&commit, gw_trans->repo, commit_id);
-	if (error)
-		goto done;
-
-	error = got_object_id_by_path(&obj_id, gw_trans->repo, commit,
-	    in_repo_path);
-	if (error)
-		goto done;
-
-	if (obj_id == NULL) {
-		error = got_error(GOT_ERR_NO_OBJ);
-		goto done;
-	}
-
-	error = got_object_get_type(&obj_type, gw_trans->repo, obj_id);
-	if (error)
-		goto done;
-
-	if (obj_type != GOT_OBJ_TYPE_BLOB) {
-		error = got_error(GOT_ERR_OBJ_TYPE);
-		goto done;
-	}
-
-	error = got_object_open_as_blob(&blob, gw_trans->repo, obj_id, 8192,
-	    fd1);
-	if (error)
-		goto done;
-
-	bca.f = got_opentemp();
-	if (bca.f == NULL) {
-		error = got_error_from_errno("got_opentemp");
-		goto done;
-	}
-	error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
-	    &bca.line_offsets, bca.f, blob);
-	if (error || bca.nlines == 0)
-		goto done;
-
-	/* Don't include \n at EOF in the blame line count. */
-	if (bca.line_offsets[bca.nlines - 1] == filesize)
-		bca.nlines--;
-
-	bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
-	if (bca.lines == NULL) {
-		error = got_error_from_errno("calloc");
-		goto done;
-	}
-	bca.lineno_cur = 1;
-	bca.nlines_prec = 0;
-	i = bca.nlines;
-	while (i > 0) {
-		i /= 10;
-		bca.nlines_prec++;
-	}
-	bca.repo = gw_trans->repo;
-	bca.gw_trans = gw_trans;
-
-	fd1 = got_opentempfd();
-	if (fd1 == -1) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-
-	f1 = got_opentemp();
-	if (f1 == NULL) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-	f2 = got_opentemp();
-	if (f2 == NULL) {
-		error = got_error_from_errno("got_opentempfd");
-		goto done;
-	}
-
-	error = got_blame(in_repo_path, commit_id, gw_trans->repo,
-	    GOT_DIFF_ALGORITHM_PATIENCE, gw_blame_cb, &bca, NULL, NULL,
-	    fd2, fd3, f1, f2);
-done:
-	free(in_repo_path);
-	free(commit_id);
-	free(obj_id);
-	free(path);
-
-	if (fd1 != -1 && close(fd1) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	if (fd2 != -1 && close(fd2) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	if (fd3 != -1 && close(fd3) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	if (f1 && fclose(f1) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-	if (f2 && fclose(f2) == EOF && error == NULL)
-		error = got_error_from_errno("fclose");
-
-	if (blob) {
-		free(bca.line_offsets);
-		for (i = 0; i < bca.nlines; i++) {
-			struct blame_line *bline = &bca.lines[i];
-			free(bline->id_str);
-			free(bline->committer);
-		}
-		free(bca.lines);
-		if (bca.f && fclose(bca.f) == EOF && error == NULL)
-			error = got_error_from_errno("fclose");
-	}
-	if (blob)
-		got_object_blob_close(blob);
-	if (commit)
-		got_object_commit_close(commit);
-	return error;
-}
-
-static const struct got_error *
-gw_output_blob_buf(struct gw_trans *gw_trans, struct gw_header *header)
-{
-	const struct got_error *error = NULL;
-	struct got_object_id *obj_id = NULL;
-	struct got_object_id *commit_id = NULL;
-	struct got_commit_object *commit = NULL;
-	struct got_blob_object *blob = NULL;
-	char *path = NULL, *in_repo_path = NULL;
-	int obj_type, set_mime = 0, fd = -1;
-	size_t len, hdrlen;
-	const uint8_t *buf;
-	enum kcgi_err kerr = KCGI_OK;
-
-	fd = got_opentempfd();
-	if (fd == -1)
-		return got_error_from_errno("got_opentempfd");
-
-	if (asprintf(&path, "%s%s%s",
-	    gw_trans->repo_folder ? gw_trans->repo_folder : "",
-	    gw_trans->repo_folder ? "/" : "",
-	    gw_trans->repo_file) == -1) {
-		error = got_error_from_errno("asprintf");
-		goto done;
-	}
-
-	error = got_repo_map_path(&in_repo_path, gw_trans->repo, path);
-	if (error)
-		goto done;
-
-	error = got_repo_match_object_id(&commit_id, NULL, gw_trans->commit_id,
-	    GOT_OBJ_TYPE_COMMIT, &header->refs, gw_trans->repo);
-	if (error)
-		goto done;
-
-	error = got_object_open_as_commit(&commit, gw_trans->repo, commit_id);
-	if (error)
-		goto done;
-
-	error = got_object_id_by_path(&obj_id, gw_trans->repo, commit,
-	    in_repo_path);
-	if (error)
-		goto done;
-
-	if (obj_id == NULL) {
-		error = got_error(GOT_ERR_NO_OBJ);
-		goto done;
-	}
-
-	error = got_object_get_type(&obj_type, gw_trans->repo, obj_id);
-	if (error)
-		goto done;
-
-	if (obj_type != GOT_OBJ_TYPE_BLOB) {
-		error = got_error(GOT_ERR_OBJ_TYPE);
-		goto done;
-	}
-
-	error = got_object_open_as_blob(&blob, gw_trans->repo, obj_id, 8192,
-	    fd);
-	if (error)
-		goto done;
-
-	hdrlen = got_object_blob_get_hdrlen(blob);
-	do {
-		error = got_object_blob_read_block(&len, blob);
-		if (error)
-			goto done;
-		buf = got_object_blob_get_read_buf(blob);
-
-		/*
-		 * Skip blob object header first time around,
-		 * which also contains a zero byte.
-		 */
-		buf += hdrlen;
-		if (set_mime == 0) {
-			if (isbinary(buf, len - hdrlen))
-				gw_trans->mime = KMIME_APP_OCTET_STREAM;
-			else
-				gw_trans->mime = KMIME_TEXT_PLAIN;
-			set_mime = 1;
-			error = gw_display_index(gw_trans);
-			if (error)
-				goto done;
-		}
-		kerr = khttp_write(gw_trans->gw_req, buf, len - hdrlen);
-		if (kerr != KCGI_OK)
-			goto done;
-		hdrlen = 0;
-	} while (len != 0);
-done:
-	free(in_repo_path);
-	free(commit_id);
-	free(obj_id);
-	free(path);
-	if (fd != -1 && close(fd) == -1 && error == NULL)
-		error = got_error_from_errno("close");
-	if (blob)
-		got_object_blob_close(blob);
-	if (commit)
-		got_object_commit_close(commit);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_output_repo_tree(struct gw_trans *gw_trans, struct gw_header *header)
-{
-	const struct got_error *error = NULL;
-	struct got_object_id *tree_id = NULL, *commit_id = NULL;
-	struct got_tree_object *tree = NULL;
-	struct got_commit_object *commit = NULL;
-	char *path = NULL, *in_repo_path = NULL;
-	char *id_str = NULL;
-	char *build_folder = NULL;
-	char *href_blob = NULL, *href_blame = NULL;
-	const char *class = NULL;
-	int nentries, i, class_flip = 0;
-	enum kcgi_err kerr = KCGI_OK;
-
-	if (gw_trans->repo_folder != NULL) {
-		path = strdup(gw_trans->repo_folder);
-		if (path == NULL) {
-			error = got_error_from_errno("strdup");
-			goto done;
-		}
-	} else {
-		error = got_repo_map_path(&in_repo_path, gw_trans->repo,
-		    gw_trans->repo_path);
-		if (error)
-			goto done;
-		free(path);
-		path = in_repo_path;
-	}
-
-	if (gw_trans->commit_id == NULL) {
-		struct got_reference *head_ref;
-		error = got_ref_open(&head_ref, gw_trans->repo,
-		    gw_trans->headref, 0);
-		if (error)
-			goto done;
-		error = got_ref_resolve(&commit_id, gw_trans->repo, head_ref);
-		if (error)
-			goto done;
-		got_ref_close(head_ref);
-		/*
-		 * gw_trans->commit_id was not parsed from the querystring
-		 * we hit this code path from gw_index, where we don't know the
-		 * commit values for the tree link yet, so set
-		 * gw_trans->commit_id here to continue further into the tree
-		 */
-		error = got_object_id_str(&gw_trans->commit_id, commit_id);
-		if (error)
-			goto done;
-
-	} else {
-		error = got_repo_match_object_id(&commit_id, NULL,
-		    gw_trans->commit_id, GOT_OBJ_TYPE_COMMIT, &header->refs,
-		    gw_trans->repo);
-		if (error)
-			goto done;
-	}
-
-	error = got_object_open_as_commit(&commit, gw_trans->repo, commit_id);
-	if (error)
-		goto done;
-
-	error = got_object_id_by_path(&tree_id, gw_trans->repo, commit,
-	    path);
-	if (error)
-		goto done;
-
-	error = got_object_open_as_tree(&tree, gw_trans->repo, tree_id);
-	if (error)
-		goto done;
-
-	nentries = got_object_tree_get_nentries(tree);
-	for (i = 0; i < nentries; i++) {
-		struct got_tree_entry *te;
-		const char *modestr = "";
-		mode_t mode;
-
-		te = got_object_tree_get_entry(tree, i);
-
-		error = got_object_id_str(&id_str, got_tree_entry_get_id(te));
-		if (error)
-			goto done;
-
-		mode = got_tree_entry_get_mode(te);
-		if (got_object_tree_entry_is_submodule(te))
-			modestr = "$";
-		else if (S_ISLNK(mode))
-			modestr = "@";
-		else if (S_ISDIR(mode))
-			modestr = "/";
-		else if (mode & S_IXUSR)
-			modestr = "*";
-
-		if (class_flip == 0) {
-			class = "back_lightgray";
-			class_flip = 1;
-		} else {
-			class = "back_white";
-			class_flip = 0;
-		}
-
-		if (S_ISDIR(mode)) {
-			if (asprintf(&build_folder, "%s/%s",
-			    gw_trans->repo_folder ? gw_trans->repo_folder : "",
-			    got_tree_entry_get_name(te)) == -1) {
-				error = got_error_from_errno("asprintf");
-				goto done;
-			}
-
-			href_blob = khttp_urlpart(NULL, NULL, "gotweb", "path",
-			    gw_trans->repo_name, "action",
-			    gw_get_action_name(gw_trans), "commit",
-			    gw_trans->commit_id, "folder", build_folder, NULL);
-			if (href_blob == NULL) {
-				error = got_error_from_errno("khttp_urlpart");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tree_wrapper", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tree_line", KATTR_CLASS, class,
-			    KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_blob, KATTR_CLASS,
-			    "diff_directory", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_printf(gw_trans->gw_html_req, "%s%s",
-			    got_tree_entry_get_name(te), modestr);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tree_line_blank", KATTR_CLASS, class,
-			    KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_entity(gw_trans->gw_html_req,
-			    KENTITY_nbsp);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-			if (kerr != KCGI_OK)
-				goto done;
-		} else {
-			href_blob = khttp_urlpart(NULL, NULL, "gotweb", "path",
-			    gw_trans->repo_name, "action", "blob", "commit",
-			    gw_trans->commit_id, "file",
-			    got_tree_entry_get_name(te), "folder",
-			    gw_trans->repo_folder ? gw_trans->repo_folder : "",
-			    NULL);
-			if (href_blob == NULL) {
-				error = got_error_from_errno("khttp_urlpart");
-				goto done;
-			}
-			href_blame = khttp_urlpart(NULL, NULL, "gotweb", "path",
-			    gw_trans->repo_name, "action", "blame", "commit",
-			    gw_trans->commit_id, "file",
-			    got_tree_entry_get_name(te), "folder",
-			    gw_trans->repo_folder ? gw_trans->repo_folder : "",
-			    NULL);
-			if (href_blame == NULL) {
-				error = got_error_from_errno("khttp_urlpart");
-				goto done;
-			}
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tree_wrapper", KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tree_line", KATTR_CLASS, class,
-			    KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_blob, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_printf(gw_trans->gw_html_req, "%s%s",
-			    got_tree_entry_get_name(te), modestr);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-			    KATTR_ID, "tree_line_navs", KATTR_CLASS, class,
-			    KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_blob, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "blob");
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A,
-			    KATTR_HREF, href_blame, KATTR__MAX);
-			if (kerr != KCGI_OK)
-				goto done;
-			kerr = khtml_puts(gw_trans->gw_html_req, "blame");
-			if (kerr != KCGI_OK)
-				goto done;
-
-			kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-			if (kerr != KCGI_OK)
-				goto done;
-		}
-		free(id_str);
-		id_str = NULL;
-		free(href_blob);
-		href_blob = NULL;
-		free(build_folder);
-		build_folder = NULL;
-	}
-done:
-	if (tree)
-		got_object_tree_close(tree);
-	if (commit)
-		got_object_commit_close(commit);
-	free(id_str);
-	free(href_blob);
-	free(href_blame);
-	free(in_repo_path);
-	free(tree_id);
-	free(build_folder);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_output_repo_heads(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	struct got_reflist_head refs;
-	struct got_reflist_entry *re;
-	char *age = NULL, *href_summary = NULL, *href_briefs = NULL;
-	char *href_commits = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	TAILQ_INIT(&refs);
-
-	error = got_ref_list(&refs, gw_trans->repo, "refs/heads",
-	    got_ref_cmp_by_name, NULL);
-	if (error)
-		goto done;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "summary_heads_title_wrapper", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "summary_heads_title", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req, "Heads");
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-	    KATTR_ID, "summary_heads_content", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	TAILQ_FOREACH(re, &refs, entry) {
-		const char *refname;
-
-		if (got_ref_is_symbolic(re->ref))
-			continue;
-
-		refname = got_ref_get_name(re->ref);
-		if (strncmp(refname, "refs/heads/", 11) != 0)
-			continue;
-
-		error = gw_get_repo_age(&age, gw_trans, gw_trans->gw_dir->path,
-		    refname, TM_DIFF);
-		if (error)
-			goto done;
-
-		if (strncmp(refname, "refs/heads/", 11) == 0)
-			refname += 11;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "heads_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "heads_age", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, age ? age : "");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "heads_space", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_entity(gw_trans->gw_html_req, KENTITY_nbsp);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV,
-		    KATTR_ID, "head", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_summary = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "summary", "headref",
-		    refname, NULL);
-		if (href_summary == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_summary, KATTR__MAX);
-		kerr = khtml_puts(gw_trans->gw_html_req, refname);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "navs_wrapper", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "navs", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_summary, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "summary");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_briefs = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "briefs", "headref",
-		    refname, NULL);
-		if (href_briefs == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_briefs, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "commit briefs");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_puts(gw_trans->gw_html_req, " | ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_commits = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "commits", "headref",
-		    refname, NULL);
-		if (href_commits == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_commits, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, "commits");
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 3);
-		if (kerr != KCGI_OK)
-			goto done;
-
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-		    "dotted_line", KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 2);
-		if (kerr != KCGI_OK)
-			goto done;
-		free(href_summary);
-		href_summary = NULL;
-		free(href_briefs);
-		href_briefs = NULL;
-		free(href_commits);
-		href_commits = NULL;
-	}
-done:
-	got_ref_list_free(&refs);
-	free(href_summary);
-	free(href_briefs);
-	free(href_commits);
-	return error;
-}
-
-static const struct got_error *
-gw_output_site_link(struct gw_trans *gw_trans)
-{
-	const struct got_error *error = NULL;
-	char *href_summary = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "site_link", KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF, GOTWEB,
-	    KATTR__MAX);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_puts(gw_trans->gw_html_req,
-	    gw_trans->gw_conf->got_site_link);
-	if (kerr != KCGI_OK)
-		goto done;
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-
-	if (gw_trans->repo_name != NULL) {
-		kerr = khtml_puts(gw_trans->gw_html_req, " / ");
-		if (kerr != KCGI_OK)
-			goto done;
-
-		href_summary = khttp_urlpart(NULL, NULL, "gotweb", "path",
-		    gw_trans->repo_name, "action", "summary", NULL);
-		if (href_summary == NULL) {
-			error = got_error_from_errno("khttp_urlpart");
-			goto done;
-		}
-		kerr = khtml_attr(gw_trans->gw_html_req, KELEM_A, KATTR_HREF,
-		    href_summary, KATTR__MAX);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_puts(gw_trans->gw_html_req, gw_trans->repo_name);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-		if (kerr != KCGI_OK)
-			goto done;
-		kerr = khtml_printf(gw_trans->gw_html_req, " / %s",
-		    gw_get_action_name(gw_trans));
-		if (kerr != KCGI_OK)
-			goto done;
-	}
-
-	kerr = khtml_closeelem(gw_trans->gw_html_req, 1);
-	if (kerr != KCGI_OK)
-		goto done;
-done:
-	free(href_summary);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-static const struct got_error *
-gw_colordiff_line(struct gw_trans *gw_trans, char *buf)
-{
-	const struct got_error *error = NULL;
-	const char *color = NULL;
-	enum kcgi_err kerr = KCGI_OK;
-
-	if (strncmp(buf, "-", 1) == 0)
-		color = "diff_minus";
-	else if (strncmp(buf, "+", 1) == 0)
-		color = "diff_plus";
-	else if (strncmp(buf, "@@", 2) == 0)
-		color = "diff_chunk_header";
-	else if (strncmp(buf, "@@", 2) == 0)
-		color = "diff_chunk_header";
-	else if (strncmp(buf, "commit +", 8) == 0)
-		color = "diff_meta";
-	else if (strncmp(buf, "commit -", 8) == 0)
-		color = "diff_meta";
-	else if (strncmp(buf, "blob +", 6) == 0)
-		color = "diff_meta";
-	else if (strncmp(buf, "blob -", 6) == 0)
-		color = "diff_meta";
-	else if (strncmp(buf, "file +", 6) == 0)
-		color = "diff_meta";
-	else if (strncmp(buf, "file -", 6) == 0)
-		color = "diff_meta";
-	else if (strncmp(buf, "from:", 5) == 0)
-		color = "diff_author";
-	else if (strncmp(buf, "via:", 4) == 0)
-		color = "diff_author";
-	else if (strncmp(buf, "date:", 5) == 0)
-		color = "diff_date";
-	kerr = khtml_attr(gw_trans->gw_html_req, KELEM_DIV, KATTR_ID,
-	    "diff_line", KATTR_CLASS, color ? color : "", KATTR__MAX);
-	if (error == NULL && kerr != KCGI_OK)
-		error = gw_kcgi_error(kerr);
-	return error;
-}
-
-int
-main(int argc, char *argv[])
-{
-	const struct got_error *error = NULL, *error2 = NULL;
-	struct gw_trans *gw_trans;
-	struct gw_dir *dir = NULL, *tdir;
-	const char *page = "index";
-	enum kcgi_err kerr = KCGI_OK;
-
-	if ((gw_trans = malloc(sizeof(struct gw_trans))) == NULL)
-		errx(1, "malloc");
-
-	if ((gw_trans->gw_req = malloc(sizeof(struct kreq))) == NULL)
-		errx(1, "malloc");
-
-	if ((gw_trans->gw_html_req = malloc(sizeof(struct khtmlreq))) == NULL)
-		errx(1, "malloc");
-
-	if ((gw_trans->gw_tmpl = malloc(sizeof(struct ktemplate))) == NULL)
-		errx(1, "malloc");
-
-	kerr = khttp_parse(gw_trans->gw_req, gw_keys, KEY__ZMAX, &page, 1, 0);
-	if (kerr != KCGI_OK) {
-		error = gw_kcgi_error(kerr);
-		goto done;
-	}
-
-	TAILQ_INIT(&gw_trans->gw_dirs);
-	TAILQ_INIT(&gw_trans->gw_headers);
-
-	gw_trans->action = -1;
-	gw_trans->page = 0;
-	gw_trans->repos_total = 0;
-	gw_trans->repo_path = NULL;
-	gw_trans->commit_id = NULL;
-	gw_trans->next_id = NULL;
-	gw_trans->prev_id = NULL;
-	gw_trans->headref = GOT_REF_HEAD;
-	gw_trans->mime = KMIME_TEXT_HTML;
-	gw_trans->gw_tmpl->key = gw_templs;
-	gw_trans->gw_tmpl->keysz = TEMPL__MAX;
-	gw_trans->gw_tmpl->arg = gw_trans;
-	gw_trans->gw_tmpl->cb = gw_template;
-
-	error = got_repo_pack_fds_open(&gw_trans->pack_fds);
-	if (error != NULL)
-		goto done;
-
-	error = parse_gotweb_config(&gw_trans->gw_conf, GOTWEB_CONF);
-	if (error)
-		goto done;
-
-	error = gw_parse_querystring(gw_trans);
-	if (error)
-		goto done;
-
-	if (gw_trans->repo) {
-		const struct got_error *close_err;
-		close_err = got_repo_close(gw_trans->repo);
-		if (error == NULL)
-			error = close_err;
-	}
-	if (gw_trans->action == GW_BLOB)
-		error = gw_blob(gw_trans);
-	else
-		error = gw_display_index(gw_trans);
-done:
-	if (error) {
-		gw_trans->error = error;
-		gw_trans->action = GW_ERR;
-		error2 = gw_display_open(gw_trans, KHTTP_200, gw_trans->mime);
-		if (error2)
-			goto cleanup; /* we can't display an error page */
-		kerr = khtml_open(gw_trans->gw_html_req, gw_trans->gw_req, 0);
-		if (kerr != KCGI_OK)
-			goto cleanup; /* we can't display an error page */
-		kerr = khttp_template(gw_trans->gw_req, gw_trans->gw_tmpl,
-			gw_query_funcs[gw_trans->action].template);
-		if (kerr != KCGI_OK) {
-			khtml_close(gw_trans->gw_html_req);
-			goto cleanup; /* we can't display an error page */
-		}
-	}
-
-cleanup:
-	if (gw_trans->pack_fds) {
-		const struct got_error *pack_err =
-		    got_repo_pack_fds_close(gw_trans->pack_fds);
-		if (error == NULL)
-			error = pack_err;
-		gw_trans->pack_fds = NULL;
-	}
-	free(gw_trans->gw_conf->got_repos_path);
-	free(gw_trans->gw_conf->got_www_path);
-	free(gw_trans->gw_conf->got_site_name);
-	free(gw_trans->gw_conf->got_site_owner);
-	free(gw_trans->gw_conf->got_site_link);
-	free(gw_trans->gw_conf->got_logo);
-	free(gw_trans->gw_conf->got_logo_url);
-	free(gw_trans->gw_conf);
-	free(gw_trans->commit_id);
-	free(gw_trans->next_id);
-	free(gw_trans->prev_id);
-	free(gw_trans->repo_path);
-	TAILQ_FOREACH_SAFE(dir, &gw_trans->gw_dirs, entry, tdir) {
-		free(dir->name);
-		free(dir->description);
-		free(dir->age);
-		free(dir->url);
-		free(dir->path);
-		free(dir);
-	}
-
-	khttp_free(gw_trans->gw_req);
-	return 0;
-}
blob - b9dd2b0786d5a06a4c43e97bf29aeab25650d68d (mode 644)
blob + /dev/null
--- gotweb/gotweb.conf.5
+++ /dev/null
@@ -1,135 +0,0 @@
-.\"
-.\" Copyright (c) 2020 Tracey Emery <tracey@traceyemery.net>
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.Dd $Mdocdate$
-.Dt GOTWEB.CONF 5
-.Os
-.Sh NAME
-.Nm gotweb.conf
-.Nd gotweb configuration file
-.Sh DESCRIPTION
-.Nm
-is the run-time configuration file for
-.Xr gotweb 8 .
-.Pp
-The file format is line-based, with one configuration directive per line.
-Any lines beginning with a
-.Sq #
-are treated as comments and ignored.
-.Pp
-Paths mentioned in
-.Nm
-must be relative to
-.Pa /var/www ,
-the
-.Xr chroot 2
-environment of
-.Xr httpd 8 .
-.Sh GLOBAL CONFIGURATION
-The available configuration directives are as follows:
-.Bl -tag -width Ds
-.It Ic got_max_commits_display Ar number
-Set the maximum amount of commits displayed per page.
-.It Ic got_logo Ar path
-Set the path to an image file containing a logo to be displayed.
-.It Ic got_logo_url Ar url
-Set a hyperlink for the logo.
-.It Ic got_max_repos Ar number
-Set the maximum amount of repositories
-.Xr gotweb 8
-will work with.
-.It Ic got_max_repos_display Ar number
-Set the maximum amount of repositories displayed on the index screen.
-.It Ic got_show_repo_age Ar on | off
-Toggle display of last repository modification date.
-.It Ic got_show_repo_cloneurl Ar on | off
-Toggle display of clone URLs for a repository.
-This requires the creation of a
-.Pa cloneurl
-file inside the repository which contains one URL per line.
-.It Ic got_show_repo_description Ar on | off
-Toggle display of the repository description.
-The
-.Pa description
-file in the repository should be updated with an appropriate description.
-.It Ic got_repos_path Ar path
-Set the path to the directory which contains Git repositories that
-.Xr gotweb 8
-should publish.
-.It Ic got_show_repo_owner Ar on | off
-Set whether to display the repository owner.
-Displaying the owner requires owner information to be added to the
-.Pa config
-file in the repository.
-.Xr gotweb 8
-will parse owner information from either a [gotweb] or a [gitweb] section.
-For example:
-.Bd -literal -offset indent
-[gotweb]
-owner = "Your Name"
-.Ed
-.It Ic got_site_link Ar string
-Set the displayed site link name for the index page.
-.It Ic got_site_name Ar string
-Set the displayed site name title.
-.It Ic got_site_owner Ar string
-Set the displayed site owner.
-.It Ic got_show_site_owner Ar on | off
-Toggle display of the site owner.
-.It Ic got_www_path Ar string
-Set the public gotweb httpd path.
-.El
-.Sh FILES
-.Bl -tag -width Ds -compact
-.It Pa /var/www/etc/gotweb.conf
-Location of the
-.Nm
-configuration file.
-.El
-.Sh EXAMPLES
-These are the currently configurable items for
-.Xr gotweb 8
-with their default values.
-.Bd -literal -offset indent
-
-#
-# gotweb options
-# all paths relative to /var/www (httpd chroot jail)
-#
-
-got_repos_path			"/got/public"
-got_www_path			"/gotweb"
-
-#got_max_repos			100
-#got_max_repos_display		25
-got_max_commits_display		50
-
-got_site_name			"my public repos"
-got_site_owner			"Got Owner"
-got_site_link			"repos"
-
-got_logo			"got.png"
-got_logo_url			"https://gameoftrees.org"
-
-# on by default
-#got_show_site_owner		off
-#got_show_repo_owner		off
-#got_show_repo_age		false
-#got_show_repo_description	no
-#got_show_repo_cloneurl		off
-.Ed
-.Sh SEE ALSO
-.Xr got 1 ,
-.Xr gotweb 8
blob - aa311d40d3fa8a2632f5b8c4acd5c1e933cc8c49 (mode 644)
blob + /dev/null
--- gotweb/gotweb.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net>
- * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef GOTWEB_H
-#define GOTWEB_H
-
-#include <stdbool.h>
-
-#define	GOTWEB_CONF	 "/etc/gotweb.conf"
-#define GOTWEB_TMPL_DIR	 "/cgi-bin/gw_tmpl"
-#define GOTWEB		 "/cgi-bin/gotweb/gotweb"
-
-#define GOTWEB_GOT_DIR	 ".got"
-#define GOTWEB_GIT_DIR	 ".git"
-
-#define D_GOTWWW	 "/gotweb"
-#define D_GOTPATH	 "/got/public"
-#define D_SITENAME	 "Gotweb"
-#define D_SITEOWNER	 "Got Owner"
-#define D_SITELINK	 "Repos"
-#define D_GOTLOGO	 "got.png"
-#define D_GOTURL	 "https://gameoftrees.org"
-
-#define	D_SHOWROWNER	 true
-#define	D_SHOWSOWNER	 true
-#define D_SHOWAGE	 true
-#define D_SHOWDESC	 true
-#define D_SHOWURL	 true
-#define	D_MAXREPO	 0
-#define D_MAXREPODISP	 25
-#define D_MAXSLCOMMDISP	 10
-#define D_MAXCOMMITDISP	 25
-
-#define BUFFER_SIZE	 2048
-
-struct gotweb_config {
-	char		*got_repos_path;
-	char		*got_www_path;
-	char		*got_site_name;
-	char		*got_site_owner;
-	char		*got_site_link;
-	char		*got_logo;
-	char		*got_logo_url;
-
-	size_t		 got_max_repos;
-	size_t		 got_max_repos_display;
-	size_t		 got_max_commits_display;
-
-	bool		 got_show_site_owner;
-	bool		 got_show_repo_owner;
-	bool		 got_show_repo_age;
-	bool		 got_show_repo_description;
-	bool		 got_show_repo_cloneurl;
-};
-
-/*
- * Parse gotweb config file, if it exists
- * Load gotweb_config struct
- */
-const struct got_error*	 parse_gotweb_config(struct gotweb_config **,
-    const char *);
-
-#endif /* GOTWEB_H */
blob - 5fd34708bd3654bc05060446ff5d55557747cfd3 (mode 644)
blob + /dev/null
--- gotweb/libexec/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-SUBDIR = got-read-blob got-read-commit got-read-object got-read-tree \
-	got-read-tag got-read-pack got-read-gitconfig got-read-gotconfig
-
-.include <bsd.subdir.mk>
blob - 85bee26728643214f5d4570f003572ac1fc36d05 (mode 644)
blob + /dev/null
--- gotweb/libexec/Makefile.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-.include "../Makefile.inc"
-
-realinstall:
-	if [ ! -d ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}/. ]; then \
-		${INSTALL} -d -o root -g daemon -m 755 \
-		    ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}; \
-	fi
-	${INSTALL} ${INSTALL_COPY} -o root -g daemon -m 755 ${PROG} \
-	    ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}/${PROG}
-
-NOMAN = Yes
blob - 58d428b99c43b2fba80028b6233bcd4ff6c7e4a4 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-blob/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-blob
-SRCS=		got-read-blob.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-blob
-
-.include <bsd.prog.mk>
blob - 669332cc8be5487a26cc868b873f782c7e351623 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-commit/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-commit
-SRCS=		got-read-commit.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-commit
-
-.include <bsd.prog.mk>
blob - d81d4666fc3206a3008ddfc673992c5ec3265bd9 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-gitconfig/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-gitconfig
-SRCS=		got-read-gitconfig.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c gitconfig.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-gitconfig
-
-.include <bsd.prog.mk>
blob - abc9574b7efb93c971c76b3576970c8c19ba0e14 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-gotconfig/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-gotconfig
-SRCS=		got-read-gotconfig.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c parse.y pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib \
-	-I${.CURDIR}/../../../libexec/got-read-gotconfig
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-gotconfig
-
-.include <bsd.prog.mk>
blob - 1c3afaf56bad757cf3c8b9574bc12521adbda7bb (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-object/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-object
-SRCS=		got-read-object.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-object
-
-.include <bsd.prog.mk>
blob - 9c1bf08b6d1c6cea526cdb38361ef89dfce5bc32 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-pack/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-pack
-SRCS=		got-read-pack.c delta.c error.c inflate.c object_cache.c \
-		object_idset.c object_parse.c opentemp.c pack.c path.c \
-		privsep.c sha1.c delta_cache.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-pack
-
-.include <bsd.prog.mk>
blob - 450ee15c54e4904304143c4129f1adf9fd085073 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-tag/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-tag
-SRCS=		got-read-tag.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-tag
-
-.include <bsd.prog.mk>
blob - 20c0a23b3bf5a858afe4cd8a8e2d57c5194dd074 (mode 644)
blob + /dev/null
--- gotweb/libexec/got-read-tree/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG=		got-read-tree
-SRCS=		got-read-tree.c error.c inflate.c object_parse.c \
-		path.c privsep.c sha1.c pollfd.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH:	${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-tree
-
-.include <bsd.prog.mk>
blob - e1d44725734b9a6babef6ed3ea9430e0c42150dd (mode 644)
blob + /dev/null
--- gotweb/parse.y
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * Copyright (c) 2019, 2020 Tracey Emery <tracey@openbsd.org>
- * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
- * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
- * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
- * Copyright (c) 2001 Markus Friedl.  All rights reserved.
- * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
- * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-%{
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/queue.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "got_error.h"
-#include "gotweb.h"
-
-TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
-static struct file {
-	TAILQ_ENTRY(file)	 entry;
-	FILE			*stream;
-	char			*name;
-	size_t	 		 ungetpos;
-	size_t			 ungetsize;
-	u_char			*ungetbuf;
-	int			 eof_reached;
-	int			 lineno;
-} *file, *topfile;
-static const struct got_error*	pushfile(struct file**, const char *);
-int		 popfile(void);
-int		 yyparse(void);
-int		 yylex(void);
-int		 yyerror(const char *, ...)
-    __attribute__((__format__ (printf, 1, 2)))
-    __attribute__((__nonnull__ (1)));
-int		 kw_cmp(const void *, const void *);
-int		 lookup(char *);
-int		 igetc(void);
-int		 lgetc(int);
-void		 lungetc(int);
-int		 findeol(void);
-
-TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
-struct sym {
-	TAILQ_ENTRY(sym)	 entry;
-	int			 used;
-	int			 persist;
-	char			*nam;
-	char			*val;
-};
-
-int	 symset(const char *, const char *, int);
-int	 cmdline_symset(char *);
-char	*symget(const char *);
-
-const struct got_error* gerror = NULL;
-struct gotweb_config		*gw_conf;
-
-typedef struct {
-	union {
-		int64_t		 number;
-		char		*string;
-	} v;
-	int lineno;
-} YYSTYPE;
-
-%}
-
-%token	GOT_WWW_PATH GOT_MAX_REPOS GOT_SITE_NAME GOT_SITE_OWNER GOT_SITE_LINK
-%token	GOT_LOGO GOT_LOGO_URL GOT_SHOW_REPO_OWNER GOT_SHOW_REPO_AGE
-%token	GOT_SHOW_REPO_DESCRIPTION GOT_MAX_REPOS_DISPLAY GOT_REPOS_PATH
-%token	GOT_MAX_COMMITS_DISPLAY ERROR GOT_SHOW_SITE_OWNER
-%token	GOT_SHOW_REPO_CLONEURL
-%token	<v.string>	STRING
-%token	<v.number>	NUMBER
-%type	<v.number>	boolean
-%%
-
-grammar		: /* empty */
-		| grammar '\n'
-		| grammar main '\n'
-		;
-
-boolean		: STRING {
-			if (strcasecmp($1, "true") == 0 ||
-			    strcasecmp($1, "on") == 0 ||
-			    strcasecmp($1, "yes") == 0)
-				$$ = 1;
-			else if (strcasecmp($1, "false") == 0 ||
-			    strcasecmp($1, "off") == 0 ||
-			    strcasecmp($1, "no") == 0)
-				$$ = 0;
-			else {
-				yyerror("invalid boolean value '%s'", $1);
-				free($1);
-				YYERROR;
-			}
-			free($1);
-		}
-		;
-main		: GOT_REPOS_PATH STRING {
-			gw_conf->got_repos_path = $2;
-		}
-		| GOT_WWW_PATH STRING {
-			gw_conf->got_www_path = $2;
-		}
-		| GOT_MAX_REPOS NUMBER {
-			if ($2 > 0)
-				gw_conf->got_max_repos = $2;
-		}
-		| GOT_SITE_NAME STRING {
-			gw_conf->got_site_name = $2;
-		}
-		| GOT_SITE_OWNER STRING {
-			gw_conf->got_site_owner = $2;
-		}
-		| GOT_SITE_LINK STRING {
-			gw_conf->got_site_link = $2;
-		}
-		| GOT_LOGO STRING {
-			gw_conf->got_logo = $2;
-		}
-		| GOT_LOGO_URL STRING {
-			gw_conf->got_logo_url = $2;
-		}
-		| GOT_SHOW_SITE_OWNER boolean {
-			gw_conf->got_show_site_owner = $2;
-		}
-		| GOT_SHOW_REPO_OWNER boolean {
-			gw_conf->got_show_repo_owner = $2;
-		}
-		| GOT_SHOW_REPO_AGE boolean {
-			gw_conf->got_show_repo_age = $2;
-		}
-		| GOT_SHOW_REPO_DESCRIPTION boolean {
-			gw_conf->got_show_repo_description = $2;
-		}
-		| GOT_SHOW_REPO_CLONEURL boolean {
-			gw_conf->got_show_repo_cloneurl = $2;
-		}
-		| GOT_MAX_REPOS_DISPLAY NUMBER {
-			if ($2 > 0)
-				gw_conf->got_max_repos_display = $2;
-		}
-		| GOT_MAX_COMMITS_DISPLAY NUMBER {
-			if ($2 > 0)
-				gw_conf->got_max_commits_display = $2;
-		}
-		;
-%%
-
-struct keywords {
-	const char	*k_name;
-	int		 k_val;
-};
-
-int
-yyerror(const char *fmt, ...)
-{
-	va_list		 ap;
-	char		*msg;
-	char		*err = NULL;
-
-	va_start(ap, fmt);
-	if (vasprintf(&msg, fmt, ap) == -1) {
-		gerror =  got_error_from_errno("vasprintf");
-		return 0;
-	}
-	va_end(ap);
-	if (asprintf(&err, "%s:%d: %s", file->name, yylval.lineno, msg) == -1) {
-		gerror = got_error_from_errno("asprintf");
-		return(0);
-	}
-	gerror = got_error_msg(GOT_ERR_PARSE_CONFIG, err);
-	free(msg);
-	return(0);
-}
-
-int
-kw_cmp(const void *k, const void *e)
-{
-	return (strcmp(k, ((const struct keywords *)e)->k_name));
-}
-
-int
-lookup(char *s)
-{
-	/* This has to be sorted always. */
-	static const struct keywords keywords[] = {
-		{ "got_logo",			GOT_LOGO },
-		{ "got_logo_url",		GOT_LOGO_URL },
-		{ "got_max_commits_display",	GOT_MAX_COMMITS_DISPLAY },
-		{ "got_max_repos",		GOT_MAX_REPOS },
-		{ "got_max_repos_display",	GOT_MAX_REPOS_DISPLAY },
-		{ "got_repos_path",		GOT_REPOS_PATH },
-		{ "got_show_repo_age",		GOT_SHOW_REPO_AGE },
-		{ "got_show_repo_cloneurl",	GOT_SHOW_REPO_CLONEURL },
-		{ "got_show_repo_description",	GOT_SHOW_REPO_DESCRIPTION },
-		{ "got_show_repo_owner",	GOT_SHOW_REPO_OWNER },
-		{ "got_show_site_owner",	GOT_SHOW_SITE_OWNER },
-		{ "got_site_link",		GOT_SITE_LINK },
-		{ "got_site_name",		GOT_SITE_NAME },
-		{ "got_site_owner",		GOT_SITE_OWNER },
-		{ "got_www_path",		GOT_WWW_PATH },
-	};
-	const struct keywords	*p;
-
-	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
-	    sizeof(keywords[0]), kw_cmp);
-
-	if (p)
-		return (p->k_val);
-	else
-		return (STRING);
-}
-
-#define START_EXPAND	1
-#define DONE_EXPAND	2
-
-static int	expanding;
-
-int
-igetc(void)
-{
-	int	c;
-
-	while (1) {
-		if (file->ungetpos > 0)
-			c = file->ungetbuf[--file->ungetpos];
-		else
-			c = getc(file->stream);
-
-		if (c == START_EXPAND)
-			expanding = 1;
-		else if (c == DONE_EXPAND)
-			expanding = 0;
-		else
-			break;
-	}
-	return (c);
-}
-
-int
-lgetc(int quotec)
-{
-	int		c, next;
-
-	if (quotec) {
-		if ((c = igetc()) == EOF) {
-			yyerror("reached end of file while parsing "
-			    "quoted string");
-			if (file == topfile || popfile() == EOF)
-				return (EOF);
-			return (quotec);
-		}
-		return (c);
-	}
-
-	while ((c = igetc()) == '\\') {
-		next = igetc();
-		if (next != '\n') {
-			c = next;
-			break;
-		}
-		yylval.lineno = file->lineno;
-		file->lineno++;
-	}
-
-	if (c == EOF) {
-		/*
-		 * Fake EOL when hit EOF for the first time. This gets line
-		 * count right if last line in included file is syntactically
-		 * invalid and has no newline.
-		 */
-		if (file->eof_reached == 0) {
-			file->eof_reached = 1;
-			return ('\n');
-		}
-		while (c == EOF) {
-			if (file == topfile || popfile() == EOF)
-				return (EOF);
-			c = igetc();
-		}
-	}
-	return (c);
-}
-
-void
-lungetc(int c)
-{
-	if (c == EOF)
-		return;
-
-	if (file->ungetpos >= file->ungetsize) {
-		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
-		if (p == NULL)
-			err(1, "%s", __func__);
-		file->ungetbuf = p;
-		file->ungetsize *= 2;
-	}
-	file->ungetbuf[file->ungetpos++] = c;
-}
-
-int
-findeol(void)
-{
-	int	c;
-
-	/* Skip to either EOF or the first real EOL. */
-	while (1) {
-		c = lgetc(0);
-		if (c == '\n') {
-			file->lineno++;
-			break;
-		}
-		if (c == EOF)
-			break;
-	}
-	return (ERROR);
-}
-
-int
-yylex(void)
-{
-	char	 buf[8096];
-	char	*p, *val;
-	int	 quotec, next, c;
-	int	 token;
-
-top:
-	p = buf;
-	while ((c = lgetc(0)) == ' ' || c == '\t')
-		; /* nothing */
-
-	yylval.lineno = file->lineno;
-	if (c == '#')
-		while ((c = lgetc(0)) != '\n' && c != EOF)
-			; /* nothing */
-	if (c == '$' && !expanding) {
-		while (1) {
-			if ((c = lgetc(0)) == EOF)
-				return (0);
-
-			if (p + 1 >= buf + sizeof(buf) - 1) {
-				yyerror("string too long");
-				return (findeol());
-			}
-			if (isalnum(c) || c == '_') {
-				*p++ = c;
-				continue;
-			}
-			*p = '\0';
-			lungetc(c);
-			break;
-		}
-		val = symget(buf);
-		if (val == NULL) {
-			yyerror("macro '%s' not defined", buf);
-			return (findeol());
-		}
-		p = val + strlen(val) - 1;
-		lungetc(DONE_EXPAND);
-		while (p >= val) {
-			lungetc((unsigned char)*p);
-			p--;
-		}
-		lungetc(START_EXPAND);
-		goto top;
-	}
-
-	switch (c) {
-	case '\'':
-	case '"':
-		quotec = c;
-		while (1) {
-			if ((c = lgetc(quotec)) == EOF)
-				return (0);
-			if (c == '\n') {
-				file->lineno++;
-				continue;
-			} else if (c == '\\') {
-				if ((next = lgetc(quotec)) == EOF)
-					return (0);
-				if (next == quotec || c == ' ' || c == '\t')
-					c = next;
-				else if (next == '\n') {
-					file->lineno++;
-					continue;
-				} else
-					lungetc(next);
-			} else if (c == quotec) {
-				*p = '\0';
-				break;
-			} else if (c == '\0') {
-				yyerror("syntax error");
-				return (findeol());
-			}
-			if (p + 1 >= buf + sizeof(buf) - 1) {
-				yyerror("string too long");
-				return (findeol());
-			}
-			*p++ = c;
-		}
-		yylval.v.string = strdup(buf);
-		if (yylval.v.string == NULL)
-			err(1, "%s", __func__);
-		return (STRING);
-	}
-
-#define allowed_to_end_number(x) \
-	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
-
-	if (c == '-' || isdigit(c)) {
-		do {
-			*p++ = c;
-			if ((size_t)(p-buf) >= sizeof(buf)) {
-				yyerror("string too long");
-				return (findeol());
-			}
-		} while ((c = lgetc(0)) != EOF && isdigit(c));
-		lungetc(c);
-		if (p == buf + 1 && buf[0] == '-')
-			goto nodigits;
-		if (c == EOF || allowed_to_end_number(c)) {
-			const char *errstr = NULL;
-
-			*p = '\0';
-			yylval.v.number = strtonum(buf, LLONG_MIN,
-			    LLONG_MAX, &errstr);
-			if (errstr) {
-				yyerror("\"%s\" invalid number: %s",
-				    buf, errstr);
-				return (findeol());
-			}
-			return (NUMBER);
-		} else {
-nodigits:
-			while (p > buf + 1)
-				lungetc((unsigned char)*--p);
-			c = (unsigned char)*--p;
-			if (c == '-')
-				return (c);
-		}
-	}
-
-#define allowed_in_string(x) \
-	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
-	x != '{' && x != '}' && \
-	x != '!' && x != '=' && x != '#' && \
-	x != ','))
-
-	if (isalnum(c) || c == ':' || c == '_') {
-		do {
-			*p++ = c;
-			if ((size_t)(p-buf) >= sizeof(buf)) {
-				yyerror("string too long");
-				return (findeol());
-			}
-		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
-		lungetc(c);
-		*p = '\0';
-		if ((token = lookup(buf)) == STRING)
-			if ((yylval.v.string = strdup(buf)) == NULL)
-				err(1, "%s", __func__);
-		return (token);
-	}
-	if (c == '\n') {
-		yylval.lineno = file->lineno;
-		file->lineno++;
-	}
-	if (c == EOF)
-		return (0);
-	return (c);
-}
-
-static const struct got_error*
-pushfile(struct file **nfile, const char *name)
-{
-	const struct got_error* error = NULL;
-
-	if (((*nfile) = calloc(1, sizeof(struct file))) == NULL)
-		return got_error_from_errno2(__func__, "calloc");
-	if (((*nfile)->name = strdup(name)) == NULL) {
-		free(*nfile);
-		return got_error_from_errno2(__func__, "strdup");
-	}
-	if (((*nfile)->stream = fopen((*nfile)->name, "re")) == NULL) {
-		char *msg = NULL;
-		if (asprintf(&msg, "%s", (*nfile)->name) == -1)
-			return got_error_from_errno("asprintf");
-		error = got_error_msg(GOT_ERR_NO_CONFIG_FILE, msg);
-		free((*nfile)->name);
-		free((*nfile));
-		free(msg);
-		return error;
-	}
-	(*nfile)->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
-	(*nfile)->ungetsize = 16;
-	(*nfile)->ungetbuf = malloc((*nfile)->ungetsize);
-	if ((*nfile)->ungetbuf == NULL) {
-		fclose((*nfile)->stream);
-		free((*nfile)->name);
-		free((*nfile));
-		return got_error_from_errno2(__func__, "malloc");
-	}
-	TAILQ_INSERT_TAIL(&files, (*nfile), entry);
-	return error;
-}
-
-int
-popfile(void)
-{
-	struct file	*prev = NULL;
-
-	TAILQ_REMOVE(&files, file, entry);
-	fclose(file->stream);
-	free(file->name);
-	free(file->ungetbuf);
-	free(file);
-	file = prev;
-	return (file ? 0 : EOF);
-}
-
-const struct got_error*
-parse_gotweb_config(struct gotweb_config **gconf, const char *filename)
-{
-	gw_conf = malloc(sizeof(struct gotweb_config));
-	if (gw_conf == NULL) {
-		gerror = got_error_from_errno("malloc");
-		goto done;
-	}
-	gw_conf->got_repos_path = strdup(D_GOTPATH);
-	if (gw_conf->got_repos_path == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_www_path = strdup(D_GOTWWW);
-	if (gw_conf->got_www_path == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_site_name = strdup(D_SITENAME);
-	if (gw_conf->got_site_name == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_site_owner = strdup(D_SITEOWNER);
-	if (gw_conf->got_site_owner == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_site_link = strdup(D_SITELINK);
-	if (gw_conf->got_site_link == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_logo = strdup(D_GOTLOGO);
-	if (gw_conf->got_logo == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_logo_url = strdup(D_GOTURL);
-	if (gw_conf->got_logo_url == NULL) {
-		gerror = got_error_from_errno("strdup");
-		goto done;
-	}
-	gw_conf->got_show_site_owner = D_SHOWSOWNER;
-	gw_conf->got_show_repo_owner = D_SHOWROWNER;
-	gw_conf->got_show_repo_age = D_SHOWAGE;
-	gw_conf->got_show_repo_description = D_SHOWDESC;
-	gw_conf->got_show_repo_cloneurl = D_SHOWURL;
-	gw_conf->got_max_repos = D_MAXREPO;
-	gw_conf->got_max_repos_display = D_MAXREPODISP;
-	gw_conf->got_max_commits_display = D_MAXCOMMITDISP;
-
-	/*
-	 * We don't require that the gotweb config file exists
-	 * So reset gerror if it doesn't exist and goto done.
-	 */
-	gerror = pushfile(&file, filename);
-	if (gerror && gerror->code == GOT_ERR_NO_CONFIG_FILE) {
-		gerror = NULL;
-		goto done;
-	} else if (gerror)
-		return gerror;
-	topfile = file;
-
-	yyparse();
-	popfile();
-done:
-	*gconf = gw_conf;
-	return gerror;
-}
-
-int
-symset(const char *nam, const char *val, int persist)
-{
-	struct sym	*sym;
-
-	TAILQ_FOREACH(sym, &symhead, entry) {
-		if (strcmp(nam, sym->nam) == 0)
-			break;
-	}
-
-	if (sym != NULL) {
-		if (sym->persist == 1)
-			return (0);
-		else {
-			free(sym->nam);
-			free(sym->val);
-			TAILQ_REMOVE(&symhead, sym, entry);
-			free(sym);
-		}
-	}
-	if ((sym = calloc(1, sizeof(*sym))) == NULL)
-		return (-1);
-
-	sym->nam = strdup(nam);
-	if (sym->nam == NULL) {
-		free(sym);
-		return (-1);
-	}
-	sym->val = strdup(val);
-	if (sym->val == NULL) {
-		free(sym->nam);
-		free(sym);
-		return (-1);
-	}
-	sym->used = 0;
-	sym->persist = persist;
-	TAILQ_INSERT_TAIL(&symhead, sym, entry);
-	return (0);
-}
-
-int
-cmdline_symset(char *s)
-{
-	char	*sym, *val;
-	int	ret;
-	size_t	len;
-
-	if ((val = strrchr(s, '=')) == NULL)
-		return (-1);
-
-	len = strlen(s) - strlen(val) + 1;
-	if ((sym = malloc(len)) == NULL)
-		errx(1, "cmdline_symset: malloc");
-
-	strlcpy(sym, s, len);
-
-	ret = symset(sym, val + 1, 1);
-	free(sym);
-
-	return (ret);
-}
-
-char *
-symget(const char *nam)
-{
-	struct sym	*sym;
-
-	TAILQ_FOREACH(sym, &symhead, entry) {
-		if (strcmp(nam, sym->nam) == 0) {
-			sym->used = 1;
-			return (sym->val);
-		}
-	}
-	return (NULL);
-}
blob - 3b4eac348bb9ce1af38f8f5b5a1aeb8f54b83e14
blob + 82afa2028dd0be74054dd2348115d8cc87611e14
--- util/got-build-regress.sh
+++ util/got-build-regress.sh
@@ -109,7 +109,7 @@ if [ "$build_status" != "0" ]; then
 	exit 0
 fi
 log_cmd build.log make install
-log_cmd build.log make -j $ncpu web
+log_cmd build.log make -j $ncpu webd
 build_status="$?"
 if [ "$build_status" != "0" ]; then
 	mail $fromaddr_arg -s "$prog build failure" $recipients < build.log
@@ -149,7 +149,7 @@ printf "\n\n\tTesting a release build\n\n" >> build.lo
 log_cmd build.log make clean
 log_cmd build.log make obj
 log_cmd build.log make -j $ncpu GOT_RELEASE=Yes
-log_cmd build.log make -j $ncpu GOT_RELEASE=Yes web
+log_cmd build.log make -j $ncpu GOT_RELEASE=Yes webd
 build_status="$?"
 if [ "$build_status" != "0" ]; then
 	mail $fromaddr_arg -s "$prog release mode build failure" $recipients < build.log