aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2016-07-23 11:45:42 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2016-07-23 11:45:42 +0000
commit05798824d24a3b26ef3439303ad694202c75729e (patch)
treee4cc6eff5bc4ba61eeea2f647be98470bad36ac0
parent9927192e4ffb982fcce1e26ae7bc0902d112dc18 (diff)
downloadsrc-05798824d24a3b26ef3439303ad694202c75729e.tar.gz
src-05798824d24a3b26ef3439303ad694202c75729e.zip
Update to mdocml 1.13.4vendor/mandoc/1.13.4
Notes
Notes: svn path=/vendor/mdocml/dist/; revision=303221 svn path=/vendor/mdocml/1.13.4/; revision=303222; tag=vendor/mandoc/1.13.4
-rw-r--r--INSTALL8
-rw-r--r--LICENSE4
-rw-r--r--Makefile30
-rw-r--r--NEWS135
-rw-r--r--TODO12
-rw-r--r--cgi.c487
-rw-r--r--cgi.h.example3
-rwxr-xr-xconfigure70
-rw-r--r--configure.local.example60
-rw-r--r--demandoc.c3
-rw-r--r--libmandoc.h3
-rw-r--r--main.c48
-rw-r--r--main.h4
-rw-r--r--man.138
-rw-r--r--man.cgi.3287
-rw-r--r--man.cgi.8146
-rw-r--r--mandoc.3185
-rw-r--r--mandoc.css5
-rw-r--r--mandoc.db.55
-rw-r--r--mandoc_headers.3176
-rw-r--r--mandoc_malloc.326
-rw-r--r--mandocdb.c15
-rw-r--r--manpage.c3
-rw-r--r--manpath.c11
-rw-r--r--mansearch.c3
-rw-r--r--mchars_alloc.37
-rw-r--r--read.c4
-rw-r--r--tag.c26
-rw-r--r--term.c4
-rw-r--r--term_ascii.c13
-rw-r--r--test-rewb-bsd.c1
-rw-r--r--test-rewb-sysv.c1
32 files changed, 1181 insertions, 642 deletions
diff --git a/INSTALL b/INSTALL
index 085fb3e1c672..58bef6a7358c 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-$Id: INSTALL,v 1.13 2015/11/07 14:01:16 schwarze Exp $
+$Id: INSTALL,v 1.15 2016/07/14 11:09:06 schwarze Exp $
About mdocml, the portable mandoc distribution
----------------------------------------------
@@ -16,7 +16,7 @@ tech@ mailing list, too.
Enjoy using the mandoc toolset!
-Ingo Schwarze, Karlsruhe, March 2015
+Ingo Schwarze, Karlsruhe, July 2016
Installation
@@ -52,7 +52,7 @@ and go back to step 2.
4. Run "make -n install" and check whether everything will be
installed to the intended places. Otherwise, put some *DIR or *NM*
-variables into "configure.local" and go back to step 2.
+variables into "configure.local" and go back to step 2.
5. Run "sudo make install". If you intend to build a binary
package using some kind of fake root mechanism, you may need a
@@ -63,7 +63,7 @@ in the "Makefile" to understand how DESTDIR is used.
manpath(1), make sure it is configured correctly, in particular,
it returns all directory trees where manual pages are installed.
Otherwise, if your system uses man.conf(5), make sure it contains
-a "_whatdb" line for each directory tree, and the order of these
+a "manpath" line for each directory tree, and the order of these
lines meets your wishes.
7. If you compiled with database support, run the command "sudo
diff --git a/LICENSE b/LICENSE
index ad3cd4b8086e..57e5656ba73f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,11 +1,11 @@
-$Id: LICENSE,v 1.11 2015/11/07 17:58:55 schwarze Exp $
+$Id: LICENSE,v 1.12 2016/07/07 23:46:36 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-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
-Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2010-2016 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) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
diff --git a/Makefile b/Makefile
index 9be2bd9c61f5..f76b13763136 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
-# $Id: Makefile,v 1.480 2015/11/07 21:53:14 schwarze Exp $
+# $Id: Makefile,v 1.488 2016/07/12 05:18:38 kristaps Exp $
#
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-# Copyright (c) 2011, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2011, 2013-2016 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
@@ -15,7 +15,7 @@
# 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.3
+VERSION = 1.13.4
# === LIST OF FILES ====================================================
@@ -31,6 +31,9 @@ TESTSRCS = test-dirent-namlen.c \
test-pledge.c \
test-progname.c \
test-reallocarray.c \
+ test-rewb-bsd.c \
+ test-rewb-sysv.c \
+ test-sandbox_init.c \
test-sqlite3.c \
test-sqlite3_errstr.c \
test-strcasestr.c \
@@ -138,6 +141,7 @@ DISTFILES = INSTALL \
makewhatis.8 \
man.1 \
man.7 \
+ man.cgi.3 \
man.cgi.8 \
man.conf.5 \
man.h \
@@ -164,6 +168,7 @@ DISTFILES = INSTALL \
predefs.in \
roff.7 \
roff.h \
+ roff_int.h \
soelim.1 \
st.in \
tag.h \
@@ -293,6 +298,7 @@ WWW_MANS = apropos.1.html \
roff.7.html \
tbl.7.html \
makewhatis.8.html \
+ man.cgi.3.html \
man.cgi.8.html \
man.h.html \
manconf.h.html \
@@ -392,34 +398,30 @@ db-install: base-build
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) mandoc.css $(DESTDIR)$(HTDOCDIR)
- $(INSTALL_MAN) apropos.1 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1/
- $(INSTALL_MAN) man.cgi.8 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8/
Makefile.local config.h: configure ${TESTSRCS}
@echo "$@ is out of date; please run ./configure"
@exit 1
libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
- $(AR) rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
+ ar rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
mandoc: $(MAIN_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) -o $@ $(MAIN_OBJS) libmandoc.a $(DBLIB)
+ $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD)
manpage: $(MANPAGE_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) -o $@ $(MANPAGE_OBJS) libmandoc.a $(DBLIB)
+ $(CC) -o $@ $(LDFLAGS) $(MANPAGE_OBJS) libmandoc.a $(LDADD)
man.cgi: $(CGI_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
+ $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD)
demandoc: $(DEMANDOC_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a $(DBLIB)
+ $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD)
soelim: $(SOELIM_OBJS)
- $(CC) $(LDFLAGS) -o $@ $(SOELIM_OBJS)
+ $(CC) -o $@ $(LDFLAGS) $(SOELIM_OBJS)
# --- maintainer targets ---
@@ -439,6 +441,8 @@ depend: config.h
Makefile.depend > Makefile.tmp
mv Makefile.tmp Makefile.depend
+dist: mdocml.sha256
+
mdocml.sha256: mdocml.tar.gz
sha256 mdocml.tar.gz > $@
diff --git a/NEWS b/NEWS
index 985f265d3cdd..7f5625a7a157 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,140 @@
-$Id: NEWS,v 1.10 2015/11/05 16:58:20 schwarze Exp $
+$Id: NEWS,v 1.12 2016/07/14 11:09:06 schwarze Exp $
This file lists the most important changes in the mdocml.bsd.lv distribution.
+Changes in version 1.13.4, released on July 14, 2016
+
+ --- MAJOR NEW FEATURES ---
+ * man.conf(5): Design and implement a simpler configuration file format.
+ * man(1): Leverage less(1) -T and :t in a way resembling ctags(1)
+ to jump to the definitions of various terms inside manual pages.
+ * soelim(1): New implementation by Baptiste Daroussin.
+ * privilege limitation: Use OpenBSD pledge(2) or OS X sandbox_init(3)
+ when available.
+ * man.cgi(8): Support short URIs like http://man.openbsd.org/mdoc .
+ * mandoc.css: Use one unified stylesheet rather than three different ones.
+ --- MAJOR FUNCTIONALLY RELEVANT BUGFIXES ---
+ * mdoc(7): Fix multiple aspects of SYNOPSIS .Nm formatting.
+ * man(1): Fix process group handling, avoiding unclean shutdowns.
+ --- PORTABILITY IMPROVEMENTS ---
+ * Correctly use the ohash(3) compatibility implementation
+ even when building without SQLite support.
+ * Add compat glue for building on Solaris 9 and 10.
+ * Let ./configure select a supported RE syntax for word boundaries.
+ * Support LDFLAGS, to be used for example for hardening options.
+ * Avoid mixing putchar(3) and putwchar(3) on the same file descriptor,
+ it resulted in output corruption on some platforms.
+ * Avoid reusing va_lists, use va_copy(3) for better portability.
+ * Do not hardcode the path to the more(1) program.
+ --- MINOR NEW FEATURES ---
+ * roff(7): Implement \n(.$ (number of macro arguments).
+ * roff(7): Fully implement \z (do not advance cursor).
+ * roff(7): Implement the `r' conditional (register exists).
+ * roff(7): Implement \\$* (interpolate all arguments).
+ * roff(7): Parse and ignore \, and \/ (italic corrections).
+ * When there is no -m, no -M, no MANPATH and no /etc/man.conf,
+ fall back to /usr/share/man:/usr/X11R6/man:/usr/local/man.
+ * man(1): Give manuals in purely numerical sections priority over
+ manuals of the same name in sections with an alphabetical suffix.
+ * man.cgi(8): Support "header.html" and "footer.html".
+ * man.cgi(8): Set the "autofocus" attribute on the query text box.
+ * man.cgi(8): Simplify the search form, drop two useless buttons.
+ * man.cgi(8): Delete the pseudo-manpath "mandoc", assume that
+ apropos(1) and man.cgi(8) are installed in the default manpath.
+ --- RELIABILITY BUGFIXES ---
+ * mdoc(7): Avoid a use after free and an assertion failure when nodes
+ are deleted during validation.
+ * mdoc(7): Avoid a NULL pointer access when .Bd has no arguments.
+ * mdoc(7): Avoid a NULL pointer access triggered by mismatching end macros.
+ * mdoc(7): Avoid an assertion when .Fo has no argument.
+ * mdoc(7): Avoid an assertion when .Ta<tab> occurs in .Bl -column.
+ * mdoc(7): Avoid an assertion when a body gets broken and has a tail.
+ * roff(7): Avoid an assertion caused by blanks inside \o.
+ * roff(7): Make .so links to gziped manuals work without mandoc.db(5).
+ * tbl(7): Avoid a use after free when the last line of a layout is empty.
+ * eqn(7): Avoid an infinite loop caused by recursive "define".
+ * makewhatis(8): Avoid a segfault caused by unusual directory structures.
+ * Fix handling of leading, trailing, and double colons in MANPATH and -m.
+ --- MINOR BUGFIXES ---
+ * mdoc(7): Put arguments to end macros of broken partial explicit blocks
+ inside the breaking block.
+ * mdoc(7): Let .Dv force normal font.
+ * mdoc(7): Make trailing whitespace significant in .Bl -tag widths.
+ * mdoc(7): Fix macro interpretation around tabs in .Bl -column.
+ * man(7): Use the default width for .RS without arguments.
+ * man(7): On a new RS nesting level, the saved width starts from
+ the default width, not from the saved width of the previous level.
+ * man(7): Allow .PD in next-line scope.
+ * man(7): Improve handling of empty .HP.
+ * man(7): Improve formatting of .br and .sp inside .HP.
+ * man(7): Do not mistreat empty arguments to font alternating
+ macros as vertical spacing requests.
+ * man(7): Allow fill mode changes in tagged paragraph next-line scope.
+ * man(7): Fix minor bugs in block rewinding and simplify the related code.
+ * man(7): Add missing line breaks before subsection headers.
+ * man(7): Give section and subsection headers hanging indentation.
+ * man(7): Make trailing whitespace significant in .TP widths.
+ * roff(7): Don't allow breaking the output line after hyphens
+ that immediately follow escape sequences.
+ * roff(7): Ignore blank characters at the beginning of conditional blocks.
+ * roff(7): Escape breakable hyphens only after handling input line traps.
+ * roff(7): Reject \[uD800] to \[uDFFF] (surrogates) in the parser.
+ * tbl(7): Allow more than one data field after T} on the same input line.
+ * terminal output: Apply bold and italic to non-ASCII Unicode codepoints.
+ * terminal output: Improve rounding rules for horizontal scaling widths.
+ * HTML output: Render ASCII_NBRSP as "&nbsp;", not "-".
+ * man(1): Do not match the first part of a name if it continues with a dot.
+ * man(1): Keep working even if the current directory is unusable.
+ * man(1): Better error message when $PAGER is invalid.
+ * makewhatis(8): Improve handling of .Va and .Vt macros.
+ * apropos(1): Print "nothing appropriate" to stderr when appropriate.
+ * apropos(1): Abort with a useful error message when elementary
+ database operations like preparing queries or binding variables fail.
+ --- STRUCTURAL CHANGES, no functional change ---
+ * mdoc(7) and man(7): Unified data structures struct roff_node etc.
+ * mdoc(7) and man(7): Unified node handling library in roff.c.
+ * mdoc(7) and man(7): Seperate validation phase from parsing.
+ * roff(7): Major character table cleanup.
+ * Link with libz rather than forking gunzip(1).
+ --- THANKS TO ---
+ * Baptiste Daroussin (FreeBSD) for the new soelim(1)
+ and for release testing.
+ * Anthony Bentley (OpenBSD) for unifying mandoc.css, two nice
+ patches for man.cgi(8), some documentation patches, some bug
+ reports, and various useful discussions.
+ * Todd Miller (OpenBSD) for lots of help with process group and
+ signal handling, a few patches, some bug reports and some useful
+ discussions.
+ * Jonathan Gray (OpenBSD) for yet more testing with afl(1)
+ again resulting in more than half a dozen important bug reports.
+ * Svyatoslav Mishyn (Crux Linux) for some patches, several bug
+ reports, and extensive release testing.
+ * Christian Neukirchen (void Linux) for a number of compatibility
+ patches and suggestions and several bug reports.
+ * Christos Zoulas (NetBSD) for a bug fix patch and some useful
+ suggestions for cleanup.
+ * Florian Obser (OpenBSD) for a bugfix patch and some bug reports.
+ * Sevan Janiyan for help with Solaris compatibility and release
+ testing on many platforms.
+ * Jan Holzhueter and OpenCSW in general for help with Solaris
+ compatibility, and for providing me with a Solaris 9/10/11 testing
+ environment.
+ * Michael McConville (OpenBSD) for some simple cleanup patches.
+ * Thomas Klausner (NetBSD) for some bug reports and release testing.
+ * Christian Weisgerber, Dmitrij Czarkoff, Igor Sobrado,
+ Ken Westerback, Marc Espie, Mike Belopuhov, Rafael Neves,
+ Ted Unangst, Tim van der Molen, Theo Buehler, Theo de Raadt
+ (OpenBSD), Kurt Jaeger, Dag Erling Smoergrav (FreeBSD),
+ Joerg Sonnenberger (NetBSD), Carsten Kunze (Heirloom troff),
+ Daniel Levai, Fabian Raetz, Jan Stary, Jean-Yves Migeon,
+ Lorenzo Beretta, Markus Waldeck, Maxim Belooussov, Michael Reed,
+ Peter Bray, and Serguey Parkhomovsky for bug reports and feature
+ suggestions.
+ * Alexander Hall, Andrew Fresh, Antoine Jacoutot, Doug Hogan,
+ Jason McIntyre, Jasper Lievisse Adriaanse, Kent Spillner,
+ Nicholas Marriott, Peter Hessler, Sebastien Marie, Stefan Sperling,
+ and Theo de Raadt (OpenBSD) for helpful discussions and feedback.
+
Changes in version 1.13.3, released on March 13, 2015
--- MAJOR NEW FEATURES ---
diff --git a/TODO b/TODO
index d24c939afa4a..99a16a9e62a4 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
-* $Id: TODO,v 1.216 2016/01/08 01:37:32 schwarze Exp $
+* $Id: TODO,v 1.218 2016/06/05 21:06:04 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@@ -416,6 +416,11 @@ are mere guesses, and some may be wrong.
see also matthew@ Fri, 18 Jul 2014 19:25:12 -0700
loc * exist * algo ** size * imp ***
+- In -man -Thtml, .nf does not preserve indentation.
+ It should either convert blanks to &nbsp;
+ or use <pre> rather than <div> (like .Bd -literal does).
+ Reported by afresh1@ 12 Apr 2016 14:35:45 -0700
+
- .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal
space, see for example random(3). Introduced in
http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92
@@ -583,8 +588,6 @@ are mere guesses, and some may be wrong.
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
************************************************************************
@@ -628,9 +631,6 @@ Several areas can be cleaned up to make mandoc even faster. These are
* structural issues
************************************************************************
-- Use libz directly instead of forking gunzip(1).
- Suggested by bapt at FreeBSD among others.
-
- We use the input line number at several places to distinguish
same-line from different-line input. That plainly doesn't work
with user-defined macros, leading to random breakage.
diff --git a/cgi.c b/cgi.c
index 0b01d06602e4..f8497b588d95 100644
--- a/cgi.c
+++ b/cgi.c
@@ -1,7 +1,7 @@
-/* $Id: cgi.c,v 1.116 2016/01/04 12:36:26 schwarze Exp $ */
+/* $Id: cgi.c,v 1.135 2016/07/11 22:48:37 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@usta.de>
+ * Copyright (c) 2014, 2015, 2016 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
@@ -21,6 +21,7 @@
#include <sys/time.h>
#include <ctype.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -55,15 +56,20 @@ struct req {
struct query q;
char **p; /* array of available manpaths */
size_t psz; /* number of available manpaths */
+ int isquery; /* QUERY_STRING used, not PATH_INFO */
+};
+
+enum focus {
+ FOCUS_NONE = 0,
+ FOCUS_QUERY
};
-static void catman(const struct req *, const char *);
-static void format(const struct req *, const char *);
static void html_print(const char *);
static void html_putchar(char);
static int http_decode(char *);
-static void http_parse(struct req *, const char *);
-static void pathgen(struct req *);
+static void parse_manpath_conf(struct req *);
+static void parse_path_info(struct req *req, const char *path);
+static void parse_query_string(struct req *, const char *);
static void pg_error_badrequest(const char *);
static void pg_error_internal(void);
static void pg_index(const struct req *);
@@ -74,16 +80,18 @@ static void pg_searchres(const struct req *,
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_catman(const struct req *, const char *);
static void resp_copy(const char *);
static void resp_end_html(void);
-static void resp_searchform(const struct req *);
+static void resp_format(const struct req *, const char *);
+static void resp_searchform(const struct req *, enum focus);
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 *scriptname; /* CGI script name */
+static const char *scriptname = SCRIPT_NAME;
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static const char *const sec_numbers[] = {
@@ -106,16 +114,16 @@ 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",
+ "hppa", "hppa64", "i386", "landisk",
+ "loongson", "luna88k", "macppc", "mips64",
+ "octeon", "sgi", "socppc", "sparc",
+ "sparc64", "zaurus",
"amiga", "arc", "arm32", "atari",
- "beagle", "cats", "hp300", "mac68k",
- "mvme68k", "mvme88k", "mvmeppc", "palm",
- "pc532", "pegasos", "pmax", "powerpc",
- "sun3", "wgrisc", "x68k"
+ "aviion", "beagle", "cats", "hp300",
+ "ia64", "mac68k", "mvme68k", "mvme88k",
+ "mvmeppc", "palm", "pc532", "pegasos",
+ "pmax", "powerpc", "solbourne", "sun3",
+ "vax", "wgrisc", "x68k"
};
static const int arch_MAX = sizeof(arch_names) / sizeof(char *);
@@ -182,11 +190,12 @@ set_query_attr(char **attr, char **val)
* and store the values into the query structure.
*/
static void
-http_parse(struct req *req, const char *qs)
+parse_query_string(struct req *req, const char *qs)
{
char *key, *val;
size_t keysz, valsz;
+ req->isquery = 1;
req->q.manpath = NULL;
req->q.arch = NULL;
req->q.sec = NULL;
@@ -338,14 +347,14 @@ resp_begin_html(int code, const char *msg)
resp_begin_http(code, msg);
printf("<!DOCTYPE html>\n"
- "<HTML>\n"
- "<HEAD>\n"
- "<META CHARSET=\"UTF-8\" />\n"
- "<LINK REL=\"stylesheet\" HREF=\"%s/mandoc.css\""
- " TYPE=\"text/css\" media=\"all\">\n"
- "<TITLE>%s</TITLE>\n"
- "</HEAD>\n"
- "<BODY>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta charset=\"UTF-8\"/>\n"
+ "<link rel=\"stylesheet\" href=\"%s/mandoc.css\""
+ " type=\"text/css\" media=\"all\">\n"
+ "<title>%s</title>\n"
+ "</head>\n"
+ "<body>\n"
"<!-- Begin page content. //-->\n",
CSS_DIR, CUSTOMIZE_TITLE);
@@ -358,103 +367,87 @@ resp_end_html(void)
resp_copy(MAN_DIR "/footer.html");
- puts("</BODY>\n"
- "</HTML>");
+ puts("</body>\n"
+ "</html>");
}
static void
-resp_searchform(const struct req *req)
+resp_searchform(const struct req *req, enum focus focus)
{
int i;
puts("<!-- Begin search form. //-->");
- printf("<DIV ID=\"mancgi\">\n"
- "<FORM ACTION=\"%s\" METHOD=\"get\">\n"
- "<FIELDSET>\n"
- "<LEGEND>Manual Page Search Parameters</LEGEND>\n",
+ printf("<div id=\"mancgi\">\n"
+ "<form action=\"/%s\" method=\"get\">\n"
+ "<fieldset>\n"
+ "<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)
+ printf("<input type=\"text\" name=\"query\" value=\"");
+ if (req->q.query != NULL)
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");
+ printf( "\" size=\"40\"");
+ if (focus == FOCUS_QUERY)
+ printf(" autofocus");
+ puts(">");
- /* Write show radio button */
+ /* Write submission buttons. */
- 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");
+ printf( "<button type=\"submit\" name=\"apropos\" value=\"0\">"
+ "man</button>\n"
+ "<button type=\"submit\" name=\"apropos\" value=\"1\">"
+ "apropos</button>\n<br/>\n");
/* Write section selector. */
- puts( "</TD></TR><TR><TD>\n"
- "<SELECT NAME=\"sec\">");
+ puts("<select name=\"sec\">");
for (i = 0; i < sec_MAX; i++) {
- printf("<OPTION VALUE=\"%s\"", sec_numbers[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]);
+ printf(" selected=\"selected\"");
+ printf(">%s</option>\n", sec_names[i]);
}
- puts("</SELECT>");
+ puts("</select>");
/* Write architecture selector. */
- printf( "<SELECT NAME=\"arch\">\n"
- "<OPTION VALUE=\"default\"");
+ printf( "<select name=\"arch\">\n"
+ "<option value=\"default\"");
if (NULL == req->q.arch)
- printf(" SELECTED=\"selected\"");
- puts(">All Architectures</OPTION>");
+ printf(" selected=\"selected\"");
+ puts(">All Architectures</option>");
for (i = 0; i < arch_MAX; i++) {
- printf("<OPTION VALUE=\"%s\"", arch_names[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]);
+ printf(" selected=\"selected\"");
+ printf(">%s</option>\n", arch_names[i]);
}
- puts("</SELECT>");
+ 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 ");
+ printf("<option ");
if (strcmp(req->q.manpath, req->p[i]) == 0)
- printf("SELECTED=\"selected\" ");
- printf("VALUE=\"");
+ printf("selected=\"selected\" ");
+ printf("value=\"");
html_print(req->p[i]);
printf("\">");
html_print(req->p[i]);
- puts("</OPTION>");
+ puts("</option>");
}
- puts("</SELECT>");
+ puts("</select>");
}
- /* 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("</fieldset>\n"
+ "</form>\n"
+ "</div>");
puts("<!-- End search form. //-->");
}
@@ -477,9 +470,6 @@ validate_manpath(const struct req *req, const char* manpath)
{
size_t i;
- if ( ! strcmp(manpath, "mandoc"))
- return 1;
-
for (i = 0; i < req->psz; i++)
if ( ! strcmp(manpath, req->p[i]))
return 1;
@@ -503,15 +493,16 @@ pg_index(const struct req *req)
{
resp_begin_html(200, NULL);
- resp_searchform(req);
- printf("<P>\n"
+ resp_searchform(req, FOCUS_QUERY);
+ printf("<p>\n"
"This web interface is documented in the\n"
- "<A HREF=\"%s/mandoc/man8/man.cgi.8\">man.cgi</A>\n"
+ "<a href=\"/%s%sman.cgi.8\">man.cgi(8)</a>\n"
"manual, and the\n"
- "<A HREF=\"%s/mandoc/man1/apropos.1\">apropos</A>\n"
+ "<a href=\"/%s%sapropos.1\">apropos(1)</a>\n"
"manual explains the query syntax.\n"
- "</P>\n",
- scriptname, scriptname);
+ "</p>\n",
+ scriptname, *scriptname == '\0' ? "" : "/",
+ scriptname, *scriptname == '\0' ? "" : "/");
resp_end_html();
}
@@ -519,10 +510,10 @@ static void
pg_noresult(const struct req *req, const char *msg)
{
resp_begin_html(200, NULL);
- resp_searchform(req);
- puts("<P>");
+ resp_searchform(req, FOCUS_QUERY);
+ puts("<p>");
puts(msg);
- puts("</P>");
+ puts("</p>");
resp_end_html();
}
@@ -531,12 +522,12 @@ pg_error_badrequest(const char *msg)
{
resp_begin_html(400, "Bad Request");
- puts("<H1>Bad Request</H1>\n"
- "<P>\n");
+ 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);
+ "<a href=\"/%s\">main page</a>.\n"
+ "</p>", scriptname);
resp_end_html();
}
@@ -544,7 +535,7 @@ static void
pg_error_internal(void)
{
resp_begin_html(500, "Internal Server Error");
- puts("<P>Internal Server Error</P>");
+ puts("<p>Internal Server Error</p>");
resp_end_html();
}
@@ -552,28 +543,30 @@ static void
pg_searchres(const struct req *req, struct manpage *r, size_t sz)
{
char *arch, *archend;
- size_t i, iuse, isec;
+ const char *sec;
+ size_t i, iuse;
int archprio, archpriouse;
int prio, priouse;
- char sec;
for (i = 0; i < sz; i++) {
if (validate_filename(r[i].file))
continue;
- fprintf(stderr, "invalid filename %s in %s database\n",
+ warnx("invalid filename %s in %s database",
r[i].file, req->q.manpath);
pg_error_internal();
return;
}
- if (1 == sz) {
+ if (req->isquery && sz == 1) {
/*
* If we have just one result, then jump there now
* without any delay.
*/
printf("Status: 303 See Other\r\n");
- printf("Location: http://%s%s/%s/%s",
- HTTP_HOST, scriptname, req->q.manpath, r[0].file);
+ printf("Location: http://%s/%s%s%s/%s",
+ HTTP_HOST, scriptname,
+ *scriptname == '\0' ? "" : "/",
+ req->q.manpath, r[0].file);
printf("\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"\r\n");
@@ -581,50 +574,57 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
}
resp_begin_html(200, NULL);
- resp_searchform(req);
- puts("<DIV CLASS=\"results\">");
- puts("<TABLE>");
+ resp_searchform(req,
+ req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY);
- for (i = 0; i < sz; i++) {
- printf("<TR>\n"
- "<TD CLASS=\"title\">\n"
- "<A HREF=\"%s/%s/%s",
- scriptname, req->q.manpath, r[i].file);
- printf("\">");
- html_print(r[i].names);
- printf("</A>\n"
- "</TD>\n"
- "<TD CLASS=\"desc\">");
- html_print(r[i].output);
- puts("</TD>\n"
- "</TR>");
- }
+ if (sz > 1) {
+ puts("<div class=\"results\">");
+ puts("<table>");
- puts("</TABLE>\n"
- "</DIV>");
+ for (i = 0; i < sz; i++) {
+ printf("<tr>\n"
+ "<td class=\"title\">\n"
+ "<a href=\"/%s%s%s/%s",
+ scriptname, *scriptname == '\0' ? "" : "/",
+ req->q.manpath, r[i].file);
+ printf("\">");
+ html_print(r[i].names);
+ printf("</a>\n"
+ "</td>\n"
+ "<td class=\"desc\">");
+ html_print(r[i].output);
+ puts("</td>\n"
+ "</tr>");
+ }
+
+ puts("</table>\n"
+ "</div>");
+ }
/*
* In man(1) mode, show one of the pages
* even if more than one is found.
*/
- if (req->q.equal) {
- puts("<HR>");
+ if (req->q.equal || sz == 1) {
+ puts("<hr>");
iuse = 0;
- priouse = 10;
+ priouse = 20;
archpriouse = 3;
for (i = 0; i < sz; i++) {
- isec = strcspn(r[i].file, "123456789");
- sec = r[i].file[isec];
- if ('\0' == sec)
+ sec = r[i].file;
+ sec += strcspn(sec, "123456789");
+ if (sec[0] == '\0')
continue;
- prio = sec_prios[sec - '1'];
- if (NULL == req->q.arch) {
+ prio = sec_prios[sec[0] - '1'];
+ if (sec[1] != '/')
+ prio += 10;
+ if (req->q.arch == NULL) {
archprio =
- (NULL == (arch = strchr(
- r[i].file + isec, '/'))) ? 3 :
- (NULL == (archend = strchr(
- arch + 1, '/'))) ? 0 :
+ ((arch = strchr(sec + 1, '/'))
+ == NULL) ? 3 :
+ ((archend = strchr(arch + 1, '/'))
+ == NULL) ? 0 :
strncmp(arch, "amd64/",
archend - arch) ? 2 : 1;
if (archprio < archpriouse) {
@@ -648,7 +648,7 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
}
static void
-catman(const struct req *req, const char *file)
+resp_catman(const struct req *req, const char *file)
{
FILE *f;
char *p;
@@ -658,12 +658,12 @@ catman(const struct req *req, const char *file)
int italic, bold;
if ((f = fopen(file, "r")) == NULL) {
- puts("<P>You specified an invalid manual file.</P>");
+ puts("<p>You specified an invalid manual file.</p>");
return;
}
- puts("<DIV CLASS=\"catman\">\n"
- "<PRE>");
+ puts("<div class=\"catman\">\n"
+ "<pre>");
p = NULL;
sz = 0;
@@ -689,9 +689,9 @@ catman(const struct req *req, const char *file)
if ('\b' != p[i + 1]) {
if (italic)
- printf("</I>");
+ printf("</i>");
if (bold)
- printf("</B>");
+ printf("</b>");
italic = bold = 0;
html_putchar(p[i]);
continue;
@@ -702,9 +702,9 @@ catman(const struct req *req, const char *file)
if ('_' == p[i]) {
if (bold)
- printf("</B>");
+ printf("</b>");
if ( ! italic)
- printf("<I>");
+ printf("<i>");
bold = 0;
italic = 1;
i += 2;
@@ -726,9 +726,9 @@ catman(const struct req *req, const char *file)
('*' == p[i] && '|' == p[i + 2]) ||
('|' == p[i] && '*' == p[i + 2])) {
if (italic)
- printf("</I>");
+ printf("</i>");
if (bold)
- printf("</B>");
+ printf("</b>");
italic = bold = 0;
putchar('*');
i += 2;
@@ -740,9 +740,9 @@ catman(const struct req *req, const char *file)
('+' == p[i] && '|' == p[i + 1]) ||
('|' == p[i] && '+' == p[i + 1])) {
if (italic)
- printf("</I>");
+ printf("</i>");
if (bold)
- printf("</B>");
+ printf("</b>");
italic = bold = 0;
putchar('+');
i += 2;
@@ -752,9 +752,9 @@ catman(const struct req *req, const char *file)
/* Bold mode. */
if (italic)
- printf("</I>");
+ printf("</i>");
if ( ! bold)
- printf("<B>");
+ printf("<b>");
bold = 1;
italic = 0;
i += 2;
@@ -767,9 +767,9 @@ catman(const struct req *req, const char *file)
*/
if (italic)
- printf("</I>");
+ printf("</i>");
if (bold)
- printf("</B>");
+ printf("</b>");
if (i == len - 1 && p[i] != '\n')
html_putchar(p[i]);
@@ -778,14 +778,14 @@ catman(const struct req *req, const char *file)
}
free(p);
- puts("</PRE>\n"
- "</DIV>");
+ puts("</pre>\n"
+ "</div>");
fclose(f);
}
static void
-format(const struct req *req, const char *file)
+resp_format(const struct req *req, const char *file)
{
struct manoutput conf;
struct mparse *mp;
@@ -795,7 +795,7 @@ format(const struct req *req, const char *file)
int usepath;
if (-1 == (fd = open(file, O_RDONLY, 0))) {
- puts("<P>You specified an invalid manual file.</P>");
+ puts("<p>You specified an invalid manual file.</p>");
return;
}
@@ -807,17 +807,12 @@ format(const struct req *req, const char *file)
memset(&conf, 0, sizeof(conf));
conf.fragment = 1;
usepath = strcmp(req->q.manpath, req->p[0]);
- mandoc_asprintf(&conf.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 : "");
+ mandoc_asprintf(&conf.man, "/%s%s%%N.%%S",
+ usepath ? req->q.manpath : "", usepath ? "/" : "");
mparse_result(mp, &man, NULL);
if (man == NULL) {
- fprintf(stderr, "fatal mandoc error: %s/%s\n",
- req->q.manpath, file);
+ warnx("fatal mandoc error: %s/%s", req->q.manpath, file);
pg_error_internal();
mparse_free(mp);
mchars_free();
@@ -848,9 +843,9 @@ resp_show(const struct req *req, const char *file)
file += 2;
if ('c' == *file)
- catman(req, file);
+ resp_catman(req, file);
else
- format(req, file);
+ resp_format(req, file);
}
static void
@@ -881,18 +876,12 @@ pg_show(struct req *req, const char *fullpath)
*/
if (chdir(manpath) == -1) {
- fprintf(stderr, "chdir %s: %s\n",
- manpath, strerror(errno));
+ warn("chdir %s", manpath);
pg_error_internal();
free(manpath);
return;
}
-
- if (strcmp(manpath, "mandoc")) {
- free(req->q.manpath);
- req->q.manpath = manpath;
- } else
- free(manpath);
+ free(manpath);
if ( ! validate_filename(file)) {
pg_error_badrequest(
@@ -901,7 +890,7 @@ pg_show(struct req *req, const char *fullpath)
}
resp_begin_html(200, NULL);
- resp_searchform(req);
+ resp_searchform(req, FOCUS_NONE);
resp_show(req, file);
resp_end_html();
}
@@ -923,9 +912,8 @@ pg_search(const struct req *req)
* relative to the manpath root.
*/
- if (-1 == (chdir(req->q.manpath))) {
- fprintf(stderr, "chdir %s: %s\n",
- req->q.manpath, strerror(errno));
+ if (chdir(req->q.manpath) == -1) {
+ warn("chdir %s", req->q.manpath);
pg_error_internal();
return;
}
@@ -1000,19 +988,7 @@ main(void)
itimer.it_interval.tv_sec = 2;
itimer.it_interval.tv_usec = 0;
if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) {
- fprintf(stderr, "setitimer: %s\n", strerror(errno));
- pg_error_internal();
- return EXIT_FAILURE;
- }
-
- /* Scan our run-time environment. */
-
- if (NULL == (scriptname = getenv("SCRIPT_NAME")))
- scriptname = "";
-
- if ( ! validate_urifrag(scriptname)) {
- fprintf(stderr, "unsafe SCRIPT_NAME \"%s\"\n",
- scriptname);
+ warn("setitimer");
pg_error_internal();
return EXIT_FAILURE;
}
@@ -1023,20 +999,31 @@ main(void)
* relative to the same position.
*/
- if (-1 == chdir(MAN_DIR)) {
- fprintf(stderr, "MAN_DIR: %s: %s\n",
- MAN_DIR, strerror(errno));
+ if (chdir(MAN_DIR) == -1) {
+ warn("MAN_DIR: %s", MAN_DIR);
pg_error_internal();
return EXIT_FAILURE;
}
memset(&req, 0, sizeof(struct req));
- pathgen(&req);
+ req.q.equal = 1;
+ parse_manpath_conf(&req);
- /* Next parse out the query string. */
+ /* Parse the path info and the query string. */
- if (NULL != (querystring = getenv("QUERY_STRING")))
- http_parse(&req, querystring);
+ if ((path = getenv("PATH_INFO")) == NULL)
+ path = "";
+ else if (*path == '/')
+ path++;
+
+ if (*path != '\0') {
+ parse_path_info(&req, path);
+ if (req.q.manpath == NULL || access(path, F_OK) == -1)
+ path = "";
+ } else if ((querystring = getenv("QUERY_STRING")) != NULL)
+ parse_query_string(&req, querystring);
+
+ /* Validate parsed data and add defaults. */
if (req.q.manpath == NULL)
req.q.manpath = mandoc_strdup(req.p[0]);
@@ -1054,12 +1041,6 @@ main(void)
/* Dispatch to the three different pages. */
- path = getenv("PATH_INFO");
- if (NULL == path)
- path = "";
- else if ('/' == *path)
- path++;
-
if ('\0' != *path)
pg_show(&req, path);
else if (NULL != req.q.query)
@@ -1078,19 +1059,95 @@ main(void)
}
/*
+ * If PATH_INFO is not a file name, translate it to a query.
+ */
+static void
+parse_path_info(struct req *req, const char *path)
+{
+ char *dir[4];
+ int i;
+
+ req->isquery = 0;
+ req->q.equal = 1;
+ req->q.manpath = mandoc_strdup(path);
+ req->q.arch = NULL;
+
+ /* Mandatory manual page name. */
+ if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) {
+ req->q.query = req->q.manpath;
+ req->q.manpath = NULL;
+ } else
+ *req->q.query++ = '\0';
+
+ /* Optional trailing section. */
+ if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) {
+ if(isdigit((unsigned char)req->q.sec[1])) {
+ *req->q.sec++ = '\0';
+ req->q.sec = mandoc_strdup(req->q.sec);
+ } else
+ req->q.sec = NULL;
+ }
+
+ /* Handle the case of name[.section] only. */
+ if (req->q.manpath == NULL)
+ return;
+ req->q.query = mandoc_strdup(req->q.query);
+
+ /* Split directory components. */
+ dir[i = 0] = req->q.manpath;
+ while ((dir[i + 1] = strchr(dir[i], '/')) != NULL) {
+ if (++i == 3) {
+ pg_error_badrequest(
+ "You specified too many directory components.");
+ exit(EXIT_FAILURE);
+ }
+ *dir[i]++ = '\0';
+ }
+
+ /* Optional manpath. */
+ if ((i = validate_manpath(req, req->q.manpath)) == 0)
+ req->q.manpath = NULL;
+ else if (dir[1] == NULL)
+ return;
+
+ /* Optional section. */
+ if (strncmp(dir[i], "man", 3) == 0) {
+ free(req->q.sec);
+ req->q.sec = mandoc_strdup(dir[i++] + 3);
+ }
+ if (dir[i] == NULL) {
+ if (req->q.manpath == NULL)
+ free(dir[0]);
+ return;
+ }
+ if (dir[i + 1] != NULL) {
+ pg_error_badrequest(
+ "You specified an invalid directory component.");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Optional architecture. */
+ if (i) {
+ req->q.arch = mandoc_strdup(dir[i]);
+ if (req->q.manpath == NULL)
+ free(dir[0]);
+ } else
+ req->q.arch = dir[0];
+}
+
+/*
* Scan for indexable paths.
*/
static void
-pathgen(struct req *req)
+parse_manpath_conf(struct req *req)
{
FILE *fp;
char *dp;
size_t dpsz;
ssize_t len;
- if (NULL == (fp = fopen("manpath.conf", "r"))) {
- fprintf(stderr, "%s/manpath.conf: %s\n",
- MAN_DIR, strerror(errno));
+ if ((fp = fopen("manpath.conf", "r")) == NULL) {
+ warn("%s/manpath.conf", MAN_DIR);
pg_error_internal();
exit(EXIT_FAILURE);
}
@@ -1104,14 +1161,14 @@ pathgen(struct req *req)
req->p = mandoc_realloc(req->p,
(req->psz + 1) * sizeof(char *));
if ( ! validate_urifrag(dp)) {
- fprintf(stderr, "%s/manpath.conf contains "
- "unsafe path \"%s\"\n", MAN_DIR, dp);
+ warnx("%s/manpath.conf contains "
+ "unsafe path \"%s\"", 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);
+ if (strchr(dp, '/') != NULL) {
+ warnx("%s/manpath.conf contains "
+ "path with slash \"%s\"", MAN_DIR, dp);
pg_error_internal();
exit(EXIT_FAILURE);
}
@@ -1121,8 +1178,8 @@ pathgen(struct req *req)
}
free(dp);
- if ( req->p == NULL ) {
- fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR);
+ if (req->p == NULL) {
+ warnx("%s/manpath.conf is empty", MAN_DIR);
pg_error_internal();
exit(EXIT_FAILURE);
}
diff --git a/cgi.h.example b/cgi.h.example
index c4878d34a194..7e5f3917b526 100644
--- a/cgi.h.example
+++ b/cgi.h.example
@@ -1,7 +1,8 @@
/* Example compile-time configuration file for man.cgi(8). */
#define HTTP_HOST "mdocml.bsd.lv"
-#define MAN_DIR "/var/www/man"
+#define SCRIPT_NAME "cgi-bin/man.cgi"
+#define MAN_DIR "/man"
#define CSS_DIR ""
#define CUSTOMIZE_TITLE "Manual pages with mandoc"
#define COMPAT_OLDURI Yes
diff --git a/configure b/configure
index 21997fcc2083..6f2c4116bf30 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2014, 2015, 2016 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
@@ -36,7 +36,10 @@ OSNAME=
CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make -f -`
CFLAGS="-g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings"
-DBLIB=
+LDADD=
+LDFLAGS=
+LD_OHASH=
+LD_SQLITE3=
STATIC="-static"
BUILD_DB=1
@@ -55,6 +58,7 @@ HAVE_PROGNAME=
HAVE_REALLOCARRAY=
HAVE_REWB_BSD=
HAVE_REWB_SYSV=
+HAVE_SANDBOX_INIT=
HAVE_STRCASESTR=
HAVE_STRINGLIST=
HAVE_STRLCAT=
@@ -183,6 +187,7 @@ runtest isblank ISBLANK || true
runtest mkdtemp MKDTEMP || true
runtest mmap MMAP || true
runtest pledge PLEDGE || true
+runtest sandbox_init SANDBOX_INIT || true
runtest progname PROGNAME || true
runtest reallocarray REALLOCARRAY || true
runtest rewb-bsd REWB_BSD || true
@@ -198,28 +203,32 @@ runtest vasprintf VASPRINTF || true
runtest wchar WCHAR || true
# --- sqlite3 ---
-DETECTLIB=
if [ ${BUILD_DB} -eq 0 ]; then
echo "BUILD_DB=0 (manual)" 1>&2
echo "BUILD_DB=0 (manual)" 1>&3
echo 1>&3
HAVE_SQLITE3=0
elif ismanual sqlite3 "${HAVE_SQLITE3}"; then
- DETECTLIB="-lsqlite3"
-elif [ -n "${DBLIB}" ]; then
- runtest sqlite3 SQLITE3 "${DBLIB}" || true
+ if [ -z "${LD_SQLITE3}" ]; then
+ LD_SQLITE3="-lsqlite3"
+ fi
+elif [ -n "${LD_SQLITE3}" ]; then
+ runtest sqlite3 SQLITE3 "${LD_SQLITE3}" || true
elif singletest sqlite3 SQLITE3 "-lsqlite3"; then
- DETECTLIB="-lsqlite3"
+ LD_SQLITE3="-lsqlite3"
elif runtest sqlite3 SQLITE3 \
"-I/usr/local/include -L/usr/local/lib -lsqlite3"; then
- DETECTLIB="-L/usr/local/lib -lsqlite3"
+ LD_SQLITE3="-L/usr/local/lib -lsqlite3"
CFLAGS="${CFLAGS} -I/usr/local/include"
fi
-if [ ${BUILD_DB} -gt 0 -a ${HAVE_SQLITE3} -eq 0 ]; then
- echo "BUILD_DB=0 (no sqlite3)" 1>&2
- echo "BUILD_DB=0 (no sqlite3)" 1>&3
- echo 1>&3
- BUILD_DB=0
+if [ ${HAVE_SQLITE3} -eq 0 ]; then
+ LD_SQLITE3=
+ if [ ${BUILD_DB} -gt 0 ]; then
+ echo "BUILD_DB=0 (no sqlite3)" 1>&2
+ echo "BUILD_DB=0 (no sqlite3)" 1>&3
+ echo 1>&3
+ BUILD_DB=0
+ fi
fi
# --- sqlite3_errstr ---
@@ -227,35 +236,30 @@ if [ ${BUILD_DB} -eq 0 ]; then
HAVE_SQLITE3_ERRSTR=1
elif ismanual sqlite3_errstr "${HAVE_SQLITE3_ERRSTR}"; then
:
-elif [ -n "${DBLIB}" ]; then
- runtest sqlite3_errstr SQLITE3_ERRSTR "${DBLIB}" || true
else
- runtest sqlite3_errstr SQLITE3_ERRSTR "${DETECTLIB}" || true
+ runtest sqlite3_errstr SQLITE3_ERRSTR "${LD_SQLITE3}" || true
fi
# --- ohash ---
-if [ ${BUILD_DB} -eq 0 ]; then
- HAVE_OHASH=1
-elif ismanual ohash "${HAVE_OHASH}"; then
+if ismanual ohash "${HAVE_OHASH}"; then
:
-elif [ -n "${DBLIB}" ]; then
- runtest ohash OHASH "${DBLIB}" || true
+elif [ -n "${LD_OHASH}" ]; then
+ runtest ohash OHASH "${LD_OHASH}" || true
elif singletest ohash OHASH; then
:
elif runtest ohash OHASH "-lutil"; then
- DETECTLIB="${DETECTLIB} -lutil"
+ LD_OHASH="-lutil"
fi
-
-# --- DBLIB ---
-if [ ${BUILD_DB} -eq 0 ]; then
- DBLIB="-lz"
-elif [ -z "${DBLIB}" ]; then
- DBLIB="${DETECTLIB} -lz"
- echo "DBLIB=\"${DBLIB}\"" 1>&2
- echo "DBLIB=\"${DBLIB}\"" 1>&3
- echo 1>&3
+if [ "${HAVE_OHASH}" -eq 0 ]; then
+ LD_OHASH=
fi
+# --- LDADD ---
+LDADD="${LDADD} ${LD_SQLITE3} ${LD_OHASH} -lz"
+echo "LDADD=\"${LDADD}\"" 1>&2
+echo "LDADD=\"${LDADD}\"" 1>&3
+echo 1>&3
+
# --- manpath ---
if ismanual manpath "${HAVE_MANPATH}"; then
:
@@ -315,6 +319,7 @@ cat << __HEREDOC__
#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY}
#define HAVE_REWB_BSD ${HAVE_REWB_BSD}
#define HAVE_REWB_SYSV ${HAVE_REWB_SYSV}
+#define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT}
#define HAVE_STRCASESTR ${HAVE_STRCASESTR}
#define HAVE_STRINGLIST ${HAVE_STRINGLIST}
#define HAVE_STRLCAT ${HAVE_STRLCAT}
@@ -426,7 +431,8 @@ BUILD_TARGETS = ${BUILD_TARGETS}
INSTALL_TARGETS = ${INSTALL_TARGETS}
CC = ${CC}
CFLAGS = ${CFLAGS}
-DBLIB = ${DBLIB}
+LDADD = ${LDADD}
+LDFLAGS = ${LDFLAGS}
STATIC = ${STATIC}
PREFIX = ${PREFIX}
BINDIR = ${BINDIR}
diff --git a/configure.local.example b/configure.local.example
index de9f08f1410c..c955a80a3869 100644
--- a/configure.local.example
+++ b/configure.local.example
@@ -1,6 +1,6 @@
-# $Id: configure.local.example,v 1.10 2015/11/07 13:14:21 schwarze Exp $
+# $Id: configure.local.example,v 1.13 2016/07/14 11:09:06 schwarze Exp $
#
-# Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2014, 2015, 2016 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
@@ -65,7 +65,7 @@ MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
# If you do not want uname(3) to be called but instead want a fixed
# string to be used, use the following line:
-OSNAME="OpenBSD 5.6"
+OSNAME="OpenBSD 5.9"
# The following installation directories are used.
# It is possible to set only one or a few of these variables,
@@ -123,6 +123,26 @@ MANM_TBL="mandoc_tbl" # default is "tbl"
BINM_MAN=mman # default is "man"
BINM_SOELIM=msoelim # default is "soelim"
+# Before falling back to the bundled version of the ohash(3) hashing
+# library, autoconfiguration tries the following linker flag to
+# link against your system version. If you do have ohash(3) on
+# your system but it needs different linker flags, set the following
+# variable to specify the required linker flags.
+
+LD_OHASH="-lutil"
+
+# Some platforms may need additional linker flags to link against libmandoc
+# that are not autodetected.
+# For example, Solaris 9 and 10 need -lrt for nanosleep(2).
+
+LDADD="-lrt"
+
+# Some systems may want to set additional linker flags for all the
+# binaries, not only for those using libmandoc, for example for
+# hardening options.
+
+LDFLAGS="-Wl,-z,relro"
+
# It is possible to change the utility program used for installation
# and the modes files are installed with. The defaults are:
@@ -141,18 +161,16 @@ INSTALL_DATA="${INSTALL} -m 0444"
BUILD_DB=0
-# Two libraries are needed: SQLite3 and ohash(3).
-# Autoconfiguration tries the following linker flags to find them.
-# If none of these work, add a working DBLIB line to configure.local,
-# disabling autodetection for library directories.
+# Autoconfiguration tries the following linker flags to find the
+# SQLite3 library installed on your system. If none of these work,
+# set the following variable to specify the required linker flags.
-DBLIB="-lsqlite3"
-DBLIB="-lsqlite3 -lutil"
-DBLIB="-L/usr/local/lib -lsqlite3"
+LD_SQLITE3="-lsqlite3"
+LD_SQLITE3="-L/usr/local/lib -lsqlite3"
# When library autodetection decides to use -L/usr/local/lib,
# -I/usr/local/include is automatically added to CFLAGS.
-# If you manually set DBLIB to something including -L/usr/local/lib,
+# If you manually set LD_SQLITE3 to something including -L/usr/local/lib,
# chances are you will also need the following line:
CFLAGS="${CFLAGS} -I/usr/local/include"
@@ -218,27 +236,45 @@ CGIBINDIR="${WWWPREFIX}/cgi-bin"
CC=cc
+# IBM AIX may need:
+
+CC=xlc
+
# The default compiler flags are:
CFLAGS="-g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings"
+# IBM AIX xlc does not support -W; in that case, please use:
+
+CFLAGS="-g"
+
# In rare cases, it may be required to skip individual automatic tests.
# Each of the following variables can be set to 0 (test will not be run
# and will be regarded as failed) or 1 (test will not be run and will
# be regarded as successful).
HAVE_DIRENT_NAMLEN=0
-HAVE_FGETLN=0
+HAVE_ERR=0
HAVE_FTS=0
+HAVE_GETLINE=0
HAVE_GETSUBOPT=0
+HAVE_ISBLANK=0
+HAVE_MKDTEMP=0
HAVE_MMAP=0
+HAVE_PLEDGE=0
+HAVE_PROGNAME=0
HAVE_REALLOCARRAY=0
+HAVE_REWB_BSD=0
+HAVE_REWB_SYSV=0
HAVE_STRCASESTR=0
+HAVE_STRINGLIST=0
HAVE_STRLCAT=0
HAVE_STRLCPY=0
HAVE_STRPTIME=0
HAVE_STRSEP=0
HAVE_STRTONUM=0
+HAVE_VASPRINTF=0
+HAVE_WCHAR=0
HAVE_SQLITE3=0
HAVE_SQLITE3_ERRSTR=0
diff --git a/demandoc.c b/demandoc.c
index 13b78903da0e..c33fd89169a7 100644
--- a/demandoc.c
+++ b/demandoc.c
@@ -1,4 +1,4 @@
-/* $Id: demandoc.c,v 1.26 2016/01/08 02:53:13 schwarze Exp $ */
+/* $Id: demandoc.c,v 1.27 2016/07/09 15:24:19 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -20,7 +20,6 @@
#include <assert.h>
#include <ctype.h>
-#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/libmandoc.h b/libmandoc.h
index 939ec83c574d..9ed8f15049f6 100644
--- a/libmandoc.h
+++ b/libmandoc.h
@@ -1,4 +1,4 @@
-/* $Id: libmandoc.h,v 1.62 2015/11/07 14:01:16 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.63 2016/07/07 19:19:01 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -38,7 +38,6 @@ struct tbl_span;
struct eqn;
struct roff;
struct roff_man;
-struct roff_node;
void mandoc_msg(enum mandocerr, struct mparse *,
int, int, const char *);
diff --git a/main.c b/main.c
index 2fc2e1eb3f95..527db244283e 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.262 2016/01/08 02:53:13 schwarze Exp $ */
+/* $Id: main.c,v 1.269 2016/07/12 05:18:38 kristaps Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze <schwarze@openbsd.org>
@@ -30,11 +30,15 @@
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
+#if HAVE_SANDBOX_INIT
+#include <sandbox.h>
+#endif
#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "mandoc_aux.h"
@@ -123,9 +127,9 @@ main(int argc, char *argv[])
unsigned char *uc;
struct manpage *res, *resp;
char *conf_file, *defpaths;
- size_t isec, i, sz;
+ const char *sec;
+ size_t i, sz;
int prio, best_prio;
- char sec;
enum outmode outmode;
int fd;
int show_usage;
@@ -158,6 +162,11 @@ main(int argc, char *argv[])
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
+#if HAVE_SANDBOX_INIT
+ if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1)
+ errx((int)MANDOCLEVEL_SYSERR, "sandbox_init");
+#endif
+
/* Search options. */
memset(&conf, 0, sizeof(conf));
@@ -389,7 +398,7 @@ main(int argc, char *argv[])
if (outmode == OUTMODE_ONE) {
argc = 1;
- best_prio = 10;
+ best_prio = 20;
} else if (outmode == OUTMODE_ALL)
argc = (int)sz;
@@ -405,11 +414,13 @@ main(int argc, char *argv[])
res[i].output);
else if (outmode == OUTMODE_ONE) {
/* Search for the best section. */
- isec = strcspn(res[i].file, "123456789");
- sec = res[i].file[isec];
- if ('\0' == sec)
+ sec = res[i].file;
+ sec += strcspn(sec, "123456789");
+ if (sec[0] == '\0')
continue;
- prio = sec_prios[sec - '1'];
+ prio = sec_prios[sec[0] - '1'];
+ if (sec[1] != '/')
+ prio += 10;
if (prio >= best_prio)
continue;
best_prio = prio;
@@ -476,7 +487,7 @@ main(int argc, char *argv[])
conf.output.synopsisonly);
if (argc > 1 && curp.outtype <= OUTT_UTF8)
- ascii_sepline(curp.outdata);
+ terminal_sepline(curp.outdata);
} else if (rc < MANDOCLEVEL_ERROR)
rc = MANDOCLEVEL_ERROR;
@@ -661,8 +672,8 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
found:
#if HAVE_SQLITE3
- warnx("outdated mandoc.db lacks %s(%s) entry, run makewhatis %s",
- name, sec, paths->paths[ipath]);
+ warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
+ name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
#endif
*res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
page = *res + (*ressz - 1);
@@ -681,7 +692,7 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
int argc, char **argv, struct manpage **res, size_t *ressz)
{
const char *const sections[] =
- {"1", "8", "6", "2", "3", "3p", "5", "7", "4", "9"};
+ {"1", "8", "6", "2", "3", "5", "7", "4", "9", "3p"};
const size_t nsec = sizeof(sections)/sizeof(sections[0]);
size_t ipath, isec, lastsz;
@@ -1018,6 +1029,7 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
static pid_t
spawn_pager(struct tag_files *tag_files)
{
+ const struct timespec timeout = { 0, 100000000 }; /* 0.1s */
#define MAX_PAGER_ARGS 16
char *argv[MAX_PAGER_ARGS];
const char *pager;
@@ -1051,11 +1063,11 @@ spawn_pager(struct tag_files *tag_files)
break;
}
- /* For more(1) and less(1), use the tag file. */
+ /* For less(1), use the tag file. */
if ((cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
- if (strcmp(cp, "less") == 0 || strcmp(cp, "more") == 0) {
+ if (strcmp(cp, "less") == 0) {
argv[argc++] = mandoc_strdup("-T");
argv[argc++] = tag_files->tfn;
}
@@ -1067,8 +1079,6 @@ spawn_pager(struct tag_files *tag_files)
case -1:
err((int)MANDOCLEVEL_SYSERR, "fork");
case 0:
- /* Set pgrp in both parent and child to avoid racing exec. */
- (void)setpgid(0, 0);
break;
default:
(void)setpgid(pager_pid, 0);
@@ -1087,6 +1097,12 @@ spawn_pager(struct tag_files *tag_files)
err((int)MANDOCLEVEL_SYSERR, "pager stdout");
close(tag_files->ofd);
close(tag_files->tfd);
+
+ /* Do not start the pager before controlling the terminal. */
+
+ while (tcgetpgrp(STDIN_FILENO) != getpid())
+ nanosleep(&timeout, NULL);
+
execvp(argv[0], argv);
err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
}
diff --git a/main.h b/main.h
index e9e7e8668677..a53df93c38f3 100644
--- a/main.h
+++ b/main.h
@@ -1,4 +1,4 @@
-/* $Id: main.h,v 1.24 2015/11/07 14:01:16 schwarze Exp $ */
+/* $Id: main.h,v 1.25 2016/07/08 22:29:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -43,7 +43,6 @@ void *locale_alloc(const struct manoutput *);
void *utf8_alloc(const struct manoutput *);
void *ascii_alloc(const struct manoutput *);
void ascii_free(void *);
-void ascii_sepline(void *);
void *pdf_alloc(const struct manoutput *);
void *ps_alloc(const struct manoutput *);
@@ -51,3 +50,4 @@ void pspdf_free(void *);
void terminal_mdoc(void *, const struct roff_man *);
void terminal_man(void *, const struct roff_man *);
+void terminal_sepline(void *);
diff --git a/man.1 b/man.1
index f29360bd5f06..0a7ae6d904fc 100644
--- a/man.1
+++ b/man.1
@@ -1,4 +1,4 @@
-.\" $Id: man.1,v 1.16 2015/09/21 09:59:02 schwarze Exp $
+.\" $Id: man.1,v 1.17 2016/07/01 20:24:04 schwarze Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -31,7 +31,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
-.Dd $Mdocdate: September 21 2015 $
+.Dd $Mdocdate: July 1 2016 $
.Dt MAN 1
.Os
.Sh NAME
@@ -209,13 +209,9 @@ architecture whilst using another.
This option overrides the
.Ev MACHINE
environment variable.
-.It Xo
-.Op Fl s
-.Ar section
-.Xc
-Restricts the directories that
-.Nm
-will search to a specific section.
+.It Oo Fl s Oc Ar section
+Only select manuals from the specified
+.Ar section .
The currently available sections are:
.Pp
.Bl -tag -width "localXXX" -offset indent -compact
@@ -225,9 +221,7 @@ General commands
.It 2
System calls and error numbers.
.It 3
-Libraries.
-.It 3f
-Fortran programmer's reference guide.
+Library functions.
.It 3p
.Xr perl 1
programmer's reference guide.
@@ -238,30 +232,12 @@ File formats.
.It 6
Games.
.It 7
-Miscellaneous.
+Miscellaneous information.
.It 8
System maintenance and operation commands.
.It 9
Kernel internals.
-.It X11
-An alias for X11R6.
-.It X11R6
-X Window System.
-.It local
-Pages located in
-.Pa /usr/local .
-.It n
-Tcl/Tk commands.
.El
-.Pp
-The
-.Nm
-configuration file,
-.Xr man.conf 5 ,
-specifies the possible
-.Ar section
-values, and their search order.
-Additional sections may be specified.
.It Fl T Ar output
Select the output format.
The default is
diff --git a/man.cgi.3 b/man.cgi.3
new file mode 100644
index 000000000000..e7c1d2fca0ca
--- /dev/null
+++ b/man.cgi.3
@@ -0,0 +1,287 @@
+.\" $Id: man.cgi.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $
+.\"
+.\" Copyright (c) 2016 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.
+.\"
+.Dd $Mdocdate: July 7 2016 $
+.Dt MAN.CGI 3
+.Os
+.Sh NAME
+.Nm man.cgi
+.Nd internals of the CGI program to search and display manual pages
+.Sh DESCRIPTION
+The source code of
+.Xr man.cgi 8
+is organized in four levels:
+.Pp
+.Bl -enum -compact
+.It
+.Sx Top level
+.It
+.Sx Page generators
+.It
+.Sx Result generators
+.It
+.Sx Utility routines
+.El
+.Ss Top level
+The top level of
+.Xr man.cgi 8
+consists of the
+.Fn main
+program and a few parser routines.
+.Bl -tag -width 1n
+.It Ft int Fn main void
+The main program
+.Bl -dash -compact
+.It
+limits execution time;
+.It
+changes to
+.Dv MAN_DIR ,
+the data directory containing all the manual trees;
+.It
+calls
+.Fn parse_manpath_conf ;
+.It
+if
+.Ev PATH_INFO
+is empty, calls
+.Fn parse_query_string ;
+otherwise,
+calls
+.Fn parse_path_info ;
+.It
+validates the manpath and the architecture;
+.It
+calls the appropriate one among the
+.Sx Page generators .
+.El
+.It Ft void Fn parse_manpath_conf "struct req *req"
+Parses and validates
+.Pa manpath.conf
+and fills
+.Va req->p
+and
+.Va req->psz .
+.It Ft void Fn parse_path_info "struct req *req" "const char *path"
+Parses and validates
+.Ev PATH_INFO ,
+clears
+.Va req->isquery ,
+and fills
+.Va req->q .
+.It Ft void Fn parse_query_string "struct req *req" "const char *qs"
+Parses and validates
+.Ev QUERY_STRING ,
+sets
+.Va req->isquery ,
+and fills
+.Va req->q .
+This function is the only user of the utility functions
+.Fn http_decode
+and
+.Fn set_query_attr .
+.El
+.Ss Page generators
+The purpose of each page generator is to print a complete HTML page,
+starting with the HTTP headers and continuing to the page footer.
+Before starting HTML output with
+.Fn resp_begin_html ,
+some page generators do some preparatory work, for example to decide
+which page to show.
+Each page generator ends with a call to
+.Fn resp_end_html .
+.Bl -tag -width 1n
+.It Ft void Fn pg_show "struct req *req" "const char *fullpath"
+This page generator is used when
+.Ev PATH_INFO
+contains the complete path to a manual page including manpath,
+section directory, optional architecture subdirectory, manual name
+and section number suffix.
+It validates the manpath, changes into it, validate the filename,
+and then calls
+.Fn resp_begin_html ,
+.Fn resp_searchform ,
+.Fn resp_show ,
+and
+.Fn resp_end_html
+in that order.
+.It Ft void Fn pg_search "const struct req *req"
+This page generator is used when
+.Ev PATH_INFO
+contains a search query in short format or when
+.Ev PATH_INFO
+is empty and a
+.Ev QUERY_STRING
+is provided.
+It changes into the manpath and calls
+.Xr mansearch 3 .
+Depending on the result, it calls either
+.Fn pg_noresult
+or
+.Fn pg_searchres .
+.It Ft void Fn pg_noresult "const struct req *req" "const char *msg"
+This function calls
+.Fn resp_begin_html ,
+.Fn resp_searchform ,
+prints the
+.Fa msg
+passed to it, and calls
+.Fn resp_end_html .
+.It Ft void Fn pg_searchres "const struct req *req" "struct manpage *r"\
+ "size_t sz"
+This function first validates the filenames found.
+If
+.Ev QUERY_STRING
+was used and there is exactly one result,
+it writes an HTTP redirect to that result.
+Otherwise, it writes an HTML result page beginning with
+.Fn resp_begin_html
+and
+.Fn resp_searchform .
+If there is more than one result, it writes a list of links
+to all the results.
+If it was a
+.Xr man 1
+rather than an
+.Xr apropos 1
+query or if there is only one single result, it calls
+.Fn resp_show .
+Finally, it calls
+.Fn resp_end_html .
+.It Ft void Fn pg_index "const struct req *req"
+This page generator is used when
+.Ev PATH_INFO
+and
+.Ev QUERY_STRING
+are both empty.
+It calls
+.Fn resp_begin_html
+and
+.Fn resp_searchform ,
+writes links to help pages, and calls
+.Fn resp_end_html .
+.It Ft void Fn pg_error_badrequest "const char *msg"
+This page generator is used when
+.Fn main
+or
+.Fn pg_show
+detect an invalid URI.
+It calls
+.Fn resp_begin_html ,
+prints the
+.Fa msg
+provided, and calls
+.Fn resp_end_html .
+.It Ft void Fn pg_error_internal void
+This page generator is used by various functions when errors are
+detected in the
+.Pa manpath.conf
+configuration file, in
+.Xr mandoc.db 5
+databases, in the
+.Xr mandoc 3
+parser, in file system permissions, or when setting up timeouts.
+It calls
+.Fn resp_begin_html ,
+prints
+.Qq "Internal Server Error" ,
+and calls
+.Fn resp_end_html .
+Before calling
+.Fn pg_error_internal ,
+call
+.Xr warn 3
+or
+.Xr warnx 3
+to log the reason of the error to the
+.Xr httpd 8
+server log file.
+.El
+.Ss Result generators
+The purpose of result generators is to print a chunk of HTML code.
+When they print untrusted strings or characters,
+.Fn html_print
+and
+.Fn html_putchar
+are used.
+The highest level result generators are:
+.Bl -tag -width 1n
+.It Ft void Fn resp_begin_html "int code" "const char *msg"
+This generator calls
+.Fn resp_begin_http
+to print the HTTP headers, then prints the HTML header up to the
+opening tag of the <body> element, then copies the file
+.Pa header.html
+to the output, if it exists and is readable.
+.It Ft void Fn resp_searchform "const struct req *req" "enum focus focus"
+This generator prints a search form, filling it with data
+from the provided request object.
+If the
+.Fa focus
+argument is
+.Dv FOCUS_QUERY ,
+it sets the document's autofocus to the query input box.
+.It Ft void Fn resp_show "const struct req *req" "const char *file"
+This wrapper dispatches to either
+.Fn resp_catman
+or
+.Fn resp_format ,
+depending on whether
+.Ar file
+starts with
+.Pa cat
+or
+.Pa man ,
+respectively.
+.It Ft void Fn resp_catman "const struct req *req" "const char *file"
+This generator translates a preformatted, backspace-encoded manual
+page to HTML and prints it to the output.
+.It Ft void Fn resp_format "const struct req *req" "const char *file"
+This generator formats a manual page on the standard output,
+using the functions documented in
+.Xr mchars_alloc 3
+and
+.Xr mandoc 3 .
+.It Ft void Fn resp_end_html void
+This generator copies the file
+.Pa footer.html
+to the output, if it exists and is readable,
+and closes the <body> and <html> elements.
+.El
+.Ss Utility routines
+These functions take a string and return 1 if it is valid, or 0 otherwise.
+.Bl -tag -width 1n
+.It Ft int Fn validate_urifrag "const char *frag"
+Checks that the string only contains alphanumeric ASCII characters,
+dashes, dots, slashes, and underscores.
+.It Ft int Fn validate_manpath "const struct req *req" "const char* manpath"
+Checks that the string is either
+.Qq mandoc
+or one of the manpaths configured in
+.Pa manpath.conf .
+.It Ft int Fn validate_filename "const char *file"
+Checks that the string starts with
+.Qq man
+or
+.Qq cat
+and does not ascend to parent directories.
+.El
+.Sh SEE ALSO
+.Xr mandoc 3 ,
+.Xr mansearch 3 ,
+.Xr mchars_alloc 3 ,
+.Xr mandoc.db 5 ,
+.Xr man.cgi 8
diff --git a/man.cgi.8 b/man.cgi.8
index 2e54dbf4b81f..0e1b60d61a04 100644
--- a/man.cgi.8
+++ b/man.cgi.8
@@ -1,6 +1,6 @@
-.\" $Id: man.cgi.8,v 1.13 2015/11/05 20:55:41 schwarze Exp $
+.\" $Id: man.cgi.8,v 1.20 2016/07/11 22:48:37 schwarze Exp $
.\"
-.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2014, 2015, 2016 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
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 5 2015 $
+.Dd $Mdocdate: July 11 2016 $
.Dt MAN.CGI 8
.Os
.Sh NAME
@@ -26,9 +26,9 @@ The
CGI program searches for manual pages on a WWW server
and displays them to HTTP clients,
providing functionality equivalent to the
-.Xr apropos 1
-and
.Xr man 1
+and
+.Xr apropos 1
utilities.
It can use multiple manual trees in parallel.
.Ss HTML search interface
@@ -51,20 +51,15 @@ The effect of prepending a backslash to another character is undefined;
in the current implementation, it has no effect.
.It
A
-.Dq Submit
-button to send a search request from the client to the server.
-.It
-A
-.Dq Reset
-button to undo any changes to the input boxes and the dropdown menus
-and reset them to the values contained in the
-.Ev QUERY_STRING .
-.It
-Radio buttons to select pages either by name like in
.Xr man 1
-or using
+submit button.
+The string in the input box is interpreted as the name of a manual page.
+.It
+An
.Xr apropos 1
-queries.
+submit button.
+The string in the input box is interpreted as a search
+.Ar expression .
.It
A dropdown menu to optionally select a manual section.
If one is provided, it has the same effect as the
@@ -162,9 +157,7 @@ Configure your web server to execute CGI programs located in
.Pa /cgi-bin .
When using
.Ox
-.Xr httpd 8
-or
-.Xr nginx 8 ,
+.Xr httpd 8 ,
the
.Xr slowcgi 8
proxy daemon is needed to translate FastCGI requests to plain old CGI.
@@ -183,31 +176,42 @@ Only useful for running on www.openbsd.org to deal with old URIs containing
.Qq "manpath=OpenBSD "
where the blank character has to be translated to a hyphen.
When compiling for other sites, this definition can be deleted.
-.It Ev CSS_DIR
-An optional path to the directory containing the CSS files,
+.It Dv CSS_DIR
+An optional file system path to the directory containing the file
+.Pa mandoc.css ,
to be specified relative to the server's document root,
and to be specified without a trailing slash.
-When not specified, the CSS files
-are assumed to be in the document root.
+When empty, the CSS file is assumed to be in the document root.
+Otherwise, a leading slash is needed.
This is used in generated HTML code.
-.It Ev CUSTOMIZE_TITLE
+.It Dv CUSTOMIZE_TITLE
An ASCII string to be used for the HTML <TITLE> element.
-.It Ev HTTP_HOST
+.It Dv HTTP_HOST
The FQDN of the (possibly virtual) host the HTTP server is running on.
This is used for
.Ic Location:
headers in HTTP 303 responses.
-.It Ev MAN_DIR
-A path to the
+.It Dv MAN_DIR
+A file system path to the
.Nm
-data directory to be used instead of
-.Pa /var/www/man ,
-relative to the web server
+data directory relative to the web server
.Xr chroot 2
-directory, to be specified without a trailing slash.
-This is prepended to the manpath when opening
+directory, to be specified with a leading slash and without a trailing slash.
+It needs to have at least one component; the root directory cannot be used
+for this purpose.
+The files
+.Pa manpath.conf ,
+.Pa header.html ,
+and
+.Pa footer.html
+are looked up in this directory.
+It is also prepended to the manpath when opening
.Xr mandoc.db 5
and manual page files.
+.It Dv SCRIPT_NAME
+The initial component of URIs, to be specified without leading
+and trailing slashes.
+It can be empty.
.El
.Pp
After editing
@@ -216,13 +220,16 @@ run
.Pp
.Dl make man.cgi
.Pp
-and copy the files to the proper locations.
-Reading the
-.Cm installcgi
-target in the
-.Pa Makefile
-can help with that, but do not run it without carefully checking it
-because the directory layouts of web servers vary greatly.
+and copy the resulting binary to the proper location,
+for example using the command:
+.Pp
+.Dl make installcgi
+.Pp
+In addition to that, make sure the default manpath contains the files
+.Pa man1/apropos.1
+and
+.Pa man8/man.cgi.8 ,
+or the documentation links at the bottom of the index page will not work.
.Ss URI interface
.Nm
uniform resource identifiers are not needed for interactive use,
@@ -234,14 +241,22 @@ The
.Cm http://
protocol specifier.
.It
-The host name and a following slash.
+The host name.
.It
-The path to the program, normally
-.Pa cgi-bin/man.cgi/ .
+The
+.Dv SCRIPT_NAME ,
+preceded by a slash unless empty.
.It
To show a single page, a slash, the manpath, another slash,
and the name of the requested file, for example
.Pa /OpenBSD-current/man1/mandoc.1 .
+This can be abbreviated according to the following syntax:
+.Sm off
+.Op / Ar manpath
+.Op / Cm man Ar sec
+.Op / Ar arch
+.Pf / Ar name Op \&. Ar sec
+.Sm on
.It
For searches, a query string starting with a question mark
and consisting of
@@ -295,13 +310,20 @@ the underscore
.Pq Sq _
.El
.Pp
-In particular, this applies to the
-.Ev SCRIPT_NAME ,
-to all manpaths, and to all architecture names.
+In particular, this applies to all manpaths and architecture names.
.Sh ENVIRONMENT
The web server may pass the following CGI variables to
.Nm :
.Bl -tag -width Ds
+.It Ev SCRIPT_NAME
+The initial part of the URI passed from the client to the server,
+starting after the server's host name and ending before
+.Ev PATH_INFO .
+This is ignored by
+.Nm .
+When constructing URIs for links and redirections, the
+.Dv SCRIPT_NAME
+preprocessor constant is used instead.
.It Ev PATH_INFO
The final part of the URI path passed from the client to the server,
starting after the
@@ -317,17 +339,6 @@ It is the final part of the URI, after the question mark.
It is used by the
.Cm search
page to acquire the named parameters it needs.
-.It Ev SCRIPT_NAME
-The path to the
-.Nm
-binary relative to the server root, usually
-.Pa /cgi-bin/man.cgi .
-This is used for generating URIs to be embedded
-in generated HTML code and HTTP headers.
-If this contains any character not contained in the
-.Sx Restricted character set ,
-.Nm
-reports an internal server error and exits without doing anything.
.El
.Sh FILES
.Bl -tag -width Ds
@@ -337,13 +348,18 @@ Default web server
directory.
All the following paths are specified relative to this directory.
.It Pa /cgi-bin/man.cgi
-The path to the
+The usual file system path to the
.Nm
-program relative to the server root.
-Can be overridden by
-.Ev SCRIPT_NAME .
+program inside the web server
+.Xr chroot 2
+directory.
+A different name can be chosen, but in any case, it needs to be configured in
+.Xr httpd.conf 5 .
.It Pa /htdocs
-The path to the server document root relative to the server root.
+The file system path to the server document root directory
+relative to the server
+.Xr chroot 2
+directory.
This is part of the web server configuration and not specific to
.Nm .
.It Pa /htdocs/mandoc.css
@@ -355,11 +371,7 @@ Default
.Nm
data directory containing all the manual trees.
Can be overridden by
-.Ev MAN_DIR .
-.It Pa /man/mandoc/man1/apropos.1 , /man/mandoc/man8/man.cgi.8
-Manual pages documenting
-.Nm
-itself, linked from the index page.
+.Dv MAN_DIR .
.It Pa /man/manpath.conf
The list of available manpaths, one per line.
If any of the lines in this file contains a slash
diff --git a/mandoc.3 b/mandoc.3
index 61012edec95e..18b5707c492e 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.3,v 1.36 2016/01/08 17:48:09 schwarze Exp $
+.\" $Id: mandoc.3,v 1.37 2016/07/07 19:19:01 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,18 +15,16 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: January 8 2016 $
+.Dd $Mdocdate: July 7 2016 $
.Dt MANDOC 3
.Os
.Sh NAME
.Nm mandoc ,
-.Nm man_deroff ,
-.Nm man_meta ,
+.Nm deroff ,
+.Nm mandocmsg ,
.Nm man_mparse ,
-.Nm man_node ,
-.Nm mdoc_deroff ,
-.Nm mdoc_meta ,
-.Nm mdoc_node ,
+.Nm man_validate ,
+.Nm mdoc_validate ,
.Nm mparse_alloc ,
.Nm mparse_free ,
.Nm mparse_getkeep ,
@@ -91,8 +89,7 @@
.Ft void
.Fo mparse_result
.Fa "struct mparse *parse"
-.Fa "struct mdoc **mdoc"
-.Fa "struct man **man"
+.Fa "struct roff_man **man"
.Fa "char **sodest"
.Fc
.Ft "const char *"
@@ -103,45 +100,33 @@
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
-.In sys/types.h
-.In mandoc.h
-.In mdoc.h
+.In roff.h
.Ft void
-.Fo mdoc_deroff
+.Fo deroff
.Fa "char **dest"
-.Fa "const struct mdoc_node *node"
-.Fc
-.Ft "const struct mdoc_meta *"
-.Fo mdoc_meta
-.Fa "const struct mdoc *mdoc"
-.Fc
-.Ft "const struct mdoc_node *"
-.Fo mdoc_node
-.Fa "const struct mdoc *mdoc"
+.Fa "const struct roff_node *node"
.Fc
+.In sys/types.h
+.In mandoc.h
+.In mdoc.h
.Vt extern const char * const * mdoc_argnames;
.Vt extern const char * const * mdoc_macronames;
+.Ft void
+.Fo mdoc_validate
+.Fa "struct roff_man *mdoc"
+.Fc
.In sys/types.h
.In mandoc.h
.In man.h
-.Ft void
-.Fo man_deroff
-.Fa "char **dest"
-.Fa "const struct man_node *node"
-.Fc
-.Ft "const struct man_meta *"
-.Fo man_meta
-.Fa "const struct man *man"
-.Fc
+.Vt extern const char * const * man_macronames;
.Ft "const struct mparse *"
.Fo man_mparse
-.Fa "const struct man *man"
+.Fa "const struct roff_man *man"
.Fc
-.Ft "const struct man_node *"
-.Fo man_node
-.Fa "const struct man *man"
+.Ft void
+.Fo man_validate
+.Fa "struct roff_man *man"
.Fc
-.Vt extern const char * const * man_macronames;
.Sh DESCRIPTION
The
.Nm mandoc
@@ -182,10 +167,24 @@ close it with
retrieve the syntax tree with
.Fn mparse_result ;
.It
-iterate over parse nodes with
-.Fn mdoc_node
+depending on whether the
+.Fa macroset
+member of the returned
+.Vt struct roff_man
+is
+.Dv MACROSET_MDOC
+or
+.Dv MACROSET_MAN ,
+validate it with
+.Fn mdoc_validate
or
-.Fn man_node ;
+.Fn man_validate ,
+respectively;
+.It
+iterate over parse nodes with starting from the
+.Fa first
+member of the returned
+.Vt struct roff_man ;
.It
free all allocated memory with
.Fn mparse_free
@@ -193,7 +192,7 @@ and
.Xr mchars_free 3 ,
or invoke
.Fn mparse_reset
-and parse new files.
+and go back to step 2 to parse new files.
.El
.Sh REFERENCE
This section documents the functions, types, and variables available
@@ -211,6 +210,9 @@ An error or warning message during parsing.
A classification of an
.Vt "enum mandocerr"
as regards system operation.
+See the DIAGNOSTICS section in
+.Xr mandoc 1
+regarding the meanings of the levels.
.It Vt "struct mparse"
An opaque pointer to a running parse sequence.
Created with
@@ -226,67 +228,37 @@ messages emitted by the parser.
.El
.Ss Functions
.Bl -ohang
-.It Fn man_deroff
+.It Fn deroff
Obtain a text-only representation of a
-.Vt struct man_node ,
+.Vt struct roff_node ,
including text contained in its child nodes.
-To be used on children of the pointer returned from
-.Fn man_node .
+To be used on children of the
+.Fa first
+member of
+.Vt struct roff_man .
When it is no longer needed, the pointer returned from
-.Fn man_deroff
+.Fn deroff
can be passed to
.Xr free 3 .
-.It Fn man_meta
-Obtain the meta-data of a successful
-.Xr man 7
-parse.
-This may only be used on a pointer returned by
-.Fn mparse_result .
-Declared in
-.In man.h ,
-implemented in
-.Pa man.c .
.It Fn man_mparse
Get the parser used for the current output.
Declared in
.In man.h ,
implemented in
.Pa man.c .
-.It Fn man_node
-Obtain the root node of a successful
-.Xr man 7
-parse.
-This may only be used on a pointer returned by
+.It Fn man_validate
+Validate the
+.Dv MACROSET_MAN
+parse tree obtained with
.Fn mparse_result .
Declared in
.In man.h ,
implemented in
.Pa man.c .
-.It Fn mdoc_deroff
-Obtain a text-only representation of a
-.Vt struct mdoc_node ,
-including text contained in its child nodes.
-To be used on children of the pointer returned from
-.Fn mdoc_node .
-When it is no longer needed, the pointer returned from
-.Fn mdoc_deroff
-can be passed to
-.Xr free 3 .
-.It Fn mdoc_meta
-Obtain the meta-data of a successful
-.Xr mdoc
-parse.
-This may only be used on a pointer returned by
-.Fn mparse_result .
-Declared in
-.In mdoc.h ,
-implemented in
-.Pa mdoc.c .
-.It Fn mdoc_node
-Obtain the root node of a successful
-.Xr mdoc
-parse.
-This may only be used on a pointer returned by
+.It Fn mdoc_validate
+Validate the
+.Dv MACROSET_MDOC
+parse tree obtained with
.Fn mparse_result .
Declared in
.In mdoc.h ,
@@ -335,6 +307,9 @@ A callback function to handle errors and warnings.
See
.Pa main.c
for an example.
+If printing of error messages is not desired,
+.Dv NULL
+may be passed.
.It Ar defos
A default string for the
.Xr mdoc 7
@@ -343,6 +318,9 @@ macro, overriding the
.Dv OSNAME
preprocessor definition and the results of
.Xr uname 3 .
+Passing
+.Dv NULL
+sets no default.
.El
.Pp
The same parser may be used for multiple files so long as
@@ -421,7 +399,7 @@ implemented in
.Pa read.c .
.It Fn mparse_result
Obtain the result of a parse.
-One of the three pointers will be filled in.
+One of the two pointers will be filled in.
Declared in
.In mandoc.h ,
implemented in
@@ -442,13 +420,19 @@ implemented in
.Ss Variables
.Bl -ohang
.It Va man_macronames
-The string representation of a man macro as indexed by
+The string representation of a
+.Xr man 7
+macro as indexed by
.Vt "enum mant" .
.It Va mdoc_argnames
-The string representation of a mdoc macro argument as indexed by
+The string representation of an
+.Xr mdoc 7
+macro argument as indexed by
.Vt "enum mdocargt" .
.It Va mdoc_macronames
-The string representation of a mdoc macro as indexed by
+The string representation of an
+.Xr mdoc 7
+macro as indexed by
.Vt "enum mdoct" .
.El
.Sh IMPLEMENTATION NOTES
@@ -492,15 +476,15 @@ This AST is governed by the ontological rules dictated in
and derives its terminology accordingly.
.Pp
The AST is composed of
-.Vt struct man_node
+.Vt struct roff_node
nodes with element, root and text types as declared by the
.Va type
field.
Each node also provides its parse point (the
.Va line ,
-.Va sec ,
+.Va pos ,
and
-.Va pos
+.Va sec
fields), its position in the tree (the
.Va parent ,
.Va child ,
@@ -544,16 +528,16 @@ are described simply as
.Qq elements .
.Pp
The AST is composed of
-.Vt struct mdoc_node
+.Vt struct roff_node
nodes with block, head, body, element, root and text types as declared
by the
.Va type
field.
Each node also provides its parse point (the
.Va line ,
-.Va sec ,
+.Va pos ,
and
-.Va pos
+.Va sec
fields), its position in the tree (the
.Va parent ,
.Va child ,
@@ -670,9 +654,13 @@ consistent across troff implementations, especially when using multiple
levels of badly-nested blocks.
.Sh SEE ALSO
.Xr mandoc 1 ,
+.Xr man.cgi 3 ,
.Xr mandoc_escape 3 ,
+.Xr mandoc_headers 3 ,
.Xr mandoc_malloc 3 ,
+.Xr mansearch 3 ,
.Xr mchars_alloc 3 ,
+.Xr tbl 3 ,
.Xr eqn 7 ,
.Xr man 7 ,
.Xr mandoc_char 7 ,
@@ -680,7 +668,10 @@ levels of badly-nested blocks.
.Xr roff 7 ,
.Xr tbl 7
.Sh AUTHORS
+.An -nosplit
The
.Nm
library was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and is maintained by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/mandoc.css b/mandoc.css
index 38c5c58b1704..90085061fc08 100644
--- a/mandoc.css
+++ b/mandoc.css
@@ -1,4 +1,4 @@
-/* $Id: mandoc.css,v 1.1 2015/11/05 17:47:51 schwarze Exp $ */
+/* $Id: mandoc.css,v 1.2 2016/04/13 10:19:23 schwarze Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
@@ -24,7 +24,8 @@ body > div.results { font-size: smaller; }
#mancgi input[name=expr] { width: 25%; }
.results td.title { vertical-align: top;
padding-right: 1em; }
-h1 { margin-bottom: 1ex; font-size: 110%; margin-left: -4ex; } /* Section header (Sh, SH). */
+h1 { margin-bottom: 1ex; font-size: 110% }
+div.section > h1 { margin-left: -4ex; } /* Section header (Sh, SH). */
h2 { margin-bottom: 1ex; font-size: 105%; margin-left: -2ex; } /* Sub-section header (Ss, SS). */
table { width: 100%; margin-top: 0ex; margin-bottom: 0ex; } /* All tables. */
td { vertical-align: top; } /* All table cells. */
diff --git a/mandoc.db.5 b/mandoc.db.5
index 60908bc4d397..de6ea11bd0df 100644
--- a/mandoc.db.5
+++ b/mandoc.db.5
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.db.5,v 1.3 2014/12/30 21:34:57 schwarze Exp $
+.\" $Id: mandoc.db.5,v 1.4 2016/07/07 14:35:48 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" 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 30 2014 $
+.Dd $Mdocdate: July 7 2016 $
.Dt MANDOC.DB 5
.Os
.Sh NAME
@@ -133,7 +133,6 @@ The same for
.Xr man 1 ,
.Xr sqlite3 1 ,
.Xr whatis 1 ,
-.Xr mansearch 3 ,
.Xr makewhatis 8
.Sh HISTORY
A manual page database
diff --git a/mandoc_headers.3 b/mandoc_headers.3
index 6c30e16491eb..b8c204bb5bcf 100644
--- a/mandoc_headers.3
+++ b/mandoc_headers.3
@@ -62,6 +62,11 @@ for
.Vt size_t .
Provides the utility functions documented in
.Xr mandoc_malloc 3 .
+.It Qq Pa mandoc_ohash.h
+Includes
+.In ohash.h
+and provides
+.Fn mandoc_ohash_init .
.It Qq Pa mandoc.h
Requires
.In sys/types.h
@@ -80,7 +85,6 @@ Provides
.Vt enum eqn_pilet ,
.Vt enum eqn_post ,
.Vt struct tbl_opts ,
-.Vt struct tbl_head ,
.Vt struct tbl_cell ,
.Vt struct tbl_row ,
.Vt struct tbl_dat ,
@@ -103,30 +107,30 @@ Uses the opaque type
from
.Pa read.c
for function prototypes.
-Uses the types
-.Vt struct mdoc
-from
-.Pa libmdoc.h
-and
-.Vt struct man
+Uses the type
+.Vt struct roff_man
from
-.Pa libman.h
-as opaque types for function prototypes.
+.Pa roff.h
+as an opaque type for function prototypes.
.It Qq Pa roff.h
Provides
.Vt enum mdoc_endbody ,
+.Vt enum roff_macroset ,
+.Vt enum roff_next ,
.Vt enum roff_sec ,
.Vt enum roff_type ,
+.Vt struct roff_man ,
.Vt struct roff_meta ,
-and
-.Vt struct roff_node .
+.Vt struct roff_node ,
+and the function
+.Fn deroff .
.Pp
Uses pointers to the types
.Vt struct mdoc_arg
and
.Vt union mdoc_data
from
-.Qq Pa mdoc.h
+.Pa mdoc.h
as opaque struct members.
.El
.Pp
@@ -139,51 +143,38 @@ Afterwards, any other mandoc headers can be included as needed.
Requires
.In sys/types.h
for
-.Vt size_t
-and
-.Qq Pa roff.h
-for
-.Vt enum roff_type .
+.Vt size_t .
.Pp
Provides
.Vt enum mdocargt ,
-.Vt enum mdoc_disp ,
-.Vt enum mdoc_list ,
.Vt enum mdoc_auth ,
+.Vt enum mdoc_disp ,
.Vt enum mdoc_font ,
+.Vt enum mdoc_list ,
.Vt struct mdoc_argv ,
.Vt struct mdoc_arg ,
-.Vt struct mdoc_bd ,
-.Vt struct mdoc_bl ,
.Vt struct mdoc_an ,
+.Vt struct mdoc_bd ,
.Vt struct mdoc_bf ,
+.Vt struct mdoc_bl ,
.Vt struct mdoc_rs ,
+.Vt union mdoc_data ,
and the functions
.Fn mdoc_*
described in
.Xr mandoc 3 .
.Pp
Uses the type
-.Vt struct mdoc
+.Vt struct roff_man
from
-.Pa libmdoc.h
+.Pa roff.h
as an opaque type for function prototypes.
-Uses pointers to the types
-.Vt struct tbl_span
-and
-.Vt struct eqn
-as opaque struct members.
.Pp
When this header is included, the same file should not include
.Pa libman.h
or
.Pa libroff.h .
.It Qq Pa man.h
-Requires
-.Qq Pa roff.h
-for
-.Vt enum roff_type .
-.Pp
Provides the functions
.Fn man_*
described in
@@ -195,15 +186,10 @@ from
.Pa read.c
for function prototypes.
Uses the type
-.Vt struct man
+.Vt struct roff_man
from
-.Pa libman.h
+.Pa roff.h
as an opaque type for function prototypes.
-Uses pointers to the types
-.Vt struct tbl_span
-and
-.Vt struct eqn
-as opaque struct members.
.Pp
When this header is included, the same file should not include
.Pa libmdoc.h
@@ -220,16 +206,11 @@ are included, the same file should not include any formatter headers.
Requires
.In sys/types.h
for
-.Vt size_t ,
-.Qq Pa mandoc.h
-for
-.Vt enum mandocerr ,
+.Vt size_t
and
-.Qq Pa roff.h
+.Qq Pa mandoc.h
for
-.Vt struct roff_meta
-and
-.Vt struct roff_node .
+.Vt enum mandocerr .
.Pp
Provides
.Vt enum rofferr ,
@@ -251,14 +232,42 @@ Uses the types
and
.Vt struct eqn
from
+.Pa mandoc.h
+and
+.Vt struct roff_man
+from
+.Pa roff.h
+as opaque types for function prototypes.
+.It Qq Pa roff_int.h
+Requires
+.Qq Pa roff.h
+for
+.Vt enum roff_type .
+.Pp
+Provides functions named
+.Fn roff_*
+to handle roff nodes and the two special functions
+.Fn man_breakscope
+and
+.Fn mdoc_argv_free
+because the latter two are needed by
+.Qq Pa roff.c .
+.Pp
+Uses the types
+.Vt struct eqn
+and
+.Vt struct tbl_span
+from
.Pa mandoc.h ,
-.Vt struct mdoc
+.Vt struct roff_man
+and
+.Vt struct roff_node
from
-.Pa libmdoc.h ,
+.Pa roff.h ,
and
-.Vt struct man
+.Vt struct mdoc_arg
from
-.Pa libman.h
+.Pa mdoc.h
as opaque types for function prototypes.
.It Qq Pa libmdoc.h
Requires
@@ -269,23 +278,24 @@ and
.Vt struct mdoc_* .
.Pp
Provides
-.Vt enum mdoc_next ,
.Vt enum margserr ,
.Vt enum mdelim ,
-.Vt struct mdoc ,
.Vt struct mdoc_macro ,
and many functions internal to the
.Xr mdoc 7
parser.
.Pp
-Uses the opaque types
+Uses the opaque type
.Vt struct mparse
from
-.Pa read.c
+.Pa read.c .
+Uses the types
+.Vt struct roff_man
and
-.Vt struct roff
+.Vt struct roff_node
from
-.Pa roff.c .
+.Pa roff.h
+as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa man.h ,
@@ -293,29 +303,19 @@ When this header is included, the same file should not include
or
.Pa libroff.h .
.It Qq Pa libman.h
-Requires
-.Qq Pa roff.h
-for
-.Vt struct roff_meta
-and
-.Vt struct roff_node .
-.Pp
Provides
-.Vt enum man_next ,
-.Vt struct man ,
-.Vt struct man_macro ,
-and many functions internal to the
+.Vt struct man_macro
+and some functions internal to the
.Xr man 7
parser.
.Pp
-Uses the opaque types
-.Vt struct mparse
-from
-.Pa read.c
+Uses the types
+.Vt struct roff_man
and
-.Vt struct roff
+.Vt struct roff_node
from
-.Pa roff.c .
+.Pa roff.h
+as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa mdoc.h ,
@@ -420,7 +420,7 @@ from
and
.Vt struct roff_meta
from
-.Qq Pa roff.h
+.Pa roff.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
@@ -456,18 +456,26 @@ When this header is included, the same file should not include
.Pa term.h
or
.Pa mansearch.h .
+.It Qq Pa tag.h
+Requires
+.In sys/types.h
+for
+.Vt size_t .
+.Pp
+Provides an interface to generate
+.Xr ctags 1
+files for the
+.Ic :t
+functionality mentioned in
+.Xr man 1 .
.It Qq Pa main.h
Provides the top level steering functions for all formatters.
.Pp
-Uses the types
-.Vt struct mdoc
-from
-.Pa libmdoc.h
-and
-.Vt struct man
+Uses the type
+.Vt struct roff_man
from
-.Pa libman.h
-as opaque types for function prototypes.
+.Pa roff.h
+as an opaque type for function prototypes.
.It Qq Pa manconf.h
Requires
.In sys/types.h
diff --git a/mandoc_malloc.3 b/mandoc_malloc.3
index c16798424af6..ae3ca16aa4a8 100644
--- a/mandoc_malloc.3
+++ b/mandoc_malloc.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc_malloc.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $
+.\" $Id: mandoc_malloc.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 5 2014 $
+.Dd $Mdocdate: July 7 2016 $
.Dt MANDOC_MALLOC 3
.Os
.Sh NAME
@@ -26,8 +26,6 @@
.Nm mandoc_strndup ,
.Nm mandoc_asprintf
.Nd memory allocation function wrappers used in the mandoc library
-.Sh LIBRARY
-.Lb libmandoc
.Sh SYNOPSIS
.In sys/types.h
.In mandoc_aux.h
@@ -67,21 +65,18 @@
.Fa "..."
.Fc
.Sh DESCRIPTION
-These functions call the
-.Lb libc
-functions of the same names, passing through their return values when
-successful.
+These functions call the libc functions of the same names, passing
+through their return values when successful.
In case of failure, they do not return, but instead call
-.Xr perror 3
-and
-.Xr exit 3 .
-They can be used both internally by any code in the
-.Lb libmandoc
+.Xr err 3 .
+They can be used both internally by any code in the mandoc libraries
and externally by programs using that library, for example
.Xr mandoc 1 ,
+.Xr man 1 ,
.Xr apropos 1 ,
+.Xr makewhatis 8 ,
and
-.Xr makewhatis 8 .
+.Xr man.cgi 8 .
.Pp
The function
.Fn mandoc_malloc
@@ -149,9 +144,8 @@ These functions are implemented in
.Pa mandoc_aux.c .
.Sh SEE ALSO
.Xr asprintf 3 ,
-.Xr exit 3 ,
+.Xr err 3 ,
.Xr malloc 3 ,
-.Xr perror 3 ,
.Xr strdup 3
.Sh STANDARDS
The functions
diff --git a/mandocdb.c b/mandocdb.c
index 08f89c17e3d4..6c04cb05256c 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -1,4 +1,4 @@
-/* $Id: mandocdb.c,v 1.215 2016/01/08 17:48:09 schwarze Exp $ */
+/* $Id: mandocdb.c,v 1.218 2016/07/12 05:18:38 kristaps Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2016 Ingo Schwarze <schwarze@openbsd.org>
@@ -33,8 +33,10 @@
#else
#include "compat_fts.h"
#endif
-#include <getopt.h>
#include <limits.h>
+#if HAVE_SANDBOX_INIT
+#include <sandbox.h>
+#endif
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
@@ -346,6 +348,13 @@ mandocdb(int argc, char *argv[])
}
#endif
+#if HAVE_SANDBOX_INIT
+ if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) {
+ warnx("sandbox_init");
+ return (int)MANDOCLEVEL_SYSERR;
+ }
+#endif
+
memset(&conf, 0, sizeof(conf));
memset(stmts, 0, STMT__MAX * sizeof(sqlite3_stmt *));
@@ -574,7 +583,7 @@ usage:
* or
* [./]cat<section>[/<arch>]/<name>.0
*
- * TODO: accomodate for multi-language directories.
+ * TODO: accommodate for multi-language directories.
*/
static int
treescan(void)
diff --git a/manpage.c b/manpage.c
index 45b6e7659bae..af7d3db23023 100644
--- a/manpage.c
+++ b/manpage.c
@@ -1,4 +1,4 @@
-/* $Id: manpage.c,v 1.13 2015/11/07 17:58:55 schwarze Exp $ */
+/* $Id: manpage.c,v 1.14 2016/07/09 15:24:19 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -20,7 +20,6 @@
#include <sys/types.h>
#include <assert.h>
-#include <getopt.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/manpath.c b/manpath.c
index 0627f13d25ad..83c329ec9bbb 100644
--- a/manpath.c
+++ b/manpath.c
@@ -1,4 +1,4 @@
-/* $Id: manpath.c,v 1.29 2015/11/07 17:58:55 schwarze Exp $ */
+/* $Id: manpath.c,v 1.30 2016/05/28 13:44:13 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -224,13 +224,12 @@ manconf_file(struct manconf *conf, const char *file)
while ((linelen = getline(&line, &linesz, stream)) != -1) {
cp = line;
- ep = cp + linelen;
- if (ep[-1] != '\n')
- break;
- *--ep = '\0';
+ ep = cp + linelen - 1;
+ while (ep > cp && isspace((unsigned char)*ep))
+ *ep-- = '\0';
while (isspace((unsigned char)*cp))
cp++;
- if (*cp == '#')
+ if (cp == ep || *cp == '#')
continue;
for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
diff --git a/mansearch.c b/mansearch.c
index 843326baf103..1ab879d7f211 100644
--- a/mansearch.c
+++ b/mansearch.c
@@ -1,4 +1,4 @@
-/* $Id: mansearch.c,v 1.64 2016/01/08 15:02:54 schwarze Exp $ */
+/* $Id: mansearch.c,v 1.65 2016/07/09 15:24:19 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -26,7 +26,6 @@
#endif
#include <errno.h>
#include <fcntl.h>
-#include <getopt.h>
#include <glob.h>
#include <limits.h>
#include <regex.h>
diff --git a/mchars_alloc.3 b/mchars_alloc.3
index 2d42a432e5e6..4bb862083ab3 100644
--- a/mchars_alloc.3
+++ b/mchars_alloc.3
@@ -1,4 +1,4 @@
-.\" $Id: mchars_alloc.3,v 1.3 2015/10/13 22:59:54 schwarze Exp $
+.\" $Id: mchars_alloc.3,v 1.4 2016/07/07 19:19:01 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" 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 13 2015 $
+.Dd $Mdocdate: July 7 2016 $
.Dt MCHARS_ALLOC 3
.Os
.Sh NAME
@@ -23,7 +23,8 @@
.Nm mchars_num2char ,
.Nm mchars_num2uc ,
.Nm mchars_spec2cp ,
-.Nm mchars_spec2str
+.Nm mchars_spec2str ,
+.Nm mchars_uc2str
.Nd character table for mandoc
.Sh SYNOPSIS
.In sys/types.h
diff --git a/read.c b/read.c
index 0ef3cdfcf486..6cbcd2df0079 100644
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/* $Id: read.c,v 1.148 2016/01/08 02:53:13 schwarze Exp $ */
+/* $Id: read.c,v 1.149 2016/07/10 13:34:30 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
@@ -798,7 +798,7 @@ mparse_open(struct mparse *curp, const char *file)
if ( ! curp->gzip) {
mandoc_asprintf(&cp, "%s.gz", file);
- fd = open(file, O_RDONLY);
+ fd = open(cp, O_RDONLY);
free(cp);
if (fd != -1) {
curp->gzip = 1;
diff --git a/tag.c b/tag.c
index 57925cebd3be..baedf15ad9e4 100644
--- a/tag.c
+++ b/tag.c
@@ -1,4 +1,4 @@
-/* $Id: tag.c,v 1.11 2015/11/20 21:59:54 schwarze Exp $ */
+/* $Id: tag.c,v 1.12 2016/07/08 20:42:15 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -57,6 +57,24 @@ tag_init(void)
tag_files.tfd = -1;
tag_files.tcpgid = -1;
+ /* Clean up when dying from a signal. */
+
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = tag_signal;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ /*
+ * POSIX requires that a process calling tcsetpgrp(3)
+ * from the background gets a SIGTTOU signal.
+ * In that case, do not stop.
+ */
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTTOU, &sa, NULL);
+
/* Save the original standard output for use by the pager. */
if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
@@ -68,12 +86,6 @@ tag_init(void)
sizeof(tag_files.ofn));
(void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
sizeof(tag_files.tfn));
- memset(&sa, 0, sizeof(sa));
- sigfillset(&sa.sa_mask);
- sa.sa_handler = tag_signal;
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
if ((ofd = mkstemp(tag_files.ofn)) == -1)
goto fail;
if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
diff --git a/term.c b/term.c
index e9171013e04b..0fd8f7c01974 100644
--- a/term.c
+++ b/term.c
@@ -1,4 +1,4 @@
-/* $Id: term.c,v 1.256 2016/01/07 21:03:54 schwarze Exp $ */
+/* $Id: term.c,v 1.257 2016/04/12 15:30:00 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -160,7 +160,7 @@ term_flushln(struct termp *p)
if (' ' == p->buf[j] || '\t' == p->buf[j])
break;
- /* Back over the the last printed character. */
+ /* Back over the last printed character. */
if (8 == p->buf[j]) {
assert(j);
vend -= (*p->width)(p, p->buf[j - 1]);
diff --git a/term_ascii.c b/term_ascii.c
index 7215a5971665..fecdb0a964dc 100644
--- a/term_ascii.c
+++ b/term_ascii.c
@@ -1,4 +1,4 @@
-/* $Id: term_ascii.c,v 1.52 2015/11/12 21:50:03 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.53 2016/07/08 22:29:05 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -163,18 +163,17 @@ ascii_setwidth(struct termp *p, int iop, int width)
}
void
-ascii_sepline(void *arg)
+terminal_sepline(void *arg)
{
struct termp *p;
size_t i;
p = (struct termp *)arg;
- p->line += 3;
- putchar('\n');
+ (*p->endline)(p);
for (i = 0; i < p->defrmargin; i++)
- putchar('-');
- putchar('\n');
- putchar('\n');
+ (*p->letter)(p, '-');
+ (*p->endline)(p);
+ (*p->endline)(p);
}
static size_t
diff --git a/test-rewb-bsd.c b/test-rewb-bsd.c
index 88d3d357d4d4..872dd4c81d02 100644
--- a/test-rewb-bsd.c
+++ b/test-rewb-bsd.c
@@ -1,4 +1,5 @@
#include <sys/types.h>
+#include <stddef.h>
#include <regex.h>
int
diff --git a/test-rewb-sysv.c b/test-rewb-sysv.c
index cb35c544e971..1e7fbc821944 100644
--- a/test-rewb-sysv.c
+++ b/test-rewb-sysv.c
@@ -1,4 +1,5 @@
#include <sys/types.h>
+#include <stddef.h>
#include <regex.h>
int