Import mdocml-1.13.1 vendor/MDOCML
authorFranco Fichtner <franco@lastsummer.de>
Mon, 27 Oct 2014 21:18:52 +0000 (22:18 +0100)
committerFranco Fichtner <franco@lastsummer.de>
Mon, 27 Oct 2014 21:18:52 +0000 (22:18 +0100)
120 files changed:
contrib/mdocml/INSTALL [new file with mode: 0644]
contrib/mdocml/LICENSE [new file with mode: 0644]
contrib/mdocml/Makefile
contrib/mdocml/Makefile.depend [new file with mode: 0644]
contrib/mdocml/NEWS
contrib/mdocml/TODO
contrib/mdocml/apropos.1
contrib/mdocml/apropos.c
contrib/mdocml/apropos_db.c [deleted file]
contrib/mdocml/apropos_db.h [deleted file]
contrib/mdocml/arch.c
contrib/mdocml/arch.in
contrib/mdocml/att.c
contrib/mdocml/catman.8 [deleted file]
contrib/mdocml/catman.c [deleted file]
contrib/mdocml/cgi.c
contrib/mdocml/cgi.h.example [new file with mode: 0644]
contrib/mdocml/chars.c
contrib/mdocml/chars.in
contrib/mdocml/compat_ohash.c [new file with mode: 0644]
contrib/mdocml/compat_ohash.h [new file with mode: 0644]
contrib/mdocml/compat_reallocarray.c [copied from contrib/mdocml/lib.c with 59% similarity]
contrib/mdocml/compat_sqlite3_errstr.c [new file with mode: 0644]
contrib/mdocml/compat_strcasestr.c [new file with mode: 0644]
contrib/mdocml/compat_strsep.c [new file with mode: 0644]
contrib/mdocml/config.h.post
contrib/mdocml/config.h.pre
contrib/mdocml/configure [new file with mode: 0755]
contrib/mdocml/demandoc.c
contrib/mdocml/eqn.c
contrib/mdocml/eqn_html.c
contrib/mdocml/eqn_term.c
contrib/mdocml/external.png [deleted file]
contrib/mdocml/gmdiff
contrib/mdocml/html.c
contrib/mdocml/html.h
contrib/mdocml/index.css [deleted file]
contrib/mdocml/index.sgml [deleted file]
contrib/mdocml/lib.c
contrib/mdocml/lib.in
contrib/mdocml/libman.h
contrib/mdocml/libmandoc.h
contrib/mdocml/libmdoc.h
contrib/mdocml/libroff.h
contrib/mdocml/main.c
contrib/mdocml/main.h
contrib/mdocml/makewhatis.8 [new file with mode: 0644]
contrib/mdocml/man.7
contrib/mdocml/man.c
contrib/mdocml/man.cgi.7 [deleted file]
contrib/mdocml/man.cgi.8 [new file with mode: 0644]
contrib/mdocml/man.h
contrib/mdocml/man_hash.c
contrib/mdocml/man_html.c
contrib/mdocml/man_macro.c
contrib/mdocml/man_term.c
contrib/mdocml/man_validate.c
contrib/mdocml/mandoc.1
contrib/mdocml/mandoc.3
contrib/mdocml/mandoc.c
contrib/mdocml/mandoc.db.5 [new file with mode: 0644]
contrib/mdocml/mandoc.h
contrib/mdocml/mandoc_aux.c [new file with mode: 0644]
contrib/mdocml/mandoc_aux.h [copied from contrib/mdocml/att.c with 56% similarity]
contrib/mdocml/mandoc_escape.3 [new file with mode: 0644]
contrib/mdocml/mandoc_html.3 [new file with mode: 0644]
contrib/mdocml/mandoc_malloc.3 [new file with mode: 0644]
contrib/mdocml/mandocdb.8 [deleted file]
contrib/mdocml/mandocdb.c
contrib/mdocml/mandocdb.h [deleted file]
contrib/mdocml/manpage.c [new file with mode: 0644]
contrib/mdocml/manpath.c
contrib/mdocml/mansearch.3 [new file with mode: 0644]
contrib/mdocml/mansearch.c [new file with mode: 0644]
contrib/mdocml/mansearch.h [new file with mode: 0644]
contrib/mdocml/mansearch_const.c [copied from contrib/mdocml/msec.c with 59% similarity]
contrib/mdocml/mchars_alloc.3 [new file with mode: 0644]
contrib/mdocml/mdoc.7
contrib/mdocml/mdoc.c
contrib/mdocml/mdoc.h
contrib/mdocml/mdoc_argv.c
contrib/mdocml/mdoc_hash.c
contrib/mdocml/mdoc_html.c
contrib/mdocml/mdoc_macro.c
contrib/mdocml/mdoc_man.c
contrib/mdocml/mdoc_term.c
contrib/mdocml/mdoc_validate.c
contrib/mdocml/msec.c
contrib/mdocml/out.c
contrib/mdocml/out.h
contrib/mdocml/read.c
contrib/mdocml/roff.7
contrib/mdocml/roff.c
contrib/mdocml/st.c
contrib/mdocml/st.in
contrib/mdocml/tbl.c
contrib/mdocml/tbl_data.c
contrib/mdocml/tbl_html.c
contrib/mdocml/tbl_layout.c
contrib/mdocml/tbl_opts.c
contrib/mdocml/tbl_term.c
contrib/mdocml/term.c
contrib/mdocml/term.h
contrib/mdocml/term_ascii.c
contrib/mdocml/term_ps.c
contrib/mdocml/test-betoh64.c [deleted file]
contrib/mdocml/test-fgetln.c
contrib/mdocml/test-getsubopt.c
contrib/mdocml/test-mmap.c
contrib/mdocml/test-ohash.c [new file with mode: 0644]
contrib/mdocml/test-reallocarray.c [new file with mode: 0644]
contrib/mdocml/test-sqlite3_errstr.c [new file with mode: 0644]
contrib/mdocml/test-strcasestr.c [new file with mode: 0644]
contrib/mdocml/test-strlcat.c
contrib/mdocml/test-strlcpy.c
contrib/mdocml/test-strptime.c
contrib/mdocml/test-strsep.c [new file with mode: 0644]
contrib/mdocml/tree.c
contrib/mdocml/vol.c
contrib/mdocml/whatis.1 [deleted file]

diff --git a/contrib/mdocml/INSTALL b/contrib/mdocml/INSTALL
new file mode 100644 (file)
index 0000000..da8eeab
--- /dev/null
@@ -0,0 +1,187 @@
+$Id: INSTALL,v 1.2 2014/08/10 17:22:26 schwarze Exp $
+
+About mdocml, the portable mandoc distribution
+----------------------------------------------
+The mandoc manpage compiler toolset is a suite of tools compiling
+mdoc(7), the roff(7) macro language of choice for BSD manual pages,
+and man(7), the predominant historical language for UNIX manuals.
+The toolset does not yet implement man(1); that is only scheduled
+for the next release, 1.13.2.  It can, however, already serve to
+translate source manpages to the output displayed by man(1).
+For general information, see <http://mdocml.bsd.lv/>.
+
+In this document, we describe the installation and deployment of
+mandoc(1), first as a simple, standalone formatter, and then as part of
+the man(1) system.
+
+In case you have questions or want to provide feedback, read
+<http://mdocml.bsd.lv/contact.html>.  Consider subscribing to the
+discuss@ mailing list mentioned on that page.  If you intend to
+help with the development of mandoc, consider subscribing to the
+tech@ mailing list, too.
+
+Enjoy using the mandoc toolset!
+
+Ingo Schwarze, Karlsruhe, August 2014
+
+
+Installation
+------------
+Before manually installing mandoc on your system, please check
+whether the newest version of mandoc is already installed by default
+or available via a binary package or a ports system.  A list of the
+latest bundled and ported versions of mandoc for various operating
+systems is maintained at <http://mdocml.bsd.lv/ports.html>.
+
+If mandoc is installed, you can check the version by running "mandoc -V".
+The version contained in this distribution tarball is listed near
+the beginning of the file "Makefile".
+
+Regarding how packages and ports are maintained for your operating
+system, please consult your operating system documentation.
+To install mandoc manually, the following steps are needed:
+
+1. Decide whether you want to build the base tools mandoc(1),
+preconv(1) and demandoc(1) only or whether you also want to build the
+database tools apropos(1) and makewhatis(8).  For the latter,
+the following dependencies are required:
+
+1.1. The SQLite database system, see <http://sqlite.org/>.
+The recommended version of SQLite is 3.8.4.3 or newer.  The mandoc
+toolset is known to work with version 3.7.5 or newer.  Versions
+older than 3.8.3 may not achieve full performance due to the
+missing SQLITE_DETERMINISTIC optimization flag.  Versions older
+than 3.8.0 may not show full error information if opening a database
+fails due to the missing sqlite3_errstr() API.  Both are very minor
+problems, apropos(1) is fully usable with SQLite 3.7.5.  Versions
+older than 3.7.5 may or may not work, they have not been tested.
+
+1.2. The fts(3) directory traversion functions.
+A compatibility version will be bundled for 1.13.2 but is not available
+yet.  If you want apropos(1) and makewhatis(8) but do not have fts(3),
+please stay with mandoc 1.12.3 for now and upgrade first to 1.12.4,
+then to 1.13.2 when these versionns are released.  Be careful: the
+glibc version of fts(3) is known to be broken on 32bit platforms,
+see <https://sourceware.org/bugzilla/show_bug.cgi?id=15838>.
+
+1.3. Marc Espie's ohash(3) library.
+If your system does not have it, the bundled compatibility version
+will be used, so you probably need not worry about it.
+
+2. If you choose to build the database tools, too, decide whether
+you also want to build the CGI program, man.cgi(8).
+
+3. Read the beginning of the file "Makefile" from "USER SETTINGS"
+to "END OF USER SETTINGS" and edit it as required.  In particular,
+disable "BUILD_TARGETS += db-build" if you do not want database
+support or enable "BUILD_TARGETS += cgi-build" if you do want
+the CGI program.
+
+4. Run "make".  No separate "./configure" or "make depend" steps
+are needed.  The former is run automatically by "make".  The latter
+is a maintainer target.  If you merely want to build the released
+version as opposed to doing active development, there is no need
+to regenerate the dependency specifications.  Any POSIX-compatible
+make, in particular both BSD make and GNU make, should work.
+
+5. Run "make -n install" and check whether everything will be
+installed to the intended places.  Otherwise, edit the *DIR variables
+in the Makefile until it is.
+
+6. Run "sudo make install".  If you intend to build a binary
+package using some kind of fake root mechanism, you may need a
+command like "make DESTDIR=... install".  Read the *-install targets
+in the "Makefile" to understand how DESTDIR is used.
+
+7. To set up a man.cgi(8) server, read its manual page.
+
+8. To use mandoc(1) as your man(1) formatter, read the "Deployment"
+section below.
+
+
+Checking autoconfiguration quality
+----------------------------------
+If you want to check whether automatic configuration works well
+on your platform, consider the following:
+
+The mandoc package intentionally does not use GNU autoconf because
+we consider that toolset a blatant example of overengineering that
+is obsolete nowadays, since all modern operating systems are now
+reasonably close to POSIX and do not need arcane shell magic any
+longer.  If your system does need such magic, consider upgrading
+to reasonably modern POSIX-compliant tools rather than asking for
+autoconf-style workarounds.
+
+As far as mandoc is using any features not mandated by ANSI X3.159-1989
+("ANSI C") or IEEE Std 1003.1-2008 ("POSIX") that some modern systems
+do not have, we intend to provide autoconfiguration tests and
+compat_*.c implementations.  Please report any that turn out to be
+missing.  Note that while we do strive to produce portable code,
+we do not slavishly restrict ourselves to POSIX-only interfaces.
+For improved security and readability, we do use well-designed,
+modern interfaces like reallocarray(3) even if they are still rather
+uncommon, of course bundling compat_*.c implementations as needed.
+
+Where mandoc is using ANSI C or POSIX features that some systems
+still lack and that compat_*.c implementations can be provided for
+without too much hassle, we will consider adding them, too, so
+please report whatever is missing on your platform.
+
+The following steps can be used to manually check the automatic
+configuration on your platform:
+
+1. Run "make clean".
+
+2. Run "make config.h"
+
+3. Read the file "config.log".  It shows the compiler commands used
+to test the libraries installed on your system and the standard
+output and standard error output these commands produce.  Watch out
+for unexpected failures.  Those are most likely to happen if headers
+or libraries are installed in unusual places or interfaces defined
+in unusual headers.  You can also look at the file "config.h" and
+check that no expected "#define HAVE_*" lines are missing.  The
+list of tests run can be found in the file "configure".
+
+
+Deployment
+----------
+If you want to integrate the mandoc(1) tools with your existing
+man(1) system as a formatter, then contact us first: on systems without
+mandoc(1) as the default, you may have your work cut out for you!
+Usually, you can have your default installation and mandoc(1) work right
+alongside each other by using user-specific versions of the files
+mentioned below.
+
+0. Back up each file you want to change!
+
+1. First see whether your system has "/etc/man.conf" or "/etc/manpath.conf"
+(if it has neither, but man(1) is functional, then let us know) or,
+if running as your own user, a per-user override file.  In either
+case, find where man(1) is executing nroff(1) or groff(1) to format
+manuals.  Replace these calls with mandoc(1).
+
+2. Then make sure that man(1) isn't running preprocessors, so you may
+need to replace tbl(1), eqn(1), and similar references with cat(1).
+Some man(1) implementations, like that on Mac OSX, let you run "man -d"
+to see how the formatter is invoked.  Use this to test your changes.  On
+Mac OS X, for instance, man(1) will prepend all files with ".ll" and
+".nr" to set the terminal size, so you need to pass "tail -n+2 |
+mandoc(1)" to disregard them.
+
+3. Finally, make sure that mandoc(1) is actually being invoked instead
+of cached pages being pulled up.  You can usually do this by commenting
+out NOCACHE or similar.
+
+mandoc(1) still has a long way to go in understanding non-trivial
+low-level roff(7) markup embedded in some man(7) pages.  On the BSD
+systems using mandoc(1), third-party software is generally vetted
+on whether it may be formatted with mandoc(1).  If not, groff(1)
+is pulled in as a dependency and used to install a pre-formatted
+"catpage" intead of directly as manual page source.
+
+For more background on switching operating systems to use mandoc(1)
+instead of groff(1) to format manuals, see the two BSDCan presentations
+by Ingo Schwarze:
+<http://www.openbsd.org/papers/bsdcan11-mandoc-openbsd.html>
+<http://www.openbsd.org/papers/bsdcan14-mandoc.pdf>
diff --git a/contrib/mdocml/LICENSE b/contrib/mdocml/LICENSE
new file mode 100644 (file)
index 0000000..35072fb
--- /dev/null
@@ -0,0 +1,44 @@
+$Id: LICENSE,v 1.2 2014/04/23 21:06:41 schwarze Exp $
+
+With the exceptions noted below, all code and documentation
+contained in the mdocml toolkit is protected by the Copyright
+of the following developers:
+
+Copyright (c) 2008, 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+Copyright (c) 2010, 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
+Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
+Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+Copyright (c) 1998, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
+
+See the individual source files for information about who contributed
+to which file during which years.
+
+
+The mdocml distribution as a whole is distributed by its developers
+under the following license:
+
+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.
+
+
+The following files included from outside sources are protected by
+other people's Copyright and are distributed under a 3-clause BSD
+license; see these individual files for details.
+
+compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c:
+Copyright (c) 1990, 1993 The Regents of the University of California
+
+compat_fgetln.c:
+Copyright (c) 1998 The NetBSD Foundation, Inc.
index 20b9fea..47f37a7 100644 (file)
@@ -1,15 +1,30 @@
-.PHONY:         clean install installwww
-.SUFFIXES:      .sgml .html .md5 .h .h.html
-.SUFFIXES:      .1       .3       .7       .8
-.SUFFIXES:      .1.html  .3.html  .7.html  .8.html
+# $Id: Makefile,v 1.435 2014/08/10 02:45:04 schwarze Exp $
+#
+# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+# Copyright (c) 2011, 2013, 2014 Ingo Schwarze <schwarze@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.
+
+VERSION                 = 1.13.1
+
+# === USER SETTINGS ====================================================
+
+# --- user settings relevant for all builds ----------------------------
 
 # Specify this if you want to hard-code the operating system to appear
 # in the lower-left hand corner of -mdoc manuals.
 #
-# CFLAGS       += -DOSNAME="\"OpenBSD 5.4\""
-
-VERSION                 = 1.12.3
-VDATE           = 31 December 2013
+# CFLAGS       += -DOSNAME="\"OpenBSD 5.5\""
 
 # IFF your system supports multi-byte functions (setlocale(), wcwidth(),
 # putwchar()) AND has __STDC_ISO_10646__ (that is, wchar_t is simply a
@@ -19,113 +34,136 @@ VDATE              = 31 December 2013
 #
 CFLAGS         += -DUSE_WCHAR
 
-# If your system has manpath(1), uncomment this.  This is most any
-# system that's not OpenBSD or NetBSD.  If uncommented, apropos(1),
-# mandocdb(8), and man.cgi will popen(3) manpath(1) to get the MANPATH
-# variable.
-#CFLAGS                += -DUSE_MANPATH
-
-# If your system does not support static binaries, comment this,
-# for example on Mac OS X.
-STATIC          = -static
-# Linux requires -pthread to statically link with libdb.
-#STATIC                += -pthread
-
 CFLAGS         += -g -DHAVE_CONFIG_H
 CFLAGS         += -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings
 PREFIX          = /usr/local
-WWWPREFIX       = /var/www
-HTDOCDIR        = $(WWWPREFIX)/htdocs
-CGIBINDIR       = $(WWWPREFIX)/cgi-bin
 BINDIR          = $(PREFIX)/bin
 INCLUDEDIR      = $(PREFIX)/include/mandoc
 LIBDIR          = $(PREFIX)/lib/mandoc
 MANDIR          = $(PREFIX)/man
 EXAMPLEDIR      = $(PREFIX)/share/examples/mandoc
+
 INSTALL                 = install
-INSTALL_PROGRAM         = $(INSTALL) -m 0755
+INSTALL_PROGRAM         = $(INSTALL) -m 0555
 INSTALL_DATA    = $(INSTALL) -m 0444
-INSTALL_LIB     = $(INSTALL) -m 0644
+INSTALL_LIB     = $(INSTALL) -m 0444
 INSTALL_SOURCE  = $(INSTALL) -m 0644
 INSTALL_MAN     = $(INSTALL_DATA)
 
-# Non-BSD systems (Linux, etc.) need -ldb to compile mandocdb and
-# apropos.
-# However, if you don't have -ldb at all (or it's not native), then
-# comment out apropos and mandocdb. 
+# --- user settings related to database support ------------------------
+
+# Building apropos(1) and makewhatis(8) requires both SQLite3 and fts(3).
+# To avoid those dependencies, comment the following line.
+# Be careful: the fts(3) implementation in glibc is broken on 32bit
+# machines, see: https://sourceware.org/bugzilla/show_bug.cgi?id=15838
 #
-#DBLIB          = -ldb
-DBBIN           = apropos mandocdb man.cgi catman whatis
-DBLN            = llib-lapropos.ln llib-lmandocdb.ln llib-lman.cgi.ln llib-lcatman.ln
+BUILD_TARGETS  += db-build
 
-all: mandoc preconv demandoc $(DBBIN)
+# The remaining settings in this section
+# are only relevant if db-build is enabled.
+# Otherwise, they have no effect either way.
 
-SRCS            = Makefile \
-                  NEWS \
-                  TODO \
-                  apropos.1 \
-                  apropos.c \
-                  apropos_db.c \
-                  apropos_db.h \
+# If your system has manpath(1), uncomment this.  This is most any
+# system that's not OpenBSD or NetBSD.  If uncommented, apropos(1)
+# and makewhatis(8) will use manpath(1) to get the MANPATH variable.
+#
+#CFLAGS                += -DUSE_MANPATH
+
+# On some systems, SQLite3 may be installed below /usr/local.
+# In that case, uncomment the following two lines.
+#
+#CFLAGS                += -I/usr/local/include
+#DBLIB         += -L/usr/local/lib
+
+# OpenBSD has the ohash functions in libutil.
+# Comment the following line if your system doesn't.
+#
+DBLIB          += -lutil
+
+SBINDIR                 = $(PREFIX)/sbin
+
+# --- user settings related to man.cgi ---------------------------------
+
+# To build man.cgi, copy cgi.h.example to cgi.h, edit it,
+# and enable the following line.
+# Obviously, this requires that db-build is enabled, too.
+#
+#BUILD_TARGETS += cgi-build
+
+# The remaining settings in this section
+# are only relevant if cgi-build is enabled.
+# Otherwise, they have no effect either way.
+
+# If your system does not support static binaries, comment this,
+# for example on Mac OS X.
+#
+STATIC          = -static
+
+# Linux requires -pthread for statical linking.
+#
+#STATIC                += -pthread
+
+WWWPREFIX       = /var/www
+HTDOCDIR        = $(WWWPREFIX)/htdocs
+CGIBINDIR       = $(WWWPREFIX)/cgi-bin
+
+# === END OF USER SETTINGS =============================================
+
+INSTALL_TARGETS         = $(BUILD_TARGETS:-build=-install)
+
+BASEBIN                 = mandoc preconv demandoc
+DBBIN           = apropos makewhatis
+CGIBIN          = man.cgi
+
+DBLIB          += -lsqlite3
+
+TESTSRCS        = test-fgetln.c \
+                  test-getsubopt.c \
+                  test-mmap.c \
+                  test-ohash.c \
+                  test-reallocarray.c \
+                  test-sqlite3_errstr.c \
+                  test-strcasestr.c \
+                  test-strlcat.c \
+                  test-strlcpy.c \
+                  test-strptime.c \
+                  test-strsep.c
+
+SRCS            = apropos.c \
                   arch.c \
-                  arch.in \
                   att.c \
-                  att.in \
-                  catman.8 \
-                  catman.c \
                   cgi.c \
                   chars.c \
-                  chars.in \
                   compat_fgetln.c \
                   compat_getsubopt.c \
+                  compat_ohash.c \
+                  compat_reallocarray.c \
+                  compat_sqlite3_errstr.c \
+                  compat_strcasestr.c \
                   compat_strlcat.c \
                   compat_strlcpy.c \
-                  config.h.post \
-                  config.h.pre \
-                  demandoc.1 \
+                  compat_strsep.c \
                   demandoc.c \
-                  eqn.7 \
                   eqn.c \
                   eqn_html.c \
                   eqn_term.c \
-                  example.style.css \
-                  external.png \
-                  gmdiff \
                   html.c \
-                  html.h \
-                  index.css \
-                  index.sgml \
                   lib.c \
-                  lib.in \
-                  libman.h \
-                  libmandoc.h \
-                  libmdoc.h \
-                  libroff.h \
                   main.c \
-                  main.h \
-                  man.7 \
                   man.c \
-                  man.cgi.7 \
-                  man-cgi.css \
-                  man.h \
                   man_hash.c \
                   man_html.c \
                   man_macro.c \
                   man_term.c \
                   man_validate.c \
-                  mandoc.1 \
-                  mandoc.3 \
                   mandoc.c \
-                  mandoc.h \
-                  mandoc_char.7 \
-                  mandocdb.8 \
+                  mandoc_aux.c \
                   mandocdb.c \
-                  mandocdb.h \
+                  manpage.c \
                   manpath.c \
-                  manpath.h \
-                  mdoc.7 \
+                  mansearch.c \
+                  mansearch_const.c \
                   mdoc.c \
-                  mdoc.h \
                   mdoc_argv.c \
                   mdoc_hash.c \
                   mdoc_html.c \
@@ -134,20 +172,11 @@ SRCS               = Makefile \
                   mdoc_term.c \
                   mdoc_validate.c \
                   msec.c \
-                  msec.in \
                   out.c \
-                  out.h \
-                  preconv.1 \
                   preconv.c \
-                  predefs.in \
                   read.c \
-                  roff.7 \
                   roff.c \
                   st.c \
-                  st.in \
-                  style.css \
-                  tbl.3 \
-                  tbl.7 \
                   tbl.c \
                   tbl_data.c \
                   tbl_html.c \
@@ -155,20 +184,70 @@ SRCS               = Makefile \
                   tbl_opts.c \
                   tbl_term.c \
                   term.c \
-                  term.h \
                   term_ascii.c \
                   term_ps.c \
-                  test-betoh64.c \
-                  test-fgetln.c \
-                  test-getsubopt.c \
-                  test-mmap.c \
-                  test-strlcat.c \
-                  test-strlcpy.c \
-                  test-strptime.c \
                   tree.c \
                   vol.c \
+                  $(TESTSRCS)
+
+DISTFILES       = INSTALL \
+                  LICENSE \
+                  Makefile \
+                  Makefile.depend \
+                  NEWS \
+                  TODO \
+                  apropos.1 \
+                  arch.in \
+                  att.in \
+                  cgi.h.example \
+                  chars.in \
+                  compat_ohash.h \
+                  config.h.post \
+                  config.h.pre \
+                  configure \
+                  demandoc.1 \
+                  eqn.7 \
+                  example.style.css \
+                  gmdiff \
+                  html.h \
+                  lib.in \
+                  libman.h \
+                  libmandoc.h \
+                  libmdoc.h \
+                  libroff.h \
+                  main.h \
+                  makewhatis.8 \
+                  man-cgi.css \
+                  man.7 \
+                  man.cgi.8 \
+                  man.h \
+                  mandoc.1 \
+                  mandoc.3 \
+                  mandoc.db.5 \
+                  mandoc.h \
+                  mandoc_aux.h \
+                  mandoc_char.7 \
+                  mandoc_escape.3 \
+                  mandoc_html.3 \
+                  mandoc_malloc.3 \
+                  manpath.h \
+                  mansearch.3 \
+                  mansearch.h \
+                  mchars_alloc.3 \
+                  mdoc.7 \
+                  mdoc.h \
+                  msec.in \
+                  out.h \
+                  preconv.1 \
+                  predefs.in \
+                  roff.7 \
+                  st.in \
+                  style.css \
+                  tbl.3 \
+                  tbl.7 \
+                  term.h \
                   vol.in \
-                  whatis.1
+                  $(SRCS)
 
 LIBMAN_OBJS     = man.o \
                   man_hash.o \
@@ -198,35 +277,25 @@ LIBMANDOC_OBJS     = $(LIBMAN_OBJS) \
                   $(LIBROFF_OBJS) \
                   chars.o \
                   mandoc.o \
+                  mandoc_aux.o \
                   msec.o \
                   read.o
 
 COMPAT_OBJS     = compat_fgetln.o \
                   compat_getsubopt.o \
+                  compat_ohash.o \
+                  compat_reallocarray.o \
+                  compat_sqlite3_errstr.o \
+                  compat_strcasestr.o \
                   compat_strlcat.o \
-                  compat_strlcpy.o
-
-arch.o: arch.in
-att.o: att.in
-chars.o: chars.in
-lib.o: lib.in
-msec.o: msec.in
-roff.o: predefs.in
-st.o: st.in
-vol.o: vol.in
-
-$(LIBMAN_OBJS): libman.h
-$(LIBMDOC_OBJS): libmdoc.h
-$(LIBROFF_OBJS): libroff.h
-$(LIBMANDOC_OBJS): mandoc.h mdoc.h man.h libmandoc.h config.h
-$(COMPAT_OBJS): config.h
+                  compat_strlcpy.o \
+                  compat_strsep.o
 
 MANDOC_HTML_OBJS = eqn_html.o \
                   html.o \
                   man_html.o \
                   mdoc_html.o \
                   tbl_html.o
-$(MANDOC_HTML_OBJS): html.h
 
 MANDOC_MAN_OBJS  = mdoc_man.o
 
@@ -237,7 +306,6 @@ MANDOC_TERM_OBJS = eqn_term.o \
                   term_ascii.o \
                   term_ps.o \
                   tbl_term.o
-$(MANDOC_TERM_OBJS): term.h
 
 MANDOC_OBJS     = $(MANDOC_HTML_OBJS) \
                   $(MANDOC_MAN_OBJS) \
@@ -245,76 +313,85 @@ MANDOC_OBJS        = $(MANDOC_HTML_OBJS) \
                   main.o \
                   out.o \
                   tree.o
-$(MANDOC_OBJS): main.h mandoc.h mdoc.h man.h config.h out.h
 
-MANDOCDB_OBJS   = mandocdb.o manpath.o
-$(MANDOCDB_OBJS): mandocdb.h mandoc.h mdoc.h man.h config.h manpath.h
+MAKEWHATIS_OBJS         = mandocdb.o mansearch_const.o manpath.o
 
 PRECONV_OBJS    = preconv.o
-$(PRECONV_OBJS): config.h
 
-APROPOS_OBJS    = apropos.o apropos_db.o manpath.o
-$(APROPOS_OBJS): config.h mandoc.h apropos_db.h manpath.h mandocdb.h
+APROPOS_OBJS    = apropos.o mansearch.o mansearch_const.o manpath.o
 
 CGI_OBJS        = $(MANDOC_HTML_OBJS) \
-                  $(MANDOC_MAN_OBJS) \
-                  $(MANDOC_TERM_OBJS) \
                   cgi.o \
-                  apropos_db.o \
-                  manpath.o \
-                  out.o \
-                  tree.o
-$(CGI_OBJS): main.h mdoc.h man.h out.h config.h mandoc.h apropos_db.h manpath.h mandocdb.h
+                  mansearch.o \
+                  mansearch_const.o \
+                  out.o
 
-CATMAN_OBJS     = catman.o manpath.o
-$(CATMAN_OBJS): config.h mandoc.h manpath.h mandocdb.h
+MANPAGE_OBJS    = manpage.o mansearch.o mansearch_const.o manpath.o
 
 DEMANDOC_OBJS   = demandoc.o
-$(DEMANDOC_OBJS): config.h
 
-INDEX_MANS      = apropos.1.html \
-                  catman.8.html \
+WWW_MANS        = apropos.1.html \
                   demandoc.1.html \
                   mandoc.1.html \
-                  whatis.1.html \
+                  preconv.1.html \
                   mandoc.3.html \
+                  mandoc_escape.3.html \
+                  mandoc_html.3.html \
+                  mandoc_malloc.3.html \
+                  mansearch.3.html \
+                  mchars_alloc.3.html \
                   tbl.3.html \
+                  mandoc.db.5.html \
                   eqn.7.html \
                   man.7.html \
-                  man.cgi.7.html \
                   mandoc_char.7.html \
                   mdoc.7.html \
-                  preconv.1.html \
                   roff.7.html \
                   tbl.7.html \
-                  mandocdb.8.html
-
-$(INDEX_MANS): mandoc
-
-INDEX_OBJS      = $(INDEX_MANS) \
+                  makewhatis.8.html \
+                  man.cgi.8.html \
                   man.h.html \
                   mandoc.h.html \
-                  mdoc.h.html \
-                  mdocml.tar.gz \
-                  mdocml.md5
+                  mandoc_aux.h.html \
+                  manpath.h.html \
+                  mansearch.h.html \
+                  mdoc.h.html
+
+WWW_OBJS        = mdocml.tar.gz \
+                  mdocml.sha256
+
+# === DEPENDENCY HANDLING ==============================================
+
+all: base-build $(BUILD_TARGETS)
+
+base-build: $(BASEBIN)
+
+db-build: $(DBBIN)
+
+cgi-build: $(CGIBIN)
+
+install: base-install $(INSTALL_TARGETS)
 
-www: index.html
+www: $(WWW_OBJS) $(WWW_MANS)
+
+include Makefile.depend
+
+# === TARGETS CONTAINING SHELL COMMANDS ================================
 
 clean:
        rm -f libmandoc.a $(LIBMANDOC_OBJS)
-       rm -f mandocdb $(MANDOCDB_OBJS)
+       rm -f apropos $(APROPOS_OBJS)
+       rm -f makewhatis $(MAKEWHATIS_OBJS)
        rm -f preconv $(PRECONV_OBJS)
-       rm -f apropos whatis $(APROPOS_OBJS)
        rm -f man.cgi $(CGI_OBJS)
-       rm -f catman $(CATMAN_OBJS)
+       rm -f manpage $(MANPAGE_OBJS)
        rm -f demandoc $(DEMANDOC_OBJS)
        rm -f mandoc $(MANDOC_OBJS)
        rm -f config.h config.log $(COMPAT_OBJS)
-       rm -f mdocml.tar.gz
-       rm -f index.html $(INDEX_OBJS)
+       rm -f $(WWW_MANS) $(WWW_OBJS)
        rm -rf *.dSYM
 
-install: all
+base-install: base-build
        mkdir -p $(DESTDIR)$(BINDIR)
        mkdir -p $(DESTDIR)$(EXAMPLEDIR)
        mkdir -p $(DESTDIR)$(LIBDIR)
@@ -322,31 +399,59 @@ install: all
        mkdir -p $(DESTDIR)$(MANDIR)/man1
        mkdir -p $(DESTDIR)$(MANDIR)/man3
        mkdir -p $(DESTDIR)$(MANDIR)/man7
-       $(INSTALL_PROGRAM) mandoc preconv demandoc $(DESTDIR)$(BINDIR)
+       $(INSTALL_PROGRAM) $(BASEBIN) $(DESTDIR)$(BINDIR)
        $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
-       $(INSTALL_LIB) man.h mdoc.h mandoc.h $(DESTDIR)$(INCLUDEDIR)
+       $(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h \
+               $(DESTDIR)$(INCLUDEDIR)
        $(INSTALL_MAN) mandoc.1 preconv.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
-       $(INSTALL_MAN) mandoc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
-       $(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 $(DESTDIR)$(MANDIR)/man7
+       $(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
+               mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
+       $(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 \
+               $(DESTDIR)$(MANDIR)/man7
        $(INSTALL_DATA) example.style.css $(DESTDIR)$(EXAMPLEDIR)
 
-installcgi: all
+db-install: db-build
+       mkdir -p $(DESTDIR)$(BINDIR)
+       mkdir -p $(DESTDIR)$(SBINDIR)
+       mkdir -p $(DESTDIR)$(MANDIR)/man1
+       mkdir -p $(DESTDIR)$(MANDIR)/man3
+       mkdir -p $(DESTDIR)$(MANDIR)/man5
+       mkdir -p $(DESTDIR)$(MANDIR)/man8
+       $(INSTALL_PROGRAM) apropos $(DESTDIR)$(BINDIR)
+       ln -f $(DESTDIR)$(BINDIR)/apropos $(DESTDIR)$(BINDIR)/whatis
+       $(INSTALL_PROGRAM) makewhatis $(DESTDIR)$(SBINDIR)
+       $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1
+       ln -f $(DESTDIR)$(MANDIR)/man1/apropos.1 \
+               $(DESTDIR)$(MANDIR)/man1/whatis.1
+       $(INSTALL_MAN) mansearch.3 $(DESTDIR)$(MANDIR)/man3
+       $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5
+       $(INSTALL_MAN) makewhatis.8 $(DESTDIR)$(MANDIR)/man8
+
+cgi-install: cgi-build
        mkdir -p $(DESTDIR)$(CGIBINDIR)
        mkdir -p $(DESTDIR)$(HTDOCDIR)
+       mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1
+       mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8
        $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR)
        $(INSTALL_DATA) example.style.css $(DESTDIR)$(HTDOCDIR)/man.css
        $(INSTALL_DATA) man-cgi.css $(DESTDIR)$(HTDOCDIR)
-
-installwww: www
-       mkdir -p $(PREFIX)/snapshots
-       mkdir -p $(PREFIX)/binaries
-       $(INSTALL_DATA) index.html external.png index.css $(PREFIX)
-       $(INSTALL_DATA) $(INDEX_MANS) style.css $(PREFIX)
-       $(INSTALL_DATA) mandoc.h.html man.h.html mdoc.h.html $(PREFIX)
-       $(INSTALL_DATA) mdocml.tar.gz $(PREFIX)/snapshots
-       $(INSTALL_DATA) mdocml.md5 $(PREFIX)/snapshots
-       $(INSTALL_DATA) mdocml.tar.gz $(PREFIX)/snapshots/mdocml-$(VERSION).tar.gz
-       $(INSTALL_DATA) mdocml.md5 $(PREFIX)/snapshots/mdocml-$(VERSION).md5
+       $(INSTALL_MAN) apropos.1 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1/
+       $(INSTALL_MAN) man.cgi.8 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8/
+
+www-install: www
+       mkdir -p $(DESTDIR)$(HTDOCDIR)/snapshots
+       $(INSTALL_DATA) $(WWW_MANS) style.css $(DESTDIR)$(HTDOCDIR)
+       $(INSTALL_DATA) $(WWW_OBJS) $(DESTDIR)$(HTDOCDIR)/snapshots
+       $(INSTALL_DATA) mdocml.tar.gz \
+               $(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).tar.gz
+       $(INSTALL_DATA) mdocml.sha256 \
+               $(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).sha256
+
+depend: config.h
+       mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
+       perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \
+               s|\\\n||g; s|  +| |g; print;' Makefile.depend > Makefile.tmp
+       mv Makefile.tmp Makefile.depend
 
 libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
        $(AR) rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
@@ -354,81 +459,47 @@ libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
 mandoc: $(MANDOC_OBJS) libmandoc.a
        $(CC) $(LDFLAGS) -o $@ $(MANDOC_OBJS) libmandoc.a
 
-mandocdb: $(MANDOCDB_OBJS) libmandoc.a
-       $(CC) $(LDFLAGS) -o $@ $(MANDOCDB_OBJS) libmandoc.a $(DBLIB)
+makewhatis: $(MAKEWHATIS_OBJS) libmandoc.a
+       $(CC) $(LDFLAGS) -o $@ $(MAKEWHATIS_OBJS) libmandoc.a $(DBLIB)
 
 preconv: $(PRECONV_OBJS)
        $(CC) $(LDFLAGS) -o $@ $(PRECONV_OBJS)
 
-whatis: apropos
-       cp -f apropos whatis
+manpage: $(MANPAGE_OBJS) libmandoc.a
+       $(CC) $(LDFLAGS) -o $@ $(MANPAGE_OBJS) libmandoc.a $(DBLIB)
 
 apropos: $(APROPOS_OBJS) libmandoc.a
        $(CC) $(LDFLAGS) -o $@ $(APROPOS_OBJS) libmandoc.a $(DBLIB)
 
-catman: $(CATMAN_OBJS) libmandoc.a
-       $(CC) $(LDFLAGS) -o $@ $(CATMAN_OBJS) libmandoc.a $(DBLIB)
-
 man.cgi: $(CGI_OBJS) libmandoc.a
        $(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
 
 demandoc: $(DEMANDOC_OBJS) libmandoc.a
        $(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a
 
-mdocml.md5: mdocml.tar.gz
-       md5 mdocml.tar.gz >$@
+mdocml.sha256: mdocml.tar.gz
+       sha256 mdocml.tar.gz > $@
 
-mdocml.tar.gz: $(SRCS)
+mdocml.tar.gz: $(DISTFILES)
        mkdir -p .dist/mdocml-$(VERSION)/
-       $(INSTALL_SOURCE) $(SRCS) .dist/mdocml-$(VERSION)
-       ( cd .dist/ && tar zcf ../$@ ./ )
+       $(INSTALL_SOURCE) $(DISTFILES) .dist/mdocml-$(VERSION)
+       chmod 755 .dist/mdocml-$(VERSION)/configure
+       ( cd .dist/ && tar zcf ../$@ mdocml-$(VERSION) )
        rm -rf .dist/
 
-index.html: $(INDEX_OBJS)
-
-config.h: config.h.pre config.h.post
+config.h: configure config.h.pre config.h.post $(TESTSRCS)
        rm -f config.log
-       ( cat config.h.pre; \
-         echo; \
-         echo '#define VERSION "$(VERSION)"'; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-fgetln test-fgetln.c >> config.log 2>&1; then \
-               echo '#define HAVE_FGETLN'; \
-               rm test-fgetln; \
-         fi; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strptime test-strptime.c >> config.log 2>&1; then \
-               echo '#define HAVE_STRPTIME'; \
-               rm test-strptime; \
-         fi; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-getsubopt test-getsubopt.c >> config.log 2>&1; then \
-               echo '#define HAVE_GETSUBOPT'; \
-               rm test-getsubopt; \
-         fi; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strlcat test-strlcat.c >> config.log 2>&1; then \
-               echo '#define HAVE_STRLCAT'; \
-               rm test-strlcat; \
-         fi; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-mmap test-mmap.c >> config.log 2>&1; then \
-               echo '#define HAVE_MMAP'; \
-               rm test-mmap; \
-         fi; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strlcpy test-strlcpy.c >> config.log 2>&1; then \
-               echo '#define HAVE_STRLCPY'; \
-               rm test-strlcpy; \
-         fi; \
-         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-betoh64 test-betoh64.c >> config.log 2>&1; then \
-               echo '#define HAVE_BETOH64'; \
-               rm test-betoh64; \
-         fi; \
-         echo; \
-         cat config.h.post \
-       ) > $@
+       CC="$(CC)" CFLAGS="$(CFLAGS)" DBLIB="$(DBLIB)" \
+               VERSION="$(VERSION)" ./configure
 
-.h.h.html:
-       highlight -I $< >$@
+.PHONY:         base-install cgi-install db-install install www-install
+.PHONY:         clean depend
+.SUFFIXES:      .1       .3       .5       .7       .8       .h
+.SUFFIXES:      .1.html  .3.html  .5.html  .7.html  .8.html  .h.html
 
-.1.1.html .3.3.html .7.7.html .8.8.html:
-       ./mandoc -Thtml -Wall,stop -Ostyle=style.css,man=%N.%S.html,includes=%I.html $< >$@
+.h.h.html:
+       highlight -I $< > $@
 
-.sgml.html:
-       validate --warn $<
-       sed -e "s!@VERSION@!$(VERSION)!" -e "s!@VDATE@!$(VDATE)!" $< >$@
+.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
+       ./mandoc -Thtml -Wall,stop \
+               -Ostyle=style.css,man=%N.%S.html,includes=%I.html $< > $@
diff --git a/contrib/mdocml/Makefile.depend b/contrib/mdocml/Makefile.depend
new file mode 100644 (file)
index 0000000..dc49310
--- /dev/null
@@ -0,0 +1,70 @@
+apropos.o: apropos.c config.h manpath.h mansearch.h
+arch.o: arch.c config.h mdoc.h libmdoc.h arch.in
+att.o: att.c config.h mdoc.h libmdoc.h att.in
+cgi.o: cgi.c config.h mandoc.h mandoc_aux.h main.h manpath.h mansearch.h cgi.h
+chars.o: chars.c config.h mandoc.h mandoc_aux.h libmandoc.h chars.in
+compat_fgetln.o: compat_fgetln.c config.h 
+compat_getsubopt.o: compat_getsubopt.c config.h 
+compat_ohash.o: compat_ohash.c config.h 
+compat_reallocarray.o: compat_reallocarray.c config.h 
+compat_sqlite3_errstr.o: compat_sqlite3_errstr.c config.h 
+compat_strcasestr.o: compat_strcasestr.c config.h 
+compat_strlcat.o: compat_strlcat.c config.h 
+compat_strlcpy.o: compat_strlcpy.c config.h 
+compat_strsep.o: compat_strsep.c config.h 
+demandoc.o: demandoc.c config.h man.h mdoc.h mandoc.h
+eqn.o: eqn.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h
+eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h
+html.o: html.c config.h mandoc.h mandoc_aux.h libmandoc.h out.h html.h main.h
+lib.o: lib.c config.h mdoc.h libmdoc.h lib.in
+main.o: main.c config.h mandoc.h mandoc_aux.h main.h mdoc.h man.h
+man.o: man.c config.h man.h mandoc.h mandoc_aux.h libman.h libmandoc.h
+man_hash.o: man_hash.c config.h man.h mandoc.h libman.h
+man_html.o: man_html.c config.h mandoc.h mandoc_aux.h out.h html.h man.h main.h
+man_macro.o: man_macro.c config.h man.h mandoc.h libmandoc.h libman.h
+man_term.o: man_term.c config.h mandoc.h mandoc_aux.h out.h man.h term.h main.h
+man_validate.o: man_validate.c config.h man.h mandoc.h mandoc_aux.h libman.h libmandoc.h
+mandoc.o: mandoc.c config.h mandoc.h mandoc_aux.h libmandoc.h
+mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
+mandocdb.o: mandocdb.c config.h mdoc.h man.h mandoc.h mandoc_aux.h manpath.h mansearch.h
+manpage.o: manpage.c config.h manpath.h mansearch.h
+manpath.o: manpath.c config.h mandoc_aux.h manpath.h
+mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h manpath.h mansearch.h
+mansearch_const.o: mansearch_const.c config.h manpath.h mansearch.h
+mdoc.o: mdoc.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
+mdoc_argv.o: mdoc_argv.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
+mdoc_hash.o: mdoc_hash.c config.h mdoc.h libmdoc.h
+mdoc_html.o: mdoc_html.c config.h mandoc.h mandoc_aux.h out.h html.h mdoc.h main.h
+mdoc_macro.o: mdoc_macro.c config.h mdoc.h mandoc.h libmdoc.h libmandoc.h
+mdoc_man.o: mdoc_man.c config.h mandoc.h mandoc_aux.h out.h man.h mdoc.h main.h
+mdoc_term.o: mdoc_term.c config.h mandoc.h mandoc_aux.h out.h term.h mdoc.h main.h
+mdoc_validate.o: mdoc_validate.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
+msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
+out.o: out.c config.h mandoc_aux.h mandoc.h out.h
+preconv.o: preconv.c config.h 
+read.o: read.c config.h mandoc.h mandoc_aux.h libmandoc.h mdoc.h man.h main.h
+roff.o: roff.c config.h mandoc.h mandoc_aux.h libroff.h libmandoc.h predefs.in
+st.o: st.c config.h mdoc.h libmdoc.h st.in
+tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h
+tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h
+tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h
+term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
+term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
+term_ps.o: term_ps.c config.h mandoc.h mandoc_aux.h out.h main.h term.h
+tree.o: tree.c config.h mandoc.h mdoc.h man.h main.h
+vol.o: vol.c config.h mdoc.h libmdoc.h vol.in
+test-fgetln.o: test-fgetln.c 
+test-getsubopt.o: test-getsubopt.c 
+test-mmap.o: test-mmap.c 
+test-ohash.o: test-ohash.c 
+test-reallocarray.o: test-reallocarray.c 
+test-sqlite3_errstr.o: test-sqlite3_errstr.c 
+test-strcasestr.o: test-strcasestr.c 
+test-strlcat.o: test-strlcat.c 
+test-strlcpy.o: test-strlcpy.c 
+test-strptime.o: test-strptime.c 
+test-strsep.o: test-strsep.c 
index 6f21a38..61006b5 100644 (file)
@@ -1,7 +1,87 @@
-$Id: NEWS,v 1.3 2013/10/13 16:06:50 schwarze Exp $
+$Id: NEWS,v 1.5 2014/08/10 16:32:57 schwarze Exp $
 
 This file lists the most important changes in the mdocml.bsd.lv distribution.
 
+Changes in version 1.13.1, released on August 10, 2014
+
+    --- MAJOR NEW FEATURES ---
+ * A complete apropos(1)/makewhatis(8)/man.cgi(8) suite
+   based on SQLite3 is now included.
+   CAVEAT: This also requires a working fts(3) implementation.
+   If your system lacks that *and* you want apropos(1)/makewhatis(8),
+   stay with 1.12.3 for now, then go to 1.12.4 and 1.13.2.
+ * The roff(7) parser now provides an almost complete implementation
+   of numerical expressions.
+ * Warning and error messages have been improved in many ways.
+   Almost all fatal errors were downgraded to normal errors and some
+   even to warnings.  Almost all messages now mention the macro where
+   the issue is detected and many indicate the workaround employed.
+   The mandoc(1) manual now includes a list explaining all messages.
+    --- MINOR NEW FEATURES ---
+ * The roff(7) parser now supports the .ami (append to macro with
+   indirectly specified name), .as (append to user-defined
+   string), .dei (define macro with indirectly specified name),
+   .ll (line length), and .rr (remove register) requests.
+ * The roff(7) parser now supports string comparison and numerical
+   conditionals in the .if and .ie requests.
+ * The roff parser now fully supports the \B (validate numerical
+   expression) and partially supports the \w (measure text width)
+   escape sequences.
+ * The terminal formatter now supports the \: (optional line break)
+   escape sequence.
+ * The roff parser now supports expansion of user-defined strings
+   involving indirect references.
+ * The roff(7) parser now handles some pre-defined read-only
+   number registers that occur in the pod2man(1) preamble.
+ * For backward compatibility, the mdoc(7) parser and formatters
+   now support the obsolete macros .En, .Es, .Fr, and .Ot.
+ * The mdoc(7) formatter non partially supports .Bd -centered.
+ * tbl(7) now handles leading and trailing vertical lines.
+ * The build system now provides fallback versions of strcasestr(3)
+   and strsep(3) for systems lacking them.
+ * The mdoc(7) manual now explains how various standards
+   supported by the .St macro are related to each other.
+    --- BUGFIXES ---
+ * In the roff(7) parser, several bugs were fixed with respect
+   to closing conditional blocks on macro lines.
+ * Parsing of roff(7) identifiers and escape sequences was improved
+   in multiple respects.
+ * In the mdoc(7) parser, the handling of defective document
+   prologues was improved in multiple ways.
+ * The mdoc(7) parser no longer skips content before the first section
+   header, and it no longer deletes non-.% content from .Rs blocks.
+ * In the mdoc(7) parser, a crash was fixed related to weird .Sh headers.
+ * In the mdoc(7) parser, handling of .Sm with missing or invalid
+   arguments was corrected.
+ * In the mdoc(7) parser, trailing punctuation at the end of partial
+   implicit macros no longer triggers end-of-sentence spacing.
+ * In the terminal formatter, two crashes were fixed: one triggered by
+   excessive indentation and another by excessively long .Nm arguments.
+ * In the terminal formatter, a floating point rounding bug was
+   fixed that sometimes caused an off-by-one error in indentation.
+ * In the UTF-8 formatter, rendering of accents, breakable hyphens,
+   and non-breakable spaces was corrected.
+ * In the HTML formatter, encoding of special characters was
+   corrected in multiple respects.
+ * In the mdoc(7) formatter, rendering of .Ex and .Rv was
+   improved for various edge cases.
+ * In the mdoc(7) formatter, handling of empty .Bl -inset item
+   heads was improved.
+ * In the man(7) formatter, some bugs were fixed with respect
+   to same-line detection in the context of .TP and .nf macros,
+   and the indentation of .IP and .TP blocks was improved.
+ * The mandoc(3) library no longer prints to stderr.
+    --- THANKS TO ---
+   Abhinav Upadhyay (NetBSD), Andreas Voegele, Anthony Bentley (OpenBSD),
+   Christian Weisgerber (OpenBSD), Havard Eidnes (NetBSD), Jan Stary,
+   Jason McIntyre (OpenBSD), Jeremie Courreges-Anglas (OpenBSD),
+   Joerg Sonnenberger (NetBSD), Juan Francisco Cantero Hurtado (OpenBSD),
+   Marc Espie (OpenBSD), Matthias Scheler (NetBSD), Pascal Stumpf (OpenBSD),
+   Paul Onyschuk (Alpine Linux), Sebastien Marie, Steffen Nurpmeso,
+   Stuart Henderson (OpenBSD), Ted Unangst (OpenBSD), Theo de Raadt (OpenBSD),
+   Thomas Klausner (NetBSD), and Ulrich Spoerlein (FreeBSD)
+   for reporting bugs and missing features.
+
 Changes in version 1.12.3, released on December 31, 2013
 
  * In the mdoc(7) SYNOPSIS, line breaks and hanging indentation
index 26f42c2..a41df29 100644 (file)
@@ -1,13 +1,15 @@
 ************************************************************************
 * Official mandoc TODO.
-* $Id: TODO,v 1.162 2013/12/25 14:40:34 schwarze Exp $
+* $Id: TODO,v 1.176 2014/08/09 14:24:53 schwarze Exp $
 ************************************************************************
 
 ************************************************************************
 * crashes
 ************************************************************************
 
-None known.
+- The abort() in bufcat(), html.c, can be triggered via buffmt_includes()
+  by running -Thtml -Oincludes on a file containing a long .In argument.
+  Fixing this will probably require reworking the whole bufcat() concept.
 
 ************************************************************************
 * missing features
@@ -15,11 +17,6 @@ None known.
 
 --- missing roff features ----------------------------------------------
 
-- roff.c should treat \n(.H>23 and \n(.V>19 in the pod2man(1)
-  preamble as true, see for example AUTHORS in MooseX::Getopt.3p
-  reported by Andreas Voegele <mail at andreasvoegele dot com>
-  Tue, 22 Nov 2011 15:34:47 +0100 on ports@
-
 - .ad (adjust margins)
   .ad l -- adjust left margin only (flush left)
   .ad r -- adjust right margin only (flush right)
@@ -29,20 +26,9 @@ None known.
   .ad   -- re-enable adjustment without changing the mode
   Adjustment mode is ignored while in no-fill mode (.nf).
 
-- .as (append to string)
-  found by jca@ in ratpoison(1)  Sun, 30 Jun 2013 12:01:09 +0200
-  
-- .ce (center N lines)
-  found by naddy@ in xloadimage(1)
-  found by Juan Francisco Cantero Hurtado <iam at juanfra dot info>
-           in lang/racket(1)  Thu, 20 Jun 2013 03:19:11 +0200
-
 - .fc (field control)
   found by naddy@ in xloadimage(1)
   
-- .ll (line length)
-  found by naddy@ in textproc/enchant(1)  Sat, 12 Oct 2013 03:27:10 +0200
-
 - .nr third argument (auto-increment step size, requires \n+)
   found by bentley@ in sbcl(1)  Mon, 9 Dec 2013 18:36:57 -0700
 
@@ -51,6 +37,7 @@ None known.
 
 - .ta (tab settings) occurs in ircbug(1) and probably gnats(1)
   reported by brad@  Sat, 15 Jan 2011 15:50:51 -0500
+  also Tcl_NewStringObj(3) via wiz@  Wed, 5 Mar 2014 22:27:43 +0100
 
 - .ti (temporary indent)
   found by naddy@ in xloadimage(1)
@@ -70,6 +57,10 @@ None known.
 - \n+ and \n- numerical register increment and decrement
   found by bentley@ in sbcl(1)  Mon, 9 Dec 2013 18:36:57 -0700
 
+- \w'' width measurements
+  would not be very useful without an expression parser, see below
+  needed for Tcl_NewStringObj(3) via wiz@  Wed, 5 Mar 2014 22:27:43 +0100
+
 - using undefined strings or macros defines them to be empty
   wl@  Mon, 14 Nov 2011 14:37:01 +0000
 
@@ -96,6 +87,12 @@ None known.
   because libmdoc does not yet use mandoc_getarg().
   Also check what happens in plain text, it must be identical to \e.
 
+- .Bd -centered implies -filled, not -unfilled, which is not
+  easy to implement; it requires code similar to .ce, which
+  we don't have either.
+  Besides, groff has bug causing text right *before* .Bd -centered
+  to be centered as well.
+
 - .Bd -filled should not be the same as .Bd -ragged, but align both
   the left and right margin.  In groff, it is implemented in terms
   of .ad b, which we don't have either.  Found in cksum(1).
@@ -129,10 +126,19 @@ None known.
 
 - have a blank `It' head for `Bl -tag' not puke
 
+- check whether it is correct that `D1' uses INDENT+1;
+  does it need its own constant?
+
 - prohibit `Nm' from having non-text HEAD children
   (e.g., NetBSD mDNSShared/dns-sd.1)
   (mdoc_html.c and mdoc_term.c `Nm' handlers can be slightly simplified)
 
+- support translated section names
+  e.g. x11/scrotwm scrotwm_es.1:21:2: error: NAME section must be first
+  that one uses NOMBRE because it is spanish...
+  deraadt tends to think that section-dependent macro behaviour
+  is a bad idea in the first place, so this may be irrelevant
+
 - When there is free text in the SYNOPSIS and that free text contains
   the .Nm macro, groff somehow understands to treat the .Nm as an in-line
   macro, while mandoc treats it as a block macro and breaks the line.
@@ -143,18 +149,15 @@ None known.
 
 --- missing man features -----------------------------------------------
 
-- groff an-ext.tmac macros (.UR, .UE) occur in xine(5)
-  reported by brad@  Sat, 15 Jan 2011 15:45:23 -0500
-  also occur in freeciv-client(6) freeciv-server(6) freeciv-modpack(6)
-  reported by bentley@  Tue, 30 Oct 2012 01:05:57 -0600
-
 - -T[x]html doesn't stipulate non-collapsing spaces in literal mode
 
 --- missing tbl features -----------------------------------------------
 
-- implement basic non-parametric .de to support e.g. sox(1)
-  reported by naddy@ Sat, 16 Oct 2010 23:51:57 +0200
-  *** sox(1) still doesn't work, tbl(1) errors need investigation
+- look at the POSIX manuals in the books/man-pages-posix port,
+  they use some unsupported tbl(7) features.
+
+- investigate tbl(1) errors in sox(1)
+  see also naddy@  Sat, 16 Oct 2010 23:51:57 +0200
 
 - allow standalone `.' to be interpreted as an end-of-layout
   delimiter instead of being thrown away as a no-op roff line
@@ -165,14 +168,19 @@ None known.
 - italic correction (\/) in PostScript mode
   Werner LEMBERG on groff at gnu dot org  Sun, 10 Nov 2013 12:47:46
 
-- The whatis(1) utility looks for whole words in Nm.
-  If the file name of a page does not agree with the contents of any
-  of its Nm macros (e.g. pool(9)), add the file name as an Nm entry
-  to the mandoc.db as well, such that whatis(1) finds it.
-  If there is a page with a file name that does not appear as a substring
-  neither in Nm nor in Nd, the same fix would allow finding that page
-  with apropos(1) using the file name as a key, as well.
-  Issue reported by tedu@  Fri, 05 Jul 2013 21:15:23 -0400
+- When makewhatis(8) encounters a FATAL parse error,
+  it silently treats the file as formatted, which makes no sense
+  at all for paths like man1/foo.1 - and which also contradicts
+  what the manual says at the end of the description.
+  The end result will be ENOENT for file names returned
+  by mansearch() in manpage.file.
+
+- makewhatis(8) for preformatted pages:
+  parse the section number from the header line
+  and compare to the section number from the directory name
+
+- Does makewhatis(8) detect missing NAME sections, missing names,
+  and missing descriptions in all the file formats?
 
 - clean up escape sequence handling, creating three classes:
   (1) fully implemented, or parsed and ignored without loss of content
@@ -181,6 +189,16 @@ None known.
       see textproc/mgdiff(1) for nice examples
   (3) undefined, just output the character -> perhaps WARNING
 
+- kettenis wants base roff, ms, and me  Fri, 1 Jan 2010 22:13:15 +0100 (CET)
+
+--- compatibility checks -----------------------------------------------
+
+- is .Bk implemented correctly in modern groff?
+  sobrado@  Tue, 19 Apr 2011 22:12:55 +0200
+
+- compare output to Heirloom roff, Solaris roff, and
+  http://repo.or.cz/w/neatroff.git  http://litcave.rudi.ir/
+
 - look at pages generated from reStructeredText, e.g. devel/mercurial hg(1)
   These are a weird mixture of man(7) and custom autogenerated low-level
   roff stuff.  Figure out to what extent we can cope.
@@ -188,14 +206,24 @@ None known.
   noted by stsp@  Sat, 24 Apr 2010 09:17:55 +0200
   reminded by nicm@  Mon, 3 May 2010 09:52:41 +0100
 
+- look at pages generated from ronn(1) github.com/rtomayko/ronn
+  (based on markdown)
+
 - look at pages generated from Texinfo source by yat2m, e.g. security/gnupg
   First impression is not that bad.
 
+- look at pages generated by pandoc; see
+  https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/Writers/Man.hs
+  porting planned by kili@  Thu, 19 Jun 2014 19:46:28 +0200
+
 - check compatibility with Plan9:
   http://swtch.com/usr/local/plan9/tmac/tmac.an
   http://swtch.com/plan9port/man/man7/man.html
   "Anthony J. Bentley" <anthonyjbentley@gmail.com> 28 Dec 2010 21:58:40 -0700
 
+- check compatibility with the man(7) formatter
+  https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c
+
 ************************************************************************
 * formatting issues: ugly output
 ************************************************************************
@@ -227,6 +255,10 @@ None known.
   the right solution, it sends mandoc into an endless loop.
   reported by Nicolas Joly  Sat, 17 Nov 2012 11:49:54 +0100
 
+- global variables in the SYNOPSIS of section 3 pages
+  .Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ...
+  from kristaps@  Tue, 08 Jun 2010 11:13:32 +0200
+
 - in enclosures, mandoc sometimes fancies a bogus end of sentence
   reminded by jmc@  Thu, 23 Sep 2010 18:13:39 +0059
 
@@ -234,6 +266,23 @@ None known.
   reveals lots of bugs both in groff and mandoc...
   reported by bentley@  Wed, 22 May 2013 23:49:30 -0600
 
+--- PDF issues ---------------------------------------------------------
+
+- PDF output doesn't use a monospaced font for .Bd -literal
+  Example: "mandoc -Tpdf afterboot.8 > output.pdf && pdfviewer output.pdf".
+  Search the text "Routing tables".
+  Also check what PostScript mode does when fixing this.
+  reported by juanfra@ Wed, 04 Jun 2014 21:44:58 +0200
+
+--- HTML issues --------------------------------------------------------
+
+- <dl><dt><dd> formatting is ugly
+  hints are easy to find on the web, e.g.
+  http://stackoverflow.com/questions/1713048/
+  see also matthew@  Fri, 18 Jul 2014 19:25:12 -0700
+
+- check https://github.com/trentm/mdocml
+
 ************************************************************************
 * formatting issues: gratuitous differences
 ************************************************************************
@@ -246,6 +295,10 @@ None known.
   is just "o\bo".
   see for example OpenBSD ksh(1)
 
+- In .Bl -enum -width 0n, groff continues one the same line after
+  the number, mandoc breaks the line.
+  mail to kristaps@  Mon, 20 Jul 2009 02:21:39 +0200
+
 - .Pp between two .It in .Bl -column should produce one,
   not two blank lines, see e.g. login.conf(5).
   reported by jmc@  Sun, 17 Apr 2011 14:04:58 +0059
@@ -298,10 +351,58 @@ None known.
     operate in batch mode
   in dig(1).
 
+************************************************************************
+* warning issues
+************************************************************************
+
+- check that MANDOCERR_BADTAB is thrown in the right cases,
+  i.e. when finding a literal tab character in fill mode,
+  and possibly change the wording of the warning message
+  to refer to fill mode, not literal mode
+  See the mail from Werner LEMBERG on the groff list,
+  Fri, 14 Feb 2014 18:54:42 +0100 (CET)
+
+- warn about "new sentence, new line"
+
+- mandoc_special does not really check the escape sequence,
+  but just the overall format
+
+- integrate mdoclint into mandoc ("end-of-line whitespace" thread)
+  from jmc@  Mon, 13 Jul 2009 17:12:09 +0100
+  from kristaps@  Mon, 13 Jul 2009 18:34:53 +0200
+  from jmc@  Mon, 13 Jul 2009 17:45:37 +0059
+  from kristaps@  Mon, 13 Jul 2009 19:02:03 +0200
+
+- -Tlint parser errors and warnings to stdout
+  to tech@mdocml, naddy@  Wed, 28 Sep 2011 11:21:46 +0200
+  wait!  kristaps@  Sun, 02 Oct 2011 17:12:52 +0200
+
+- for system errors, use errno/strerror/warn/err
+
+************************************************************************
+* documentation issues
+************************************************************************
+
+- mention hyphenation rules:
+  breaking at letter-letter in text mode (not macro args)
+  proper hyphenation is unimplemented
+
+- talk about spacing around delimiters
+  to jmc@, kristaps@  Sat, 23 Apr 2011 17:41:27 +0200
+
+- mark macros as: page structure domain, manual domain, general text domain
+  is this useful?
+
+- mention /usr/share/misc/mdoc.template in mdoc(7)?
+
 ************************************************************************
 * performance issues
 ************************************************************************
 
+- Why are we using MAP_SHARED, not MAP_PRIVATE for mmap(2)?
+  How does SQLITE_CONFIG_PAGECACHE actually work?  Document it!
+  from kristaps@  Sat, 09 Aug 2014 13:51:36 +0200
+
 Several areas can be cleaned up to make mandoc even faster.  These are 
 
 - improve hashing mechanism for macros (quite important: performance)
@@ -328,3 +429,9 @@ Several areas can be cleaned up to make mandoc even faster.  These are
   Decide which formats should be recognized where.
   Update both mdoc(7) and man(7) documentation.
   Triggered by  Tim van der Molen  Tue, 22 Feb 2011 20:30:45 +0100
+
+- Consider creating some views that will make the database more
+  readable from the sqlite3 shell.  Consider using them to
+  abstract from the database structure, too.
+  suggested by espie@  Sat, 19 Apr 2014 14:52:57 +0200
+
index 5adfeb6..1468242 100644 (file)
@@ -1,6 +1,7 @@
-.\"    $Id: apropos.1,v 1.16.2.3 2013/10/05 01:25:20 schwarze Exp $
+.\"    $Id: apropos.1,v 1.29 2014/04/24 00:28:19 schwarze Exp $
 .\"
-.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@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
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: October 5 2013 $
+.Dd $Mdocdate: April 24 2014 $
 .Dt APROPOS 1
 .Os
 .Sh NAME
-.Nm apropos
+.Nm apropos ,
+.Nm whatis
 .Nd search manual page databases
 .Sh SYNOPSIS
 .Nm
 .Op Fl C Ar file
 .Op Fl M Ar path
 .Op Fl m Ar path
+.Op Fl O Ar outkey
 .Op Fl S Ar arch
 .Op Fl s Ar section
 .Ar expression ...
 .Sh DESCRIPTION
 The
-.Nm
-utility queries manual page databases generated by
-.Xr mandocdb 8 ,
-evaluating on
+.Nm apropos
+and
+.Nm whatis
+utilities query manual page databases generated by
+.Xr makewhatis 8 ,
+evaluating
 .Ar expression
 for each file in each database.
+By default, it displays the names, section numbers, and description lines
+of all matching manuals.
 .Pp
 By default,
 .Nm
 searches for
-.Xr mandocdb 8
+.Xr makewhatis 8
 databases in the default paths stipulated by
-.Xr man 1 ,
-parses terms as case-sensitive regular expressions
-.Pq the Li \&~ operator
+.Xr man 1
+and uses case-insensitive substring matching
+.Pq the Cm = No operator
 over manual names and descriptions
 .Pq the Li \&Nm No and Li \&Nd No macro keys .
 Multiple terms imply pairwise
 .Fl o .
+.Nm whatis
+maps terms only to case-sensitive manual names.
 .Pp
 Its arguments are as follows:
 .Bl -tag -width Ds
@@ -61,22 +70,32 @@ format.
 .It Fl M Ar path
 Use the colon-separated path instead of the default list of paths
 searched for
-.Xr mandocdb 8
+.Xr makewhatis 8
 databases.
 Invalid paths, or paths without manual databases, are ignored.
 .It Fl m Ar path
 Prepend the colon-separated paths to the list of paths searched
 for
-.Xr mandocdb 8
+.Xr makewhatis 8
 databases.
 Invalid paths, or paths without manual databases, are ignored.
+.It Fl O Ar outkey
+Show the values associated with the key
+.Ar outkey
+instead of the manual descriptions.
 .It Fl S Ar arch
-Search only for a particular architecture.
-.It Fl s Ar cat
-Search only for a manual section.
+Restrict the search to pages for the specified
+.Xr machine 1
+architecture.
+.Ar arch
+is case insensitive.
+By default, pages for all architectures are shown.
+.It Fl s Ar section
+Restrict the search to the specified section of the manual.
+By default, pages from all sections are shown.
 See
 .Xr man 1
-for a listing of manual sections.
+for a listing of sections.
 .El
 .Pp
 An
@@ -103,34 +122,40 @@ True if both
 and
 .Ar expr2
 are true (logical
-.Qq and ) .
+.Sq and ) .
 .It Ar expr1 Oo Fl o Oc Ar expr2
 True if
 .Ar expr1
 and/or
 .Ar expr2
 evaluate to true (logical
-.Qq or ) .
+.Sq or ) .
 .It Ar term
 True if
 .Ar term
 is satisfied.
 This has syntax
-.Li [key[,key]*(=~)]?val ,
-where operand
-.Cm key
+.Sm off
+.Oo
+.Op Ar key Op , Ar key ...
+.Pq Cm = | ~
+.Oc
+.Ar val ,
+.Sm on
+where
+.Ar key
 is an
 .Xr mdoc 7
 macro to query and
-.Cm val
+.Ar val
 is its value.
 See
 .Sx Macro Keys
 for a list of available keys.
 Operator
-.Li \&=
+.Cm =
 evaluates a substring, while
-.Li \&~
+.Cm ~
 evaluates a regular expression.
 .It Fl i Ar term
 If
@@ -140,34 +165,38 @@ is evaluated case-insensitively.
 Has no effect on substring terms.
 .El
 .Pp
-Results are sorted by manual title, with output formatted as
+.Nm whatis
+considers an
+.Ar expression
+to consist of an opaque keyword.
+.Pp
+Results are sorted by manual sections and names, with output formatted as
 .Pp
-.D1 title(sec) \- description
+.D1 name[, name...](sec) \- description
 .Pp
 Where
-.Qq title
-is the manual's title (note multiple manual names may exist for one
-title),
-.Qq sec
+.Dq name
+is the manual's name,
+.Dq sec
 is the manual section, and
-.Qq description
+.Dq description
 is the manual's short description.
 If an architecture is specified for the manual, it is displayed as
 .Pp
-.D1 title(cat/arch) \- description
+.D1 name(sec/arch) \- description
 .Pp
 Resulting manuals may be accessed as
 .Pp
-.Dl $ man \-s sec title
+.Dl $ man \-s sec name
 .Pp
 If an architecture is specified in the output, use
 .Pp
-.Dl $ man \-s sec \-S arch title
+.Dl $ man \-s sec \-S arch name
 .Ss Macro Keys
 Queries evaluate over a subset of
 .Xr mdoc 7
 macros indexed by
-.Xr mandocdb 8 .
+.Xr makewhatis 8 .
 In addition to the macro keys listed below, the special key
 .Cm any
 may be used to match any available macro key.
@@ -176,6 +205,8 @@ Names and description:
 .Bl -column "xLix" description -offset indent -compact
 .It Li \&Nm Ta manual name
 .It Li \&Nd Ta one-line manual description
+.It Li arch Ta machine architecture (case-insensitive)
+.It Li sec  Ta manual section number
 .El
 .Pp
 Sections and cross references:
@@ -239,35 +270,31 @@ Text production:
 .It Li \&Dx Ta Dx No version reference
 .El
 .Sh ENVIRONMENT
-.Bl -tag -width Ds
+.Bl -tag -width MANPATH
 .It Ev MANPATH
-Colon-separated paths modifying the default list of paths searched for
-manual databases.
+The standard search path used by
+.Xr man 1
+may be changed by specifying a path in the
+.Ev MANPATH
+environment variable.
 Invalid paths, or paths without manual databases, are ignored.
 Overridden by
 .Fl M .
 If
 .Ev MANPATH
-begins with a
-.Sq \&: ,
-it is appended to the default list;
-else if it ends with
-.Sq \&: ,
-it is prepended to the default list; else if it contains
-.Sq \&:: ,
-the default list is inserted between the colons.
-If none of these conditions are met, it overrides the default list.
+begins with a colon, it is appended to the default list;
+if it ends with a colon, it is prepended to the default list;
+or if it contains two adjacent colons,
+the standard search path is inserted between the colons.
+If none of these conditions are met, it overrides the
+standard search path.
 .El
 .Sh FILES
 .Bl -tag -width "/etc/man.conf" -compact
 .It Pa mandoc.db
 name of the
-.Xr mandocdb 8
+.Xr makewhatis 8
 keyword database
-.It Pa mandoc.index
-name of the
-.Xr mandocdb 8
-filename database
 .It Pa /etc/man.conf
 default
 .Xr man 1
@@ -277,35 +304,84 @@ configuration file
 .Ex -std
 .Sh EXAMPLES
 Search for
-.Qq mdoc
-as a substring and regular expression
-within each manual name and description:
+.Qq .cf
+as a substring of manual names and descriptions:
 .Pp
-.Dl $ apropos mdoc
-.Dl $ apropos ~^mdoc$
+.Dl $ apropos .cf
 .Pp
 Include matches for
-.Qq roff
+.Qq .cnf
 and
-.Qq man
-for the regular expression case:
+.Qq .conf
+as well:
 .Pp
-.Dl $ apropos ~^mdoc$ roff man
-.Dl $ apropos ~^mdoc$ \-o roff \-o man
+.Dl $ apropos .cf .cnf .conf
 .Pp
-Search for
+Search in names and descriptions using a regular expression:
+.Pp
+.Dl $ apropos '~set.?[ug]id'
+.Pp
+Search for manuals in the library section mentioning both the
 .Qq optind
-and
+and the
 .Qq optarg
-as variable names in the library category:
+variables:
 .Pp
-.Dl $ apropos \-s 3 Va~^optind \-a Va~^optarg$
+.Dl $ apropos \-s 3 Va=optind \-a Va=optarg
+.Pp
+Do exactly the same as calling
+.Xr whatis 1
+with the argument
+.Qq ssh :
+.Pp
+.Dl $ apropos \-\- \-i 'Nm~[[:<:]]ssh[[:>:]]'
+.Pp
+The following two invocations are equivalent:
+.Pp
+.D1 Li $ apropos -S Ar arch Li -s Ar section expression
+.Bd -ragged -offset indent
+.Li $ apropos \e( Ar expression Li \e)
+.Li -a arch~^( Ns Ar arch Ns Li |any)$
+.Li -a sec~^ Ns Ar section Ns Li $
+.Ed
 .Sh SEE ALSO
 .Xr man 1 ,
 .Xr re_format 7 ,
-.Xr mandocdb 8
-.Sh AUTHORS
+.Xr makewhatis 8
+.Sh HISTORY
+An
+.Nm
+utility first appeared in
+.Bx 2 .
+It was rewritten from scratch for
+.Ox 5.6 .
+.Pp
 The
+.Fl M
+option and the
+.Ev MANPATH
+variable first appeared in
+.Bx 4.3 ;
+.Fl m
+in
+.Bx 4.3 Reno ;
+.Fl C
+in
+.Bx 4.4 Lite1 ;
+and
+.Fl S
+and
+.Fl s
+in
+.Ox 4.5 .
+.Sh AUTHORS
+.An -nosplit
+.An Bill Joy
+wrote the original
+.Bx
 .Nm
-utility was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
+in February 1979.
+The current version was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
index f5d1425..80b6bc6 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: apropos.c,v 1.27.2.1 2013/09/17 23:23:10 schwarze Exp $ */
+/*     $Id: apropos.c,v 1.39 2014/04/20 16:46:04 schwarze Exp $ */
 /*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@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
 
 #include <assert.h>
 #include <getopt.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
-#include "apropos_db.h"
-#include "mandoc.h"
 #include "manpath.h"
+#include "mansearch.h"
 
-static int      cmp(const void *, const void *);
-static void     list(struct res *, size_t, void *);
-
-static char    *progname;
 
 int
 main(int argc, char *argv[])
 {
-       int              ch, rc, whatis;
-       struct res      *res;
+       int              ch, whatis;
+       struct mansearch search;
+       size_t           i, sz;
+       struct manpage  *res;
        struct manpaths  paths;
-       size_t           terms, ressz;
-       struct opts      opts;
-       struct expr     *e;
        char            *defpaths, *auxpaths;
        char            *conf_file;
+       char            *progname;
+       const char      *outkey;
        extern char     *optarg;
        extern int       optind;
 
@@ -58,30 +56,31 @@ main(int argc, char *argv[])
        whatis = (0 == strncmp(progname, "whatis", 6));
 
        memset(&paths, 0, sizeof(struct manpaths));
-       memset(&opts, 0, sizeof(struct opts));
+       memset(&search, 0, sizeof(struct mansearch));
 
-       ressz = 0;
-       res = NULL;
        auxpaths = defpaths = NULL;
        conf_file = NULL;
-       e = NULL;
+       outkey = "Nd";
 
-       while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
+       while (-1 != (ch = getopt(argc, argv, "C:M:m:O:S:s:")))
                switch (ch) {
-               case ('C'):
+               case 'C':
                        conf_file = optarg;
                        break;
-               case ('M'):
+               case 'M':
                        defpaths = optarg;
                        break;
-               case ('m'):
+               case 'm':
                        auxpaths = optarg;
                        break;
-               case ('S'):
-                       opts.arch = optarg;
+               case 'O':
+                       outkey = optarg;
+                       break;
+               case 'S':
+                       search.arch = optarg;
                        break;
-               case ('s'):
-                       opts.cat = optarg;
+               case 's':
+                       search.sec = optarg;
                        break;
                default:
                        goto usage;
@@ -93,64 +92,32 @@ main(int argc, char *argv[])
        if (0 == argc)
                goto usage;
 
-       rc = 0;
+       search.deftype = whatis ? TYPE_Nm : TYPE_Nm | TYPE_Nd;
+       search.flags = whatis ? MANSEARCH_WHATIS : 0;
 
        manpath_parse(&paths, conf_file, defpaths, auxpaths);
+       mansearch_setup(1);
+       ch = mansearch(&search, &paths, argc, argv, outkey, &res, &sz);
+       manpath_free(&paths);
 
-       e = whatis ? termcomp(argc, argv, &terms) :
-                    exprcomp(argc, argv, &terms);
-               
-       if (NULL == e) {
-               fprintf(stderr, "%s: Bad expression\n", progname);
-               goto out;
-       }
-
-       rc = apropos_search
-               (paths.sz, paths.paths, &opts, 
-                e, terms, NULL, &ressz, &res, list);
+       if (0 == ch)
+               goto usage;
 
-       if (0 == rc) {
-               fprintf(stderr, "%s: Bad database\n", progname);
-               goto out;
+       for (i = 0; i < sz; i++) {
+               printf("%s - %s\n", res[i].names,
+                   NULL == res[i].output ? "" : res[i].output);
+               free(res[i].file);
+               free(res[i].names);
+               free(res[i].output);
        }
 
-out:
-       manpath_free(&paths);
-       resfree(res, ressz);
-       exprfree(e);
-       return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
-
+       free(res);
+       mansearch_setup(0);
+       return(sz ? EXIT_SUCCESS : EXIT_FAILURE);
 usage:
        fprintf(stderr, "usage: %s [-C file] [-M path] [-m path] "
+                       "[-O outkey] "
                        "[-S arch] [-s section]%s ...\n", progname,
                        whatis ? " name" : "\n               expression");
        return(EXIT_FAILURE);
 }
-
-/* ARGSUSED */
-static void
-list(struct res *res, size_t sz, void *arg)
-{
-       size_t           i;
-
-       qsort(res, sz, sizeof(struct res), cmp);
-
-       for (i = 0; i < sz; i++) {
-               if ( ! res[i].matched)
-                       continue;
-               printf("%s(%s%s%s) - %.70s\n",
-                               res[i].title,
-                               res[i].cat,
-                               *res[i].arch ? "/" : "",
-                               *res[i].arch ? res[i].arch : "",
-                               res[i].desc);
-       }
-}
-
-static int
-cmp(const void *p1, const void *p2)
-{
-
-       return(strcasecmp(((const struct res *)p1)->title,
-                               ((const struct res *)p2)->title));
-}
diff --git a/contrib/mdocml/apropos_db.c b/contrib/mdocml/apropos_db.c
deleted file mode 100644 (file)
index 786fc7b..0000000
+++ /dev/null
@@ -1,884 +0,0 @@
-/*     $Id: apropos_db.c,v 1.32.2.3 2013/10/10 23:43:04 schwarze Exp $ */
-/*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@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.
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/param.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <regex.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#if defined(__APPLE__)
-# include <libkern/OSByteOrder.h>
-#elif defined(__linux__)
-# include <endian.h>
-#elif defined(__sun)
-# include <sys/byteorder.h>
-#else
-# include <sys/endian.h>
-#endif
-
-#if defined(__linux__) || defined(__sun)
-# include <db_185.h>
-#else
-# include <db.h>
-#endif
-
-#include "mandocdb.h"
-#include "apropos_db.h"
-#include "mandoc.h"
-
-#define        RESFREE(_x) \
-       do { \
-               free((_x)->file); \
-               free((_x)->cat); \
-               free((_x)->title); \
-               free((_x)->arch); \
-               free((_x)->desc); \
-               free((_x)->matches); \
-       } while (/*CONSTCOND*/0)
-
-struct expr {
-       int              regex; /* is regex? */
-       int              index; /* index in match array */
-       uint64_t         mask; /* type-mask */
-       int              and; /* is rhs of logical AND? */
-       char            *v; /* search value */
-       regex_t          re; /* compiled re, if regex */
-       struct expr     *next; /* next in sequence */
-       struct expr     *subexpr;
-};
-
-struct type {
-       uint64_t         mask;
-       const char      *name;
-};
-
-struct rectree {
-       struct res      *node; /* record array for dir tree */
-       int              len; /* length of record array */
-};
-
-static const struct type types[] = {
-       { TYPE_An, "An" },
-       { TYPE_Ar, "Ar" },
-       { TYPE_At, "At" },
-       { TYPE_Bsx, "Bsx" },
-       { TYPE_Bx, "Bx" },
-       { TYPE_Cd, "Cd" },
-       { TYPE_Cm, "Cm" },
-       { TYPE_Dv, "Dv" },
-       { TYPE_Dx, "Dx" },
-       { TYPE_Em, "Em" },
-       { TYPE_Er, "Er" },
-       { TYPE_Ev, "Ev" },
-       { TYPE_Fa, "Fa" },
-       { TYPE_Fl, "Fl" },
-       { TYPE_Fn, "Fn" },
-       { TYPE_Fn, "Fo" },
-       { TYPE_Ft, "Ft" },
-       { TYPE_Fx, "Fx" },
-       { TYPE_Ic, "Ic" },
-       { TYPE_In, "In" },
-       { TYPE_Lb, "Lb" },
-       { TYPE_Li, "Li" },
-       { TYPE_Lk, "Lk" },
-       { TYPE_Ms, "Ms" },
-       { TYPE_Mt, "Mt" },
-       { TYPE_Nd, "Nd" },
-       { TYPE_Nm, "Nm" },
-       { TYPE_Nx, "Nx" },
-       { TYPE_Ox, "Ox" },
-       { TYPE_Pa, "Pa" },
-       { TYPE_Rs, "Rs" },
-       { TYPE_Sh, "Sh" },
-       { TYPE_Ss, "Ss" },
-       { TYPE_St, "St" },
-       { TYPE_Sy, "Sy" },
-       { TYPE_Tn, "Tn" },
-       { TYPE_Va, "Va" },
-       { TYPE_Va, "Vt" },
-       { TYPE_Xr, "Xr" },
-       { UINT64_MAX, "any" },
-       { 0, NULL }
-};
-
-static DB      *btree_open(void);
-static int      btree_read(const DBT *, const DBT *,
-                       const struct mchars *,
-                       uint64_t *, recno_t *, char **);
-static int      expreval(const struct expr *, int *);
-static void     exprexec(const struct expr *,
-                       const char *, uint64_t, struct res *);
-static int      exprmark(const struct expr *,
-                       const char *, uint64_t, int *);
-static struct expr *exprexpr(int, char *[], int *, int *, size_t *);
-static struct expr *exprterm(char *, int);
-static DB      *index_open(void);
-static int      index_read(const DBT *, const DBT *, int,
-                       const struct mchars *, struct res *);
-static void     norm_string(const char *,
-                       const struct mchars *, char **);
-static size_t   norm_utf8(unsigned int, char[7]);
-static int      single_search(struct rectree *, const struct opts *,
-                       const struct expr *, size_t terms,
-                       struct mchars *, int);
-
-/*
- * Open the keyword mandoc-db database.
- */
-static DB *
-btree_open(void)
-{
-       BTREEINFO        info;
-       DB              *db;
-
-       memset(&info, 0, sizeof(BTREEINFO));
-       info.lorder = 4321;
-       info.flags = R_DUP;
-
-       db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info);
-       if (NULL != db)
-               return(db);
-
-       return(NULL);
-}
-
-/*
- * Read a keyword from the database and normalise it.
- * Return 0 if the database is insane, else 1.
- */
-static int
-btree_read(const DBT *k, const DBT *v, const struct mchars *mc,
-               uint64_t *mask, recno_t *rec, char **buf)
-{
-       uint64_t         vbuf[2];
-
-       /* Are our sizes sane? */
-       if (k->size < 2 || sizeof(vbuf) != v->size)
-               return(0);
-
-       /* Is our string nil-terminated? */
-       if ('\0' != ((const char *)k->data)[(int)k->size - 1])
-               return(0);
-
-       norm_string((const char *)k->data, mc, buf);
-       memcpy(vbuf, v->data, v->size);
-       *mask = betoh64(vbuf[0]);
-       *rec  = betoh64(vbuf[1]);
-       return(1);
-}
-
-/*
- * Take a Unicode codepoint and produce its UTF-8 encoding.
- * This isn't the best way to do this, but it works.
- * The magic numbers are from the UTF-8 packaging.
- * They're not as scary as they seem: read the UTF-8 spec for details.
- */
-static size_t
-norm_utf8(unsigned int cp, char out[7])
-{
-       int              rc;
-
-       rc = 0;
-
-       if (cp <= 0x0000007F) {
-               rc = 1;
-               out[0] = (char)cp;
-       } else if (cp <= 0x000007FF) {
-               rc = 2;
-               out[0] = (cp >> 6  & 31) | 192;
-               out[1] = (cp       & 63) | 128;
-       } else if (cp <= 0x0000FFFF) {
-               rc = 3;
-               out[0] = (cp >> 12 & 15) | 224;
-               out[1] = (cp >> 6  & 63) | 128;
-               out[2] = (cp       & 63) | 128;
-       } else if (cp <= 0x001FFFFF) {
-               rc = 4;
-               out[0] = (cp >> 18 & 7) | 240;
-               out[1] = (cp >> 12 & 63) | 128;
-               out[2] = (cp >> 6  & 63) | 128;
-               out[3] = (cp       & 63) | 128;
-       } else if (cp <= 0x03FFFFFF) {
-               rc = 5;
-               out[0] = (cp >> 24 & 3) | 248;
-               out[1] = (cp >> 18 & 63) | 128;
-               out[2] = (cp >> 12 & 63) | 128;
-               out[3] = (cp >> 6  & 63) | 128;
-               out[4] = (cp       & 63) | 128;
-       } else if (cp <= 0x7FFFFFFF) {
-               rc = 6;
-               out[0] = (cp >> 30 & 1) | 252;
-               out[1] = (cp >> 24 & 63) | 128;
-               out[2] = (cp >> 18 & 63) | 128;
-               out[3] = (cp >> 12 & 63) | 128;
-               out[4] = (cp >> 6  & 63) | 128;
-               out[5] = (cp       & 63) | 128;
-       } else
-               return(0);
-
-       out[rc] = '\0';
-       return((size_t)rc);
-}
-
-/*
- * Normalise strings from the index and database.
- * These strings are escaped as defined by mandoc_char(7) along with
- * other goop in mandoc.h (e.g., soft hyphens).
- * This function normalises these into a nice UTF-8 string.
- * Returns 0 if the database is fucked.
- */
-static void
-norm_string(const char *val, const struct mchars *mc, char **buf)
-{
-       size_t            sz, bsz;
-       char              utfbuf[7];
-       const char       *seq, *cpp;
-       int               len, u, pos;
-       enum mandoc_esc   esc;
-       static const char res[] = { '\\', '\t',
-                               ASCII_NBRSP, ASCII_HYPH, '\0' };
-
-       /* Pre-allocate by the length of the input */
-
-       bsz = strlen(val) + 1;
-       *buf = mandoc_realloc(*buf, bsz);
-       pos = 0;
-
-       while ('\0' != *val) {
-               /*
-                * Halt on the first escape sequence.
-                * This also halts on the end of string, in which case
-                * we just copy, fallthrough, and exit the loop.
-                */
-               if ((sz = strcspn(val, res)) > 0) {
-                       memcpy(&(*buf)[pos], val, sz);
-                       pos += (int)sz;
-                       val += (int)sz;
-               }
-
-               if (ASCII_HYPH == *val) {
-                       (*buf)[pos++] = '-';
-                       val++;
-                       continue;
-               } else if ('\t' == *val || ASCII_NBRSP == *val) {
-                       (*buf)[pos++] = ' ';
-                       val++;
-                       continue;
-               } else if ('\\' != *val)
-                       break;
-
-               /* Read past the slash. */
-
-               val++;
-               u = 0;
-
-               /*
-                * Parse the escape sequence and see if it's a
-                * predefined character or special character.
-                */
-
-               esc = mandoc_escape(&val, &seq, &len);
-               if (ESCAPE_ERROR == esc)
-                       break;
-
-               /*
-                * XXX - this just does UTF-8, but we need to know
-                * beforehand whether we should do text substitution.
-                */
-
-               switch (esc) {
-               case (ESCAPE_SPECIAL):
-                       if (0 != (u = mchars_spec2cp(mc, seq, len)))
-                               break;
-                       /* FALLTHROUGH */
-               default:
-                       continue;
-               }
-
-               /*
-                * If we have a Unicode codepoint, try to convert that
-                * to a UTF-8 byte string.
-                */
-
-               cpp = utfbuf;
-               if (0 == (sz = norm_utf8(u, utfbuf)))
-                       continue;
-
-               /* Copy the rendered glyph into the stream. */
-
-               sz = strlen(cpp);
-               bsz += sz;
-
-               *buf = mandoc_realloc(*buf, bsz);
-
-               memcpy(&(*buf)[pos], cpp, sz);
-               pos += (int)sz;
-       }
-
-       (*buf)[pos] = '\0';
-}
-
-/*
- * Open the filename-index mandoc-db database.
- * Returns NULL if opening failed.
- */
-static DB *
-index_open(void)
-{
-       DB              *db;
-
-       db = dbopen(MANDOC_IDX, O_RDONLY, 0, DB_RECNO, NULL);
-       if (NULL != db)
-               return(db);
-
-       return(NULL);
-}
-
-/*
- * Safely unpack from an index file record into the structure.
- * Returns 1 if an entry was unpacked, 0 if the database is insane.
- */
-static int
-index_read(const DBT *key, const DBT *val, int index,
-               const struct mchars *mc, struct res *rec)
-{
-       size_t           left;
-       char            *np, *cp;
-       char             type;
-
-#define        INDEX_BREAD(_dst) \
-       do { \
-               if (NULL == (np = memchr(cp, '\0', left))) \
-                       return(0); \
-               norm_string(cp, mc, &(_dst)); \
-               left -= (np - cp) + 1; \
-               cp = np + 1; \
-       } while (/* CONSTCOND */ 0)
-
-       if (0 == (left = val->size))
-               return(0);
-
-       cp = val->data;
-       assert(sizeof(recno_t) == key->size);
-       memcpy(&rec->rec, key->data, key->size);
-       rec->volume = index;
-
-       if ('d' == (type = *cp++))
-               rec->type = RESTYPE_MDOC;
-       else if ('a' == type)
-               rec->type = RESTYPE_MAN;
-       else if ('c' == type)
-               rec->type = RESTYPE_CAT;
-       else
-               return(0);
-
-       left--;
-       INDEX_BREAD(rec->file);
-       INDEX_BREAD(rec->cat);
-       INDEX_BREAD(rec->title);
-       INDEX_BREAD(rec->arch);
-       INDEX_BREAD(rec->desc);
-       return(1);
-}
-
-/*
- * Search mandocdb databases in paths for expression "expr".
- * Filter out by "opts".
- * Call "res" with the results, which may be zero.
- * Return 0 if there was a database error, else return 1.
- */
-int
-apropos_search(int pathsz, char **paths, const struct opts *opts,
-               const struct expr *expr, size_t terms, void *arg,
-               size_t *sz, struct res **resp,
-               void (*res)(struct res *, size_t, void *))
-{
-       struct rectree   tree;
-       struct mchars   *mc;
-       int              i;
-
-       memset(&tree, 0, sizeof(struct rectree));
-
-       mc = mchars_alloc();
-       *sz = 0;
-       *resp = NULL;
-
-       /*
-        * Main loop.  Change into the directory containing manpage
-        * databases.  Run our expession over each database in the set.
-        */
-
-       for (i = 0; i < pathsz; i++) {
-               assert('/' == paths[i][0]);
-               if (chdir(paths[i]))
-                       continue;
-               if (single_search(&tree, opts, expr, terms, mc, i))
-                       continue;
-
-               resfree(tree.node, tree.len);
-               mchars_free(mc);
-               return(0);
-       }
-
-       (*res)(tree.node, tree.len, arg);
-       *sz = tree.len;
-       *resp = tree.node;
-       mchars_free(mc);
-       return(1);
-}
-
-static int
-single_search(struct rectree *tree, const struct opts *opts,
-               const struct expr *expr, size_t terms,
-               struct mchars *mc, int vol)
-{
-       int              root, leaf, ch;
-       DBT              key, val;
-       DB              *btree, *idx;
-       char            *buf;
-       struct res      *rs;
-       struct res       r;
-       uint64_t         mask;
-       recno_t          rec;
-
-       root    = -1;
-       leaf    = -1;
-       btree   = NULL;
-       idx     = NULL;
-       buf     = NULL;
-       rs      = tree->node;
-
-       memset(&r, 0, sizeof(struct res));
-
-       if (NULL == (btree = btree_open()))
-               return(1);
-
-       if (NULL == (idx = index_open())) {
-               (*btree->close)(btree);
-               return(1);
-       }
-
-       while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
-               if ( ! btree_read(&key, &val, mc, &mask, &rec, &buf))
-                       break;
-
-               /*
-                * See if this keyword record matches any of the
-                * expressions we have stored.
-                */
-               if ( ! exprmark(expr, buf, mask, NULL))
-                       continue;
-
-               /*
-                * O(log n) scan for prior records.  Since a record
-                * number is unbounded, this has decent performance over
-                * a complex hash function.
-                */
-
-               for (leaf = root; leaf >= 0; )
-                       if (rec > rs[leaf].rec &&
-                                       rs[leaf].rhs >= 0)
-                               leaf = rs[leaf].rhs;
-                       else if (rec < rs[leaf].rec &&
-                                       rs[leaf].lhs >= 0)
-                               leaf = rs[leaf].lhs;
-                       else
-                               break;
-
-               /*
-                * If we find a record, see if it has already evaluated
-                * to true.  If it has, great, just keep going.  If not,
-                * try to evaluate it now and continue anyway.
-                */
-
-               if (leaf >= 0 && rs[leaf].rec == rec) {
-                       if (0 == rs[leaf].matched)
-                               exprexec(expr, buf, mask, &rs[leaf]);
-                       continue;
-               }
-
-               /*
-                * We have a new file to examine.
-                * Extract the manpage's metadata from the index
-                * database, then begin partial evaluation.
-                */
-
-               key.data = &rec;
-               key.size = sizeof(recno_t);
-
-               if (0 != (*idx->get)(idx, &key, &val, 0))
-                       break;
-
-               r.lhs = r.rhs = -1;
-               if ( ! index_read(&key, &val, vol, mc, &r))
-                       break;
-
-               /* XXX: this should be elsewhere, I guess? */
-
-               if (opts->cat && strcasecmp(opts->cat, r.cat))
-                       continue;
-
-               if (opts->arch && *r.arch)
-                       if (strcasecmp(opts->arch, r.arch))
-                               continue;
-
-               tree->node = rs = mandoc_realloc
-                       (rs, (tree->len + 1) * sizeof(struct res));
-
-               memcpy(&rs[tree->len], &r, sizeof(struct res));
-               memset(&r, 0, sizeof(struct res));
-               rs[tree->len].matches =
-                       mandoc_calloc(terms, sizeof(int));
-
-               exprexec(expr, buf, mask, &rs[tree->len]);
-
-               /* Append to our tree. */
-
-               if (leaf >= 0) {
-                       if (rec > rs[leaf].rec)
-                               rs[leaf].rhs = tree->len;
-                       else
-                               rs[leaf].lhs = tree->len;
-               } else
-                       root = tree->len;
-
-               tree->len++;
-       }
-
-       (*btree->close)(btree);
-       (*idx->close)(idx);
-
-       free(buf);
-       RESFREE(&r);
-       return(1 == ch);
-}
-
-void
-resfree(struct res *rec, size_t sz)
-{
-       size_t           i;
-
-       for (i = 0; i < sz; i++)
-               RESFREE(&rec[i]);
-       free(rec);
-}
-
-/*
- * Compile a list of straight-up terms.
- * The arguments are re-written into ~[[:<:]]term[[:>:]], or "term"
- * surrounded by word boundaries, then pumped through exprterm().
- * Terms are case-insensitive.
- * This emulates whatis(1) behaviour.
- */
-struct expr *
-termcomp(int argc, char *argv[], size_t *tt)
-{
-       char            *buf;
-       int              pos;
-       struct expr     *e, *next;
-       size_t           sz;
-
-       buf = NULL;
-       e = NULL;
-       *tt = 0;
-
-       for (pos = argc - 1; pos >= 0; pos--) {
-               sz = strlen(argv[pos]) + 18;
-               buf = mandoc_realloc(buf, sz);
-               strlcpy(buf, "Nm~[[:<:]]", sz);
-               strlcat(buf, argv[pos], sz);
-               strlcat(buf, "[[:>:]]", sz);
-               if (NULL == (next = exprterm(buf, 0))) {
-                       free(buf);
-                       exprfree(e);
-                       return(NULL);
-               }
-               next->next = e;
-               e = next;
-               (*tt)++;
-       }
-
-       free(buf);
-       return(e);
-}
-
-/*
- * Compile a sequence of logical expressions.
- * See apropos.1 for a grammar of this sequence.
- */
-struct expr *
-exprcomp(int argc, char *argv[], size_t *tt)
-{
-       int              pos, lvl;
-       struct expr     *e;
-
-       pos = lvl = 0;
-       *tt = 0;
-
-       e = exprexpr(argc, argv, &pos, &lvl, tt);
-
-       if (0 == lvl && pos >= argc)
-               return(e);
-
-       exprfree(e);
-       return(NULL);
-}
-
-/*
- * Compile an array of tokens into an expression.
- * An informal expression grammar is defined in apropos(1).
- * Return NULL if we fail doing so.  All memory will be cleaned up.
- * Return the root of the expression sequence if alright.
- */
-static struct expr *
-exprexpr(int argc, char *argv[], int *pos, int *lvl, size_t *tt)
-{
-       struct expr     *e, *first, *next;
-       int              log;
-
-       first = next = NULL;
-
-       for ( ; *pos < argc; (*pos)++) {
-               e = next;
-
-               /*
-                * Close out a subexpression.
-                */
-
-               if (NULL != e && 0 == strcmp(")", argv[*pos])) {
-                       if (--(*lvl) < 0)
-                               goto err;
-                       break;
-               }
-
-               /*
-                * Small note: if we're just starting, don't let "-a"
-                * and "-o" be considered logical operators: they're
-                * just tokens unless pairwise joining, in which case we
-                * record their existence (or assume "OR").
-                */
-               log = 0;
-
-               if (NULL != e && 0 == strcmp("-a", argv[*pos]))
-                       log = 1;
-               else if (NULL != e && 0 == strcmp("-o", argv[*pos]))
-                       log = 2;
-
-               if (log > 0 && ++(*pos) >= argc)
-                       goto err;
-
-               /*
-                * Now we parse the term part.  This can begin with
-                * "-i", in which case the expression is case
-                * insensitive.
-                */
-
-               if (0 == strcmp("(", argv[*pos])) {
-                       ++(*pos);
-                       ++(*lvl);
-                       next = mandoc_calloc(1, sizeof(struct expr));
-                       next->subexpr = exprexpr(argc, argv, pos, lvl, tt);
-                       if (NULL == next->subexpr) {
-                               free(next);
-                               next = NULL;
-                       }
-               } else if (0 == strcmp("-i", argv[*pos])) {
-                       if (++(*pos) >= argc)
-                               goto err;
-                       next = exprterm(argv[*pos], 0);
-               } else
-                       next = exprterm(argv[*pos], 1);
-
-               if (NULL == next)
-                       goto err;
-
-               next->and = log == 1;
-               next->index = (int)(*tt)++;
-
-               /* Append to our chain of expressions. */
-
-               if (NULL == first) {
-                       assert(NULL == e);
-                       first = next;
-               } else {
-                       assert(NULL != e);
-                       e->next = next;
-               }
-       }
-
-       return(first);
-err:
-       exprfree(first);
-       return(NULL);
-}
-
-/*
- * Parse a terminal expression with the grammar as defined in
- * apropos(1).
- * Return NULL if we fail the parse.
- */
-static struct expr *
-exprterm(char *buf, int cs)
-{
-       struct expr      e;
-       struct expr     *p;
-       char            *key;
-       int              i;
-
-       memset(&e, 0, sizeof(struct expr));
-
-       /* Choose regex or substring match. */
-
-       if (NULL == (e.v = strpbrk(buf, "=~"))) {
-               e.regex = 0;
-               e.v = buf;
-       } else {
-               e.regex = '~' == *e.v;
-               *e.v++ = '\0';
-       }
-
-       /* Determine the record types to search for. */
-
-       e.mask = 0;
-       if (buf < e.v) {
-               while (NULL != (key = strsep(&buf, ","))) {
-                       i = 0;
-                       while (types[i].mask &&
-                                       strcmp(types[i].name, key))
-                               i++;
-                       e.mask |= types[i].mask;
-               }
-       }
-       if (0 == e.mask)
-               e.mask = TYPE_Nm | TYPE_Nd;
-
-       if (e.regex) {
-               i = REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE);
-               if (regcomp(&e.re, e.v, i))
-                       return(NULL);
-       }
-
-       e.v = mandoc_strdup(e.v);
-
-       p = mandoc_calloc(1, sizeof(struct expr));
-       memcpy(p, &e, sizeof(struct expr));
-       return(p);
-}
-
-void
-exprfree(struct expr *p)
-{
-       struct expr     *pp;
-
-       while (NULL != p) {
-               if (p->subexpr)
-                       exprfree(p->subexpr);
-               if (p->regex)
-                       regfree(&p->re);
-               free(p->v);
-               pp = p->next;
-               free(p);
-               p = pp;
-       }
-}
-
-static int
-exprmark(const struct expr *p, const char *cp,
-               uint64_t mask, int *ms)
-{
-
-       for ( ; p; p = p->next) {
-               if (p->subexpr) {
-                       if (exprmark(p->subexpr, cp, mask, ms))
-                               return(1);
-                       continue;
-               } else if ( ! (mask & p->mask))
-                       continue;
-
-               if (p->regex) {
-                       if (regexec(&p->re, cp, 0, NULL, 0))
-                               continue;
-               } else if (NULL == strcasestr(cp, p->v))
-                       continue;
-
-               if (NULL == ms)
-                       return(1);
-               else
-                       ms[p->index] = 1;
-       }
-
-       return(0);
-}
-
-static int
-expreval(const struct expr *p, int *ms)
-{
-       int              match;
-
-       /*
-        * AND has precedence over OR.  Analysis is left-right, though
-        * it doesn't matter because there are no side-effects.
-        * Thus, step through pairwise ANDs and accumulate their Boolean
-        * evaluation.  If we encounter a single true AND collection or
-        * standalone term, the whole expression is true (by definition
-        * of OR).
-        */
-
-       for (match = 0; p && ! match; p = p->next) {
-               /* Evaluate a subexpression, if applicable. */
-               if (p->subexpr && ! ms[p->index])
-                       ms[p->index] = expreval(p->subexpr, ms);
-
-               match = ms[p->index];
-               for ( ; p->next && p->next->and; p = p->next) {
-                       /* Evaluate a subexpression, if applicable. */
-                       if (p->next->subexpr && ! ms[p->next->index])
-                               ms[p->next->index] =
-                                       expreval(p->next->subexpr, ms);
-                       match = match && ms[p->next->index];
-               }
-       }
-
-       return(match);
-}
-
-/*
- * First, update the array of terms for which this expression evaluates
- * to true.
- * Second, logically evaluate all terms over the updated array of truth
- * values.
- * If this evaluates to true, mark the expression as satisfied.
- */
-static void
-exprexec(const struct expr *e, const char *cp,
-               uint64_t mask, struct res *r)
-{
-
-       assert(0 == r->matched);
-       exprmark(e, cp, mask, r->matches);
-       r->matched = expreval(e, r->matches);
-}
diff --git a/contrib/mdocml/apropos_db.h b/contrib/mdocml/apropos_db.h
deleted file mode 100644 (file)
index 72d4c20..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*     $Id: apropos_db.h,v 1.13 2012/03/24 01:46:25 kristaps Exp $ */
-/*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * 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 APROPOS_H
-#define APROPOS_H
-
-enum   restype {
-       RESTYPE_MAN, /* man(7) file */
-       RESTYPE_MDOC, /* mdoc(7) file */
-       RESTYPE_CAT /* pre-formatted file */
-};
-
-struct res {
-       enum restype     type; /* input file type */
-       char            *file; /* file in file-system */
-       char            *cat; /* category (3p, 3, etc.) */
-       char            *title; /* title (FOO, etc.) */
-       char            *arch; /* arch (or empty string) */
-       char            *desc; /* description (from Nd) */
-       unsigned int     rec; /* record in index */
-       /*
-        * The index volume.  This indexes into the array of directories
-        * searched for manual page databases.
-        */
-       unsigned int     volume;
-       /*
-        * The following fields are used internally.
-        *
-        * Maintain a binary tree for checking the uniqueness of `rec'
-        * when adding elements to the results array.
-        * Since the results array is dynamic, use offset in the array
-        * instead of a pointer to the structure.
-        */
-       int              lhs;
-       int              rhs;
-       int              matched; /* expression is true */
-       int             *matches; /* partial truth evaluations */
-};
-
-struct opts {
-       const char      *arch; /* restrict to architecture */
-       const char      *cat; /* restrict to manual section */
-};
-
-__BEGIN_DECLS
-
-struct expr;
-
-int             apropos_search(int, char **, const struct opts *,
-                       const struct expr *, size_t, 
-                       void *, size_t *, struct res **,
-                       void (*)(struct res *, size_t, void *));
-struct expr    *exprcomp(int, char *[], size_t *);
-void            exprfree(struct expr *);
-void            resfree(struct res *, size_t);
-struct expr    *termcomp(int, char *[], size_t *);
-
-__END_DECLS
-
-#endif /*!APROPOS_H*/
index e764bfe..3e746d8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: arch.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/*     $Id: arch.c,v 1.11 2014/04/20 16:46:04 schwarze Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
  *
 #include "config.h"
 #endif
 
-#include <stdlib.h>
 #include <string.h>
-#include <time.h>
 
 #include "mdoc.h"
-#include "mandoc.h"
 #include "libmdoc.h"
 
 #define LINE(x, y) \
        if (0 == strcmp(p, x)) return(y);
 
+
 const char *
 mdoc_a2arch(const char *p)
 {
 
-#include "arch.in" 
+#include "arch.in"
 
        return(NULL);
 }
index d0c445f..a22ffd5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: arch.in,v 1.14 2013/09/16 22:12:57 schwarze Exp $ */
+/*     $Id: arch.in,v 1.15 2014/04/27 22:42:15 schwarze Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -65,8 +65,8 @@ LINE("ibmnws",                "IBMNWS")
 LINE("iyonix",         "Iyonix")
 LINE("landisk",                "LANDISK")
 LINE("loongson",       "Loongson")
-LINE("luna68k",                "Luna68k")
-LINE("luna88k",                "Luna88k")
+LINE("luna68k",                "LUNA68K")
+LINE("luna88k",                "LUNA88K")
 LINE("m68k",           "m68k")
 LINE("mac68k",         "Mac68k")
 LINE("macppc",         "MacPPC")
index 24d757d..059639a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: att.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/*     $Id: att.c,v 1.11 2014/04/20 16:46:04 schwarze Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
  *
 #include "config.h"
 #endif
 
-#include <stdlib.h>
 #include <string.h>
-#include <time.h>
 
 #include "mdoc.h"
-#include "mandoc.h"
 #include "libmdoc.h"
 
 #define LINE(x, y) \
        if (0 == strcmp(p, x)) return(y);
 
+
 const char *
 mdoc_a2att(const char *p)
 {
 
-#include "att.in" 
+#include "att.in"
 
        return(NULL);
 }
diff --git a/contrib/mdocml/catman.8 b/contrib/mdocml/catman.8
deleted file mode 100644 (file)
index f5246f9..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-.\"    $Id: catman.8,v 1.5 2011/12/25 19:35:44 kristaps Exp $
-.\"
-.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\"
-.\" 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: December 25 2011 $
-.Dt CATMAN 8
-.Os
-.Sh NAME
-.Nm catman
-.Nd update a man.cgi manpage cache
-.Sh SYNOPSIS
-.Nm catman
-.Op Fl fv
-.Op Fl C Ar file
-.Op Fl M Ar manpath
-.Op Fl m Ar manpath
-.Op Fl o Ar path
-.Sh DESCRIPTION
-The
-.Nm
-utility updates cached manpages for a jailed
-.Xr man.cgi 7 .
-.Pp
-By default,
-.Nm
-searches for
-.Xr mandocdb 8
-databases in the default paths stipulated by
-.Xr man 1
-and updates the cache in
-.Pa /var/www/cache/man.cgi .
-.Pp
-Its arguments are as follows:
-.Bl -tag -width Ds
-.It Fl f
-Force an update to all files.
-.It Fl v
-Print each file being updated.
-.It Fl C Ar file
-Specify an alternative configuration
-.Ar file
-in
-.Xr man.conf 5
-format.
-.It Fl M Ar manpath
-Use the colon-separated path instead of the default list of paths
-searched for
-.Xr mandocdb 8
-databases.
-Invalid paths, or paths without manual databases, are ignored.
-.It Fl m Ar manpath
-Prepend the colon-separated paths to the list of paths searched
-for
-.Xr mandocdb 8
-databases.
-Invalid paths, or paths without manual databases, are ignored.
-.It Fl o Ar path
-Update into the directory tree under
-.Ar path .
-.El
-.Pp
-Cache updates occur when a
-.Xr mandocdb 8
-database is older than the cached copy unless
-.Fl f
-is specified, in which case files are always considered out of date.
-Cached manual pages are only updated if older than the master copy.
-.Sh ENVIRONMENT
-.Bl -tag -width Ds
-.It Ev MANPATH
-Colon-separated paths modifying the default list of paths searched for
-manual databases.
-Invalid paths, or paths without manual databases, are ignored.
-Overridden by
-.Fl M .
-If
-.Ev MANPATH
-begins with a
-.Sq \&: ,
-it is appended to the default list;
-else if it ends with
-.Sq \&: ,
-it is prepended to the default list; else if it contains
-.Sq \&:: ,
-the default list is inserted between the colons.
-If none of these conditions are met, it overrides the default list.
-.El
-.Sh EXIT STATUS
-.Ex -std
-.Sh SEE ALSO
-.Xr mandoc 1 ,
-.Xr man.cgi 7 ,
-.Xr mandocdb 8
-.Sh AUTHORS
-The
-.Nm
-utility was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv .
diff --git a/contrib/mdocml/catman.c b/contrib/mdocml/catman.c
deleted file mode 100644 (file)
index 8767e5e..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-/*     $Id: catman.c,v 1.11.2.2 2013/10/11 00:06:48 schwarze Exp $ */
-/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * 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.
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#if defined(__linux__) || defined(__sun)
-# include <db_185.h>
-#else
-# include <db.h>
-#endif
-
-#include "manpath.h"
-#include "mandocdb.h"
-
-#define        xstrlcpy(_dst, _src, _sz) \
-       do if (strlcpy((_dst), (_src), (_sz)) >= (_sz)) { \
-               fprintf(stderr, "%s: Path too long", (_dst)); \
-               exit(EXIT_FAILURE); \
-       } while (/* CONSTCOND */0)
-
-#define        xstrlcat(_dst, _src, _sz) \
-       do if (strlcat((_dst), (_src), (_sz)) >= (_sz)) { \
-               fprintf(stderr, "%s: Path too long", (_dst)); \
-               exit(EXIT_FAILURE); \
-       } while (/* CONSTCOND */0)
-
-static int              indexhtml(char *, size_t, char *, size_t);
-static int              manup(const struct manpaths *, char *);
-static int              mkpath(char *, mode_t, mode_t);
-static int              treecpy(char *, char *);
-static int              update(char *, char *);
-static void             usage(void);
-
-static const char      *progname;
-static int              verbose;
-static int              force;
-
-int
-main(int argc, char *argv[])
-{
-       int              ch;
-       char            *aux, *base, *conf_file;
-       struct manpaths  dirs;
-       char             buf[MAXPATHLEN];
-       extern char     *optarg;
-       extern int       optind;
-
-       progname = strrchr(argv[0], '/');
-       if (progname == NULL)
-               progname = argv[0];
-       else
-               ++progname;
-
-       aux = base = conf_file = NULL;
-       xstrlcpy(buf, "/var/www/cache/man.cgi", MAXPATHLEN);
-
-       while (-1 != (ch = getopt(argc, argv, "C:fm:M:o:v")))
-               switch (ch) {
-               case ('C'):
-                       conf_file = optarg;
-                       break;
-               case ('f'):
-                       force = 1;
-                       break;
-               case ('m'):
-                       aux = optarg;
-                       break;
-               case ('M'):
-                       base = optarg;
-                       break;
-               case ('o'):
-                       xstrlcpy(buf, optarg, MAXPATHLEN);
-                       break;
-               case ('v'):
-                       verbose++;
-                       break;
-               default:
-                       usage();
-                       return(EXIT_FAILURE);
-               }
-
-       argc -= optind;
-       argv += optind;
-
-       if (argc > 0) {
-               usage();
-               return(EXIT_FAILURE);
-       }
-
-       memset(&dirs, 0, sizeof(struct manpaths));
-       manpath_parse(&dirs, conf_file, base, aux);
-       ch = manup(&dirs, buf);
-       manpath_free(&dirs);
-       return(ch ? EXIT_SUCCESS : EXIT_FAILURE);
-}
-
-static void
-usage(void)
-{
-       
-       fprintf(stderr, "usage: %s "
-                       "[-fv] "
-                       "[-C file] "
-                       "[-o path] "
-                       "[-m manpath] "
-                       "[-M manpath]\n",
-                       progname);
-}
-
-/*
- * If "src" file doesn't exist (errors out), return -1.  Otherwise,
- * return 1 if "src" is newer (which also happens "dst" doesn't exist)
- * and 0 otherwise.
- */
-static int
-isnewer(const char *dst, const char *src)
-{
-       struct stat      s1, s2;
-
-       if (-1 == stat(src, &s1))
-               return(-1);
-       if (force)
-               return(1);
-
-       return(-1 == stat(dst, &s2) ? 1 : s1.st_mtime > s2.st_mtime);
-}
-
-/*
- * Copy the contents of one file into another.
- * Returns 0 on failure, 1 on success.
- */
-static int
-filecpy(const char *dst, const char *src)
-{
-       char             buf[BUFSIZ];
-       int              sfd, dfd, rc;
-       ssize_t          rsz, wsz;
-
-       sfd = dfd = -1;
-       rc = 0;
-
-       if (-1 == (dfd = open(dst, O_CREAT|O_TRUNC|O_WRONLY, 0644))) {
-               perror(dst);
-               goto out;
-       } else if (-1 == (sfd = open(src, O_RDONLY, 0))) {
-               perror(src);
-               goto out;
-       } 
-
-       while ((rsz = read(sfd, buf, BUFSIZ)) > 0)
-               if (-1 == (wsz = write(dfd, buf, (size_t)rsz))) {
-                       perror(dst);
-                       goto out;
-               } else if (wsz < rsz) {
-                       fprintf(stderr, "%s: Short write\n", dst);
-                       goto out;
-               }
-       
-       if (rsz < 0)
-               perror(src);
-       else
-               rc = 1;
-out:
-       if (-1 != sfd)
-               close(sfd);
-       if (-1 != dfd)
-               close(dfd);
-
-       return(rc);
-}
-
-/*
- * Pass over the recno database and re-create HTML pages if they're
- * found to be out of date.
- * Returns -1 on fatal error, 1 on success.
- */
-static int
-indexhtml(char *src, size_t ssz, char *dst, size_t dsz)
-{
-       DB              *idx;
-       DBT              key, val;
-       int              c, rc;
-       unsigned int     fl;
-       const char      *f;
-       char            *d;
-       char             fname[MAXPATHLEN];
-
-       xstrlcpy(fname, dst, MAXPATHLEN);
-       xstrlcat(fname, "/", MAXPATHLEN);
-       xstrlcat(fname, MANDOC_IDX, MAXPATHLEN);
-
-       idx = dbopen(fname, O_RDONLY, 0, DB_RECNO, NULL);
-       if (NULL == idx) {
-               perror(fname);
-               return(-1);
-       }
-
-       fl = R_FIRST;
-       while (0 == (c = (*idx->seq)(idx, &key, &val, fl))) {
-               fl = R_NEXT;
-               /*
-                * If the record is zero-length, then it's unassigned.
-                * Skip past these.
-                */
-               if (0 == val.size)
-                       continue;
-
-               f = (const char *)val.data + 1;
-               if (NULL == memchr(f, '\0', val.size - 1))
-                       break;
-
-               src[(int)ssz] = dst[(int)dsz] = '\0';
-
-               xstrlcat(dst, "/", MAXPATHLEN);
-               xstrlcat(dst, f, MAXPATHLEN);
-
-               xstrlcat(src, "/", MAXPATHLEN);
-               xstrlcat(src, f, MAXPATHLEN);
-
-               if (-1 == (rc = isnewer(dst, src))) {
-                       fprintf(stderr, "%s: File missing\n", f);
-                       break;
-               } else if (0 == rc)
-                       continue;
-
-               d = strrchr(dst, '/');
-               assert(NULL != d);
-               *d = '\0';
-
-               if (-1 == mkpath(dst, 0755, 0755)) {
-                       perror(dst);
-                       break;
-               }
-
-               *d = '/';
-
-               if ( ! filecpy(dst, src))
-                       break;
-               if (verbose)
-                       printf("%s\n", dst);
-       }
-
-       (*idx->close)(idx);
-
-       if (c < 0)
-               perror(fname);
-       else if (0 == c) 
-               fprintf(stderr, "%s: Corrupt index\n", fname);
-
-       return(1 == c ? 1 : -1);
-}
-
-/*
- * Copy both recno and btree databases into the destination.
- * Call in to begin recreating HTML files.
- * Return -1 on fatal error and 1 if the update went well.
- */
-static int
-update(char *dst, char *src)
-{
-       size_t           dsz, ssz;
-
-       dsz = strlen(dst);
-       ssz = strlen(src);
-
-       xstrlcat(src, "/", MAXPATHLEN);
-       xstrlcat(dst, "/", MAXPATHLEN);
-
-       xstrlcat(src, MANDOC_DB, MAXPATHLEN);
-       xstrlcat(dst, MANDOC_DB, MAXPATHLEN);
-
-       if ( ! filecpy(dst, src))
-               return(-1);
-       if (verbose)
-               printf("%s\n", dst);
-
-       dst[(int)dsz] = src[(int)ssz] = '\0';
-
-       xstrlcat(src, "/", MAXPATHLEN);
-       xstrlcat(dst, "/", MAXPATHLEN);
-
-       xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
-       xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);
-
-       if ( ! filecpy(dst, src))
-               return(-1);
-       if (verbose)
-               printf("%s\n", dst);
-
-       dst[(int)dsz] = src[(int)ssz] = '\0';
-
-       return(indexhtml(src, ssz, dst, dsz));
-}
-
-/*
- * See if btree or recno databases in the destination are out of date
- * with respect to a single manpath component.
- * Return -1 on fatal error, 0 if the source is no longer valid (and
- * shouldn't be listed), and 1 if the update went well.
- */
-static int
-treecpy(char *dst, char *src)
-{
-       size_t           dsz, ssz;
-       int              rc;
-
-       dsz = strlen(dst);
-       ssz = strlen(src);
-
-       xstrlcat(src, "/", MAXPATHLEN);
-       xstrlcat(dst, "/", MAXPATHLEN);
-
-       xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
-       xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);
-
-       if (-1 == (rc = isnewer(dst, src)))
-               return(0);
-
-       dst[(int)dsz] = src[(int)ssz] = '\0';
-
-       if (1 == rc)
-               return(update(dst, src));
-
-       xstrlcat(src, "/", MAXPATHLEN);
-       xstrlcat(dst, "/", MAXPATHLEN);
-
-       xstrlcat(src, MANDOC_DB, MAXPATHLEN);
-       xstrlcat(dst, MANDOC_DB, MAXPATHLEN);
-
-       if (-1 == (rc = isnewer(dst, src)))
-               return(0);
-       else if (rc == 0)
-               return(1);
-
-       dst[(int)dsz] = src[(int)ssz] = '\0';
-
-       return(update(dst, src));
-}
-
-/*
- * Update the destination's file-tree with respect to changes in the
- * source manpath components.
- * "Change" is defined by an updated index or btree database.
- * Returns 1 on success, 0 on failure.
- */
-static int
-manup(const struct manpaths *dirs, char *base)
-{
-       char             dst[MAXPATHLEN],
-                        src[MAXPATHLEN];
-       const char      *path;
-       size_t           i;
-       int              c;
-       size_t           sz;
-       FILE            *f;
-
-       /* Create the path and file for the catman.conf file. */
-
-       sz = strlen(base);
-       xstrlcpy(dst, base, MAXPATHLEN);
-       xstrlcat(dst, "/etc", MAXPATHLEN);
-       if (-1 == mkpath(dst, 0755, 0755)) {
-               perror(dst);
-               return(0);
-       }
-
-       xstrlcat(dst, "/catman.conf", MAXPATHLEN);
-       if (NULL == (f = fopen(dst, "w"))) {
-               perror(dst);
-               return(0);
-       } else if (verbose)
-               printf("%s\n", dst);
-
-       for (i = 0; i < dirs->sz; i++) {
-               path = dirs->paths[i];
-               dst[(int)sz] = '\0';
-               xstrlcat(dst, path, MAXPATHLEN);
-               if (-1 == mkpath(dst, 0755, 0755)) {
-                       perror(dst);
-                       break;
-               }
-
-               xstrlcpy(src, path, MAXPATHLEN);
-               if (-1 == (c = treecpy(dst, src)))
-                       break;
-               else if (0 == c)
-                       continue;
-
-               /*
-                * We want to use a relative path here because manpath.h
-                * will realpath() when invoked with man.cgi, and we'll
-                * make sure to chdir() into the cache directory before.
-                *
-                * This allows the cache directory to be in an arbitrary
-                * place, working in both chroot() and non-chroot()
-                * "safe" modes.
-                */
-               assert('/' == path[0]);
-               fprintf(f, "_whatdb %s/whatis.db\n", path + 1);
-       }
-
-       fclose(f);
-       return(i == dirs->sz);
-}
-
-/*
- * Copyright (c) 1983, 1992, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-static int
-mkpath(char *path, mode_t mode, mode_t dir_mode)
-{
-       struct stat sb;
-       char *slash;
-       int done, exists;
-
-       slash = path;
-
-       for (;;) {
-               /* LINTED */
-               slash += strspn(slash, "/");
-               /* LINTED */
-               slash += strcspn(slash, "/");
-
-               done = (*slash == '\0');
-               *slash = '\0';
-
-               /* skip existing path components */
-               exists = !stat(path, &sb);
-               if (!done && exists && S_ISDIR(sb.st_mode)) {
-                       *slash = '/';
-                       continue;
-               }
-
-               if (mkdir(path, done ? mode : dir_mode) == 0) {
-                       if (mode > 0777 && chmod(path, mode) < 0)
-                               return (-1);
-               } else {
-                       if (!exists) {
-                               /* Not there */
-                               return (-1);
-                       }
-                       if (!S_ISDIR(sb.st_mode)) {
-                               /* Is there, but isn't a directory */
-                               errno = ENOTDIR;
-                               return (-1);
-                       }
-               }
-
-               if (done)
-                       break;
-
-               *slash = '/';
-       }
-
-       return (0);
-}
index 64bde45..1e38e3d 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: cgi.c,v 1.46 2013/10/11 00:06:48 schwarze Exp $ */
+/*     $Id: cgi.c,v 1.92 2014/08/05 15:29:30 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@usta.de>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include "config.h"
 #endif
 
-#include <sys/wait.h>
-
-#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
-#include <dirent.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <regex.h>
-#include <stdio.h>
-#include <stdarg.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#if defined(__sun)
-/* for stat() */
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#endif
-
-#include "apropos_db.h"
 #include "mandoc.h"
-#include "mdoc.h"
-#include "man.h"
+#include "mandoc_aux.h"
 #include "main.h"
 #include "manpath.h"
-#include "mandocdb.h"
-
-#if defined(__linux__) || defined(__sun)
-# include <db_185.h>
-#else
-# include <db.h>
-#endif
-
-enum   page {
-       PAGE_INDEX,
-       PAGE_SEARCH,
-       PAGE_SHOW,
-       PAGE__MAX
-};
-
-struct paths {
-       char            *name;
-       char            *path;
-};
+#include "mansearch.h"
+#include "cgi.h"
 
 /*
  * A query as passed to the search function.
  */
 struct query {
-       const char      *arch; /* architecture */
-       const char      *sec; /* manual section */
-       const char      *expr; /* unparsed expression string */
-       int              manroot; /* manroot index (or -1)*/
-       int              legacy; /* whether legacy mode */
+       char            *manpath; /* desired manual directory */
+       char            *arch; /* architecture */
+       char            *sec; /* manual section */
+       char            *query; /* unparsed query expression */
+       int              equal; /* match whole names, not substrings */
 };
 
 struct req {
-       struct query     q;
-       struct paths    *p;
-       size_t           psz;
-       enum page        page;
+       struct query      q;
+       char            **p; /* array of available manpaths */
+       size_t            psz; /* number of available manpaths */
 };
 
-static int              atou(const char *, unsigned *);
 static void             catman(const struct req *, const char *);
-static int              cmp(const void *, const void *);
 static void             format(const struct req *, const char *);
 static void             html_print(const char *);
-static void             html_printquery(const struct req *);
 static void             html_putchar(char);
 static int              http_decode(char *);
-static void             http_parse(struct req *, char *);
+static void             http_parse(struct req *, const char *);
 static void             http_print(const char *);
 static void             http_putchar(char);
-static void             http_printquery(const struct req *);
-static int              pathstop(DIR *);
-static void             pathgen(DIR *, char *, struct req *);
-static void             pg_index(const struct req *, char *);
-static void             pg_search(const struct req *, char *);
-static void             pg_show(const struct req *, char *);
-static void             resp_bad(void);
-static void             resp_baddb(void);
-static void             resp_error400(void);
-static void             resp_error404(const char *);
+static void             http_printquery(const struct req *, const char *);
+static void             pathgen(struct req *);
+static void             pg_error_badrequest(const char *);
+static void             pg_error_internal(void);
+static void             pg_index(const struct req *);
+static void             pg_noresult(const struct req *, const char *);
+static void             pg_search(const struct req *);
+static void             pg_searchres(const struct req *,
+                               struct manpage *, size_t);
+static void             pg_show(struct req *, const char *);
 static void             resp_begin_html(int, const char *);
 static void             resp_begin_http(int, const char *);
 static void             resp_end_html(void);
-static void             resp_index(const struct req *);
-static void             resp_search(struct res *, size_t, void *);
 static void             resp_searchform(const struct req *);
+static void             resp_show(const struct req *, const char *);
+static void             set_query_attr(char **, char **);
+static int              validate_filename(const char *);
+static int              validate_manpath(const struct req *, const char *);
+static int              validate_urifrag(const char *);
 
-static const char       *progname; /* cgi script name */
-static const char       *cache; /* cache directory */
-static const char       *css; /* css directory */
-static const char       *host; /* hostname */
+static const char       *scriptname; /* CGI script name */
 
-static const char * const pages[PAGE__MAX] = {
-       "index", /* PAGE_INDEX */ 
-       "search", /* PAGE_SEARCH */
-       "show", /* PAGE_SHOW */
+static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
+static const char *const sec_numbers[] = {
+    "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9"
 };
-
-/*
- * This is just OpenBSD's strtol(3) suggestion.
- * I use it instead of strtonum(3) for portability's sake.
- */
-static int
-atou(const char *buf, unsigned *v)
-{
-       char            *ep;
-       long             lval;
-
-       errno = 0;
-       lval = strtol(buf, &ep, 10);
-       if (buf[0] == '\0' || *ep != '\0')
-               return(0);
-       if ((errno == ERANGE && (lval == LONG_MAX || 
-                                       lval == LONG_MIN)) ||
-                       (lval > INT_MAX || lval < 0))
-               return(0);
-
-       *v = (unsigned int)lval;
-       return(1);
-}
+static const char *const sec_names[] = {
+    "All Sections",
+    "1 - General Commands",
+    "2 - System Calls",
+    "3 - Subroutines",
+    "3p - Perl Subroutines",
+    "4 - Special Files",
+    "5 - File Formats",
+    "6 - Games",
+    "7 - Macros and Conventions",
+    "8 - Maintenance Commands",
+    "9 - Kernel Interface"
+};
+static const int sec_MAX = sizeof(sec_names) / sizeof(char *);
+
+static const char *const arch_names[] = {
+    "amd64",       "alpha",       "armish",      "armv7",
+    "aviion",      "hppa",        "hppa64",      "i386",
+    "ia64",        "landisk",     "loongson",    "luna88k",
+    "macppc",      "mips64",      "octeon",      "sgi",
+    "socppc",      "solbourne",   "sparc",       "sparc64",
+    "vax",         "zaurus",
+    "amiga",       "arc",         "arm32",       "atari",
+    "beagle",      "cats",        "hp300",       "mac68k",
+    "mvme68k",     "mvme88k",     "mvmeppc",     "palm",
+    "pc532",       "pegasos",     "pmax",        "powerpc",
+    "sun3",        "wgrisc",      "x68k"
+};
+static const int arch_MAX = sizeof(arch_names) / sizeof(char *);
 
 /*
  * Print a character, escaping HTML along the way.
@@ -173,29 +143,30 @@ html_putchar(char c)
                break;
        }
 }
-static void
-http_printquery(const struct req *req)
-{
-
-       printf("&expr=");
-       http_print(req->q.expr ? req->q.expr : "");
-       printf("&sec=");
-       http_print(req->q.sec ? req->q.sec : "");
-       printf("&arch=");
-       http_print(req->q.arch ? req->q.arch : "");
-}
-
 
 static void
-html_printquery(const struct req *req)
+http_printquery(const struct req *req, const char *sep)
 {
 
-       printf("&amp;expr=");
-       html_print(req->q.expr ? req->q.expr : "");
-       printf("&amp;sec=");
-       html_print(req->q.sec ? req->q.sec : "");
-       printf("&amp;arch=");
-       html_print(req->q.arch ? req->q.arch : "");
+       if (NULL != req->q.query) {
+               printf("query=");
+               http_print(req->q.query);
+       }
+       if (0 == req->q.equal)
+               printf("%sapropos=1", sep);
+       if (NULL != req->q.sec) {
+               printf("%ssec=", sep);
+               http_print(req->q.sec);
+       }
+       if (NULL != req->q.arch) {
+               printf("%sarch=", sep);
+               http_print(req->q.arch);
+       }
+       if (NULL != req->q.manpath &&
+           strcmp(req->q.manpath, req->p[0])) {
+               printf("%smanpath=", sep);
+               http_print(req->q.manpath);
+       }
 }
 
 static void
@@ -223,81 +194,114 @@ html_print(const char *p)
 }
 
 /*
- * Parse out key-value pairs from an HTTP request variable.
- * This can be either a cookie or a POST/GET string, although man.cgi
- * uses only GET for simplicity.
+ * Transfer the responsibility for the allocated string *val
+ * to the query structure.
+ */
+static void
+set_query_attr(char **attr, char **val)
+{
+
+       free(*attr);
+       if (**val == '\0') {
+               *attr = NULL;
+               free(*val);
+       } else
+               *attr = *val;
+       *val = NULL;
+}
+
+/*
+ * Parse the QUERY_STRING for key-value pairs
+ * and store the values into the query structure.
  */
 static void
-http_parse(struct req *req, char *p)
+http_parse(struct req *req, const char *qs)
 {
-       char            *key, *val, *manroot;
-       int              i, legacy;
+       char            *key, *val;
+       size_t           keysz, valsz;
 
-       memset(&req->q, 0, sizeof(struct query));
+       req->q.manpath  = NULL;
+       req->q.arch     = NULL;
+       req->q.sec      = NULL;
+       req->q.query    = NULL;
+       req->q.equal    = 1;
 
-       legacy = -1;
-       manroot = NULL;
+       key = val = NULL;
+       while (*qs != '\0') {
 
-       while ('\0' != *p) {
-               key = p;
-               val = NULL;
+               /* Parse one key. */
 
-               p += (int)strcspn(p, ";&");
-               if ('\0' != *p)
-                       *p++ = '\0';
-               if (NULL != (val = strchr(key, '=')))
-                       *val++ = '\0';
+               keysz = strcspn(qs, "=;&");
+               key = mandoc_strndup(qs, keysz);
+               qs += keysz;
+               if (*qs != '=')
+                       goto next;
 
-               if ('\0' == *key || NULL == val || '\0' == *val)
-                       continue;
+               /* Parse one value. */
 
-               /* Just abort handling. */
-
-               if ( ! http_decode(key))
-                       break;
-               if (NULL != val && ! http_decode(val))
-                       break;
-
-               if (0 == strcmp(key, "expr"))
-                       req->q.expr = val;
-               else if (0 == strcmp(key, "query"))
-                       req->q.expr = val;
-               else if (0 == strcmp(key, "sec"))
-                       req->q.sec = val;
-               else if (0 == strcmp(key, "sektion"))
-                       req->q.sec = val;
-               else if (0 == strcmp(key, "arch"))
-                       req->q.arch = val;
-               else if (0 == strcmp(key, "manpath"))
-                       manroot = val;
-               else if (0 == strcmp(key, "apropos"))
-                       legacy = 0 == strcmp(val, "0");
-       }
+               valsz = strcspn(++qs, ";&");
+               val = mandoc_strndup(qs, valsz);
+               qs += valsz;
 
-       /* Test for old man.cgi compatibility mode. */
+               /* Decode and catch encoding errors. */
 
-       req->q.legacy = legacy > 0;
+               if ( ! (http_decode(key) && http_decode(val)))
+                       goto next;
 
-       /* 
-        * Section "0" means no section when in legacy mode.
-        * For some man.cgi scripts, "default" arch is none.
-        */
+               /* Handle key-value pairs. */
+
+               if ( ! strcmp(key, "query"))
+                       set_query_attr(&req->q.query, &val);
+
+               else if ( ! strcmp(key, "apropos"))
+                       req->q.equal = !strcmp(val, "0");
+
+               else if ( ! strcmp(key, "manpath")) {
+#ifdef COMPAT_OLDURI
+                       if ( ! strncmp(val, "OpenBSD ", 8)) {
+                               val[7] = '-';
+                               if ('C' == val[8])
+                                       val[8] = 'c';
+                       }
+#endif
+                       set_query_attr(&req->q.manpath, &val);
+               }
+
+               else if ( ! (strcmp(key, "sec")
+#ifdef COMPAT_OLDURI
+                   && strcmp(key, "sektion")
+#endif
+                   )) {
+                       if ( ! strcmp(val, "0"))
+                               *val = '\0';
+                       set_query_attr(&req->q.sec, &val);
+               }
 
-       if (req->q.legacy && NULL != req->q.sec)
-               if (0 == strcmp(req->q.sec, "0"))
-                       req->q.sec = NULL;
-       if (req->q.legacy && NULL != req->q.arch)
-               if (0 == strcmp(req->q.arch, "default"))
-                       req->q.arch = NULL;
+               else if ( ! strcmp(key, "arch")) {
+                       if ( ! strcmp(val, "default"))
+                               *val = '\0';
+                       set_query_attr(&req->q.arch, &val);
+               }
 
-       /* Default to first manroot. */
+               /*
+                * The key must be freed in any case.
+                * The val may have been handed over to the query
+                * structure, in which case it is now NULL.
+                */
+next:
+               free(key);
+               key = NULL;
+               free(val);
+               val = NULL;
 
-       if (NULL != manroot) {
-               for (i = 0; i < (int)req->psz; i++)
-                       if (0 == strcmp(req->p[i].name, manroot))
-                               break;
-               req->q.manroot = i < (int)req->psz ? i : -1;
+               if (*qs != '\0')
+                       qs++;
        }
+
+       /* Fall back to the default manpath. */
+
+       if (req->q.manpath == NULL)
+               req->q.manpath = mandoc_strdup(req->p[0]);
 }
 
 static void
@@ -323,11 +327,13 @@ static int
 http_decode(char *p)
 {
        char             hex[3];
+       char            *q;
        int              c;
 
        hex[2] = '\0';
 
-       for ( ; '\0' != *p; p++) {
+       q = p;
+       for ( ; '\0' != *p; p++, q++) {
                if ('%' == *p) {
                        if ('\0' == (hex[0] = *(p + 1)))
                                return(0);
@@ -338,13 +344,13 @@ http_decode(char *p)
                        if ('\0' == c)
                                return(0);
 
-                       *p = (char)c;
-                       memmove(p + 1, p + 3, strlen(p + 3) + 1);
+                       *q = (char)c;
+                       p += 2;
                } else
-                       *p = '+' == *p ? ' ' : *p;
+                       *q = '+' == *p ? ' ' : *p;
        }
 
-       *p = '\0';
+       *q = '\0';
        return(1);
 }
 
@@ -353,12 +359,12 @@ resp_begin_http(int code, const char *msg)
 {
 
        if (200 != code)
-               printf("Status: %d %s\n", code, msg);
+               printf("Status: %d %s\r\n", code, msg);
 
-       puts("Content-Type: text/html; charset=utf-8\n"
-            "Cache-Control: no-cache\n"
-            "Pragma: no-cache\n"
-            "");
+       printf("Content-Type: text/html; charset=utf-8\r\n"
+            "Cache-Control: no-cache\r\n"
+            "Pragma: no-cache\r\n"
+            "\r\n");
 
        fflush(stdout);
 }
@@ -380,10 +386,11 @@ resp_begin_html(int code, const char *msg)
               " TYPE=\"text/css\" media=\"all\">\n"
               "<LINK REL=\"stylesheet\" HREF=\"%s/man.css\""
               " TYPE=\"text/css\" media=\"all\">\n"
-              "<TITLE>System Manpage Reference</TITLE>\n"
+              "<TITLE>%s</TITLE>\n"
               "</HEAD>\n"
               "<BODY>\n"
-              "<!-- Begin page content. //-->\n", css, css);
+              "<!-- Begin page content. //-->\n",
+              CSS_DIR, CSS_DIR, CUSTOMIZE_TITLE);
 }
 
 static void
@@ -399,192 +406,288 @@ resp_searchform(const struct req *req)
 {
        int              i;
 
+       puts(CUSTOMIZE_BEGIN);
        puts("<!-- Begin search form. //-->");
        printf("<DIV ID=\"mancgi\">\n"
-              "<FORM ACTION=\"%s/search.html\" METHOD=\"get\">\n"
+              "<FORM ACTION=\"%s\" METHOD=\"get\">\n"
               "<FIELDSET>\n"
-              "<LEGEND>Search Parameters</LEGEND>\n"
-              "<INPUT TYPE=\"submit\" "
-              " VALUE=\"Search\"> for manuals satisfying \n"
-              "<INPUT TYPE=\"text\" NAME=\"expr\" VALUE=\"",
-              progname);
-       html_print(req->q.expr ? req->q.expr : "");
-       printf("\">, section "
-              "<INPUT TYPE=\"text\""
-              " SIZE=\"4\" NAME=\"sec\" VALUE=\"");
-       html_print(req->q.sec ? req->q.sec : "");
-       printf("\">, arch "
-              "<INPUT TYPE=\"text\""
-              " SIZE=\"8\" NAME=\"arch\" VALUE=\"");
-       html_print(req->q.arch ? req->q.arch : "");
-       printf("\">");
+              "<LEGEND>Manual Page Search Parameters</LEGEND>\n",
+              scriptname);
+
+       /* Write query input box. */
+
+       printf( "<TABLE><TR><TD>\n"
+               "<INPUT TYPE=\"text\" NAME=\"query\" VALUE=\"");
+       if (NULL != req->q.query)
+               html_print(req->q.query);
+       puts("\" SIZE=\"40\">");
+
+       /* Write submission and reset buttons. */
+
+       printf( "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n"
+               "<INPUT TYPE=\"reset\" VALUE=\"Reset\">\n");
+
+       /* Write show radio button */
+
+       printf( "</TD><TD>\n"
+               "<INPUT TYPE=\"radio\" ");
+       if (req->q.equal)
+               printf("CHECKED=\"checked\" ");
+       printf( "NAME=\"apropos\" ID=\"show\" VALUE=\"0\">\n"
+               "<LABEL FOR=\"show\">Show named manual page</LABEL>\n");
+
+       /* Write section selector. */
+
+       puts(   "</TD></TR><TR><TD>\n"
+               "<SELECT NAME=\"sec\">");
+       for (i = 0; i < sec_MAX; i++) {
+               printf("<OPTION VALUE=\"%s\"", sec_numbers[i]);
+               if (NULL != req->q.sec &&
+                   0 == strcmp(sec_numbers[i], req->q.sec))
+                       printf(" SELECTED=\"selected\"");
+               printf(">%s</OPTION>\n", sec_names[i]);
+       }
+       puts("</SELECT>");
+
+       /* Write architecture selector. */
+
+       printf( "<SELECT NAME=\"arch\">\n"
+               "<OPTION VALUE=\"default\"");
+       if (NULL == req->q.arch)
+               printf(" SELECTED=\"selected\"");
+       puts(">All Architectures</OPTION>");
+       for (i = 0; i < arch_MAX; i++) {
+               printf("<OPTION VALUE=\"%s\"", arch_names[i]);
+               if (NULL != req->q.arch &&
+                   0 == strcmp(arch_names[i], req->q.arch))
+                       printf(" SELECTED=\"selected\"");
+               printf(">%s</OPTION>\n", arch_names[i]);
+       }
+       puts("</SELECT>");
+
+       /* Write manpath selector. */
+
        if (req->psz > 1) {
-               puts("<SELECT NAME=\"manpath\">");
+               puts("<SELECT NAME=\"manpath\">");
                for (i = 0; i < (int)req->psz; i++) {
-                       printf("<OPTION %s VALUE=\"",
-                               (i == req->q.manroot) ||
-                               (0 == i && -1 == req->q.manroot) ?
-                               "SELECTED=\"selected\"" : "");
-                       html_print(req->p[i].name);
+                       printf("<OPTION ");
+                       if (NULL == req->q.manpath ? 0 == i :
+                           0 == strcmp(req->q.manpath, req->p[i]))
+                               printf("SELECTED=\"selected\" ");
+                       printf("VALUE=\"");
+                       html_print(req->p[i]);
                        printf("\">");
-                       html_print(req->p[i].name);
+                       html_print(req->p[i]);
                        puts("</OPTION>");
                }
                puts("</SELECT>");
        }
-       puts(".\n"
-            "<INPUT TYPE=\"reset\" VALUE=\"Reset\">\n"
+
+       /* Write search radio button */
+
+       printf( "</TD><TD>\n"
+               "<INPUT TYPE=\"radio\" ");
+       if (0 == req->q.equal)
+               printf("CHECKED=\"checked\" ");
+       printf( "NAME=\"apropos\" ID=\"search\" VALUE=\"1\">\n"
+               "<LABEL FOR=\"search\">Search with apropos query</LABEL>\n");
+
+       puts("</TD></TR></TABLE>\n"
             "</FIELDSET>\n"
             "</FORM>\n"
             "</DIV>");
        puts("<!-- End search form. //-->");
 }
 
-static void
-resp_index(const struct req *req)
+static int
+validate_urifrag(const char *frag)
 {
 
-       resp_begin_html(200, NULL);
-       resp_searchform(req);
-       resp_end_html();
+       while ('\0' != *frag) {
+               if ( ! (isalnum((unsigned char)*frag) ||
+                   '-' == *frag || '.' == *frag ||
+                   '/' == *frag || '_' == *frag))
+                       return(0);
+               frag++;
+       }
+       return(1);
 }
 
-static void
-resp_error400(void)
+static int
+validate_manpath(const struct req *req, const char* manpath)
 {
+       size_t   i;
 
-       resp_begin_html(400, "Query Malformed");
-       printf("<H1>Malformed Query</H1>\n"
-              "<P>\n"
-              "The query your entered was malformed.\n"
-              "Try again from the\n"
-              "<A HREF=\"%s/index.html\">main page</A>.\n"
-              "</P>", progname);
-       resp_end_html();
+       if ( ! strcmp(manpath, "mandoc"))
+               return(1);
+
+       for (i = 0; i < req->psz; i++)
+               if ( ! strcmp(manpath, req->p[i]))
+                       return(1);
+
+       return(0);
+}
+
+static int
+validate_filename(const char *file)
+{
+
+       if ('.' == file[0] && '/' == file[1])
+               file += 2;
+
+       return ( ! (strstr(file, "../") || strstr(file, "/..") ||
+           (strncmp(file, "man", 3) && strncmp(file, "cat", 3))));
 }
 
 static void
-resp_error404(const char *page)
+pg_index(const struct req *req)
 {
 
-       resp_begin_html(404, "Not Found");
-       puts("<H1>Page Not Found</H1>\n"
-            "<P>\n"
-            "The page you're looking for, ");
-       printf("<B>");
-       html_print(page);
-       printf("</B>,\n"
-              "could not be found.\n"
-              "Try searching from the\n"
-              "<A HREF=\"%s/index.html\">main page</A>.\n"
-              "</P>", progname);
+       resp_begin_html(200, NULL);
+       resp_searchform(req);
+       printf("<P>\n"
+              "This web interface is documented in the\n"
+              "<A HREF=\"%s/mandoc/man8/man.cgi.8\">man.cgi</A>\n"
+              "manual, and the\n"
+              "<A HREF=\"%s/mandoc/man1/apropos.1\">apropos</A>\n"
+              "manual explains the query syntax.\n"
+              "</P>\n",
+              scriptname, scriptname);
        resp_end_html();
 }
 
 static void
-resp_bad(void)
+pg_noresult(const struct req *req, const char *msg)
 {
-       resp_begin_html(500, "Internal Server Error");
-       puts("<P>Generic badness happened.</P>");
+       resp_begin_html(200, NULL);
+       resp_searchform(req);
+       puts("<P>");
+       puts(msg);
+       puts("</P>");
        resp_end_html();
 }
 
 static void
-resp_baddb(void)
+pg_error_badrequest(const char *msg)
 {
 
-       resp_begin_html(500, "Internal Server Error");
-       puts("<P>Your database is broken.</P>");
+       resp_begin_html(400, "Bad Request");
+       puts("<H1>Bad Request</H1>\n"
+            "<P>\n");
+       puts(msg);
+       printf("Try again from the\n"
+              "<A HREF=\"%s\">main page</A>.\n"
+              "</P>", scriptname);
        resp_end_html();
 }
 
 static void
-resp_search(struct res *r, size_t sz, void *arg)
+pg_error_internal(void)
 {
-       size_t           i, matched;
-       const struct req *req;
+       resp_begin_html(500, "Internal Server Error");
+       puts("<P>Internal Server Error</P>");
+       resp_end_html();
+}
 
-       req = (const struct req *)arg;
+static void
+pg_searchres(const struct req *req, struct manpage *r, size_t sz)
+{
+       char            *arch, *archend;
+       size_t           i, iuse, isec;
+       int              archprio, archpriouse;
+       int              prio, priouse;
+       char             sec;
 
-       if (sz > 0)
-               assert(req->q.manroot >= 0);
+       for (i = 0; i < sz; i++) {
+               if (validate_filename(r[i].file))
+                       continue;
+               fprintf(stderr, "invalid filename %s in %s database\n",
+                   r[i].file, req->q.manpath);
+               pg_error_internal();
+               return;
+       }
 
-       for (matched = i = 0; i < sz; i++)
-               if (r[i].matched)
-                       matched++;
-       
-       if (1 == matched) {
-               for (i = 0; i < sz; i++)
-                       if (r[i].matched)
-                               break;
+       if (1 == sz) {
                /*
                 * If we have just one result, then jump there now
                 * without any delay.
                 */
-               puts("Status: 303 See Other");
-               printf("Location: http://%s%s/show/%d/%u/%u.html?",
-                               host, progname, req->q.manroot,
-                               r[i].volume, r[i].rec);
-               http_printquery(req);
-               puts("\n"
-                    "Content-Type: text/html; charset=utf-8\n");
+               printf("Status: 303 See Other\r\n");
+               printf("Location: http://%s%s/%s/%s?",
+                   HTTP_HOST, scriptname, req->q.manpath, r[0].file);
+               http_printquery(req, "&");
+               printf("\r\n"
+                    "Content-Type: text/html; charset=utf-8\r\n"
+                    "\r\n");
                return;
        }
 
        resp_begin_html(200, NULL);
        resp_searchform(req);
-
        puts("<DIV CLASS=\"results\">");
-
-       if (0 == matched) {
-               puts("<P>\n"
-                    "No results found.\n"
-                    "</P>\n"
-                    "</DIV>");
-               resp_end_html();
-               return;
-       }
-
-       qsort(r, sz, sizeof(struct res), cmp);
-
        puts("<TABLE>");
 
        for (i = 0; i < sz; i++) {
-               if ( ! r[i].matched)
-                       continue;
                printf("<TR>\n"
                       "<TD CLASS=\"title\">\n"
-                      "<A HREF=\"%s/show/%d/%u/%u.html?", 
-                               progname, req->q.manroot,
-                               r[i].volume, r[i].rec);
-               html_printquery(req);
+                      "<A HREF=\"%s/%s/%s?", 
+                   scriptname, req->q.manpath, r[i].file);
+               http_printquery(req, "&amp;");
                printf("\">");
-               html_print(r[i].title);
-               putchar('(');
-               html_print(r[i].cat);
-               if (r[i].arch && '\0' != *r[i].arch) {
-                       putchar('/');
-                       html_print(r[i].arch);
-               }
-               printf(")</A>\n"
+               html_print(r[i].names);
+               printf("</A>\n"
                       "</TD>\n"
                       "<TD CLASS=\"desc\">");
-               html_print(r[i].desc);
+               html_print(r[i].output);
                puts("</TD>\n"
                     "</TR>");
        }
 
        puts("</TABLE>\n"
             "</DIV>");
-       resp_end_html();
-}
 
-/* ARGSUSED */
-static void
-pg_index(const struct req *req, char *path)
-{
+       /*
+        * In man(1) mode, show one of the pages
+        * even if more than one is found.
+        */
 
-       resp_index(req);
+       if (req->q.equal) {
+               puts("<HR>");
+               iuse = 0;
+               priouse = 10;
+               archpriouse = 3;
+               for (i = 0; i < sz; i++) {
+                       isec = strcspn(r[i].file, "123456789");
+                       sec = r[i].file[isec];
+                       if ('\0' == sec)
+                               continue;
+                       prio = sec_prios[sec - '1'];
+                       if (NULL == req->q.arch) {
+                               archprio =
+                                   (NULL == (arch = strchr(
+                                       r[i].file + isec, '/'))) ? 3 :
+                                   (NULL == (archend = strchr(
+                                       arch + 1, '/'))) ? 0 :
+                                   strncmp(arch, "amd64/",
+                                       archend - arch) ? 2 : 1;
+                               if (archprio < archpriouse) {
+                                       archpriouse = archprio;
+                                       priouse = prio;
+                                       iuse = i;
+                                       continue;
+                               }
+                               if (archprio > archpriouse)
+                                       continue;
+                       }
+                       if (prio >= priouse)
+                               continue;
+                       priouse = prio;
+                       iuse = i;
+               }
+               resp_show(req, r[iuse].file);
+       }
+
+       resp_end_html();
 }
 
 static void
@@ -597,12 +700,10 @@ catman(const struct req *req, const char *file)
        int              italic, bold;
 
        if (NULL == (f = fopen(file, "r"))) {
-               resp_baddb();
+               puts("<P>You specified an invalid manual file.</P>");
                return;
        }
 
-       resp_begin_html(200, NULL);
-       resp_searchform(req);
        puts("<DIV CLASS=\"catman\">\n"
             "<PRE>");
 
@@ -716,9 +817,7 @@ catman(const struct req *req, const char *file)
        }
 
        puts("</PRE>\n"
-            "</DIV>\n"
-            "</BODY>\n"
-            "</HTML>");
+            "</DIV>");
 
        fclose(f);
 }
@@ -727,42 +826,49 @@ static void
 format(const struct req *req, const char *file)
 {
        struct mparse   *mp;
-       int              fd;
        struct mdoc     *mdoc;
        struct man      *man;
        void            *vp;
+       char            *opts;
        enum mandoclevel rc;
-       char             opts[PATH_MAX + 128];
+       int              fd;
+       int              usepath;
 
        if (-1 == (fd = open(file, O_RDONLY, 0))) {
-               resp_baddb();
+               puts("<P>You specified an invalid manual file.</P>");
                return;
        }
 
-       mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL, NULL);
+       mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL,
+           req->q.manpath);
        rc = mparse_readfd(mp, fd, file);
        close(fd);
 
        if (rc >= MANDOCLEVEL_FATAL) {
-               resp_baddb();
+               fprintf(stderr, "fatal mandoc error: %s/%s\n",
+                   req->q.manpath, file);
+               pg_error_internal();
                return;
        }
 
-       snprintf(opts, sizeof(opts), "fragment,"
-                       "man=%s/search.html?sec=%%S&expr=Nm~^%%N$,"
-                       /*"includes=/cgi-bin/man.cgi/usr/include/%%I"*/,
-                       progname);
+       usepath = strcmp(req->q.manpath, req->p[0]);
+       mandoc_asprintf(&opts,
+           "fragment,man=%s?query=%%N&sec=%%S%s%s%s%s",
+           scriptname,
+           req->q.arch ? "&arch="       : "",
+           req->q.arch ? req->q.arch    : "",
+           usepath     ? "&manpath="    : "",
+           usepath     ? req->q.manpath : "");
 
-       mparse_result(mp, &mdoc, &man);
+       mparse_result(mp, &mdoc, &man, NULL);
        if (NULL == man && NULL == mdoc) {
-               resp_baddb();
+               fprintf(stderr, "fatal mandoc error: %s/%s\n",
+                   req->q.manpath, file);
+               pg_error_internal();
                mparse_free(mp);
                return;
        }
 
-       resp_begin_html(200, NULL);
-       resp_searchform(req);
-
        vp = html_alloc(opts);
 
        if (NULL != mdoc)
@@ -770,145 +876,87 @@ format(const struct req *req, const char *file)
        else
                html_man(vp, man);
 
-       puts("</BODY>\n"
-            "</HTML>");
-
        html_free(vp);
        mparse_free(mp);
+       free(opts);
+}
+
+static void
+resp_show(const struct req *req, const char *file)
+{
+
+       if ('.' == file[0] && '/' == file[1])
+               file += 2;
+
+       if ('c' == *file)
+               catman(req, file);
+       else
+               format(req, file);
 }
 
 static void
-pg_show(const struct req *req, char *path)
+pg_show(struct req *req, const char *fullpath)
 {
-       struct manpaths  ps;
-       size_t           sz;
-       char            *sub;
-       char             file[PATH_MAX];
-       const char      *cp;
-       int              rc, catm;
-       unsigned int     vol, rec, mr;
-       DB              *idx;
-       DBT              key, val;
-
-       idx = NULL;
-
-       /* Parse out mroot, volume, and record from the path. */
-
-       if (NULL == path || NULL == (sub = strchr(path, '/'))) {
-               resp_error400();
+       char            *manpath;
+       const char      *file;
+
+       if ((file = strchr(fullpath, '/')) == NULL) {
+               pg_error_badrequest(
+                   "You did not specify a page to show.");
                return;
        } 
-       *sub++ = '\0';
-       if ( ! atou(path, &mr)) {
-               resp_error400();
-               return;
-       }
-       path = sub;
-       if (NULL == (sub = strchr(path, '/'))) {
-               resp_error400();
-               return;
-       }
-       *sub++ = '\0';
-       if ( ! atou(path, &vol) || ! atou(sub, &rec)) {
-               resp_error400();
-               return;
-       } else if (mr >= (unsigned int)req->psz) {
-               resp_error400();
+       manpath = mandoc_strndup(fullpath, file - fullpath);
+       file++;
+
+       if ( ! validate_manpath(req, manpath)) {
+               pg_error_badrequest(
+                   "You specified an invalid manpath.");
+               free(manpath);
                return;
        }
 
        /*
-        * Begin by chdir()ing into the manroot.
+        * Begin by chdir()ing into the manpath.
         * This way we can pick up the database files, which are
         * relative to the manpath root.
         */
 
-       if (-1 == chdir(req->p[(int)mr].path)) {
-               perror(req->p[(int)mr].path);
-               resp_baddb();
+       if (chdir(manpath) == -1) {
+               fprintf(stderr, "chdir %s: %s\n",
+                   manpath, strerror(errno));
+               pg_error_internal();
+               free(manpath);
                return;
        }
 
-       memset(&ps, 0, sizeof(struct manpaths));
-       manpath_manconf(&ps, "etc/catman.conf");
-
-       if (vol >= (unsigned int)ps.sz) {
-               resp_error400();
-               goto out;
-       }
-
-       sz = strlcpy(file, ps.paths[vol], PATH_MAX);
-       assert(sz < PATH_MAX);
-       strlcat(file, "/", PATH_MAX);
-       strlcat(file, MANDOC_IDX, PATH_MAX);
-
-       /* Open the index recno(3) database. */
-
-       idx = dbopen(file, O_RDONLY, 0, DB_RECNO, NULL);
-       if (NULL == idx) {
-               perror(file);
-               resp_baddb();
-               goto out;
-       }
-
-       key.data = &rec;
-       key.size = 4;
+       if (strcmp(manpath, "mandoc")) {
+               free(req->q.manpath);
+               req->q.manpath = manpath;
+       } else
+               free(manpath);
 
-       if (0 != (rc = (*idx->get)(idx, &key, &val, 0))) {
-               rc < 0 ? resp_baddb() : resp_error400();
-               goto out;
-       } else if (0 == val.size) {
-               resp_baddb();
-               goto out;
+       if ( ! validate_filename(file)) {
+               pg_error_badrequest(
+                   "You specified an invalid manual file.");
+               return;
        }
 
-       cp = (char *)val.data;
-       catm = 'c' == *cp++;
-
-       if (NULL == memchr(cp, '\0', val.size - 1)) 
-               resp_baddb();
-       else {
-               file[(int)sz] = '\0';
-               strlcat(file, "/", PATH_MAX);
-               strlcat(file, cp, PATH_MAX);
-               if (catm) 
-                       catman(req, file);
-               else
-                       format(req, file);
-       }
-out:
-       if (idx)
-               (*idx->close)(idx);
-       manpath_free(&ps);
+       resp_begin_html(200, NULL);
+       resp_searchform(req);
+       resp_show(req, file);
+       resp_end_html();
 }
 
 static void
-pg_search(const struct req *req, char *path)
+pg_search(const struct req *req)
 {
-       size_t            tt, ressz;
-       struct manpaths   ps;
-       int               i, sz, rc;
-       const char       *ep, *start;
-       struct res      *res;
-       char            **cp;
-       struct opts       opt;
-       struct expr      *expr;
-
-       if (req->q.manroot < 0 || 0 == req->psz) {
-               resp_search(NULL, 0, (void *)req);
-               return;
-       }
-
-       memset(&opt, 0, sizeof(struct opts));
-
-       ep       = req->q.expr;
-       opt.arch = req->q.arch;
-       opt.cat  = req->q.sec;
-       rc       = -1;
-       sz       = 0;
-       cp       = NULL;
-       ressz    = 0;
-       res      = NULL;
+       struct mansearch          search;
+       struct manpaths           paths;
+       struct manpage           *res;
+       char                    **cp;
+       const char               *ep, *start;
+       size_t                    ressz;
+       int                       i, sz;
 
        /*
         * Begin by chdir()ing into the root of the manpath.
@@ -916,26 +964,35 @@ pg_search(const struct req *req, char *path)
         * relative to the manpath root.
         */
 
-       assert(req->q.manroot < (int)req->psz);
-       if (-1 == (chdir(req->p[req->q.manroot].path))) {
-               perror(req->p[req->q.manroot].path);
-               resp_search(NULL, 0, (void *)req);
+       if (-1 == (chdir(req->q.manpath))) {
+               fprintf(stderr, "chdir %s: %s\n",
+                   req->q.manpath, strerror(errno));
+               pg_error_internal();
                return;
        }
 
-       memset(&ps, 0, sizeof(struct manpaths));
-       manpath_manconf(&ps, "etc/catman.conf");
+       search.arch = req->q.arch;
+       search.sec = req->q.sec;
+       search.deftype = req->q.equal ? TYPE_Nm : (TYPE_Nm | TYPE_Nd);
+       search.flags = req->q.equal ? MANSEARCH_MAN : 0;
+
+       paths.sz = 1;
+       paths.paths = mandoc_malloc(sizeof(char *));
+       paths.paths[0] = mandoc_strdup(".");
 
        /*
         * Poor man's tokenisation: just break apart by spaces.
         * Yes, this is half-ass.  But it works for now.
         */
 
+       ep = req->q.query;
        while (ep && isspace((unsigned char)*ep))
                ep++;
 
+       sz = 0;
+       cp = NULL;
        while (ep && '\0' != *ep) {
-               cp = mandoc_realloc(cp, (sz + 1) * sizeof(char *));
+               cp = mandoc_reallocarray(cp, sz + 1, sizeof(char *));
                start = ep;
                while ('\0' != *ep && ! isspace((unsigned char)*ep))
                        ep++;
@@ -946,288 +1003,148 @@ pg_search(const struct req *req, char *path)
                        ep++;
        }
 
-       /*
-        * Pump down into apropos backend.
-        * The resp_search() function is called with the results.
-        */
-
-       expr = req->q.legacy ? 
-               termcomp(sz, cp, &tt) : exprcomp(sz, cp, &tt);
-
-       if (NULL != expr)
-               rc = apropos_search
-                       (ps.sz, ps.paths, &opt, expr, tt, 
-                        (void *)req, &ressz, &res, resp_search);
-
-       /* ...unless errors occured. */
-
-       if (0 == rc)
-               resp_baddb();
-       else if (-1 == rc)
-               resp_search(NULL, 0, NULL);
+       if (0 == mansearch(&search, &paths, sz, cp, "Nd", &res, &ressz))
+               pg_noresult(req, "You entered an invalid query.");
+       else if (0 == ressz)
+               pg_noresult(req, "No results found.");
+       else
+               pg_searchres(req, res, ressz);
 
        for (i = 0; i < sz; i++)
                free(cp[i]);
-
        free(cp);
-       resfree(res, ressz);
-       exprfree(expr);
-       manpath_free(&ps);
+
+       for (i = 0; i < (int)ressz; i++) {
+               free(res[i].file);
+               free(res[i].names);
+               free(res[i].output);
+       }
+       free(res);
+
+       free(paths.paths[0]);
+       free(paths.paths);
 }
 
 int
 main(void)
 {
-       int              i;
-       char             buf[PATH_MAX];
-       DIR             *cwd;
        struct req       req;
-       char            *p, *path, *subpath;
+       const char      *path;
+       const char      *querystring;
+       int              i;
 
        /* Scan our run-time environment. */
 
-       if (NULL == (cache = getenv("CACHE_DIR")))
-               cache = "/cache/man.cgi";
-
-       if (NULL == (progname = getenv("SCRIPT_NAME")))
-               progname = "";
+       if (NULL == (scriptname = getenv("SCRIPT_NAME")))
+               scriptname = "";
 
-       if (NULL == (css = getenv("CSS_DIR")))
-               css = "";
-
-       if (NULL == (host = getenv("HTTP_HOST")))
-               host = "localhost";
+       if ( ! validate_urifrag(scriptname)) {
+               fprintf(stderr, "unsafe SCRIPT_NAME \"%s\"\n",
+                   scriptname);
+               pg_error_internal();
+               return(EXIT_FAILURE);
+       }
 
        /*
-        * First we change directory into the cache directory so that
+        * First we change directory into the MAN_DIR so that
         * subsequent scanning for manpath directories is rooted
         * relative to the same position.
         */
 
-       if (-1 == chdir(cache)) {
-               perror(cache);
-               resp_bad();
-               return(EXIT_FAILURE);
-       } else if (NULL == (cwd = opendir(cache))) {
-               perror(cache);
-               resp_bad();
+       if (-1 == chdir(MAN_DIR)) {
+               fprintf(stderr, "MAN_DIR: %s: %s\n",
+                   MAN_DIR, strerror(errno));
+               pg_error_internal();
                return(EXIT_FAILURE);
        } 
 
        memset(&req, 0, sizeof(struct req));
-
-       strlcpy(buf, ".", PATH_MAX);
-       pathgen(cwd, buf, &req);
-       closedir(cwd);
+       pathgen(&req);
 
        /* Next parse out the query string. */
 
-       if (NULL != (p = getenv("QUERY_STRING")))
-               http_parse(&req, p);
-
-       /*
-        * Now juggle paths to extract information.
-        * We want to extract our filetype (the file suffix), the
-        * initial path component, then the trailing component(s).
-        * Start with leading subpath component. 
-        */
+       if (NULL != (querystring = getenv("QUERY_STRING")))
+               http_parse(&req, querystring);
 
-       subpath = path = NULL;
-       req.page = PAGE__MAX;
-
-       if (NULL == (path = getenv("PATH_INFO")) || '\0' == *path)
-               req.page = PAGE_INDEX;
-
-       if (NULL != path && '/' == *path && '\0' == *++path)
-               req.page = PAGE_INDEX;
-
-       /* Strip file suffix. */
-
-       if (NULL != path && NULL != (p = strrchr(path, '.')))
-               if (NULL != p && NULL == strchr(p, '/'))
-                       *p++ = '\0';
-
-       /* Resolve subpath component. */
-
-       if (NULL != path && NULL != (subpath = strchr(path, '/')))
-               *subpath++ = '\0';
-
-       /* Map path into one we recognise. */
-
-       if (NULL != path && '\0' != *path)
-               for (i = 0; i < (int)PAGE__MAX; i++) 
-                       if (0 == strcmp(pages[i], path)) {
-                               req.page = (enum page)i;
-                               break;
-                       }
-
-       /* Route pages. */
-
-       switch (req.page) {
-       case (PAGE_INDEX):
-               pg_index(&req, subpath);
-               break;
-       case (PAGE_SEARCH):
-               pg_search(&req, subpath);
-               break;
-       case (PAGE_SHOW):
-               pg_show(&req, subpath);
-               break;
-       default:
-               resp_error404(path);
-               break;
+       if ( ! (NULL == req.q.manpath ||
+           validate_manpath(&req, req.q.manpath))) {
+               pg_error_badrequest(
+                   "You specified an invalid manpath.");
+               return(EXIT_FAILURE);
        }
 
-       for (i = 0; i < (int)req.psz; i++) {
-               free(req.p[i].path);
-               free(req.p[i].name);
+       if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
+               pg_error_badrequest(
+                   "You specified an invalid architecture.");
+               return(EXIT_FAILURE);
        }
 
-       free(req.p);
-       return(EXIT_SUCCESS);
-}
-
-static int
-cmp(const void *p1, const void *p2)
-{
-
-       return(strcasecmp(((const struct res *)p1)->title,
-                               ((const struct res *)p2)->title));
-}
+       /* Dispatch to the three different pages. */
 
-/*
- * Check to see if an "etc" path consists of a catman.conf file.  If it
- * does, that means that the path contains a tree created by catman(8)
- * and should be used for indexing.
- */
-static int
-pathstop(DIR *dir)
-{
-       struct dirent   *d;
-#if defined(__sun)
-       struct stat      sb;
-#endif
+       path = getenv("PATH_INFO");
+       if (NULL == path)
+               path = "";
+       else if ('/' == *path)
+               path++;
 
-       while (NULL != (d = readdir(dir))) {
-#if defined(__sun)
-               stat(d->d_name, &sb);
-               if (S_IFREG & sb.st_mode)
-#else
-               if (DT_REG == d->d_type)
-#endif
-                       if (0 == strcmp(d->d_name, "catman.conf"))
-                               return(1);
-  }
-
-       return(0);
+       if ('\0' != *path)
+               pg_show(&req, path);
+       else if (NULL != req.q.query)
+               pg_search(&req);
+       else
+               pg_index(&req);
+
+       free(req.q.manpath);
+       free(req.q.arch);
+       free(req.q.sec);
+       free(req.q.query);
+       for (i = 0; i < (int)req.psz; i++)
+               free(req.p[i]);
+       free(req.p);
+       return(EXIT_SUCCESS);
 }
 
 /*
  * Scan for indexable paths.
- * This adds all paths with "etc/catman.conf" to the buffer.
  */
 static void
-pathgen(DIR *dir, char *path, struct req *req)
+pathgen(struct req *req)
 {
-       struct dirent   *d;
-       char            *cp;
-       DIR             *cd;
-       int              rc;
-       size_t           sz, ssz;
-#if defined(__sun)
-       struct stat      sb;
-#endif
-
-       sz = strlcat(path, "/", PATH_MAX);
-       if (sz >= PATH_MAX) {
-               fprintf(stderr, "%s: Path too long", path);
-               return;
-       } 
-
-       /* 
-        * First, scan for the "etc" directory.
-        * If it's found, then see if it should cause us to stop.  This
-        * happens when a catman.conf is found in the directory.
-        */
-
-       rc = 0;
-       while (0 == rc && NULL != (d = readdir(dir))) {
-#if defined(__sun)
-               stat(d->d_name, &sb);
-               if (!(S_IFDIR & sb.st_mode)
-#else
-               if (DT_DIR != d->d_type
-#endif
-        || strcmp(d->d_name, "etc"))
-                       continue;
-
-               path[(int)sz] = '\0';
-               ssz = strlcat(path, d->d_name, PATH_MAX);
-
-               if (ssz >= PATH_MAX) {
-                       fprintf(stderr, "%s: Path too long", path);
-                       return;
-               } else if (NULL == (cd = opendir(path))) {
-                       perror(path);
-                       return;
-               } 
-               
-               rc = pathstop(cd);
-               closedir(cd);
+       FILE    *fp;
+       char    *dp;
+       size_t   dpsz;
+
+       if (NULL == (fp = fopen("manpath.conf", "r"))) {
+               fprintf(stderr, "%s/manpath.conf: %s\n",
+                       MAN_DIR, strerror(errno));
+               pg_error_internal();
+               exit(EXIT_FAILURE);
        }
 
-       if (rc > 0) {
-               /* This also strips the trailing slash. */
-               path[(int)--sz] = '\0';
-               req->p = mandoc_realloc
-                       (req->p, 
-                        (req->psz + 1) * sizeof(struct paths));
-               /*
-                * Strip out the leading "./" unless we're just a ".",
-                * in which case use an empty string as our name.
-                */
-               req->p[(int)req->psz].path = mandoc_strdup(path);
-               req->p[(int)req->psz].name = 
-                       cp = mandoc_strdup(path + (1 == sz ? 1 : 2));
-               req->psz++;
-               /* 
-                * The name is just the path with all the slashes taken
-                * out of it.  Simple but effective. 
-                */
-               for ( ; '\0' != *cp; cp++) 
-                       if ('/' == *cp)
-                               *cp = ' ';
-               return;
-       } 
-
-       /*
-        * If no etc/catman.conf was found, recursively enter child
-        * directory and continue scanning.
-        */
-
-       rewinddir(dir);
-       while (NULL != (d = readdir(dir))) {
-#if defined(__sun)
-               stat(d->d_name, &sb);
-               if (!(S_IFDIR & sb.st_mode)
-#else
-               if (DT_DIR != d->d_type
-#endif
-        || '.' == d->d_name[0])
-                       continue;
-
-               path[(int)sz] = '\0';
-               ssz = strlcat(path, d->d_name, PATH_MAX);
-
-               if (ssz >= PATH_MAX) {
-                       fprintf(stderr, "%s: Path too long", path);
-                       return;
-               } else if (NULL == (cd = opendir(path))) {
-                       perror(path);
-                       return;
+       while (NULL != (dp = fgetln(fp, &dpsz))) {
+               if ('\n' == dp[dpsz - 1])
+                       dpsz--;
+               req->p = mandoc_realloc(req->p,
+                   (req->psz + 1) * sizeof(char *));
+               dp = mandoc_strndup(dp, dpsz);
+               if ( ! validate_urifrag(dp)) {
+                       fprintf(stderr, "%s/manpath.conf contains "
+                           "unsafe path \"%s\"\n", MAN_DIR, dp);
+                       pg_error_internal();
+                       exit(EXIT_FAILURE);
+               }
+               if (NULL != strchr(dp, '/')) {
+                       fprintf(stderr, "%s/manpath.conf contains "
+                           "path with slash \"%s\"\n", MAN_DIR, dp);
+                       pg_error_internal();
+                       exit(EXIT_FAILURE);
                }
+               req->p[req->psz++] = dp;
+       }
 
-               pathgen(cd, path, req);
-               closedir(cd);
+       if ( req->p == NULL ) {
+               fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR);
+               pg_error_internal();
+               exit(EXIT_FAILURE);
        }
 }
diff --git a/contrib/mdocml/cgi.h.example b/contrib/mdocml/cgi.h.example
new file mode 100644 (file)
index 0000000..f4c7831
--- /dev/null
@@ -0,0 +1,9 @@
+/* Example compile-time configuration file for man.cgi(8). */
+
+#define        HTTP_HOST "mdocml.bsd.lv"
+#define        MAN_DIR "/var/www/man"
+#define        CSS_DIR ""
+#define        CUSTOMIZE_TITLE "Manual pages with mandoc"
+#define        CUSTOMIZE_BEGIN "<H2>\nManual pages with " \
+       "<A HREF=\"http://mdocml.bsd.lv/\">mandoc</A>\n</H2>"
+#define        COMPAT_OLDURI Yes
index 3ad1f57..d758d0c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: chars.c,v 1.54 2013/06/20 22:39:30 schwarze Exp $ */
+/*     $Id: chars.c,v 1.58 2014/07/23 15:00:08 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include "mandoc.h"
+#include "mandoc_aux.h"
 #include "libmandoc.h"
 
 #define        PRINT_HI         126
@@ -37,7 +38,7 @@ struct        ln {
        int               unicode;
 };
 
-#define        LINES_MAX         329
+#define        LINES_MAX         330
 
 #define CHAR(in, ch, code) \
        { NULL, (in), (ch), (code) },
@@ -51,9 +52,10 @@ struct       mchars {
        struct ln       **htab;
 };
 
-static const struct ln  *find(const struct mchars *, 
+static const struct ln  *find(const struct mchars *,
                                const char *, size_t);
 
+
 void
 mchars_free(struct mchars *arg)
 {
@@ -110,27 +112,38 @@ mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
 char
 mchars_num2char(const char *p, size_t sz)
 {
-       int               i;
+       int       i;
 
        if ((i = mandoc_strntoi(p, sz, 10)) < 0)
                return('\0');
-       return(i > 0 && i < 256 && isprint(i) ? 
-                       /* LINTED */ i : '\0');
+
+       return(i > 0 && i < 256 && isprint(i) ? i : '\0');
 }
 
 int
 mchars_num2uc(const char *p, size_t sz)
 {
-       int               i;
+       int      i;
 
        if ((i = mandoc_strntoi(p, sz, 16)) < 0)
                return('\0');
-       /* FIXME: make sure we're not in a bogus range. */
+
+       /*
+        * Security warning:
+        * Never extend the range of accepted characters
+        * to overlap with the ASCII range, 0x00-0x7F
+        * without re-auditing the callers of this function.
+        * Some callers might relay on the fact that we never
+        * return ASCII characters for their escaping decisions.
+        *
+        * XXX Code is missing here to exclude bogus ranges.
+        */
+
        return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
 }
 
 const char *
-mchars_spec2str(const struct mchars *arg, 
+mchars_spec2str(const struct mchars *arg,
                const char *p, size_t sz, size_t *rsz)
 {
        const struct ln *ln;
@@ -159,8 +172,8 @@ find(const struct mchars *tab, const char *p, size_t sz)
        hash = (int)p[0] - PRINT_LO;
 
        for (pp = tab->htab[hash]; pp; pp = pp->next)
-               if (0 == strncmp(pp->code, p, sz) && 
-                               '\0' == pp->code[(int)sz])
+               if (0 == strncmp(pp->code, p, sz) &&
+                   '\0' == pp->code[(int)sz])
                        return(pp);
 
        return(NULL);
index cc6549e..098504f 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: chars.in,v 1.43 2013/06/20 22:39:30 schwarze Exp $ */
+/*     $Id: chars.in,v 1.46 2014/04/20 16:46:04 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@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
@@ -16,7 +17,7 @@
  */
 
 /*
- * The ASCII translation tables.  
+ * The ASCII translation tables.
  *
  * The left-hand side corresponds to the input sequence (\x, \(xx, \*(xx
  * and so on) whose length is listed second element.  The right-hand
  * XXX - update LINES_MAX if adding more!
  */
 
-/* Non-breaking, non-collapsing space uses unit separator. */
+/* Special break control characters. */
 static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
+static const char ascii_break[2] = { ASCII_BREAK, '\0' };
 
 CHAR_TBL_START
 
 /* Spacing. */
-CHAR("c",                      "",             0)
-CHAR("0",                      " ",            8194)
 CHAR(" ",                      ascii_nbrsp,    160)
 CHAR("~",                      ascii_nbrsp,    160)
-CHAR("%",                      "",             0)
-CHAR("&",                      "",             0)
-CHAR("^",                      "",             0)
+CHAR("0",                      " ",            8194)
 CHAR("|",                      "",             0)
-CHAR("}",                      "",             0)
+CHAR("^",                      "",             0)
+CHAR("&",                      "",             0)
+CHAR("%",                      "",             0)
+CHAR(":",                      ascii_break,    0)
+/* XXX The following three do not really belong into this file. */
 CHAR("t",                      "",             0)
+CHAR("c",                      "",             0)
+CHAR("}",                      "",             0)
 
 /* Accents. */
-CHAR("a\"",                    "\"",           779)
+CHAR("a\"",                    "\"",           733)
 CHAR("a-",                     "-",            175)
 CHAR("a.",                     ".",            729)
-CHAR("a^",                     "^",            770)
-CHAR("\'",                     "\'",           769)
-CHAR("aa",                     "\'",           769)
-CHAR("ga",                     "`",            768)
-CHAR("`",                      "`",            768)
-CHAR("ab",                     "`",            774)
-CHAR("ac",                     ",",            807)
-CHAR("ad",                     "\"",           776)
+CHAR("a^",                     "^",            94)
+CHAR("\'",                     "\'",           180)
+CHAR("aa",                     "\'",           180)
+CHAR("ga",                     "`",            96)
+CHAR("`",                      "`",            96)
+CHAR("ab",                     "`",            728)
+CHAR("ac",                     ",",            184)
+CHAR("ad",                     "\"",           168)
 CHAR("ah",                     "v",            711)
 CHAR("ao",                     "o",            730)
-CHAR("a~",                     "~",            771)
-CHAR("ho",                     ",",            808)
+CHAR("a~",                     "~",            126)
+CHAR("ho",                     ",",            731)
 CHAR("ha",                     "^",            94)
 CHAR("ti",                     "~",            126)
 
diff --git a/contrib/mdocml/compat_ohash.c b/contrib/mdocml/compat_ohash.c
new file mode 100644 (file)
index 0000000..0992b36
--- /dev/null
@@ -0,0 +1,339 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_OHASH
+
+int dummy;
+
+#else
+
+/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
+
+/* Copyright (c) 1999, 2004 Marc Espie <espie@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 <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "compat_ohash.h"
+
+struct _ohash_record {
+       uint32_t        hv;
+       const char      *p;
+};
+
+#define DELETED                ((const char *)h)
+#define NONE           (h->size)
+
+/* Don't bother changing the hash table if the change is small enough.  */
+#define MINSIZE                (1UL << 4)
+#define MINDELETED     4
+
+static void ohash_resize(struct ohash *);
+
+
+/* This handles the common case of variable length keys, where the
+ * key is stored at the end of the record.
+ */
+void *
+ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
+{
+       char *p;
+
+       if (!*end)
+               *end = start + strlen(start);
+       p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
+       if (p) {
+               memcpy(p+i->key_offset, start, *end-start);
+               p[i->key_offset + (*end - start)] = '\0';
+       }
+       return (void *)p;
+}
+
+/* hash_delete only frees the hash structure. Use hash_first/hash_next
+ * to free entries as well.  */
+void
+ohash_delete(struct ohash *h)
+{
+       (h->info.free)(h->t, h->info.data);
+#ifndef NDEBUG
+       h->t = NULL;
+#endif
+}
+
+static void
+ohash_resize(struct ohash *h)
+{
+       struct _ohash_record *n;
+       size_t ns;
+       unsigned int    j;
+       unsigned int    i, incr;
+
+       if (4 * h->deleted < h->total) {
+               if (h->size >= (UINT_MAX >> 1U))
+                       ns = UINT_MAX;
+               else
+                       ns = h->size << 1U;
+       } else if (3 * h->deleted > 2 * h->total)
+               ns = h->size >> 1U;
+       else
+               ns = h->size;
+       if (ns < MINSIZE)
+               ns = MINSIZE;
+#ifdef STATS_HASH
+       STAT_HASH_EXPAND++;
+       STAT_HASH_SIZE += ns - h->size;
+#endif
+
+       n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
+       if (!n)
+               return;
+
+       for (j = 0; j < h->size; j++) {
+               if (h->t[j].p != NULL && h->t[j].p != DELETED) {
+                       i = h->t[j].hv % ns;
+                       incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
+                       while (n[i].p != NULL) {
+                               i += incr;
+                               if (i >= ns)
+                                       i -= ns;
+                       }
+                       n[i].hv = h->t[j].hv;
+                       n[i].p = h->t[j].p;
+               }
+       }
+       (h->info.free)(h->t, h->info.data);
+       h->t = n;
+       h->size = ns;
+       h->total -= h->deleted;
+       h->deleted = 0;
+}
+
+void *
+ohash_remove(struct ohash *h, unsigned int i)
+{
+       void            *result = (void *)h->t[i].p;
+
+       if (result == NULL || result == DELETED)
+               return NULL;
+
+#ifdef STATS_HASH
+       STAT_HASH_ENTRIES--;
+#endif
+       h->t[i].p = DELETED;
+       h->deleted++;
+       if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
+               ohash_resize(h);
+       return result;
+}
+
+void *
+ohash_find(struct ohash *h, unsigned int i)
+{
+       if (h->t[i].p == DELETED)
+               return NULL;
+       else
+               return (void *)h->t[i].p;
+}
+
+void *
+ohash_insert(struct ohash *h, unsigned int i, void *p)
+{
+#ifdef STATS_HASH
+       STAT_HASH_ENTRIES++;
+#endif
+       if (h->t[i].p == DELETED) {
+               h->deleted--;
+               h->t[i].p = p;
+       } else {
+               h->t[i].p = p;
+               /* Arbitrary resize boundary.  Tweak if not efficient enough.  */
+               if (++h->total * 4 > h->size * 3)
+                       ohash_resize(h);
+       }
+       return p;
+}
+
+unsigned int
+ohash_entries(struct ohash *h)
+{
+       return h->total - h->deleted;
+}
+
+void *
+ohash_first(struct ohash *h, unsigned int *pos)
+{
+       *pos = 0;
+       return ohash_next(h, pos);
+}
+
+void *
+ohash_next(struct ohash *h, unsigned int *pos)
+{
+       for (; *pos < h->size; (*pos)++)
+               if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
+                       return (void *)h->t[(*pos)++].p;
+       return NULL;
+}
+
+void
+ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
+{
+       h->size = 1UL << size;
+       if (h->size < MINSIZE)
+               h->size = MINSIZE;
+#ifdef STATS_HASH
+       STAT_HASH_CREATION++;
+       STAT_HASH_SIZE += h->size;
+#endif
+       /* Copy info so that caller may free it.  */
+       h->info.key_offset = info->key_offset;
+       h->info.calloc = info->calloc;
+       h->info.free = info->free;
+       h->info.alloc = info->alloc;
+       h->info.data = info->data;
+       h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
+                   h->info.data);
+       h->total = h->deleted = 0;
+}
+
+uint32_t
+ohash_interval(const char *s, const char **e)
+{
+       uint32_t k;
+
+       if (!*e)
+               *e = s + strlen(s);
+       if (s == *e)
+               k = 0;
+       else
+               k = *s++;
+       while (s != *e)
+               k =  ((k << 2) | (k >> 30)) ^ *s++;
+       return k;
+}
+
+unsigned int
+ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
+    uint32_t hv)
+{
+       unsigned int    i, incr;
+       unsigned int    empty;
+
+#ifdef STATS_HASH
+       STAT_HASH_LOOKUP++;
+#endif
+       empty = NONE;
+       i = hv % h->size;
+       incr = ((hv % (h->size-2)) & ~1) + 1;
+       while (h->t[i].p != NULL) {
+#ifdef STATS_HASH
+               STAT_HASH_LENGTH++;
+#endif
+               if (h->t[i].p == DELETED) {
+                       if (empty == NONE)
+                               empty = i;
+               } else if (h->t[i].hv == hv &&
+                   strncmp(h->t[i].p+h->info.key_offset, start,
+                       end - start) == 0 &&
+                   (h->t[i].p+h->info.key_offset)[end-start] == '\0') {
+                       if (empty != NONE) {
+                               h->t[empty].hv = hv;
+                               h->t[empty].p = h->t[i].p;
+                               h->t[i].p = DELETED;
+                               return empty;
+                       } else {
+#ifdef STATS_HASH
+                               STAT_HASH_POSITIVE++;
+#endif
+                               return i;
+                       }
+               }
+               i += incr;
+               if (i >= h->size)
+                       i -= h->size;
+       }
+
+       /* Found an empty position.  */
+       if (empty != NONE)
+               i = empty;
+       h->t[i].hv = hv;
+       return i;
+}
+
+unsigned int
+ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
+{
+       unsigned int    i, incr;
+       unsigned int    empty;
+
+#ifdef STATS_HASH
+       STAT_HASH_LOOKUP++;
+#endif
+       empty = NONE;
+       i = hv % h->size;
+       incr = ((hv % (h->size-2)) & ~1) + 1;
+       while (h->t[i].p != NULL) {
+#ifdef STATS_HASH
+               STAT_HASH_LENGTH++;
+#endif
+               if (h->t[i].p == DELETED) {
+                       if (empty == NONE)
+                               empty = i;
+               } else if (h->t[i].hv == hv &&
+                   memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
+                       if (empty != NONE) {
+                               h->t[empty].hv = hv;
+                               h->t[empty].p = h->t[i].p;
+                               h->t[i].p = DELETED;
+                               return empty;
+                       } else {
+#ifdef STATS_HASH
+                               STAT_HASH_POSITIVE++;
+#endif
+                       }       return i;
+               }
+               i += incr;
+               if (i >= h->size)
+                       i -= h->size;
+       }
+
+       /* Found an empty position.  */
+       if (empty != NONE)
+               i = empty;
+       h->t[i].hv = hv;
+       return i;
+}
+
+unsigned int
+ohash_qlookup(struct ohash *h, const char *s)
+{
+       const char *e = NULL;
+       return ohash_qlookupi(h, s, &e);
+}
+
+unsigned int
+ohash_qlookupi(struct ohash *h, const char *s, const char **e)
+{
+       uint32_t hv;
+
+       hv = ohash_interval(s, e);
+       return ohash_lookup_interval(h, s, *e, hv);
+}
+
+#endif /*!HAVE_OHASH*/
diff --git a/contrib/mdocml/compat_ohash.h b/contrib/mdocml/compat_ohash.h
new file mode 100644 (file)
index 0000000..e3124c9
--- /dev/null
@@ -0,0 +1,73 @@
+/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */
+
+/* Copyright (c) 1999, 2004 Marc Espie <espie@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 OHASH_H
+#define OHASH_H
+
+/* Open hashing support. 
+ * Open hashing was chosen because it is much lighter than other hash
+ * techniques, and more efficient in most cases.
+ */
+
+/* user-visible data structure */
+struct ohash_info {
+       ptrdiff_t key_offset;
+       void *data;     /* user data */
+       void *(*calloc)(size_t, size_t, void *);
+       void (*free)(void *, void *);
+       void *(*alloc)(size_t, void *);
+};
+
+struct _ohash_record;
+
+/* private structure. It's there just so you can do a sizeof */
+struct ohash {
+       struct _ohash_record    *t;
+       struct ohash_info       info;
+       unsigned int            size;
+       unsigned int            total;
+       unsigned int            deleted;
+};
+
+/* For this to be tweakable, we use small primitives, and leave part of the
+ * logic to the client application.  e.g., hashing is left to the client
+ * application.  We also provide a simple table entry lookup that yields
+ * a hashing table index (opaque) to be used in find/insert/remove.
+ * The keys are stored at a known position in the client data.
+ */
+__BEGIN_DECLS
+void ohash_init(struct ohash *, unsigned, struct ohash_info *);
+void ohash_delete(struct ohash *);
+
+unsigned int ohash_lookup_interval(struct ohash *, const char *,
+           const char *, uint32_t);
+unsigned int ohash_lookup_memory(struct ohash *, const char *,
+           size_t, uint32_t);
+void *ohash_find(struct ohash *, unsigned int);
+void *ohash_remove(struct ohash *, unsigned int);
+void *ohash_insert(struct ohash *, unsigned int, void *);
+void *ohash_first(struct ohash *, unsigned int *);
+void *ohash_next(struct ohash *, unsigned int *);
+unsigned int ohash_entries(struct ohash *);
+
+void *ohash_create_entry(struct ohash_info *, const char *, const char **);
+uint32_t ohash_interval(const char *, const char **);
+
+unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
+unsigned int ohash_qlookup(struct ohash *, const char *);
+__END_DECLS
+#endif
similarity index 59%
copy from contrib/mdocml/lib.c
copy to contrib/mdocml/compat_reallocarray.c
index 7a18a5d..e25d837 100644 (file)
@@ -1,6 +1,16 @@
-/*     $Id: lib.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_REALLOCARRAY
+
+int dummy;
+
+#else
+
+/*     $OpenBSD: malloc.c,v 1.158 2014/04/23 15:07:27 tedu Exp $       */
 /*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
 #include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "mdoc.h"
-#include "mandoc.h"
-#include "libmdoc.h"
 
-#define LINE(x, y) \
-       if (0 == strcmp(p, x)) return(y);
+#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
 
-const char *
-mdoc_a2lib(const char *p)
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
 {
-
-#include "lib.in"
-
-       return(NULL);
+       if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+           nmemb > 0 && SIZE_MAX / nmemb < size) {
+               errno = ENOMEM;
+               return NULL;
+       }
+       return realloc(optr, size * nmemb);
 }
+
+#endif /*!HAVE_REALLOCARRAY*/
diff --git a/contrib/mdocml/compat_sqlite3_errstr.c b/contrib/mdocml/compat_sqlite3_errstr.c
new file mode 100644 (file)
index 0000000..b8d6eb5
--- /dev/null
@@ -0,0 +1,18 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SQLITE3_ERRSTR
+
+int dummy;
+
+#else
+
+const char *
+sqlite3_errstr(int rc)
+{
+
+       return(rc ? "unknown error" : "not an error");
+}
+
+#endif
diff --git a/contrib/mdocml/compat_strcasestr.c b/contrib/mdocml/compat_strcasestr.c
new file mode 100644 (file)
index 0000000..5216d02
--- /dev/null
@@ -0,0 +1,74 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRCASESTR
+
+int dummy;
+
+#else
+
+/*     ($)NetBSD: strcasestr.c,v 1.2 2005/02/09 21:35:47 kleink Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+
+#define        __UNCONST(a)    ((void *)(unsigned long)(const void *)(a))
+
+/*
+ * Find the first occurrence of find in s, ignore case.
+ */
+char *
+strcasestr(const char *s, const char *find)
+{
+       char c, sc;
+       size_t len;
+
+       if ((c = *find++) != 0) {
+               c = tolower((unsigned char)c);
+               len = strlen(find);
+               do {
+                       do {
+                               if ((sc = *s++) == 0)
+                                       return (NULL);
+                       } while ((char)tolower((unsigned char)sc) != c);
+               } while (strncasecmp(s, find, len) != 0);
+               s--;
+       }
+       return __UNCONST(s);
+}
+
+#endif
diff --git a/contrib/mdocml/compat_strsep.c b/contrib/mdocml/compat_strsep.c
new file mode 100644 (file)
index 0000000..a5c58c6
--- /dev/null
@@ -0,0 +1,80 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRSEP
+
+int dummy;
+
+#else
+
+/*     ($)OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $      */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.  
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+       char *s;
+       const char *spanp;
+       int c, sc;
+       char *tok;
+
+       if ((s = *stringp) == NULL)
+               return (NULL);
+       for (tok = s;;) {
+               c = *s++;
+               spanp = delim;
+               do {
+                       if ((sc = *spanp++) == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else
+                                       s[-1] = 0;
+                               *stringp = s;
+                               return (tok);
+                       }
+               } while (sc != 0);
+       }
+       /* NOTREACHED */
+}
+
+#endif
index 9a33671..e95f5f5 100644 (file)
@@ -1,5 +1,3 @@
-#include <sys/types.h>
-
 #if !defined(__BEGIN_DECLS)
 #  ifdef __cplusplus
 #  define      __BEGIN_DECLS           extern "C" {
 #  endif
 #endif
 
-#ifndef HAVE_BETOH64
-#  if defined(__APPLE__)
-#    define betoh64(x) OSSwapBigToHostInt64(x)
-#    define htobe64(x) OSSwapHostToBigInt64(x)
-#  elif defined(__sun)
-#    define betoh64(x) BE_64(x)
-#    define htobe64(x) BE_64(x)
-#  else
-#    define betoh64(x) be64toh(x)
-#  endif
+#ifndef HAVE_FGETLN
+extern char     *fgetln(FILE *, size_t *);
+#endif
+#ifndef HAVE_GETSUBOPT
+extern int       getsubopt(char **, char * const *, char **);
+extern char     *suboptarg;
+#endif
+#ifndef HAVE_REALLOCARRAY
+extern void     *reallocarray(void *, size_t, size_t);
+#endif
+#ifndef HAVE_SQLITE3_ERRSTR
+extern const char *sqlite3_errstr(int);
+#endif
+#ifndef HAVE_STRCASESTR
+extern char     *strcasestr(const char *, const char *);
 #endif
-
 #ifndef HAVE_STRLCAT
 extern size_t    strlcat(char *, const char *, size_t);
 #endif
 #ifndef HAVE_STRLCPY
 extern size_t    strlcpy(char *, const char *, size_t);
 #endif
-#ifndef HAVE_GETSUBOPT
-extern int       getsubopt(char **, char * const *, char **);
-extern char     *suboptarg;
-#endif
-#ifndef HAVE_FGETLN
-extern char     *fgetln(FILE *, size_t *);
+#ifndef HAVE_STRSEP
+extern char     *strsep(char **, const char *);
 #endif
 
 #endif /* MANDOC_CONFIG_H */
index bc59478..1c3940d 100644 (file)
@@ -2,7 +2,8 @@
 #define        MANDOC_CONFIG_H
 
 #if defined(__linux__) || defined(__MINT__)
-# define _GNU_SOURCE /* strptime(), getsubopt() */
+# define _GNU_SOURCE /* getsubopt(), strcasestr(), strptime() */
 #endif
 
+#include <sys/types.h>
 #include <stdio.h>
diff --git a/contrib/mdocml/configure b/contrib/mdocml/configure
new file mode 100755 (executable)
index 0000000..5b987eb
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Ingo Schwarze <schwarze@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.
+
+echo "/* RUNNING ./CONFIGURE - SHOULD BE USED ONLY VIA MAKE, READ INSTALL */"
+
+set -e
+exec > config.h 2> config.log
+
+CFLAGS="${CFLAGS} -Wno-unused -Werror"
+
+runtest() {
+       echo ${CC} ${CFLAGS} ${3} -o test-${1} test-${1}.c 1>&2
+       ${CC} ${CFLAGS} ${3} -o "test-${1}" "test-${1}.c" 1>&2 || return 0
+       "./test-${1}" && echo "#define HAVE_${2}" \
+               || echo FAILURE: test-${1} returned $? 1>&2
+       rm "test-${1}"
+}
+
+cat config.h.pre
+echo
+echo "#define VERSION \"${VERSION}\""
+runtest fgetln FGETLN
+runtest getsubopt GETSUBOPT
+runtest mmap MMAP
+runtest ohash OHASH "${DBLIB}"
+runtest reallocarray REALLOCARRAY
+runtest sqlite3_errstr SQLITE3_ERRSTR "${DBLIB}"
+runtest strcasestr STRCASESTR
+runtest strlcat STRLCAT
+runtest strlcpy STRLCPY
+runtest strptime STRPTIME
+runtest strsep STRSEP
+echo
+cat config.h.post
+
+exit 0
index aad4208..4a7b979 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: demandoc.c,v 1.7 2012/05/31 22:27:14 schwarze Exp $ */
+/*     $Id: demandoc.c,v 1.10 2014/03/19 22:20:43 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -76,7 +76,7 @@ main(int argc, char *argv[])
        argc -= optind;
        argv += optind;
 
-       mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL, NULL);
+       mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, NULL);
        assert(mp);
 
        if (0 == argc)
@@ -110,7 +110,7 @@ pmandoc(struct mparse *mp, int fd, const char *fn, int list)
                return;
        }
 
-       mparse_result(mp, &mdoc, &man);
+       mparse_result(mp, &mdoc, &man, NULL);
        line = 1;
        col = 0;
 
index 37f01bc..cda0db5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */
+/*     $Id: eqn.c,v 1.44 2014/07/06 19:09:00 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -26,6 +26,7 @@
 #include <time.h>
 
 #include "mandoc.h"
+#include "mandoc_aux.h"
 #include "libmandoc.h"
 #include "libroff.h"
 
@@ -137,12 +138,11 @@ struct    eqnsym {
        const char      *sym;
 };
 
-
 static enum eqn_rest    eqn_box(struct eqn_node *, struct eqn_box *);
-static struct eqn_box  *eqn_box_alloc(struct eqn_node *, 
+static struct eqn_box  *eqn_box_alloc(struct eqn_node *,
                                struct eqn_box *);
 static void             eqn_box_free(struct eqn_box *);
-static struct eqn_def  *eqn_def_find(struct eqn_node *, 
+static struct eqn_def  *eqn_def_find(struct eqn_node *,
                                const char *, size_t);
 static int              eqn_do_gfont(struct eqn_node *);
 static int              eqn_do_gsize(struct eqn_node *);
@@ -156,7 +156,7 @@ static      enum eqn_rest    eqn_list(struct eqn_node *, struct eqn_box *);
 static enum eqn_rest    eqn_matrix(struct eqn_node *, struct eqn_box *);
 static const char      *eqn_nexttok(struct eqn_node *, size_t *);
 static const char      *eqn_nextrawtok(struct eqn_node *, size_t *);
-static const char      *eqn_next(struct eqn_node *, 
+static const char      *eqn_next(struct eqn_node *,
                                char, size_t *, int);
 static void             eqn_rewind(struct eqn_node *);
 
@@ -277,9 +277,9 @@ static      const struct eqnsym eqnsyms[EQNSYM__MAX] = {
        { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
 };
 
-/* ARGSUSED */
+
 enum rofferr
-eqn_read(struct eqn_node **epp, int ln, 
+eqn_read(struct eqn_node **epp, int ln,
                const char *p, int pos, int *offs)
 {
        size_t           sz;
@@ -298,9 +298,10 @@ eqn_read(struct eqn_node **epp, int ln,
                p += 3;
                while (' ' == *p || '\t' == *p)
                        p++;
-               if ('\0' == *p) 
+               if ('\0' == *p)
                        return(er);
-               mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL);
+               mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
+                   ln, pos, "EN %s", p);
                return(er);
        }
 
@@ -413,11 +414,11 @@ eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
 
        while (EQN_OK == (c = eqn_box(ep, bp)))
                switch (bp->last->pile) {
-               case (EQNPILE_LCOL):
+               case EQNPILE_LCOL:
                        /* FALLTHROUGH */
-               case (EQNPILE_CCOL):
+               case EQNPILE_CCOL:
                        /* FALLTHROUGH */
-               case (EQNPILE_RCOL):
+               case EQNPILE_RCOL:
                        continue;
                default:
                        EQN_MSG(MANDOCERR_EQNSYNT, ep);
@@ -512,9 +513,8 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
        for (i = 0; i < (int)EQN__MAX; i++) {
                if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
                        continue;
-               return((*eqnparts[i].fp)(ep) ? 
-                               EQN_OK : EQN_ERR);
-       } 
+               return((*eqnparts[i].fp)(ep) ? EQN_OK : EQN_ERR);
+       }
 
        if (STRNEQ(start, sz, "{", 1)) {
                if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
@@ -529,7 +529,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
                        return(EQN_OK);
                EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
                return(EQN_ERR);
-       } 
+       }
 
        for (i = 0; i < (int)EQNPILE__MAX; i++) {
                if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
@@ -575,7 +575,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
                if (NULL == last->last) {
                        EQN_MSG(MANDOCERR_EQNSYNT, ep);
                        return(EQN_ERR);
-               } 
+               }
                last->last->pos = (enum eqn_post)i;
                if (EQN_EOF == (c = eqn_box(ep, last))) {
                        EQN_MSG(MANDOCERR_EQNEOF, ep);
@@ -590,7 +590,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
                if (NULL == last->last) {
                        EQN_MSG(MANDOCERR_EQNSYNT, ep);
                        return(EQN_ERR);
-               } 
+               }
                last->last->mark = (enum eqn_markt)i;
                if (EQN_EOF == (c = eqn_box(ep, last))) {
                        EQN_MSG(MANDOCERR_EQNEOF, ep);
@@ -629,7 +629,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
        for (i = 0; i < (int)EQNSYM__MAX; i++)
                if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
                        sym[63] = '\0';
-                       snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
+                       (void)snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
                        bp->text = mandoc_strdup(sym);
                        return(EQN_OK);
                }
@@ -762,13 +762,13 @@ again:
                if (q)
                        ep->cur++;
                while (' ' == ep->data[(int)ep->cur] ||
-                               '\t' == ep->data[(int)ep->cur] ||
-                               '^' == ep->data[(int)ep->cur] ||
-                               '~' == ep->data[(int)ep->cur])
+                   '\t' == ep->data[(int)ep->cur] ||
+                   '^' == ep->data[(int)ep->cur] ||
+                   '~' == ep->data[(int)ep->cur])
                        ep->cur++;
        } else {
                if (q)
-                       EQN_MSG(MANDOCERR_BADQUOTE, ep);
+                       EQN_MSG(MANDOCERR_ARG_QUOTE, ep);
                next = strchr(start, '\0');
                *sz = (size_t)(next - start);
                ep->cur += *sz;
@@ -790,8 +790,8 @@ again:
                }
 
                diff = def->valsz - *sz;
-               memmove(start + *sz + diff, start + *sz, 
-                               (strlen(start) - *sz) + 1);
+               memmove(start + *sz + diff, start + *sz,
+                   (strlen(start) - *sz) + 1);
                memcpy(start, def->val, def->valsz);
                goto again;
        }
@@ -852,8 +852,8 @@ eqn_do_define(struct eqn_node *ep)
                return(0);
        }
 
-       /* 
-        * Search for a key that already exists. 
+       /*
+        * Search for a key that already exists.
         * Create a new key if none is found.
         */
 
@@ -865,15 +865,14 @@ eqn_do_define(struct eqn_node *ep)
 
                if (i == (int)ep->defsz) {
                        ep->defsz++;
-                       ep->defs = mandoc_realloc
-                               (ep->defs, ep->defsz * 
-                                sizeof(struct eqn_def));
+                       ep->defs = mandoc_reallocarray(ep->defs,
+                           ep->defsz, sizeof(struct eqn_def));
                        ep->defs[i].key = ep->defs[i].val = NULL;
                }
 
                ep->defs[i].keysz = sz;
-               ep->defs[i].key = mandoc_realloc
-                       (ep->defs[i].key, sz + 1);
+               ep->defs[i].key = mandoc_realloc(
+                   ep->defs[i].key, sz + 1);
 
                memcpy(ep->defs[i].key, start, sz);
                ep->defs[i].key[(int)sz] = '\0';
@@ -901,7 +900,7 @@ eqn_do_gfont(struct eqn_node *ep)
        if (NULL == eqn_nextrawtok(ep, NULL)) {
                EQN_MSG(MANDOCERR_EQNEOF, ep);
                return(0);
-       } 
+       }
        return(1);
 }
 
@@ -914,7 +913,7 @@ eqn_do_gsize(struct eqn_node *ep)
        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
                EQN_MSG(MANDOCERR_EQNEOF, ep);
                return(0);
-       } 
+       }
        ep->gsize = mandoc_strntoi(start, sz, 10);
        return(1);
 }
@@ -940,9 +939,9 @@ eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
 {
        int              i;
 
-       for (i = 0; i < (int)ep->defsz; i++) 
-               if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key, 
-                                       ep->defs[i].keysz, key, sz))
+       for (i = 0; i < (int)ep->defsz; i++)
+               if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
+                   ep->defs[i].keysz, key, sz))
                        return(&ep->defs[i]);
 
        return(NULL);
index 80c82f1..3e58ab5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: eqn_html.c,v 1.2 2011/07/24 10:09:03 kristaps Exp $ */
+/*     $Id: eqn_html.c,v 1.3 2014/04/20 16:46:04 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -35,9 +35,9 @@ static        const enum htmltag fontmap[EQNFONT__MAX] = {
        TAG_I /* EQNFONT_ITALIC */
 };
 
-
 static void    eqn_box(struct html *, const struct eqn_box *);
 
+
 void
 print_eqn(struct html *p, const struct eqn *ep)
 {
@@ -59,12 +59,12 @@ eqn_box(struct html *p, const struct eqn_box *bp)
 {
        struct tag      *t;
 
-       t = EQNFONT_NONE == bp->font ? NULL : 
-               print_otag(p, fontmap[(int)bp->font], 0, NULL);
+       t = EQNFONT_NONE == bp->font ? NULL :
+           print_otag(p, fontmap[(int)bp->font], 0, NULL);
 
        if (bp->left)
                print_text(p, bp->left);
-       
+
        if (bp->text)
                print_text(p, bp->text);
 
index cfbd8d4..889c5c6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: eqn_term.c,v 1.4 2011/07/24 10:09:03 kristaps Exp $ */
+/*     $Id: eqn_term.c,v 1.5 2014/04/20 16:46:04 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -37,6 +37,7 @@ static        const enum termfont fontmap[EQNFONT__MAX] = {
 
 static void    eqn_box(struct termp *, const struct eqn_box *);
 
+
 void
 term_eqn(struct termp *p, const struct eqn *ep)
 {
@@ -68,7 +69,7 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
                term_word(p, ")");
        if (bp->right)
                term_word(p, bp->right);
-       if (EQNFONT_NONE != bp->font) 
+       if (EQNFONT_NONE != bp->font)
                term_fontpop(p);
 
        if (bp->next)
diff --git a/contrib/mdocml/external.png b/contrib/mdocml/external.png
deleted file mode 100644 (file)
index 419c06f..0000000
Binary files a/contrib/mdocml/external.png and /dev/null differ
index a5bca9d..2c7ba4b 100644 (file)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@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
@@ -27,8 +27,11 @@ while [ -n "$1" ]; do
   file=$1
   shift
   echo " ========== $file ========== "
-  tbl $file | groff -mandoc -Tascii -P -c 2>&1 > /tmp/groff.out
-  mandoc -Ios='OpenBSD ports' -Werror $file 2>&1 > /tmp/mandoc.out
+  tbl $file | groff -mandoc -Tascii -P -c 2> /tmp/groff.err > /tmp/groff.out
+  mandoc -Ios='OpenBSD ports' -Werror $file 2> /tmp/mandoc.err > /tmp/mandoc.out
+  for i in groff mandoc; do
+    [[ -s /tmp/$i.err ]] && echo "$i errors:" && cat /tmp/$i.err
+  done
   diff -au /tmp/groff.out /tmp/mandoc.out 2>&1
 done
 
index 9d28b42..d4783ee 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: html.c,v 1.152 2013/08/08 20:07:47 schwarze Exp $ */
+/*     $Id: html.c,v 1.159 2014/07/23 15:00:08 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@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
@@ -31,6 +31,7 @@
 #include <unistd.h>
 
 #include "mandoc.h"
+#include "mandoc_aux.h"
 #include "libmandoc.h"
 #include "out.h"
 #include "html.h"
@@ -109,11 +110,13 @@ static    const char      *const roffscales[SCALE_MAX] = {
 
 static void     bufncat(struct html *, const char *, size_t);
 static void     print_ctag(struct html *, enum htmltag);
+static int      print_escape(char);
 static int      print_encode(struct html *, const char *, int);
 static void     print_metaf(struct html *, enum mandoc_esc);
 static void     print_attr(struct html *, const char *, const char *);
 static void     *ml_alloc(char *, enum htmltype);
 
+
 static void *
 ml_alloc(char *outopts, enum htmltype type)
 {
@@ -135,16 +138,16 @@ ml_alloc(char *outopts, enum htmltype type)
 
        while (outopts && *outopts)
                switch (getsubopt(&outopts, UNCONST(toks), &v)) {
-               case (0):
+               case 0:
                        h->style = v;
                        break;
-               case (1):
+               case 1:
                        h->base_man = v;
                        break;
-               case (2):
+               case 2:
                        h->base_includes = v;
                        break;
-               case (3):
+               case 3:
                        h->oflags |= HTML_FRAGMENT;
                        break;
                default:
@@ -161,7 +164,6 @@ html_alloc(char *outopts)
        return(ml_alloc(outopts, HTML_HTML_4_01_STRICT));
 }
 
-
 void *
 xhtml_alloc(char *outopts)
 {
@@ -169,7 +171,6 @@ xhtml_alloc(char *outopts)
        return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT));
 }
 
-
 void
 html_free(void *p)
 {
@@ -179,17 +180,16 @@ html_free(void *p)
        h = (struct html *)p;
 
        while ((tag = h->tags.head) != NULL) {
-               h->tags.head = tag->next;       
+               h->tags.head = tag->next;
                free(tag);
        }
-       
+
        if (h->symtab)
                mchars_free(h->symtab);
 
        free(h);
 }
 
-
 void
 print_gen_head(struct html *h)
 {
@@ -226,21 +226,21 @@ print_metaf(struct html *h, enum mandoc_esc deco)
        enum htmlfont    font;
 
        switch (deco) {
-       case (ESCAPE_FONTPREV):
+       case ESCAPE_FONTPREV:
                font = h->metal;
                break;
-       case (ESCAPE_FONTITALIC):
+       case ESCAPE_FONTITALIC:
                font = HTMLFONT_ITALIC;
                break;
-       case (ESCAPE_FONTBOLD):
+       case ESCAPE_FONTBOLD:
                font = HTMLFONT_BOLD;
                break;
-       case (ESCAPE_FONTBI):
+       case ESCAPE_FONTBI:
                font = HTMLFONT_BI;
                break;
-       case (ESCAPE_FONT):
+       case ESCAPE_FONT:
                /* FALLTHROUGH */
-       case (ESCAPE_FONTROMAN):
+       case ESCAPE_FONTROMAN:
                font = HTMLFONT_NONE;
                break;
        default:
@@ -257,13 +257,13 @@ print_metaf(struct html *h, enum mandoc_esc deco)
        h->metac = font;
 
        switch (font) {
-       case (HTMLFONT_ITALIC):
+       case HTMLFONT_ITALIC:
                h->metaf = print_otag(h, TAG_I, 0, NULL);
                break;
-       case (HTMLFONT_BOLD):
+       case HTMLFONT_BOLD:
                h->metaf = print_otag(h, TAG_B, 0, NULL);
                break;
-       case (HTMLFONT_BI):
+       case HTMLFONT_BI:
                h->metaf = print_otag(h, TAG_B, 0, NULL);
                print_otag(h, TAG_I, 0, NULL);
                break;
@@ -302,19 +302,19 @@ html_strlen(const char *cp)
                        break;
                cp++;
                switch (mandoc_escape(&cp, NULL, NULL)) {
-               case (ESCAPE_ERROR):
+               case ESCAPE_ERROR:
                        return(sz);
-               case (ESCAPE_UNICODE):
+               case ESCAPE_UNICODE:
                        /* FALLTHROUGH */
-               case (ESCAPE_NUMBERED):
+               case ESCAPE_NUMBERED:
                        /* FALLTHROUGH */
-               case (ESCAPE_SPECIAL):
+               case ESCAPE_SPECIAL:
                        if (skip)
                                skip = 0;
                        else
                                sz++;
                        break;
-               case (ESCAPE_SKIPCHAR):
+               case ESCAPE_SKIPCHAR:
                        skip = 1;
                        break;
                default:
@@ -324,6 +324,37 @@ html_strlen(const char *cp)
        return(sz);
 }
 
+static int
+print_escape(char c)
+{
+
+       switch (c) {
+       case '<':
+               printf("&lt;");
+               break;
+       case '>':
+               printf("&gt;");
+               break;
+       case '&':
+               printf("&amp;");
+               break;
+       case '"':
+               printf("&quot;");
+               break;
+       case ASCII_NBRSP:
+               putchar('-');
+               break;
+       case ASCII_HYPH:
+               putchar('-');
+               /* FALLTHROUGH */
+       case ASCII_BREAK:
+               break;
+       default:
+               return(0);
+       }
+       return(1);
+}
+
 static int
 print_encode(struct html *h, const char *p, int norecurse)
 {
@@ -331,7 +362,8 @@ print_encode(struct html *h, const char *p, int norecurse)
        int              c, len, nospace;
        const char      *seq;
        enum mandoc_esc  esc;
-       static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
+       static const char rejs[9] = { '\\', '<', '>', '&', '"',
+               ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
 
        nospace = 0;
 
@@ -350,43 +382,29 @@ print_encode(struct html *h, const char *p, int norecurse)
                if ('\0' == *p)
                        break;
 
-               switch (*p++) {
-               case ('<'):
-                       printf("&lt;");
+               if (print_escape(*p++))
                        continue;
-               case ('>'):
-                       printf("&gt;");
-                       continue;
-               case ('&'):
-                       printf("&amp;");
-                       continue;
-               case (ASCII_HYPH):
-                       putchar('-');
-                       continue;
-               default:
-                       break;
-               }
 
                esc = mandoc_escape(&p, &seq, &len);
                if (ESCAPE_ERROR == esc)
                        break;
 
                switch (esc) {
-               case (ESCAPE_FONT):
+               case ESCAPE_FONT:
                        /* FALLTHROUGH */
-               case (ESCAPE_FONTPREV):
+               case ESCAPE_FONTPREV:
                        /* FALLTHROUGH */
-               case (ESCAPE_FONTBOLD):
+               case ESCAPE_FONTBOLD:
                        /* FALLTHROUGH */
-               case (ESCAPE_FONTITALIC):
+               case ESCAPE_FONTITALIC:
                        /* FALLTHROUGH */
-               case (ESCAPE_FONTBI):
+               case ESCAPE_FONTBI:
                        /* FALLTHROUGH */
-               case (ESCAPE_FONTROMAN):
+               case ESCAPE_FONTROMAN:
                        if (0 == norecurse)
                                print_metaf(h, esc);
                        continue;
-               case (ESCAPE_SKIPCHAR):
+               case ESCAPE_SKIPCHAR:
                        h->flags |= HTML_SKIPCHAR;
                        continue;
                default:
@@ -399,25 +417,26 @@ print_encode(struct html *h, const char *p, int norecurse)
                }
 
                switch (esc) {
-               case (ESCAPE_UNICODE):
-                       /* Skip passed "u" header. */
+               case ESCAPE_UNICODE:
+                       /* Skip past "u" header. */
                        c = mchars_num2uc(seq + 1, len - 1);
                        if ('\0' != c)
                                printf("&#x%x;", c);
                        break;
-               case (ESCAPE_NUMBERED):
+               case ESCAPE_NUMBERED:
                        c = mchars_num2char(seq, len);
-                       if ('\0' != c)
+                       if ( ! ('\0' == c || print_escape(c)))
                                putchar(c);
                        break;
-               case (ESCAPE_SPECIAL):
+               case ESCAPE_SPECIAL:
                        c = mchars_spec2cp(h->symtab, seq, len);
                        if (c > 0)
                                printf("&#%d;", c);
-                       else if (-1 == c && 1 == len)
+                       else if (-1 == c && 1 == len &&
+                           !print_escape(*seq))
                                putchar((int)*seq);
                        break;
-               case (ESCAPE_NOSPACE):
+               case ESCAPE_NOSPACE:
                        if ('\0' == *p)
                                nospace = 1;
                        break;
@@ -429,7 +448,6 @@ print_encode(struct html *h, const char *p, int norecurse)
        return(nospace);
 }
 
-
 static void
 print_attr(struct html *h, const char *key, const char *val)
 {
@@ -438,9 +456,8 @@ print_attr(struct html *h, const char *key, const char *val)
        putchar('\"');
 }
 
-
 struct tag *
-print_otag(struct html *h, enum htmltag tag, 
+print_otag(struct html *h, enum htmltag tag,
                int sz, const struct htmlpair *p)
 {
        int              i;
@@ -490,7 +507,7 @@ print_otag(struct html *h, enum htmltag tag,
 
        if (HTML_AUTOCLOSE & htmltags[tag].flags)
                switch (h->type) {
-               case (HTML_XHTML_1_0_STRICT):
+               case HTML_XHTML_1_0_STRICT:
                        putchar('/');
                        break;
                default:
@@ -507,16 +524,15 @@ print_otag(struct html *h, enum htmltag tag,
        return(t);
 }
 
-
 static void
 print_ctag(struct html *h, enum htmltag tag)
 {
-       
+
        printf("</%s>", htmltags[tag].name);
        if (HTML_CLRLINE & htmltags[tag].flags) {
                h->flags |= HTML_NOSPACE;
                putchar('\n');
-       } 
+       }
 }
 
 void
@@ -527,7 +543,7 @@ print_gen_decls(struct html *h)
        const char      *name;
 
        switch (h->type) {
-       case (HTML_HTML_4_01_STRICT):
+       case HTML_HTML_4_01_STRICT:
                name = "HTML";
                doctype = "-//W3C//DTD HTML 4.01//EN";
                dtd = "http://www.w3.org/TR/html4/strict.dtd";
@@ -540,8 +556,8 @@ print_gen_decls(struct html *h)
                break;
        }
 
-       printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n", 
-                       name, doctype, dtd);
+       printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
+           name, doctype, dtd);
 }
 
 void
@@ -560,13 +576,13 @@ print_text(struct html *h, const char *word)
 
        assert(NULL == h->metaf);
        switch (h->metac) {
-       case (HTMLFONT_ITALIC):
+       case HTMLFONT_ITALIC:
                h->metaf = print_otag(h, TAG_I, 0, NULL);
                break;
-       case (HTMLFONT_BOLD):
+       case HTMLFONT_BOLD:
                h->metaf = print_otag(h, TAG_B, 0, NULL);
                break;
-       case (HTMLFONT_BI):
+       case HTMLFONT_BI:
                h->metaf = print_otag(h, TAG_B, 0, NULL);
                print_otag(h, TAG_I, 0, NULL);
                break;
@@ -589,14 +605,13 @@ print_text(struct html *h, const char *word)
        h->flags &= ~HTML_IGNDELIM;
 }
 
-
 void
 print_tagq(struct html *h, const struct tag *until)
 {
        struct tag      *tag;
 
        while ((tag = h->tags.head) != NULL) {
-               /* 
+               /*
                 * Remember to close out and nullify the current
                 * meta-font and table, if applicable.
                 */
@@ -612,7 +627,6 @@ print_tagq(struct html *h, const struct tag *until)
        }
 }
 
-
 void
 print_stagq(struct html *h, const struct tag *suntil)
 {
@@ -621,7 +635,7 @@ print_stagq(struct html *h, const struct tag *suntil)
        while ((tag = h->tags.head) != NULL) {
                if (suntil && tag == suntil)
                        return;
-               /* 
+               /*
                 * Remember to close out and nullify the current
                 * meta-font and table, if applicable.
                 */
@@ -657,6 +671,12 @@ void
 bufcat(struct html *h, const char *p)
 {
 
+       /*
+        * XXX This is broken and not easy to fix.
+        * When using the -Oincludes option, buffmt_includes()
+        * may pass in strings overrunning BUFSIZ, causing a crash.
+        */
+
        h->buflen = strlcat(h->buf, p, BUFSIZ);
        assert(h->buflen < BUFSIZ);
 }
@@ -667,8 +687,8 @@ bufcat_fmt(struct html *h, const char *fmt, ...)
        va_list          ap;
 
        va_start(ap, fmt);
-       (void)vsnprintf(h->buf + (int)h->buflen, 
-                       BUFSIZ - h->buflen - 1, fmt, ap);
+       (void)vsnprintf(h->buf + (int)h->buflen,
+           BUFSIZ - h->buflen - 1, fmt, ap);
        va_end(ap);
        h->buflen = strlen(h->buf);
 }
@@ -688,12 +708,12 @@ buffmt_includes(struct html *h, const char *name)
        const char      *p, *pp;
 
        pp = h->base_includes;
-       
+
        bufinit(h);
        while (NULL != (p = strchr(pp, '%'))) {
                bufncat(h, pp, (size_t)(p - pp));
                switch (*(p + 1)) {
-               case('I'):
+               case'I':
                        bufcat(h, name);
                        break;
                default:
@@ -707,22 +727,21 @@ buffmt_includes(struct html *h, const char *name)
 }
 
 void
-buffmt_man(struct html *h, 
-               const char *name, const char *sec)
+buffmt_man(struct html *h, const char *name, const char *sec)
 {
        const char      *p, *pp;
 
        pp = h->base_man;
-       
+
        bufinit(h);
        while (NULL != (p = strchr(pp, '%'))) {
                bufncat(h, pp, (size_t)(p - pp));
                switch (*(p + 1)) {
-               case('S'):
+               case 'S':
                        bufcat(h, sec ? sec : "1");
                        break;
-               case('N'):
-                       bufcat_fmt(h, name);
+               case 'N':
+                       bufcat_fmt(h, "%s", name);
                        break;
                default:
                        bufncat(h, p, 2);
index 894cfc4..ca15f0f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: html.h,v 1.49 2013/08/08 20:07:47 schwarze Exp $ */
+/*     $Id: html.h,v 1.51 2014/04/20 16:46:04 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -105,7 +105,7 @@ struct      htmlpair {
 #define        PAIR_STYLE_INIT(p, h)   PAIR_INIT(p, ATTR_STYLE, (h)->buf)
 #define        PAIR_SUMMARY_INIT(p, v) PAIR_INIT(p, ATTR_SUMMARY, v)
 
-enum   htmltype { 
+enum   htmltype {
        HTML_HTML_4_01_STRICT,
        HTML_XHTML_1_0_STRICT
 };
@@ -127,7 +127,7 @@ struct      html {
        char             *base_includes; /* base for include href */
        char             *style; /* style-sheet URI */
        char              buf[BUFSIZ]; /* see bufcat and friends */
-       size_t            buflen; 
+       size_t            buflen;
        struct tag       *metaf; /* current open font scope */
        enum htmlfont     metal; /* last used font */
        enum htmlfont     metac; /* current font mode */
@@ -138,7 +138,7 @@ struct      html {
 
 void             print_gen_decls(struct html *);
 void             print_gen_head(struct html *);
-struct tag      *print_otag(struct html *, enum htmltag, 
+struct tag      *print_otag(struct html *, enum htmltag,
                                int, const struct htmlpair *);
 void             print_tagq(struct html *, const struct tag *);
 void             print_stagq(struct html *, const struct tag *);
@@ -147,15 +147,18 @@ void                print_tblclose(struct html *);
 void             print_tbl(struct html *, const struct tbl_span *);
 void             print_eqn(struct html *, const struct eqn *);
 
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 2, 3)))
+#endif
 void             bufcat_fmt(struct html *, const char *, ...);
 void             bufcat(struct html *, const char *);
 void             bufcat_id(struct html *, const char *);
-void             bufcat_style(struct html *, 
+void             bufcat_style(struct html *,
                        const char *, const char *);
-void             bufcat_su(struct html *, const char *, 
+void             bufcat_su(struct html *, const char *,
                        const struct roffsu *);
 void             bufinit(struct html *);
-void             buffmt_man(struct html *, 
+void             buffmt_man(struct html *,
                        const char *, const char *);
 void             buffmt_includes(struct html *, const char *);
 
diff --git a/contrib/mdocml/index.css b/contrib/mdocml/index.css
deleted file mode 100644 (file)
index d98316e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-html           { min-width: 40em;
-                 margin-top: 2em;
-                 margin-left: auto;
-                 margin-right: auto;
-                 width: 80%; }
-
-body           { text-align: justify; 
-                 font-family: Helvetica,Arial,sans-serif;
-                 line-height: 120%;
-                 font-size: small; }
-
-p,ul,table     { margin-left: 3em; }
-
-p.head, 
-p.subhead,
-p.foot         { margin-left: 0.0em; margin-right: 0.0em; }
-
-p.news         { margin-left: 2.0em; }
-
-li             { margin: 0.25em; }
-
-h1             { font-size: 110%; }
-h2             { font-size: 105%; margin-left: 1.5em }
-
-p.head         { margin-bottom: 0.5em;
-                 border-bottom: 1px solid #dddddd; 
-                 padding-bottom: 0.2em; }
-
-p.subhead      { margin-top: 0em; 
-                 margin-bottom: 1.75em; }
-
-p.foot         { border-top: 1px solid #dddddd; 
-                 color: #666666;
-                 padding-top: 0.2em;
-                 margin-top: 1.75em; }
-
-span.nm                { color: green; }
-
-span.file      { font-style: italic; }
-
-span.attn      { font-weight: bold; }
-
-span.flag      { font-weight: bold; }
-
-a              { text-decoration: none; }
-
-a.external     { background: transparent url(external.png) center right no-repeat; 
-                 padding-right: 12px; }
diff --git a/contrib/mdocml/index.sgml b/contrib/mdocml/index.sgml
deleted file mode 100644 (file)
index 83a43a7..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<HTML>
-       <HEAD>
-               <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
-               <LINK REL="stylesheet" HREF="index.css" TYPE="text/css" MEDIA="all">
-               <TITLE>mdocml | UNIX manpage compiler</TITLE>
-       </HEAD>
-       <BODY>
-               <P CLASS="head">
-                       <A HREF="http://www.openbsd.org/"><IMG SRC="puffy.gif" ALT="Puffy" WIDTH="100" HEIGHT="91" STYLE="float: right"></A>
-                       <B>mdocml</B> &#8211; UNIX manpage compiler, current version @VERSION@ (@VDATE@)
-               </P>
-               <P CLASS="subhead">
-                       Sources: <A HREF="/snapshots/mdocml.tar.gz">current</A>,
-                       <A HREF="/cgi-bin/cvsweb/?cvsroot=mdocml">cvsweb</A>
-                       (<A HREF="/snapshots/">archives</A>)
-               </P>
-               <H1>
-                       <A NAME="description">Description</A>
-               </H1>
-               <P>
-                       <SPAN CLASS="nm">mdocml</SPAN> is a suite of tools compiling <I><A HREF="mdoc.7.html">mdoc</A></I>, the roff macro
-                       package of choice for BSD manual pages, and <I><A HREF="man.7.html">man</A></I>, the predominant historical package for
-                       UNIX manuals.
-                       It is small, ISO C, <A CLASS="external" HREF="http://www.isc.org/software/license">ISC</A>-licensed, and quite fast.
-               </P>
-               <P>
-                       The tool set features <A HREF="mandoc.1.html">mandoc</A>,
-                       based on the <A HREF="mandoc.3.html">libmandoc</A> validating compiler,
-                       to format output for UNIX terminals (with
-                       support for wide-character locales), XHTML, HTML, PostScript, and PDF.  
-                       It also includes <A HREF="preconv.1.html">preconv</A>, for recoding multibyte manuals; 
-                       <A HREF="demandoc.1.html">demandoc</A>, for emitting only text parts of manuals;
-                       <A HREF="mandocdb.8.html">mandocdb</A>, for indexing manuals; and
-                       <A HREF="apropos.1.html">apropos</A>, <A HREF="whatis.1.html">whatis</A>, and
-                       <A HREF="man.cgi.7.html">man.cgi</A> (via <A HREF="catman.8.html">catman</A>) for semantic search of manual content.
-               </P>
-               <P>
-                       <SPAN CLASS="nm">mdocml</SPAN> has predominantly been developed on OpenBSD
-                       and is both an <A CLASS="external" HREF="http://www.openbsd.org/">OpenBSD</A>
-                       and a <A CLASS="external" HREF="http://bsd.lv/">BSD.lv</A> project.  
-                       We strive to support all interested free operating systems, in particular
-                       <A CLASS="external" HREF="http://www.dragonflybsd.org/">DragonFly</A>,
-                       <A CLASS="external" HREF="http://www.netbsd.org/">NetBSD</A>,
-                       <A CLASS="external" HREF="http://www.freebsd.org/">FreeBSD</A>,
-                       <A CLASS="external" HREF="http://www.minix3.org/">Minix 3</A>,
-                       and <A CLASS="external" HREF="http://www.gnu.org/">GNU</A>/Linux,
-                       as well as all systems running the <A CLASS="external" HREF="http://www.pkgsrc.org/">pkgsrc</A> portable package build system.
-                       All of these projects have helped to make <SPAN CLASS="nm">mdocml</SPAN> better, by providing feedback and advice,
-                       bug reports, and patches.
-               </P>
-               <P>
-                       <I>Disambiguation</I>: <SPAN CLASS="nm">mdocml</SPAN> is often referred to by its installed binary, <Q>mandoc</Q>.
-               </P>
-               <H2>
-                       <A NAME="sources">Sources</A>
-               </H2>
-               <P>
-                       <SPAN CLASS="nm">mdocml</SPAN> should build and run on any modern system with
-                       <A HREF="http://www.oracle.com/technetwork/database/berkeleydb/overview/index.html">libdb</A>
-                       (this is installed by default on BSD UNIX systems &mdash; see the <I>Makefile</I> if you're running Linux).
-                       To build and install into <I>/usr/local/</I>, just run <CODE>make install</CODE>.
-                       Be careful: the <B>preconv</B>, <B>apropos</B>, and <B>whatis</B> installed binary names
-                       may be taken by existing utilities.
-               </P>
-               <H2>
-                       Downstream
-               </H2>
-               <P>
-                       Several systems come bundled with <SPAN CLASS="nm">mdocml</SPAN> utilities.
-                       If your system does not appear below, the maintainers have not contacted me and it should not be considered
-                       <Q>official</Q>, so please <A HREF="#contact">contact us</A> if you plan on maintaining a downstream version!
-               </P>
-               <TABLE WIDTH="100%" SUMMARY="Downstream Sources">
-                       <COL WIDTH="175">
-                       <COL>
-                       <TBODY>
-                               <TR>
-                                       <TD>DragonFly BSD</TD>
-                                       <TD>
-                                       <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/contrib/mdocml" CLASS="external">contrib/mdocml</A> (1.12.3 sources)
-                                       <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/lib/libmandoc" CLASS="external">lib/libmandoc</A>
-                                       <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/usr.bin/mandoc" CLASS="external">usr.bin/mandoc</A> (build system)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>FreeBSD 10.0, -CURRENT</TD>
-                                       <TD>
-                                       <A HREF="http://svnweb.freebsd.org/base/head/contrib/mdocml/" CLASS="external">contrib/mdocml</A> (1.12.1 sources)
-                                       <A HREF="http://svnweb.freebsd.org/base/head/usr.bin/mandoc/" CLASS="external">usr.bin/mandoc</A> (build system)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>FreeBSD 9.x, 8.x</TD>
-                                       <TD>
-                                       <A HREF="http://svnweb.freebsd.org/ports/head/textproc/mdocml/" CLASS="external">ports/textproc/mdocml</A> (1.12.2 port)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>NetBSD</TD>
-                                       <TD>
-                                       <A HREF="http://cvsweb.netbsd.org/bsdweb.cgi/src/external/bsd/mdocml/" CLASS="external">src/external/bsd/mdocml</A> (1.12.1 sources plus patches and build system)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>OpenBSD</TD>
-                                       <TD>
-                                       <A HREF="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/mandoc/" CLASS="external">src/usr.bin/mandoc</A> (1.12.3 sources under active development and build system)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>pkgsrc</TD>
-                                       <TD>
-                                       <A HREF="http://pkgsrc.se/textproc/mdocml" CLASS="external">textproc/mdocml</A> (1.12.2 port)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>Minix3</TD>
-                                       <TD>
-                                       <A HREF="http://git.minix3.org/?p=minix.git;a=tree;f=external/bsd/mdocml" CLASS="external">external/bsd/mdocml</A> (1.10.9 sources and build system)
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD>Alpine Linux</TD>
-                                       <TD>
-                                       <A HREF="http://git.alpinelinux.org/cgit/aports/tree/main/mdocml" CLASS="external">aports/main/mdocml</A> (1.12.2 port)
-                                       </TD>
-                               </TR>
-                       </TBODY>
-               </TABLE>
-               <H1>
-                       <A NAME="documentation">Documentation</A>
-               </H1>
-               <P>
-                       These manuals are generated automatically and refer to the current release.
-                       They are the authoritative documentation for the <SPAN CLASS="nm">mdocml</SPAN> system.
-               </P>
-
-               <TABLE WIDTH="100%" SUMMARY="Documentation">
-                       <COL WIDTH="175">
-                       <COL>
-                       <TBODY>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="apropos.1.html">apropos(1)</A></TD>
-                                       <TD VALIGN="top">
-                                               search the manual page database
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="demandoc.1.html">demandoc(1)</A></TD>
-                                       <TD VALIGN="top">
-                                               emit only text of UNIX manuals
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="mandoc.1.html">mandoc(1)</A></TD>
-                                       <TD VALIGN="top">
-                                               format and display UNIX manuals
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="preconv.1.html">preconv(1)</A></TD>
-                                       <TD VALIGN="top">
-                                               recode multibyte UNIX manuals
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="whatis.1.html">whatis(1)</A></TD>
-                                       <TD VALIGN="top">
-                                               search the manual page database
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="mandoc.3.html">mandoc(3)</A></TD>
-                                       <TD VALIGN="top">
-                                               mandoc macro compiler library
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="tbl.3.html">tbl(3)</A></TD>
-                                       <TD VALIGN="top">
-                                               roff table parser library for mandoc
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="eqn.7.html">eqn(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               eqn-mandoc language reference
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="man.7.html">man(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               man language reference
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="man.cgi.7.html">man.cgi(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               cgi for manpage query and display
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="mandoc_char.7.html">mandoc_char(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               mandoc special characters
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="mdoc.7.html">mdoc(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               mdoc language reference
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="roff.7.html">roff(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               roff-mandoc language reference
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="tbl.7.html">tbl(7)</A></TD>
-                                       <TD VALIGN="top">
-                                               tbl-mandoc language reference
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="catman.8.html">catman(8)</A></TD>
-                                       <TD VALIGN="top">
-                                               update a man.cgi manpage cache
-                                       </TD>
-                               </TR>
-                               <TR>
-                                       <TD VALIGN="top"><A HREF="mandocdb.8.html">mandocdb(8)</A></TD>
-                                       <TD VALIGN="top">
-                                               index UNIX manuals
-                                       </TD>
-                               </TR>
-                       </TBODY>
-               </TABLE>
-               <H2>
-                       <A NAME="links">Supplementary Information</A>
-               </H2>
-               <UL>
-                       <LI>
-                               <A HREF="http://manpages.bsd.lv/">Practical UNIX Manuals</A>: mdoc tutorial by Kristaps Dzonsons
-                       </LI>
-                       <LI>
-                               <A HREF="http://www.openbsd.org/faq/ports/specialtopics.html#Mandoc" CLASS="external">OpenBSD porting guide</A>
-                               chapter regarding manual pages
-                       </LI>
-                       <LI>
-                               <A HREF="press.html">Publications and media coverage</A>
-                               concerning mdocml and mandoc
-                       </LI>
-                       <LI>
-                               <A HREF="http://manpages.bsd.lv/history.html">History of UNIX Manpages</A>: a comprehensive overview by Kristaps Dzonsons
-                       </LI>
-               </UL>
-               <H1>
-                       <A NAME="contact">Contact</A>
-               </H1>
-               <P>
-                       Use the mailing lists for bug-reports, patches, questions, etc.  Please check the
-                       <A HREF="http://mdocml.bsd.lv/cgi-bin/cvsweb/TODO?cvsroot=mdocml">TODO</A> for known issues
-                       before posting.  All lists are subscripti