summaryrefslogtreecommitdiffstats
path: root/contrib/mdocml
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2014-11-22 18:57:23 +0000
committerbapt <bapt@FreeBSD.org>2014-11-22 18:57:23 +0000
commit322e9f202c55a90688e5243b26f9fe13233b06d6 (patch)
treeaba7ac26366d9bbe229fb31209028de396e0734c /contrib/mdocml
parent94074b10c06e084bdb5dbf5e550c6f73d8083f99 (diff)
parenteb03421ddbdfb35eb3ab61dbe59c906ce9e5db96 (diff)
downloadFreeBSD-src-322e9f202c55a90688e5243b26f9fe13233b06d6.zip
FreeBSD-src-322e9f202c55a90688e5243b26f9fe13233b06d6.tar.gz
Update mandoc to 1.13.1
Diffstat (limited to 'contrib/mdocml')
-rw-r--r--contrib/mdocml/INSTALL187
-rw-r--r--contrib/mdocml/LICENSE44
-rw-r--r--contrib/mdocml/Makefile505
-rw-r--r--contrib/mdocml/Makefile.depend70
-rw-r--r--contrib/mdocml/NEWS82
-rw-r--r--contrib/mdocml/TODO175
-rw-r--r--contrib/mdocml/apropos.1387
-rw-r--r--contrib/mdocml/apropos.c123
-rw-r--r--contrib/mdocml/arch.c8
-rw-r--r--contrib/mdocml/arch.in6
-rw-r--r--contrib/mdocml/att.c8
-rw-r--r--contrib/mdocml/cgi.c1150
-rw-r--r--contrib/mdocml/cgi.h.example9
-rw-r--r--contrib/mdocml/chars.c35
-rw-r--r--contrib/mdocml/chars.in44
-rw-r--r--contrib/mdocml/compat_ohash.c339
-rw-r--r--contrib/mdocml/compat_ohash.h73
-rw-r--r--contrib/mdocml/compat_reallocarray.c45
-rw-r--r--contrib/mdocml/compat_sqlite3_errstr.c18
-rw-r--r--contrib/mdocml/compat_strcasestr.c74
-rw-r--r--contrib/mdocml/compat_strsep.c80
-rw-r--r--contrib/mdocml/config.h47
-rw-r--r--contrib/mdocml/config.h.post42
-rw-r--r--contrib/mdocml/config.h.pre9
-rwxr-xr-xcontrib/mdocml/configure49
-rw-r--r--contrib/mdocml/demandoc.c257
-rw-r--r--contrib/mdocml/eqn.c73
-rw-r--r--contrib/mdocml/eqn_html.c10
-rw-r--r--contrib/mdocml/eqn_term.c5
-rw-r--r--contrib/mdocml/external.pngbin165 -> 0 bytes
-rw-r--r--contrib/mdocml/gmdiff38
-rw-r--r--contrib/mdocml/html.c183
-rw-r--r--contrib/mdocml/html.h17
-rw-r--r--contrib/mdocml/lib.c5
-rw-r--r--contrib/mdocml/lib.in3
-rw-r--r--contrib/mdocml/libman.h14
-rw-r--r--contrib/mdocml/libmandoc.h36
-rw-r--r--contrib/mdocml/libmdoc.h19
-rw-r--r--contrib/mdocml/libroff.h6
-rw-r--r--contrib/mdocml/main.c131
-rw-r--r--contrib/mdocml/main.h4
-rw-r--r--contrib/mdocml/makewhatis.8217
-rw-r--r--contrib/mdocml/man.7116
-rw-r--r--contrib/mdocml/man.c218
-rw-r--r--contrib/mdocml/man.cgi.8409
-rw-r--r--contrib/mdocml/man.h6
-rw-r--r--contrib/mdocml/man_hash.c8
-rw-r--r--contrib/mdocml/man_html.c102
-rw-r--r--contrib/mdocml/man_macro.c155
-rw-r--r--contrib/mdocml/man_term.c274
-rw-r--r--contrib/mdocml/man_validate.c370
-rw-r--r--contrib/mdocml/mandoc.1875
-rw-r--r--contrib/mdocml/mandoc.3341
-rw-r--r--contrib/mdocml/mandoc.c226
-rw-r--r--contrib/mdocml/mandoc.db.5144
-rw-r--r--contrib/mdocml/mandoc.h216
-rw-r--r--contrib/mdocml/mandoc_aux.c121
-rw-r--r--contrib/mdocml/mandoc_aux.h33
-rw-r--r--contrib/mdocml/mandoc_escape.3362
-rw-r--r--contrib/mdocml/mandoc_html.3249
-rw-r--r--contrib/mdocml/mandoc_malloc.3197
-rw-r--r--contrib/mdocml/mandocdb.c2491
-rw-r--r--contrib/mdocml/manpage.c190
-rw-r--r--contrib/mdocml/manpath.c222
-rw-r--r--contrib/mdocml/manpath.h38
-rw-r--r--contrib/mdocml/mansearch.3228
-rw-r--r--contrib/mdocml/mansearch.c861
-rw-r--r--contrib/mdocml/mansearch.h101
-rw-r--r--contrib/mdocml/mansearch_const.c35
-rw-r--r--contrib/mdocml/mchars_alloc.3224
-rw-r--r--contrib/mdocml/mdoc.7578
-rw-r--r--contrib/mdocml/mdoc.c339
-rw-r--r--contrib/mdocml/mdoc.h26
-rw-r--r--contrib/mdocml/mdoc_argv.c112
-rw-r--r--contrib/mdocml/mdoc_hash.c6
-rw-r--r--contrib/mdocml/mdoc_html.c646
-rw-r--r--contrib/mdocml/mdoc_macro.c384
-rw-r--r--contrib/mdocml/mdoc_man.c353
-rw-r--r--contrib/mdocml/mdoc_term.c732
-rw-r--r--contrib/mdocml/mdoc_validate.c1755
-rw-r--r--contrib/mdocml/msec.c3
-rw-r--r--contrib/mdocml/out.c58
-rw-r--r--contrib/mdocml/out.h6
-rw-r--r--contrib/mdocml/read.c365
-rw-r--r--contrib/mdocml/roff.7305
-rw-r--r--contrib/mdocml/roff.c1266
-rw-r--r--contrib/mdocml/st.c5
-rw-r--r--contrib/mdocml/st.in5
-rw-r--r--contrib/mdocml/tbl.c25
-rw-r--r--contrib/mdocml/tbl_data.c49
-rw-r--r--contrib/mdocml/tbl_html.c11
-rw-r--r--contrib/mdocml/tbl_layout.c110
-rw-r--r--contrib/mdocml/tbl_opts.c47
-rw-r--r--contrib/mdocml/tbl_term.c74
-rw-r--r--contrib/mdocml/term.c225
-rw-r--r--contrib/mdocml/term.h22
-rw-r--r--contrib/mdocml/term_ascii.c84
-rw-r--r--contrib/mdocml/term_ps.c212
-rw-r--r--contrib/mdocml/test-fgetln.c11
-rw-r--r--contrib/mdocml/test-getsubopt.c19
-rw-r--r--contrib/mdocml/test-mmap.c9
-rw-r--r--contrib/mdocml/test-ohash.c21
-rw-r--r--contrib/mdocml/test-reallocarray.c7
-rw-r--r--contrib/mdocml/test-sqlite3_errstr.c8
-rw-r--r--contrib/mdocml/test-strcasestr.c13
-rw-r--r--contrib/mdocml/test-strlcat.c9
-rw-r--r--contrib/mdocml/test-strlcpy.c9
-rw-r--r--contrib/mdocml/test-strsep.c10
-rw-r--r--contrib/mdocml/tree.c122
-rw-r--r--contrib/mdocml/vol.c5
110 files changed, 16307 insertions, 5178 deletions
diff --git a/contrib/mdocml/INSTALL b/contrib/mdocml/INSTALL
new file mode 100644
index 0000000..da8eeab
--- /dev/null
+++ b/contrib/mdocml/INSTALL
@@ -0,0 +1,187 @@
+$Id: INSTALL,v 1.2 2014/08/10 17:22:26 schwarze Exp $
+
+About mdocml, the portable mandoc distribution
+----------------------------------------------
+The mandoc manpage compiler toolset is a suite of tools compiling
+mdoc(7), the roff(7) macro language of choice for BSD manual pages,
+and man(7), the predominant historical language for UNIX manuals.
+The toolset does not yet implement man(1); that is only scheduled
+for the next release, 1.13.2. It can, however, already serve to
+translate source manpages to the output displayed by man(1).
+For general information, see <http://mdocml.bsd.lv/>.
+
+In this document, we describe the installation and deployment of
+mandoc(1), first as a simple, standalone formatter, and then as part of
+the man(1) system.
+
+In case you have questions or want to provide feedback, read
+<http://mdocml.bsd.lv/contact.html>. Consider subscribing to the
+discuss@ mailing list mentioned on that page. If you intend to
+help with the development of mandoc, consider subscribing to the
+tech@ mailing list, too.
+
+Enjoy using the mandoc toolset!
+
+Ingo Schwarze, Karlsruhe, August 2014
+
+
+Installation
+------------
+Before manually installing mandoc on your system, please check
+whether the newest version of mandoc is already installed by default
+or available via a binary package or a ports system. A list of the
+latest bundled and ported versions of mandoc for various operating
+systems is maintained at <http://mdocml.bsd.lv/ports.html>.
+
+If mandoc is installed, you can check the version by running "mandoc -V".
+The version contained in this distribution tarball is listed near
+the beginning of the file "Makefile".
+
+Regarding how packages and ports are maintained for your operating
+system, please consult your operating system documentation.
+To install mandoc manually, the following steps are needed:
+
+1. Decide whether you want to build the base tools mandoc(1),
+preconv(1) and demandoc(1) only or whether you also want to build the
+database tools apropos(1) and makewhatis(8). For the latter,
+the following dependencies are required:
+
+1.1. The SQLite database system, see <http://sqlite.org/>.
+The recommended version of SQLite is 3.8.4.3 or newer. The mandoc
+toolset is known to work with version 3.7.5 or newer. Versions
+older than 3.8.3 may not achieve full performance due to the
+missing SQLITE_DETERMINISTIC optimization flag. Versions older
+than 3.8.0 may not show full error information if opening a database
+fails due to the missing sqlite3_errstr() API. Both are very minor
+problems, apropos(1) is fully usable with SQLite 3.7.5. Versions
+older than 3.7.5 may or may not work, they have not been tested.
+
+1.2. The fts(3) directory traversion functions.
+A compatibility version will be bundled for 1.13.2 but is not available
+yet. If you want apropos(1) and makewhatis(8) but do not have fts(3),
+please stay with mandoc 1.12.3 for now and upgrade first to 1.12.4,
+then to 1.13.2 when these versionns are released. Be careful: the
+glibc version of fts(3) is known to be broken on 32bit platforms,
+see <https://sourceware.org/bugzilla/show_bug.cgi?id=15838>.
+
+1.3. Marc Espie's ohash(3) library.
+If your system does not have it, the bundled compatibility version
+will be used, so you probably need not worry about it.
+
+2. If you choose to build the database tools, too, decide whether
+you also want to build the CGI program, man.cgi(8).
+
+3. Read the beginning of the file "Makefile" from "USER SETTINGS"
+to "END OF USER SETTINGS" and edit it as required. In particular,
+disable "BUILD_TARGETS += db-build" if you do not want database
+support or enable "BUILD_TARGETS += cgi-build" if you do want
+the CGI program.
+
+4. Run "make". No separate "./configure" or "make depend" steps
+are needed. The former is run automatically by "make". The latter
+is a maintainer target. If you merely want to build the released
+version as opposed to doing active development, there is no need
+to regenerate the dependency specifications. Any POSIX-compatible
+make, in particular both BSD make and GNU make, should work.
+
+5. Run "make -n install" and check whether everything will be
+installed to the intended places. Otherwise, edit the *DIR variables
+in the Makefile until it is.
+
+6. Run "sudo make install". If you intend to build a binary
+package using some kind of fake root mechanism, you may need a
+command like "make DESTDIR=... install". Read the *-install targets
+in the "Makefile" to understand how DESTDIR is used.
+
+7. To set up a man.cgi(8) server, read its manual page.
+
+8. To use mandoc(1) as your man(1) formatter, read the "Deployment"
+section below.
+
+
+Checking autoconfiguration quality
+----------------------------------
+If you want to check whether automatic configuration works well
+on your platform, consider the following:
+
+The mandoc package intentionally does not use GNU autoconf because
+we consider that toolset a blatant example of overengineering that
+is obsolete nowadays, since all modern operating systems are now
+reasonably close to POSIX and do not need arcane shell magic any
+longer. If your system does need such magic, consider upgrading
+to reasonably modern POSIX-compliant tools rather than asking for
+autoconf-style workarounds.
+
+As far as mandoc is using any features not mandated by ANSI X3.159-1989
+("ANSI C") or IEEE Std 1003.1-2008 ("POSIX") that some modern systems
+do not have, we intend to provide autoconfiguration tests and
+compat_*.c implementations. Please report any that turn out to be
+missing. Note that while we do strive to produce portable code,
+we do not slavishly restrict ourselves to POSIX-only interfaces.
+For improved security and readability, we do use well-designed,
+modern interfaces like reallocarray(3) even if they are still rather
+uncommon, of course bundling compat_*.c implementations as needed.
+
+Where mandoc is using ANSI C or POSIX features that some systems
+still lack and that compat_*.c implementations can be provided for
+without too much hassle, we will consider adding them, too, so
+please report whatever is missing on your platform.
+
+The following steps can be used to manually check the automatic
+configuration on your platform:
+
+1. Run "make clean".
+
+2. Run "make config.h"
+
+3. Read the file "config.log". It shows the compiler commands used
+to test the libraries installed on your system and the standard
+output and standard error output these commands produce. Watch out
+for unexpected failures. Those are most likely to happen if headers
+or libraries are installed in unusual places or interfaces defined
+in unusual headers. You can also look at the file "config.h" and
+check that no expected "#define HAVE_*" lines are missing. The
+list of tests run can be found in the file "configure".
+
+
+Deployment
+----------
+If you want to integrate the mandoc(1) tools with your existing
+man(1) system as a formatter, then contact us first: on systems without
+mandoc(1) as the default, you may have your work cut out for you!
+Usually, you can have your default installation and mandoc(1) work right
+alongside each other by using user-specific versions of the files
+mentioned below.
+
+0. Back up each file you want to change!
+
+1. First see whether your system has "/etc/man.conf" or "/etc/manpath.conf"
+(if it has neither, but man(1) is functional, then let us know) or,
+if running as your own user, a per-user override file. In either
+case, find where man(1) is executing nroff(1) or groff(1) to format
+manuals. Replace these calls with mandoc(1).
+
+2. Then make sure that man(1) isn't running preprocessors, so you may
+need to replace tbl(1), eqn(1), and similar references with cat(1).
+Some man(1) implementations, like that on Mac OSX, let you run "man -d"
+to see how the formatter is invoked. Use this to test your changes. On
+Mac OS X, for instance, man(1) will prepend all files with ".ll" and
+".nr" to set the terminal size, so you need to pass "tail -n+2 |
+mandoc(1)" to disregard them.
+
+3. Finally, make sure that mandoc(1) is actually being invoked instead
+of cached pages being pulled up. You can usually do this by commenting
+out NOCACHE or similar.
+
+mandoc(1) still has a long way to go in understanding non-trivial
+low-level roff(7) markup embedded in some man(7) pages. On the BSD
+systems using mandoc(1), third-party software is generally vetted
+on whether it may be formatted with mandoc(1). If not, groff(1)
+is pulled in as a dependency and used to install a pre-formatted
+"catpage" intead of directly as manual page source.
+
+For more background on switching operating systems to use mandoc(1)
+instead of groff(1) to format manuals, see the two BSDCan presentations
+by Ingo Schwarze:
+<http://www.openbsd.org/papers/bsdcan11-mandoc-openbsd.html>
+<http://www.openbsd.org/papers/bsdcan14-mandoc.pdf>
diff --git a/contrib/mdocml/LICENSE b/contrib/mdocml/LICENSE
new file mode 100644
index 0000000..35072fb
--- /dev/null
+++ b/contrib/mdocml/LICENSE
@@ -0,0 +1,44 @@
+$Id: LICENSE,v 1.2 2014/04/23 21:06:41 schwarze Exp $
+
+With the exceptions noted below, all code and documentation
+contained in the mdocml toolkit is protected by the Copyright
+of the following developers:
+
+Copyright (c) 2008, 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+Copyright (c) 2010, 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
+Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
+Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+Copyright (c) 1998, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
+
+See the individual source files for information about who contributed
+to which file during which years.
+
+
+The mdocml distribution as a whole is distributed by its developers
+under the following license:
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+The following files included from outside sources are protected by
+other people's Copyright and are distributed under a 3-clause BSD
+license; see these individual files for details.
+
+compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c:
+Copyright (c) 1990, 1993 The Regents of the University of California
+
+compat_fgetln.c:
+Copyright (c) 1998 The NetBSD Foundation, Inc.
diff --git a/contrib/mdocml/Makefile b/contrib/mdocml/Makefile
new file mode 100644
index 0000000..47f37a7
--- /dev/null
+++ b/contrib/mdocml/Makefile
@@ -0,0 +1,505 @@
+# $Id: Makefile,v 1.435 2014/08/10 02:45:04 schwarze Exp $
+#
+# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+# Copyright (c) 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+VERSION = 1.13.1
+
+# === USER SETTINGS ====================================================
+
+# --- user settings relevant for all builds ----------------------------
+
+# Specify this if you want to hard-code the operating system to appear
+# in the lower-left hand corner of -mdoc manuals.
+#
+# CFLAGS += -DOSNAME="\"OpenBSD 5.5\""
+
+# IFF your system supports multi-byte functions (setlocale(), wcwidth(),
+# putwchar()) AND has __STDC_ISO_10646__ (that is, wchar_t is simply a
+# UCS-4 value) should you define USE_WCHAR. If you define it and your
+# system DOESN'T support this, -Tlocale will produce garbage.
+# If you don't define it, -Tlocale is a synonym for -Tacsii.
+#
+CFLAGS += -DUSE_WCHAR
+
+CFLAGS += -g -DHAVE_CONFIG_H
+CFLAGS += -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+INCLUDEDIR = $(PREFIX)/include/mandoc
+LIBDIR = $(PREFIX)/lib/mandoc
+MANDIR = $(PREFIX)/man
+EXAMPLEDIR = $(PREFIX)/share/examples/mandoc
+
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL) -m 0555
+INSTALL_DATA = $(INSTALL) -m 0444
+INSTALL_LIB = $(INSTALL) -m 0444
+INSTALL_SOURCE = $(INSTALL) -m 0644
+INSTALL_MAN = $(INSTALL_DATA)
+
+# --- user settings related to database support ------------------------
+
+# Building apropos(1) and makewhatis(8) requires both SQLite3 and fts(3).
+# To avoid those dependencies, comment the following line.
+# Be careful: the fts(3) implementation in glibc is broken on 32bit
+# machines, see: https://sourceware.org/bugzilla/show_bug.cgi?id=15838
+#
+BUILD_TARGETS += db-build
+
+# The remaining settings in this section
+# are only relevant if db-build is enabled.
+# Otherwise, they have no effect either way.
+
+# If your system has manpath(1), uncomment this. This is most any
+# system that's not OpenBSD or NetBSD. If uncommented, apropos(1)
+# and makewhatis(8) will use manpath(1) to get the MANPATH variable.
+#
+#CFLAGS += -DUSE_MANPATH
+
+# On some systems, SQLite3 may be installed below /usr/local.
+# In that case, uncomment the following two lines.
+#
+#CFLAGS += -I/usr/local/include
+#DBLIB += -L/usr/local/lib
+
+# OpenBSD has the ohash functions in libutil.
+# Comment the following line if your system doesn't.
+#
+DBLIB += -lutil
+
+SBINDIR = $(PREFIX)/sbin
+
+# --- user settings related to man.cgi ---------------------------------
+
+# To build man.cgi, copy cgi.h.example to cgi.h, edit it,
+# and enable the following line.
+# Obviously, this requires that db-build is enabled, too.
+#
+#BUILD_TARGETS += cgi-build
+
+# The remaining settings in this section
+# are only relevant if cgi-build is enabled.
+# Otherwise, they have no effect either way.
+
+# If your system does not support static binaries, comment this,
+# for example on Mac OS X.
+#
+STATIC = -static
+
+# Linux requires -pthread for statical linking.
+#
+#STATIC += -pthread
+
+WWWPREFIX = /var/www
+HTDOCDIR = $(WWWPREFIX)/htdocs
+CGIBINDIR = $(WWWPREFIX)/cgi-bin
+
+# === END OF USER SETTINGS =============================================
+
+INSTALL_TARGETS = $(BUILD_TARGETS:-build=-install)
+
+BASEBIN = mandoc preconv demandoc
+DBBIN = apropos makewhatis
+CGIBIN = man.cgi
+
+DBLIB += -lsqlite3
+
+TESTSRCS = test-fgetln.c \
+ test-getsubopt.c \
+ test-mmap.c \
+ test-ohash.c \
+ test-reallocarray.c \
+ test-sqlite3_errstr.c \
+ test-strcasestr.c \
+ test-strlcat.c \
+ test-strlcpy.c \
+ test-strptime.c \
+ test-strsep.c
+
+SRCS = apropos.c \
+ arch.c \
+ att.c \
+ cgi.c \
+ chars.c \
+ compat_fgetln.c \
+ compat_getsubopt.c \
+ compat_ohash.c \
+ compat_reallocarray.c \
+ compat_sqlite3_errstr.c \
+ compat_strcasestr.c \
+ compat_strlcat.c \
+ compat_strlcpy.c \
+ compat_strsep.c \
+ demandoc.c \
+ eqn.c \
+ eqn_html.c \
+ eqn_term.c \
+ html.c \
+ lib.c \
+ main.c \
+ man.c \
+ man_hash.c \
+ man_html.c \
+ man_macro.c \
+ man_term.c \
+ man_validate.c \
+ mandoc.c \
+ mandoc_aux.c \
+ mandocdb.c \
+ manpage.c \
+ manpath.c \
+ mansearch.c \
+ mansearch_const.c \
+ mdoc.c \
+ mdoc_argv.c \
+ mdoc_hash.c \
+ mdoc_html.c \
+ mdoc_macro.c \
+ mdoc_man.c \
+ mdoc_term.c \
+ mdoc_validate.c \
+ msec.c \
+ out.c \
+ preconv.c \
+ read.c \
+ roff.c \
+ st.c \
+ tbl.c \
+ tbl_data.c \
+ tbl_html.c \
+ tbl_layout.c \
+ tbl_opts.c \
+ tbl_term.c \
+ term.c \
+ term_ascii.c \
+ term_ps.c \
+ tree.c \
+ vol.c \
+ $(TESTSRCS)
+
+DISTFILES = INSTALL \
+ LICENSE \
+ Makefile \
+ Makefile.depend \
+ NEWS \
+ TODO \
+ apropos.1 \
+ arch.in \
+ att.in \
+ cgi.h.example \
+ chars.in \
+ compat_ohash.h \
+ config.h.post \
+ config.h.pre \
+ configure \
+ demandoc.1 \
+ eqn.7 \
+ example.style.css \
+ gmdiff \
+ html.h \
+ lib.in \
+ libman.h \
+ libmandoc.h \
+ libmdoc.h \
+ libroff.h \
+ main.h \
+ makewhatis.8 \
+ man-cgi.css \
+ man.7 \
+ man.cgi.8 \
+ man.h \
+ mandoc.1 \
+ mandoc.3 \
+ mandoc.db.5 \
+ mandoc.h \
+ mandoc_aux.h \
+ mandoc_char.7 \
+ mandoc_escape.3 \
+ mandoc_html.3 \
+ mandoc_malloc.3 \
+ manpath.h \
+ mansearch.3 \
+ mansearch.h \
+ mchars_alloc.3 \
+ mdoc.7 \
+ mdoc.h \
+ msec.in \
+ out.h \
+ preconv.1 \
+ predefs.in \
+ roff.7 \
+ st.in \
+ style.css \
+ tbl.3 \
+ tbl.7 \
+ term.h \
+ vol.in \
+ $(SRCS)
+
+LIBMAN_OBJS = man.o \
+ man_hash.o \
+ man_macro.o \
+ man_validate.o
+
+LIBMDOC_OBJS = arch.o \
+ att.o \
+ lib.o \
+ mdoc.o \
+ mdoc_argv.o \
+ mdoc_hash.o \
+ mdoc_macro.o \
+ mdoc_validate.o \
+ st.o \
+ vol.o
+
+LIBROFF_OBJS = eqn.o \
+ roff.o \
+ tbl.o \
+ tbl_data.o \
+ tbl_layout.o \
+ tbl_opts.o
+
+LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
+ $(LIBMDOC_OBJS) \
+ $(LIBROFF_OBJS) \
+ chars.o \
+ mandoc.o \
+ mandoc_aux.o \
+ msec.o \
+ read.o
+
+COMPAT_OBJS = compat_fgetln.o \
+ compat_getsubopt.o \
+ compat_ohash.o \
+ compat_reallocarray.o \
+ compat_sqlite3_errstr.o \
+ compat_strcasestr.o \
+ compat_strlcat.o \
+ compat_strlcpy.o \
+ compat_strsep.o
+
+MANDOC_HTML_OBJS = eqn_html.o \
+ html.o \
+ man_html.o \
+ mdoc_html.o \
+ tbl_html.o
+
+MANDOC_MAN_OBJS = mdoc_man.o
+
+MANDOC_TERM_OBJS = eqn_term.o \
+ man_term.o \
+ mdoc_term.o \
+ term.o \
+ term_ascii.o \
+ term_ps.o \
+ tbl_term.o
+
+MANDOC_OBJS = $(MANDOC_HTML_OBJS) \
+ $(MANDOC_MAN_OBJS) \
+ $(MANDOC_TERM_OBJS) \
+ main.o \
+ out.o \
+ tree.o
+
+MAKEWHATIS_OBJS = mandocdb.o mansearch_const.o manpath.o
+
+PRECONV_OBJS = preconv.o
+
+APROPOS_OBJS = apropos.o mansearch.o mansearch_const.o manpath.o
+
+CGI_OBJS = $(MANDOC_HTML_OBJS) \
+ cgi.o \
+ mansearch.o \
+ mansearch_const.o \
+ out.o
+
+MANPAGE_OBJS = manpage.o mansearch.o mansearch_const.o manpath.o
+
+DEMANDOC_OBJS = demandoc.o
+
+WWW_MANS = apropos.1.html \
+ demandoc.1.html \
+ mandoc.1.html \
+ preconv.1.html \
+ mandoc.3.html \
+ mandoc_escape.3.html \
+ mandoc_html.3.html \
+ mandoc_malloc.3.html \
+ mansearch.3.html \
+ mchars_alloc.3.html \
+ tbl.3.html \
+ mandoc.db.5.html \
+ eqn.7.html \
+ man.7.html \
+ mandoc_char.7.html \
+ mdoc.7.html \
+ roff.7.html \
+ tbl.7.html \
+ makewhatis.8.html \
+ man.cgi.8.html \
+ man.h.html \
+ mandoc.h.html \
+ mandoc_aux.h.html \
+ manpath.h.html \
+ mansearch.h.html \
+ mdoc.h.html
+
+WWW_OBJS = mdocml.tar.gz \
+ mdocml.sha256
+
+# === DEPENDENCY HANDLING ==============================================
+
+all: base-build $(BUILD_TARGETS)
+
+base-build: $(BASEBIN)
+
+db-build: $(DBBIN)
+
+cgi-build: $(CGIBIN)
+
+install: base-install $(INSTALL_TARGETS)
+
+www: $(WWW_OBJS) $(WWW_MANS)
+
+include Makefile.depend
+
+# === TARGETS CONTAINING SHELL COMMANDS ================================
+
+clean:
+ rm -f libmandoc.a $(LIBMANDOC_OBJS)
+ rm -f apropos $(APROPOS_OBJS)
+ rm -f makewhatis $(MAKEWHATIS_OBJS)
+ rm -f preconv $(PRECONV_OBJS)
+ rm -f man.cgi $(CGI_OBJS)
+ rm -f manpage $(MANPAGE_OBJS)
+ rm -f demandoc $(DEMANDOC_OBJS)
+ rm -f mandoc $(MANDOC_OBJS)
+ rm -f config.h config.log $(COMPAT_OBJS)
+ rm -f $(WWW_MANS) $(WWW_OBJS)
+ rm -rf *.dSYM
+
+base-install: base-build
+ mkdir -p $(DESTDIR)$(BINDIR)
+ mkdir -p $(DESTDIR)$(EXAMPLEDIR)
+ mkdir -p $(DESTDIR)$(LIBDIR)
+ mkdir -p $(DESTDIR)$(INCLUDEDIR)
+ mkdir -p $(DESTDIR)$(MANDIR)/man1
+ mkdir -p $(DESTDIR)$(MANDIR)/man3
+ mkdir -p $(DESTDIR)$(MANDIR)/man7
+ $(INSTALL_PROGRAM) $(BASEBIN) $(DESTDIR)$(BINDIR)
+ $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
+ $(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h \
+ $(DESTDIR)$(INCLUDEDIR)
+ $(INSTALL_MAN) mandoc.1 preconv.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
+ $(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
+ mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
+ $(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 \
+ $(DESTDIR)$(MANDIR)/man7
+ $(INSTALL_DATA) example.style.css $(DESTDIR)$(EXAMPLEDIR)
+
+db-install: db-build
+ mkdir -p $(DESTDIR)$(BINDIR)
+ mkdir -p $(DESTDIR)$(SBINDIR)
+ mkdir -p $(DESTDIR)$(MANDIR)/man1
+ mkdir -p $(DESTDIR)$(MANDIR)/man3
+ mkdir -p $(DESTDIR)$(MANDIR)/man5
+ mkdir -p $(DESTDIR)$(MANDIR)/man8
+ $(INSTALL_PROGRAM) apropos $(DESTDIR)$(BINDIR)
+ ln -f $(DESTDIR)$(BINDIR)/apropos $(DESTDIR)$(BINDIR)/whatis
+ $(INSTALL_PROGRAM) makewhatis $(DESTDIR)$(SBINDIR)
+ $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1
+ ln -f $(DESTDIR)$(MANDIR)/man1/apropos.1 \
+ $(DESTDIR)$(MANDIR)/man1/whatis.1
+ $(INSTALL_MAN) mansearch.3 $(DESTDIR)$(MANDIR)/man3
+ $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5
+ $(INSTALL_MAN) makewhatis.8 $(DESTDIR)$(MANDIR)/man8
+
+cgi-install: cgi-build
+ mkdir -p $(DESTDIR)$(CGIBINDIR)
+ mkdir -p $(DESTDIR)$(HTDOCDIR)
+ mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1
+ mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8
+ $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR)
+ $(INSTALL_DATA) example.style.css $(DESTDIR)$(HTDOCDIR)/man.css
+ $(INSTALL_DATA) man-cgi.css $(DESTDIR)$(HTDOCDIR)
+ $(INSTALL_MAN) apropos.1 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1/
+ $(INSTALL_MAN) man.cgi.8 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8/
+
+www-install: www
+ mkdir -p $(DESTDIR)$(HTDOCDIR)/snapshots
+ $(INSTALL_DATA) $(WWW_MANS) style.css $(DESTDIR)$(HTDOCDIR)
+ $(INSTALL_DATA) $(WWW_OBJS) $(DESTDIR)$(HTDOCDIR)/snapshots
+ $(INSTALL_DATA) mdocml.tar.gz \
+ $(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).tar.gz
+ $(INSTALL_DATA) mdocml.sha256 \
+ $(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).sha256
+
+depend: config.h
+ mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
+ perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \
+ s|\\\n||g; s| +| |g; print;' Makefile.depend > Makefile.tmp
+ mv Makefile.tmp Makefile.depend
+
+libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
+ $(AR) rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
+
+mandoc: $(MANDOC_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(MANDOC_OBJS) libmandoc.a
+
+makewhatis: $(MAKEWHATIS_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(MAKEWHATIS_OBJS) libmandoc.a $(DBLIB)
+
+preconv: $(PRECONV_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(PRECONV_OBJS)
+
+manpage: $(MANPAGE_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(MANPAGE_OBJS) libmandoc.a $(DBLIB)
+
+apropos: $(APROPOS_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(APROPOS_OBJS) libmandoc.a $(DBLIB)
+
+man.cgi: $(CGI_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
+
+demandoc: $(DEMANDOC_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a
+
+mdocml.sha256: mdocml.tar.gz
+ sha256 mdocml.tar.gz > $@
+
+mdocml.tar.gz: $(DISTFILES)
+ mkdir -p .dist/mdocml-$(VERSION)/
+ $(INSTALL_SOURCE) $(DISTFILES) .dist/mdocml-$(VERSION)
+ chmod 755 .dist/mdocml-$(VERSION)/configure
+ ( cd .dist/ && tar zcf ../$@ mdocml-$(VERSION) )
+ rm -rf .dist/
+
+config.h: configure config.h.pre config.h.post $(TESTSRCS)
+ rm -f config.log
+ CC="$(CC)" CFLAGS="$(CFLAGS)" DBLIB="$(DBLIB)" \
+ VERSION="$(VERSION)" ./configure
+
+.PHONY: base-install cgi-install db-install install www-install
+.PHONY: clean depend
+.SUFFIXES: .1 .3 .5 .7 .8 .h
+.SUFFIXES: .1.html .3.html .5.html .7.html .8.html .h.html
+
+.h.h.html:
+ highlight -I $< > $@
+
+.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
+ ./mandoc -Thtml -Wall,stop \
+ -Ostyle=style.css,man=%N.%S.html,includes=%I.html $< > $@
diff --git a/contrib/mdocml/Makefile.depend b/contrib/mdocml/Makefile.depend
new file mode 100644
index 0000000..dc49310
--- /dev/null
+++ b/contrib/mdocml/Makefile.depend
@@ -0,0 +1,70 @@
+apropos.o: apropos.c config.h manpath.h mansearch.h
+arch.o: arch.c config.h mdoc.h libmdoc.h arch.in
+att.o: att.c config.h mdoc.h libmdoc.h att.in
+cgi.o: cgi.c config.h mandoc.h mandoc_aux.h main.h manpath.h mansearch.h cgi.h
+chars.o: chars.c config.h mandoc.h mandoc_aux.h libmandoc.h chars.in
+compat_fgetln.o: compat_fgetln.c config.h
+compat_getsubopt.o: compat_getsubopt.c config.h
+compat_ohash.o: compat_ohash.c config.h
+compat_reallocarray.o: compat_reallocarray.c config.h
+compat_sqlite3_errstr.o: compat_sqlite3_errstr.c config.h
+compat_strcasestr.o: compat_strcasestr.c config.h
+compat_strlcat.o: compat_strlcat.c config.h
+compat_strlcpy.o: compat_strlcpy.c config.h
+compat_strsep.o: compat_strsep.c config.h
+demandoc.o: demandoc.c config.h man.h mdoc.h mandoc.h
+eqn.o: eqn.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h
+eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h
+html.o: html.c config.h mandoc.h mandoc_aux.h libmandoc.h out.h html.h main.h
+lib.o: lib.c config.h mdoc.h libmdoc.h lib.in
+main.o: main.c config.h mandoc.h mandoc_aux.h main.h mdoc.h man.h
+man.o: man.c config.h man.h mandoc.h mandoc_aux.h libman.h libmandoc.h
+man_hash.o: man_hash.c config.h man.h mandoc.h libman.h
+man_html.o: man_html.c config.h mandoc.h mandoc_aux.h out.h html.h man.h main.h
+man_macro.o: man_macro.c config.h man.h mandoc.h libmandoc.h libman.h
+man_term.o: man_term.c config.h mandoc.h mandoc_aux.h out.h man.h term.h main.h
+man_validate.o: man_validate.c config.h man.h mandoc.h mandoc_aux.h libman.h libmandoc.h
+mandoc.o: mandoc.c config.h mandoc.h mandoc_aux.h libmandoc.h
+mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
+mandocdb.o: mandocdb.c config.h mdoc.h man.h mandoc.h mandoc_aux.h manpath.h mansearch.h
+manpage.o: manpage.c config.h manpath.h mansearch.h
+manpath.o: manpath.c config.h mandoc_aux.h manpath.h
+mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h manpath.h mansearch.h
+mansearch_const.o: mansearch_const.c config.h manpath.h mansearch.h
+mdoc.o: mdoc.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
+mdoc_argv.o: mdoc_argv.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
+mdoc_hash.o: mdoc_hash.c config.h mdoc.h libmdoc.h
+mdoc_html.o: mdoc_html.c config.h mandoc.h mandoc_aux.h out.h html.h mdoc.h main.h
+mdoc_macro.o: mdoc_macro.c config.h mdoc.h mandoc.h libmdoc.h libmandoc.h
+mdoc_man.o: mdoc_man.c config.h mandoc.h mandoc_aux.h out.h man.h mdoc.h main.h
+mdoc_term.o: mdoc_term.c config.h mandoc.h mandoc_aux.h out.h term.h mdoc.h main.h
+mdoc_validate.o: mdoc_validate.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
+msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
+out.o: out.c config.h mandoc_aux.h mandoc.h out.h
+preconv.o: preconv.c config.h
+read.o: read.c config.h mandoc.h mandoc_aux.h libmandoc.h mdoc.h man.h main.h
+roff.o: roff.c config.h mandoc.h mandoc_aux.h libroff.h libmandoc.h predefs.in
+st.o: st.c config.h mdoc.h libmdoc.h st.in
+tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h
+tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
+tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h
+tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h
+term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
+term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
+term_ps.o: term_ps.c config.h mandoc.h mandoc_aux.h out.h main.h term.h
+tree.o: tree.c config.h mandoc.h mdoc.h man.h main.h
+vol.o: vol.c config.h mdoc.h libmdoc.h vol.in
+test-fgetln.o: test-fgetln.c
+test-getsubopt.o: test-getsubopt.c
+test-mmap.o: test-mmap.c
+test-ohash.o: test-ohash.c
+test-reallocarray.o: test-reallocarray.c
+test-sqlite3_errstr.o: test-sqlite3_errstr.c
+test-strcasestr.o: test-strcasestr.c
+test-strlcat.o: test-strlcat.c
+test-strlcpy.o: test-strlcpy.c
+test-strptime.o: test-strptime.c
+test-strsep.o: test-strsep.c
diff --git a/contrib/mdocml/NEWS b/contrib/mdocml/NEWS
index 6f21a38..61006b5 100644
--- a/contrib/mdocml/NEWS
+++ b/contrib/mdocml/NEWS
@@ -1,7 +1,87 @@
-$Id: NEWS,v 1.3 2013/10/13 16:06:50 schwarze Exp $
+$Id: NEWS,v 1.5 2014/08/10 16:32:57 schwarze Exp $
This file lists the most important changes in the mdocml.bsd.lv distribution.
+Changes in version 1.13.1, released on August 10, 2014
+
+ --- MAJOR NEW FEATURES ---
+ * A complete apropos(1)/makewhatis(8)/man.cgi(8) suite
+ based on SQLite3 is now included.
+ CAVEAT: This also requires a working fts(3) implementation.
+ If your system lacks that *and* you want apropos(1)/makewhatis(8),
+ stay with 1.12.3 for now, then go to 1.12.4 and 1.13.2.
+ * The roff(7) parser now provides an almost complete implementation
+ of numerical expressions.
+ * Warning and error messages have been improved in many ways.
+ Almost all fatal errors were downgraded to normal errors and some
+ even to warnings. Almost all messages now mention the macro where
+ the issue is detected and many indicate the workaround employed.
+ The mandoc(1) manual now includes a list explaining all messages.
+ --- MINOR NEW FEATURES ---
+ * The roff(7) parser now supports the .ami (append to macro with
+ indirectly specified name), .as (append to user-defined
+ string), .dei (define macro with indirectly specified name),
+ .ll (line length), and .rr (remove register) requests.
+ * The roff(7) parser now supports string comparison and numerical
+ conditionals in the .if and .ie requests.
+ * The roff parser now fully supports the \B (validate numerical
+ expression) and partially supports the \w (measure text width)
+ escape sequences.
+ * The terminal formatter now supports the \: (optional line break)
+ escape sequence.
+ * The roff parser now supports expansion of user-defined strings
+ involving indirect references.
+ * The roff(7) parser now handles some pre-defined read-only
+ number registers that occur in the pod2man(1) preamble.
+ * For backward compatibility, the mdoc(7) parser and formatters
+ now support the obsolete macros .En, .Es, .Fr, and .Ot.
+ * The mdoc(7) formatter non partially supports .Bd -centered.
+ * tbl(7) now handles leading and trailing vertical lines.
+ * The build system now provides fallback versions of strcasestr(3)
+ and strsep(3) for systems lacking them.
+ * The mdoc(7) manual now explains how various standards
+ supported by the .St macro are related to each other.
+ --- BUGFIXES ---
+ * In the roff(7) parser, several bugs were fixed with respect
+ to closing conditional blocks on macro lines.
+ * Parsing of roff(7) identifiers and escape sequences was improved
+ in multiple respects.
+ * In the mdoc(7) parser, the handling of defective document
+ prologues was improved in multiple ways.
+ * The mdoc(7) parser no longer skips content before the first section
+ header, and it no longer deletes non-.% content from .Rs blocks.
+ * In the mdoc(7) parser, a crash was fixed related to weird .Sh headers.
+ * In the mdoc(7) parser, handling of .Sm with missing or invalid
+ arguments was corrected.
+ * In the mdoc(7) parser, trailing punctuation at the end of partial
+ implicit macros no longer triggers end-of-sentence spacing.
+ * In the terminal formatter, two crashes were fixed: one triggered by
+ excessive indentation and another by excessively long .Nm arguments.
+ * In the terminal formatter, a floating point rounding bug was
+ fixed that sometimes caused an off-by-one error in indentation.
+ * In the UTF-8 formatter, rendering of accents, breakable hyphens,
+ and non-breakable spaces was corrected.
+ * In the HTML formatter, encoding of special characters was
+ corrected in multiple respects.
+ * In the mdoc(7) formatter, rendering of .Ex and .Rv was
+ improved for various edge cases.
+ * In the mdoc(7) formatter, handling of empty .Bl -inset item
+ heads was improved.
+ * In the man(7) formatter, some bugs were fixed with respect
+ to same-line detection in the context of .TP and .nf macros,
+ and the indentation of .IP and .TP blocks was improved.
+ * The mandoc(3) library no longer prints to stderr.
+ --- THANKS TO ---
+ Abhinav Upadhyay (NetBSD), Andreas Voegele, Anthony Bentley (OpenBSD),
+ Christian Weisgerber (OpenBSD), Havard Eidnes (NetBSD), Jan Stary,
+ Jason McIntyre (OpenBSD), Jeremie Courreges-Anglas (OpenBSD),
+ Joerg Sonnenberger (NetBSD), Juan Francisco Cantero Hurtado (OpenBSD),
+ Marc Espie (OpenBSD), Matthias Scheler (NetBSD), Pascal Stumpf (OpenBSD),
+ Paul Onyschuk (Alpine Linux), Sebastien Marie, Steffen Nurpmeso,
+ Stuart Henderson (OpenBSD), Ted Unangst (OpenBSD), Theo de Raadt (OpenBSD),
+ Thomas Klausner (NetBSD), and Ulrich Spoerlein (FreeBSD)
+ for reporting bugs and missing features.
+
Changes in version 1.12.3, released on December 31, 2013
* In the mdoc(7) SYNOPSIS, line breaks and hanging indentation
diff --git a/contrib/mdocml/TODO b/contrib/mdocml/TODO
index 26f42c2..a41df29 100644
--- a/contrib/mdocml/TODO
+++ b/contrib/mdocml/TODO
@@ -1,13 +1,15 @@
************************************************************************
* Official mandoc TODO.
-* $Id: TODO,v 1.162 2013/12/25 14:40:34 schwarze Exp $
+* $Id: TODO,v 1.176 2014/08/09 14:24:53 schwarze Exp $
************************************************************************
************************************************************************
* crashes
************************************************************************
-None known.
+- The abort() in bufcat(), html.c, can be triggered via buffmt_includes()
+ by running -Thtml -Oincludes on a file containing a long .In argument.
+ Fixing this will probably require reworking the whole bufcat() concept.
************************************************************************
* missing features
@@ -15,11 +17,6 @@ None known.
--- missing roff features ----------------------------------------------
-- roff.c should treat \n(.H>23 and \n(.V>19 in the pod2man(1)
- preamble as true, see for example AUTHORS in MooseX::Getopt.3p
- reported by Andreas Voegele <mail at andreasvoegele dot com>
- Tue, 22 Nov 2011 15:34:47 +0100 on ports@
-
- .ad (adjust margins)
.ad l -- adjust left margin only (flush left)
.ad r -- adjust right margin only (flush right)
@@ -29,20 +26,9 @@ None known.
.ad -- re-enable adjustment without changing the mode
Adjustment mode is ignored while in no-fill mode (.nf).
-- .as (append to string)
- found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
-
-- .ce (center N lines)
- found by naddy@ in xloadimage(1)
- found by Juan Francisco Cantero Hurtado <iam at juanfra dot info>
- in lang/racket(1) Thu, 20 Jun 2013 03:19:11 +0200
-
- .fc (field control)
found by naddy@ in xloadimage(1)
-- .ll (line length)
- found by naddy@ in textproc/enchant(1) Sat, 12 Oct 2013 03:27:10 +0200
-
- .nr third argument (auto-increment step size, requires \n+)
found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
@@ -51,6 +37,7 @@ None known.
- .ta (tab settings) occurs in ircbug(1) and probably gnats(1)
reported by brad@ Sat, 15 Jan 2011 15:50:51 -0500
+ also Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
- .ti (temporary indent)
found by naddy@ in xloadimage(1)
@@ -70,6 +57,10 @@ None known.
- \n+ and \n- numerical register increment and decrement
found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
+- \w'' width measurements
+ would not be very useful without an expression parser, see below
+ needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
+
- using undefined strings or macros defines them to be empty
wl@ Mon, 14 Nov 2011 14:37:01 +0000
@@ -96,6 +87,12 @@ None known.
because libmdoc does not yet use mandoc_getarg().
Also check what happens in plain text, it must be identical to \e.
+- .Bd -centered implies -filled, not -unfilled, which is not
+ easy to implement; it requires code similar to .ce, which
+ we don't have either.
+ Besides, groff has bug causing text right *before* .Bd -centered
+ to be centered as well.
+
- .Bd -filled should not be the same as .Bd -ragged, but align both
the left and right margin. In groff, it is implemented in terms
of .ad b, which we don't have either. Found in cksum(1).
@@ -129,10 +126,19 @@ None known.
- have a blank `It' head for `Bl -tag' not puke
+- check whether it is correct that `D1' uses INDENT+1;
+ does it need its own constant?
+
- prohibit `Nm' from having non-text HEAD children
(e.g., NetBSD mDNSShared/dns-sd.1)
(mdoc_html.c and mdoc_term.c `Nm' handlers can be slightly simplified)
+- support translated section names
+ e.g. x11/scrotwm scrotwm_es.1:21:2: error: NAME section must be first
+ that one uses NOMBRE because it is spanish...
+ deraadt tends to think that section-dependent macro behaviour
+ is a bad idea in the first place, so this may be irrelevant
+
- When there is free text in the SYNOPSIS and that free text contains
the .Nm macro, groff somehow understands to treat the .Nm as an in-line
macro, while mandoc treats it as a block macro and breaks the line.
@@ -143,18 +149,15 @@ None known.
--- missing man features -----------------------------------------------
-- groff an-ext.tmac macros (.UR, .UE) occur in xine(5)
- reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
- also occur in freeciv-client(6) freeciv-server(6) freeciv-modpack(6)
- reported by bentley@ Tue, 30 Oct 2012 01:05:57 -0600
-
- -T[x]html doesn't stipulate non-collapsing spaces in literal mode
--- missing tbl features -----------------------------------------------
-- implement basic non-parametric .de to support e.g. sox(1)
- reported by naddy@ Sat, 16 Oct 2010 23:51:57 +0200
- *** sox(1) still doesn't work, tbl(1) errors need investigation
+- look at the POSIX manuals in the books/man-pages-posix port,
+ they use some unsupported tbl(7) features.
+
+- investigate tbl(1) errors in sox(1)
+ see also naddy@ Sat, 16 Oct 2010 23:51:57 +0200
- allow standalone `.' to be interpreted as an end-of-layout
delimiter instead of being thrown away as a no-op roff line
@@ -165,14 +168,19 @@ None known.
- italic correction (\/) in PostScript mode
Werner LEMBERG on groff at gnu dot org Sun, 10 Nov 2013 12:47:46
-- The whatis(1) utility looks for whole words in Nm.
- If the file name of a page does not agree with the contents of any
- of its Nm macros (e.g. pool(9)), add the file name as an Nm entry
- to the mandoc.db as well, such that whatis(1) finds it.
- If there is a page with a file name that does not appear as a substring
- neither in Nm nor in Nd, the same fix would allow finding that page
- with apropos(1) using the file name as a key, as well.
- Issue reported by tedu@ Fri, 05 Jul 2013 21:15:23 -0400
+- When makewhatis(8) encounters a FATAL parse error,
+ it silently treats the file as formatted, which makes no sense
+ at all for paths like man1/foo.1 - and which also contradicts
+ what the manual says at the end of the description.
+ The end result will be ENOENT for file names returned
+ by mansearch() in manpage.file.
+
+- makewhatis(8) for preformatted pages:
+ parse the section number from the header line
+ and compare to the section number from the directory name
+
+- Does makewhatis(8) detect missing NAME sections, missing names,
+ and missing descriptions in all the file formats?
- clean up escape sequence handling, creating three classes:
(1) fully implemented, or parsed and ignored without loss of content
@@ -181,6 +189,16 @@ None known.
see textproc/mgdiff(1) for nice examples
(3) undefined, just output the character -> perhaps WARNING
+- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET)
+
+--- compatibility checks -----------------------------------------------
+
+- is .Bk implemented correctly in modern groff?
+ sobrado@ Tue, 19 Apr 2011 22:12:55 +0200
+
+- compare output to Heirloom roff, Solaris roff, and
+ http://repo.or.cz/w/neatroff.git http://litcave.rudi.ir/
+
- look at pages generated from reStructeredText, e.g. devel/mercurial hg(1)
These are a weird mixture of man(7) and custom autogenerated low-level
roff stuff. Figure out to what extent we can cope.
@@ -188,14 +206,24 @@ None known.
noted by stsp@ Sat, 24 Apr 2010 09:17:55 +0200
reminded by nicm@ Mon, 3 May 2010 09:52:41 +0100
+- look at pages generated from ronn(1) github.com/rtomayko/ronn
+ (based on markdown)
+
- look at pages generated from Texinfo source by yat2m, e.g. security/gnupg
First impression is not that bad.
+- look at pages generated by pandoc; see
+ https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/Writers/Man.hs
+ porting planned by kili@ Thu, 19 Jun 2014 19:46:28 +0200
+
- check compatibility with Plan9:
http://swtch.com/usr/local/plan9/tmac/tmac.an
http://swtch.com/plan9port/man/man7/man.html
"Anthony J. Bentley" <anthonyjbentley@gmail.com> 28 Dec 2010 21:58:40 -0700
+- check compatibility with the man(7) formatter
+ https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c
+
************************************************************************
* formatting issues: ugly output
************************************************************************
@@ -227,6 +255,10 @@ None known.
the right solution, it sends mandoc into an endless loop.
reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100
+- global variables in the SYNOPSIS of section 3 pages
+ .Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ...
+ from kristaps@ Tue, 08 Jun 2010 11:13:32 +0200
+
- in enclosures, mandoc sometimes fancies a bogus end of sentence
reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059
@@ -234,6 +266,23 @@ None known.
reveals lots of bugs both in groff and mandoc...
reported by bentley@ Wed, 22 May 2013 23:49:30 -0600
+--- PDF issues ---------------------------------------------------------
+
+- PDF output doesn't use a monospaced font for .Bd -literal
+ Example: "mandoc -Tpdf afterboot.8 > output.pdf && pdfviewer output.pdf".
+ Search the text "Routing tables".
+ Also check what PostScript mode does when fixing this.
+ reported by juanfra@ Wed, 04 Jun 2014 21:44:58 +0200
+
+--- HTML issues --------------------------------------------------------
+
+- <dl><dt><dd> formatting is ugly
+ hints are easy to find on the web, e.g.
+ http://stackoverflow.com/questions/1713048/
+ see also matthew@ Fri, 18 Jul 2014 19:25:12 -0700
+
+- check https://github.com/trentm/mdocml
+
************************************************************************
* formatting issues: gratuitous differences
************************************************************************
@@ -246,6 +295,10 @@ None known.
is just "o\bo".
see for example OpenBSD ksh(1)
+- In .Bl -enum -width 0n, groff continues one the same line after
+ the number, mandoc breaks the line.
+ mail to kristaps@ Mon, 20 Jul 2009 02:21:39 +0200
+
- .Pp between two .It in .Bl -column should produce one,
not two blank lines, see e.g. login.conf(5).
reported by jmc@ Sun, 17 Apr 2011 14:04:58 +0059
@@ -299,9 +352,57 @@ None known.
in dig(1).
************************************************************************
+* warning issues
+************************************************************************
+
+- check that MANDOCERR_BADTAB is thrown in the right cases,
+ i.e. when finding a literal tab character in fill mode,
+ and possibly change the wording of the warning message
+ to refer to fill mode, not literal mode
+ See the mail from Werner LEMBERG on the groff list,
+ Fri, 14 Feb 2014 18:54:42 +0100 (CET)
+
+- warn about "new sentence, new line"
+
+- mandoc_special does not really check the escape sequence,
+ but just the overall format
+
+- integrate mdoclint into mandoc ("end-of-line whitespace" thread)
+ from jmc@ Mon, 13 Jul 2009 17:12:09 +0100
+ from kristaps@ Mon, 13 Jul 2009 18:34:53 +0200
+ from jmc@ Mon, 13 Jul 2009 17:45:37 +0059
+ from kristaps@ Mon, 13 Jul 2009 19:02:03 +0200
+
+- -Tlint parser errors and warnings to stdout
+ to tech@mdocml, naddy@ Wed, 28 Sep 2011 11:21:46 +0200
+ wait! kristaps@ Sun, 02 Oct 2011 17:12:52 +0200
+
+- for system errors, use errno/strerror/warn/err
+
+************************************************************************
+* documentation issues
+************************************************************************
+
+- mention hyphenation rules:
+ breaking at letter-letter in text mode (not macro args)
+ proper hyphenation is unimplemented
+
+- talk about spacing around delimiters
+ to jmc@, kristaps@ Sat, 23 Apr 2011 17:41:27 +0200
+
+- mark macros as: page structure domain, manual domain, general text domain
+ is this useful?
+
+- mention /usr/share/misc/mdoc.template in mdoc(7)?
+
+************************************************************************
* performance issues
************************************************************************
+- Why are we using MAP_SHARED, not MAP_PRIVATE for mmap(2)?
+ How does SQLITE_CONFIG_PAGECACHE actually work? Document it!
+ from kristaps@ Sat, 09 Aug 2014 13:51:36 +0200
+
Several areas can be cleaned up to make mandoc even faster. These are
- improve hashing mechanism for macros (quite important: performance)
@@ -328,3 +429,9 @@ Several areas can be cleaned up to make mandoc even faster. These are
Decide which formats should be recognized where.
Update both mdoc(7) and man(7) documentation.
Triggered by Tim van der Molen Tue, 22 Feb 2011 20:30:45 +0100
+
+- Consider creating some views that will make the database more
+ readable from the sqlite3 shell. Consider using them to
+ abstract from the database structure, too.
+ suggested by espie@ Sat, 19 Apr 2014 14:52:57 +0200
+
diff --git a/contrib/mdocml/apropos.1 b/contrib/mdocml/apropos.1
new file mode 100644
index 0000000..1468242
--- /dev/null
+++ b/contrib/mdocml/apropos.1
@@ -0,0 +1,387 @@
+.\" $Id: apropos.1,v 1.29 2014/04/24 00:28:19 schwarze Exp $
+.\"
+.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" 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: April 24 2014 $
+.Dt APROPOS 1
+.Os
+.Sh NAME
+.Nm apropos ,
+.Nm whatis
+.Nd search manual page databases
+.Sh SYNOPSIS
+.Nm
+.Op Fl C Ar file
+.Op Fl M Ar path
+.Op Fl m Ar path
+.Op Fl O Ar outkey
+.Op Fl S Ar arch
+.Op Fl s Ar section
+.Ar expression ...
+.Sh DESCRIPTION
+The
+.Nm apropos
+and
+.Nm whatis
+utilities query manual page databases generated by
+.Xr makewhatis 8 ,
+evaluating
+.Ar expression
+for each file in each database.
+By default, it displays the names, section numbers, and description lines
+of all matching manuals.
+.Pp
+By default,
+.Nm
+searches for
+.Xr makewhatis 8
+databases in the default paths stipulated by
+.Xr man 1
+and uses case-insensitive substring matching
+.Pq the Cm = No operator
+over manual names and descriptions
+.Pq the Li \&Nm No and Li \&Nd No macro keys .
+Multiple terms imply pairwise
+.Fl o .
+.Nm whatis
+maps terms only to case-sensitive manual names.
+.Pp
+Its arguments are as follows:
+.Bl -tag -width Ds
+.It Fl C Ar file
+Specify an alternative configuration
+.Ar file
+in
+.Xr man.conf 5
+format.
+.It Fl M Ar path
+Use the colon-separated path instead of the default list of paths
+searched for
+.Xr makewhatis 8
+databases.
+Invalid paths, or paths without manual databases, are ignored.
+.It Fl m Ar path
+Prepend the colon-separated paths to the list of paths searched
+for
+.Xr makewhatis 8
+databases.
+Invalid paths, or paths without manual databases, are ignored.
+.It Fl O Ar outkey
+Show the values associated with the key
+.Ar outkey
+instead of the manual descriptions.
+.It Fl S Ar arch
+Restrict the search to pages for the specified
+.Xr machine 1
+architecture.
+.Ar arch
+is case insensitive.
+By default, pages for all architectures are shown.
+.It Fl s Ar section
+Restrict the search to the specified section of the manual.
+By default, pages from all sections are shown.
+See
+.Xr man 1
+for a listing of sections.
+.El
+.Pp
+An
+.Ar expression
+consists of search terms joined by logical operators
+.Fl a
+.Pq and
+and
+.Fl o
+.Pq or .
+The
+.Fl a
+operator has precedence over
+.Fl o
+and both are evaluated left-to-right.
+.Bl -tag -width Ds
+.It \&( Ar expr No \&)
+True if the subexpression
+.Ar expr
+is true.
+.It Ar expr1 Fl a Ar expr2
+True if both
+.Ar expr1
+and
+.Ar expr2
+are true (logical
+.Sq and ) .
+.It Ar expr1 Oo Fl o Oc Ar expr2
+True if
+.Ar expr1
+and/or
+.Ar expr2
+evaluate to true (logical
+.Sq or ) .
+.It Ar term
+True if
+.Ar term
+is satisfied.
+This has syntax
+.Sm off
+.Oo
+.Op Ar key Op , Ar key ...
+.Pq Cm = | ~
+.Oc
+.Ar val ,
+.Sm on
+where
+.Ar key
+is an
+.Xr mdoc 7
+macro to query and
+.Ar val
+is its value.
+See
+.Sx Macro Keys
+for a list of available keys.
+Operator
+.Cm =
+evaluates a substring, while
+.Cm ~
+evaluates a regular expression.
+.It Fl i Ar term
+If
+.Ar term
+is a regular expression, it
+is evaluated case-insensitively.
+Has no effect on substring terms.
+.El
+.Pp
+.Nm whatis
+considers an
+.Ar expression
+to consist of an opaque keyword.
+.Pp
+Results are sorted by manual sections and names, with output formatted as
+.Pp
+.D1 name[, name...](sec) \- description
+.Pp
+Where
+.Dq name
+is the manual's name,
+.Dq sec
+is the manual section, and
+.Dq description
+is the manual's short description.
+If an architecture is specified for the manual, it is displayed as
+.Pp
+.D1 name(sec/arch) \- description
+.Pp
+Resulting manuals may be accessed as
+.Pp
+.Dl $ man \-s sec name
+.Pp
+If an architecture is specified in the output, use
+.Pp
+.Dl $ man \-s sec \-S arch name
+.Ss Macro Keys
+Queries evaluate over a subset of
+.Xr mdoc 7
+macros indexed by
+.Xr makewhatis 8 .
+In addition to the macro keys listed below, the special key
+.Cm any
+may be used to match any available macro key.
+.Pp
+Names and description:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&Nm Ta manual name
+.It Li \&Nd Ta one-line manual description
+.It Li arch Ta machine architecture (case-insensitive)
+.It Li sec Ta manual section number
+.El
+.Pp
+Sections and cross references:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&Sh Ta section header (excluding standard sections)
+.It Li \&Ss Ta subsection header
+.It Li \&Xr Ta cross reference to another manual page
+.It Li \&Rs Ta bibliographic reference
+.El
+.Pp
+Semantic markup for command line utilities:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&Fl Ta command line options (flags)
+.It Li \&Cm Ta command modifier
+.It Li \&Ar Ta command argument
+.It Li \&Ic Ta internal or interactive command
+.It Li \&Ev Ta environmental variable
+.It Li \&Pa Ta file system path
+.El
+.Pp
+Semantic markup for function libraries:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&Lb Ta function library name
+.It Li \&In Ta include file
+.It Li \&Ft Ta function return type
+.It Li \&Fn Ta function name
+.It Li \&Fa Ta function argument type and name
+.It Li \&Vt Ta variable type
+.It Li \&Va Ta variable name
+.It Li \&Dv Ta defined variable or preprocessor constant
+.It Li \&Er Ta error constant
+.It Li \&Ev Ta environmental variable
+.El
+.Pp
+Various semantic markup:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&An Ta author name
+.It Li \&Lk Ta hyperlink
+.It Li \&Mt Ta Do mailto Dc hyperlink
+.It Li \&Cd Ta kernel configuration declaration
+.It Li \&Ms Ta mathematical symbol
+.It Li \&Tn Ta tradename
+.El
+.Pp
+Physical markup:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&Em Ta italic font or underline
+.It Li \&Sy Ta boldface font
+.It Li \&Li Ta typewriter font
+.El
+.Pp
+Text production:
+.Bl -column "xLix" description -offset indent -compact
+.It Li \&St Ta reference to a standards document
+.It Li \&At Ta At No version reference
+.It Li \&Bx Ta Bx No version reference
+.It Li \&Bsx Ta Bsx No version reference
+.It Li \&Nx Ta Nx No version reference
+.It Li \&Fx Ta Fx No version reference
+.It Li \&Ox Ta Ox No version reference
+.It Li \&Dx Ta Dx No version reference
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width MANPATH
+.It Ev MANPATH
+The standard search path used by
+.Xr man 1
+may be changed by specifying a path in the
+.Ev MANPATH
+environment variable.
+Invalid paths, or paths without manual databases, are ignored.
+Overridden by
+.Fl M .
+If
+.Ev MANPATH
+begins with a colon, it is appended to the default list;
+if it ends with a colon, it is prepended to the default list;
+or if it contains two adjacent colons,
+the standard search path is inserted between the colons.
+If none of these conditions are met, it overrides the
+standard search path.
+.El
+.Sh FILES
+.Bl -tag -width "/etc/man.conf" -compact
+.It Pa mandoc.db
+name of the
+.Xr makewhatis 8
+keyword database
+.It Pa /etc/man.conf
+default
+.Xr man 1
+configuration file
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Search for
+.Qq .cf
+as a substring of manual names and descriptions:
+.Pp
+.Dl $ apropos .cf
+.Pp
+Include matches for
+.Qq .cnf
+and
+.Qq .conf
+as well:
+.Pp
+.Dl $ apropos .cf .cnf .conf
+.Pp
+Search in names and descriptions using a regular expression:
+.Pp
+.Dl $ apropos '~set.?[ug]id'
+.Pp
+Search for manuals in the library section mentioning both the
+.Qq optind
+and the
+.Qq optarg
+variables:
+.Pp
+.Dl $ apropos \-s 3 Va=optind \-a Va=optarg
+.Pp
+Do exactly the same as calling
+.Xr whatis 1
+with the argument
+.Qq ssh :
+.Pp
+.Dl $ apropos \-\- \-i 'Nm~[[:<:]]ssh[[:>:]]'
+.Pp
+The following two invocations are equivalent:
+.Pp
+.D1 Li $ apropos -S Ar arch Li -s Ar section expression
+.Bd -ragged -offset indent
+.Li $ apropos \e( Ar expression Li \e)
+.Li -a arch~^( Ns Ar arch Ns Li |any)$
+.Li -a sec~^ Ns Ar section Ns Li $
+.Ed
+.Sh SEE ALSO
+.Xr man 1 ,
+.Xr re_format 7 ,
+.Xr makewhatis 8
+.Sh HISTORY
+An
+.Nm
+utility first appeared in
+.Bx 2 .
+It was rewritten from scratch for
+.Ox 5.6 .
+.Pp
+The
+.Fl M
+option and the
+.Ev MANPATH
+variable first appeared in
+.Bx 4.3 ;
+.Fl m
+in
+.Bx 4.3 Reno ;
+.Fl C
+in
+.Bx 4.4 Lite1 ;
+and
+.Fl S
+and
+.Fl s
+in
+.Ox 4.5 .
+.Sh AUTHORS
+.An -nosplit
+.An Bill Joy
+wrote the original
+.Bx
+.Nm
+in February 1979.
+The current version was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/contrib/mdocml/apropos.c b/contrib/mdocml/apropos.c
new file mode 100644
index 0000000..80b6bc6
--- /dev/null
+++ b/contrib/mdocml/apropos.c
@@ -0,0 +1,123 @@
+/* $Id: apropos.c,v 1.39 2014/04/20 16:46:04 schwarze Exp $ */
+/*
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sys/param.h>
+
+#include <assert.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "manpath.h"
+#include "mansearch.h"
+
+
+int
+main(int argc, char *argv[])
+{
+ int ch, whatis;
+ struct mansearch search;
+ size_t i, sz;
+ struct manpage *res;
+ struct manpaths paths;
+ char *defpaths, *auxpaths;
+ char *conf_file;
+ char *progname;
+ const char *outkey;
+ extern char *optarg;
+ extern int optind;
+
+ progname = strrchr(argv[0], '/');
+ if (progname == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ whatis = (0 == strncmp(progname, "whatis", 6));
+
+ memset(&paths, 0, sizeof(struct manpaths));
+ memset(&search, 0, sizeof(struct mansearch));
+
+ auxpaths = defpaths = NULL;
+ conf_file = NULL;
+ outkey = "Nd";
+
+ while (-1 != (ch = getopt(argc, argv, "C:M:m:O:S:s:")))
+ switch (ch) {
+ case 'C':
+ conf_file = optarg;
+ break;
+ case 'M':
+ defpaths = optarg;
+ break;
+ case 'm':
+ auxpaths = optarg;
+ break;
+ case 'O':
+ outkey = optarg;
+ break;
+ case 'S':
+ search.arch = optarg;
+ break;
+ case 's':
+ search.sec = optarg;
+ break;
+ default:
+ goto usage;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (0 == argc)
+ goto usage;
+
+ search.deftype = whatis ? TYPE_Nm : TYPE_Nm | TYPE_Nd;
+ search.flags = whatis ? MANSEARCH_WHATIS : 0;
+
+ manpath_parse(&paths, conf_file, defpaths, auxpaths);
+ mansearch_setup(1);
+ ch = mansearch(&search, &paths, argc, argv, outkey, &res, &sz);
+ manpath_free(&paths);
+
+ if (0 == ch)
+ goto usage;
+
+ for (i = 0; i < sz; i++) {
+ printf("%s - %s\n", res[i].names,
+ NULL == res[i].output ? "" : res[i].output);
+ free(res[i].file);
+ free(res[i].names);
+ free(res[i].output);
+ }
+
+ free(res);
+ mansearch_setup(0);
+ return(sz ? EXIT_SUCCESS : EXIT_FAILURE);
+usage:
+ fprintf(stderr, "usage: %s [-C file] [-M path] [-m path] "
+ "[-O outkey] "
+ "[-S arch] [-s section]%s ...\n", progname,
+ whatis ? " name" : "\n expression");
+ return(EXIT_FAILURE);
+}
diff --git a/contrib/mdocml/arch.c b/contrib/mdocml/arch.c
index e764bfe..3e746d8 100644
--- a/contrib/mdocml/arch.c
+++ b/contrib/mdocml/arch.c
@@ -1,4 +1,4 @@
-/* $Id: arch.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: arch.c,v 1.11 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,22 +18,20 @@
#include "config.h"
#endif
-#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
if (0 == strcmp(p, x)) return(y);
+
const char *
mdoc_a2arch(const char *p)
{
-#include "arch.in"
+#include "arch.in"
return(NULL);
}
diff --git a/contrib/mdocml/arch.in b/contrib/mdocml/arch.in
index d0c445f..a22ffd5 100644
--- a/contrib/mdocml/arch.in
+++ b/contrib/mdocml/arch.in
@@ -1,4 +1,4 @@
-/* $Id: arch.in,v 1.14 2013/09/16 22:12:57 schwarze Exp $ */
+/* $Id: arch.in,v 1.15 2014/04/27 22:42:15 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -65,8 +65,8 @@ LINE("ibmnws", "IBMNWS")
LINE("iyonix", "Iyonix")
LINE("landisk", "LANDISK")
LINE("loongson", "Loongson")
-LINE("luna68k", "Luna68k")
-LINE("luna88k", "Luna88k")
+LINE("luna68k", "LUNA68K")
+LINE("luna88k", "LUNA88K")
LINE("m68k", "m68k")
LINE("mac68k", "Mac68k")
LINE("macppc", "MacPPC")
diff --git a/contrib/mdocml/att.c b/contrib/mdocml/att.c
index 24d757d..059639a 100644
--- a/contrib/mdocml/att.c
+++ b/contrib/mdocml/att.c
@@ -1,4 +1,4 @@
-/* $Id: att.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: att.c,v 1.11 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,22 +18,20 @@
#include "config.h"
#endif
-#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
if (0 == strcmp(p, x)) return(y);
+
const char *
mdoc_a2att(const char *p)
{
-#include "att.in"
+#include "att.in"
return(NULL);
}
diff --git a/contrib/mdocml/cgi.c b/contrib/mdocml/cgi.c
new file mode 100644
index 0000000..1e38e3d
--- /dev/null
+++ b/contrib/mdocml/cgi.c
@@ -0,0 +1,1150 @@
+/* $Id: cgi.c,v 1.92 2014/08/05 15:29:30 schwarze Exp $ */
+/*
+ * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@usta.de>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mandoc.h"
+#include "mandoc_aux.h"
+#include "main.h"
+#include "manpath.h"
+#include "mansearch.h"
+#include "cgi.h"
+
+/*
+ * A query as passed to the search function.
+ */
+struct query {
+ char *manpath; /* desired manual directory */
+ char *arch; /* architecture */
+ char *sec; /* manual section */
+ char *query; /* unparsed query expression */
+ int equal; /* match whole names, not substrings */
+};
+
+struct req {
+ struct query q;
+ char **p; /* array of available manpaths */
+ size_t psz; /* number of available manpaths */
+};
+
+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 http_print(const char *);
+static void http_putchar(char);
+static void http_printquery(const struct req *, const char *);
+static void pathgen(struct req *);
+static void pg_error_badrequest(const char *);
+static void pg_error_internal(void);
+static void pg_index(const struct req *);
+static void pg_noresult(const struct req *, const char *);
+static void pg_search(const struct req *);
+static void pg_searchres(const struct req *,
+ struct manpage *, size_t);
+static void pg_show(struct req *, const char *);
+static void resp_begin_html(int, const char *);
+static void resp_begin_http(int, const char *);
+static void resp_end_html(void);
+static void resp_searchform(const struct req *);
+static void resp_show(const struct req *, const char *);
+static void set_query_attr(char **, char **);
+static int validate_filename(const char *);
+static int validate_manpath(const struct req *, const char *);
+static int validate_urifrag(const char *);
+
+static const char *scriptname; /* CGI script name */
+
+static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
+static const char *const sec_numbers[] = {
+ "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9"
+};
+static const char *const sec_names[] = {
+ "All Sections",
+ "1 - General Commands",
+ "2 - System Calls",
+ "3 - Subroutines",
+ "3p - Perl Subroutines",
+ "4 - Special Files",
+ "5 - File Formats",
+ "6 - Games",
+ "7 - Macros and Conventions",
+ "8 - Maintenance Commands",
+ "9 - Kernel Interface"
+};
+static const int sec_MAX = sizeof(sec_names) / sizeof(char *);
+
+static const char *const arch_names[] = {
+ "amd64", "alpha", "armish", "armv7",
+ "aviion", "hppa", "hppa64", "i386",
+ "ia64", "landisk", "loongson", "luna88k",
+ "macppc", "mips64", "octeon", "sgi",
+ "socppc", "solbourne", "sparc", "sparc64",
+ "vax", "zaurus",
+ "amiga", "arc", "arm32", "atari",
+ "beagle", "cats", "hp300", "mac68k",
+ "mvme68k", "mvme88k", "mvmeppc", "palm",
+ "pc532", "pegasos", "pmax", "powerpc",
+ "sun3", "wgrisc", "x68k"
+};
+static const int arch_MAX = sizeof(arch_names) / sizeof(char *);
+
+/*
+ * Print a character, escaping HTML along the way.
+ * This will pass non-ASCII straight to output: be warned!
+ */
+static void
+html_putchar(char c)
+{
+
+ switch (c) {
+ case ('"'):
+ printf("&quote;");
+ break;
+ case ('&'):
+ printf("&amp;");
+ break;
+ case ('>'):
+ printf("&gt;");
+ break;
+ case ('<'):
+ printf("&lt;");
+ break;
+ default:
+ putchar((unsigned char)c);
+ break;
+ }
+}
+
+static void
+http_printquery(const struct req *req, const char *sep)
+{
+
+ if (NULL != req->q.query) {
+ printf("query=");
+ http_print(req->q.query);
+ }
+ if (0 == req->q.equal)
+ printf("%sapropos=1", sep);
+ if (NULL != req->q.sec) {
+ printf("%ssec=", sep);
+ http_print(req->q.sec);
+ }
+ if (NULL != req->q.arch) {
+ printf("%sarch=", sep);
+ http_print(req->q.arch);
+ }
+ if (NULL != req->q.manpath &&
+ strcmp(req->q.manpath, req->p[0])) {
+ printf("%smanpath=", sep);
+ http_print(req->q.manpath);
+ }
+}
+
+static void
+http_print(const char *p)
+{
+
+ if (NULL == p)
+ return;
+ while ('\0' != *p)
+ http_putchar(*p++);
+}
+
+/*
+ * Call through to html_putchar().
+ * Accepts NULL strings.
+ */
+static void
+html_print(const char *p)
+{
+
+ if (NULL == p)
+ return;
+ while ('\0' != *p)
+ html_putchar(*p++);
+}
+
+/*
+ * Transfer the responsibility for the allocated string *val
+ * to the query structure.
+ */
+static void
+set_query_attr(char **attr, char **val)
+{
+
+ free(*attr);
+ if (**val == '\0') {
+ *attr = NULL;
+ free(*val);
+ } else
+ *attr = *val;
+ *val = NULL;
+}
+
+/*
+ * Parse the QUERY_STRING for key-value pairs
+ * and store the values into the query structure.
+ */
+static void
+http_parse(struct req *req, const char *qs)
+{
+ char *key, *val;
+ size_t keysz, valsz;
+
+ req->q.manpath = NULL;
+ req->q.arch = NULL;
+ req->q.sec = NULL;
+ req->q.query = NULL;
+ req->q.equal = 1;
+
+ key = val = NULL;
+ while (*qs != '\0') {
+
+ /* Parse one key. */
+
+ keysz = strcspn(qs, "=;&");
+ key = mandoc_strndup(qs, keysz);
+ qs += keysz;
+ if (*qs != '=')
+ goto next;
+
+ /* Parse one value. */
+
+ valsz = strcspn(++qs, ";&");
+ val = mandoc_strndup(qs, valsz);
+ qs += valsz;
+
+ /* Decode and catch encoding errors. */
+
+ if ( ! (http_decode(key) && http_decode(val)))
+ goto next;
+
+ /* Handle key-value pairs. */
+
+ if ( ! strcmp(key, "query"))
+ set_query_attr(&req->q.query, &val);
+
+ else if ( ! strcmp(key, "apropos"))
+ req->q.equal = !strcmp(val, "0");
+
+ else if ( ! strcmp(key, "manpath")) {
+#ifdef COMPAT_OLDURI
+ if ( ! strncmp(val, "OpenBSD ", 8)) {
+ val[7] = '-';
+ if ('C' == val[8])
+ val[8] = 'c';
+ }
+#endif
+ set_query_attr(&req->q.manpath, &val);
+ }
+
+ else if ( ! (strcmp(key, "sec")
+#ifdef COMPAT_OLDURI
+ && strcmp(key, "sektion")
+#endif
+ )) {
+ if ( ! strcmp(val, "0"))
+ *val = '\0';
+ set_query_attr(&req->q.sec, &val);
+ }
+
+ else if ( ! strcmp(key, "arch")) {
+ if ( ! strcmp(val, "default"))
+ *val = '\0';
+ set_query_attr(&req->q.arch, &val);
+ }
+
+ /*
+ * The key must be freed in any case.
+ * The val may have been handed over to the query
+ * structure, in which case it is now NULL.
+ */
+next:
+ free(key);
+ key = NULL;
+ free(val);
+ val = NULL;
+
+ if (*qs != '\0')
+ qs++;
+ }
+
+ /* Fall back to the default manpath. */
+
+ if (req->q.manpath == NULL)
+ req->q.manpath = mandoc_strdup(req->p[0]);
+}
+
+static void
+http_putchar(char c)
+{
+
+ if (isalnum((unsigned char)c)) {
+ putchar((unsigned char)c);
+ return;
+ } else if (' ' == c) {
+ putchar('+');
+ return;
+ }
+ printf("%%%.2x", c);
+}
+
+/*
+ * HTTP-decode a string. The standard explanation is that this turns
+ * "%4e+foo" into "n foo" in the regular way. This is done in-place
+ * over the allocated string.
+ */
+static int
+http_decode(char *p)
+{
+ char hex[3];
+ char *q;
+ int c;
+
+ hex[2] = '\0';
+
+ q = p;
+ for ( ; '\0' != *p; p++, q++) {
+ if ('%' == *p) {
+ if ('\0' == (hex[0] = *(p + 1)))
+ return(0);
+ if ('\0' == (hex[1] = *(p + 2)))
+ return(0);
+ if (1 != sscanf(hex, "%x", &c))
+ return(0);
+ if ('\0' == c)
+ return(0);
+
+ *q = (char)c;
+ p += 2;
+ } else
+ *q = '+' == *p ? ' ' : *p;
+ }
+
+ *q = '\0';
+ return(1);
+}
+
+static void
+resp_begin_http(int code, const char *msg)
+{
+
+ if (200 != code)
+ printf("Status: %d %s\r\n", code, msg);
+
+ printf("Content-Type: text/html; charset=utf-8\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Pragma: no-cache\r\n"
+ "\r\n");
+
+ fflush(stdout);
+}
+
+static void
+resp_begin_html(int code, const char *msg)
+{
+
+ resp_begin_http(code, msg);
+
+ printf("<!DOCTYPE HTML PUBLIC "
+ " \"-//W3C//DTD HTML 4.01//EN\""
+ " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
+ "<HTML>\n"
+ "<HEAD>\n"
+ "<META HTTP-EQUIV=\"Content-Type\""
+ " CONTENT=\"text/html; charset=utf-8\">\n"
+ "<LINK REL=\"stylesheet\" HREF=\"%s/man-cgi.css\""
+ " TYPE=\"text/css\" media=\"all\">\n"
+ "<LINK REL=\"stylesheet\" HREF=\"%s/man.css\""
+ " TYPE=\"text/css\" media=\"all\">\n"
+ "<TITLE>%s</TITLE>\n"
+ "</HEAD>\n"
+ "<BODY>\n"
+ "<!-- Begin page content. //-->\n",
+ CSS_DIR, CSS_DIR, CUSTOMIZE_TITLE);
+}
+
+static void
+resp_end_html(void)
+{
+
+ puts("</BODY>\n"
+ "</HTML>");
+}
+
+static void
+resp_searchform(const struct req *req)
+{
+ int i;
+
+ puts(CUSTOMIZE_BEGIN);
+ puts("<!-- Begin search form. //-->");
+ 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)
+ html_print(req->q.query);
+ puts("\" SIZE=\"40\">");
+
+ /* Write submission and reset buttons. */
+
+ printf( "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n"
+ "<INPUT TYPE=\"reset\" VALUE=\"Reset\">\n");
+
+ /* Write show radio button */
+
+ printf( "</TD><TD>\n"
+ "<INPUT TYPE=\"radio\" ");
+ if (req->q.equal)
+ printf("CHECKED=\"checked\" ");
+ printf( "NAME=\"apropos\" ID=\"show\" VALUE=\"0\">\n"
+ "<LABEL FOR=\"show\">Show named manual page</LABEL>\n");
+
+ /* Write section selector. */
+
+ puts( "</TD></TR><TR><TD>\n"
+ "<SELECT NAME=\"sec\">");
+ for (i = 0; i < sec_MAX; i++) {
+ printf("<OPTION VALUE=\"%s\"", sec_numbers[i]);
+ if (NULL != req->q.sec &&
+ 0 == strcmp(sec_numbers[i], req->q.sec))
+ printf(" SELECTED=\"selected\"");
+ printf(">%s</OPTION>\n", sec_names[i]);
+ }
+ puts("</SELECT>");
+
+ /* Write architecture selector. */
+
+ printf( "<SELECT NAME=\"arch\">\n"
+ "<OPTION VALUE=\"default\"");
+ if (NULL == req->q.arch)
+ printf(" SELECTED=\"selected\"");
+ puts(">All Architectures</OPTION>");
+ for (i = 0; i < arch_MAX; i++) {
+ printf("<OPTION VALUE=\"%s\"", arch_names[i]);
+ if (NULL != req->q.arch &&
+ 0 == strcmp(arch_names[i], req->q.arch))
+ printf(" SELECTED=\"selected\"");
+ printf(">%s</OPTION>\n", arch_names[i]);
+ }
+ puts("</SELECT>");
+
+ /* Write manpath selector. */
+
+ if (req->psz > 1) {
+ puts("<SELECT NAME=\"manpath\">");
+ for (i = 0; i < (int)req->psz; i++) {
+ printf("<OPTION ");
+ if (NULL == req->q.manpath ? 0 == i :
+ 0 == strcmp(req->q.manpath, req->p[i]))
+ printf("SELECTED=\"selected\" ");
+ printf("VALUE=\"");
+ html_print(req->p[i]);
+ printf("\">");
+ html_print(req->p[i]);
+ puts("</OPTION>");
+ }
+ 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("<!-- End search form. //-->");
+}
+
+static int
+validate_urifrag(const char *frag)
+{
+
+ while ('\0' != *frag) {
+ if ( ! (isalnum((unsigned char)*frag) ||
+ '-' == *frag || '.' == *frag ||
+ '/' == *frag || '_' == *frag))
+ return(0);
+ frag++;
+ }
+ return(1);
+}
+
+static int
+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);
+
+ return(0);
+}
+
+static int
+validate_filename(const char *file)
+{
+
+ if ('.' == file[0] && '/' == file[1])
+ file += 2;
+
+ return ( ! (strstr(file, "../") || strstr(file, "/..") ||
+ (strncmp(file, "man", 3) && strncmp(file, "cat", 3))));
+}
+
+static void
+pg_index(const struct req *req)
+{
+
+ resp_begin_html(200, NULL);
+ resp_searchform(req);
+ printf("<P>\n"
+ "This web interface is documented in the\n"
+ "<A HREF=\"%s/mandoc/man8/man.cgi.8\">man.cgi</A>\n"
+ "manual, and the\n"
+ "<A HREF=\"%s/mandoc/man1/apropos.1\">apropos</A>\n"
+ "manual explains the query syntax.\n"
+ "</P>\n",
+ scriptname, scriptname);
+ resp_end_html();
+}
+
+static void
+pg_noresult(const struct req *req, const char *msg)
+{
+ resp_begin_html(200, NULL);
+ resp_searchform(req);
+ puts("<P>");
+ puts(msg);
+ puts("</P>");
+ resp_end_html();
+}
+
+static void
+pg_error_badrequest(const char *msg)
+{
+
+ resp_begin_html(400, "Bad Request");
+ puts("<H1>Bad Request</H1>\n"
+ "<P>\n");
+ puts(msg);
+ printf("Try again from the\n"
+ "<A HREF=\"%s\">main page</A>.\n"
+ "</P>", scriptname);
+ resp_end_html();
+}
+
+static void
+pg_error_internal(void)
+{
+ resp_begin_html(500, "Internal Server Error");
+ puts("<P>Internal Server Error</P>");
+ resp_end_html();
+}
+
+static void
+pg_searchres(const struct req *req, struct manpage *r, size_t sz)
+{
+ char *arch, *archend;
+ size_t i, iuse, isec;
+ int archprio, archpriouse;
+ int prio, priouse;
+ char sec;
+
+ for (i = 0; i < sz; i++) {
+ if (validate_filename(r[i].file))
+ continue;
+ fprintf(stderr, "invalid filename %s in %s database\n",
+ r[i].file, req->q.manpath);
+ pg_error_internal();
+ return;
+ }
+
+ if (1 == sz) {
+ /*
+ * 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);
+ http_printquery(req, "&");
+ printf("\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "\r\n");
+ return;
+ }
+
+ resp_begin_html(200, NULL);
+ resp_searchform(req);
+ puts("<DIV CLASS=\"results\">");
+ puts("<TABLE>");
+
+ 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);
+ http_printquery(req, "&amp;");
+ 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>");
+ iuse = 0;
+ priouse = 10;
+ archpriouse = 3;
+ for (i = 0; i < sz; i++) {
+ isec = strcspn(r[i].file, "123456789");
+ sec = r[i].file[isec];
+ if ('\0' == sec)
+ continue;
+ prio = sec_prios[sec - '1'];
+ if (NULL == req->q.arch) {
+ archprio =
+ (NULL == (arch = strchr(
+ r[i].file + isec, '/'))) ? 3 :
+ (NULL == (archend = strchr(
+ arch + 1, '/'))) ? 0 :
+ strncmp(arch, "amd64/",
+ archend - arch) ? 2 : 1;
+ if (archprio < archpriouse) {
+ archpriouse = archprio;
+ priouse = prio;
+ iuse = i;
+ continue;
+ }
+ if (archprio > archpriouse)
+ continue;
+ }
+ if (prio >= priouse)
+ continue;
+ priouse = prio;
+ iuse = i;
+ }
+ resp_show(req, r[iuse].file);
+ }
+
+ resp_end_html();
+}
+
+static void
+catman(const struct req *req, const char *file)
+{
+ FILE *f;
+ size_t len;
+ int i;
+ char *p;
+ int italic, bold;
+
+ if (NULL == (f = fopen(file, "r"))) {
+ puts("<P>You specified an invalid manual file.</P>");
+ return;
+ }
+
+ puts("<DIV CLASS=\"catman\">\n"
+ "<PRE>");
+
+ while (NULL != (p = fgetln(f, &len))) {
+ bold = italic = 0;
+ for (i = 0; i < (int)len - 1; i++) {
+ /*
+ * This means that the catpage is out of state.
+ * Ignore it and keep going (although the
+ * catpage is bogus).
+ */
+
+ if ('\b' == p[i] || '\n' == p[i])
+ continue;
+
+ /*
+ * Print a regular character.
+ * Close out any bold/italic scopes.
+ * If we're in back-space mode, make sure we'll
+ * have something to enter when we backspace.
+ */
+
+ if ('\b' != p[i + 1]) {
+ if (italic)
+ printf("</I>");
+ if (bold)
+ printf("</B>");
+ italic = bold = 0;
+ html_putchar(p[i]);
+ continue;
+ } else if (i + 2 >= (int)len)
+ continue;
+
+ /* Italic mode. */
+
+ if ('_' == p[i]) {
+ if (bold)
+ printf("</B>");
+ if ( ! italic)
+ printf("<I>");
+ bold = 0;
+ italic = 1;
+ i += 2;
+ html_putchar(p[i]);
+ continue;
+ }
+
+ /*
+ * Handle funny behaviour troff-isms.
+ * These grok'd from the original man2html.c.
+ */
+
+ if (('+' == p[i] && 'o' == p[i + 2]) ||
+ ('o' == p[i] && '+' == p[i + 2]) ||
+ ('|' == p[i] && '=' == p[i + 2]) ||
+ ('=' == p[i] && '|' == p[i + 2]) ||
+ ('*' == p[i] && '=' == p[i + 2]) ||
+ ('=' == p[i] && '*' == p[i + 2]) ||
+ ('*' == p[i] && '|' == p[i + 2]) ||
+ ('|' == p[i] && '*' == p[i + 2])) {
+ if (italic)
+ printf("</I>");
+ if (bold)
+ printf("</B>");
+ italic = bold = 0;
+ putchar('*');
+ i += 2;
+ continue;
+ } else if (('|' == p[i] && '-' == p[i + 2]) ||
+ ('-' == p[i] && '|' == p[i + 1]) ||
+ ('+' == p[i] && '-' == p[i + 1]) ||
+ ('-' == p[i] && '+' == p[i + 1]) ||
+ ('+' == p[i] && '|' == p[i + 1]) ||
+ ('|' == p[i] && '+' == p[i + 1])) {
+ if (italic)
+ printf("</I>");
+ if (bold)
+ printf("</B>");
+ italic = bold = 0;
+ putchar('+');
+ i += 2;
+ continue;
+ }
+
+ /* Bold mode. */
+
+ if (italic)
+ printf("</I>");
+ if ( ! bold)
+ printf("<B>");
+ bold = 1;
+ italic = 0;
+ i += 2;
+ html_putchar(p[i]);
+ }
+
+ /*
+ * Clean up the last character.
+ * We can get to a newline; don't print that.
+ */
+
+ if (italic)
+ printf("</I>");
+ if (bold)
+ printf("</B>");
+
+ if (i == (int)len - 1 && '\n' != p[i])
+ html_putchar(p[i]);
+
+ putchar('\n');
+ }
+
+ puts("</PRE>\n"
+ "</DIV>");
+
+ fclose(f);
+}
+
+static void
+format(const struct req *req, const char *file)
+{
+ struct mparse *mp;
+ struct mdoc *mdoc;
+ struct man *man;
+ void *vp;
+ char *opts;
+ enum mandoclevel rc;
+ int fd;
+ int usepath;
+
+ if (-1 == (fd = open(file, O_RDONLY, 0))) {
+ puts("<P>You specified an invalid manual file.</P>");
+ return;
+ }
+
+ mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL,
+ req->q.manpath);
+ rc = mparse_readfd(mp, fd, file);
+ close(fd);
+
+ if (rc >= MANDOCLEVEL_FATAL) {
+ fprintf(stderr, "fatal mandoc error: %s/%s\n",
+ req->q.manpath, file);
+ pg_error_internal();
+ return;
+ }
+
+ usepath = strcmp(req->q.manpath, req->p[0]);
+ mandoc_asprintf(&opts,
+ "fragment,man=%s?query=%%N&sec=%%S%s%s%s%s",
+ scriptname,
+ req->q.arch ? "&arch=" : "",
+ req->q.arch ? req->q.arch : "",
+ usepath ? "&manpath=" : "",
+ usepath ? req->q.manpath : "");
+
+ mparse_result(mp, &mdoc, &man, NULL);
+ if (NULL == man && NULL == mdoc) {
+ fprintf(stderr, "fatal mandoc error: %s/%s\n",
+ req->q.manpath, file);
+ pg_error_internal();
+ mparse_free(mp);
+ return;
+ }
+
+ vp = html_alloc(opts);
+
+ if (NULL != mdoc)
+ html_mdoc(vp, mdoc);
+ else
+ html_man(vp, man);
+
+ html_free(vp);
+ mparse_free(mp);
+ free(opts);
+}
+
+static void
+resp_show(const struct req *req, const char *file)
+{
+
+ if ('.' == file[0] && '/' == file[1])
+ file += 2;
+
+ if ('c' == *file)
+ catman(req, file);
+ else
+ format(req, file);
+}
+
+static void
+pg_show(struct req *req, const char *fullpath)
+{
+ char *manpath;
+ const char *file;
+
+ if ((file = strchr(fullpath, '/')) == NULL) {
+ pg_error_badrequest(
+ "You did not specify a page to show.");
+ return;
+ }
+ manpath = mandoc_strndup(fullpath, file - fullpath);
+ file++;
+
+ if ( ! validate_manpath(req, manpath)) {
+ pg_error_badrequest(
+ "You specified an invalid manpath.");
+ free(manpath);
+ return;
+ }
+
+ /*
+ * Begin by chdir()ing into the manpath.
+ * This way we can pick up the database files, which are
+ * relative to the manpath root.
+ */
+
+ if (chdir(manpath) == -1) {
+ fprintf(stderr, "chdir %s: %s\n",
+ manpath, strerror(errno));
+ pg_error_internal();
+ free(manpath);
+ return;
+ }
+
+ if (strcmp(manpath, "mandoc")) {
+ free(req->q.manpath);
+ req->q.manpath = manpath;
+ } else
+ free(manpath);
+
+ if ( ! validate_filename(file)) {
+ pg_error_badrequest(
+ "You specified an invalid manual file.");
+ return;
+ }
+
+ resp_begin_html(200, NULL);
+ resp_searchform(req);
+ resp_show(req, file);
+ resp_end_html();
+}
+
+static void
+pg_search(const struct req *req)
+{
+ struct mansearch search;
+ struct manpaths paths;
+ struct manpage *res;
+ char **cp;
+ const char *ep, *start;
+ size_t ressz;
+ int i, sz;
+
+ /*
+ * Begin by chdir()ing into the root of the manpath.
+ * This way we can pick up the database files, which are
+ * relative to the manpath root.
+ */
+
+ if (-1 == (chdir(req->q.manpath))) {
+ fprintf(stderr, "chdir %s: %s\n",
+ req->q.manpath, strerror(errno));
+ pg_error_internal();
+ return;
+ }
+
+ search.arch = req->q.arch;
+ search.sec = req->q.sec;
+ search.deftype = req->q.equal ? TYPE_Nm : (TYPE_Nm | TYPE_Nd);
+ search.flags = req->q.equal ? MANSEARCH_MAN : 0;
+
+ paths.sz = 1;
+ paths.paths = mandoc_malloc(sizeof(char *));
+ paths.paths[0] = mandoc_strdup(".");
+
+ /*
+ * Poor man's tokenisation: just break apart by spaces.
+ * Yes, this is half-ass. But it works for now.
+ */
+
+ ep = req->q.query;
+ while (ep && isspace((unsigned char)*ep))
+ ep++;
+
+ sz = 0;
+ cp = NULL;
+ while (ep && '\0' != *ep) {
+ cp = mandoc_reallocarray(cp, sz + 1, sizeof(char *));
+ start = ep;
+ while ('\0' != *ep && ! isspace((unsigned char)*ep))
+ ep++;
+ cp[sz] = mandoc_malloc((ep - start) + 1);
+ memcpy(cp[sz], start, ep - start);
+ cp[sz++][ep - start] = '\0';
+ while (isspace((unsigned char)*ep))
+ ep++;
+ }
+
+ if (0 == mansearch(&search, &paths, sz, cp, "Nd", &res, &ressz))
+ pg_noresult(req, "You entered an invalid query.");
+ else if (0 == ressz)
+ pg_noresult(req, "No results found.");
+ else
+ pg_searchres(req, res, ressz);
+
+ for (i = 0; i < sz; i++)
+ free(cp[i]);
+ free(cp);
+
+ for (i = 0; i < (int)ressz; i++) {
+ free(res[i].file);
+ free(res[i].names);
+ free(res[i].output);
+ }
+ free(res);
+
+ free(paths.paths[0]);
+ free(paths.paths);
+}
+
+int
+main(void)
+{
+ struct req req;
+ const char *path;
+ const char *querystring;
+ int i;
+
+ /* Scan our run-time environment. */
+
+ if (NULL == (scriptname = getenv("SCRIPT_NAME")))
+ scriptname = "";
+
+ if ( ! validate_urifrag(scriptname)) {
+ fprintf(stderr, "unsafe SCRIPT_NAME \"%s\"\n",
+ scriptname);
+ pg_error_internal();
+ return(EXIT_FAILURE);
+ }
+
+ /*
+ * First we change directory into the MAN_DIR so that
+ * subsequent scanning for manpath directories is rooted
+ * relative to the same position.
+ */
+
+ if (-1 == chdir(MAN_DIR)) {
+ fprintf(stderr, "MAN_DIR: %s: %s\n",
+ MAN_DIR, strerror(errno));
+ pg_error_internal();
+ return(EXIT_FAILURE);
+ }
+
+ memset(&req, 0, sizeof(struct req));
+ pathgen(&req);
+
+ /* Next parse out the query string. */
+
+ if (NULL != (querystring = getenv("QUERY_STRING")))
+ http_parse(&req, querystring);
+
+ if ( ! (NULL == req.q.manpath ||
+ validate_manpath(&req, req.q.manpath))) {
+ pg_error_badrequest(
+ "You specified an invalid manpath.");
+ return(EXIT_FAILURE);
+ }
+
+ if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
+ pg_error_badrequest(
+ "You specified an invalid architecture.");
+ return(EXIT_FAILURE);
+ }
+
+ /* 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)
+ pg_search(&req);
+ else
+ pg_index(&req);
+
+ free(req.q.manpath);
+ free(req.q.arch);
+ free(req.q.sec);
+ free(req.q.query);
+ for (i = 0; i < (int)req.psz; i++)
+ free(req.p[i]);
+ free(req.p);
+ return(EXIT_SUCCESS);
+}
+
+/*
+ * Scan for indexable paths.
+ */
+static void
+pathgen(struct req *req)
+{
+ FILE *fp;
+ char *dp;
+ size_t dpsz;
+
+ if (NULL == (fp = fopen("manpath.conf", "r"))) {
+ fprintf(stderr, "%s/manpath.conf: %s\n",
+ MAN_DIR, strerror(errno));
+ pg_error_internal();
+ exit(EXIT_FAILURE);
+ }
+
+ while (NULL != (dp = fgetln(fp, &dpsz))) {
+ if ('\n' == dp[dpsz - 1])
+ dpsz--;
+ req->p = mandoc_realloc(req->p,
+ (req->psz + 1) * sizeof(char *));
+ dp = mandoc_strndup(dp, dpsz);
+ if ( ! validate_urifrag(dp)) {
+ fprintf(stderr, "%s/manpath.conf contains "
+ "unsafe path \"%s\"\n", MAN_DIR, dp);
+ pg_error_internal();
+ exit(EXIT_FAILURE);
+ }
+ if (NULL != strchr(dp, '/')) {
+ fprintf(stderr, "%s/manpath.conf contains "
+ "path with slash \"%s\"\n", MAN_DIR, dp);
+ pg_error_internal();
+ exit(EXIT_FAILURE);
+ }
+ req->p[req->psz++] = dp;
+ }
+
+ if ( req->p == NULL ) {
+ fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR);
+ pg_error_internal();
+ exit(EXIT_FAILURE);
+ }
+}
diff --git a/contrib/mdocml/cgi.h.example b/contrib/mdocml/cgi.h.example
new file mode 100644
index 0000000..f4c7831
--- /dev/null
+++ b/contrib/mdocml/cgi.h.example
@@ -0,0 +1,9 @@
+/* Example compile-time configuration file for man.cgi(8). */
+
+#define HTTP_HOST "mdocml.bsd.lv"
+#define MAN_DIR "/var/www/man"
+#define CSS_DIR ""
+#define CUSTOMIZE_TITLE "Manual pages with mandoc"
+#define CUSTOMIZE_BEGIN "<H2>\nManual pages with " \
+ "<A HREF=\"http://mdocml.bsd.lv/\">mandoc</A>\n</H2>"
+#define COMPAT_OLDURI Yes
diff --git a/contrib/mdocml/chars.c b/contrib/mdocml/chars.c
index 3ad1f57..d758d0c 100644
--- a/contrib/mdocml/chars.c
+++ b/contrib/mdocml/chars.c
@@ -1,4 +1,4 @@
-/* $Id: chars.c,v 1.54 2013/06/20 22:39:30 schwarze Exp $ */
+/* $Id: chars.c,v 1.58 2014/07/23 15:00:08 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -25,6 +25,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#define PRINT_HI 126
@@ -37,7 +38,7 @@ struct ln {
int unicode;
};
-#define LINES_MAX 329
+#define LINES_MAX 330
#define CHAR(in, ch, code) \
{ NULL, (in), (ch), (code) },
@@ -51,9 +52,10 @@ struct mchars {
struct ln **htab;
};
-static const struct ln *find(const struct mchars *,
+static const struct ln *find(const struct mchars *,
const char *, size_t);
+
void
mchars_free(struct mchars *arg)
{
@@ -110,27 +112,38 @@ mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
char
mchars_num2char(const char *p, size_t sz)
{
- int i;
+ int i;
if ((i = mandoc_strntoi(p, sz, 10)) < 0)
return('\0');
- return(i > 0 && i < 256 && isprint(i) ?
- /* LINTED */ i : '\0');
+
+ return(i > 0 && i < 256 && isprint(i) ? i : '\0');
}
int
mchars_num2uc(const char *p, size_t sz)
{
- int i;
+ int i;
if ((i = mandoc_strntoi(p, sz, 16)) < 0)
return('\0');
- /* FIXME: make sure we're not in a bogus range. */
+
+ /*
+ * Security warning:
+ * Never extend the range of accepted characters
+ * to overlap with the ASCII range, 0x00-0x7F
+ * without re-auditing the callers of this function.
+ * Some callers might relay on the fact that we never
+ * return ASCII characters for their escaping decisions.
+ *
+ * XXX Code is missing here to exclude bogus ranges.
+ */
+
return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
}
const char *
-mchars_spec2str(const struct mchars *arg,
+mchars_spec2str(const struct mchars *arg,
const char *p, size_t sz, size_t *rsz)
{
const struct ln *ln;
@@ -159,8 +172,8 @@ find(const struct mchars *tab, const char *p, size_t sz)
hash = (int)p[0] - PRINT_LO;
for (pp = tab->htab[hash]; pp; pp = pp->next)
- if (0 == strncmp(pp->code, p, sz) &&
- '\0' == pp->code[(int)sz])
+ if (0 == strncmp(pp->code, p, sz) &&
+ '\0' == pp->code[(int)sz])
return(pp);
return(NULL);
diff --git a/contrib/mdocml/chars.in b/contrib/mdocml/chars.in
index cc6549e..098504f 100644
--- a/contrib/mdocml/chars.in
+++ b/contrib/mdocml/chars.in
@@ -1,6 +1,7 @@
-/* $Id: chars.in,v 1.43 2013/06/20 22:39:30 schwarze Exp $ */
+/* $Id: chars.in,v 1.46 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +17,7 @@
*/
/*
- * The ASCII translation tables.
+ * The ASCII translation tables.
*
* The left-hand side corresponds to the input sequence (\x, \(xx, \*(xx
* and so on) whose length is listed second element. The right-hand
@@ -27,39 +28,42 @@
* XXX - update LINES_MAX if adding more!
*/
-/* Non-breaking, non-collapsing space uses unit separator. */
+/* Special break control characters. */
static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
+static const char ascii_break[2] = { ASCII_BREAK, '\0' };
CHAR_TBL_START
/* Spacing. */
-CHAR("c", "", 0)
-CHAR("0", " ", 8194)
CHAR(" ", ascii_nbrsp, 160)
CHAR("~", ascii_nbrsp, 160)
-CHAR("%", "", 0)
-CHAR("&", "", 0)
-CHAR("^", "", 0)
+CHAR("0", " ", 8194)
CHAR("|", "", 0)
-CHAR("}", "", 0)
+CHAR("^", "", 0)
+CHAR("&", "", 0)
+CHAR("%", "", 0)
+CHAR(":", ascii_break, 0)
+/* XXX The following three do not really belong into this file. */
CHAR("t", "", 0)
+CHAR("c", "", 0)
+CHAR("}", "", 0)
/* Accents. */
-CHAR("a\"", "\"", 779)
+CHAR("a\"", "\"", 733)
CHAR("a-", "-", 175)
CHAR("a.", ".", 729)
-CHAR("a^", "^", 770)
-CHAR("\'", "\'", 769)
-CHAR("aa", "\'", 769)
-CHAR("ga", "`", 768)
-CHAR("`", "`", 768)
-CHAR("ab", "`", 774)
-CHAR("ac", ",", 807)
-CHAR("ad", "\"", 776)
+CHAR("a^", "^", 94)
+CHAR("\'", "\'", 180)
+CHAR("aa", "\'", 180)
+CHAR("ga", "`", 96)
+CHAR("`", "`", 96)
+CHAR("ab", "`", 728)
+CHAR("ac", ",", 184)
+CHAR("ad", "\"", 168)
CHAR("ah", "v", 711)
CHAR("ao", "o", 730)
-CHAR("a~", "~", 771)
-CHAR("ho", ",", 808)
+CHAR("a~", "~", 126)
+CHAR("ho", ",", 731)
CHAR("ha", "^", 94)
CHAR("ti", "~", 126)
diff --git a/contrib/mdocml/compat_ohash.c b/contrib/mdocml/compat_ohash.c
new file mode 100644
index 0000000..0992b36
--- /dev/null
+++ b/contrib/mdocml/compat_ohash.c
@@ -0,0 +1,339 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_OHASH
+
+int dummy;
+
+#else
+
+/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
+
+/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "compat_ohash.h"
+
+struct _ohash_record {
+ uint32_t hv;
+ const char *p;
+};
+
+#define DELETED ((const char *)h)
+#define NONE (h->size)
+
+/* Don't bother changing the hash table if the change is small enough. */
+#define MINSIZE (1UL << 4)
+#define MINDELETED 4
+
+static void ohash_resize(struct ohash *);
+
+
+/* This handles the common case of variable length keys, where the
+ * key is stored at the end of the record.
+ */
+void *
+ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
+{
+ char *p;
+
+ if (!*end)
+ *end = start + strlen(start);
+ p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
+ if (p) {
+ memcpy(p+i->key_offset, start, *end-start);
+ p[i->key_offset + (*end - start)] = '\0';
+ }
+ return (void *)p;
+}
+
+/* hash_delete only frees the hash structure. Use hash_first/hash_next
+ * to free entries as well. */
+void
+ohash_delete(struct ohash *h)
+{
+ (h->info.free)(h->t, h->info.data);
+#ifndef NDEBUG
+ h->t = NULL;
+#endif
+}
+
+static void
+ohash_resize(struct ohash *h)
+{
+ struct _ohash_record *n;
+ size_t ns;
+ unsigned int j;
+ unsigned int i, incr;
+
+ if (4 * h->deleted < h->total) {
+ if (h->size >= (UINT_MAX >> 1U))
+ ns = UINT_MAX;
+ else
+ ns = h->size << 1U;
+ } else if (3 * h->deleted > 2 * h->total)
+ ns = h->size >> 1U;
+ else
+ ns = h->size;
+ if (ns < MINSIZE)
+ ns = MINSIZE;
+#ifdef STATS_HASH
+ STAT_HASH_EXPAND++;
+ STAT_HASH_SIZE += ns - h->size;
+#endif
+
+ n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
+ if (!n)
+ return;
+
+ for (j = 0; j < h->size; j++) {
+ if (h->t[j].p != NULL && h->t[j].p != DELETED) {
+ i = h->t[j].hv % ns;
+ incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
+ while (n[i].p != NULL) {
+ i += incr;
+ if (i >= ns)
+ i -= ns;
+ }
+ n[i].hv = h->t[j].hv;
+ n[i].p = h->t[j].p;
+ }
+ }
+ (h->info.free)(h->t, h->info.data);
+ h->t = n;
+ h->size = ns;
+ h->total -= h->deleted;
+ h->deleted = 0;
+}
+
+void *
+ohash_remove(struct ohash *h, unsigned int i)
+{
+ void *result = (void *)h->t[i].p;
+
+ if (result == NULL || result == DELETED)
+ return NULL;
+
+#ifdef STATS_HASH
+ STAT_HASH_ENTRIES--;
+#endif
+ h->t[i].p = DELETED;
+ h->deleted++;
+ if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
+ ohash_resize(h);
+ return result;
+}
+
+void *
+ohash_find(struct ohash *h, unsigned int i)
+{
+ if (h->t[i].p == DELETED)
+ return NULL;
+ else
+ return (void *)h->t[i].p;
+}
+
+void *
+ohash_insert(struct ohash *h, unsigned int i, void *p)
+{
+#ifdef STATS_HASH
+ STAT_HASH_ENTRIES++;
+#endif
+ if (h->t[i].p == DELETED) {
+ h->deleted--;
+ h->t[i].p = p;
+ } else {
+ h->t[i].p = p;
+ /* Arbitrary resize boundary. Tweak if not efficient enough. */
+ if (++h->total * 4 > h->size * 3)
+ ohash_resize(h);
+ }
+ return p;
+}
+
+unsigned int
+ohash_entries(struct ohash *h)
+{
+ return h->total - h->deleted;
+}
+
+void *
+ohash_first(struct ohash *h, unsigned int *pos)
+{
+ *pos = 0;
+ return ohash_next(h, pos);
+}
+
+void *
+ohash_next(struct ohash *h, unsigned int *pos)
+{
+ for (; *pos < h->size; (*pos)++)
+ if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
+ return (void *)h->t[(*pos)++].p;
+ return NULL;
+}
+
+void
+ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
+{
+ h->size = 1UL << size;
+ if (h->size < MINSIZE)
+ h->size = MINSIZE;
+#ifdef STATS_HASH
+ STAT_HASH_CREATION++;
+ STAT_HASH_SIZE += h->size;
+#endif
+ /* Copy info so that caller may free it. */
+ h->info.key_offset = info->key_offset;
+ h->info.calloc = info->calloc;
+ h->info.free = info->free;
+ h->info.alloc = info->alloc;
+ h->info.data = info->data;
+ h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
+ h->info.data);
+ h->total = h->deleted = 0;
+}
+
+uint32_t
+ohash_interval(const char *s, const char **e)
+{
+ uint32_t k;
+
+ if (!*e)
+ *e = s + strlen(s);
+ if (s == *e)
+ k = 0;
+ else
+ k = *s++;
+ while (s != *e)
+ k = ((k << 2) | (k >> 30)) ^ *s++;
+ return k;
+}
+
+unsigned int
+ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
+ uint32_t hv)
+{
+ unsigned int i, incr;
+ unsigned int empty;
+
+#ifdef STATS_HASH
+ STAT_HASH_LOOKUP++;
+#endif
+ empty = NONE;
+ i = hv % h->size;
+ incr = ((hv % (h->size-2)) & ~1) + 1;
+ while (h->t[i].p != NULL) {
+#ifdef STATS_HASH
+ STAT_HASH_LENGTH++;
+#endif
+ if (h->t[i].p == DELETED) {
+ if (empty == NONE)
+ empty = i;
+ } else if (h->t[i].hv == hv &&
+ strncmp(h->t[i].p+h->info.key_offset, start,
+ end - start) == 0 &&
+ (h->t[i].p+h->info.key_offset)[end-start] == '\0') {
+ if (empty != NONE) {
+ h->t[empty].hv = hv;
+ h->t[empty].p = h->t[i].p;
+ h->t[i].p = DELETED;
+ return empty;
+ } else {
+#ifdef STATS_HASH
+ STAT_HASH_POSITIVE++;
+#endif
+ return i;
+ }
+ }
+ i += incr;
+ if (i >= h->size)
+ i -= h->size;
+ }
+
+ /* Found an empty position. */
+ if (empty != NONE)
+ i = empty;
+ h->t[i].hv = hv;
+ return i;
+}
+
+unsigned int
+ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
+{
+ unsigned int i, incr;
+ unsigned int empty;
+
+#ifdef STATS_HASH
+ STAT_HASH_LOOKUP++;
+#endif
+ empty = NONE;
+ i = hv % h->size;
+ incr = ((hv % (h->size-2)) & ~1) + 1;
+ while (h->t[i].p != NULL) {
+#ifdef STATS_HASH
+ STAT_HASH_LENGTH++;
+#endif
+ if (h->t[i].p == DELETED) {
+ if (empty == NONE)
+ empty = i;
+ } else if (h->t[i].hv == hv &&
+ memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
+ if (empty != NONE) {
+ h->t[empty].hv = hv;
+ h->t[empty].p = h->t[i].p;
+ h->t[i].p = DELETED;
+ return empty;
+ } else {
+#ifdef STATS_HASH
+ STAT_HASH_POSITIVE++;
+#endif
+ } return i;
+ }
+ i += incr;
+ if (i >= h->size)
+ i -= h->size;
+ }
+
+ /* Found an empty position. */
+ if (empty != NONE)
+ i = empty;
+ h->t[i].hv = hv;
+ return i;
+}
+
+unsigned int
+ohash_qlookup(struct ohash *h, const char *s)
+{
+ const char *e = NULL;
+ return ohash_qlookupi(h, s, &e);
+}
+
+unsigned int
+ohash_qlookupi(struct ohash *h, const char *s, const char **e)
+{
+ uint32_t hv;
+
+ hv = ohash_interval(s, e);
+ return ohash_lookup_interval(h, s, *e, hv);
+}
+
+#endif /*!HAVE_OHASH*/
diff --git a/contrib/mdocml/compat_ohash.h b/contrib/mdocml/compat_ohash.h
new file mode 100644
index 0000000..e3124c9
--- /dev/null
+++ b/contrib/mdocml/compat_ohash.h
@@ -0,0 +1,73 @@
+/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */
+
+/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef OHASH_H
+#define OHASH_H
+
+/* Open hashing support.
+ * Open hashing was chosen because it is much lighter than other hash
+ * techniques, and more efficient in most cases.
+ */
+
+/* user-visible data structure */
+struct ohash_info {
+ ptrdiff_t key_offset;
+ void *data; /* user data */
+ void *(*calloc)(size_t, size_t, void *);
+ void (*free)(void *, void *);
+ void *(*alloc)(size_t, void *);
+};
+
+struct _ohash_record;
+
+/* private structure. It's there just so you can do a sizeof */
+struct ohash {
+ struct _ohash_record *t;
+ struct ohash_info info;
+ unsigned int size;
+ unsigned int total;
+ unsigned int deleted;
+};
+
+/* For this to be tweakable, we use small primitives, and leave part of the
+ * logic to the client application. e.g., hashing is left to the client
+ * application. We also provide a simple table entry lookup that yields
+ * a hashing table index (opaque) to be used in find/insert/remove.
+ * The keys are stored at a known position in the client data.
+ */
+__BEGIN_DECLS
+void ohash_init(struct ohash *, unsigned, struct ohash_info *);
+void ohash_delete(struct ohash *);
+
+unsigned int ohash_lookup_interval(struct ohash *, const char *,
+ const char *, uint32_t);
+unsigned int ohash_lookup_memory(struct ohash *, const char *,
+ size_t, uint32_t);
+void *ohash_find(struct ohash *, unsigned int);
+void *ohash_remove(struct ohash *, unsigned int);
+void *ohash_insert(struct ohash *, unsigned int, void *);
+void *ohash_first(struct ohash *, unsigned int *);
+void *ohash_next(struct ohash *, unsigned int *);
+unsigned int ohash_entries(struct ohash *);
+
+void *ohash_create_entry(struct ohash_info *, const char *, const char **);
+uint32_t ohash_interval(const char *, const char **);
+
+unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
+unsigned int ohash_qlookup(struct ohash *, const char *);
+__END_DECLS
+#endif
diff --git a/contrib/mdocml/compat_reallocarray.c b/contrib/mdocml/compat_reallocarray.c
new file mode 100644
index 0000000..e25d837
--- /dev/null
+++ b/contrib/mdocml/compat_reallocarray.c
@@ -0,0 +1,45 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_REALLOCARRAY
+
+int dummy;
+
+#else
+
+/* $OpenBSD: malloc.c,v 1.158 2014/04/23 15:07:27 tedu Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(optr, size * nmemb);
+}
+
+#endif /*!HAVE_REALLOCARRAY*/
diff --git a/contrib/mdocml/compat_sqlite3_errstr.c b/contrib/mdocml/compat_sqlite3_errstr.c
new file mode 100644
index 0000000..b8d6eb5
--- /dev/null
+++ b/contrib/mdocml/compat_sqlite3_errstr.c
@@ -0,0 +1,18 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SQLITE3_ERRSTR
+
+int dummy;
+
+#else
+
+const char *
+sqlite3_errstr(int rc)
+{
+
+ return(rc ? "unknown error" : "not an error");
+}
+
+#endif
diff --git a/contrib/mdocml/compat_strcasestr.c b/contrib/mdocml/compat_strcasestr.c
new file mode 100644
index 0000000..5216d02
--- /dev/null
+++ b/contrib/mdocml/compat_strcasestr.c
@@ -0,0 +1,74 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRCASESTR
+
+int dummy;
+
+#else
+
+/* ($)NetBSD: strcasestr.c,v 1.2 2005/02/09 21:35:47 kleink Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+
+/*
+ * Find the first occurrence of find in s, ignore case.
+ */
+char *
+strcasestr(const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = tolower((unsigned char)c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower((unsigned char)sc) != c);
+ } while (strncasecmp(s, find, len) != 0);
+ s--;
+ }
+ return __UNCONST(s);
+}
+
+#endif
diff --git a/contrib/mdocml/compat_strsep.c b/contrib/mdocml/compat_strsep.c
new file mode 100644
index 0000000..a5c58c6
--- /dev/null
+++ b/contrib/mdocml/compat_strsep.c
@@ -0,0 +1,80 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRSEP
+
+int dummy;
+
+#else
+
+/* ($)OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+#endif
diff --git a/contrib/mdocml/config.h b/contrib/mdocml/config.h
index 0b070d5..c1d5951 100644
--- a/contrib/mdocml/config.h
+++ b/contrib/mdocml/config.h
@@ -2,20 +2,21 @@
#define MANDOC_CONFIG_H
#if defined(__linux__) || defined(__MINT__)
-# define _GNU_SOURCE /* strptime(), getsubopt() */
+# define _GNU_SOURCE /* getsubopt(), strcasestr(), strptime() */
#endif
+#include <sys/types.h>
#include <stdio.h>
-#define VERSION "1.12.3"
+#define VERSION "1.13.1"
#define HAVE_FGETLN
-#define HAVE_STRPTIME
#define HAVE_GETSUBOPT
-#define HAVE_STRLCAT
#define HAVE_MMAP
+#define HAVE_STRCASESTR
+#define HAVE_STRLCAT
#define HAVE_STRLCPY
-
-#include <sys/types.h>
+#define HAVE_STRPTIME
+#define HAVE_STRSEP
#if !defined(__BEGIN_DECLS)
# ifdef __cplusplus
@@ -32,30 +33,30 @@
# endif
#endif
-#ifndef HAVE_BETOH64
-# if defined(__APPLE__)
-# define betoh64(x) OSSwapBigToHostInt64(x)
-# define htobe64(x) OSSwapHostToBigInt64(x)
-# elif defined(__sun)
-# define betoh64(x) BE_64(x)
-# define htobe64(x) BE_64(x)
-# else
-# define betoh64(x) be64toh(x)
-# endif
+#ifndef HAVE_FGETLN
+extern char *fgetln(FILE *, size_t *);
+#endif
+#ifndef HAVE_GETSUBOPT
+extern int getsubopt(char **, char * const *, char **);
+extern char *suboptarg;
+#endif
+#ifndef HAVE_REALLOCARRAY
+extern void *reallocarray(void *, size_t, size_t);
+#endif
+#ifndef HAVE_SQLITE3_ERRSTR
+extern const char *sqlite3_errstr(int);
+#endif
+#ifndef HAVE_STRCASESTR
+extern char *strcasestr(const char *, const char *);
#endif
-
#ifndef HAVE_STRLCAT
extern size_t strlcat(char *, const char *, size_t);
#endif
#ifndef HAVE_STRLCPY
extern size_t strlcpy(char *, const char *, size_t);
#endif
-#ifndef HAVE_GETSUBOPT
-extern int getsubopt(char **, char * const *, char **);
-extern char *suboptarg;
-#endif
-#ifndef HAVE_FGETLN
-extern char *fgetln(FILE *, size_t *);
+#ifndef HAVE_STRSEP
+extern char *strsep(char **, const char *);
#endif
#endif /* MANDOC_CONFIG_H */
diff --git a/contrib/mdocml/config.h.post b/contrib/mdocml/config.h.post
new file mode 100644
index 0000000..e95f5f5
--- /dev/null
+++ b/contrib/mdocml/config.h.post
@@ -0,0 +1,42 @@
+#if !defined(__BEGIN_DECLS)
+# ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# else
+# define __BEGIN_DECLS
+# endif
+#endif
+#if !defined(__END_DECLS)
+# ifdef __cplusplus
+# define __END_DECLS }
+# else
+# define __END_DECLS
+# endif
+#endif
+
+#ifndef HAVE_FGETLN
+extern char *fgetln(FILE *, size_t *);
+#endif
+#ifndef HAVE_GETSUBOPT
+extern int getsubopt(char **, char * const *, char **);
+extern char *suboptarg;
+#endif
+#ifndef HAVE_REALLOCARRAY
+extern void *reallocarray(void *, size_t, size_t);
+#endif
+#ifndef HAVE_SQLITE3_ERRSTR
+extern const char *sqlite3_errstr(int);
+#endif
+#ifndef HAVE_STRCASESTR
+extern char *strcasestr(const char *, const char *);
+#endif
+#ifndef HAVE_STRLCAT
+extern size_t strlcat(char *, const char *, size_t);
+#endif
+#ifndef HAVE_STRLCPY
+extern size_t strlcpy(char *, const char *, size_t);
+#endif
+#ifndef HAVE_STRSEP
+extern char *strsep(char **, const char *);
+#endif
+
+#endif /* MANDOC_CONFIG_H */
diff --git a/contrib/mdocml/config.h.pre b/contrib/mdocml/config.h.pre
new file mode 100644
index 0000000..1c3940d
--- /dev/null
+++ b/contrib/mdocml/config.h.pre
@@ -0,0 +1,9 @@
+#ifndef MANDOC_CONFIG_H
+#define MANDOC_CONFIG_H
+
+#if defined(__linux__) || defined(__MINT__)
+# define _GNU_SOURCE /* getsubopt(), strcasestr(), strptime() */
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
diff --git a/contrib/mdocml/configure b/contrib/mdocml/configure
new file mode 100755
index 0000000..5b987eb
--- /dev/null
+++ b/contrib/mdocml/configure
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+echo "/* RUNNING ./CONFIGURE - SHOULD BE USED ONLY VIA MAKE, READ INSTALL */"
+
+set -e
+exec > config.h 2> config.log
+
+CFLAGS="${CFLAGS} -Wno-unused -Werror"
+
+runtest() {
+ echo ${CC} ${CFLAGS} ${3} -o test-${1} test-${1}.c 1>&2
+ ${CC} ${CFLAGS} ${3} -o "test-${1}" "test-${1}.c" 1>&2 || return 0
+ "./test-${1}" && echo "#define HAVE_${2}" \
+ || echo FAILURE: test-${1} returned $? 1>&2
+ rm "test-${1}"
+}
+
+cat config.h.pre
+echo
+echo "#define VERSION \"${VERSION}\""
+runtest fgetln FGETLN
+runtest getsubopt GETSUBOPT
+runtest mmap MMAP
+runtest ohash OHASH "${DBLIB}"
+runtest reallocarray REALLOCARRAY
+runtest sqlite3_errstr SQLITE3_ERRSTR "${DBLIB}"
+runtest strcasestr STRCASESTR
+runtest strlcat STRLCAT
+runtest strlcpy STRLCPY
+runtest strptime STRPTIME
+runtest strsep STRSEP
+echo
+cat config.h.post
+
+exit 0
diff --git a/contrib/mdocml/demandoc.c b/contrib/mdocml/demandoc.c
new file mode 100644
index 0000000..4a7b979
--- /dev/null
+++ b/contrib/mdocml/demandoc.c
@@ -0,0 +1,257 @@
+/* $Id: demandoc.c,v 1.10 2014/03/19 22:20:43 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "man.h"
+#include "mdoc.h"
+#include "mandoc.h"
+
+static void pline(int, int *, int *, int);
+static void pman(const struct man_node *, int *, int *, int);
+static void pmandoc(struct mparse *, int, const char *, int);
+static void pmdoc(const struct mdoc_node *, int *, int *, int);
+static void pstring(const char *, int, int *, int);
+static void usage(void);
+
+static const char *progname;
+
+int
+main(int argc, char *argv[])
+{
+ struct mparse *mp;
+ int ch, i, list;
+ extern int optind;
+
+ progname = strrchr(argv[0], '/');
+ if (progname == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ mp = NULL;
+ list = 0;
+
+ while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
+ switch (ch) {
+ case ('i'):
+ /* FALLTHROUGH */
+ case ('k'):
+ /* FALLTHROUGH */
+ case ('m'):
+ /* FALLTHROUGH */
+ case ('p'):
+ break;
+ case ('w'):
+ list = 1;
+ break;
+ default:
+ usage();
+ return((int)MANDOCLEVEL_BADARG);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, NULL);
+ assert(mp);
+
+ if (0 == argc)
+ pmandoc(mp, STDIN_FILENO, "<stdin>", list);
+
+ for (i = 0; i < argc; i++) {
+ mparse_reset(mp);
+ pmandoc(mp, -1, argv[i], list);
+ }
+
+ mparse_free(mp);
+ return((int)MANDOCLEVEL_OK);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
+}
+
+static void
+pmandoc(struct mparse *mp, int fd, const char *fn, int list)
+{
+ struct mdoc *mdoc;
+ struct man *man;
+ int line, col;
+
+ if (mparse_readfd(mp, fd, fn) >= MANDOCLEVEL_FATAL) {
+ fprintf(stderr, "%s: Parse failure\n", fn);
+ return;
+ }
+
+ mparse_result(mp, &mdoc, &man, NULL);
+ line = 1;
+ col = 0;
+
+ if (mdoc)
+ pmdoc(mdoc_node(mdoc), &line, &col, list);
+ else if (man)
+ pman(man_node(man), &line, &col, list);
+ else
+ return;
+
+ if ( ! list)
+ putchar('\n');
+}
+
+/*
+ * Strip the escapes out of a string, emitting the results.
+ */
+static void
+pstring(const char *p, int col, int *colp, int list)
+{
+ enum mandoc_esc esc;
+ const char *start, *end;
+ int emit;
+
+ /*
+ * Print as many column spaces til we achieve parity with the
+ * input document.
+ */
+
+again:
+ if (list && '\0' != *p) {
+ while (isspace((unsigned char)*p))
+ p++;
+
+ while ('\'' == *p || '(' == *p || '"' == *p)
+ p++;
+
+ emit = isalpha((unsigned char)p[0]) &&
+ isalpha((unsigned char)p[1]);
+
+ for (start = p; '\0' != *p; p++)
+ if ('\\' == *p) {
+ p++;
+ esc = mandoc_escape(&p, NULL, NULL);
+ if (ESCAPE_ERROR == esc)
+ return;
+ emit = 0;
+ } else if (isspace((unsigned char)*p))
+ break;
+
+ end = p - 1;
+
+ while (end > start)
+ if ('.' == *end || ',' == *end ||
+ '\'' == *end || '"' == *end ||
+ ')' == *end || '!' == *end ||
+ '?' == *end || ':' == *end ||
+ ';' == *end)
+ end--;
+ else
+ break;
+
+ if (emit && end - start >= 1) {
+ for ( ; start <= end; start++)
+ if (ASCII_HYPH == *start)
+ putchar('-');
+ else
+ putchar((unsigned char)*start);
+ putchar('\n');
+ }
+
+ if (isspace((unsigned char)*p))
+ goto again;
+
+ return;
+ }
+
+ while (*colp < col) {
+ putchar(' ');
+ (*colp)++;
+ }
+
+ /*
+ * Print the input word, skipping any special characters.
+ */
+ while ('\0' != *p)
+ if ('\\' == *p) {
+ p++;
+ esc = mandoc_escape(&p, NULL, NULL);
+ if (ESCAPE_ERROR == esc)
+ break;
+ } else {
+ putchar((unsigned char )*p++);
+ (*colp)++;
+ }
+}
+
+static void
+pline(int line, int *linep, int *col, int list)
+{
+
+ if (list)
+ return;
+
+ /*
+ * Print out as many lines as needed to reach parity with the
+ * original input.
+ */
+
+ while (*linep < line) {
+ putchar('\n');
+ (*linep)++;
+ }
+
+ *col = 0;
+}
+
+static void
+pmdoc(const struct mdoc_node *p, int *line, int *col, int list)
+{
+
+ for ( ; p; p = p->next) {
+ if (MDOC_LINE & p->flags)
+ pline(p->line, line, col, list);
+ if (MDOC_TEXT == p->type)
+ pstring(p->string, p->pos, col, list);
+ if (p->child)
+ pmdoc(p->child, line, col, list);
+ }
+}
+
+static void
+pman(const struct man_node *p, int *line, int *col, int list)
+{
+
+ for ( ; p; p = p->next) {
+ if (MAN_LINE & p->flags)
+ pline(p->line, line, col, list);
+ if (MAN_TEXT == p->type)
+ pstring(p->string, p->pos, col, list);
+ if (p->child)
+ pman(p->child, line, col, list);
+ }
+}
diff --git a/contrib/mdocml/eqn.c b/contrib/mdocml/eqn.c
index 37f01bc..cda0db5 100644
--- a/contrib/mdocml/eqn.c
+++ b/contrib/mdocml/eqn.c
@@ -1,4 +1,4 @@
-/* $Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */
+/* $Id: eqn.c,v 1.44 2014/07/06 19:09:00 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -26,6 +26,7 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
@@ -137,12 +138,11 @@ struct eqnsym {
const char *sym;
};
-
static enum eqn_rest eqn_box(struct eqn_node *, struct eqn_box *);
-static struct eqn_box *eqn_box_alloc(struct eqn_node *,
+static struct eqn_box *eqn_box_alloc(struct eqn_node *,
struct eqn_box *);
static void eqn_box_free(struct eqn_box *);
-static struct eqn_def *eqn_def_find(struct eqn_node *,
+static struct eqn_def *eqn_def_find(struct eqn_node *,
const char *, size_t);
static int eqn_do_gfont(struct eqn_node *);
static int eqn_do_gsize(struct eqn_node *);
@@ -156,7 +156,7 @@ static enum eqn_rest eqn_list(struct eqn_node *, struct eqn_box *);
static enum eqn_rest eqn_matrix(struct eqn_node *, struct eqn_box *);
static const char *eqn_nexttok(struct eqn_node *, size_t *);
static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
-static const char *eqn_next(struct eqn_node *,
+static const char *eqn_next(struct eqn_node *,
char, size_t *, int);
static void eqn_rewind(struct eqn_node *);
@@ -277,9 +277,9 @@ static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
{ { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
};
-/* ARGSUSED */
+
enum rofferr
-eqn_read(struct eqn_node **epp, int ln,
+eqn_read(struct eqn_node **epp, int ln,
const char *p, int pos, int *offs)
{
size_t sz;
@@ -298,9 +298,10 @@ eqn_read(struct eqn_node **epp, int ln,
p += 3;
while (' ' == *p || '\t' == *p)
p++;
- if ('\0' == *p)
+ if ('\0' == *p)
return(er);
- mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL);
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
+ ln, pos, "EN %s", p);
return(er);
}
@@ -413,11 +414,11 @@ eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
while (EQN_OK == (c = eqn_box(ep, bp)))
switch (bp->last->pile) {
- case (EQNPILE_LCOL):
+ case EQNPILE_LCOL:
/* FALLTHROUGH */
- case (EQNPILE_CCOL):
+ case EQNPILE_CCOL:
/* FALLTHROUGH */
- case (EQNPILE_RCOL):
+ case EQNPILE_RCOL:
continue;
default:
EQN_MSG(MANDOCERR_EQNSYNT, ep);
@@ -512,9 +513,8 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
for (i = 0; i < (int)EQN__MAX; i++) {
if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
continue;
- return((*eqnparts[i].fp)(ep) ?
- EQN_OK : EQN_ERR);
- }
+ return((*eqnparts[i].fp)(ep) ? EQN_OK : EQN_ERR);
+ }
if (STRNEQ(start, sz, "{", 1)) {
if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
@@ -529,7 +529,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
return(EQN_OK);
EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
return(EQN_ERR);
- }
+ }
for (i = 0; i < (int)EQNPILE__MAX; i++) {
if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
@@ -575,7 +575,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
if (NULL == last->last) {
EQN_MSG(MANDOCERR_EQNSYNT, ep);
return(EQN_ERR);
- }
+ }
last->last->pos = (enum eqn_post)i;
if (EQN_EOF == (c = eqn_box(ep, last))) {
EQN_MSG(MANDOCERR_EQNEOF, ep);
@@ -590,7 +590,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
if (NULL == last->last) {
EQN_MSG(MANDOCERR_EQNSYNT, ep);
return(EQN_ERR);
- }
+ }
last->last->mark = (enum eqn_markt)i;
if (EQN_EOF == (c = eqn_box(ep, last))) {
EQN_MSG(MANDOCERR_EQNEOF, ep);
@@ -629,7 +629,7 @@ eqn_box(struct eqn_node *ep, struct eqn_box *last)
for (i = 0; i < (int)EQNSYM__MAX; i++)
if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
sym[63] = '\0';
- snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
+ (void)snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
bp->text = mandoc_strdup(sym);
return(EQN_OK);
}
@@ -762,13 +762,13 @@ again:
if (q)
ep->cur++;
while (' ' == ep->data[(int)ep->cur] ||
- '\t' == ep->data[(int)ep->cur] ||
- '^' == ep->data[(int)ep->cur] ||
- '~' == ep->data[(int)ep->cur])
+ '\t' == ep->data[(int)ep->cur] ||
+ '^' == ep->data[(int)ep->cur] ||
+ '~' == ep->data[(int)ep->cur])
ep->cur++;
} else {
if (q)
- EQN_MSG(MANDOCERR_BADQUOTE, ep);
+ EQN_MSG(MANDOCERR_ARG_QUOTE, ep);
next = strchr(start, '\0');
*sz = (size_t)(next - start);
ep->cur += *sz;
@@ -790,8 +790,8 @@ again:
}
diff = def->valsz - *sz;
- memmove(start + *sz + diff, start + *sz,
- (strlen(start) - *sz) + 1);
+ memmove(start + *sz + diff, start + *sz,
+ (strlen(start) - *sz) + 1);
memcpy(start, def->val, def->valsz);
goto again;
}
@@ -852,8 +852,8 @@ eqn_do_define(struct eqn_node *ep)
return(0);
}
- /*
- * Search for a key that already exists.
+ /*
+ * Search for a key that already exists.
* Create a new key if none is found.
*/
@@ -865,15 +865,14 @@ eqn_do_define(struct eqn_node *ep)
if (i == (int)ep->defsz) {
ep->defsz++;
- ep->defs = mandoc_realloc
- (ep->defs, ep->defsz *
- sizeof(struct eqn_def));
+ ep->defs = mandoc_reallocarray(ep->defs,
+ ep->defsz, sizeof(struct eqn_def));
ep->defs[i].key = ep->defs[i].val = NULL;
}
ep->defs[i].keysz = sz;
- ep->defs[i].key = mandoc_realloc
- (ep->defs[i].key, sz + 1);
+ ep->defs[i].key = mandoc_realloc(
+ ep->defs[i].key, sz + 1);
memcpy(ep->defs[i].key, start, sz);
ep->defs[i].key[(int)sz] = '\0';
@@ -901,7 +900,7 @@ eqn_do_gfont(struct eqn_node *ep)
if (NULL == eqn_nextrawtok(ep, NULL)) {
EQN_MSG(MANDOCERR_EQNEOF, ep);
return(0);
- }
+ }
return(1);
}
@@ -914,7 +913,7 @@ eqn_do_gsize(struct eqn_node *ep)
if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
EQN_MSG(MANDOCERR_EQNEOF, ep);
return(0);
- }
+ }
ep->gsize = mandoc_strntoi(start, sz, 10);
return(1);
}
@@ -940,9 +939,9 @@ eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
{
int i;
- for (i = 0; i < (int)ep->defsz; i++)
- if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
- ep->defs[i].keysz, key, sz))
+ for (i = 0; i < (int)ep->defsz; i++)
+ if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
+ ep->defs[i].keysz, key, sz))
return(&ep->defs[i]);
return(NULL);
diff --git a/contrib/mdocml/eqn_html.c b/contrib/mdocml/eqn_html.c
index 80c82f1..3e58ab5 100644
--- a/contrib/mdocml/eqn_html.c
+++ b/contrib/mdocml/eqn_html.c
@@ -1,4 +1,4 @@
-/* $Id: eqn_html.c,v 1.2 2011/07/24 10:09:03 kristaps Exp $ */
+/* $Id: eqn_html.c,v 1.3 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -35,9 +35,9 @@ static const enum htmltag fontmap[EQNFONT__MAX] = {
TAG_I /* EQNFONT_ITALIC */
};
-
static void eqn_box(struct html *, const struct eqn_box *);
+
void
print_eqn(struct html *p, const struct eqn *ep)
{
@@ -59,12 +59,12 @@ eqn_box(struct html *p, const struct eqn_box *bp)
{
struct tag *t;
- t = EQNFONT_NONE == bp->font ? NULL :
- print_otag(p, fontmap[(int)bp->font], 0, NULL);
+ t = EQNFONT_NONE == bp->font ? NULL :
+ print_otag(p, fontmap[(int)bp->font], 0, NULL);
if (bp->left)
print_text(p, bp->left);
-
+
if (bp->text)
print_text(p, bp->text);
diff --git a/contrib/mdocml/eqn_term.c b/contrib/mdocml/eqn_term.c
index cfbd8d4..889c5c6 100644
--- a/contrib/mdocml/eqn_term.c
+++ b/contrib/mdocml/eqn_term.c
@@ -1,4 +1,4 @@
-/* $Id: eqn_term.c,v 1.4 2011/07/24 10:09:03 kristaps Exp $ */
+/* $Id: eqn_term.c,v 1.5 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -37,6 +37,7 @@ static const enum termfont fontmap[EQNFONT__MAX] = {
static void eqn_box(struct termp *, const struct eqn_box *);
+
void
term_eqn(struct termp *p, const struct eqn *ep)
{
@@ -68,7 +69,7 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
term_word(p, ")");
if (bp->right)
term_word(p, bp->right);
- if (EQNFONT_NONE != bp->font)
+ if (EQNFONT_NONE != bp->font)
term_fontpop(p);
if (bp->next)
diff --git a/contrib/mdocml/external.png b/contrib/mdocml/external.png
deleted file mode 100644
index 419c06f..0000000
--- a/contrib/mdocml/external.png
+++ /dev/null
Binary files differ
diff --git a/contrib/mdocml/gmdiff b/contrib/mdocml/gmdiff
new file mode 100644
index 0000000..2c7ba4b
--- /dev/null
+++ b/contrib/mdocml/gmdiff
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# 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.
+
+if [ `id -u` -eq 0 ]; then
+ echo "$0: do not run me as root"
+ exit 1
+fi
+
+if [ $# -eq 0 ]; then
+ echo "usage: $0 manual_source_file ..."
+ exit 1
+fi
+
+while [ -n "$1" ]; do
+ file=$1
+ shift
+ echo " ========== $file ========== "
+ tbl $file | groff -mandoc -Tascii -P -c 2> /tmp/groff.err > /tmp/groff.out
+ mandoc -Ios='OpenBSD ports' -Werror $file 2> /tmp/mandoc.err > /tmp/mandoc.out
+ for i in groff mandoc; do
+ [[ -s /tmp/$i.err ]] && echo "$i errors:" && cat /tmp/$i.err
+ done
+ diff -au /tmp/groff.out /tmp/mandoc.out 2>&1
+done
+
+exit 0
diff --git a/contrib/mdocml/html.c b/contrib/mdocml/html.c
index 9d28b42..d4783ee 100644
--- a/contrib/mdocml/html.c
+++ b/contrib/mdocml/html.c
@@ -1,7 +1,7 @@
-/* $Id: html.c,v 1.152 2013/08/08 20:07:47 schwarze Exp $ */
+/* $Id: html.c,v 1.159 2014/07/23 15:00:08 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -31,6 +31,7 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "out.h"
#include "html.h"
@@ -109,11 +110,13 @@ static const char *const roffscales[SCALE_MAX] = {
static void bufncat(struct html *, const char *, size_t);
static void print_ctag(struct html *, enum htmltag);
+static int print_escape(char);
static int print_encode(struct html *, const char *, int);
static void print_metaf(struct html *, enum mandoc_esc);
static void print_attr(struct html *, const char *, const char *);
static void *ml_alloc(char *, enum htmltype);
+
static void *
ml_alloc(char *outopts, enum htmltype type)
{
@@ -135,16 +138,16 @@ ml_alloc(char *outopts, enum htmltype type)
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
- case (0):
+ case 0:
h->style = v;
break;
- case (1):
+ case 1:
h->base_man = v;
break;
- case (2):
+ case 2:
h->base_includes = v;
break;
- case (3):
+ case 3:
h->oflags |= HTML_FRAGMENT;
break;
default:
@@ -161,7 +164,6 @@ html_alloc(char *outopts)
return(ml_alloc(outopts, HTML_HTML_4_01_STRICT));
}
-
void *
xhtml_alloc(char *outopts)
{
@@ -169,7 +171,6 @@ xhtml_alloc(char *outopts)
return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT));
}
-
void
html_free(void *p)
{
@@ -179,17 +180,16 @@ html_free(void *p)
h = (struct html *)p;
while ((tag = h->tags.head) != NULL) {
- h->tags.head = tag->next;
+ h->tags.head = tag->next;
free(tag);
}
-
+
if (h->symtab)
mchars_free(h->symtab);
free(h);
}
-
void
print_gen_head(struct html *h)
{
@@ -226,21 +226,21 @@ print_metaf(struct html *h, enum mandoc_esc deco)
enum htmlfont font;
switch (deco) {
- case (ESCAPE_FONTPREV):
+ case ESCAPE_FONTPREV:
font = h->metal;
break;
- case (ESCAPE_FONTITALIC):
+ case ESCAPE_FONTITALIC:
font = HTMLFONT_ITALIC;
break;
- case (ESCAPE_FONTBOLD):
+ case ESCAPE_FONTBOLD:
font = HTMLFONT_BOLD;
break;
- case (ESCAPE_FONTBI):
+ case ESCAPE_FONTBI:
font = HTMLFONT_BI;
break;
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
/* FALLTHROUGH */
- case (ESCAPE_FONTROMAN):
+ case ESCAPE_FONTROMAN:
font = HTMLFONT_NONE;
break;
default:
@@ -257,13 +257,13 @@ print_metaf(struct html *h, enum mandoc_esc deco)
h->metac = font;
switch (font) {
- case (HTMLFONT_ITALIC):
+ case HTMLFONT_ITALIC:
h->metaf = print_otag(h, TAG_I, 0, NULL);
break;
- case (HTMLFONT_BOLD):
+ case HTMLFONT_BOLD:
h->metaf = print_otag(h, TAG_B, 0, NULL);
break;
- case (HTMLFONT_BI):
+ case HTMLFONT_BI:
h->metaf = print_otag(h, TAG_B, 0, NULL);
print_otag(h, TAG_I, 0, NULL);
break;
@@ -302,19 +302,19 @@ html_strlen(const char *cp)
break;
cp++;
switch (mandoc_escape(&cp, NULL, NULL)) {
- case (ESCAPE_ERROR):
+ case ESCAPE_ERROR:
return(sz);
- case (ESCAPE_UNICODE):
+ case ESCAPE_UNICODE:
/* FALLTHROUGH */
- case (ESCAPE_NUMBERED):
+ case ESCAPE_NUMBERED:
/* FALLTHROUGH */
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
if (skip)
skip = 0;
else
sz++;
break;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SKIPCHAR:
skip = 1;
break;
default:
@@ -325,13 +325,45 @@ html_strlen(const char *cp)
}
static int
+print_escape(char c)
+{
+
+ switch (c) {
+ case '<':
+ printf("&lt;");
+ break;
+ case '>':
+ printf("&gt;");
+ break;
+ case '&':
+ printf("&amp;");
+ break;
+ case '"':
+ printf("&quot;");
+ break;
+ case ASCII_NBRSP:
+ putchar('-');
+ break;
+ case ASCII_HYPH:
+ putchar('-');
+ /* FALLTHROUGH */
+ case ASCII_BREAK:
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+static int
print_encode(struct html *h, const char *p, int norecurse)
{
size_t sz;
int c, len, nospace;
const char *seq;
enum mandoc_esc esc;
- static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
+ static const char rejs[9] = { '\\', '<', '>', '&', '"',
+ ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
nospace = 0;
@@ -350,43 +382,29 @@ print_encode(struct html *h, const char *p, int norecurse)
if ('\0' == *p)
break;
- switch (*p++) {
- case ('<'):
- printf("&lt;");
+ if (print_escape(*p++))
continue;
- case ('>'):
- printf("&gt;");
- continue;
- case ('&'):
- printf("&amp;");
- continue;
- case (ASCII_HYPH):
- putchar('-');
- continue;
- default:
- break;
- }
esc = mandoc_escape(&p, &seq, &len);
if (ESCAPE_ERROR == esc)
break;
switch (esc) {
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
/* FALLTHROUGH */
- case (ESCAPE_FONTPREV):
+ case ESCAPE_FONTPREV:
/* FALLTHROUGH */
- case (ESCAPE_FONTBOLD):
+ case ESCAPE_FONTBOLD:
/* FALLTHROUGH */
- case (ESCAPE_FONTITALIC):
+ case ESCAPE_FONTITALIC:
/* FALLTHROUGH */
- case (ESCAPE_FONTBI):
+ case ESCAPE_FONTBI:
/* FALLTHROUGH */
- case (ESCAPE_FONTROMAN):
+ case ESCAPE_FONTROMAN:
if (0 == norecurse)
print_metaf(h, esc);
continue;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SKIPCHAR:
h->flags |= HTML_SKIPCHAR;
continue;
default:
@@ -399,25 +417,26 @@ print_encode(struct html *h, const char *p, int norecurse)
}
switch (esc) {
- case (ESCAPE_UNICODE):
- /* Skip passed "u" header. */
+ case ESCAPE_UNICODE:
+ /* Skip past "u" header. */
c = mchars_num2uc(seq + 1, len - 1);
if ('\0' != c)
printf("&#x%x;", c);
break;
- case (ESCAPE_NUMBERED):
+ case ESCAPE_NUMBERED:
c = mchars_num2char(seq, len);
- if ('\0' != c)
+ if ( ! ('\0' == c || print_escape(c)))
putchar(c);
break;
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
c = mchars_spec2cp(h->symtab, seq, len);
if (c > 0)
printf("&#%d;", c);
- else if (-1 == c && 1 == len)
+ else if (-1 == c && 1 == len &&
+ !print_escape(*seq))
putchar((int)*seq);
break;
- case (ESCAPE_NOSPACE):
+ case ESCAPE_NOSPACE:
if ('\0' == *p)
nospace = 1;
break;
@@ -429,7 +448,6 @@ print_encode(struct html *h, const char *p, int norecurse)
return(nospace);
}
-
static void
print_attr(struct html *h, const char *key, const char *val)
{
@@ -438,9 +456,8 @@ print_attr(struct html *h, const char *key, const char *val)
putchar('\"');
}
-
struct tag *
-print_otag(struct html *h, enum htmltag tag,
+print_otag(struct html *h, enum htmltag tag,
int sz, const struct htmlpair *p)
{
int i;
@@ -490,7 +507,7 @@ print_otag(struct html *h, enum htmltag tag,
if (HTML_AUTOCLOSE & htmltags[tag].flags)
switch (h->type) {
- case (HTML_XHTML_1_0_STRICT):
+ case HTML_XHTML_1_0_STRICT:
putchar('/');
break;
default:
@@ -507,16 +524,15 @@ print_otag(struct html *h, enum htmltag tag,
return(t);
}
-
static void
print_ctag(struct html *h, enum htmltag tag)
{
-
+
printf("</%s>", htmltags[tag].name);
if (HTML_CLRLINE & htmltags[tag].flags) {
h->flags |= HTML_NOSPACE;
putchar('\n');
- }
+ }
}
void
@@ -527,7 +543,7 @@ print_gen_decls(struct html *h)
const char *name;
switch (h->type) {
- case (HTML_HTML_4_01_STRICT):
+ case HTML_HTML_4_01_STRICT:
name = "HTML";
doctype = "-//W3C//DTD HTML 4.01//EN";
dtd = "http://www.w3.org/TR/html4/strict.dtd";
@@ -540,8 +556,8 @@ print_gen_decls(struct html *h)
break;
}
- printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
- name, doctype, dtd);
+ printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
+ name, doctype, dtd);
}
void
@@ -560,13 +576,13 @@ print_text(struct html *h, const char *word)
assert(NULL == h->metaf);
switch (h->metac) {
- case (HTMLFONT_ITALIC):
+ case HTMLFONT_ITALIC:
h->metaf = print_otag(h, TAG_I, 0, NULL);
break;
- case (HTMLFONT_BOLD):
+ case HTMLFONT_BOLD:
h->metaf = print_otag(h, TAG_B, 0, NULL);
break;
- case (HTMLFONT_BI):
+ case HTMLFONT_BI:
h->metaf = print_otag(h, TAG_B, 0, NULL);
print_otag(h, TAG_I, 0, NULL);
break;
@@ -589,14 +605,13 @@ print_text(struct html *h, const char *word)
h->flags &= ~HTML_IGNDELIM;
}
-
void
print_tagq(struct html *h, const struct tag *until)
{
struct tag *tag;
while ((tag = h->tags.head) != NULL) {
- /*
+ /*
* Remember to close out and nullify the current
* meta-font and table, if applicable.
*/
@@ -612,7 +627,6 @@ print_tagq(struct html *h, const struct tag *until)
}
}
-
void
print_stagq(struct html *h, const struct tag *suntil)
{
@@ -621,7 +635,7 @@ print_stagq(struct html *h, const struct tag *suntil)
while ((tag = h->tags.head) != NULL) {
if (suntil && tag == suntil)
return;
- /*
+ /*
* Remember to close out and nullify the current
* meta-font and table, if applicable.
*/
@@ -657,6 +671,12 @@ void
bufcat(struct html *h, const char *p)
{
+ /*
+ * XXX This is broken and not easy to fix.
+ * When using the -Oincludes option, buffmt_includes()
+ * may pass in strings overrunning BUFSIZ, causing a crash.
+ */
+
h->buflen = strlcat(h->buf, p, BUFSIZ);
assert(h->buflen < BUFSIZ);
}
@@ -667,8 +687,8 @@ bufcat_fmt(struct html *h, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- (void)vsnprintf(h->buf + (int)h->buflen,
- BUFSIZ - h->buflen - 1, fmt, ap);
+ (void)vsnprintf(h->buf + (int)h->buflen,
+ BUFSIZ - h->buflen - 1, fmt, ap);
va_end(ap);
h->buflen = strlen(h->buf);
}
@@ -688,12 +708,12 @@ buffmt_includes(struct html *h, const char *name)
const char *p, *pp;
pp = h->base_includes;
-
+
bufinit(h);
while (NULL != (p = strchr(pp, '%'))) {
bufncat(h, pp, (size_t)(p - pp));
switch (*(p + 1)) {
- case('I'):
+ case'I':
bufcat(h, name);
break;
default:
@@ -707,22 +727,21 @@ buffmt_includes(struct html *h, const char *name)
}
void
-buffmt_man(struct html *h,
- const char *name, const char *sec)
+buffmt_man(struct html *h, const char *name, const char *sec)
{
const char *p, *pp;
pp = h->base_man;
-
+
bufinit(h);
while (NULL != (p = strchr(pp, '%'))) {
bufncat(h, pp, (size_t)(p - pp));
switch (*(p + 1)) {
- case('S'):
+ case 'S':
bufcat(h, sec ? sec : "1");
break;
- case('N'):
- bufcat_fmt(h, name);
+ case 'N':
+ bufcat_fmt(h, "%s", name);
break;
default:
bufncat(h, p, 2);
diff --git a/contrib/mdocml/html.h b/contrib/mdocml/html.h
index 894cfc4..ca15f0f 100644
--- a/contrib/mdocml/html.h
+++ b/contrib/mdocml/html.h
@@ -1,4 +1,4 @@
-/* $Id: html.h,v 1.49 2013/08/08 20:07:47 schwarze Exp $ */
+/* $Id: html.h,v 1.51 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -105,7 +105,7 @@ struct htmlpair {
#define PAIR_STYLE_INIT(p, h) PAIR_INIT(p, ATTR_STYLE, (h)->buf)
#define PAIR_SUMMARY_INIT(p, v) PAIR_INIT(p, ATTR_SUMMARY, v)
-enum htmltype {
+enum htmltype {
HTML_HTML_4_01_STRICT,
HTML_XHTML_1_0_STRICT
};
@@ -127,7 +127,7 @@ struct html {
char *base_includes; /* base for include href */
char *style; /* style-sheet URI */
char buf[BUFSIZ]; /* see bufcat and friends */
- size_t buflen;
+ size_t buflen;
struct tag *metaf; /* current open font scope */
enum htmlfont metal; /* last used font */
enum htmlfont metac; /* current font mode */
@@ -138,7 +138,7 @@ struct html {
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
-struct tag *print_otag(struct html *, enum htmltag,
+struct tag *print_otag(struct html *, enum htmltag,
int, const struct htmlpair *);
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
@@ -147,15 +147,18 @@ void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
void print_eqn(struct html *, const struct eqn *);
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 2, 3)))
+#endif
void bufcat_fmt(struct html *, const char *, ...);
void bufcat(struct html *, const char *);
void bufcat_id(struct html *, const char *);
-void bufcat_style(struct html *,
+void bufcat_style(struct html *,
const char *, const char *);
-void bufcat_su(struct html *, const char *,
+void bufcat_su(struct html *, const char *,
const struct roffsu *);
void bufinit(struct html *);
-void buffmt_man(struct html *,
+void buffmt_man(struct html *,
const char *, const char *);
void buffmt_includes(struct html *, const char *);
diff --git a/contrib/mdocml/lib.c b/contrib/mdocml/lib.c
index 7a18a5d..8cc8a77 100644
--- a/contrib/mdocml/lib.c
+++ b/contrib/mdocml/lib.c
@@ -1,4 +1,4 @@
-/* $Id: lib.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: lib.c,v 1.10 2014/03/23 11:25:26 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,12 +18,9 @@
#include "config.h"
#endif
-#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
diff --git a/contrib/mdocml/lib.in b/contrib/mdocml/lib.in
index 81cb560..a785c72 100644
--- a/contrib/mdocml/lib.in
+++ b/contrib/mdocml/lib.in
@@ -1,6 +1,7 @@
-/* $Id: lib.in,v 1.17 2013/10/13 15:24:03 schwarze Exp $ */
+/* $Id: lib.in,v 1.18 2014/01/06 00:53:33 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2009, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/contrib/mdocml/libman.h b/contrib/mdocml/libman.h
index f2ba6a1..e852927 100644
--- a/contrib/mdocml/libman.h
+++ b/contrib/mdocml/libman.h
@@ -1,4 +1,4 @@
-/* $Id: libman.h,v 1.56 2012/11/17 00:26:33 schwarze Exp $ */
+/* $Id: libman.h,v 1.63 2014/08/01 21:24:17 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -24,13 +24,11 @@ enum man_next {
struct man {
struct mparse *parse; /* parse pointer */
+ int quick; /* abort parse early */
int flags; /* parse flags */
-#define MAN_HALT (1 << 0) /* badness happened: die */
#define MAN_ELINE (1 << 1) /* Next-line element scope. */
#define MAN_BLINE (1 << 2) /* Next-line block scope. */
-#define MAN_ILINE (1 << 3) /* Ignored in next-line scope. */
#define MAN_LITERAL (1 << 4) /* Literal input. */
-#define MAN_BPLINE (1 << 5)
#define MAN_NEWLINE (1 << 6) /* first macro/text in a line */
enum man_next next; /* where to put the next node */
struct man_node *last; /* the last parsed node */
@@ -61,10 +59,6 @@ extern const struct man_macro *const man_macros;
__BEGIN_DECLS
-#define man_pmsg(man, l, p, t) \
- mandoc_msg((t), (man)->parse, (l), (p), NULL)
-#define man_nmsg(man, n, t) \
- mandoc_msg((t), (man)->parse, (n)->line, (n)->pos, NULL)
int man_word_alloc(struct man *, int, int, const char *);
int man_block_alloc(struct man *, int, int, enum mant);
int man_head_alloc(struct man *, int, int, enum mant);
@@ -76,9 +70,7 @@ void man_hash_init(void);
enum mant man_hash_find(const char *);
int man_macroend(struct man *);
int man_valid_post(struct man *);
-int man_valid_pre(struct man *, struct man_node *);
-int man_unscope(struct man *,
- const struct man_node *, enum mandocerr);
+int man_unscope(struct man *, const struct man_node *);
__END_DECLS
diff --git a/contrib/mdocml/libmandoc.h b/contrib/mdocml/libmandoc.h
index 3c005e1..1011cc50 100644
--- a/contrib/mdocml/libmandoc.h
+++ b/contrib/mdocml/libmandoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmandoc.h,v 1.35 2013/12/15 21:23:52 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.42 2014/07/09 11:31:43 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -36,46 +36,50 @@ struct roff;
struct mdoc;
struct man;
-void mandoc_msg(enum mandocerr, struct mparse *,
+void mandoc_msg(enum mandocerr, struct mparse *,
int, int, const char *);
-void mandoc_vmsg(enum mandocerr, struct mparse *,
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 5, 6)))
+#endif
+void mandoc_vmsg(enum mandocerr, struct mparse *,
int, int, const char *, ...);
char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct mparse *, char *, int, int);
-int mandoc_eos(const char *, size_t, int);
+int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*);
-void mdoc_free(struct mdoc *);
-struct mdoc *mdoc_alloc(struct roff *, struct mparse *, char *);
+void mdoc_free(struct mdoc *);
+struct mdoc *mdoc_alloc(struct roff *, struct mparse *,
+ const char *, int);
void mdoc_reset(struct mdoc *);
-int mdoc_parseln(struct mdoc *, int, char *, int);
+int mdoc_parseln(struct mdoc *, int, char *, int);
int mdoc_endparse(struct mdoc *);
int mdoc_addspan(struct mdoc *, const struct tbl_span *);
int mdoc_addeqn(struct mdoc *, const struct eqn *);
-void man_free(struct man *);
-struct man *man_alloc(struct roff *, struct mparse *);
+void man_free(struct man *);
+struct man *man_alloc(struct roff *, struct mparse *, int);
void man_reset(struct man *);
-int man_parseln(struct man *, int, char *, int);
+int man_parseln(struct man *, int, char *, int);
int man_endparse(struct man *);
int man_addspan(struct man *, const struct tbl_span *);
int man_addeqn(struct man *, const struct eqn *);
-void roff_free(struct roff *);
-struct roff *roff_alloc(enum mparset, struct mparse *);
+void roff_free(struct roff *);
+struct roff *roff_alloc(struct mparse *, int);
void roff_reset(struct roff *);
-enum rofferr roff_parseln(struct roff *, int,
+enum rofferr roff_parseln(struct roff *, int,
char **, size_t *, int, int *);
void roff_endparse(struct roff *);
void roff_setreg(struct roff *, const char *, int, char sign);
int roff_getreg(const struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
-int roff_getcontrol(const struct roff *,
+int roff_getcontrol(const struct roff *,
const char *, int *);
#if 0
char roff_eqndelim(const struct roff *);
-void roff_openeqn(struct roff *, const char *,
+void roff_openeqn(struct roff *, const char *,
int, int, const char *);
int roff_closeeqn(struct roff *);
#endif
diff --git a/contrib/mdocml/libmdoc.h b/contrib/mdocml/libmdoc.h
index 3f14519..1507a8c 100644
--- a/contrib/mdocml/libmdoc.h
+++ b/contrib/mdocml/libmdoc.h
@@ -1,4 +1,4 @@
-/* $Id: libmdoc.h,v 1.82 2013/10/21 23:47:58 schwarze Exp $ */
+/* $Id: libmdoc.h,v 1.88 2014/08/01 17:40:34 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -25,9 +25,9 @@ enum mdoc_next {
struct mdoc {
struct mparse *parse; /* parse pointer */
- char *defos; /* default argument for .Os */
+ const char *defos; /* default argument for .Os */
+ int quick; /* abort parse early */
int flags; /* parse flags */
-#define MDOC_HALT (1 << 0) /* error in parse: halt */
#define MDOC_LITERAL (1 << 1) /* in a literal scope */
#define MDOC_PBODY (1 << 2) /* in the document body */
#define MDOC_NEWLINE (1 << 3) /* first macro/text in a line */
@@ -40,6 +40,7 @@ struct mdoc {
enum mdoc_next next; /* where to put the next node */
struct mdoc_node *last; /* the last node parsed */
struct mdoc_node *first; /* the first node parsed */
+ struct mdoc_node *last_es; /* the most recent Es node */
struct mdoc_meta meta; /* document meta-data */
enum mdoc_sec lastnamed;
enum mdoc_sec lastsec;
@@ -103,17 +104,13 @@ extern const struct mdoc_macro *const mdoc_macros;
__BEGIN_DECLS
-#define mdoc_pmsg(mdoc, l, p, t) \
- mandoc_msg((t), (mdoc)->parse, (l), (p), NULL)
-#define mdoc_nmsg(mdoc, n, t) \
- mandoc_msg((t), (mdoc)->parse, (n)->line, (n)->pos, NULL)
int mdoc_macro(MACRO_PROT_ARGS);
-int mdoc_word_alloc(struct mdoc *,
+int mdoc_word_alloc(struct mdoc *,
int, int, const char *);
void mdoc_word_append(struct mdoc *, const char *);
-int mdoc_elem_alloc(struct mdoc *, int, int,
+int mdoc_elem_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
-int mdoc_block_alloc(struct mdoc *, int, int,
+int mdoc_block_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
int mdoc_head_alloc(struct mdoc *, int, int, enum mdoct);
int mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct);
@@ -136,7 +133,7 @@ enum margverr mdoc_argv(struct mdoc *, int, enum mdoct,
void mdoc_argv_free(struct mdoc_arg *);
enum margserr mdoc_args(struct mdoc *, int,
int *, char *, enum mdoct, char **);
-enum margserr mdoc_zargs(struct mdoc *, int,
+enum margserr mdoc_zargs(struct mdoc *, int,
int *, char *, char **);
int mdoc_macroend(struct mdoc *);
enum mdelim mdoc_isdelim(const char *);
diff --git a/contrib/mdocml/libroff.h b/contrib/mdocml/libroff.h
index 5b84c5f..f917b14 100644
--- a/contrib/mdocml/libroff.h
+++ b/contrib/mdocml/libroff.h
@@ -1,4 +1,4 @@
-/* $Id: libroff.h,v 1.28 2013/05/31 21:37:17 schwarze Exp $ */
+/* $Id: libroff.h,v 1.29 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -66,7 +66,7 @@ struct tbl_node *tbl_alloc(int, int, struct mparse *);
void tbl_restart(int, int, struct tbl_node *);
void tbl_free(struct tbl_node *);
void tbl_reset(struct tbl_node *);
-enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
+enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
int tbl_option(struct tbl_node *, int, const char *);
int tbl_layout(struct tbl_node *, int, const char *);
int tbl_data(struct tbl_node *, int, const char *);
@@ -76,7 +76,7 @@ void tbl_end(struct tbl_node **);
struct eqn_node *eqn_alloc(const char *, int, int, struct mparse *);
enum rofferr eqn_end(struct eqn_node **);
void eqn_free(struct eqn_node *);
-enum rofferr eqn_read(struct eqn_node **, int,
+enum rofferr eqn_read(struct eqn_node **, int,
const char *, int, int *);
__END_DECLS
diff --git a/contrib/mdocml/main.c b/contrib/mdocml/main.c
index 7e5c7a9..d97c8e2 100644
--- a/contrib/mdocml/main.c
+++ b/contrib/mdocml/main.c
@@ -1,7 +1,8 @@
-/* $Id: main.c,v 1.167 2012/11/19 17:22:26 schwarze Exp $ */
+/* $Id: main.c,v 1.177 2014/06/21 22:24:01 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,6 +28,7 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "main.h"
#include "mdoc.h"
#include "man.h"
@@ -58,18 +60,18 @@ struct curparse {
struct mparse *mp;
enum mandoclevel wlevel; /* ignore messages below this */
int wstop; /* stop after a file with a warning */
- enum outt outtype; /* which output to use */
+ enum outt outtype; /* which output to use */
out_mdoc outmdoc; /* mdoc output ptr */
- out_man outman; /* man output ptr */
+ out_man outman; /* man output ptr */
out_free outfree; /* free output ptr */
void *outdata; /* data for output */
char outopts[BUFSIZ]; /* buf of output opts */
};
-static int moptions(enum mparset *, char *);
+static int moptions(int *, char *);
static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
-static void parse(struct curparse *, int,
+static void parse(struct curparse *, int,
const char *, enum mandoclevel *);
static int toptions(struct curparse *, char *);
static void usage(void) __attribute__((noreturn));
@@ -78,12 +80,13 @@ static int woptions(struct curparse *, char *);
static const char *progname;
+
int
main(int argc, char *argv[])
{
int c;
struct curparse curp;
- enum mparset type;
+ int options;
enum mandoclevel rc;
char *defos;
@@ -95,44 +98,45 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
- type = MPARSE_AUTO;
+ options = MPARSE_SO;
curp.outtype = OUTT_ASCII;
curp.wlevel = MANDOCLEVEL_FATAL;
defos = NULL;
- /* LINTED */
while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
switch (c) {
- case ('I'):
+ case 'I':
if (strncmp(optarg, "os=", 3)) {
- fprintf(stderr, "-I%s: Bad argument\n",
- optarg);
+ fprintf(stderr,
+ "%s: -I%s: Bad argument\n",
+ progname, optarg);
return((int)MANDOCLEVEL_BADARG);
}
if (defos) {
- fprintf(stderr, "-I%s: Duplicate argument\n",
- optarg);
+ fprintf(stderr,
+ "%s: -I%s: Duplicate argument\n",
+ progname, optarg);
return((int)MANDOCLEVEL_BADARG);
}
defos = mandoc_strdup(optarg + 3);
break;
- case ('m'):
- if ( ! moptions(&type, optarg))
+ case 'm':
+ if ( ! moptions(&options, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('O'):
+ case 'O':
(void)strlcat(curp.outopts, optarg, BUFSIZ);
(void)strlcat(curp.outopts, ",", BUFSIZ);
break;
- case ('T'):
+ case 'T':
if ( ! toptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('W'):
+ case 'W':
if ( ! woptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('V'):
+ case 'V':
version();
/* NOTREACHED */
default:
@@ -140,7 +144,7 @@ main(int argc, char *argv[])
/* NOTREACHED */
}
- curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp, defos);
+ curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
/*
* Conditionally start up the lookaside buffer before parsing.
@@ -191,15 +195,15 @@ usage(void)
"[-Ooption] "
"[-Toutput] "
"[-Wlevel]\n"
- "\t [file ...]\n",
+ "\t [file ...]\n",
progname);
exit((int)MANDOCLEVEL_BADARG);
}
static void
-parse(struct curparse *curp, int fd,
- const char *file, enum mandoclevel *level)
+parse(struct curparse *curp, int fd, const char *file,
+ enum mandoclevel *level)
{
enum mandoclevel rc;
struct mdoc *mdoc;
@@ -229,31 +233,31 @@ parse(struct curparse *curp, int fd,
if ( ! (curp->outman && curp->outmdoc)) {
switch (curp->outtype) {
- case (OUTT_XHTML):
+ case OUTT_XHTML:
curp->outdata = xhtml_alloc(curp->outopts);
curp->outfree = html_free;
break;
- case (OUTT_HTML):
+ case OUTT_HTML:
curp->outdata = html_alloc(curp->outopts);
curp->outfree = html_free;
break;
- case (OUTT_UTF8):
+ case OUTT_UTF8:
curp->outdata = utf8_alloc(curp->outopts);
curp->outfree = ascii_free;
break;
- case (OUTT_LOCALE):
+ case OUTT_LOCALE:
curp->outdata = locale_alloc(curp->outopts);
curp->outfree = ascii_free;
break;
- case (OUTT_ASCII):
+ case OUTT_ASCII:
curp->outdata = ascii_alloc(curp->outopts);
curp->outfree = ascii_free;
break;
- case (OUTT_PDF):
+ case OUTT_PDF:
curp->outdata = pdf_alloc(curp->outopts);
curp->outfree = pspdf_free;
break;
- case (OUTT_PS):
+ case OUTT_PS:
curp->outdata = ps_alloc(curp->outopts);
curp->outfree = pspdf_free;
break;
@@ -262,29 +266,29 @@ parse(struct curparse *curp, int fd,
}
switch (curp->outtype) {
- case (OUTT_HTML):
+ case OUTT_HTML:
/* FALLTHROUGH */
- case (OUTT_XHTML):
+ case OUTT_XHTML:
curp->outman = html_man;
curp->outmdoc = html_mdoc;
break;
- case (OUTT_TREE):
+ case OUTT_TREE:
curp->outman = tree_man;
curp->outmdoc = tree_mdoc;
break;
- case (OUTT_MAN):
+ case OUTT_MAN:
curp->outmdoc = man_mdoc;
curp->outman = man_man;
break;
- case (OUTT_PDF):
+ case OUTT_PDF:
/* FALLTHROUGH */
- case (OUTT_ASCII):
+ case OUTT_ASCII:
/* FALLTHROUGH */
- case (OUTT_UTF8):
+ case OUTT_UTF8:
/* FALLTHROUGH */
- case (OUTT_LOCALE):
+ case OUTT_LOCALE:
/* FALLTHROUGH */
- case (OUTT_PS):
+ case OUTT_PS:
curp->outman = terminal_man;
curp->outmdoc = terminal_mdoc;
break;
@@ -293,7 +297,7 @@ parse(struct curparse *curp, int fd,
}
}
- mparse_result(curp->mp, &mdoc, &man);
+ mparse_result(curp->mp, &mdoc, &man, NULL);
/* Execute the out device, if it exists. */
@@ -311,17 +315,18 @@ parse(struct curparse *curp, int fd,
}
static int
-moptions(enum mparset *tflags, char *arg)
+moptions(int *options, char *arg)
{
if (0 == strcmp(arg, "doc"))
- *tflags = MPARSE_MDOC;
+ *options |= MPARSE_MDOC;
else if (0 == strcmp(arg, "andoc"))
- *tflags = MPARSE_AUTO;
+ /* nothing to do */;
else if (0 == strcmp(arg, "an"))
- *tflags = MPARSE_MAN;
+ *options |= MPARSE_MAN;
else {
- fprintf(stderr, "%s: Bad argument\n", arg);
+ fprintf(stderr, "%s: -m%s: Bad argument\n",
+ progname, arg);
return(0);
}
@@ -354,7 +359,8 @@ toptions(struct curparse *curp, char *arg)
else if (0 == strcmp(arg, "pdf"))
curp->outtype = OUTT_PDF;
else {
- fprintf(stderr, "%s: Bad argument\n", arg);
+ fprintf(stderr, "%s: -T%s: Bad argument\n",
+ progname, arg);
return(0);
}
@@ -365,7 +371,7 @@ static int
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
- const char *toks[6];
+ const char *toks[6];
toks[0] = "stop";
toks[1] = "all";
@@ -377,22 +383,23 @@ woptions(struct curparse *curp, char *arg)
while (*arg) {
o = arg;
switch (getsubopt(&arg, UNCONST(toks), &v)) {
- case (0):
+ case 0:
curp->wstop = 1;
break;
- case (1):
+ case 1:
/* FALLTHROUGH */
- case (2):
+ case 2:
curp->wlevel = MANDOCLEVEL_WARNING;
break;
- case (3):
+ case 3:
curp->wlevel = MANDOCLEVEL_ERROR;
break;
- case (4):
+ case 4:
curp->wlevel = MANDOCLEVEL_FATAL;
break;
default:
- fprintf(stderr, "-W%s: Bad argument\n", o);
+ fprintf(stderr, "%s: -W%s: Bad argument\n",
+ progname, o);
return(0);
}
}
@@ -401,14 +408,20 @@ woptions(struct curparse *curp, char *arg)
}
static void
-mmsg(enum mandocerr t, enum mandoclevel lvl,
+mmsg(enum mandocerr t, enum mandoclevel lvl,
const char *file, int line, int col, const char *msg)
{
+ const char *mparse_msg;
+
+ fprintf(stderr, "%s: %s:", progname, file);
+
+ if (line)
+ fprintf(stderr, "%d:%d:", line, col + 1);
+
+ fprintf(stderr, " %s", mparse_strlevel(lvl));
- fprintf(stderr, "%s:%d:%d: %s: %s",
- file, line, col + 1,
- mparse_strlevel(lvl),
- mparse_strerror(t));
+ if (NULL != (mparse_msg = mparse_strerror(t)))
+ fprintf(stderr, ": %s", mparse_msg);
if (msg)
fprintf(stderr, ": %s", msg);
diff --git a/contrib/mdocml/main.h b/contrib/mdocml/main.h
index 79dcf48..beb0481 100644
--- a/contrib/mdocml/main.h
+++ b/contrib/mdocml/main.h
@@ -1,4 +1,4 @@
-/* $Id: main.h,v 1.15 2011/10/06 22:29:12 kristaps Exp $ */
+/* $Id: main.h,v 1.16 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -25,7 +25,7 @@ struct man;
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
-/*
+/*
* Definitions for main.c-visible output device functions, e.g., -Thtml
* and -Tascii. Note that ascii_alloc() is named as such in
* anticipation of latin1_alloc() and so on, all of which map into the
diff --git a/contrib/mdocml/makewhatis.8 b/contrib/mdocml/makewhatis.8
new file mode 100644
index 0000000..02c4cc3
--- /dev/null
+++ b/contrib/mdocml/makewhatis.8
@@ -0,0 +1,217 @@
+.\" $Id: makewhatis.8,v 1.2 2014/04/25 12:13:15 schwarze Exp $
+.\"
+.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2011, 2012 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: April 25 2014 $
+.Dt MAKEWHATIS 8
+.Os
+.Sh NAME
+.Nm makewhatis
+.Nd index UNIX manuals
+.Sh SYNOPSIS
+.Nm
+.Op Fl aDnpQ
+.Op Fl T Cm utf8
+.Op Fl C Ar file
+.Nm
+.Op Fl aDnpQ
+.Op Fl T Cm utf8
+.Ar dir ...
+.Nm
+.Op Fl DnpQ
+.Op Fl T Cm utf8
+.Fl d Ar dir
+.Op Ar
+.Nm
+.Op Fl Dnp
+.Op Fl T Cm utf8
+.Fl u Ar dir
+.Op Ar
+.Nm
+.Op Fl DQ
+.Fl t Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility extracts keywords from
+.Ux
+manuals and indexes them in a database for fast retrieval by
+.Xr apropos 1 ,
+.Xr whatis 1 ,
+and
+.Xr man 1 Ns 's
+.Fl k
+option.
+.Pp
+By default,
+.Nm
+creates a database in each
+.Ar dir
+using the files
+.Sm off
+.Sy man Ar section Li /
+.Op Ar arch Li /
+.Ar title . section
+.Sm on
+and
+.Sm off
+.Sy cat Ar section Li /
+.Op Ar arch Li /
+.Ar title . Sy 0
+.Sm on
+in that directory.
+Existing databases are replaced.
+If
+.Ar dir
+is not provided,
+.Nm
+uses the default paths stipulated by
+.Xr manpath 1 ,
+or
+.Xr man.conf 5 .
+.Pp
+The arguments are as follows:
+.Bl -tag -width "-C file"
+.It Fl a
+Use all directories and files found below
+.Ar dir ... .
+.It Fl C Ar file
+Specify an alternative configuration
+.Ar file
+in
+.Xr man.conf 5
+format.
+.It Fl D
+Display all files added or removed to the index.
+With a second
+.Fl D ,
+also show all keyswords added for each file.
+.It Fl d Ar dir
+Merge (remove and re-add)
+.Ar
+to the database in
+.Ar dir .
+.It Fl n
+Do not create or modify any database; scan and parse only,
+and print manual page names and descriptions to standard output.
+.It Fl p
+Print warnings about potential problems with manual pages
+to the standard error output.
+.It Fl Q
+Quickly build reduced-size databases
+by reading only the NAME sections of manuals.
+The resulting databases will usually contain names and descriptions only.
+.It Fl T Cm utf8
+Use UTF-8 encoding instead of ASCII for strings stored in the databases.
+.It Fl t Ar
+Check the given
+.Ar files
+for potential problems.
+Implies
+.Fl a ,
+.Fl n ,
+and
+.Fl p .
+All diagnostic messages are printed to the standard output;
+the standard error output is not used.
+.It Fl u Ar dir
+Remove
+.Ar
+from the database in
+.Ar dir .
+.El
+.Pp
+If fatal parse errors are encountered while parsing, the offending file
+is printed to stderr, omitted from the index, and the parse continues
+with the next input file.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa mandoc.db
+A database of manpages relative to the directory of the file.
+This file is portable across architectures and systems, so long as the
+manpage hierarchy it indexes does not change.
+.It Pa /etc/man.conf
+The default
+.Xr man 1
+configuration file.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Pp
+.Bl -tag -width Ds -compact
+.It 0
+No errors occurred.
+.It 5
+Invalid command line arguments were specified.
+No input files have been read.
+.It 6
+An operating system error occurred, for example memory exhaustion or an
+error accessing input files.
+Such errors cause
+.Nm
+to exit at once, possibly in the middle of parsing or formatting a file.
+The output databases are corrupt and should be removed.
+.El
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr man 1 ,
+.Xr whatis 1 ,
+.Xr man.conf 5
+.Sh HISTORY
+A
+.Nm
+utility first appeared in
+.Bx 2 .
+It was rewritten in
+.Xr perl 1
+for
+.Ox 2.7
+and in C for
+.Ox 5.6 .
+.Pp
+The
+.Ar dir
+argument first appeared in
+.Nx 1.0 ;
+the options
+.Fl dpt
+in
+.Ox 2.7 ;
+the option
+.Fl u
+in
+.Ox 3.4 ;
+and the options
+.Fl aCDnQT
+in
+.Ox 5.6 .
+.Sh AUTHORS
+.An -nosplit
+.An Bill Joy
+wrote the original
+.Bx
+.Nm
+in February 1979,
+.An Marc Espie
+started the Perl version in 2000,
+and the current version of
+.Nm
+was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/contrib/mdocml/man.7 b/contrib/mdocml/man.7
index f2f4d1d..4b64d7f 100644
--- a/contrib/mdocml/man.7
+++ b/contrib/mdocml/man.7
@@ -1,7 +1,8 @@
-.\" $Id: man.7,v 1.120 2013/09/16 22:58:57 schwarze Exp $
+.\" $Id: man.7,v 1.127 2014/06/22 16:39:45 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.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 +16,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: September 16 2013 $
+.Dd $Mdocdate: June 22 2014 $
.Dt MAN 7
.Os
.Sh NAME
@@ -97,30 +98,32 @@ file for a utility
.Bd -literal -offset indent
\&.TH PROGNAME 1 2009-10-10
\&.SH NAME
-\efBprogname\efR \e(en a description goes here
+\efBprogname\efR \e(en one line about what it does
\&.\e\(dq .SH LIBRARY
-\&.\e\(dq For sections 2 & 3 only.
+\&.\e\(dq For sections 2, 3, and 9 only.
\&.\e\(dq Not used in OpenBSD.
\&.SH SYNOPSIS
-\efBprogname\efR [\efB\e-options\efR] arguments...
+\efBprogname\efR [\efB\e-options\efR] \efIfile ...\efR
\&.SH DESCRIPTION
-The \efBfoo\efR utility processes files...
+The \efBfoo\efR utility processes files ...
+\&.\e\(dq .Sh CONTEXT
+\&.\e\(dq For section 9 functions only.
\&.\e\(dq .SH IMPLEMENTATION NOTES
\&.\e\(dq Not used in OpenBSD.
\&.\e\(dq .SH RETURN VALUES
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, and 9 function return values only.
\&.\e\(dq .SH ENVIRONMENT
-\&.\e\(dq For sections 1, 6, 7, & 8 only.
+\&.\e\(dq For sections 1, 6, 7, and 8 only.
\&.\e\(dq .SH FILES
\&.\e\(dq .SH EXIT STATUS
-\&.\e\(dq For sections 1, 6, & 8 only.
+\&.\e\(dq For sections 1, 6, and 8 only.
\&.\e\(dq .SH EXAMPLES
\&.\e\(dq .SH DIAGNOSTICS
-\&.\e\(dq For sections 1, 4, 6, 7, & 8 only.
+\&.\e\(dq For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
\&.\e\(dq .SH ERRORS
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, 4, and 9 errno settings only.
\&.\e\(dq .SH SEE ALSO
-\&.\e\(dq .BR foo ( 1 )
+\&.\e\(dq .BR foobar ( 1 )
\&.\e\(dq .SH STANDARDS
\&.\e\(dq .SH HISTORY
\&.\e\(dq .SH AUTHORS
@@ -170,6 +173,9 @@ This expands upon the brief, one-line description in
.Em NAME .
It usually contains a break-down of the options (if documenting a
command).
+.It Em CONTEXT
+This section lists the contexts in which functions can be called in section 9.
+The contexts are autoconf, process, or interrupt.
.It Em IMPLEMENTATION NOTES
Implementation-specific notes should be kept here.
This is useful when implementing standard functions that may have side
@@ -196,13 +202,19 @@ well-tested invocations.
Make sure that examples work properly!
.It Em DIAGNOSTICS
Documents error conditions.
-This is most useful in section 4 manuals.
+In section 4 and 9 manuals, these are usually messages
+printed by the kernel to the console and to the kernel log.
+In section 1, 6, 7, and 8, these are usually messages
+printed by userland programs to the standard error output.
+.Pp
Historically, this section was used in place of
.Em EXIT STATUS
for manuals in sections 1, 6, and 8; however, this practise is
discouraged.
.It Em ERRORS
-Documents error handling in sections 2, 3, and 9.
+Documents
+.Xr errno 2
+settings in sections 2, 3, 4, and 9.
.It Em SEE ALSO
References other manuals with related topics.
This section should exist for most manuals.
@@ -280,7 +292,7 @@ For the scoping of individual macros, see
.Sx MACRO SYNTAX .
.Ss \&AT
Sets the volume for the footer for compatibility with man pages from
-.Tn AT&T UNIX
+.At
releases.
The optional arguments specify which release it is from.
.Ss \&B
@@ -656,6 +668,20 @@ Sets the volume for the footer for compatibility with man pages from
.Bx
releases.
The optional first argument specifies which release it is from.
+.Ss \&UE
+End a uniform resource identifier block.
+This is a non-standard GNU extension, included only for compatibility.
+See
+.Sx \&UE .
+.Ss \&UR
+Begin a uniform resource identifier block.
+This is a non-standard GNU extension, included only for compatibility.
+It has the following syntax:
+.Bd -literal -offset indent
+.Pf \. Sx \&UR Ar uri
+link description to be shown
+.Pf \. Sx UE
+.Ed
.Ss \&br
Breaks the current line.
Consecutive invocations have no further effect.
@@ -665,11 +691,6 @@ See also
.Ss \&fi
End literal mode begun by
.Sx \&nf .
-.Ss \&ft
-Change the current font mode.
-See
-.Sx Text Decoration
-for a listing of available font modes.
.Ss \&in
Indent relative to the current indentation:
.Pp
@@ -750,10 +771,13 @@ The syntax is as follows:
.It Sx \&BI Ta n Ta current Ta \&
.It Sx \&BR Ta n Ta current Ta \&
.It Sx \&DT Ta 0 Ta current Ta \&
+.It Sx \&EE Ta 0 Ta current Ta compat
+.It Sx \&EX Ta 0 Ta current Ta compat
.It Sx \&I Ta n Ta next-line Ta \&
.It Sx \&IB Ta n Ta current Ta \&
.It Sx \&IR Ta n Ta current Ta \&
.It Sx \&OP Ta 0, 1 Ta current Ta compat
+.It Sx \&PD Ta 1 Ta current Ta \&
.It Sx \&R Ta n Ta next-line Ta \&
.It Sx \&RB Ta n Ta current Ta \&
.It Sx \&RI Ta n Ta current Ta \&
@@ -763,7 +787,6 @@ The syntax is as follows:
.It Sx \&UC Ta <=1 Ta current Ta \&
.It Sx \&br Ta 0 Ta current Ta compat
.It Sx \&fi Ta 0 Ta current Ta compat
-.It Sx \&ft Ta 1 Ta current Ta compat
.It Sx \&in Ta 1 Ta current Ta compat
.It Sx \&na Ta 0 Ta current Ta compat
.It Sx \&nf Ta 0 Ta current Ta compat
@@ -823,6 +846,8 @@ implicitly closed, is syntactically incorrect.
.It Sx \&SH Ta >0 Ta next-line Ta section Ta \&
.It Sx \&SS Ta >0 Ta next-line Ta sub-section Ta \&
.It Sx \&TP Ta n Ta next-line Ta paragraph Ta \&
+.It Sx \&UE Ta 0 Ta current Ta none Ta compat
+.It Sx \&UR Ta 1 Ta current Ta part Ta compat
.El
.Pp
Macros marked
@@ -848,10 +873,11 @@ Note that macros like
.Sx \&BR
open and close a font scope for each argument.
.Sh COMPATIBILITY
-This section documents areas of questionable portability between
+This section mentions some areas of questionable portability between
implementations of the
.Nm
language.
+More incompatibilities exist.
.Pp
.Bl -dash -compact
.It
@@ -863,47 +889,12 @@ to close out a literal context opened with
.Sx \&nf .
This behaviour may not be portable.
.It
-In quoted literals, GNU troff allowed pair-wise double-quotes to produce
-a standalone double-quote in formatted output.
-It is not known whether this behaviour is exhibited by other formatters.
-.It
troff suppresses a newline before
.Sq \(aq
macro output; in mandoc, it is an alias for the standard
.Sq \&.
control character.
.It
-The
-.Sq \eh
-.Pq horizontal position ,
-.Sq \ev
-.Pq vertical position ,
-.Sq \em
-.Pq text colour ,
-.Sq \eM
-.Pq text filling colour ,
-.Sq \ez
-.Pq zero-length character ,
-.Sq \ew
-.Pq string length ,
-.Sq \ek
-.Pq horizontal position marker ,
-.Sq \eo
-.Pq text overstrike ,
-and
-.Sq \es
-.Pq text size
-escape sequences are all discarded in mandoc.
-.It
-The
-.Sq \ef
-scaling unit is accepted by mandoc, but rendered as the default unit.
-.It
-The
-.Sx \&sp
-macro does not accept negative values in mandoc.
-In GNU troff, this would result in strange behaviour.
-.It
In page header lines, GNU troff versions up to and including 1.21
only print
.Ar volume
@@ -919,8 +910,13 @@ is given, like in
.El
.Pp
The
-.Sx OP
-macro is part of the extended
+.Sx EE ,
+.Sx EX ,
+.Sx OP ,
+.Sx UE ,
+and
+.Sx UR
+macros are part of the GNU extended
.Nm
macro set, and may not be portable to non-GNU troff implementations.
.Sh SEE ALSO
diff --git a/contrib/mdocml/man.c b/contrib/mdocml/man.c
index e6e1c28..75a6350 100644
--- a/contrib/mdocml/man.c
+++ b/contrib/mdocml/man.c
@@ -1,6 +1,8 @@
-/* $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */
+/* $Id: man.c,v 1.137 2014/08/01 21:24:17 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
*
* 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 +23,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -28,12 +31,13 @@
#include "man.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libman.h"
#include "libmandoc.h"
-const char *const __man_macronames[MAN_MAX] = {
+const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
- "TP", "LP", "PP", "P",
+ "TP", "LP", "PP", "P",
"IP", "HP", "SM", "SB",
"BI", "IB", "BR", "RB",
"R", "B", "I", "IR",
@@ -41,17 +45,17 @@ const char *const __man_macronames[MAN_MAX] = {
"fi", "RE", "RS", "DT",
"UC", "PD", "AT", "in",
"ft", "OP", "EX", "EE",
- "UR", "UE"
+ "UR", "UE", "ll"
};
const char * const *man_macronames = __man_macronames;
-static struct man_node *man_node_alloc(struct man *, int, int,
+static struct man_node *man_node_alloc(struct man *, int, int,
enum man_type, enum mant);
-static int man_node_append(struct man *,
+static int man_node_append(struct man *,
struct man_node *);
static void man_node_free(struct man_node *);
-static void man_node_unlink(struct man *,
+static void man_node_unlink(struct man *,
struct man_node *);
static int man_ptext(struct man *, int, char *, int);
static int man_pmacro(struct man *, int, char *, int);
@@ -64,20 +68,16 @@ const struct man_node *
man_node(const struct man *man)
{
- assert( ! (MAN_HALT & man->flags));
return(man->first);
}
-
const struct man_meta *
man_meta(const struct man *man)
{
- assert( ! (MAN_HALT & man->flags));
return(&man->meta);
}
-
void
man_reset(struct man *man)
{
@@ -86,7 +86,6 @@ man_reset(struct man *man)
man_alloc1(man);
}
-
void
man_free(struct man *man)
{
@@ -95,9 +94,8 @@ man_free(struct man *man)
free(man);
}
-
struct man *
-man_alloc(struct roff *roff, struct mparse *parse)
+man_alloc(struct roff *roff, struct mparse *parse, int quick)
{
struct man *p;
@@ -105,39 +103,31 @@ man_alloc(struct roff *roff, struct mparse *parse)
man_hash_init();
p->parse = parse;
+ p->quick = quick;
p->roff = roff;
man_alloc1(p);
return(p);
}
-
int
man_endparse(struct man *man)
{
- assert( ! (MAN_HALT & man->flags));
- if (man_macroend(man))
- return(1);
- man->flags |= MAN_HALT;
- return(0);
+ return(man_macroend(man));
}
-
int
man_parseln(struct man *man, int ln, char *buf, int offs)
{
man->flags |= MAN_NEWLINE;
- assert( ! (MAN_HALT & man->flags));
-
return (roff_getcontrol(man->roff, buf, &offs) ?
- man_pmacro(man, ln, buf, offs) :
- man_ptext(man, ln, buf, offs));
+ man_pmacro(man, ln, buf, offs) :
+ man_ptext(man, ln, buf, offs));
}
-
static void
man_free1(struct man *man)
{
@@ -156,7 +146,6 @@ man_free1(struct man *man)
free(man->meta.msec);
}
-
static void
man_alloc1(struct man *man)
{
@@ -180,12 +169,12 @@ man_node_append(struct man *man, struct man_node *p)
assert(MAN_ROOT != p->type);
switch (man->next) {
- case (MAN_NEXT_SIBLING):
+ case MAN_NEXT_SIBLING:
man->last->next = p;
p->prev = man->last;
p->parent = man->last->parent;
break;
- case (MAN_NEXT_CHILD):
+ case MAN_NEXT_CHILD:
man->last->child = p;
p->parent = man->last;
break;
@@ -193,23 +182,24 @@ man_node_append(struct man *man, struct man_node *p)
abort();
/* NOTREACHED */
}
-
+
assert(p->parent);
p->parent->nchild++;
- if ( ! man_valid_pre(man, p))
- return(0);
-
switch (p->type) {
- case (MAN_HEAD):
+ case MAN_BLOCK:
+ if (p->tok == MAN_SH || p->tok == MAN_SS)
+ man->flags &= ~MAN_LITERAL;
+ break;
+ case MAN_HEAD:
assert(MAN_BLOCK == p->parent->type);
p->parent->head = p;
break;
- case (MAN_TAIL):
+ case MAN_TAIL:
assert(MAN_BLOCK == p->parent->type);
p->parent->tail = p;
break;
- case (MAN_BODY):
+ case MAN_BODY:
assert(MAN_BLOCK == p->parent->type);
p->parent->body = p;
break;
@@ -220,9 +210,9 @@ man_node_append(struct man *man, struct man_node *p)
man->last = p;
switch (p->type) {
- case (MAN_TBL):
+ case MAN_TBL:
/* FALLTHROUGH */
- case (MAN_TEXT):
+ case MAN_TEXT:
if ( ! man_valid_post(man))
return(0);
break;
@@ -233,9 +223,8 @@ man_node_append(struct man *man, struct man_node *p)
return(1);
}
-
static struct man_node *
-man_node_alloc(struct man *man, int line, int pos,
+man_node_alloc(struct man *man, int line, int pos,
enum man_type type, enum mant tok)
{
struct man_node *p;
@@ -252,7 +241,6 @@ man_node_alloc(struct man *man, int line, int pos,
return(p);
}
-
int
man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
{
@@ -265,7 +253,6 @@ man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
return(1);
}
-
int
man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
{
@@ -278,7 +265,6 @@ man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
return(1);
}
-
int
man_head_alloc(struct man *man, int line, int pos, enum mant tok)
{
@@ -291,7 +277,6 @@ man_head_alloc(struct man *man, int line, int pos, enum mant tok)
return(1);
}
-
int
man_body_alloc(struct man *man, int line, int pos, enum mant tok)
{
@@ -304,7 +289,6 @@ man_body_alloc(struct man *man, int line, int pos, enum mant tok)
return(1);
}
-
int
man_block_alloc(struct man *man, int line, int pos, enum mant tok)
{
@@ -332,7 +316,6 @@ man_word_alloc(struct man *man, int line, int pos, const char *word)
return(1);
}
-
/*
* Free all of the resources held by a node. This does NOT unlink a
* node from its context; for that, see man_node_unlink().
@@ -346,7 +329,6 @@ man_node_free(struct man_node *p)
free(p);
}
-
void
man_node_delete(struct man *man, struct man_node *p)
{
@@ -363,8 +345,6 @@ man_addeqn(struct man *man, const struct eqn *ep)
{
struct man_node *n;
- assert( ! (MAN_HALT & man->flags));
-
n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
n->eqn = ep;
@@ -380,8 +360,6 @@ man_addspan(struct man *man, const struct tbl_span *sp)
{
struct man_node *n;
- assert( ! (MAN_HALT & man->flags));
-
n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
n->span = sp;
@@ -403,7 +381,7 @@ man_descope(struct man *man, int line, int offs)
if (MAN_ELINE & man->flags) {
man->flags &= ~MAN_ELINE;
- if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
+ if ( ! man_unscope(man, man->last->parent))
return(0);
}
@@ -411,7 +389,7 @@ man_descope(struct man *man, int line, int offs)
return(1);
man->flags &= ~MAN_BLINE;
- if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
+ if ( ! man_unscope(man, man->last->parent))
return(0);
return(man_body_alloc(man, line, offs, man->last->tok));
}
@@ -448,9 +426,9 @@ man_ptext(struct man *man, int line, char *buf, int offs)
return(1);
}
- /*
+ /*
* Warn if the last un-escaped character is whitespace. Then
- * strip away the remaining spaces (tabs stay!).
+ * strip away the remaining spaces (tabs stay!).
*/
i = (int)strlen(buf);
@@ -458,7 +436,8 @@ man_ptext(struct man *man, int line, char *buf, int offs)
if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
if (i > 1 && '\\' != buf[i - 2])
- man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
+ line, i - 1, NULL);
for (--i; i && ' ' == buf[i]; i--)
/* Spin back to non-space. */ ;
@@ -479,7 +458,7 @@ man_ptext(struct man *man, int line, char *buf, int offs)
*/
assert(i);
- if (mandoc_eos(buf, (size_t)i, 0))
+ if (mandoc_eos(buf, (size_t)i))
man->last->flags |= MAN_EOS;
return(man_descope(man, line, offs));
@@ -488,13 +467,15 @@ man_ptext(struct man *man, int line, char *buf, int offs)
static int
man_pmacro(struct man *man, int ln, char *buf, int offs)
{
- int i, ppos;
- enum mant tok;
char mac[5];
struct man_node *n;
+ enum mant tok;
+ int i, ppos;
+ int bline;
if ('"' == buf[offs]) {
- man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT);
+ mandoc_msg(MANDOCERR_COMMENT_BAD, man->parse,
+ ln, offs, NULL);
return(1);
} else if ('\0' == buf[offs])
return(1);
@@ -507,8 +488,8 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
*/
i = 0;
- while (i < 4 && '\0' != buf[offs] &&
- ' ' != buf[offs] && '\t' != buf[offs])
+ while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] &&
+ '\t' != buf[offs])
mac[i++] = buf[offs++];
mac[i] = '\0';
@@ -516,8 +497,8 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
if (MAN_MAX == tok) {
- mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln,
- ppos, "%s", buf + ppos - 1);
+ mandoc_msg(MANDOCERR_MACRO, man->parse,
+ ln, ppos, buf + ppos - 1);
return(1);
}
@@ -526,15 +507,16 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
while (buf[offs] && ' ' == buf[offs])
offs++;
- /*
+ /*
* Trailing whitespace. Note that tabs are allowed to be passed
* into the parser as "text", so we only warn about spaces here.
*/
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
- man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
+ ln, offs - 1, NULL);
- /*
+ /*
* Remove prior ELINE macro, as it's being clobbered by a new
* macro. Note that NSCOPED macros do not close out ELINE
* macros---they don't print text---so we let those slip by.
@@ -550,7 +532,7 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
if (MAN_NSCOPED & man_macros[n->tok].flags)
n = n->parent;
- mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
+ mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line,
n->pos, "%s breaks %s", man_macronames[tok],
man_macronames[n->tok]);
@@ -581,7 +563,7 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
assert(MAN_BLOCK == n->type);
assert(MAN_SCOPED & man_macros[n->tok].flags);
- mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
+ mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line,
n->pos, "%s breaks %s", man_macronames[tok],
man_macronames[n->tok]);
@@ -589,63 +571,41 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
man->flags &= ~MAN_BLINE;
}
- /*
- * Save the fact that we're in the next-line for a block. In
- * this way, embedded roff instructions can "remember" state
- * when they exit.
- */
+ /* Remember whether we are in next-line scope for a block head. */
- if (MAN_BLINE & man->flags)
- man->flags |= MAN_BPLINE;
+ bline = man->flags & MAN_BLINE;
/* Call to handler... */
assert(man_macros[tok].fp);
if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf))
- goto err;
+ return(0);
- /*
- * We weren't in a block-line scope when entering the
- * above-parsed macro, so return.
- */
+ /* In quick mode (for mandocdb), abort after the NAME section. */
- if ( ! (MAN_BPLINE & man->flags)) {
- man->flags &= ~MAN_ILINE;
- return(1);
+ if (man->quick && MAN_SH == tok) {
+ n = man->last;
+ if (MAN_BODY == n->type &&
+ strcmp(n->prev->child->string, "NAME"))
+ return(2);
}
- man->flags &= ~MAN_BPLINE;
/*
- * If we're in a block scope, then allow this macro to slip by
- * without closing scope around it.
+ * If we are in a next-line scope for a block head,
+ * close it out now and switch to the body,
+ * unless the next-line scope is allowed to continue.
*/
- if (MAN_ILINE & man->flags) {
- man->flags &= ~MAN_ILINE;
+ if ( ! bline || man->flags & MAN_ELINE ||
+ man_macros[tok].flags & MAN_NSCOPED)
return(1);
- }
-
- /*
- * If we've opened a new next-line element scope, then return
- * now, as the next line will close out the block scope.
- */
-
- if (MAN_ELINE & man->flags)
- return(1);
-
- /* Close out the block scope opened in the prior line. */
assert(MAN_BLINE & man->flags);
man->flags &= ~MAN_BLINE;
- if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
+ if ( ! man_unscope(man, man->last->parent))
return(0);
return(man_body_alloc(man, ln, ppos, man->last->tok));
-
-err: /* Error out. */
-
- man->flags |= MAN_HALT;
- return(0);
}
/*
@@ -696,3 +656,49 @@ man_mparse(const struct man *man)
assert(man && man->parse);
return(man->parse);
}
+
+void
+man_deroff(char **dest, const struct man_node *n)
+{
+ char *cp;
+ size_t sz;
+
+ if (MAN_TEXT != n->type) {
+ for (n = n->child; n; n = n->next)
+ man_deroff(dest, n);
+ return;
+ }
+
+ /* Skip leading whitespace and escape sequences. */
+
+ cp = n->string;
+ while ('\0' != *cp) {
+ if ('\\' == *cp) {
+ cp++;
+ mandoc_escape((const char **)&cp, NULL, NULL);
+ } else if (isspace((unsigned char)*cp))
+ cp++;
+ else
+ break;
+ }
+
+ /* Skip trailing whitespace. */
+
+ for (sz = strlen(cp); sz; sz--)
+ if (0 == isspace((unsigned char)cp[sz-1]))
+ break;
+
+ /* Skip empty strings. */
+
+ if (0 == sz)
+ return;
+
+ if (NULL == *dest) {
+ *dest = mandoc_strndup(cp, sz);
+ return;
+ }
+
+ mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
+ free(*dest);
+ *dest = cp;
+}
diff --git a/contrib/mdocml/man.cgi.8 b/contrib/mdocml/man.cgi.8
new file mode 100644
index 0000000..69335e6
--- /dev/null
+++ b/contrib/mdocml/man.cgi.8
@@ -0,0 +1,409 @@
+.\" $Id: man.cgi.8,v 1.9 2014/07/22 18:14:13 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: July 22 2014 $
+.Dt MAN.CGI 8
+.Os
+.Sh NAME
+.Nm man.cgi
+.Nd CGI program to search and display manual pages
+.Sh DESCRIPTION
+The
+.Nm
+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
+utilities.
+It can use multiple manual trees in parallel.
+.Ss HTML search interface
+At the top of each generated HTML page,
+.Nm
+displays a search form containing these elements:
+.Bl -enum
+.It
+An input box for search queries, expecting
+either a name of a manual page or an
+.Ar expression
+using the syntax described in the
+.Xr apropos 1
+manual; filling this in is required for each search.
+.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
+.Xr apropos 1
+queries.
+.It
+A dropdown menu to optionally select a manual section.
+If one is provided, it has the same effect as the
+.Xr man 1
+and
+.Xr apropos 1
+.Fl s
+option.
+Otherwise, pages from all sections are shown.
+.It
+A dropdown menu to optionally select an architecture.
+If one is provided, it has the same effect as the
+.Xr man 1
+and
+.Xr apropos 1
+.Fl S
+option.
+By default, pages for all architectures are shown.
+.It
+A dropdown menu to select a manual tree.
+If the configuration file
+.Pa /var/www/man/manpath.conf
+contains only one manpath, the dropdown menu is not shown.
+By default, the first manpath given in the file is used.
+.El
+.Ss Program output
+The
+.Nm
+program generates five kinds of output pages:
+.Bl -tag -width Ds
+.It The index page.
+This is returned when calling
+.Nm
+without
+.Ev PATH_INFO
+and without a
+.Ev QUERY_STRING .
+It serves as a starting point for using the program
+and shows the search form only.
+.It A list page.
+Lists are returned when searches match more than one manual page.
+The first column shows the names and section numbers of manuals
+as clickable links.
+The second column shows the one-line descriptions of the manuals.
+.It A manual page.
+This output format is used when a search matches exactly one
+manual page, or when a link on a list page or an
+.Ic \&Xr
+link on another manual page is followed.
+.It A no-result page.
+This is shown when a search request returns no results -
+eiher because it violates the query syntax, or because
+the search does not match any manual pages.
+.It \&An error page.
+This cannot happen by merely clicking the
+.Dq Search
+button, but only by manually entering an invalid URI.
+It does not show the search form, but only an error message
+and a link back to the index page.
+.El
+.Ss Setup
+For each manual tree, create one first-level subdirectory below
+.Pa /var/www/man .
+The name of one of these directories is called a
+.Dq manpath
+in the context of
+.Nm .
+Create a single ASCII text file
+.Pa /var/www/man/manpath.conf
+containing the names of these directories, one per line.
+The directory given first is used as the default manpath.
+.Pp
+Inside each of these directories, use the same directory and file
+structure as found below
+.Pa /usr/share/man ,
+that is, second-level subdirectories
+.Pa /var/www/man/*/man1 , /var/www/man/*/man2
+etc. containing source
+.Xr mdoc 7
+and
+.Xr man 7
+manuals with file name extensions matching the section numbers,
+second-level subdirectories
+.Pa /var/www/man/*/cat1 , /var/www/man/*/cat2
+etc. containing preformatted manuals with the file name extension
+.Sq 0 ,
+and optional third-level subdirectories for architectures.
+Use
+.Xr makewhatis 8
+to create a
+.Xr mandoc.db 5
+database inside each manpath.
+.Pp
+Configure your web server to execute CGI programs located in
+.Pa /cgi-bin .
+When using
+.Xr nginx 8 ,
+the
+.Xr slowcgi 8
+proxy daemon is needed to translate FastCGI requests to plain old CGI.
+.Pp
+To compile
+.Nm ,
+first copy
+.Pa cgi.h.example
+to
+.Pa cgi.h
+and edit it according to your needs.
+It contains the following compile-time definitions:
+.Bl -tag -width Ds
+.It Ev COMPAT_OLDURI
+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,
+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.
+This is used in generated HTML code.
+.It Ev CUSTOMIZE_BEGIN
+A HTML string to be inserted right after opening the
+.Aq BODY
+element.
+.It Ev CUSTOMIZE_TITLE
+An ASCII string to be used for the HTML
+.Aq TITLE
+element.
+.It Ev 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
+.Nm
+data directory to be used instead of
+.Pa /var/www/man ,
+relative to the web server
+.Xr chroot 2
+directory, to be specified without a trailing slash.
+This is prepended to the manpath when opening
+.Xr mandoc.db 5
+and manual page files.
+.El
+.Pp
+After editing
+.Pa cgi.h ,
+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.
+.Ss URI interface
+.Nm
+uniform resource identifiers are not needed for interactive use,
+but can be useful for deep linking.
+They consist of:
+.Bl -enum
+.It
+The
+.Cm http://
+protocol specifier.
+.It
+The host name and a following slash.
+.It
+The path to the program, normally
+.Pa cgi-bin/man.cgi/ .
+.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 .
+.It
+For searches, a query string starting with a question mark
+and consisting of
+.Ar key Ns = Ns Ar value
+pairs, separated by ampersands, for example
+.Pa ?manpath=OpenBSD-current&query=mandoc .
+Supported keys are
+.Cm manpath ,
+.Cm query ,
+.Cm sec ,
+.Cm arch ,
+corresponding to
+.Xr apropos 1
+.Fl M ,
+.Ar expression ,
+.Fl s ,
+.Fl S ,
+respectively, and
+.Cm apropos ,
+which is a boolean parameter to select or deselect the
+.Xr apropos 1
+query mode.
+For backward compatibility with the traditional
+.Nm ,
+.Cm sektion
+is supported as an alias for
+.Cm sec .
+.El
+.Ss Restricted character set
+For security reasons, in particular to prevent cross site scripting
+attacks, some strings used by
+.Nm
+can only contain the following characters:
+.Pp
+.Bl -dash -compact -offset indent
+.It
+lower case and upper case ASCII letters
+.It
+the ten decimal digits
+.It
+the dash
+.Pq Sq -
+.It
+the dot
+.Pq Sq \&.
+.It
+the slash
+.Pq Sq /
+.It
+the underscore
+.Pq Sq _
+.El
+.Pp
+In particular, this applies to the
+.Ev SCRIPT_NAME ,
+to all manpaths, and to all architecture names.
+.Sh ENVIRONMENT
+The web server may pass the following CGI variables to
+.Nm :
+.Bl -tag -width Ds
+.It Ev PATH_INFO
+The final part of the URI path passed from the client to the server,
+starting after the
+.Ev SCRIPT_NAME
+and ending before the
+.Ev QUERY_STRING .
+It is used by the
+.Cm show
+page to aquire the manpath and filename it needs.
+.It Ev QUERY_STRING
+The HTTP query string passed from the client to the server.
+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
+.It Pa /var/www
+Default web server
+.Xr chroot 2
+directory.
+All the following paths are specified relative to this directory.
+.It Pa /cgi-bin/man.cgi
+The path to the
+.Nm
+program relative to the server root.
+Can be overridden by
+.Ev SCRIPT_NAME .
+.It Pa /htdocs
+The path to the server document root relative to the server root.
+This is part of the web server configuration and not specific to
+.Nm .
+.It Pa /htdocs/man-cgi.css
+A style sheet for general
+.Nm
+styling, referenced from each generated HTML page.
+.It Pa /htdocs/man.css
+A style sheet for
+.Xr mandoc 1
+HTML styling, referenced from each generated HTML page after
+.Pa man-cgi.css .
+.It Pa /man
+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.
+.It Pa /man/manpath.conf
+The list of available manpaths, one per line.
+If any of the lines in this file contains a slash
+.Pq Sq /
+or any character not contained in the
+.Sx Restricted character set ,
+.Nm
+reports an internal server error and exits without doing anything.
+.It Pa /man/OpenBSD-current/man1/mandoc.1
+An example
+.Xr mdoc 7
+source file located below the
+.Dq OpenBSD-current
+manpath.
+.El
+.Sh COMPATIBILITY
+The
+.Nm
+CGI program is call-compatible with queries from the traditional
+.Pa man.cgi
+script by Wolfram Schneider.
+However, the output may not be quite the same.
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr mandoc.db 5 ,
+.Xr makewhatis 8 ,
+.Xr slowcgi 8
+.Sh HISTORY
+A version of
+.Nm
+based on
+.Xr mandoc 1
+first appeared in mdocml-1.12.1 (March 2012).
+The current SQLite3-based version first appeared in
+.Ox 5.6 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+program was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and ported to the SQLite3-based
+.Xr mandoc.db 5
+backend by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/contrib/mdocml/man.h b/contrib/mdocml/man.h
index ef9480f..aa80b67 100644
--- a/contrib/mdocml/man.h
+++ b/contrib/mdocml/man.h
@@ -1,6 +1,7 @@
-/* $Id: man.h,v 1.62 2013/10/17 20:54:58 schwarze Exp $ */
+/* $Id: man.h,v 1.65 2014/06/20 23:02:31 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -56,6 +57,7 @@ enum mant {
MAN_EE,
MAN_UR,
MAN_UE,
+ MAN_ll,
MAN_MAX
};
@@ -77,6 +79,7 @@ struct man_meta {
char *vol; /* `TH' volume */
char *title; /* `TH' title (e.g., FOO) */
char *source; /* `TH' source (e.g., GNU) */
+ int hasbody; /* document is not empty */
};
struct man_node {
@@ -111,6 +114,7 @@ struct man;
const struct man_node *man_node(const struct man *);
const struct man_meta *man_meta(const struct man *);
const struct mparse *man_mparse(const struct man *);
+void man_deroff(char **, const struct man_node *);
__END_DECLS
diff --git a/contrib/mdocml/man_hash.c b/contrib/mdocml/man_hash.c
index 86c5c40..ab88722 100644
--- a/contrib/mdocml/man_hash.c
+++ b/contrib/mdocml/man_hash.c
@@ -1,4 +1,4 @@
-/* $Id: man_hash.c,v 1.25 2011/07/24 18:15:14 kristaps Exp $ */
+/* $Id: man_hash.c,v 1.27 2014/04/20 16:46:04 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -23,7 +23,6 @@
#include <assert.h>
#include <ctype.h>
#include <limits.h>
-#include <stdlib.h>
#include <string.h>
#include "man.h"
@@ -49,6 +48,7 @@
*/
static unsigned char table[26 * HASH_DEPTH];
+
/*
* XXX - this hash has global scope, so if intended for use as a library
* with multiple callers, it will need re-invocation protection.
@@ -60,8 +60,7 @@ man_hash_init(void)
memset(table, UCHAR_MAX, sizeof(table));
- assert(/* LINTED */
- MAN_MAX < UCHAR_MAX);
+ assert(MAN_MAX < UCHAR_MAX);
for (i = 0; i < (int)MAN_MAX; i++) {
x = man_macronames[i][0];
@@ -80,7 +79,6 @@ man_hash_init(void)
}
}
-
enum mant
man_hash_find(const char *tmp)
{
diff --git a/contrib/mdocml/man_html.c b/contrib/mdocml/man_html.c
index 2c4e220..9689cc2 100644
--- a/contrib/mdocml/man_html.c
+++ b/contrib/mdocml/man_html.c
@@ -1,7 +1,7 @@
-/* $Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp $ */
+/* $Id: man_html.c,v 1.96 2014/08/01 19:25:52 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +28,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "html.h"
#include "man.h"
@@ -53,7 +54,7 @@ struct htmlman {
int (*post)(MAN_ARGS);
};
-static void print_bvspace(struct html *,
+static void print_bvspace(struct html *,
const struct man_node *);
static void print_man(MAN_ARGS);
static void print_man_head(MAN_ARGS);
@@ -90,7 +91,7 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_PP_pre, NULL }, /* PP */
{ man_PP_pre, NULL }, /* P */
{ man_IP_pre, NULL }, /* IP */
- { man_HP_pre, NULL }, /* HP */
+ { man_HP_pre, NULL }, /* HP */
{ man_SM_pre, NULL }, /* SM */
{ man_SM_pre, NULL }, /* SB */
{ man_alt_pre, NULL }, /* BI */
@@ -119,8 +120,10 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_literal_pre, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */
{ NULL, NULL }, /* UE */
+ { man_ign_pre, NULL }, /* ll */
};
+
/*
* Printing leading vertical space before a block.
* This is used for the paragraph macros.
@@ -155,7 +158,7 @@ html_man(void *arg, const struct man *man)
}
static void
-print_man(MAN_ARGS)
+print_man(MAN_ARGS)
{
struct tag *t, *tt;
struct htmlpair tag;
@@ -170,15 +173,13 @@ print_man(MAN_ARGS)
print_tagq(h, tt);
print_otag(h, TAG_BODY, 0, NULL);
print_otag(h, TAG_DIV, 1, &tag);
- } else
+ } else
t = print_otag(h, TAG_DIV, 1, &tag);
print_man_nodelist(man, n, mh, h);
print_tagq(h, t);
}
-
-/* ARGSUSED */
static void
print_man_head(MAN_ARGS)
{
@@ -191,7 +192,6 @@ print_man_head(MAN_ARGS)
print_text(h, h->buf);
}
-
static void
print_man_nodelist(MAN_ARGS)
{
@@ -201,7 +201,6 @@ print_man_nodelist(MAN_ARGS)
print_man_nodelist(man, n->next, mh, h);
}
-
static void
print_man_node(MAN_ARGS)
{
@@ -212,10 +211,10 @@ print_man_node(MAN_ARGS)
t = h->tags.head;
switch (n->type) {
- case (MAN_ROOT):
+ case MAN_ROOT:
man_root_pre(man, n, mh, h);
break;
- case (MAN_TEXT):
+ case MAN_TEXT:
/*
* If we have a blank line, output a vertical space.
* If we have a space as the first character, break
@@ -233,10 +232,10 @@ print_man_node(MAN_ARGS)
print_text(h, n->string);
return;
- case (MAN_EQN):
+ case MAN_EQN:
print_eqn(h, n->eqn);
break;
- case (MAN_TBL):
+ case MAN_TBL:
/*
* This will take care of initialising all of the table
* state data for the first table, then tearing it down
@@ -245,7 +244,7 @@ print_man_node(MAN_ARGS)
print_tbl(h, n->span);
return;
default:
- /*
+ /*
* Close out scope of font prior to opening a macro
* scope.
*/
@@ -275,10 +274,10 @@ print_man_node(MAN_ARGS)
print_stagq(h, t);
switch (n->type) {
- case (MAN_ROOT):
+ case MAN_ROOT:
man_root_post(man, n, mh, h);
break;
- case (MAN_EQN):
+ case MAN_EQN:
break;
default:
if (mans[n->tok].post)
@@ -287,7 +286,6 @@ print_man_node(MAN_ARGS)
}
}
-
static int
a2width(const struct man_node *n, struct roffsu *su)
{
@@ -300,22 +298,16 @@ a2width(const struct man_node *n, struct roffsu *su)
return(0);
}
-
-/* ARGSUSED */
static void
man_root_pre(MAN_ARGS)
{
struct htmlpair tag[3];
struct tag *t, *tt;
- char b[BUFSIZ], title[BUFSIZ];
-
- b[0] = 0;
- if (man->vol)
- (void)strlcat(b, man->vol, BUFSIZ);
+ char *title;
assert(man->title);
assert(man->msec);
- snprintf(title, BUFSIZ - 1, "%s(%s)", man->title, man->msec);
+ mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
PAIR_SUMMARY_INIT(&tag[0], "Document Header");
PAIR_CLASS_INIT(&tag[1], "head");
@@ -338,7 +330,8 @@ man_root_pre(MAN_ARGS)
PAIR_CLASS_INIT(&tag[0], "head-vol");
PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
print_otag(h, TAG_TD, 2, tag);
- print_text(h, b);
+ if (NULL != man->vol)
+ print_text(h, man->vol);
print_stagq(h, tt);
PAIR_CLASS_INIT(&tag[0], "head-rtitle");
@@ -346,10 +339,9 @@ man_root_pre(MAN_ARGS)
print_otag(h, TAG_TD, 2, tag);
print_text(h, title);
print_tagq(h, t);
+ free(title);
}
-
-/* ARGSUSED */
static void
man_root_post(MAN_ARGS)
{
@@ -383,7 +375,6 @@ man_root_post(MAN_ARGS)
}
-/* ARGSUSED */
static int
man_br_pre(MAN_ARGS)
{
@@ -397,7 +388,7 @@ man_br_pre(MAN_ARGS)
if ( ! a2roffsu(n->string, &su, SCALE_VS))
SCALE_VS_INIT(&su, atoi(n->string));
} else
- su.scale = 0;
+ su.scale = 0.0;
bufinit(h);
bufcat_su(h, "height", &su);
@@ -410,7 +401,6 @@ man_br_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_SH_pre(MAN_ARGS)
{
@@ -428,7 +418,6 @@ man_SH_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_alt_pre(MAN_ARGS)
{
@@ -437,7 +426,7 @@ man_alt_pre(MAN_ARGS)
enum htmltag fp;
struct tag *t;
- if ((savelit = mh->fl & MANH_LITERAL))
+ if ((savelit = mh->fl & MANH_LITERAL))
print_otag(h, TAG_BR, 0, NULL);
mh->fl &= ~MANH_LITERAL;
@@ -445,22 +434,22 @@ man_alt_pre(MAN_ARGS)
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
t = NULL;
switch (n->tok) {
- case (MAN_BI):
+ case MAN_BI:
fp = i % 2 ? TAG_I : TAG_B;
break;
- case (MAN_IB):
+ case MAN_IB:
fp = i % 2 ? TAG_B : TAG_I;
break;
- case (MAN_RI):
+ case MAN_RI:
fp = i % 2 ? TAG_I : TAG_MAX;
break;
- case (MAN_IR):
+ case MAN_IR:
fp = i % 2 ? TAG_MAX : TAG_I;
break;
- case (MAN_BR):
+ case MAN_BR:
fp = i % 2 ? TAG_MAX : TAG_B;
break;
- case (MAN_RB):
+ case MAN_RB:
fp = i % 2 ? TAG_B : TAG_MAX;
break;
default:
@@ -486,18 +475,16 @@ man_alt_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_SM_pre(MAN_ARGS)
{
-
+
print_otag(h, TAG_SMALL, 0, NULL);
if (MAN_SB == n->tok)
print_otag(h, TAG_B, 0, NULL);
return(1);
}
-/* ARGSUSED */
static int
man_SS_pre(MAN_ARGS)
{
@@ -515,7 +502,6 @@ man_SS_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_PP_pre(MAN_ARGS)
{
@@ -528,13 +514,12 @@ man_PP_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_IP_pre(MAN_ARGS)
{
const struct man_node *nn;
- if (MAN_BODY == n->type) {
+ if (MAN_BODY == n->type) {
print_otag(h, TAG_DD, 0, NULL);
return(1);
} else if (MAN_HEAD != n->type) {
@@ -553,15 +538,19 @@ man_IP_pre(MAN_ARGS)
/* For TP, only print next-line header elements. */
- if (MAN_TP == n->tok)
- for (nn = n->child; nn; nn = nn->next)
- if (nn->line > n->line)
- print_man_node(man, nn, mh, h);
+ if (MAN_TP == n->tok) {
+ nn = n->child;
+ while (NULL != nn && 0 == (MAN_LINE & nn->flags))
+ nn = nn->next;
+ while (NULL != nn) {
+ print_man_node(man, nn, mh, h);
+ nn = nn->next;
+ }
+ }
return(0);
}
-/* ARGSUSED */
static int
man_HP_pre(MAN_ARGS)
{
@@ -590,7 +579,6 @@ man_HP_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_OP_pre(MAN_ARGS)
{
@@ -620,8 +608,6 @@ man_OP_pre(MAN_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
man_B_pre(MAN_ARGS)
{
@@ -630,16 +616,14 @@ man_B_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_I_pre(MAN_ARGS)
{
-
+
print_otag(h, TAG_I, 0, NULL);
return(1);
}
-/* ARGSUSED */
static int
man_literal_pre(MAN_ARGS)
{
@@ -653,7 +637,6 @@ man_literal_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_in_pre(MAN_ARGS)
{
@@ -662,7 +645,6 @@ man_in_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_ign_pre(MAN_ARGS)
{
@@ -670,7 +652,6 @@ man_ign_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_RS_pre(MAN_ARGS)
{
@@ -693,7 +674,6 @@ man_RS_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_UR_pre(MAN_ARGS)
{
diff --git a/contrib/mdocml/man_macro.c b/contrib/mdocml/man_macro.c
index 479d048..ea45a50 100644
--- a/contrib/mdocml/man_macro.c
+++ b/contrib/mdocml/man_macro.c
@@ -1,4 +1,4 @@
-/* $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.87 2014/07/30 23:01:39 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -40,17 +40,15 @@ static int blk_close(MACRO_PROT_ARGS);
static int blk_exp(MACRO_PROT_ARGS);
static int blk_imp(MACRO_PROT_ARGS);
static int in_line_eoln(MACRO_PROT_ARGS);
-static int man_args(struct man *, int,
+static int man_args(struct man *, int,
int *, char *, char **);
-static int rew_scope(enum man_type,
+static int rew_scope(enum man_type,
struct man *, enum mant);
-static enum rew rew_dohalt(enum mant, enum man_type,
+static enum rew rew_dohalt(enum mant, enum man_type,
const struct man_node *);
-static enum rew rew_block(enum mant, enum man_type,
+static enum rew rew_block(enum mant, enum man_type,
const struct man_node *);
-static void rew_warn(struct man *,
- struct man_node *, enum mandocerr);
const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_NSCOPED }, /* br */
@@ -91,85 +89,80 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
{ blk_close, 0 }, /* UE */
+ { in_line_eoln, 0 }, /* ll */
};
const struct man_macro * const man_macros = __man_macros;
-/*
- * Warn when "n" is an explicit non-roff macro.
- */
-static void
-rew_warn(struct man *man, struct man_node *n, enum mandocerr er)
-{
-
- if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
- return;
- if (MAN_VALID & n->flags)
- return;
- if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
- return;
-
- assert(er < MANDOCERR_FATAL);
- man_nmsg(man, n, er);
-}
-
-
-/*
- * Rewind scope. If a code "er" != MANDOCERR_MAX has been provided, it
- * will be used if an explicit block scope is being closed out.
- */
int
-man_unscope(struct man *man, const struct man_node *to,
- enum mandocerr er)
+man_unscope(struct man *man, const struct man_node *to)
{
struct man_node *n;
- assert(to);
-
man->next = MAN_NEXT_SIBLING;
+ to = to->parent;
+ n = man->last;
+ while (n != to) {
+
+ /* Reached the end of the document? */
+
+ if (to == NULL && ! (n->flags & MAN_VALID)) {
+ if (man->flags & (MAN_BLINE | MAN_ELINE) &&
+ man_macros[n->tok].flags & MAN_SCOPED) {
+ mandoc_vmsg(MANDOCERR_BLK_LINE,
+ man->parse, n->line, n->pos,
+ "EOF breaks %s",
+ man_macronames[n->tok]);
+ if (man->flags & MAN_ELINE)
+ man->flags &= ~MAN_ELINE;
+ else {
+ assert(n->type == MAN_HEAD);
+ n = n->parent;
+ man->flags &= ~MAN_BLINE;
+ }
+ man->last = n;
+ n = n->parent;
+ man_node_delete(man, man->last);
+ continue;
+ }
+ if (n->type == MAN_BLOCK &&
+ man_macros[n->tok].flags & MAN_EXPLICIT)
+ mandoc_msg(MANDOCERR_BLK_NOEND,
+ man->parse, n->line, n->pos,
+ man_macronames[n->tok]);
+ }
- /* LINTED */
- while (man->last != to) {
/*
- * Save the parent here, because we may delete the
- * man->last node in the post-validation phase and reset
- * it to man->last->parent, causing a step in the closing
- * out to be lost.
+ * We might delete the man->last node
+ * in the post-validation phase.
+ * Save a pointer to the parent such that
+ * we know where to continue the iteration.
*/
- n = man->last->parent;
- rew_warn(man, man->last, er);
+ man->last = n;
+ n = n->parent;
if ( ! man_valid_post(man))
return(0);
- man->last = n;
- assert(man->last);
}
-
- rew_warn(man, man->last, er);
- if ( ! man_valid_post(man))
- return(0);
-
return(1);
}
-
static enum rew
rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
{
- if (MAN_BLOCK == type && ntok == n->parent->tok &&
- MAN_BODY == n->parent->type)
+ if (MAN_BLOCK == type && ntok == n->parent->tok &&
+ MAN_BODY == n->parent->type)
return(REW_REWIND);
return(ntok == n->tok ? REW_HALT : REW_NOHALT);
}
-
/*
* There are three scope levels: scoped to the root (all), scoped to the
* section (all less sections), and scoped to subsections (all less
* sections and subsections).
*/
-static enum rew
+static enum rew
rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
{
enum rew c;
@@ -196,20 +189,20 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
return(REW_REWIND);
}
- /*
+ /*
* Next follow the implicit scope-smashings as defined by man.7:
* section, sub-section, etc.
*/
switch (tok) {
- case (MAN_SH):
+ case MAN_SH:
break;
- case (MAN_SS):
+ case MAN_SS:
/* Rewind to a section, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
return(c);
break;
- case (MAN_RS):
+ case MAN_RS:
/* Preserve empty paragraphs before RS. */
if (0 == n->nchild && (MAN_P == n->tok ||
MAN_PP == n->tok || MAN_LP == n->tok))
@@ -237,7 +230,6 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
return(REW_NOHALT);
}
-
/*
* Rewinding entails ascending the parse tree until a coherent point,
* for example, the `SH' macro will close out any intervening `SS'
@@ -249,9 +241,8 @@ rew_scope(enum man_type type, struct man *man, enum mant tok)
struct man_node *n;
enum rew c;
- /* LINTED */
for (n = man->last; n; n = n->parent) {
- /*
+ /*
* Whether we should stop immediately (REW_HALT), stop
* and rewind until this point (REW_REWIND), or keep
* rewinding (REW_NOHALT).
@@ -263,31 +254,30 @@ rew_scope(enum man_type type, struct man *man, enum mant tok)
break;
}
- /*
+ /*
* Rewind until the current point. Warn if we're a roff
* instruction that's mowing over explicit scopes.
*/
assert(n);
- return(man_unscope(man, n, MANDOCERR_MAX));
+ return(man_unscope(man, n));
}
/*
* Close out a generic explicit macro.
*/
-/* ARGSUSED */
int
blk_close(MACRO_PROT_ARGS)
{
- enum mant ntok;
+ enum mant ntok;
const struct man_node *nn;
switch (tok) {
- case (MAN_RE):
+ case MAN_RE:
ntok = MAN_RS;
break;
- case (MAN_UE):
+ case MAN_UE:
ntok = MAN_UR;
break;
default:
@@ -300,17 +290,16 @@ blk_close(MACRO_PROT_ARGS)
break;
if (NULL == nn) {
- man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
+ line, ppos, man_macronames[tok]);
if ( ! rew_scope(MAN_BLOCK, man, MAN_PP))
return(0);
- } else
- man_unscope(man, nn, MANDOCERR_MAX);
+ } else
+ man_unscope(man, nn);
return(1);
}
-
-/* ARGSUSED */
int
blk_exp(MACRO_PROT_ARGS)
{
@@ -343,22 +332,19 @@ blk_exp(MACRO_PROT_ARGS)
if (n->tok != tok)
continue;
assert(MAN_HEAD == n->type);
- man_unscope(man, n, MANDOCERR_MAX);
+ man_unscope(man, n);
break;
}
return(man_body_alloc(man, line, ppos, tok));
}
-
-
/*
* Parse an implicit-block macro. These contain a MAN_HEAD and a
* MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
* scopes, such as `SH' closing out an `SS', are defined in the rew
* routines.
*/
-/* ARGSUSED */
int
blk_imp(MACRO_PROT_ARGS)
{
@@ -410,8 +396,6 @@ blk_imp(MACRO_PROT_ARGS)
return(man_body_alloc(man, line, ppos, tok));
}
-
-/* ARGSUSED */
int
in_line_eoln(MACRO_PROT_ARGS)
{
@@ -438,7 +422,7 @@ in_line_eoln(MACRO_PROT_ARGS)
*/
if (n != man->last &&
- mandoc_eos(man->last->string, strlen(man->last->string), 0))
+ mandoc_eos(man->last->string, strlen(man->last->string)))
man->last->flags |= MAN_EOS;
/*
@@ -451,18 +435,11 @@ in_line_eoln(MACRO_PROT_ARGS)
assert( ! (MAN_NSCOPED & man_macros[tok].flags));
man->flags |= MAN_ELINE;
return(1);
- }
-
- /* Set ignorable context, if applicable. */
-
- if (MAN_NSCOPED & man_macros[tok].flags) {
- assert( ! (MAN_SCOPED & man_macros[tok].flags));
- man->flags |= MAN_ILINE;
}
assert(MAN_ROOT != man->last->type);
man->next = MAN_NEXT_SIBLING;
-
+
/*
* Rewind our element scope. Note that when TH is pruned, we'll
* be back at the root, so make sure that we don't clobber as
@@ -481,7 +458,7 @@ in_line_eoln(MACRO_PROT_ARGS)
assert(man->last);
/*
- * Same here regarding whether we're back at the root.
+ * Same here regarding whether we're back at the root.
*/
if (man->last->type != MAN_ROOT && ! man_valid_post(man))
@@ -495,7 +472,7 @@ int
man_macroend(struct man *man)
{
- return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT));
+ return(man_unscope(man, man->first));
}
static int
diff --git a/contrib/mdocml/man_term.c b/contrib/mdocml/man_term.c
index 4bd6244..c91c074 100644
--- a/contrib/mdocml/man_term.c
+++ b/contrib/mdocml/man_term.c
@@ -1,7 +1,7 @@
-/* $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */
+/* $Id: man_term.c,v 1.149 2014/06/20 23:02:31 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +28,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "man.h"
#include "term.h"
@@ -45,7 +46,7 @@ struct mtermp {
int pardist; /* vert. space before par., unit: [v] */
};
-#define DECL_ARGS struct termp *p, \
+#define DECL_ARGS struct termp *p, \
struct mtermp *mt, \
const struct man_node *n, \
const struct man_meta *meta
@@ -64,7 +65,7 @@ static void print_man_nodelist(DECL_ARGS);
static void print_man_node(DECL_ARGS);
static void print_man_head(struct termp *, const void *);
static void print_man_foot(struct termp *, const void *);
-static void print_bvspace(struct termp *,
+static void print_bvspace(struct termp *,
const struct man_node *, int);
static int pre_B(DECL_ARGS);
@@ -84,6 +85,7 @@ static int pre_ft(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
static int pre_literal(DECL_ARGS);
+static int pre_ll(DECL_ARGS);
static int pre_sp(DECL_ARGS);
static void post_IP(DECL_ARGS);
@@ -104,7 +106,7 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_PP, NULL, 0 }, /* PP */
{ pre_PP, NULL, 0 }, /* P */
{ pre_IP, post_IP, 0 }, /* IP */
- { pre_HP, post_HP, 0 }, /* HP */
+ { pre_HP, post_HP, 0 }, /* HP */
{ NULL, NULL, 0 }, /* SM */
{ pre_B, NULL, 0 }, /* SB */
{ pre_alternate, NULL, 0 }, /* BI */
@@ -133,10 +135,10 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
+ { pre_ll, NULL, MAN_NOTEXT }, /* ll */
};
-
void
terminal_man(void *arg, const struct man *man)
{
@@ -187,7 +189,6 @@ a2height(const struct termp *p, const char *cp)
return(term_vspan(p, &su));
}
-
static int
a2width(const struct termp *p, const char *cp)
{
@@ -226,7 +227,7 @@ print_bvspace(struct termp *p, const struct man_node *n, int pardist)
term_vspace(p);
}
-/* ARGSUSED */
+
static int
pre_ign(DECL_ARGS)
{
@@ -234,8 +235,14 @@ pre_ign(DECL_ARGS)
return(0);
}
+static int
+pre_ll(DECL_ARGS)
+{
+
+ term_setwidth(p, n->nchild ? n->child->string : NULL);
+ return(0);
+}
-/* ARGSUSED */
static int
pre_I(DECL_ARGS)
{
@@ -244,8 +251,6 @@ pre_I(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
pre_literal(DECL_ARGS)
{
@@ -266,14 +271,13 @@ pre_literal(DECL_ARGS)
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
- p->flags &= ~TERMP_NOBREAK;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
return(0);
}
-/* ARGSUSED */
static int
pre_PD(DECL_ARGS)
{
@@ -288,7 +292,6 @@ pre_PD(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_alternate(DECL_ARGS)
{
@@ -297,27 +300,27 @@ pre_alternate(DECL_ARGS)
int savelit, i;
switch (n->tok) {
- case (MAN_RB):
+ case MAN_RB:
font[0] = TERMFONT_NONE;
font[1] = TERMFONT_BOLD;
break;
- case (MAN_RI):
+ case MAN_RI:
font[0] = TERMFONT_NONE;
font[1] = TERMFONT_UNDER;
break;
- case (MAN_BR):
+ case MAN_BR:
font[0] = TERMFONT_BOLD;
font[1] = TERMFONT_NONE;
break;
- case (MAN_BI):
+ case MAN_BI:
font[0] = TERMFONT_BOLD;
font[1] = TERMFONT_UNDER;
break;
- case (MAN_IR):
+ case MAN_IR:
font[0] = TERMFONT_UNDER;
font[1] = TERMFONT_NONE;
break;
- case (MAN_IB):
+ case MAN_IB:
font[0] = TERMFONT_UNDER;
font[1] = TERMFONT_BOLD;
break;
@@ -340,7 +343,6 @@ pre_alternate(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_B(DECL_ARGS)
{
@@ -349,7 +351,6 @@ pre_B(DECL_ARGS)
return(1);
}
-/* ARGSUSED */
static int
pre_OP(DECL_ARGS)
{
@@ -372,7 +373,6 @@ pre_OP(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_ft(DECL_ARGS)
{
@@ -385,26 +385,26 @@ pre_ft(DECL_ARGS)
cp = n->child->string;
switch (*cp) {
- case ('4'):
+ case '4':
/* FALLTHROUGH */
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('B'):
+ case 'B':
term_fontrepl(p, TERMFONT_BOLD);
break;
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('I'):
+ case 'I':
term_fontrepl(p, TERMFONT_UNDER);
break;
- case ('P'):
+ case 'P':
term_fontlast(p);
break;
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('C'):
+ case 'C':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
term_fontrepl(p, TERMFONT_NONE);
break;
default:
@@ -413,7 +413,6 @@ pre_ft(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_in(DECL_ARGS)
{
@@ -447,7 +446,7 @@ pre_in(DECL_ARGS)
p->offset -= p->offset > v ? v : p->offset;
else if (less > 0)
p->offset += v;
- else
+ else
p->offset = v;
/* Don't let this creep beyond the right margin. */
@@ -458,8 +457,6 @@ pre_in(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
pre_sp(DECL_ARGS)
{
@@ -469,15 +466,15 @@ pre_sp(DECL_ARGS)
if ((NULL == n->prev && n->parent)) {
switch (n->parent->tok) {
- case (MAN_SH):
+ case MAN_SH:
/* FALLTHROUGH */
- case (MAN_SS):
+ case MAN_SS:
/* FALLTHROUGH */
- case (MAN_PP):
+ case MAN_PP:
/* FALLTHROUGH */
- case (MAN_LP):
+ case MAN_LP:
/* FALLTHROUGH */
- case (MAN_P):
+ case MAN_P:
/* FALLTHROUGH */
return(0);
default:
@@ -487,7 +484,7 @@ pre_sp(DECL_ARGS)
neg = 0;
switch (n->tok) {
- case (MAN_br):
+ case MAN_br:
len = 0;
break;
default:
@@ -515,8 +512,6 @@ pre_sp(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
pre_HP(DECL_ARGS)
{
@@ -525,17 +520,17 @@ pre_HP(DECL_ARGS)
const struct man_node *nn;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
print_bvspace(p, n, mt->pardist);
return(1);
- case (MAN_BODY):
+ case MAN_BODY:
break;
default:
return(0);
}
if ( ! (MANT_LITERAL & mt->fl)) {
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
}
@@ -561,16 +556,14 @@ pre_HP(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_HP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
- p->flags &= ~TERMP_NOBREAK;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0;
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
@@ -580,14 +573,12 @@ post_HP(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_PP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n, mt->pardist);
break;
@@ -599,8 +590,6 @@ pre_PP(DECL_ARGS)
return(MAN_HEAD != n->type);
}
-
-/* ARGSUSED */
static int
pre_IP(DECL_ARGS)
{
@@ -609,14 +598,14 @@ pre_IP(DECL_ARGS)
int savelit, ival;
switch (n->type) {
- case (MAN_BODY):
+ case MAN_BODY:
p->flags |= TERMP_NOSPACE;
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case (MAN_BLOCK):
+ case MAN_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
@@ -633,7 +622,7 @@ pre_IP(DECL_ARGS)
len = (size_t)ival;
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
/* Handle zero-width lengths. */
if (0 == len)
len = term_len(p, 1);
@@ -656,9 +645,10 @@ pre_IP(DECL_ARGS)
mt->fl |= MANT_LITERAL;
return(0);
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset + len;
- p->rmargin = p->maxrmargin;
+ p->rmargin = p->maxrmargin > p->offset ?
+ p->maxrmargin : p->offset;
break;
default:
break;
@@ -667,20 +657,18 @@ pre_IP(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_IP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
p->rmargin = p->maxrmargin;
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
p->offset = mt->offset;
break;
@@ -689,8 +677,6 @@ post_IP(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_TP(DECL_ARGS)
{
@@ -699,14 +685,14 @@ pre_TP(DECL_ARGS)
int savelit, ival;
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case (MAN_BODY):
+ case MAN_BODY:
p->flags |= TERMP_NOSPACE;
break;
- case (MAN_BLOCK):
+ case MAN_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
@@ -719,12 +705,12 @@ pre_TP(DECL_ARGS)
/* Calculate offset. */
if (NULL != (nn = n->parent->head->child))
- if (nn->string && nn->parent->line == nn->line)
+ if (nn->string && 0 == (MAN_LINE & nn->flags))
if ((ival = a2width(p, nn->string)) >= 0)
len = (size_t)ival;
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
/* Handle zero-length properly. */
if (0 == len)
len = term_len(p, 1);
@@ -736,9 +722,14 @@ pre_TP(DECL_ARGS)
mt->fl &= ~MANT_LITERAL;
/* Don't print same-line elements. */
- for (nn = n->child; nn; nn = nn->next)
- if (nn->line > n->line)
- print_man_node(p, mt, nn, meta);
+ nn = n->child;
+ while (NULL != nn && 0 == (MAN_LINE & nn->flags))
+ nn = nn->next;
+
+ while (NULL != nn) {
+ print_man_node(p, mt, nn, meta);
+ nn = nn->next;
+ }
if (savelit)
mt->fl |= MANT_LITERAL;
@@ -746,9 +737,10 @@ pre_TP(DECL_ARGS)
mt->lmargin[mt->lmargincur] = (size_t)ival;
return(0);
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset + len;
- p->rmargin = p->maxrmargin;
+ p->rmargin = p->maxrmargin > p->offset ?
+ p->maxrmargin : p->offset;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
break;
@@ -759,17 +751,15 @@ pre_TP(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_TP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_flushln(p);
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
p->offset = mt->offset;
break;
@@ -778,15 +768,13 @@ post_TP(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_SS(DECL_ARGS)
{
int i;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@@ -799,11 +787,11 @@ pre_SS(DECL_ARGS)
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = term_len(p, 3);
break;
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset;
break;
default:
@@ -813,17 +801,15 @@ pre_SS(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_SS(DECL_ARGS)
{
-
+
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_newln(p);
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
break;
default:
@@ -831,15 +817,13 @@ post_SS(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_SH(DECL_ARGS)
{
int i;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@@ -853,11 +837,11 @@ pre_SH(DECL_ARGS)
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = 0;
break;
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset;
break;
default:
@@ -867,17 +851,15 @@ pre_SH(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_SH(DECL_ARGS)
{
-
+
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_newln(p);
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
break;
default:
@@ -885,7 +867,6 @@ post_SH(DECL_ARGS)
}
}
-/* ARGSUSED */
static int
pre_RS(DECL_ARGS)
{
@@ -893,10 +874,10 @@ pre_RS(DECL_ARGS)
size_t sz;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
term_newln(p);
return(1);
- case (MAN_HEAD):
+ case MAN_HEAD:
return(0);
default:
break;
@@ -905,12 +886,13 @@ pre_RS(DECL_ARGS)
sz = term_len(p, p->defindent);
if (NULL != (n = n->parent->head->child))
- if ((ival = a2width(p, n->string)) >= 0)
+ if ((ival = a2width(p, n->string)) >= 0)
sz = (size_t)ival;
mt->offset += sz;
- p->rmargin = p->maxrmargin;
- p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin;
+ p->offset = mt->offset;
+ p->rmargin = p->maxrmargin > p->offset ?
+ p->maxrmargin : p->offset;
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
@@ -919,7 +901,6 @@ pre_RS(DECL_ARGS)
return(1);
}
-/* ARGSUSED */
static void
post_RS(DECL_ARGS)
{
@@ -927,9 +908,9 @@ post_RS(DECL_ARGS)
size_t sz;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
return;
- case (MAN_HEAD):
+ case MAN_HEAD:
return;
default:
term_newln(p);
@@ -938,8 +919,8 @@ post_RS(DECL_ARGS)
sz = term_len(p, p->defindent);
- if (NULL != (n = n->parent->head->child))
- if ((ival = a2width(p, n->string)) >= 0)
+ if (NULL != (n = n->parent->head->child))
+ if ((ival = a2width(p, n->string)) >= 0)
sz = (size_t)ival;
mt->offset = mt->offset < sz ? 0 : mt->offset - sz;
@@ -949,7 +930,6 @@ post_RS(DECL_ARGS)
mt->lmargincur = mt->lmarginsz;
}
-/* ARGSUSED */
static int
pre_UR(DECL_ARGS)
{
@@ -957,7 +937,6 @@ pre_UR(DECL_ARGS)
return (MAN_HEAD != n->type);
}
-/* ARGSUSED */
static void
post_UR(DECL_ARGS)
{
@@ -982,7 +961,7 @@ print_man_node(DECL_ARGS)
int c;
switch (n->type) {
- case(MAN_TEXT):
+ case MAN_TEXT:
/*
* If we have a blank line, output a vertical space.
* If we have a space as the first character, break
@@ -997,15 +976,15 @@ print_man_node(DECL_ARGS)
term_word(p, n->string);
goto out;
- case (MAN_EQN):
+ case MAN_EQN:
term_eqn(p, n->eqn);
return;
- case (MAN_TBL):
+ case MAN_TBL:
/*
* Tables are preceded by a newline. Then process a
* table line, which will cause line termination,
*/
- if (TBL_SPAN_FIRST & n->span->flags)
+ if (TBL_SPAN_FIRST & n->span->flags)
term_newln(p);
term_tbl(p, n->span);
return;
@@ -1037,7 +1016,7 @@ out:
* more specific than this.
*/
if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
- (NULL == n->next || n->next->line > n->line)) {
+ (NULL == n->next || MAN_LINE & n->next->flags)) {
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
@@ -1068,13 +1047,12 @@ print_man_nodelist(DECL_ARGS)
print_man_nodelist(p, mt, n->next, meta);
}
-
static void
print_man_foot(struct termp *p, const void *arg)
{
- char title[BUFSIZ];
- size_t datelen;
- const struct man_meta *meta;
+ const struct man_meta *meta;
+ char *title;
+ size_t datelen;
meta = (const struct man_meta *)arg;
assert(meta->title);
@@ -1083,7 +1061,8 @@ print_man_foot(struct termp *p, const void *arg)
term_fontrepl(p, TERMFONT_NONE);
- term_vspace(p);
+ if (meta->hasbody)
+ term_vspace(p);
/*
* Temporary, undocumented option to imitate mdoc(7) output.
@@ -1092,13 +1071,16 @@ print_man_foot(struct termp *p, const void *arg)
*/
if ( ! p->mdocstyle) {
- term_vspace(p);
- term_vspace(p);
- snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+ if (meta->hasbody) {
+ term_vspace(p);
+ term_vspace(p);
+ }
+ mandoc_asprintf(&title, "%s(%s)",
+ meta->title, meta->msec);
} else if (meta->source) {
- strlcpy(title, meta->source, BUFSIZ);
+ title = mandoc_strdup(meta->source);
} else {
- title[0] = '\0';
+ title = mandoc_strdup("");
}
datelen = term_strlen(p, meta->date);
@@ -1134,38 +1116,35 @@ print_man_foot(struct termp *p, const void *arg)
term_word(p, title);
term_flushln(p);
+ free(title);
}
-
static void
print_man_head(struct termp *p, const void *arg)
{
- char buf[BUFSIZ], title[BUFSIZ];
- size_t buflen, titlen;
- const struct man_meta *meta;
+ const struct man_meta *meta;
+ const char *volume;
+ char *title;
+ size_t vollen, titlen;
meta = (const struct man_meta *)arg;
assert(meta->title);
assert(meta->msec);
- if (meta->vol)
- strlcpy(buf, meta->vol, BUFSIZ);
- else
- buf[0] = '\0';
- buflen = term_strlen(p, buf);
+ volume = NULL == meta->vol ? "" : meta->vol;
+ vollen = term_strlen(p, volume);
/* Top left corner: manual title and section. */
- snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+ mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->offset = 0;
- p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
- (p->maxrmargin -
- term_strlen(p, buf) + term_len(p, 1)) / 2 :
- p->maxrmargin - buflen;
+ p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
+ (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
+ p->maxrmargin - vollen;
term_word(p, title);
term_flushln(p);
@@ -1174,10 +1153,10 @@ print_man_head(struct termp *p, const void *arg)
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
- p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
+ p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
p->maxrmargin - titlen : p->maxrmargin;
- term_word(p, buf);
+ term_word(p, volume);
term_flushln(p);
/* Top right corner: title and section, again. */
@@ -1196,7 +1175,7 @@ print_man_head(struct termp *p, const void *arg)
p->offset = 0;
p->rmargin = p->maxrmargin;
- /*
+ /*
* Groff prints three blank lines before the content.
* Do the same, except in the temporary, undocumented
* mode imitating mdoc(7) output.
@@ -1207,4 +1186,5 @@ print_man_head(struct termp *p, const void *arg)
term_vspace(p);
term_vspace(p);
}
+ free(title);
}
diff --git a/contrib/mdocml/man_validate.c b/contrib/mdocml/man_validate.c
index da2e557..c17eb9e 100644
--- a/contrib/mdocml/man_validate.c
+++ b/contrib/mdocml/man_validate.c
@@ -1,7 +1,7 @@
-/* $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */
+/* $Id: man_validate.c,v 1.105 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -32,6 +32,7 @@
#include "man.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libman.h"
#include "libmandoc.h"
@@ -39,21 +40,14 @@
typedef int (*v_check)(CHKARGS);
-struct man_valid {
- v_check *pres;
- v_check *posts;
-};
-
static int check_eq0(CHKARGS);
static int check_eq2(CHKARGS);
static int check_le1(CHKARGS);
-static int check_ge2(CHKARGS);
static int check_le5(CHKARGS);
-static int check_head1(CHKARGS);
static int check_par(CHKARGS);
static int check_part(CHKARGS);
static int check_root(CHKARGS);
-static void check_text(CHKARGS);
+static int check_text(CHKARGS);
static int post_AT(CHKARGS);
static int post_IP(CHKARGS);
@@ -61,174 +55,122 @@ static int post_vs(CHKARGS);
static int post_fi(CHKARGS);
static int post_ft(CHKARGS);
static int post_nf(CHKARGS);
-static int post_sec(CHKARGS);
static int post_TH(CHKARGS);
static int post_UC(CHKARGS);
-static int pre_sec(CHKARGS);
-
-static v_check posts_at[] = { post_AT, NULL };
-static v_check posts_br[] = { post_vs, check_eq0, NULL };
-static v_check posts_eq0[] = { check_eq0, NULL };
-static v_check posts_eq2[] = { check_eq2, NULL };
-static v_check posts_fi[] = { check_eq0, post_fi, NULL };
-static v_check posts_ft[] = { post_ft, NULL };
-static v_check posts_ip[] = { post_IP, NULL };
-static v_check posts_le1[] = { check_le1, NULL };
-static v_check posts_nf[] = { check_eq0, post_nf, NULL };
-static v_check posts_par[] = { check_par, NULL };
-static v_check posts_part[] = { check_part, NULL };
-static v_check posts_sec[] = { post_sec, NULL };
-static v_check posts_sp[] = { post_vs, check_le1, NULL };
-static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL };
-static v_check posts_uc[] = { post_UC, NULL };
-static v_check posts_ur[] = { check_head1, check_part, NULL };
-static v_check pres_sec[] = { pre_sec, NULL };
-
-static const struct man_valid man_valids[MAN_MAX] = {
- { NULL, posts_br }, /* br */
- { NULL, posts_th }, /* TH */
- { pres_sec, posts_sec }, /* SH */
- { pres_sec, posts_sec }, /* SS */
- { NULL, NULL }, /* TP */
- { NULL, posts_par }, /* LP */
- { NULL, posts_par }, /* PP */
- { NULL, posts_par }, /* P */
- { NULL, posts_ip }, /* IP */
- { NULL, NULL }, /* HP */
- { NULL, NULL }, /* SM */
- { NULL, NULL }, /* SB */
- { NULL, NULL }, /* BI */
- { NULL, NULL }, /* IB */
- { NULL, NULL }, /* BR */
- { NULL, NULL }, /* RB */
- { NULL, NULL }, /* R */
- { NULL, NULL }, /* B */
- { NULL, NULL }, /* I */
- { NULL, NULL }, /* IR */
- { NULL, NULL }, /* RI */
- { NULL, posts_eq0 }, /* na */
- { NULL, posts_sp }, /* sp */
- { NULL, posts_nf }, /* nf */
- { NULL, posts_fi }, /* fi */
- { NULL, NULL }, /* RE */
- { NULL, posts_part }, /* RS */
- { NULL, NULL }, /* DT */
- { NULL, posts_uc }, /* UC */
- { NULL, posts_le1 }, /* PD */
- { NULL, posts_at }, /* AT */
- { NULL, NULL }, /* in */
- { NULL, posts_ft }, /* ft */
- { NULL, posts_eq2 }, /* OP */
- { NULL, posts_nf }, /* EX */
- { NULL, posts_fi }, /* EE */
- { NULL, posts_ur }, /* UR */
- { NULL, NULL }, /* UE */
+static int post_UR(CHKARGS);
+
+static v_check man_valids[MAN_MAX] = {
+ post_vs, /* br */
+ post_TH, /* TH */
+ NULL, /* SH */
+ NULL, /* SS */
+ NULL, /* TP */
+ check_par, /* LP */
+ check_par, /* PP */
+ check_par, /* P */
+ post_IP, /* IP */
+ NULL, /* HP */
+ NULL, /* SM */
+ NULL, /* SB */
+ NULL, /* BI */
+ NULL, /* IB */
+ NULL, /* BR */
+ NULL, /* RB */
+ NULL, /* R */
+ NULL, /* B */
+ NULL, /* I */
+ NULL, /* IR */
+ NULL, /* RI */
+ check_eq0, /* na */
+ post_vs, /* sp */
+ post_nf, /* nf */
+ post_fi, /* fi */
+ NULL, /* RE */
+ check_part, /* RS */
+ NULL, /* DT */
+ post_UC, /* UC */
+ check_le1, /* PD */
+ post_AT, /* AT */
+ NULL, /* in */
+ post_ft, /* ft */
+ check_eq2, /* OP */
+ post_nf, /* EX */
+ post_fi, /* EE */
+ post_UR, /* UR */
+ NULL, /* UE */
+ NULL, /* ll */
};
int
-man_valid_pre(struct man *man, struct man_node *n)
-{
- v_check *cp;
-
- switch (n->type) {
- case (MAN_TEXT):
- /* FALLTHROUGH */
- case (MAN_ROOT):
- /* FALLTHROUGH */
- case (MAN_EQN):
- /* FALLTHROUGH */
- case (MAN_TBL):
- return(1);
- default:
- break;
- }
-
- if (NULL == (cp = man_valids[n->tok].pres))
- return(1);
- for ( ; *cp; cp++)
- if ( ! (*cp)(man, n))
- return(0);
- return(1);
-}
-
-
-int
man_valid_post(struct man *man)
{
+ struct man_node *n;
v_check *cp;
- if (MAN_VALID & man->last->flags)
+ n = man->last;
+ if (n->flags & MAN_VALID)
return(1);
- man->last->flags |= MAN_VALID;
+ n->flags |= MAN_VALID;
- switch (man->last->type) {
- case (MAN_TEXT):
- check_text(man, man->last);
- return(1);
- case (MAN_ROOT):
- return(check_root(man, man->last));
- case (MAN_EQN):
+ switch (n->type) {
+ case MAN_TEXT:
+ return(check_text(man, n));
+ case MAN_ROOT:
+ return(check_root(man, n));
+ case MAN_EQN:
/* FALLTHROUGH */
- case (MAN_TBL):
+ case MAN_TBL:
return(1);
default:
- break;
+ cp = man_valids + n->tok;
+ return(*cp ? (*cp)(man, n) : 1);
}
-
- if (NULL == (cp = man_valids[man->last->tok].posts))
- return(1);
- for ( ; *cp; cp++)
- if ( ! (*cp)(man, man->last))
- return(0);
-
- return(1);
}
-
static int
-check_root(CHKARGS)
+check_root(CHKARGS)
{
- if (MAN_BLINE & man->flags)
- man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
- else if (MAN_ELINE & man->flags)
- man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
+ assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
- man->flags &= ~MAN_BLINE;
- man->flags &= ~MAN_ELINE;
+ if (NULL == man->first->child)
+ mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
+ n->line, n->pos, NULL);
+ else
+ man->meta.hasbody = 1;
- if (NULL == man->first->child) {
- man_nmsg(man, n, MANDOCERR_NODOCBODY);
- return(0);
- } else if (NULL == man->meta.title) {
- man_nmsg(man, n, MANDOCERR_NOTITLE);
+ if (NULL == man->meta.title) {
+ mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
+ n->line, n->pos, NULL);
/*
* If a title hasn't been set, do so now (by
* implication, date and section also aren't set).
*/
- man->meta.title = mandoc_strdup("unknown");
- man->meta.msec = mandoc_strdup("1");
- man->meta.date = mandoc_normdate
- (man->parse, NULL, n->line, n->pos);
+ man->meta.title = mandoc_strdup("");
+ man->meta.msec = mandoc_strdup("");
+ man->meta.date = man->quick ? mandoc_strdup("") :
+ mandoc_normdate(man->parse, NULL, n->line, n->pos);
}
return(1);
}
-static void
+static int
check_text(CHKARGS)
{
char *cp, *p;
if (MAN_LITERAL & man->flags)
- return;
+ return(1);
cp = n->string;
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
- man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB);
+ mandoc_msg(MANDOCERR_FI_TAB, man->parse,
+ n->line, n->pos + (p - cp), NULL);
+ return(1);
}
#define INEQ_DEFINE(x, ineq, name) \
@@ -238,26 +180,25 @@ check_##name(CHKARGS) \
if (n->nchild ineq (x)) \
return(1); \
mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
- "line arguments %s %d (have %d)", \
- #ineq, (x), n->nchild); \
+ "line arguments %s %d (have %d)", \
+ #ineq, (x), n->nchild); \
return(1); \
}
INEQ_DEFINE(0, ==, eq0)
INEQ_DEFINE(2, ==, eq2)
INEQ_DEFINE(1, <=, le1)
-INEQ_DEFINE(2, >=, ge2)
INEQ_DEFINE(5, <=, le5)
static int
-check_head1(CHKARGS)
+post_UR(CHKARGS)
{
if (MAN_HEAD == n->type && 1 != n->nchild)
mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
n->pos, "line arguments eq 1 (have %d)", n->nchild);
- return(1);
+ return(check_part(man, n));
}
static int
@@ -272,27 +213,27 @@ post_ft(CHKARGS)
ok = 0;
cp = n->child->string;
switch (*cp) {
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('4'):
+ case '4':
/* FALLTHROUGH */
- case ('I'):
+ case 'I':
/* FALLTHROUGH */
- case ('P'):
+ case 'P':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
if ('\0' == cp[1])
ok = 1;
break;
- case ('B'):
+ case 'B':
if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
ok = 1;
break;
- case ('C'):
+ case 'C':
if ('W' == cp[1] && '\0' == cp[2])
ok = 1;
break;
@@ -301,69 +242,51 @@ post_ft(CHKARGS)
}
if (0 == ok) {
- mandoc_vmsg
- (MANDOCERR_BADFONT, man->parse,
- n->line, n->pos, "%s", cp);
+ mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
+ n->line, n->pos, "ft %s", cp);
*cp = '\0';
}
if (1 < n->nchild)
- mandoc_vmsg
- (MANDOCERR_ARGCOUNT, man->parse, n->line,
- n->pos, "want one child (have %d)",
- n->nchild);
-
- return(1);
-}
-
-static int
-pre_sec(CHKARGS)
-{
+ mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
+ n->pos, "want one child (have %d)", n->nchild);
- if (MAN_BLOCK == n->type)
- man->flags &= ~MAN_LITERAL;
return(1);
}
static int
-post_sec(CHKARGS)
-{
-
- if ( ! (MAN_HEAD == n->type && 0 == n->nchild))
- return(1);
-
- man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT);
- return(0);
-}
-
-static int
check_part(CHKARGS)
{
if (MAN_BODY == n->type && 0 == n->nchild)
- mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
- n->pos, "want children (have none)");
+ mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
+ n->pos, "want children (have none)");
return(1);
}
-
static int
check_par(CHKARGS)
{
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
if (0 == n->body->nchild)
man_node_delete(man, n);
break;
- case (MAN_BODY):
+ case MAN_BODY:
if (0 == n->nchild)
- man_nmsg(man, n, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ man->parse, n->line, n->pos,
+ "%s empty", man_macronames[n->tok]);
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
if (n->nchild)
- man_nmsg(man, n, MANDOCERR_ARGSLOST);
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ man->parse, n->line, n->pos,
+ "%s %s%s", man_macronames[n->tok],
+ n->child->string,
+ n->nchild > 1 ? " ..." : "");
break;
default:
break;
@@ -377,13 +300,15 @@ post_IP(CHKARGS)
{
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
if (0 == n->head->nchild && 0 == n->body->nchild)
man_node_delete(man, n);
break;
- case (MAN_BODY):
+ case MAN_BODY:
if (0 == n->parent->head->nchild && 0 == n->nchild)
- man_nmsg(man, n, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ man->parse, n->line, n->pos,
+ "%s empty", man_macronames[n->tok]);
break;
default:
break;
@@ -394,8 +319,10 @@ post_IP(CHKARGS)
static int
post_TH(CHKARGS)
{
+ struct man_node *nb;
const char *p;
- int line, pos;
+
+ check_le5(man, n);
free(man->meta.title);
free(man->meta.vol);
@@ -403,10 +330,10 @@ post_TH(CHKARGS)
free(man->meta.msec);
free(man->meta.date);
- line = n->line;
- pos = n->pos;
man->meta.title = man->meta.vol = man->meta.date =
- man->meta.msec = man->meta.source = NULL;
+ man->meta.msec = man->meta.source = NULL;
+
+ nb = n;
/* ->TITLE<- MSEC DATE SOURCE VOL */
@@ -414,15 +341,21 @@ post_TH(CHKARGS)
if (n && n->string) {
for (p = n->string; '\0' != *p; p++) {
/* Only warn about this once... */
- if (isalpha((unsigned char)*p) &&
- ! isupper((unsigned char)*p)) {
- man_nmsg(man, n, MANDOCERR_UPPERCASE);
+ if (isalpha((unsigned char)*p) &&
+ ! isupper((unsigned char)*p)) {
+ mandoc_vmsg(MANDOCERR_TITLE_CASE,
+ man->parse, n->line,
+ n->pos + (p - n->string),
+ "TH %s", n->string);
break;
}
}
man->meta.title = mandoc_strdup(n->string);
- } else
+ } else {
man->meta.title = mandoc_strdup("");
+ mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
+ nb->line, nb->pos, "TH");
+ }
/* TITLE ->MSEC<- DATE SOURCE VOL */
@@ -430,19 +363,27 @@ post_TH(CHKARGS)
n = n->next;
if (n && n->string)
man->meta.msec = mandoc_strdup(n->string);
- else
+ else {
man->meta.msec = mandoc_strdup("");
+ mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
+ nb->line, nb->pos, "TH %s", man->meta.title);
+ }
/* TITLE MSEC ->DATE<- SOURCE VOL */
if (n)
n = n->next;
if (n && n->string && '\0' != n->string[0]) {
- pos = n->pos;
- man->meta.date = mandoc_normdate
- (man->parse, n->string, line, pos);
- } else
+ man->meta.date = man->quick ?
+ mandoc_strdup(n->string) :
+ mandoc_normdate(man->parse, n->string,
+ n->line, n->pos);
+ } else {
man->meta.date = mandoc_strdup("");
+ mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
+ n ? n->line : nb->line,
+ n ? n->pos : nb->pos, "TH");
+ }
/* TITLE MSEC DATE ->SOURCE<- VOL */
@@ -470,8 +411,11 @@ static int
post_nf(CHKARGS)
{
+ check_eq0(man, n);
+
if (MAN_LITERAL & man->flags)
- man_nmsg(man, n, MANDOCERR_SCOPEREP);
+ mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
+ n->line, n->pos, "nf");
man->flags |= MAN_LITERAL;
return(1);
@@ -481,8 +425,11 @@ static int
post_fi(CHKARGS)
{
+ check_eq0(man, n);
+
if ( ! (MAN_LITERAL & man->flags))
- man_nmsg(man, n, MANDOCERR_WNOSCOPE);
+ mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
+ n->line, n->pos, "fi");
man->flags &= ~MAN_LITERAL;
return(1);
@@ -568,17 +515,24 @@ static int
post_vs(CHKARGS)
{
+ if (n->tok == MAN_br)
+ check_eq0(man, n);
+ else
+ check_le1(man, n);
+
if (NULL != n->prev)
return(1);
switch (n->parent->tok) {
- case (MAN_SH):
+ case MAN_SH:
/* FALLTHROUGH */
- case (MAN_SS):
- man_nmsg(man, n, MANDOCERR_IGNPAR);
+ case MAN_SS:
+ mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
+ "%s after %s", man_macronames[n->tok],
+ man_macronames[n->parent->tok]);
/* FALLTHROUGH */
- case (MAN_MAX):
- /*
+ case MAN_MAX:
+ /*
* Don't warn about this because it occurs in pod2man
* and would cause considerable (unfixable) warnage.
*/
diff --git a/contrib/mdocml/mandoc.1 b/contrib/mdocml/mandoc.1
index 0657bc6..e9f7375 100644
--- a/contrib/mdocml/mandoc.1
+++ b/contrib/mdocml/mandoc.1
@@ -1,7 +1,7 @@
-.\" $Id: mandoc.1,v 1.103 2013/07/13 19:41:16 schwarze Exp $
+.\" $Id: mandoc.1,v 1.106 2014/08/08 01:50:59 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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.
.\"
-.Dd $Mdocdate: July 13 2013 $
+.Dd $Mdocdate: August 8 2014 $
.Dt MANDOC 1
.Os
.Sh NAME
@@ -496,30 +496,28 @@ parser:
.Pp
.Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man
.Sh DIAGNOSTICS
-Standard error messages reporting parsing errors are prefixed by
+Messages displayed by
+.Nm
+follow this format:
.Pp
-.Sm off
-.D1 Ar file : line : column : \ level :
-.Sm on
+.D1 Nm Ns : Ar file : Ns Ar line : Ns Ar column : level : message : macro args
.Pp
-where the fields have the following meanings:
-.Bl -tag -width "column"
-.It Ar file
-The name of the input file causing the message.
-.It Ar line
-The line number in that input file.
-Line numbering starts at 1.
-.It Ar column
-The column number in that input file.
-Column numbering starts at 1.
-If the issue is caused by a word, the column number usually
-points to the first character of the word.
-.It Ar level
-The message level, printed in capital letters.
-.El
+Line and column numbers start at 1.
+Both are omitted for messages referring to an input file as a whole.
+Macro names and arguments are omitted where meaningless.
+Fatal messages about invalid command line arguments
+or operating system errors, for example when memory is exhausted,
+may also omit the
+.Ar file
+and
+.Ar level
+fields.
.Pp
Message levels have the following meanings:
.Bl -tag -width "warning"
+.It Cm syserr
+Opening or reading an input file failed, so the parser cannot
+even be started and no output is produced from that input file.
.It Cm fatal
The parser is unable to parse a given input file at all.
No formatted output is produced from that input file.
@@ -551,13 +549,836 @@ levels are hidden unless their level, or a lower level, is requested using a
option or
.Fl T Ns Cm lint
output mode.
-.Pp
+.Ss Warnings related to the document prologue
+.Bl -ohang
+.It Sy "missing manual title, using UNTITLED"
+.Pq mdoc
+A
+.Ic \&Dt
+macro has no arguments, or there is no
+.Ic \&Dt
+macro before the first non-prologue macro.
+.It Sy "missing manual title, using \(dq\(dq"
+.Pq man
+There is no
+.Ic \&TH
+macro, or it has no arguments.
+.It Sy "lower case character in document title"
+.Pq mdoc , man
+The title is still used as given in the
+.Ic \&Dt
+or
+.Ic \&TH
+macro.
+.It Sy "missing manual section, using \(dq\(dq"
+.Pq mdoc , man
+A
+.Ic \&Dt
+or
+.Ic \&TH
+macro lacks the mandatory section argument.
+.It Sy "unknown manual section"
+.Pq mdoc
+The section number in a
+.Ic \&Dt
+line is invalid, but still used.
+.It Sy "unknown manual volume or arch"
+.Pq mdoc
+The volume name in a
+.Ic \&Dt
+line is invalid, but still used.
+The manual is assumed to be architecture-independent.
+.It Sy "missing date, using today's date"
+.Pq mdoc, man
+The document was parsed as
+.Xr mdoc 7
+and it has no
+.Ic \&Dd
+macro, or the
+.Ic \&Dd
+macro has no arguments or only empty arguments;
+or the document was parsed as
+.Xr man 7
+and it has no
+.Ic \&TH
+macro, or the
+.Ic \&TH
+macro has less than three arguments or its third argument is empty.
+.It Sy "cannot parse date, using it verbatim"
+.Pq mdoc , man
+The date given in a
+.Ic \&Dd
+or
+.Ic \&TH
+macro does not follow the conventional format.
+.It Sy "missing Os macro, using \(dq\(dq"
+.Pq mdoc
+The default or current system is not shown in this case.
+.It Sy "duplicate prologue macro"
+.Pq mdoc
+One of the prologue macros occurs more than once.
+The last instance overrides all previous ones.
+.It Sy "late prologue macro"
+.Pq mdoc
+A
+.Ic \&Dd
+or
+.Ic \&Os
+macro occurs after some non-prologue macro, but still takes effect.
+.It Sy "skipping late title macro"
+.Pq mdoc
+The
+.Ic \&Dt
+macro can only occur before the first non-prologue macro
+because traditional formatters write the page header
+before parsing the document body.
+Even though this technical restriction does not apply to
+.Nm ,
+traditional semantics is preserved.
+The late macro is discarded including its arguments.
+.It Sy "prologue macros out of order"
+.Pq mdoc
+The prologue macros are not given in the conventional order
+.Ic \&Dd ,
+.Ic \&Dt ,
+.Ic \&Os .
+All three macros are used even when given in another order.
+.El
+.Ss Warnings regarding document structure
+.Bl -ohang
+.It Sy ".so is fragile, better use ln(1)"
+.Pq roff
+Including files only works when the parser program runs with the correct
+current working directory.
+.It Sy "no document body"
+.Pq mdoc , man
+The document body contains neither text nor macros.
+An empty document is shown, consisting only of a header and a footer line.
+.It Sy "content before first section header"
+.Pq mdoc , man
+Some macros or text precede the first
+.Ic \&Sh
+or
+.Ic \&SH
+section header.
+The offending macros and text are parsed and added to the top level
+of the syntax tree, outside any section block.
+.It Sy "first section is not NAME"
+.Pq mdoc
+The argument of the first
+.Ic \&Sh
+macro is not
+.Sq NAME .
+This may confuse
+.Xr makewhatis 8
+and
+.Xr apropos 1 .
+.It Sy "bad NAME section contents"
+.Pq mdoc
+The last node in the NAME section is not an
+.Ic \&Nd
+macro, or any preceding macro is not
+.Ic \&Nm ,
+or the NAME section is completely empty.
+This may confuse
+.Xr makewhatis 8
+and
+.Xr apropos 1 .
+.It Sy "sections out of conventional order"
+.Pq mdoc
+A standard section occurs after another section it usually precedes.
+All section titles are used as given,
+and the order of sections is not changed.
+.It Sy "duplicate section title"
+.Pq mdoc
+The same standard section title occurs more than once.
+.It Sy "unexpected section"
+.Pq mdoc
+A standard section header occurs in a section of the manual
+where it normally isn't useful.
+.El
+.Ss "Warnings related to macros and nesting"
+.Bl -ohang
+.It Sy "obsolete macro"
+.Pq mdoc
+See the
+.Xr mdoc 7
+manual for replacements.
+.It Sy "skipping paragraph macro"
+In
+.Xr mdoc 7
+documents, this happens
+.Bl -dash -compact
+.It
+at the beginning and end of sections and subsections
+.It
+right before non-compact lists and displays
+.It
+at the end of items in non-column, non-compact lists
+.It
+and for multiple consecutive paragraph macros.
+.El
+In
+.Xr man 7
+documents, it happens
+.Bl -dash -compact
+.It
+for empty
+.Ic \&P ,
+.Ic \&PP ,
+and
+.Ic \&LP
+macros
+.It
+for
+.Ic \&IP
+macros having neither head nor body arguments
+.It
+for
+.Ic \&br
+or
+.Ic \&sp
+right after
+.Ic \&SH
+or
+.Ic \&SS
+.El
+.It Sy "moving paragraph macro out of list"
+.Pq mdoc
+A list item in a
+.Ic \&Bl
+list contains a trailing paragraph macro.
+The paragraph macro is moved after the end of the list.
+.It Sy "skipping no-space macro"
+.Pq mdoc
+An input line begins with an
+.Ic \&Ns
+macro.
+The macro is ignored.
+.It Sy "blocks badly nested"
+.Pq mdoc
+If two blocks intersect, one should completely contain the other.
+Otherwise, rendered output is likely to look strange in any output
+format, and rendering in SGML-based output formats is likely to be
+outright wrong because such languages do not support badly nested
+blocks at all.
+Typical examples of badly nested blocks are
+.Qq Ic \&Ao \&Bo \&Ac \&Bc
+and
+.Qq Ic \&Ao \&Bq \&Ac .
+In these examples,
+.Ic \&Ac
+breaks
+.Ic \&Bo
+and
+.Ic \&Bq ,
+respectively.
+.It Sy "nested displays are not portable"
+.Pq mdoc
+A
+.Ic \&Bd ,
+.Ic \&D1 ,
+or
+.Ic \&Dl
+display occurs nested inside another
+.Ic \&Bd
+display.
+This works with
+.Nm ,
+but fails with most other implementations.
+.It Sy "moving content out of list"
+.Pq mdoc
+A
+.Ic \&Bl
+list block contains text or macros before the first
+.Ic \&It
+macro.
+The offending children are moved before the beginning of the list.
+.It Sy ".Vt block has child macro"
+.Pq mdoc
+The
+.Ic \&Vt
+macro supports plain text arguments only.
+Formatting may be ugly and semantic searching
+for the affected content might not work.
+.It Sy "fill mode already enabled, skipping"
+.Pq man
+A
+.Ic \&fi
+request occurs even though the document is still in fill mode,
+or already switched back to fill mode.
+It has no effect.
+.It Sy "fill mode already disabled, skipping"
+.Pq man
+An
+.Ic \&nf
+request occurs even though the document already switched to no-fill mode
+and did not switch back to fill mode yet.
+It has no effect.
+.It Sy "line scope broken"
+.Pq man
+While parsing the next-line scope of the previous macro,
+another macro is found that prematurely terminates the previous one.
+The previous, interrupted macro is deleted from the parse tree.
+.El
+.Ss "Warnings related to missing arguments"
+.Bl -ohang
+.It Sy "skipping empty request"
+.Pq roff
+The macro name is missing from a macro definition request.
+.It Sy "conditional request controls empty scope"
+.Pq roff
+A conditional request is only useful if any of the following
+follows it on the same logical input line:
+.Bl -dash -compact
+.It
+The
+.Sq \e{
+keyword to open a multi-line scope.
+.It
+A request or macro or some text, resulting in a single-line scope.
+.It
+The immediate end of the logical line without any intervening whitespace,
+resulting in next-line scope.
+.El
+Here, a conditional request is followed by trailing whitespace only,
+and there is no other content on its logical input line.
+Note that it doesn't matter whether the logical input line is split
+across multiple physical input lines using
+.Sq \e
+line continuation characters.
+This is one of the rare cases
+where trailing whitespace is syntactically significant.
+The conditional request controls a scope containing whitespace only,
+so it is unlikely to have a significant effect,
+except that it may control a following
+.Ic \&el
+clause.
+.It Sy "skipping empty macro"
+.Pq mdoc
+The indicated macro has no arguments and hence no effect.
+.It Sy "empty argument, using 0n"
+.Pq mdoc
+The required width is missing after
+.Ic \&Bd
+or
+.Ic \&Bl
+.Fl offset
+or
+.Fl width.
+.It Sy "argument count wrong"
+.Pq mdoc , man
+The indicated macro has too few or too many arguments.
+The syntax tree will contain the wrong number of arguments as given.
+Formatting behaviour depends on the specific macro in question.
+Note that the same message may also occur as an ERROR, see below.
+.It Sy "missing display type, using -ragged"
+.Pq mdoc
+The
+.Ic \&Bd
+macro is invoked without the required display type.
+.It Sy "list type is not the first argument"
+.Pq mdoc
+In a
+.Ic \&Bl
+macro, at least one other argument precedes the type argument.
+The
+.Nm
+utility copes with any argument order, but some other
+.Xr mdoc 7
+implementations do not.
+.It Sy "missing -width in -tag list, using 8n"
+.Pq mdoc
+Every
+.Ic \&Bl
+macro having the
+.Fl tag
+argument requires
+.Fl width ,
+too.
+.It Sy "missing utility name, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Ex Fl std
+macro is called without an argument before
+.Ic \&Nm
+has first been called with an argument.
+.It Sy "empty head in list item"
+.Pq mdoc
+In a
+.Ic \&Bl
+.Fl diag ,
+.Fl hang ,
+.Fl inset ,
+.Fl ohang ,
+or
+.Fl tag
+list, an
+.Ic \&It
+macro lacks the required argument.
+The item head is left empty.
+.It Sy "empty list item"
+.Pq mdoc
+In a
+.Ic \&Bl
+.Fl bullet ,
+.Fl dash ,
+.Fl enum ,
+or
+.Fl hyphen
+list, an
+.Ic \&It
+block is empty.
+An empty list item is shown.
+.It Sy "missing font type"
+.Pq mdoc
+A
+.Ic \&Bf
+macro has no argument.
+It switches to the default font,
+.Cm \efR .
+.It Sy "unknown font type"
+.Pq mdoc
+The
+.Ic \&Bf
+argument is invalid.
+The default font
+.Cm \efR
+is used instead.
+.It Sy "missing -std argument, adding it"
+.Pq mdoc
+An
+.Ic \&Ex
+or
+.Ic \&Rv
+macro lacks the required
+.Fl std
+argument.
+The
+.Nm
+utility assumes
+.Fl std
+even when it is not specified, but other implementations may not.
+.El
+.Ss "Warnings related to bad macro arguments"
+.Bl -ohang
+.It Sy "unterminated quoted argument"
+.Pq roff
+Macro arguments can be enclosed in double quote characters
+such that space characters and macro names contained in the quoted
+argument need not be escaped.
+The closing quote of the last argument of a macro can be omitted.
+However, omitting it is not recommended because it makes the code
+harder to read.
+.It Sy "duplicate argument"
+.Pq mdoc
+A
+.Ic \&Bd
+or
+.Ic \&Bl
+macro has more than one
+.Fl compact ,
+more than one
+.Fl offset ,
+or more than one
+.Fl width
+argument.
+All but the last instances of these arguments are ignored.
+.It Sy "skipping duplicate argument"
+.Pq mdoc
+An
+.Ic \&An
+macro has more than one
+.Fl split
+or
+.Fl nosplit
+argument.
+All but the first of these arguments are ignored.
+.It Sy "skipping duplicate display type"
+.Pq mdoc
+A
+.Ic \&Bd
+macro has more than one type argument; the first one is used.
+.It Sy "skipping duplicate list type"
+.Pq mdoc
+A
+.Ic \&Bl
+macro has more than one type argument; the first one is used.
+.It Sy "skipping -width argument"
+.Pq mdoc
+A
+.Ic \&Bl
+.Fl column ,
+.Fl diag ,
+.Fl ohang ,
+.Fl inset ,
+or
+.Fl item
+list has a
+.Fl width
+argument.
+That has no effect.
+.It Sy "unknown AT&T UNIX version"
+.Pq mdoc
+An
+.Ic \&At
+macro has an invalid argument.
+It is used verbatim, with
+.Qq "AT&T UNIX "
+prefixed to it.
+.It Sy "invalid content in Rs block"
+.Pq mdoc
+An
+.Ic \&Rs
+block contains plain text or non-% macros.
+The bogus content is left in the syntax tree.
+Formatting may be poor.
+.It Sy "invalid Boolean argument"
+.Pq mdoc
+An
+.Ic \&Sm
+macro has an argument other than
+.Cm on
+or
+.Cm off .
+The invalid argument is moved out of the macro, which leaves the macro
+empty, causing it to toggle the spacing mode.
+.It Sy "unknown font, skipping request"
+.Pq man
+A
+.Xr roff 7
+.Ic \&ft
+request has an invalid argument.
+.El
+.Ss "Warnings related to plain text"
+.Bl -ohang
+.It Sy "blank line in fill mode, using .sp"
+.Pq mdoc
+The meaning of blank input lines is only well-defined in non-fill mode:
+In fill mode, line breaks of text input lines are not supposed to be
+significant.
+However, for compatibility with groff, blank lines in fill mode
+are replaced with
+.Ic \&sp
+requests.
+.It Sy "tab in filled text"
+.Pq mdoc , man
+The meaning of tab characters is only well-defined in non-fill mode:
+In fill mode, whitespace is not supposed to be significant
+on text input lines.
+As an implementation dependent choice, tab characters on text lines
+are passed through to the formatters in any case.
+Given that the text before the tab character will be filled,
+it is hard to predict which tab stop position the tab will advance to.
+.It Sy "whitespace at end of input line"
+.Pq mdoc , man , roff
+Whitespace at the end of input lines is almost never semantically
+significant \(em but in the odd case where it might be, it is
+extremely confusing when reviewing and maintaining documents.
+.It Sy "bad comment style"
+.Pq roff
+Comment lines start with a dot, a backslash, and a double-quote character.
The
.Nm
-utility may also print messages related to invalid command line arguments
-or operating system errors, for example when memory is exhausted or
-input files cannot be read.
-Such messages do not carry the prefix described above.
+utility treats the line as a comment line even without the backslash,
+but leaving out the backslash might not be portable.
+.It Sy "invalid escape sequence"
+.Pq roff
+An escape sequence has an invalid opening argument delimiter, lacks the
+closing argument delimiter, or the argument has too few characters.
+If the argument is incomplete,
+.Ic \e*
+and
+.Ic \en
+expand to an empty string,
+.Ic \eB
+to the digit
+.Sq 0 ,
+and
+.Ic \ew
+to the length of the incomplete argument.
+All other invalid escape sequences are ignored.
+.It Sy "undefined string, using \(dq\(dq"
+.Pq roff
+If a string is used without being defined before,
+its value is implicitly set to the empty string.
+However, defining strings explicitly before use
+keeps the code more readable.
+.El
+.Ss "Errors related to equations"
+.Bl -inset -compact
+.It "unexpected equation scope closure"
+.It "equation scope open on exit"
+.It "overlapping equation scopes"
+.It "unexpected end of equation"
+.It "equation syntax error"
+.El
+.Ss "Errors related to tables"
+.Bl -inset -compact
+.It "bad table syntax"
+.It "bad table option"
+.It "bad table layout"
+.It "no table layout cells specified"
+.It "no table data cells specified"
+.It "ignore data in cell"
+.It "data block still open"
+.It "ignoring extra data cells"
+.El
+.Ss "Errors related to roff, mdoc, and man code"
+.Bl -ohang
+.It Sy "input stack limit exceeded, infinite loop?"
+.Pq roff
+Explicit recursion limits are implemented for the following features,
+in order to prevent infinite loops:
+.Bl -dash -compact
+.It
+expansion of nested escape sequences
+including expansion of strings and number registers,
+.It
+expansion of nested user-defined macros,
+.It
+and
+.Ic \&so
+file inclusion.
+.El
+When a limit is hit, the output is incorrect, typically losing
+some content, but the parser can continue.
+.It Sy "skipping bad character"
+.Pq mdoc , man , roff
+The input file contains a byte that is not a printable
+.Xr ascii 7
+character.
+The message mentions the character number.
+The offending byte is replaced with a question mark
+.Pq Sq \&? .
+Consider editing the input file to replace the byte with an ASCII
+transliteration of the intended character.
+.It Sy "skipping unknown macro"
+.Pq mdoc , man , roff
+The first identifier on a request or macro line is neither recognized as a
+.Xr roff 7
+request, nor as a user-defined macro, nor, respectively, as an
+.Xr mdoc 7
+or
+.Xr man 7
+macro.
+It may be mistyped or unsupported.
+The request or macro is discarded including its arguments.
+.It Sy "skipping item outside list"
+.Pq mdoc
+An
+.Ic \&It
+macro occurs outside any
+.Ic \&Bl
+list.
+It is discarded including its arguments.
+.It Sy "skipping column outside column list"
+.Pq mdoc
+A
+.Ic \&Ta
+macro occurs outside any
+.Ic \&Bl Fl column
+block.
+It is discarded including its arguments.
+.It Sy "skipping end of block that is not open"
+.Pq mdoc , man , eqn , tbl , roff
+Various syntax elements can only be used to explicitly close blocks
+that have previously been opened.
+An
+.Xr mdoc 7
+block closing macro, a
+.Xr man 7
+.Ic \&RE
+or
+.Ic \&UE
+macro, or the end of an equation, table, or
+.Xr roff 7
+conditional request is encountered but no matching block is open.
+The offending request or macro is discarded.
+.It Sy "inserting missing end of block"
+.Pq mdoc , tbl
+Various
+.Xr mdoc 7
+macros as well as tables require explicit closing by dedicated macros.
+A block that doesn't support bad nesting
+ends before all of its children are properly closed.
+The open child nodes are closed implicitly.
+.It Sy "scope open on exit"
+.Pq mdoc , man , eqn , tbl , roff
+At the end of the document, an explicit
+.Xr mdoc 7
+block, a
+.Xr man 7
+next-line scope or
+.Ic \&RS
+or
+.Ic \&UR
+block, an equation, table, or
+.Xr roff 7
+conditional or ignore block is still open.
+The open block is closed implicitly.
+.It Sy "escaped character not allowed in a name"
+.Pq roff
+Macro, string and register identifiers consist of printable,
+non-whitespace ASCII characters.
+Escape sequences and characters and strings expressed in terms of them
+cannot form part of a name.
+The first argument of an
+.Ic \&am ,
+.Ic \&as ,
+.Ic \&de ,
+.Ic \&ds ,
+.Ic \&nr ,
+or
+.Ic \&rr
+request, or any argument of an
+.Ic \&rm
+request, or the name of a request or user defined macro being called,
+is terminated by an escape sequence.
+In the cases of
+.Ic \&as ,
+.Ic \&ds ,
+and
+.Ic \&nr ,
+the request has no effect at all.
+In the cases of
+.Ic \&am ,
+.Ic \&de ,
+.Ic \&rr ,
+and
+.Ic \&rm ,
+what was parsed up to this point is used as the arguments to the request,
+and the rest of the input line is discarded including the escape sequence.
+When parsing for a request or a user-defined macro name to be called,
+only the escape sequence is discarded.
+The characters preceding it are used as the request or macro name,
+the characters following it are used as the arguments to the request or macro.
+.It Sy "argument count wrong"
+.Pq mdoc , man , roff
+The indicated request or macro has too few or too many arguments.
+The syntax tree will contain the wrong number of arguments as given.
+Formatting behaviour depends on the specific request or macro in question.
+Note that the same message may also occur as a WARNING, see above.
+.It Sy "missing list type, using -item"
+.Pq mdoc
+A
+.Ic \&Bl
+macro fails to specify the list type.
+.It Sy "missing manual name, using \(dq\(dq"
+.Pq mdoc
+The first call to
+.Ic \&Nm
+lacks the required argument.
+.It Sy "uname(3) system call failed, using UNKNOWN"
+.Pq mdoc
+The
+.Ic \&Os
+macro is called without arguments, and the
+.Xr uname 3
+system call failed.
+As a workaround,
+.Nm
+can be compiled with
+.Sm off
+.Fl D Cm OSNAME=\(dq\e\(dq Ar string Cm \e\(dq\(dq .
+.Sm on
+.It Sy "unknown standard specifier"
+.Pq mdoc
+An
+.Ic \&St
+macro has an unknown argument and is discarded.
+.It Sy "skipping request without numeric argument"
+.Pq roff
+An
+.Ic \&it
+request has a non-numeric or negative argument or no argument at all.
+The invalid request is ignored.
+.It Sy "skipping all arguments"
+.Pq mdoc , man , eqn , roff
+An
+.Xr mdoc 7
+.Ic \&Bt ,
+.Ic \&Ed ,
+.Ic \&Ef ,
+.Ic \&Ek ,
+.Ic \&El ,
+.Ic \&Re ,
+or
+.Ic \&Ud
+macro, an
+.Ic \&It
+macro in a list that don't support item heads, a
+.Xr man 7
+.Ic \&LP ,
+.Ic \&P ,
+or
+.Ic \&PP
+macro, an
+.Xr eqn 7
+.Ic \&EN
+macro, or a
+.Xr roff 7
+.Sq \&..
+block closing request is invoked with at least one argument.
+All arguments are ignored.
+.It Sy "skipping excess arguments"
+.Pq mdoc , roff
+The
+.Ic \&Bf
+macro is invoked with more than one argument, or a request of the
+.Ic \&de
+family is invoked with more than two arguments.
+The excess arguments are ignored.
+.El
+.Ss FATAL errors
+.Bl -ohang
+.It Sy "input too large"
+.Pq mdoc , man
+Currently,
+.Nm
+cannot handle input files larger than its arbitrary size limit
+of 2^31 bytes (2 Gigabytes).
+Since useful manuals are always small, this is not a problem in practice.
+Parsing is aborted as soon as the condition is detected.
+.It Sy "NOT IMPLEMENTED: Bd -file"
+.Pq mdoc
+For security reasons, the
+.Ic \&Bd
+macro does not support the
+.Fl file
+argument.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+The parser exits immediately.
+.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
+.Pq roff
+For security reasons,
+.Nm
+allows
+.Ic \&so
+file inclusion requests only with relative paths
+and only without ascending to any parent directory.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+The parser exits immediately.
+.It Sy ".so request failed"
+.Pq roff
+Servicing a
+.Ic \&so
+request requires reading an external file.
+While trying to do so, an
+.Xr open 2 ,
+.Xr stat 2 ,
+or
+.Xr read 2
+system call failed.
+The parser exits immediately.
+Before showing this message,
+.Nm
+always shows another message explaining why the system call failed.
+.El
.Sh COMPATIBILITY
This section summarises
.Nm
diff --git a/contrib/mdocml/mandoc.3 b/contrib/mdocml/mandoc.3
index fe6503d..8f76ad2 100644
--- a/contrib/mdocml/mandoc.3
+++ b/contrib/mdocml/mandoc.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.3,v 1.22 2013/10/06 17:01:52 schwarze Exp $
+.\" $Id: mandoc.3,v 1.25 2014/08/05 05:48:56 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,21 +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: October 6 2013 $
+.Dd $Mdocdate: August 5 2014 $
.Dt MANDOC 3
.Os
.Sh NAME
.Nm mandoc ,
-.Nm mandoc_escape ,
+.Nm man_deroff ,
.Nm man_meta ,
.Nm man_mparse ,
.Nm man_node ,
-.Nm mchars_alloc ,
-.Nm mchars_free ,
-.Nm mchars_num2char ,
-.Nm mchars_num2uc ,
-.Nm mchars_spec2cp ,
-.Nm mchars_spec2str ,
+.Nm mdoc_deroff ,
.Nm mdoc_meta ,
.Nm mdoc_node ,
.Nm mparse_alloc ,
@@ -45,68 +40,32 @@
.Sh LIBRARY
.Lb libmandoc
.Sh SYNOPSIS
-.In man.h
-.In mdoc.h
+.In sys/types.h
.In mandoc.h
-.Ft "enum mandoc_esc"
-.Fo mandoc_escape
-.Fa "const char const **end"
-.Fa "const char const **start"
-.Fa "int *sz"
-.Fc
-.Ft "const struct man_meta *"
-.Fo man_meta
-.Fa "const struct man *man"
-.Fc
-.Ft "const struct mparse *"
-.Fo man_mparse
-.Fa "const struct man *man"
-.Fc
-.Ft "const struct man_node *"
-.Fo man_node
-.Fa "const struct man *man"
-.Fc
-.Ft "struct mchars *"
-.Fn mchars_alloc "void"
-.Ft void
-.Fn mchars_free "struct mchars *p"
-.Ft char
-.Fn mchars_num2char "const char *cp" "size_t sz"
-.Ft int
-.Fn mchars_num2uc "const char *cp" "size_t sz"
-.Ft "const char *"
-.Fo mchars_spec2str
-.Fa "const struct mchars *p"
-.Fa "const char *cp"
-.Fa "size_t sz"
-.Fa "size_t *rsz"
-.Fc
-.Ft int
-.Fo mchars_spec2cp
-.Fa "const struct mchars *p"
-.Fa "const char *cp"
-.Fa "size_t sz"
-.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"
-.Fc
-.Ft void
+.Fd "#define ASCII_NBRSP"
+.Fd "#define ASCII_HYPH"
+.Fd "#define ASCII_BREAK"
+.Ft struct mparse *
.Fo mparse_alloc
-.Fa "enum mparset type"
+.Fa "int options"
.Fa "enum mandoclevel wlevel"
-.Fa "mandocmsg msg"
-.Fa "void *msgarg"
+.Fa "mandocmsg mmsg"
+.Fa "char *defos"
+.Fc
+.Ft void
+.Fo (*mandocmsg)
+.Fa "enum mandocerr errtype"
+.Fa "enum mandoclevel level"
+.Fa "const char *file"
+.Fa "int line"
+.Fa "int col"
+.Fa "const char *msg"
.Fc
.Ft void
.Fo mparse_free
.Fa "struct mparse *parse"
.Fc
-.Ft void
+.Ft const char *
.Fo mparse_getkeep
.Fa "const struct mparse *parse"
.Fc
@@ -129,6 +88,7 @@
.Fa "struct mparse *parse"
.Fa "struct mdoc **mdoc"
.Fa "struct man **man"
+.Fa "char **sodest"
.Fc
.Ft "const char *"
.Fo mparse_strerror
@@ -138,11 +98,45 @@
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
-.Vt extern const char * const * man_macronames;
+.In sys/types.h
+.In mandoc.h
+.In mdoc.h
+.Ft void
+.Fo mdoc_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"
+.Fc
.Vt extern const char * const * mdoc_argnames;
.Vt extern const char * const * mdoc_macronames;
-.Fd "#define ASCII_NBRSP"
-.Fd "#define ASCII_HYPH"
+.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
+.Ft "const struct mparse *"
+.Fo man_mparse
+.Fa "const struct man *man"
+.Fc
+.Ft "const struct man_node *"
+.Fo man_node
+.Fa "const struct man *man"
+.Fc
+.Vt extern const char * const * man_macronames;
.Sh DESCRIPTION
The
.Nm mandoc
@@ -184,37 +178,22 @@ or invoke
.Fn mparse_reset
and parse new files.
.El
-.Pp
-The
-.Nm
-library also contains routines for translating character strings into glyphs
-.Pq see Fn mchars_alloc
-and parsing escape sequences from strings
-.Pq see Fn mandoc_escape .
.Sh REFERENCE
This section documents the functions, types, and variables available
via
-.In mandoc.h .
+.In mandoc.h ,
+with the exception of those documented in
+.Xr mandoc_escape 3
+and
+.Xr mchars_alloc 3 .
.Ss Types
.Bl -ohang
-.It Vt "enum mandoc_esc"
-An escape sequence classification.
.It Vt "enum mandocerr"
A fatal error, error, or warning message during parsing.
.It Vt "enum mandoclevel"
A classification of an
-.Vt "enum mandoclevel"
+.Vt "enum mandocerr"
as regards system operation.
-.It Vt "struct mchars"
-An opaque pointer to an object allowing for translation between
-character strings and glyphs.
-See
-.Fn mchars_alloc .
-.It Vt "enum mparset"
-The type of parser when reading input.
-This should usually be
-.Dv MPARSE_AUTO
-for auto-detection.
.It Vt "struct mparse"
An opaque pointer to a running parse sequence.
Created with
@@ -230,38 +209,20 @@ messages emitted by the parser.
.El
.Ss Functions
.Bl -ohang
-.It Fn mandoc_escape
-Scan an escape sequence, i.e., a character string beginning with
-.Sq \e .
-Pass a pointer to the character after the
-.Sq \e
-as
-.Va end ;
-it will be set to the supremum of the parsed escape sequence unless
-returning
-.Dv ESCAPE_ERROR ,
-in which case the string is bogus and should be
-thrown away.
-If not
-.Dv ESCAPE_ERROR
-or
-.Dv ESCAPE_IGNORE ,
-.Va start
-is set to the first relevant character of the substring (font, glyph,
-whatever) of length
-.Va sz .
-Both
-.Va start
-and
-.Va sz
-may be
-.Dv NULL .
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa mandoc.c .
+.It Fn man_deroff
+Obtain a text-only representation of a
+.Vt struct man_node ,
+including text contained in its child nodes.
+To be used on children of the pointer returned from
+.Fn man_node .
+When it is no longer needed, the pointer returned from
+.Fn man_deroff
+can be passed to
+.Xr free 3 .
.It Fn man_meta
-Obtain the meta-data of a successful parse.
+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
@@ -275,67 +236,29 @@ Declared in
implemented in
.Pa man.c .
.It Fn man_node
-Obtain the root node of a successful parse.
+Obtain the root node 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 mchars_alloc
-Allocate an
-.Vt "struct mchars *"
-object for translating special characters into glyphs.
-See
-.Xr mandoc_char 7
-for an overview of special characters.
-The object must be freed with
-.Fn mchars_free .
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa chars.c .
-.It Fn mchars_free
-Free an object created with
-.Fn mchars_alloc .
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa chars.c .
-.It Fn mchars_num2char
-Convert a character index (e.g., the \eN\(aq\(aq escape) into a
-printable ASCII character.
-Returns \e0 (the nil character) if the input sequence is malformed.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa chars.c .
-.It Fn mchars_num2uc
-Convert a hexadecimal character index (e.g., the \e[uNNNN] escape) into
-a Unicode codepoint.
-Returns \e0 (the nil character) if the input sequence is malformed.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa chars.c .
-.It Fn mchars_spec2cp
-Convert a special character into a valid Unicode codepoint.
-Returns \-1 on failure or a non-zero Unicode codepoint on success.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa chars.c .
-.It Fn mchars_spec2str
-Convert a special character into an ASCII string.
-Returns
-.Dv NULL
-on failure.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa chars.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 parse.
+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
@@ -343,7 +266,9 @@ Declared in
implemented in
.Pa mdoc.c .
.It Fn mdoc_node
-Obtain the root node of a successful parse.
+Obtain the root node of a successful
+.Xr mdoc
+parse.
This may only be used on a pointer returned by
.Fn mparse_result .
Declared in
@@ -352,6 +277,57 @@ implemented in
.Pa mdoc.c .
.It Fn mparse_alloc
Allocate a parser.
+The arguments have the following effect:
+.Bl -tag -offset 5n -width inttype
+.It Ar options
+When the
+.Dv MPARSE_MDOC
+or
+.Dv MPARSE_MAN
+bit is set, only that parser is used.
+Otherwise, the document type is automatically detected.
+.Pp
+When the
+.Dv MPARSE_SO
+bit is set,
+.Xr roff 7
+.Ic \&so
+file inclusion requests are always honoured.
+Otherwise, if the request is the only content in an input file,
+only the file name is remembered, to be returned in the
+.Fa sodest
+argument of
+.Fn mparse_result .
+.Pp
+When the
+.Dv MPARSE_QUICK
+bit is set, parsing is aborted after the NAME section.
+This is for example useful in
+.Xr makewhatis 8
+.Fl Q
+to quickly build minimal databases.
+.It Ar wlevel
+Can be set to
+.Dv MANDOCLEVEL_FATAL ,
+.Dv MANDOCLEVEL_ERROR ,
+or
+.Dv MANDOCLEVEL_WARNING .
+Messages below the selected level will be suppressed.
+.It Ar mmsg
+A callback function to handle errors and warnings.
+See
+.Pa main.c
+for an example.
+.It Ar defos
+A default string for the
+.Xr mdoc 7
+.Sq \&Os
+macro, overriding the
+.Dv OSNAME
+preprocessor definition and the results of
+.Xr uname 3 .
+.El
+.Pp
The same parser may be used for multiple files so long as
.Fn mparse_reset
is called between parses.
@@ -419,7 +395,7 @@ i.e., those where
.Fn mparse_readfd
returned less than MANDOCLEVEL_FATAL
.Pc
-should invoke this function, in which case one of the two pointers will
+should invoke this function, in which case one of the three pointers will
be filled in.
Declared in
.In mandoc.h ,
@@ -473,6 +449,8 @@ The following non-printing characters may be embedded in text strings:
A non-breaking space character.
.It Dv ASCII_HYPH
A soft hyphen.
+.It Dv ASCII_BREAK
+A breakable zero-width space.
.El
.Pp
Escape characters are also passed verbatim into text strings.
@@ -480,11 +458,9 @@ An escape character is a sequence of characters beginning with the
backslash
.Pq Sq \e .
To construct human-readable text, these should be intercepted with
-.Fn mandoc_escape
-and converted with one of
-.Fn mchars_num2char ,
-.Fn mchars_spec2str ,
-and so on.
+.Xr mandoc_escape 3
+and converted with one the functions described in
+.Xr mchars_alloc 3 .
.Ss Man Abstract Syntax Tree
This AST is governed by the ontological rules dictated in
.Xr man 7
@@ -529,7 +505,7 @@ where capitalised non-terminals represent nodes.
.El
.Pp
The only elements capable of nesting other elements are those with
-next-lint scope as documented in
+next-line scope as documented in
.Xr man 7 .
.Ss Mdoc Abstract Syntax Tree
This AST is governed by the ontological
@@ -665,10 +641,13 @@ front-ends to
.Xr mandoc 1
are unable to render them in any meaningful way.
Furthermore, behaviour when encountering badly-nested blocks is not
-consistent across troff implementations, especially when using multiple
+consistent across troff implementations, especially when using multiple
levels of badly-nested blocks.
.Sh SEE ALSO
.Xr mandoc 1 ,
+.Xr mandoc_escape 3 ,
+.Xr mandoc_malloc 3 ,
+.Xr mchars_alloc 3 ,
.Xr eqn 7 ,
.Xr man 7 ,
.Xr mandoc_char 7 ,
diff --git a/contrib/mdocml/mandoc.c b/contrib/mdocml/mandoc.c
index da738f2..dd22272 100644
--- a/contrib/mdocml/mandoc.c
+++ b/contrib/mdocml/mandoc.c
@@ -1,7 +1,7 @@
-/* $Id: mandoc.c,v 1.74 2013/12/30 18:30:32 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.83 2014/07/06 19:09:00 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -31,6 +31,7 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#define DATESIZE 32
@@ -45,7 +46,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
const char *local_start;
int local_sz;
char term;
- enum mandoc_esc gly;
+ enum mandoc_esc gly;
/*
* When the caller doesn't provide return storage,
@@ -74,11 +75,11 @@ mandoc_escape(const char **end, const char **start, int *sz)
* these, but each eventually returns a substring of the glyph
* name.
*/
- case ('('):
+ case '(':
gly = ESCAPE_SPECIAL;
*sz = 2;
break;
- case ('['):
+ case '[':
gly = ESCAPE_SPECIAL;
/*
* Unicode escapes are defined in groff as \[uXXXX] to
@@ -90,7 +91,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
gly = ESCAPE_UNICODE;
term = ']';
break;
- case ('C'):
+ case 'C':
if ('\'' != **start)
return(ESCAPE_ERROR);
*start = ++*end;
@@ -104,50 +105,50 @@ mandoc_escape(const char **end, const char **start, int *sz)
/*
* Escapes taking no arguments at all.
*/
- case ('d'):
+ case 'd':
/* FALLTHROUGH */
- case ('u'):
+ case 'u':
return(ESCAPE_IGNORE);
/*
* The \z escape is supposed to output the following
- * character without advancing the cursor position.
+ * character without advancing the cursor position.
* Since we are mostly dealing with terminal mode,
* let us just skip the next character.
*/
- case ('z'):
+ case 'z':
return(ESCAPE_SKIPCHAR);
/*
* Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
* 'X' is the trigger. These have opaque sub-strings.
*/
- case ('F'):
+ case 'F':
/* FALLTHROUGH */
- case ('g'):
+ case 'g':
/* FALLTHROUGH */
- case ('k'):
+ case 'k':
/* FALLTHROUGH */
- case ('M'):
+ case 'M':
/* FALLTHROUGH */
- case ('m'):
+ case 'm':
/* FALLTHROUGH */
- case ('n'):
+ case 'n':
/* FALLTHROUGH */
- case ('V'):
+ case 'V':
/* FALLTHROUGH */
- case ('Y'):
+ case 'Y':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
- case ('f'):
+ case 'f':
if (ESCAPE_ERROR == gly)
gly = ESCAPE_FONT;
switch (**start) {
- case ('('):
+ case '(':
*start = ++*end;
*sz = 2;
break;
- case ('['):
+ case '[':
*start = ++*end;
term = ']';
break;
@@ -160,60 +161,59 @@ mandoc_escape(const char **end, const char **start, int *sz)
/*
* These escapes are of the form \X'Y', where 'X' is the trigger
* and 'Y' is any string. These have opaque sub-strings.
+ * The \B and \w escapes are handled in roff.c, roff_res().
*/
- case ('A'):
+ case 'A':
/* FALLTHROUGH */
- case ('b'):
+ case 'b':
/* FALLTHROUGH */
- case ('B'):
+ case 'D':
/* FALLTHROUGH */
- case ('D'):
+ case 'o':
/* FALLTHROUGH */
- case ('o'):
+ case 'R':
/* FALLTHROUGH */
- case ('R'):
+ case 'X':
/* FALLTHROUGH */
- case ('w'):
- /* FALLTHROUGH */
- case ('X'):
- /* FALLTHROUGH */
- case ('Z'):
- if ('\'' != **start)
+ case 'Z':
+ if ('\0' == **start)
return(ESCAPE_ERROR);
gly = ESCAPE_IGNORE;
+ term = **start;
*start = ++*end;
- term = '\'';
break;
/*
* These escapes are of the form \X'N', where 'X' is the trigger
* and 'N' resolves to a numerical expression.
*/
- case ('h'):
+ case 'h':
/* FALLTHROUGH */
- case ('H'):
+ case 'H':
/* FALLTHROUGH */
- case ('L'):
+ case 'L':
/* FALLTHROUGH */
- case ('l'):
+ case 'l':
/* FALLTHROUGH */
- case ('S'):
+ case 'S':
/* FALLTHROUGH */
- case ('v'):
+ case 'v':
/* FALLTHROUGH */
- case ('x'):
- if ('\'' != **start)
+ case 'x':
+ if (strchr(" %&()*+-./0123456789:<=>", **start)) {
+ ++*end;
return(ESCAPE_ERROR);
+ }
gly = ESCAPE_IGNORE;
+ term = **start;
*start = ++*end;
- term = '\'';
break;
/*
* Special handling for the numbered character escape.
* XXX Do any other escapes need similar handling?
*/
- case ('N'):
+ case 'N':
if ('\0' == **start)
return(ESCAPE_ERROR);
(*end)++;
@@ -229,10 +229,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
(*end)++;
return(ESCAPE_NUMBERED);
- /*
+ /*
* Sizes get a special category of their own.
*/
- case ('s'):
+ case 's':
gly = ESCAPE_IGNORE;
/* See +/- counts as a sign. */
@@ -240,15 +240,15 @@ mandoc_escape(const char **end, const char **start, int *sz)
(*end)++;
switch (**end) {
- case ('('):
+ case '(':
*start = ++*end;
*sz = 2;
break;
- case ('['):
+ case '[':
*start = ++*end;
term = ']';
break;
- case ('\''):
+ case '\'':
*start = ++*end;
term = '\'';
break;
@@ -280,9 +280,9 @@ mandoc_escape(const char **end, const char **start, int *sz)
if ('\0' != term) {
while (**end != term) {
switch (**end) {
- case ('\0'):
+ case '\0':
return(ESCAPE_ERROR);
- case ('\\'):
+ case '\\':
(*end)++;
if (ESCAPE_ERROR ==
mandoc_escape(end, NULL, NULL))
@@ -304,7 +304,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
/* Run post-processors. */
switch (gly) {
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
if (2 == *sz) {
if ('C' == **start) {
/*
@@ -322,27 +322,27 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
switch (**start) {
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('B'):
+ case 'B':
gly = ESCAPE_FONTBOLD;
break;
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('I'):
+ case 'I':
gly = ESCAPE_FONTITALIC;
break;
- case ('P'):
+ case 'P':
gly = ESCAPE_FONTPREV;
break;
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
gly = ESCAPE_FONTROMAN;
break;
}
break;
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
if (1 == *sz && 'c' == **start)
gly = ESCAPE_NOSPACE;
break;
@@ -353,74 +353,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
return(gly);
}
-void *
-mandoc_calloc(size_t num, size_t size)
-{
- void *ptr;
-
- ptr = calloc(num, size);
- if (NULL == ptr) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(ptr);
-}
-
-
-void *
-mandoc_malloc(size_t size)
-{
- void *ptr;
-
- ptr = malloc(size);
- if (NULL == ptr) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(ptr);
-}
-
-
-void *
-mandoc_realloc(void *ptr, size_t size)
-{
-
- ptr = realloc(ptr, size);
- if (NULL == ptr) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(ptr);
-}
-
-char *
-mandoc_strndup(const char *ptr, size_t sz)
-{
- char *p;
-
- p = mandoc_malloc(sz + 1);
- memcpy(p, ptr, sz);
- p[(int)sz] = '\0';
- return(p);
-}
-
-char *
-mandoc_strdup(const char *ptr)
-{
- char *p;
-
- p = strdup(ptr);
- if (NULL == p) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(p);
-}
-
/*
* Parse a quoted or unquoted roff-style request or macro argument.
* Return a pointer to the parsed argument, which is either the original
@@ -442,7 +374,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
if ('"' == *start) {
quoted = 1;
start++;
- }
+ }
pairs = 0;
white = 0;
@@ -461,14 +393,14 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
* backslashes and backslash-t to literal tabs.
*/
switch (cp[1]) {
- case ('t'):
+ case 't':
cp[0] = '\t';
/* FALLTHROUGH */
- case ('\\'):
+ case '\\':
pairs++;
cp++;
break;
- case (' '):
+ case ' ':
/* Skip escaped blanks. */
if (0 == quoted)
cp++;
@@ -497,7 +429,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
/* Quoted argument without a closing quote. */
if (1 == quoted)
- mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_ARG_QUOTE, parse, ln, *pos, NULL);
/* NUL-terminate this argument and move to the next one. */
if (pairs)
@@ -511,7 +443,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
*cpp = cp;
if ('\0' == *cp && (white || ' ' == cp[-1]))
- mandoc_msg(MANDOCERR_EOLNSPACE, parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL);
return(start);
}
@@ -579,14 +511,14 @@ mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
if (NULL == in || '\0' == *in ||
0 == strcmp(in, "$" "Mdocdate$")) {
- mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL);
+ mandoc_msg(MANDOCERR_DATE_MISSING, parse, ln, pos, NULL);
time(&t);
}
else if (a2time(&t, "%Y-%m-%d", in))
t = 0;
else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) &&
!a2time(&t, "%b %d, %Y", in)) {
- mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL);
+ mandoc_msg(MANDOCERR_DATE_BAD, parse, ln, pos, in);
t = 0;
}
out = t ? time2a(t) : NULL;
@@ -594,10 +526,10 @@ mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
}
int
-mandoc_eos(const char *p, size_t sz, int enclosed)
+mandoc_eos(const char *p, size_t sz)
{
- const char *q;
- int found;
+ const char *q;
+ int enclosed, found;
if (0 == sz)
return(0);
@@ -608,24 +540,24 @@ mandoc_eos(const char *p, size_t sz, int enclosed)
* propagate outward.
*/
- found = 0;
+ enclosed = found = 0;
for (q = p + (int)sz - 1; q >= p; q--) {
switch (*q) {
- case ('\"'):
+ case '\"':
/* FALLTHROUGH */
- case ('\''):
+ case '\'':
/* FALLTHROUGH */
- case (']'):
+ case ']':
/* FALLTHROUGH */
- case (')'):
+ case ')':
if (0 == found)
enclosed = 1;
break;
- case ('.'):
+ case '.':
/* FALLTHROUGH */
- case ('!'):
+ case '!':
/* FALLTHROUGH */
- case ('?'):
+ case '?':
found = 1;
break;
default:
diff --git a/contrib/mdocml/mandoc.db.5 b/contrib/mdocml/mandoc.db.5
new file mode 100644
index 0000000..8d56495
--- /dev/null
+++ b/contrib/mdocml/mandoc.db.5
@@ -0,0 +1,144 @@
+.\" $Id: mandoc.db.5,v 1.1 2014/04/15 20:18:26 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: April 15 2014 $
+.Dt MANDOC.DB 5
+.Os
+.Sh NAME
+.Nm mandoc.db
+.Nd manual page database
+.Sh DESCRIPTION
+The
+.Nm
+SQLite3 file format is used to store information about installed manual
+pages to facilitate semantic searching for manuals.
+Each manual page tree contains its own
+.Nm
+file; see
+.Sx FILES
+for examples.
+.Pp
+Such database files are generated by
+.Xr makewhatis 8
+and used by
+.Xr apropos 1
+and
+.Xr whatis 1 .
+.Pp
+One line in the following tables describes:
+.Bl -tag -width Ds
+.It Sy mpages
+One physical manual page file, no matter how many times and under which
+names it may appear in the file system.
+.It Sy mlinks
+One entry in the file system, no matter which content it points to.
+.It Sy names
+One manual page name, no matter whether it appears in a page header,
+in a NAME or SYNOPSIS section, or as a file name.
+.It Sy keys
+One chunk of text from some macro invocation.
+.El
+.Pp
+Each record in the latter three tables uses its
+.Va pageid
+column to point to a record in the
+.Sy mpages
+table.
+.Pp
+The other columns are as follows; unless stated otherwise, they are
+of type
+.Vt TEXT .
+.Bl -tag -width mpages.desc
+.It Sy mpages.desc
+The description line
+.Pq Sq \&Nd
+of the page.
+.It Sy mpages.form
+The
+.Vt INTEGER
+1 if the page is unformatted, i.e. in
+.Xr mdoc 7
+or
+.Xr man 7
+format, and 2 if it is formatted, i.e. a
+.Sq cat
+page.
+.It Sy mlinks.sec
+The manual section as found in the subdirectory name.
+.It Sy mlinks.arch
+The manual architecture as found in the subdirectory name, or
+.Qq any .
+.It Sy mlinks.name
+The manual name as found in the file name.
+.It Sy names.bits
+An
+.Vt INTEGER
+bit mask telling whether the name came from a header line, from the
+NAME or SYNOPSIS section, or from a file name.
+Bits are defined in
+.In mansearch.h .
+.It Sy names.name
+The name itself.
+.It Sy keys.bits
+An
+.Vt INTEGER
+bit mask telling which semantic contexts the key was found in;
+defined in
+.In mansearch.h ,
+documented in
+.Xr apropos 1 .
+.It Sy keys.key
+The string found in those contexts.
+.El
+.Sh FILES
+.Bl -tag -width /usr/share/mandoc.db -compact
+.It Pa /usr/share/mandoc.db
+The manual page database for the base system.
+.It Pa /usr/X11R6/mandoc.db
+The same for the
+.Xr X 7
+Window System.
+.It Pa /usr/local/mandoc.db
+The same for
+.Xr packages 7 .
+.El
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr man 1 ,
+.Xr sqlite3 1 ,
+.Xr whatis 1 ,
+.Xr mansearch 3 ,
+.Xr makewhatis 8
+.Sh HISTORY
+A manual page database
+.Pa /usr/lib/whatis
+first appeared in
+.Bx 2 .
+The present format first appeared in
+.Ox 5.6 .
+.Sh AUTHORS
+.An -nosplit
+The original version of
+.Xr makewhatis 8
+was written by
+.An Bill Joy
+in 1979.
+An SQLite3 version was first implemented by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+in 2012.
+The present database format was designed by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org
+in 2014.
diff --git a/contrib/mdocml/mandoc.h b/contrib/mdocml/mandoc.h
index 4c6a32f..fd91314 100644
--- a/contrib/mdocml/mandoc.h
+++ b/contrib/mdocml/mandoc.h
@@ -1,7 +1,7 @@
-/* $Id: mandoc.h,v 1.112 2013/12/30 18:30:32 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.152 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,6 +20,7 @@
#define ASCII_NBRSP 31 /* non-breaking space */
#define ASCII_HYPH 30 /* breakable hyphen */
+#define ASCII_BREAK 29 /* breakable zero-width space */
/*
* Status level. This refers to both internal status (i.e., whilst
@@ -48,66 +49,78 @@ enum mandocerr {
MANDOCERR_WARNING, /* ===== start of warnings ===== */
/* related to the prologue */
- MANDOCERR_NOTITLE, /* no title in document */
- MANDOCERR_UPPERCASE, /* document title should be all caps */
- MANDOCERR_BADMSEC, /* unknown manual section */
- MANDOCERR_BADVOLARCH, /* unknown manual volume or arch */
- MANDOCERR_NODATE, /* date missing, using today's date */
- MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */
- MANDOCERR_PROLOGOOO, /* prologue macros out of order */
- MANDOCERR_PROLOGREP, /* duplicate prologue macro */
- MANDOCERR_BADPROLOG, /* macro not allowed in prologue */
- MANDOCERR_BADBODY, /* macro not allowed in body */
+ MANDOCERR_DT_NOTITLE, /* missing manual title, using UNTITLED: line */
+ MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */
+ MANDOCERR_TITLE_CASE, /* lower case character in document title */
+ MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */
+ MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */
+ MANDOCERR_ARCH_BAD, /* unknown manual volume or arch: Dt ... volume */
+ MANDOCERR_DATE_MISSING, /* missing date, using today's date */
+ MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */
+ MANDOCERR_OS_MISSING, /* missing Os macro, using "" */
+ MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
+ MANDOCERR_PROLOG_LATE, /* late prologue macro: macro */
+ MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
+ MANDOCERR_PROLOG_ORDER, /* prologue macros out of order: macros */
/* related to document structure */
- MANDOCERR_SO, /* .so is fragile, better use ln(1) */
- MANDOCERR_NAMESECFIRST, /* NAME section must come first */
- MANDOCERR_BADNAMESEC, /* bad NAME section contents */
- MANDOCERR_SECOOO, /* sections out of conventional order */
- MANDOCERR_SECREP, /* duplicate section name */
- MANDOCERR_SECMSEC, /* section header suited to sections ... */
+ MANDOCERR_SO, /* .so is fragile, better use ln(1): so path */
+ MANDOCERR_DOC_EMPTY, /* no document body */
+ MANDOCERR_SEC_BEFORE, /* content before first section header: macro */
+ MANDOCERR_NAMESEC_FIRST, /* first section is not NAME: Sh title */
+ MANDOCERR_NAMESEC_BAD, /* bad NAME section contents: macro */
+ MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */
+ MANDOCERR_SEC_REP, /* duplicate section title: Sh title */
+ MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */
/* related to macros and nesting */
- MANDOCERR_MACROOBS, /* skipping obsolete macro */
- MANDOCERR_IGNPAR, /* skipping paragraph macro */
- MANDOCERR_MOVEPAR, /* moving paragraph macro out of list */
- MANDOCERR_IGNNS, /* skipping no-space macro */
- MANDOCERR_SCOPENEST, /* blocks badly nested */
- MANDOCERR_CHILD, /* child violates parent syntax */
- MANDOCERR_NESTEDDISP, /* nested displays are not portable */
- MANDOCERR_SCOPEREP, /* already in literal mode */
- MANDOCERR_LINESCOPE, /* line scope broken */
-
- /* related to missing macro arguments */
- MANDOCERR_MACROEMPTY, /* skipping empty macro */
+ MANDOCERR_MACRO_OBS, /* obsolete macro: macro */
+ MANDOCERR_PAR_SKIP, /* skipping paragraph macro: macro ... */
+ MANDOCERR_PAR_MOVE, /* moving paragraph macro out of list: macro */
+ MANDOCERR_NS_SKIP, /* skipping no-space macro */
+ MANDOCERR_BLK_NEST, /* blocks badly nested: macro ... */
+ MANDOCERR_BD_NEST, /* nested displays are not portable: macro ... */
+ MANDOCERR_BL_MOVE, /* moving content out of list: macro */
+ MANDOCERR_VT_CHILD, /* .Vt block has child macro: macro */
+ MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
+ MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
+ MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
+
+ /* related to missing arguments */
+ MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
+ MANDOCERR_COND_EMPTY, /* conditional request controls empty scope */
+ MANDOCERR_MACRO_EMPTY, /* skipping empty macro: macro */
+ MANDOCERR_ARG_EMPTY, /* empty argument, using 0n: macro arg */
MANDOCERR_ARGCWARN, /* argument count wrong */
- MANDOCERR_DISPTYPE, /* missing display type */
- MANDOCERR_LISTFIRST, /* list type must come first */
- MANDOCERR_NOWIDTHARG, /* tag lists require a width argument */
- MANDOCERR_FONTTYPE, /* missing font type */
- MANDOCERR_WNOSCOPE, /* skipping end of block that is not open */
-
- /* related to bad macro arguments */
- MANDOCERR_IGNARGV, /* skipping argument */
- MANDOCERR_ARGVREP, /* duplicate argument */
- MANDOCERR_DISPREP, /* duplicate display type */
- MANDOCERR_LISTREP, /* duplicate list type */
- MANDOCERR_BADATT, /* unknown AT&T UNIX version */
- MANDOCERR_BADBOOL, /* bad Boolean value */
- MANDOCERR_BADFONT, /* unknown font */
- MANDOCERR_BADSTANDARD, /* unknown standard specifier */
- MANDOCERR_BADWIDTH, /* bad width argument */
+ MANDOCERR_BD_NOTYPE, /* missing display type, using -ragged: Bd */
+ MANDOCERR_BL_LATETYPE, /* list type is not the first argument: Bl arg */
+ MANDOCERR_BL_NOWIDTH, /* missing -width in -tag list, using 8n */
+ MANDOCERR_EX_NONAME, /* missing utility name, using "": Ex */
+ MANDOCERR_IT_NOHEAD, /* empty head in list item: Bl -type It */
+ MANDOCERR_IT_NOBODY, /* empty list item: Bl -type It */
+ MANDOCERR_BF_NOFONT, /* missing font type, using \fR: Bf */
+ MANDOCERR_BF_BADFONT, /* unknown font type, using \fR: Bf font */
+ MANDOCERR_ARG_STD, /* missing -std argument, adding it: macro */
+
+ /* related to bad arguments */
+ MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
+ MANDOCERR_ARG_REP, /* duplicate argument: macro arg */
+ MANDOCERR_AN_REP, /* skipping duplicate argument: An -arg */
+ MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */
+ MANDOCERR_BL_REP, /* skipping duplicate list type: Bl -type */
+ MANDOCERR_BL_SKIPW, /* skipping -width argument: Bl -type */
+ MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */
+ MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
+ MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
+ MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
/* related to plain text */
- MANDOCERR_NOBLANKLN, /* blank line in non-literal context */
- MANDOCERR_BADTAB, /* tab in non-literal context */
- MANDOCERR_EOLNSPACE, /* end of line whitespace */
- MANDOCERR_BADCOMMENT, /* bad comment style */
- MANDOCERR_BADESCAPE, /* unknown escape sequence */
- MANDOCERR_BADQUOTE, /* unterminated quoted string */
-
- /* related to equations */
- MANDOCERR_EQNQUOTE, /* unexpected literal in equation */
+ MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */
+ MANDOCERR_FI_TAB, /* tab in filled text */
+ MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
+ MANDOCERR_COMMENT_BAD, /* bad comment style */
+ MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
+ MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
MANDOCERR_ERROR, /* ===== start of errors ===== */
@@ -128,40 +141,40 @@ enum mandocerr {
MANDOCERR_TBLBLOCK, /* data block still open */
MANDOCERR_TBLEXTRADAT, /* ignoring extra data cells */
+ /* related to document structure and macros */
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
- MANDOCERR_BADCHAR, /* skipping bad character */
- MANDOCERR_NAMESC, /* escaped character not allowed in a name */
- MANDOCERR_NONAME, /* manual name not yet set */
- MANDOCERR_NOTEXT, /* skipping text before the first section header */
- MANDOCERR_MACRO, /* skipping unknown macro */
- MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */
+ MANDOCERR_BADCHAR, /* skipping bad character: number */
+ MANDOCERR_MACRO, /* skipping unknown macro: macro */
+ MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */
+ MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */
+ MANDOCERR_BLK_NOTOPEN, /* skipping end of block that is not open */
+ MANDOCERR_BLK_BROKEN, /* inserting missing end of block: macro ... */
+ MANDOCERR_BLK_NOEND, /* appending missing end of block: macro */
+
+ /* related to request and macro arguments */
+ MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
MANDOCERR_ARGCOUNT, /* argument count wrong */
- MANDOCERR_STRAYTA, /* skipping column outside column list */
- MANDOCERR_NOSCOPE, /* skipping end of block that is not open */
- MANDOCERR_SCOPEBROKEN, /* missing end of block */
- MANDOCERR_SCOPEEXIT, /* scope open on exit */
- MANDOCERR_UNAME, /* uname(3) system call failed */
- /* FIXME: merge following with MANDOCERR_ARGCOUNT */
- MANDOCERR_NOARGS, /* macro requires line argument(s) */
- MANDOCERR_NOBODY, /* macro requires body argument(s) */
- MANDOCERR_NOARGV, /* macro requires argument(s) */
- MANDOCERR_NUMERIC, /* request requires a numeric argument */
- MANDOCERR_LISTTYPE, /* missing list type */
- MANDOCERR_ARGSLOST, /* line argument(s) will be lost */
- MANDOCERR_BODYLOST, /* body argument(s) will be lost */
+ MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
+ MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
+ MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
+ MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
+ MANDOCERR_IT_NONUM, /* skipping request without numeric argument */
+ MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
+ MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */
MANDOCERR_FATAL, /* ===== start of fatal errors ===== */
- MANDOCERR_NOTMANUAL, /* manual isn't really a manual */
- MANDOCERR_COLUMNS, /* column syntax is inconsistent */
- MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */
- MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */
- MANDOCERR_SYNTCHILD, /* child violates parent syntax */
- MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */
- MANDOCERR_SOPATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
- MANDOCERR_NODOCBODY, /* no document body */
- MANDOCERR_NODOCPROLOG, /* no document prologue */
- MANDOCERR_MEM, /* static buffer exhausted */
+ MANDOCERR_TOOLARGE, /* input too large */
+ MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
+ MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
+ MANDOCERR_SO_FAIL, /* .so request failed */
+
+ /* ===== system errors ===== */
+
+ MANDOCERR_SYSOPEN, /* cannot open file */
+ MANDOCERR_SYSSTAT, /* cannot stat file */
+ MANDOCERR_SYSREAD, /* cannot read file */
+
MANDOCERR_MAX
};
@@ -231,6 +244,7 @@ struct tbl_row {
struct tbl_row *next;
struct tbl_cell *first;
struct tbl_cell *last;
+ int vert; /* trailing vertical line */
};
enum tbl_datt {
@@ -353,7 +367,7 @@ struct eqn_box {
/*
* An equation consists of a tree of expressions starting at a given
- * line and position.
+ * line and position.
*/
struct eqn {
char *name; /* identifier (or NULL) */
@@ -363,15 +377,12 @@ struct eqn {
};
/*
- * The type of parse sequence. This value is usually passed via the
- * mandoc(1) command line of -man and -mdoc. It's almost exclusively
- * -mandoc but the others have been retained for compatibility.
+ * Parse options.
*/
-enum mparset {
- MPARSE_AUTO, /* magically determine the document type */
- MPARSE_MDOC, /* assume -mdoc */
- MPARSE_MAN /* assume -man */
-};
+#define MPARSE_MDOC 1 /* assume -mdoc */
+#define MPARSE_MAN 2 /* assume -man */
+#define MPARSE_SO 4 /* honour .so requests */
+#define MPARSE_QUICK 8 /* abort the parse early */
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
@@ -399,30 +410,25 @@ struct man;
__BEGIN_DECLS
-void *mandoc_calloc(size_t, size_t);
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
-void *mandoc_malloc(size_t);
-void *mandoc_realloc(void *, size_t);
-char *mandoc_strdup(const char *);
-char *mandoc_strndup(const char *, size_t);
struct mchars *mchars_alloc(void);
void mchars_free(struct mchars *);
-char mchars_num2char(const char *, size_t);
+char mchars_num2char(const char *, size_t);
int mchars_num2uc(const char *, size_t);
-int mchars_spec2cp(const struct mchars *,
+int mchars_spec2cp(const struct mchars *,
const char *, size_t);
-const char *mchars_spec2str(const struct mchars *,
+const char *mchars_spec2str(const struct mchars *,
const char *, size_t, size_t *);
-struct mparse *mparse_alloc(enum mparset, enum mandoclevel,
- mandocmsg, void *, char *);
+struct mparse *mparse_alloc(int, enum mandoclevel, mandocmsg,
+ const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t,
const char *);
void mparse_reset(struct mparse *);
-void mparse_result(struct mparse *,
- struct mdoc **, struct man **);
+void mparse_result(struct mparse *,
+ struct mdoc **, struct man **, char **);
const char *mparse_getkeep(const struct mparse *);
const char *mparse_strerror(enum mandocerr);
const char *mparse_strlevel(enum mandoclevel);
diff --git a/contrib/mdocml/mandoc_aux.c b/contrib/mdocml/mandoc_aux.c
new file mode 100644
index 0000000..b537673
--- /dev/null
+++ b/contrib/mdocml/mandoc_aux.c
@@ -0,0 +1,121 @@
+/* $Id: mandoc_aux.c,v 1.3 2014/07/09 08:20:34 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mandoc.h"
+#include "mandoc_aux.h"
+
+int
+mandoc_asprintf(char **dest, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(dest, fmt, ap);
+ va_end(ap);
+
+ if (-1 == ret) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ret);
+}
+
+void *
+mandoc_calloc(size_t num, size_t size)
+{
+ void *ptr;
+
+ ptr = calloc(num, size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+void *
+mandoc_malloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+void *
+mandoc_realloc(void *ptr, size_t size)
+{
+
+ ptr = realloc(ptr, size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+void *
+mandoc_reallocarray(void *ptr, size_t num, size_t size)
+{
+
+ ptr = reallocarray(ptr, num, size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+char *
+mandoc_strdup(const char *ptr)
+{
+ char *p;
+
+ p = strdup(ptr);
+ if (NULL == p) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(p);
+}
+
+char *
+mandoc_strndup(const char *ptr, size_t sz)
+{
+ char *p;
+
+ p = mandoc_malloc(sz + 1);
+ memcpy(p, ptr, sz);
+ p[(int)sz] = '\0';
+ return(p);
+}
diff --git a/contrib/mdocml/mandoc_aux.h b/contrib/mdocml/mandoc_aux.h
new file mode 100644
index 0000000..04f4baf
--- /dev/null
+++ b/contrib/mdocml/mandoc_aux.h
@@ -0,0 +1,33 @@
+/* $Id: mandoc_aux.h,v 1.2 2014/04/23 21:06:41 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef MANDOC_AUX_H
+#define MANDOC_AUX_H
+
+__BEGIN_DECLS
+
+int mandoc_asprintf(char **, const char *, ...);
+void *mandoc_calloc(size_t, size_t);
+void *mandoc_malloc(size_t);
+void *mandoc_realloc(void *, size_t);
+void *mandoc_reallocarray(void *, size_t, size_t);
+char *mandoc_strdup(const char *);
+char *mandoc_strndup(const char *, size_t);
+
+__END_DECLS
+
+#endif /*!MANDOC_AUX_H*/
diff --git a/contrib/mdocml/mandoc_escape.3 b/contrib/mdocml/mandoc_escape.3
new file mode 100644
index 0000000..84243fd
--- /dev/null
+++ b/contrib/mdocml/mandoc_escape.3
@@ -0,0 +1,362 @@
+.\" $Id: mandoc_escape.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: August 5 2014 $
+.Dt MANDOC_ESCAPE 3
+.Os
+.Sh NAME
+.Nm mandoc_escape
+.Nd parse roff escape sequences
+.Sh LIBRARY
+.Lb libmandoc
+.Sh SYNOPSIS
+.In sys/types.h
+.In mandoc.h
+.Ft "enum mandoc_esc"
+.Fo mandoc_escape
+.Fa "const char **end"
+.Fa "const char **start"
+.Fa "int *sz"
+.Fc
+.Sh DESCRIPTION
+This function scans a
+.Xr roff 7
+escape sequence.
+.Pp
+An escape sequence consists of
+.Bl -dash -compact -width 2n
+.It
+an initial backslash character
+.Pq Sq \e ,
+.It
+a single ASCII character called the escape sequence identifier,
+.It
+and, with only a few exceptions, an argument.
+.El
+.Pp
+Arguments can be given in the following forms; some escape sequence
+identifiers only accept some of these forms as specified below.
+The first three forms are called the standard forms.
+.Bl -tag -width 2n
+.It \&In brackets: Ic \&[ Ns Ar argument Ns Ic \&]
+The argument starts after the initial
+.Sq \&[ ,
+ends before the final
+.Sq \&] ,
+and the escape sequence ends with the final
+.Sq \&] .
+.It Two-character argument short form: Ic \&( Ns Ar ar
+This form can only be used for arguments
+consisting of exactly two characters.
+It has the same effect as
+.Ic \&[ Ns Ar ar Ns Ic \&] .
+.It One-character argument short form: Ar a
+This form can only be used for arguments
+consisting of exactly one character.
+It has the same effect as
+.Ic \&[ Ns Ar a Ns Ic \&] .
+.It Delimited form: Ar C Ns Ar argument Ns Ar C
+The argument starts after the initial delimiter character
+.Ar C ,
+ends before the next occurrence of the delimiter character
+.Ar C ,
+and the escape sequence ends with that second
+.Ar C .
+Some escape sequences allow arbitrary characters
+.Ar C
+as quoting characters, some restrict the range of characters
+that can be used as quoting characters.
+.El
+.Pp
+Upon function entry,
+.Fa end
+is expected to point to the escape sequence identifier.
+The values passed in as
+.Fa start
+and
+.Fa sz
+are ignored and overwritten.
+.Pp
+By design, this function cannot handle those
+.Xr roff 7
+escape sequences that require in-place expansion, in particular
+user-defined strings
+.Ic \e* ,
+number registers
+.Ic \en ,
+width measurements
+.Ic \ew ,
+and numerical expression control
+.Ic \eB .
+These are handled by
+.Fn roff_res ,
+a private preprocessor function called from
+.Fn roff_parseln ,
+see the file
+.Pa roff.c .
+.Pp
+The function
+.Fn mandoc_escape
+is used
+.Bl -dash -compact -width 2n
+.It
+recursively by itself, because some escape sequence arguments can
+in turn contain other escape sequences,
+.It
+for error detection internally by the
+.Xr roff 7
+parser part of the
+.Lb libmandoc ,
+see the file
+.Pa roff.c ,
+.It
+above all externally by the
+.Xr mandoc
+formatting modules, in particular
+.Fl Tascii
+and
+.Fl Thtml ,
+for formatting purposes, see the files
+.Pa term.c
+and
+.Pa html.c ,
+.It
+and rarely externally by high-level utilities using the mandoc library,
+for example
+.Xr makewhatis 8 ,
+to purge escape sequences from text.
+.El
+.Sh RETURN VALUES
+Upon function return, the pointer
+.Fa end
+is set to the character after the end of the escape sequence,
+such that the calling higher-level parser can easily continue.
+.Pp
+For escape sequences taking an argument, the pointer
+.Fa start
+is set to the beginning of the argument and
+.Fa sz
+is set to the length of the argument.
+For escape sequences not taking an argument,
+.Fa start
+is set to the character after the end of the sequence and
+.Fa sz
+is set to 0.
+Both
+.Fa start
+and
+.Fa sz
+may be
+.Dv NULL ;
+in that case, the argument and the length are not returned.
+.Pp
+For sequences taking an argument, the function
+.Fn mandoc_escape
+returns one of the following values:
+.Bl -tag -width 2n
+.It Dv ESCAPE_FONT
+The escape sequence
+.Ic \ef
+taking an argument in standard form:
+.Ic \ef[ , \ef( , \ef Ns Ar a .
+Two-character arguments starting with the character
+.Sq C
+are reduced to one-character arguments by skipping the
+.Sq C .
+More specific values are returned for the most commonly used arguments:
+.Bl -column "argument" "ESCAPE_FONTITALIC"
+.It argument Ta return value
+.It Cm R No or Cm 1 Ta Dv ESCAPE_FONTROMAN
+.It Cm I No or Cm 2 Ta Dv ESCAPE_FONTITALIC
+.It Cm B No or Cm 3 Ta Dv ESCAPE_FONTBOLD
+.It Cm P Ta Dv ESCAPE_FONTPREV
+.It Cm BI Ta Dv ESCAPE_FONTBI
+.El
+.It Dv ESCAPE_SPECIAL
+The escape sequence
+.Ic \eC
+taking an argument delimited with the single quote character
+and, as a special exception, the escape sequences
+.Em not
+having an identifier, that is, those where the argument, in standard
+form, directly follows the initial backslash:
+.Ic \eC' , \e[ , \e( , \e Ns Ar a .
+Note that the one-character argument short form can only be used for
+argument characters that do not clash with escape sequence identifiers.
+.Pp
+If the argument consists of more than one character
+and starts with the character
+.Sq u ,
+.Dv ESCAPE_UNICODE
+is returned as described below.
+If the argument is just the single character
+.Sq u ,
+.Dv ESCAPE_ERROR
+is returned.
+.Pp
+The
+.Dv ESCAPE_SPECIAL
+special character escape sequences can be rendered using the functions
+.Fn mchars_spec2cp
+and
+.Fn mchars_spec2str
+described in the
+.Xr mchars_alloc 3
+manual.
+.It Dv ESCAPE_UNICODE
+Escape sequences of the same format as described above under
+.Dv ESCAPE_SPECIAL ,
+but with an argument starting with the character
+.Sq u :
+.Ic \eC'u , \e[u .
+As a special exception,
+.Fa start
+is set to the character after the
+.Sq u ,
+and the
+.Fa sz
+return value does not include the
+.Sq u
+either.
+.Pp
+Such Unicode character escape sequences can be rendered using the function
+.Fn mchars_num2uc
+described in the
+.Xr mchars_alloc 3
+manual.
+.It Dv ESCAPE_NUMBERED
+The escape sequence
+.Ic \eN
+followed by a delimited argument.
+The delimiter character is arbitrary except that digits cannot be used.
+If a digit is encountered instead of the opening delimiter, that
+digit is considered to be the argument and the end of the sequence, and
+.Dv ESCAPE_IGNORE
+is returned.
+.Pp
+Such ASCII character escape sequences can be rendered using the function
+.Fn mchars_num2char
+described in the
+.Xr mchars_alloc 3
+manual.
+.It Dv ESCAPE_IGNORE
+.Bl -bullet -width 2n
+.It
+The escape sequence
+.Ic \es
+followed by an argument in standard form or by an argument delimited
+by the single quote character:
+.Ic \es' , \es[ , \es( , \es Ns Ar a .
+As a special exception, an optional
+.Sq +
+or
+.Sq \-
+character is allowed after the
+.Sq s
+for all forms.
+.It
+The escape sequences
+.Ic \eF ,
+.Ic \eg ,
+.Ic \ek ,
+.Ic \eM ,
+.Ic \em ,
+.Ic \en ,
+.Ic \eV ,
+and
+.Ic \eY
+followed by an argument in standard form.
+.It
+The escape sequences
+.Ic \eA ,
+.Ic \eb ,
+.Ic \eD ,
+.Ic \eo ,
+.Ic \eR ,
+.Ic \eX ,
+and
+.Ic \eZ
+followed by an argument delimited by an arbitrary character.
+.It
+The escape sequences
+.Ic \eH ,
+.Ic \eh ,
+.Ic \eL ,
+.Ic \el ,
+.Ic \eS ,
+.Ic \ev ,
+and
+.Ic \ex
+followed by an argument delimited by a character that cannot occur
+in numerical expressions.
+However, if any character that can occur in numerical expressions
+is found instead of a delimiter, the sequence is considered to end
+with that character, and
+.Dv ESCAPE_ERROR
+is returned.
+.El
+.It Dv ESCAPE_ERROR
+Escape sequences taking an argument but not matching any of the above patterns.
+In particular, that happens if the end of the logical input line
+is reached before the end of the argument.
+.El
+.Pp
+For sequences that do not take an argument, the function
+.Fn mandoc_escape
+returns one of the following values:
+.Bl -tag -width 2n
+.It Dv ESCAPE_SKIPCHAR
+The escape sequence
+.Qq \ez .
+.It Dv ESCAPE_NOSPACE
+The escape sequence
+.Qq \ec .
+.It Dv ESCAPE_IGNORE
+The escape sequences
+.Qq \ed
+and
+.Qq \eu .
+.El
+.Sh FILES
+This function is implemented in
+.Pa mandoc.c .
+.Sh SEE ALSO
+.Xr mchars_alloc 3 ,
+.Xr mandoc_char 7 ,
+.Xr roff 7
+.Sh HISTORY
+This function has been available since mandoc 1.11.2.
+.Sh AUTHORS
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org
+.Sh BUGS
+The function doesn't cleanly distinguish between sequences that are
+valid and supported, valid and ignored, valid and unsupported,
+syntactically invalid, or undefined.
+For sequences that are ignored or unsupported, it doesn't tell
+whether that deficiency is likely to cause major formatting problems
+and/or loss of document content.
+The function is already rather complicated and still parses some
+sequences incorrectly.
+.
+.ig
+For these sequences, the list given below specifies a starting string
+and either the length of the argument or an ending character.
+The argument starts after the starting string.
+In the former case, the sequence ends with the end of the argument.
+In the latter case, the argument ends before the ending character,
+and the sequence ends with the ending character.
+..
diff --git a/contrib/mdocml/mandoc_html.3 b/contrib/mdocml/mandoc_html.3
new file mode 100644
index 0000000..994eb3a
--- /dev/null
+++ b/contrib/mdocml/mandoc_html.3
@@ -0,0 +1,249 @@
+.\" $Id: mandoc_html.3,v 1.1 2014/07/23 18:13:09 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: July 23 2014 $
+.Dt MANDOC_HTML 3
+.Os
+.Sh NAME
+.Nm mandoc_html
+.Nd internals of the mandoc HTML formatter
+.Sh SYNOPSIS
+.In "html.h"
+.Ft void
+.Fn print_gen_decls "struct html *h"
+.Ft void
+.Fn print_gen_head "struct html *h"
+.Ft struct tag *
+.Fo print_otag
+.Fa "struct html *h"
+.Fa "enum htmltag tag"
+.Fa "int sz"
+.Fa "const struct htmlpair *p"
+.Fc
+.Ft void
+.Fo print_tagq
+.Fa "struct html *h"
+.Fa "const struct tag *until"
+.Fc
+.Ft void
+.Fo print_stagq
+.Fa "struct html *h"
+.Fa "const struct tag *suntil"
+.Fc
+.Ft void
+.Fo print_text
+.Fa "struct html *h"
+.Fa "const char *word"
+.Fc
+.Sh DESCRIPTION
+The mandoc HTML formatter is not a formal library.
+However, as it is compiled into more than one program, in particular
+.Xr mandoc 1
+and
+.Xr man.cgi 8 ,
+and because it may be security-critical in some contexts,
+some documentation is useful to help to use it correctly and
+to prevent XSS vulnerabilities.
+.Pp
+The formatter produces HTML output on the standard output.
+Since proper escaping is usually required and best taken care of
+at one central place, the language-specific formatters
+.Po
+.Pa *_html.c ,
+see
+.Sx FILES
+.Pc
+are not supposed to print directly to
+.Dv stdout
+using functions like
+.Xr printf 3 ,
+.Xr putc 3 ,
+.Xr puts 3 ,
+or
+.Xr write 2 .
+Instead, they are expected to use the output functions declared in
+.Pa html.h
+and implemented as part of the main HTML formatting engine in
+.Pa html.c .
+.Ss Data structures
+These structures are declared in
+.Pa html.h .
+.Bl -tag -width Ds
+.It Vt struct html
+Internal state of the HTML formatter.
+.It Vt struct htmlpair
+Holds one HTML attribute.
+Members are
+.Fa "enum htmlattr key"
+and
+.Fa "const char *val" .
+Helper macros
+.Fn PAIR_*
+are provided to support initialization of such structures.
+.It Vt struct tag
+One entry for the LIFO stack of HTML elements.
+Members are
+.Fa "enum htmltag tag"
+and
+.Fa "struct tag *next" .
+.El
+.Ss Private interface functions
+The function
+.Fn print_gen_decls
+prints the opening
+.Ao Pf \&? Ic xml ? Ac
+and
+.Aq Pf \&! Ic DOCTYPE
+declarations required for the current document type.
+.Pp
+The function
+.Fn print_gen_head
+prints the opening
+.Aq Ic META
+and
+.Aq Ic LINK
+elements for the document
+.Aq Ic HEAD ,
+using the
+.Fa style
+member of
+.Fa h
+unless that is
+.Dv NULL .
+It uses
+.Fn print_otag
+which takes care of properly encoding attributes,
+which is relevant for the
+.Fa style
+link in particular.
+.Pp
+The function
+.Fn print_otag
+prints the start tag of an HTML element with the name
+.Fa tag ,
+including the
+.Fa sz
+attributes that can optionally be provided in the
+.Fa p
+array.
+It uses the private function
+.Fn print_attr
+which in turn uses the private function
+.Fn print_encode
+to take care of HTML encoding.
+If required by the element type, it remembers in
+.Fa h
+that the element is open.
+The function
+.Fn print_tagq
+is used to close out all open elements up to and including
+.Fa until ;
+.Fn print_stagq
+is a variant to close out all open elements up to but excluding
+.Fa suntil .
+.Pp
+The function
+.Fn print_text
+prints HTML element content.
+It uses the private function
+.Fn print_encode
+to take care of HTML encoding.
+If the document has requested a non-standard font, for example using a
+.Xr roff 7
+.Ic \ef
+font escape sequence,
+.Fn print_text
+wraps
+.Fa word
+in an HTML font selection element using the
+.Fn print_otag
+and
+.Fn print_tagq
+functions.
+.Pp
+The functions
+.Fn bufinit ,
+.Fn bufcat* ,
+and
+.Fn buffmt*
+do not directly produce output but buffer text in the
+.Fa buf
+member of
+.Fa h .
+They are not used internally by
+.Pa html.c
+but intended for use by the language-specific formatters
+to ease preparation of strings for the
+.Fa p
+argument of
+.Fn print_otag
+and for the
+.Fa word
+argument of
+.Fn print_text .
+Consequently, these functions do not do any HTML encoding.
+.Pp
+The functions
+.Fn html_strlen ,
+.Fn print_eqn ,
+.Fn print_tbl ,
+and
+.Fn print_tblclose
+are not yet documented.
+.Sh FILES
+.Bl -tag -width mandoc_aux.c -compact
+.It Pa main.h
+declarations of public functions for use by the main program,
+not yet documented
+.It Pa html.h
+declarations of data types and private functions
+for use by language-specific HTML formatters
+.It Pa html.c
+main HTML formatting engine and utility functions
+.It Pa mdoc_html.c
+.Xr mdoc 7
+HTML formatter
+.It Pa man_html.c
+.Xr man 7
+HTML formatter
+.It Pa tbl_html.c
+.Xr tbl 7
+HTML formatter
+.It Pa eqn_html.c
+.Xr eqn 7
+HTML formatter
+.It Pa out.h
+declarations of data types and private functions
+for shared use by all mandoc formatters,
+not yet documented
+.It Pa out.c
+private functions for shared use by all mandoc formatters
+.It Pa mandoc_aux.h
+declarations of common mandoc utility functions, see
+.Xr mandoc 3
+.It Pa mandoc_aux.c
+implementation of common mandoc utility functions
+.El
+.Sh SEE ALSO
+.Xr mandoc 1 ,
+.Xr mandoc 3 ,
+.Xr man.cgi 8
+.Sh AUTHORS
+.An -nosplit
+The mandoc HTML formatter was written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
+This manual was written by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/contrib/mdocml/mandoc_malloc.3 b/contrib/mdocml/mandoc_malloc.3
new file mode 100644
index 0000000..c167984
--- /dev/null
+++ b/contrib/mdocml/mandoc_malloc.3
@@ -0,0 +1,197 @@
+.\" $Id: mandoc_malloc.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: August 5 2014 $
+.Dt MANDOC_MALLOC 3
+.Os
+.Sh NAME
+.Nm mandoc_malloc ,
+.Nm mandoc_realloc ,
+.Nm mandoc_reallocarray ,
+.Nm mandoc_calloc ,
+.Nm mandoc_strdup ,
+.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
+.Ft "void *"
+.Fo mandoc_malloc
+.Fa "size_t size"
+.Fc
+.Ft "void *"
+.Fo mandoc_realloc
+.Fa "void *ptr"
+.Fa "size_t size"
+.Fc
+.Ft "void *"
+.Fo mandoc_reallocarray
+.Fa "void *ptr"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fc
+.Ft "void *"
+.Fo mandoc_calloc
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fc
+.Ft "char *"
+.Fo mandoc_strdup
+.Fa "const char *s"
+.Fc
+.Ft "char *"
+.Fo mandoc_strndup
+.Fa "const char *s"
+.Fa "size_t maxlen"
+.Fc
+.Ft int
+.Fo mandoc_asprintf
+.Fa "char **ret"
+.Fa "const char *format"
+.Fa "..."
+.Fc
+.Sh DESCRIPTION
+These functions call the
+.Lb 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
+and externally by programs using that library, for example
+.Xr mandoc 1 ,
+.Xr apropos 1 ,
+and
+.Xr makewhatis 8 .
+.Pp
+The function
+.Fn mandoc_malloc
+allocates one new object, leaving the memory uninitialized.
+The functions
+.Fn mandoc_realloc
+and
+.Fn mandoc_reallocarray
+change the size of an existing object or array, possibly moving it.
+When shrinking the size, existing data is truncated; when growing,
+the additional memory is not initialized.
+The function
+.Fn mandoc_calloc
+allocates a new array, initializing it to zero.
+.Pp
+The argument
+.Fa size
+is the size of each object.
+The argument
+.Fa nmemb
+is the new number of objects in the array.
+The argument
+.Fa ptr
+is a pointer to the existing object or array to be resized; if it is
+.Dv NULL ,
+a new object or array is allocated.
+.Pp
+The functions
+.Fn mandoc_strdup
+and
+.Fn mandoc_strndup
+copy a string into newly allocated memory.
+For
+.Fn mandoc_strdup ,
+the string pointed to by
+.Fa s
+needs to be NUL-terminated.
+For
+.Fn mandoc_strndup ,
+at most
+.Fa maxlen
+bytes are copied.
+The function
+.Fn mandoc_asprintf
+writes output formatted according to
+.Fa format
+into newly allocated memory and returns a pointer to the result in
+.Fa ret .
+For all three string functions, the result is always NUL-terminated.
+.Pp
+When the objects and strings are no longer needed,
+the pointers returned by these functions can be passed to
+.Xr free 3 .
+.Sh RETURN VALUES
+The function
+.Fn mandoc_asprintf
+always returns the number of characters written, excluding the
+final NUL byte.
+It never returns -1.
+.Pp
+The other functions always return a valid pointer; they never return
+.Dv NULL .
+.Sh FILES
+These functions are implemented in
+.Pa mandoc_aux.c .
+.Sh SEE ALSO
+.Xr asprintf 3 ,
+.Xr exit 3 ,
+.Xr malloc 3 ,
+.Xr perror 3 ,
+.Xr strdup 3
+.Sh STANDARDS
+The functions
+.Fn malloc ,
+.Fn realloc ,
+and
+.Fn calloc
+are required by
+.St -ansiC .
+The functions
+.Fn strdup
+and
+.Fn strndup
+are required by
+.St -p1003.1-2008 .
+The function
+.Fn asprintf
+is a widespread extension that first appeared in the GNU C library.
+.Pp
+The function
+.Fn reallocarray
+is an extension that first appeared in
+.Ox 5.6 .
+If it is not provided by the operating system, the mandoc build system
+uses a bundled portable implementation.
+.Sh HISTORY
+The functions
+.Fn mandoc_malloc ,
+.Fn mandoc_realloc ,
+.Fn mandoc_calloc ,
+and
+.Fn mandoc_strdup
+have been available since mandoc 1.9.12,
+.Fn mandoc_strndup
+since 1.11.5,
+and
+.Fn mandoc_asprintf
+and
+.Fn mandoc_reallocarray
+since 1.12.4 and 1.13.0.
+.Sh AUTHORS
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org
diff --git a/contrib/mdocml/mandocdb.c b/contrib/mdocml/mandocdb.c
new file mode 100644
index 0000000..a604b46
--- /dev/null
+++ b/contrib/mdocml/mandocdb.c
@@ -0,0 +1,2491 @@
+/* $Id: mandocdb.c,v 1.155 2014/08/06 15:09:05 schwarze Exp $ */
+/*
+ * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_OHASH
+#include <ohash.h>
+#else
+#include "compat_ohash.h"
+#endif
+#include <sqlite3.h>
+
+#include "mdoc.h"
+#include "man.h"
+#include "mandoc.h"
+#include "mandoc_aux.h"
+#include "manpath.h"
+#include "mansearch.h"
+
+extern int mansearch_keymax;
+extern const char *const mansearch_keynames[];
+
+#define SQL_EXEC(_v) \
+ if (SQLITE_OK != sqlite3_exec(db, (_v), NULL, NULL, NULL)) \
+ say("", "%s: %s", (_v), sqlite3_errmsg(db))
+#define SQL_BIND_TEXT(_s, _i, _v) \
+ if (SQLITE_OK != sqlite3_bind_text \
+ ((_s), (_i)++, (_v), -1, SQLITE_STATIC)) \
+ say(mlink->file, "%s", sqlite3_errmsg(db))
+#define SQL_BIND_INT(_s, _i, _v) \
+ if (SQLITE_OK != sqlite3_bind_int \
+ ((_s), (_i)++, (_v))) \
+ say(mlink->file, "%s", sqlite3_errmsg(db))
+#define SQL_BIND_INT64(_s, _i, _v) \
+ if (SQLITE_OK != sqlite3_bind_int64 \
+ ((_s), (_i)++, (_v))) \
+ say(mlink->file, "%s", sqlite3_errmsg(db))
+#define SQL_STEP(_s) \
+ if (SQLITE_DONE != sqlite3_step((_s))) \
+ say(mlink->file, "%s", sqlite3_errmsg(db))
+
+enum op {
+ OP_DEFAULT = 0, /* new dbs from dir list or default config */
+ OP_CONFFILE, /* new databases from custom config file */
+ OP_UPDATE, /* delete/add entries in existing database */
+ OP_DELETE, /* delete entries from existing database */
+ OP_TEST /* change no databases, report potential problems */
+};
+
+enum form {
+ FORM_NONE, /* format is unknown */
+ FORM_SRC, /* format is -man or -mdoc */
+ FORM_CAT /* format is cat */
+};
+
+struct str {
+ char *rendered; /* key in UTF-8 or ASCII form */
+ const struct mpage *mpage; /* if set, the owning parse */
+ uint64_t mask; /* bitmask in sequence */
+ char key[]; /* may contain escape sequences */
+};
+
+struct inodev {
+ ino_t st_ino;
+ dev_t st_dev;
+};
+
+struct mpage {
+ struct inodev inodev; /* used for hashing routine */
+ int64_t pageid; /* pageid in mpages SQL table */
+ enum form form; /* format from file content */
+ char *sec; /* section from file content */
+ char *arch; /* architecture from file content */
+ char *title; /* title from file content */
+ char *desc; /* description from file content */
+ struct mlink *mlinks; /* singly linked list */
+};
+
+struct mlink {
+ char file[PATH_MAX]; /* filename rel. to manpath */
+ enum form dform; /* format from directory */
+ enum form fform; /* format from file name suffix */
+ char *dsec; /* section from directory */
+ char *arch; /* architecture from directory */
+ char *name; /* name from file name (not empty) */
+ char *fsec; /* section from file name suffix */
+ struct mlink *next; /* singly linked list */
+ struct mpage *mpage; /* parent */
+ int gzip; /* filename has a .gz suffix */
+};
+
+enum stmt {
+ STMT_DELETE_PAGE = 0, /* delete mpage */
+ STMT_INSERT_PAGE, /* insert mpage */
+ STMT_INSERT_LINK, /* insert mlink */
+ STMT_INSERT_NAME, /* insert name */
+ STMT_INSERT_KEY, /* insert parsed key */
+ STMT__MAX
+};
+
+typedef int (*mdoc_fp)(struct mpage *, const struct mdoc_node *);
+
+struct mdoc_handler {
+ mdoc_fp fp; /* optional handler */
+ uint64_t mask; /* set unless handler returns 0 */
+};
+
+static void dbclose(int);
+static void dbadd(struct mpage *, struct mchars *);
+static void dbadd_mlink(const struct mlink *mlink);
+static int dbopen(int);
+static void dbprune(void);
+static void filescan(const char *);
+static void *hash_alloc(size_t, void *);
+static void hash_free(void *, void *);
+static void *hash_calloc(size_t, size_t, void *);
+static void mlink_add(struct mlink *, const struct stat *);
+static void mlink_check(struct mpage *, struct mlink *);
+static void mlink_free(struct mlink *);
+static void mlinks_undupe(struct mpage *);
+static void mpages_free(void);
+static void mpages_merge(struct mchars *, struct mparse *);
+static void names_check(void);
+static void parse_cat(struct mpage *, int);
+static void parse_man(struct mpage *, const struct man_node *);
+static void parse_mdoc(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_body(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_head(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_Fd(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_Fn(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_Nd(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_Nm(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_Sh(struct mpage *, const struct mdoc_node *);
+static int parse_mdoc_Xr(struct mpage *, const struct mdoc_node *);
+static void putkey(const struct mpage *, char *, uint64_t);
+static void putkeys(const struct mpage *,
+ const char *, size_t, uint64_t);
+static void putmdockey(const struct mpage *,
+ const struct mdoc_node *, uint64_t);
+static void render_key(struct mchars *, struct str *);
+static void say(const char *, const char *, ...);
+static int set_basedir(const char *);
+static int treescan(void);
+static size_t utf8(unsigned int, char [7]);
+
+static char tempfilename[32];
+static char *progname;
+static int nodb; /* no database changes */
+static int mparse_options; /* abort the parse early */
+static int use_all; /* use all found files */
+static int debug; /* print what we're doing */
+static int warnings; /* warn about crap */
+static int write_utf8; /* write UTF-8 output; else ASCII */
+static int exitcode; /* to be returned by main */
+static enum op op; /* operational mode */
+static char basedir[PATH_MAX]; /* current base directory */
+static struct ohash mpages; /* table of distinct manual pages */
+static struct ohash mlinks; /* table of directory entries */
+static struct ohash names; /* table of all names */
+static struct ohash strings; /* table of all strings */
+static sqlite3 *db = NULL; /* current database */
+static sqlite3_stmt *stmts[STMT__MAX]; /* current statements */
+static uint64_t name_mask;
+
+static const struct mdoc_handler mdocs[MDOC_MAX] = {
+ { NULL, 0 }, /* Ap */
+ { NULL, 0 }, /* Dd */
+ { NULL, 0 }, /* Dt */
+ { NULL, 0 }, /* Os */
+ { parse_mdoc_Sh, TYPE_Sh }, /* Sh */
+ { parse_mdoc_head, TYPE_Ss }, /* Ss */
+ { NULL, 0 }, /* Pp */
+ { NULL, 0 }, /* D1 */
+ { NULL, 0 }, /* Dl */
+ { NULL, 0 }, /* Bd */
+ { NULL, 0 }, /* Ed */
+ { NULL, 0 }, /* Bl */
+ { NULL, 0 }, /* El */
+ { NULL, 0 }, /* It */
+ { NULL, 0 }, /* Ad */
+ { NULL, TYPE_An }, /* An */
+ { NULL, TYPE_Ar }, /* Ar */
+ { NULL, TYPE_Cd }, /* Cd */
+ { NULL, TYPE_Cm }, /* Cm */
+ { NULL, TYPE_Dv }, /* Dv */
+ { NULL, TYPE_Er }, /* Er */
+ { NULL, TYPE_Ev }, /* Ev */
+ { NULL, 0 }, /* Ex */
+ { NULL, TYPE_Fa }, /* Fa */
+ { parse_mdoc_Fd, 0 }, /* Fd */
+ { NULL, TYPE_Fl }, /* Fl */
+ { parse_mdoc_Fn, 0 }, /* Fn */
+ { NULL, TYPE_Ft }, /* Ft */
+ { NULL, TYPE_Ic }, /* Ic */
+ { NULL, TYPE_In }, /* In */
+ { NULL, TYPE_Li }, /* Li */
+ { parse_mdoc_Nd, 0 }, /* Nd */
+ { parse_mdoc_Nm, 0 }, /* Nm */
+ { NULL, 0 }, /* Op */
+ { NULL, 0 }, /* Ot */
+ { NULL, TYPE_Pa }, /* Pa */
+ { NULL, 0 }, /* Rv */
+ { NULL, TYPE_St }, /* St */
+ { NULL, TYPE_Va }, /* Va */
+ { parse_mdoc_body, TYPE_Va }, /* Vt */
+ { parse_mdoc_Xr, 0 }, /* Xr */
+ { NULL, 0 }, /* %A */
+ { NULL, 0 }, /* %B */
+ { NULL, 0 }, /* %D */
+ { NULL, 0 }, /* %I */
+ { NULL, 0 }, /* %J */
+ { NULL, 0 }, /* %N */
+ { NULL, 0 }, /* %O */
+ { NULL, 0 }, /* %P */
+ { NULL, 0 }, /* %R */
+ { NULL, 0 }, /* %T */
+ { NULL, 0 }, /* %V */
+ { NULL, 0 }, /* Ac */
+ { NULL, 0 }, /* Ao */
+ { NULL, 0 }, /* Aq */
+ { NULL, TYPE_At }, /* At */
+ { NULL, 0 }, /* Bc */
+ { NULL, 0 }, /* Bf */
+ { NULL, 0 }, /* Bo */
+ { NULL, 0 }, /* Bq */
+ { NULL, TYPE_Bsx }, /* Bsx */
+ { NULL, TYPE_Bx }, /* Bx */
+ { NULL, 0 }, /* Db */
+ { NULL, 0 }, /* Dc */
+ { NULL, 0 }, /* Do */
+ { NULL, 0 }, /* Dq */
+ { NULL, 0 }, /* Ec */
+ { NULL, 0 }, /* Ef */
+ { NULL, TYPE_Em }, /* Em */
+ { NULL, 0 }, /* Eo */
+ { NULL, TYPE_Fx }, /* Fx */
+ { NULL, TYPE_Ms }, /* Ms */
+ { NULL, 0 }, /* No */
+ { NULL, 0 }, /* Ns */
+ { NULL, TYPE_Nx }, /* Nx */
+ { NULL, TYPE_Ox }, /* Ox */
+ { NULL, 0 }, /* Pc */
+ { NULL, 0 }, /* Pf */
+ { NULL, 0 }, /* Po */
+ { NULL, 0 }, /* Pq */
+ { NULL, 0 }, /* Qc */
+ { NULL, 0 }, /* Ql */
+ { NULL, 0 }, /* Qo */
+ { NULL, 0 }, /* Qq */
+ { NULL, 0 }, /* Re */
+ { NULL, 0 }, /* Rs */
+ { NULL, 0 }, /* Sc */
+ { NULL, 0 }, /* So */
+ { NULL, 0 }, /* Sq */
+ { NULL, 0 }, /* Sm */
+ { NULL, 0 }, /* Sx */
+ { NULL, TYPE_Sy }, /* Sy */
+ { NULL, TYPE_Tn }, /* Tn */
+ { NULL, 0 }, /* Ux */
+ { NULL, 0 }, /* Xc */
+ { NULL, 0 }, /* Xo */
+ { parse_mdoc_head, 0 }, /* Fo */
+ { NULL, 0 }, /* Fc */
+ { NULL, 0 }, /* Oo */
+ { NULL, 0 }, /* Oc */
+ { NULL, 0 }, /* Bk */
+ { NULL, 0 }, /* Ek */
+ { NULL, 0 }, /* Bt */
+ { NULL, 0 }, /* Hf */
+ { NULL, 0 }, /* Fr */
+ { NULL, 0 }, /* Ud */
+ { NULL, TYPE_Lb }, /* Lb */
+ { NULL, 0 }, /* Lp */
+ { NULL, TYPE_Lk }, /* Lk */
+ { NULL, TYPE_Mt }, /* Mt */
+ { NULL, 0 }, /* Brq */
+ { NULL, 0 }, /* Bro */
+ { NULL, 0 }, /* Brc */
+ { NULL, 0 }, /* %C */
+ { NULL, 0 }, /* Es */
+ { NULL, 0 }, /* En */
+ { NULL, TYPE_Dx }, /* Dx */
+ { NULL, 0 }, /* %Q */
+ { NULL, 0 }, /* br */
+ { NULL, 0 }, /* sp */
+ { NULL, 0 }, /* %U */
+ { NULL, 0 }, /* Ta */
+};
+
+
+int
+main(int argc, char *argv[])
+{
+ int ch, i;
+ size_t j, sz;
+ const char *path_arg;
+ struct mchars *mc;
+ struct manpaths dirs;
+ struct mparse *mp;
+ struct ohash_info mpages_info, mlinks_info;
+
+ memset(stmts, 0, STMT__MAX * sizeof(sqlite3_stmt *));
+ memset(&dirs, 0, sizeof(struct manpaths));
+
+ mpages_info.alloc = mlinks_info.alloc = hash_alloc;
+ mpages_info.calloc = mlinks_info.calloc = hash_calloc;
+ mpages_info.free = mlinks_info.free = hash_free;
+
+ mpages_info.key_offset = offsetof(struct mpage, inodev);
+ mlinks_info.key_offset = offsetof(struct mlink, file);
+
+ progname = strrchr(argv[0], '/');
+ if (progname == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ /*
+ * We accept a few different invocations.
+ * The CHECKOP macro makes sure that invocation styles don't
+ * clobber each other.
+ */
+#define CHECKOP(_op, _ch) do \
+ if (OP_DEFAULT != (_op)) { \
+ fprintf(stderr, "%s: -%c: Conflicting option\n", \
+ progname, (_ch)); \
+ goto usage; \
+ } while (/*CONSTCOND*/0)
+
+ path_arg = NULL;
+ op = OP_DEFAULT;
+
+ while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")))
+ switch (ch) {
+ case 'a':
+ use_all = 1;
+ break;
+ case 'C':
+ CHECKOP(op, ch);
+ path_arg = optarg;
+ op = OP_CONFFILE;
+ break;
+ case 'D':
+ debug++;
+ break;
+ case 'd':
+ CHECKOP(op, ch);
+ path_arg = optarg;
+ op = OP_UPDATE;
+ break;
+ case 'n':
+ nodb = 1;
+ break;
+ case 'p':
+ warnings = 1;
+ break;
+ case 'Q':
+ mparse_options |= MPARSE_QUICK;
+ break;
+ case 'T':
+ if (strcmp(optarg, "utf8")) {
+ fprintf(stderr, "%s: -T%s: "
+ "Unsupported output format\n",
+ progname, optarg);
+ goto usage;
+ }
+ write_utf8 = 1;
+ break;
+ case 't':
+ CHECKOP(op, ch);
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ op = OP_TEST;
+ nodb = warnings = 1;
+ break;
+ case 'u':
+ CHECKOP(op, ch);
+ path_arg = optarg;
+ op = OP_DELETE;
+ break;
+ case 'v':
+ /* Compatibility with espie@'s makewhatis. */
+ break;
+ default:
+ goto usage;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (OP_CONFFILE == op && argc > 0) {
+ fprintf(stderr, "%s: -C: Too many arguments\n",
+ progname);
+ goto usage;
+ }
+
+ exitcode = (int)MANDOCLEVEL_OK;
+ mp = mparse_alloc(mparse_options, MANDOCLEVEL_FATAL, NULL, NULL);
+ mc = mchars_alloc();
+
+ ohash_init(&mpages, 6, &mpages_info);
+ ohash_init(&mlinks, 6, &mlinks_info);
+
+ if (OP_UPDATE == op || OP_DELETE == op || OP_TEST == op) {
+
+ /*
+ * Most of these deal with a specific directory.
+ * Jump into that directory first.
+ */
+ if (OP_TEST != op && 0 == set_basedir(path_arg))
+ goto out;
+
+ if (dbopen(1)) {
+ /*
+ * The existing database is usable. Process
+ * all files specified on the command-line.
+ */
+ use_all = 1;
+ for (i = 0; i < argc; i++)
+ filescan(argv[i]);
+ if (OP_TEST != op)
+ dbprune();
+ } else {
+ /*
+ * Database missing or corrupt.
+ * Recreate from scratch.
+ */
+ exitcode = (int)MANDOCLEVEL_OK;
+ op = OP_DEFAULT;
+ if (0 == treescan())
+ goto out;
+ if (0 == dbopen(0))
+ goto out;
+ }
+ if (OP_DELETE != op)
+ mpages_merge(mc, mp);
+ dbclose(OP_DEFAULT == op ? 0 : 1);
+ } else {
+ /*
+ * If we have arguments, use them as our manpaths.
+ * If we don't, grok from manpath(1) or however else
+ * manpath_parse() wants to do it.
+ */
+ if (argc > 0) {
+ dirs.paths = mandoc_reallocarray(NULL,
+ argc, sizeof(char *));
+ dirs.sz = (size_t)argc;
+ for (i = 0; i < argc; i++)
+ dirs.paths[i] = mandoc_strdup(argv[i]);
+ } else
+ manpath_parse(&dirs, path_arg, NULL, NULL);
+
+ if (0 == dirs.sz) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say("", "Empty manpath");
+ }
+
+ /*
+ * First scan the tree rooted at a base directory, then
+ * build a new database and finally move it into place.
+ * Ignore zero-length directories and strip trailing
+ * slashes.
+ */
+ for (j = 0; j < dirs.sz; j++) {
+ sz = strlen(dirs.paths[j]);
+ if (sz && '/' == dirs.paths[j][sz - 1])
+ dirs.paths[j][--sz] = '\0';
+ if (0 == sz)
+ continue;
+
+ if (j) {
+ ohash_init(&mpages, 6, &mpages_info);
+ ohash_init(&mlinks, 6, &mlinks_info);
+ }
+
+ if (0 == set_basedir(dirs.paths[j]))
+ goto out;
+ if (0 == treescan())
+ goto out;
+ if (0 == dbopen(0))
+ goto out;
+
+ mpages_merge(mc, mp);
+ if (warnings && !nodb &&
+ ! (MPARSE_QUICK & mparse_options))
+ names_check();
+ dbclose(0);
+
+ if (j + 1 < dirs.sz) {
+ mpages_free();
+ ohash_delete(&mpages);
+ ohash_delete(&mlinks);
+ }
+ }
+ }
+out:
+ manpath_free(&dirs);
+ mchars_free(mc);
+ mparse_free(mp);
+ mpages_free();
+ ohash_delete(&mpages);
+ ohash_delete(&mlinks);
+ return(exitcode);
+usage:
+ fprintf(stderr, "usage: %s [-aDnpQ] [-C file] [-Tutf8]\n"
+ " %s [-aDnpQ] [-Tutf8] dir ...\n"
+ " %s [-DnpQ] [-Tutf8] -d dir [file ...]\n"
+ " %s [-Dnp] -u dir [file ...]\n"
+ " %s [-Q] -t file ...\n",
+ progname, progname, progname,
+ progname, progname);
+
+ return((int)MANDOCLEVEL_BADARG);
+}
+
+/*
+ * Scan a directory tree rooted at "basedir" for manpages.
+ * We use fts(), scanning directory parts along the way for clues to our
+ * section and architecture.
+ *
+ * If use_all has been specified, grok all files.
+ * If not, sanitise paths to the following:
+ *
+ * [./]man*[/<arch>]/<name>.<section>
+ * or
+ * [./]cat<section>[/<arch>]/<name>.0
+ *
+ * TODO: accomodate for multi-language directories.
+ */
+static int
+treescan(void)
+{
+ char buf[PATH_MAX];
+ FTS *f;
+ FTSENT *ff;
+ struct mlink *mlink;
+ int dform, gzip;
+ char *dsec, *arch, *fsec, *cp;
+ const char *path;
+ const char *argv[2];
+
+ argv[0] = ".";
+ argv[1] = (char *)NULL;
+
+ f = fts_open((char * const *)argv,
+ FTS_PHYSICAL | FTS_NOCHDIR, NULL);
+ if (NULL == f) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&fts_open");
+ return(0);
+ }
+
+ dsec = arch = NULL;
+ dform = FORM_NONE;
+
+ while (NULL != (ff = fts_read(f))) {
+ path = ff->fts_path + 2;
+ switch (ff->fts_info) {
+
+ /*
+ * Symbolic links require various sanity checks,
+ * then get handled just like regular files.
+ */
+ case FTS_SL:
+ if (NULL == realpath(path, buf)) {
+ if (warnings)
+ say(path, "&realpath");
+ continue;
+ }
+ if (strstr(buf, basedir) != buf) {
+ if (warnings) say("",
+ "%s: outside base directory", buf);
+ continue;
+ }
+ /* Use logical inode to avoid mpages dupe. */
+ if (-1 == stat(path, ff->fts_statp)) {
+ if (warnings)
+ say(path, "&stat");
+ continue;
+ }
+ /* FALLTHROUGH */
+
+ /*
+ * If we're a regular file, add an mlink by using the
+ * stored directory data and handling the filename.
+ */
+ case FTS_F:
+ if (0 == strcmp(path, MANDOC_DB))
+ continue;
+ if ( ! use_all && ff->fts_level < 2) {
+ if (warnings)
+ say(path, "Extraneous file");
+ continue;
+ }
+ gzip = 0;
+ fsec = NULL;
+ while (NULL == fsec) {
+ fsec = strrchr(ff->fts_name, '.');
+ if (NULL == fsec || strcmp(fsec+1, "gz"))
+ break;
+ gzip = 1;
+ *fsec = '\0';
+ fsec = NULL;
+ }
+ if (NULL == fsec) {
+ if ( ! use_all) {
+ if (warnings)
+ say(path,
+ "No filename suffix");
+ continue;
+ }
+ } else if (0 == strcmp(++fsec, "html")) {
+ if (warnings)
+ say(path, "Skip html");
+ continue;
+ } else if (0 == strcmp(fsec, "ps")) {
+ if (warnings)
+ say(path, "Skip ps");
+ continue;
+ } else if (0 == strcmp(fsec, "pdf")) {
+ if (warnings)
+ say(path, "Skip pdf");
+ continue;
+ } else if ( ! use_all &&
+ ((FORM_SRC == dform && strcmp(fsec, dsec)) ||
+ (FORM_CAT == dform && strcmp(fsec, "0")))) {
+ if (warnings)
+ say(path, "Wrong filename suffix");
+ continue;
+ } else
+ fsec[-1] = '\0';
+
+ mlink = mandoc_calloc(1, sizeof(struct mlink));
+ if (strlcpy(mlink->file, path,
+ sizeof(mlink->file)) >=
+ sizeof(mlink->file)) {
+ say(path, "Filename too long");
+ free(mlink);
+ continue;
+ }
+ mlink->dform = dform;
+ mlink->dsec = dsec;
+ mlink->arch = arch;
+ mlink->name = ff->fts_name;
+ mlink->fsec = fsec;
+ mlink->gzip = gzip;
+ mlink_add(mlink, ff->fts_statp);
+ continue;
+
+ case FTS_D:
+ /* FALLTHROUGH */
+ case FTS_DP:
+ break;
+
+ default:
+ if (warnings)
+ say(path, "Not a regular file");
+ continue;
+ }
+
+ switch (ff->fts_level) {
+ case 0:
+ /* Ignore the root directory. */
+ break;
+ case 1:
+ /*
+ * This might contain manX/ or catX/.
+ * Try to infer this from the name.
+ * If we're not in use_all, enforce it.
+ */
+ cp = ff->fts_name;
+ if (FTS_DP == ff->fts_info)
+ break;
+
+ if (0 == strncmp(cp, "man", 3)) {
+ dform = FORM_SRC;
+ dsec = cp + 3;
+ } else if (0 == strncmp(cp, "cat", 3)) {
+ dform = FORM_CAT;
+ dsec = cp + 3;
+ } else {
+ dform = FORM_NONE;
+ dsec = NULL;
+ }
+
+ if (NULL != dsec || use_all)
+ break;
+
+ if (warnings)
+ say(path, "Unknown directory part");
+ fts_set(f, ff, FTS_SKIP);
+ break;
+ case 2:
+ /*
+ * Possibly our architecture.
+ * If we're descending, keep tabs on it.
+ */
+ if (FTS_DP != ff->fts_info && NULL != dsec)
+ arch = ff->fts_name;
+ else
+ arch = NULL;
+ break;
+ default:
+ if (FTS_DP == ff->fts_info || use_all)
+ break;
+ if (warnings)
+ say(path, "Extraneous directory part");
+ fts_set(f, ff, FTS_SKIP);
+ break;
+ }
+ }
+
+ fts_close(f);
+ return(1);
+}
+
+/*
+ * Add a file to the mlinks table.
+ * Do not verify that it's a "valid" looking manpage (we'll do that
+ * later).
+ *
+ * Try to infer the manual section, architecture, and page name from the
+ * path, assuming it looks like
+ *
+ * [./]man*[/<arch>]/<name>.<section>
+ * or
+ * [./]cat<section>[/<arch>]/<name>.0
+ *
+ * See treescan() for the fts(3) version of this.
+ */
+static void
+filescan(const char *file)
+{
+ char buf[PATH_MAX];
+ struct stat st;
+ struct mlink *mlink;
+ char *p, *start;
+
+ assert(use_all);
+
+ if (0 == strncmp(file, "./", 2))
+ file += 2;
+
+ /*
+ * We have to do lstat(2) before realpath(3) loses
+ * the information whether this is a symbolic link.
+ * We need to know that because for symbolic links,
+ * we want to use the orginal file name, while for
+ * regular files, we want to use the real path.
+ */
+ if (-1 == lstat(file, &st)) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say(file, "&lstat");
+ return;
+ } else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say(file, "Not a regular file");
+ return;
+ }
+
+ /*
+ * We have to resolve the file name to the real path
+ * in any case for the base directory check.
+ */
+ if (NULL == realpath(file, buf)) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say(file, "&realpath");
+ return;
+ }
+
+ if (OP_TEST == op)
+ start = buf;
+ else if (strstr(buf, basedir) == buf)
+ start = buf + strlen(basedir);
+ else {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say("", "%s: outside base directory", buf);
+ return;
+ }
+
+ /*
+ * Now we are sure the file is inside our tree.
+ * If it is a symbolic link, ignore the real path
+ * and use the original name.
+ * This implies passing stuff like "cat1/../man1/foo.1"
+ * on the command line won't work. So don't do that.
+ * Note the stat(2) can still fail if the link target
+ * doesn't exist.
+ */
+ if (S_IFLNK & st.st_mode) {
+ if (-1 == stat(buf, &st)) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say(file, "&stat");
+ return;
+ }
+ if (strlcpy(buf, file, sizeof(buf)) >= sizeof(buf)) {
+ say(file, "Filename too long");
+ return;
+ }
+ start = buf;
+ if (OP_TEST != op && strstr(buf, basedir) == buf)
+ start += strlen(basedir);
+ }
+
+ mlink = mandoc_calloc(1, sizeof(struct mlink));
+ if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
+ sizeof(mlink->file)) {
+ say(start, "Filename too long");
+ return;
+ }
+
+ /*
+ * First try to guess our directory structure.
+ * If we find a separator, try to look for man* or cat*.
+ * If we find one of these and what's underneath is a directory,
+ * assume it's an architecture.
+ */
+ if (NULL != (p = strchr(start, '/'))) {
+ *p++ = '\0';
+ if (0 == strncmp(start, "man", 3)) {
+ mlink->dform = FORM_SRC;
+ mlink->dsec = start + 3;
+ } else if (0 == strncmp(start, "cat", 3)) {
+ mlink->dform = FORM_CAT;
+ mlink->dsec = start + 3;
+ }
+
+ start = p;
+ if (NULL != mlink->dsec && NULL != (p = strchr(start, '/'))) {
+ *p++ = '\0';
+ mlink->arch = start;
+ start = p;
+ }
+ }
+
+ /*
+ * Now check the file suffix.
+ * Suffix of `.0' indicates a catpage, `.1-9' is a manpage.
+ */
+ p = strrchr(start, '\0');
+ while (p-- > start && '/' != *p && '.' != *p)
+ /* Loop. */ ;
+
+ if ('.' == *p) {
+ *p++ = '\0';
+ mlink->fsec = p;
+ }
+
+ /*
+ * Now try to parse the name.
+ * Use the filename portion of the path.
+ */
+ mlink->name = start;
+ if (NULL != (p = strrchr(start, '/'))) {
+ mlink->name = p + 1;
+ *p = '\0';
+ }
+ mlink_add(mlink, &st);
+}
+
+static void
+mlink_add(struct mlink *mlink, const struct stat *st)
+{
+ struct inodev inodev;
+ struct mpage *mpage;
+ unsigned int slot;
+
+ assert(NULL != mlink->file);
+
+ mlink->dsec = mandoc_strdup(mlink->dsec ? mlink->dsec : "");
+ mlink->arch = mandoc_strdup(mlink->arch ? mlink->arch : "");
+ mlink->name = mandoc_strdup(mlink->name ? mlink->name : "");
+ mlink->fsec = mandoc_strdup(mlink->fsec ? mlink->fsec : "");
+
+ if ('0' == *mlink->fsec) {
+ free(mlink->fsec);
+ mlink->fsec = mandoc_strdup(mlink->dsec);
+ mlink->fform = FORM_CAT;
+ } else if ('1' <= *mlink->fsec && '9' >= *mlink->fsec)
+ mlink->fform = FORM_SRC;
+ else
+ mlink->fform = FORM_NONE;
+
+ slot = ohash_qlookup(&mlinks, mlink->file);
+ assert(NULL == ohash_find(&mlinks, slot));
+ ohash_insert(&mlinks, slot, mlink);
+
+ inodev.st_ino = st->st_ino;
+ inodev.st_dev = st->st_dev;
+ slot = ohash_lookup_memory(&mpages, (char *)&inodev,
+ sizeof(struct inodev), inodev.st_ino);
+ mpage = ohash_find(&mpages, slot);
+ if (NULL == mpage) {
+ mpage = mandoc_calloc(1, sizeof(struct mpage));
+ mpage->inodev.st_ino = inodev.st_ino;
+ mpage->inodev.st_dev = inodev.st_dev;
+ ohash_insert(&mpages, slot, mpage);
+ } else
+ mlink->next = mpage->mlinks;
+ mpage->mlinks = mlink;
+ mlink->mpage = mpage;
+}
+
+static void
+mlink_free(struct mlink *mlink)
+{
+
+ free(mlink->dsec);
+ free(mlink->arch);
+ free(mlink->name);
+ free(mlink->fsec);
+ free(mlink);
+}
+
+static void
+mpages_free(void)
+{
+ struct mpage *mpage;
+ struct mlink *mlink;
+ unsigned int slot;
+
+ mpage = ohash_first(&mpages, &slot);
+ while (NULL != mpage) {
+ while (NULL != (mlink = mpage->mlinks)) {
+ mpage->mlinks = mlink->next;
+ mlink_free(mlink);
+ }
+ free(mpage->sec);
+ free(mpage->arch);
+ free(mpage->title);
+ free(mpage->desc);
+ free(mpage);
+ mpage = ohash_next(&mpages, &slot);
+ }
+}
+
+/*
+ * For each mlink to the mpage, check whether the path looks like
+ * it is formatted, and if it does, check whether a source manual
+ * exists by the same name, ignoring the suffix.
+ * If both conditions hold, drop the mlink.
+ */
+static void
+mlinks_undupe(struct mpage *mpage)
+{
+ char buf[PATH_MAX];
+ struct mlink **prev;
+ struct mlink *mlink;
+ char *bufp;
+
+ mpage->form = FORM_CAT;
+ prev = &mpage->mlinks;
+ while (NULL != (mlink = *prev)) {
+ if (FORM_CAT != mlink->dform) {
+ mpage->form = FORM_NONE;
+ goto nextlink;
+ }
+ (void)strlcpy(buf, mlink->file, sizeof(buf));
+ bufp = strstr(buf, "cat");
+ assert(NULL != bufp);
+ memcpy(bufp, "man", 3);
+ if (NULL != (bufp = strrchr(buf, '.')))
+ *++bufp = '\0';
+ (void)strlcat(buf, mlink->dsec, sizeof(buf));
+ if (NULL == ohash_find(&mlinks,
+ ohash_qlookup(&mlinks, buf)))
+ goto nextlink;
+ if (warnings)
+ say(mlink->file, "Man source exists: %s", buf);
+ if (use_all)
+ goto nextlink;
+ *prev = mlink->next;
+ mlink_free(mlink);
+ continue;
+nextlink:
+ prev = &(*prev)->next;
+ }
+}
+
+static void
+mlink_check(struct mpage *mpage, struct mlink *mlink)
+{
+ struct str *str;
+ unsigned int slot;
+
+ /*
+ * Check whether the manual section given in a file
+ * agrees with the directory where the file is located.
+ * Some manuals have suffixes like (3p) on their
+ * section number either inside the file or in the
+ * directory name, some are linked into more than one
+ * section, like encrypt(1) = makekey(8).
+ */
+
+ if (FORM_SRC == mpage->form &&
+ strcasecmp(mpage->sec, mlink->dsec))
+ say(mlink->file, "Section \"%s\" manual in %s directory",
+ mpage->sec, mlink->dsec);
+
+ /*
+ * Manual page directories exist for each kernel
+ * architecture as returned by machine(1).
+ * However, many manuals only depend on the
+ * application architecture as returned by arch(1).
+ * For example, some (2/ARM) manuals are shared
+ * across the "armish" and "zaurus" kernel
+ * architectures.
+ * A few manuals are even shared across completely
+ * different architectures, for example fdformat(1)
+ * on amd64, i386, sparc, and sparc64.
+ */
+
+ if (strcasecmp(mpage->arch, mlink->arch))
+ say(mlink->file, "Architecture \"%s\" manual in "
+ "\"%s\" directory", mpage->arch, mlink->arch);
+
+ /*
+ * XXX
+ * parse_cat() doesn't set NAME_TITLE yet.
+ */
+
+ if (FORM_CAT == mpage->form)
+ return;
+
+ /*
+ * Check whether this mlink
+ * appears as a name in the NAME section.
+ */
+
+ slot = ohash_qlookup(&names, mlink->name);
+ str = ohash_find(&names, slot);
+ assert(NULL != str);
+ if ( ! (NAME_TITLE & str->mask))
+ say(mlink->file, "Name missing in NAME section");
+}
+
+/*
+ * Run through the files in the global vector "mpages"
+ * and add them to the database specified in "basedir".
+ *
+ * This handles the parsing scheme itself, using the cues of directory
+ * and filename to determine whether the file is parsable or not.
+ */
+static void
+mpages_merge(struct mchars *mc, struct mparse *mp)
+{
+ char any[] = "any";
+ struct ohash_info str_info;
+ int fd[2];
+ struct mpage *mpage, *mpage_dest;
+ struct mlink *mlink, *mlink_dest;
+ struct mdoc *mdoc;
+ struct man *man;
+ char *sodest;
+ char *cp;
+ pid_t child_pid;
+ int status;
+ unsigned int pslot;
+ enum mandoclevel lvl;
+
+ str_info.alloc = hash_alloc;
+ str_info.calloc = hash_calloc;
+ str_info.free = hash_free;
+ str_info.key_offset = offsetof(struct str, key);
+
+ if (0 == nodb)
+ SQL_EXEC("BEGIN TRANSACTION");
+
+ mpage = ohash_first(&mpages, &pslot);
+ while (NULL != mpage) {
+ mlinks_undupe(mpage);
+ if (NULL == mpage->mlinks) {
+ mpage = ohash_next(&mpages, &pslot);
+ continue;
+ }
+
+ name_mask = NAME_MASK;
+ ohash_init(&names, 4, &str_info);
+ ohash_init(&strings, 6, &str_info);
+ mparse_reset(mp);
+ mdoc = NULL;
+ man = NULL;
+ sodest = NULL;
+ child_pid = 0;
+ fd[0] = -1;
+ fd[1] = -1;
+
+ if (mpage->mlinks->gzip) {
+ if (-1 == pipe(fd)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file, "&pipe gunzip");
+ goto nextpage;
+ }
+ switch (child_pid = fork()) {
+ case -1:
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file, "&fork gunzip");
+ child_pid = 0;
+ close(fd[1]);
+ close(fd[0]);
+ goto nextpage;
+ case 0:
+ close(fd[0]);
+ if (-1 == dup2(fd[1], STDOUT_FILENO)) {
+ say(mpage->mlinks->file,
+ "&dup gunzip");
+ exit(1);
+ }
+ execlp("gunzip", "gunzip", "-c",
+ mpage->mlinks->file, NULL);
+ say(mpage->mlinks->file, "&exec gunzip");
+ exit(1);
+ default:
+ close(fd[1]);
+ break;
+ }
+ }
+
+ /*
+ * Try interpreting the file as mdoc(7) or man(7)
+ * source code, unless it is already known to be
+ * formatted. Fall back to formatted mode.
+ */
+ if (FORM_CAT != mpage->mlinks->dform ||
+ FORM_CAT != mpage->mlinks->fform) {
+ lvl = mparse_readfd(mp, fd[0], mpage->mlinks->file);
+ if (lvl < MANDOCLEVEL_FATAL)
+ mparse_result(mp, &mdoc, &man, &sodest);
+ }
+
+ if (NULL != sodest) {
+ mlink_dest = ohash_find(&mlinks,
+ ohash_qlookup(&mlinks, sodest));
+ if (NULL != mlink_dest) {
+
+ /* The .so target exists. */
+
+ mpage_dest = mlink_dest->mpage;
+ mlink = mpage->mlinks;
+ while (1) {
+ mlink->mpage = mpage_dest;
+
+ /*
+ * If the target was already
+ * processed, add the links
+ * to the database now.
+ * Otherwise, this will
+ * happen when we come
+ * to the target.
+ */
+
+ if (mpage_dest->pageid)
+ dbadd_mlink(mlink);
+
+ if (NULL == mlink->next)
+ break;
+ mlink = mlink->next;
+ }
+
+ /* Move all links to the target. */
+
+ mlink->next = mlink_dest->next;
+ mlink_dest->next = mpage->mlinks;
+ mpage->mlinks = NULL;
+ }
+ goto nextpage;
+ } else if (NULL != mdoc) {
+ mpage->form = FORM_SRC;
+ mpage->sec = mdoc_meta(mdoc)->msec;
+ mpage->sec = mandoc_strdup(
+ NULL == mpage->sec ? "" : mpage->sec);
+ mpage->arch = mdoc_meta(mdoc)->arch;
+ mpage->arch = mandoc_strdup(
+ NULL == mpage->arch ? "" : mpage->arch);
+ mpage->title =
+ mandoc_strdup(mdoc_meta(mdoc)->title);
+ } else if (NULL != man) {
+ mpage->form = FORM_SRC;
+ mpage->sec =
+ mandoc_strdup(man_meta(man)->msec);
+ mpage->arch =
+ mandoc_strdup(mpage->mlinks->arch);
+ mpage->title =
+ mandoc_strdup(man_meta(man)->title);
+ } else {
+ mpage->form = FORM_CAT;
+ mpage->sec =
+ mandoc_strdup(mpage->mlinks->dsec);
+ mpage->arch =
+ mandoc_strdup(mpage->mlinks->arch);
+ mpage->title =
+ mandoc_strdup(mpage->mlinks->name);
+ }
+ putkey(mpage, mpage->sec, TYPE_sec);
+ putkey(mpage, '\0' == *mpage->arch ?
+ any : mpage->arch, TYPE_arch);
+
+ for (mlink = mpage->mlinks; mlink; mlink = mlink->next) {
+ if ('\0' != *mlink->dsec)
+ putkey(mpage, mlink->dsec, TYPE_sec);
+ if ('\0' != *mlink->fsec)
+ putkey(mpage, mlink->fsec, TYPE_sec);
+ putkey(mpage, '\0' == *mlink->arch ?
+ any : mlink->arch, TYPE_arch);
+ putkey(mpage, mlink->name, NAME_FILE);
+ }
+
+ assert(NULL == mpage->desc);
+ if (NULL != mdoc) {
+ if (NULL != (cp = mdoc_meta(mdoc)->name))
+ putkey(mpage, cp, NAME_HEAD);
+ parse_mdoc(mpage, mdoc_node(mdoc));
+ } else if (NULL != man)
+ parse_man(mpage, man_node(man));
+ else
+ parse_cat(mpage, fd[0]);
+ if (NULL == mpage->desc)
+ mpage->desc = mandoc_strdup(mpage->mlinks->name);
+
+ if (warnings && !use_all)
+ for (mlink = mpage->mlinks; mlink;
+ mlink = mlink->next)
+ mlink_check(mpage, mlink);
+
+ dbadd(mpage, mc);
+
+nextpage:
+ if (child_pid) {
+ if (-1 == waitpid(child_pid, &status, 0)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file, "&wait gunzip");
+ } else if (WIFSIGNALED(status)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file,
+ "gunzip died from signal %d",
+ WTERMSIG(status));
+ } else if (WEXITSTATUS(status)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file,
+ "gunzip failed with code %d",
+ WEXITSTATUS(status));
+ }
+ }
+ ohash_delete(&strings);
+ ohash_delete(&names);
+ mpage = ohash_next(&mpages, &pslot);
+ }
+
+ if (0 == nodb)
+ SQL_EXEC("END TRANSACTION");
+}
+
+static void
+names_check(void)
+{
+ sqlite3_stmt *stmt;
+ const char *name, *sec, *arch, *key;
+ int irc;
+
+ sqlite3_prepare_v2(db,
+ "SELECT name, sec, arch, key FROM ("
+ "SELECT name AS key, pageid FROM names "
+ "WHERE bits & ? AND NOT EXISTS ("
+ "SELECT pageid FROM mlinks "
+ "WHERE mlinks.pageid == names.pageid "
+ "AND mlinks.name == names.name"
+ ")"
+ ") JOIN ("
+ "SELECT sec, arch, name, pageid FROM mlinks "
+ "GROUP BY pageid"
+ ") USING (pageid);",
+ -1, &stmt, NULL);
+
+ if (SQLITE_OK != sqlite3_bind_int64(stmt, 1, NAME_TITLE))
+ say("", "%s", sqlite3_errmsg(db));
+
+ while (SQLITE_ROW == (irc = sqlite3_step(stmt))) {
+ name = (const char *)sqlite3_column_text(stmt, 0);
+ sec = (const char *)sqlite3_column_text(stmt, 1);
+ arch = (const char *)sqlite3_column_text(stmt, 2);
+ key = (const char *)sqlite3_column_text(stmt, 3);
+ say("", "%s(%s%s%s) lacks mlink \"%s\"", name, sec,
+ '\0' == *arch ? "" : "/",
+ '\0' == *arch ? "" : arch, key);
+ }
+ sqlite3_finalize(stmt);
+}
+
+static void
+parse_cat(struct mpage *mpage, int fd)
+{
+ FILE *stream;
+ char *line, *p, *title;
+ size_t len, plen, titlesz;
+
+ stream = (-1 == fd) ?
+ fopen(mpage->mlinks->file, "r") :
+ fdopen(fd, "r");
+ if (NULL == stream) {
+ if (warnings)
+ say(mpage->mlinks->file, "&fopen");
+ return;
+ }
+
+ /* Skip to first blank line. */
+
+ while (NULL != (line = fgetln(stream, &len)))
+ if ('\n' == *line)
+ break;
+
+ /*
+ * Assume the first line that is not indented
+ * is the first section header. Skip to it.
+ */
+
+ while (NULL != (line = fgetln(stream, &len)))
+ if ('\n' != *line && ' ' != *line)
+ break;
+
+ /*
+ * Read up until the next section into a buffer.
+ * Strip the leading and trailing newline from each read line,
+ * appending a trailing space.
+ * Ignore empty (whitespace-only) lines.
+ */
+
+ titlesz = 0;
+ title = NULL;
+
+ while (NULL != (line = fgetln(stream, &len))) {
+ if (' ' != *line || '\n' != line[len - 1])
+ break;
+ while (len > 0 && isspace((unsigned char)*line)) {
+ line++;
+ len--;
+ }
+ if (1 == len)
+ continue;
+ title = mandoc_realloc(title, titlesz + len);
+ memcpy(title + titlesz, line, len);
+ titlesz += len;
+ title[titlesz - 1] = ' ';
+ }
+
+ /*
+ * If no page content can be found, or the input line
+ * is already the next section header, or there is no
+ * trailing newline, reuse the page title as the page
+ * description.
+ */
+
+ if (NULL == title || '\0' == *title) {
+ if (warnings)
+ say(mpage->mlinks->file,
+ "Cannot find NAME section");
+ fclose(stream);
+ free(title);
+ return;
+ }
+
+ title = mandoc_realloc(title, titlesz + 1);
+ title[titlesz] = '\0';
+
+ /*
+ * Skip to the first dash.
+ * Use the remaining line as the description (no more than 70
+ * bytes).
+ */
+
+ if (NULL != (p = strstr(title, "- "))) {
+ for (p += 2; ' ' == *p || '\b' == *p; p++)
+ /* Skip to next word. */ ;
+ } else {
+ if (warnings)
+ say(mpage->mlinks->file,
+ "No dash in title line");
+ p = title;
+ }
+
+ plen = strlen(p);
+
+ /* Strip backspace-encoding from line. */
+
+ while (NULL != (line = memchr(p, '\b', plen))) {
+ len = line - p;
+ if (0 == len) {
+ memmove(line, line + 1, plen--);
+ continue;
+ }
+ memmove(line - 1, line + 1, plen - len);
+ plen -= 2;
+ }
+
+ mpage->desc = mandoc_strdup(p);
+ fclose(stream);
+ free(title);
+}
+
+/*
+ * Put a type/word pair into the word database for this particular file.
+ */
+static void
+putkey(const struct mpage *mpage, char *value, uint64_t type)
+{
+ char *cp;
+
+ assert(NULL != value);
+ if (TYPE_arch == type)
+ for (cp = value; *cp; cp++)
+ if (isupper((unsigned char)*cp))
+ *cp = _tolower((unsigned char)*cp);
+ putkeys(mpage, value, strlen(value), type);
+}
+
+/*
+ * Grok all nodes at or below a certain mdoc node into putkey().
+ */
+static void
+putmdockey(const struct mpage *mpage,
+ const struct mdoc_node *n, uint64_t m)
+{
+
+ for ( ; NULL != n; n = n->next) {
+ if (NULL != n->child)
+ putmdockey(mpage, n->child, m);
+ if (MDOC_TEXT == n->type)
+ putkey(mpage, n->string, m);
+ }
+}
+
+static void
+parse_man(struct mpage *mpage, const struct man_node *n)
+{
+ const struct man_node *head, *body;
+ char *start, *title;
+ char byte;
+ size_t sz;
+
+ if (NULL == n)
+ return;
+
+ /*
+ * We're only searching for one thing: the first text child in
+ * the BODY of a NAME section. Since we don't keep track of
+ * sections in -man, run some hoops to find out whether we're in
+ * the correct section or not.
+ */
+
+ if (MAN_BODY == n->type && MAN_SH == n->tok) {
+ body = n;
+ assert(body->parent);
+ if (NULL != (head = body->parent->head) &&
+ 1 == head->nchild &&
+ NULL != (head = (head->child)) &&
+ MAN_TEXT == head->type &&
+ 0 == strcmp(head->string, "NAME") &&
+ NULL != body->child) {
+
+ /*
+ * Suck the entire NAME section into memory.
+ * Yes, we might run away.
+ * But too many manuals have big, spread-out
+ * NAME sections over many lines.
+ */
+
+ title = NULL;
+ man_deroff(&title, body);
+ if (NULL == title)
+ return;
+
+ /*
+ * Go through a special heuristic dance here.
+ * Conventionally, one or more manual names are
+ * comma-specified prior to a whitespace, then a
+ * dash, then a description. Try to puzzle out
+ * the name parts here.
+ */
+
+ start = title;
+ for ( ;; ) {
+ sz = strcspn(start, " ,");
+ if ('\0' == start[sz])
+ break;
+
+ byte = start[sz];
+ start[sz] = '\0';
+
+ /*
+ * Assume a stray trailing comma in the
+ * name list if a name begins with a dash.
+ */
+
+ if ('-' == start[0] ||
+ ('\\' == start[0] && '-' == start[1]))
+ break;
+
+ putkey(mpage, start, NAME_TITLE);
+
+ if (' ' == byte) {
+ start += sz + 1;
+ break;
+ }
+
+ assert(',' == byte);
+ start += sz + 1;
+ while (' ' == *start)
+ start++;
+ }
+
+ if (start == title) {
+ putkey(mpage, start, NAME_TITLE);
+ free(title);
+ return;
+ }
+
+ while (isspace((unsigned char)*start))
+ start++;
+
+ if (0 == strncmp(start, "-", 1))
+ start += 1;
+ else if (0 == strncmp(start, "\\-\\-", 4))
+ start += 4;
+ else if (0 == strncmp(start, "\\-", 2))
+ start += 2;
+ else if (0 == strncmp(start, "\\(en", 4))
+ start += 4;
+ else if (0 == strncmp(start, "\\(em", 4))
+ start += 4;
+
+ while (' ' == *start)
+ start++;
+
+ mpage->desc = mandoc_strdup(start);
+ free(title);
+ return;
+ }
+ }
+
+ for (n = n->child; n; n = n->next) {
+ if (NULL != mpage->desc)
+ break;
+ parse_man(mpage, n);
+ }
+}
+
+static void
+parse_mdoc(struct mpage *mpage, const struct mdoc_node *n)
+{
+
+ assert(NULL != n);
+ for (n = n->child; NULL != n; n = n->next) {
+ switch (n->type) {
+ case MDOC_ELEM:
+ /* FALLTHROUGH */
+ case MDOC_BLOCK:
+ /* FALLTHROUGH */
+ case MDOC_HEAD:
+ /* FALLTHROUGH */
+ case MDOC_BODY:
+ /* FALLTHROUGH */
+ case MDOC_TAIL:
+ if (NULL != mdocs[n->tok].fp)
+ if (0 == (*mdocs[n->tok].fp)(mpage, n))
+ break;
+ if (mdocs[n->tok].mask)
+ putmdockey(mpage, n->child,
+ mdocs[n->tok].mask);
+ break;
+ default:
+ assert(MDOC_ROOT != n->type);
+ continue;
+ }
+ if (NULL != n->child)
+ parse_mdoc(mpage, n);
+ }
+}
+
+static int
+parse_mdoc_Fd(struct mpage *mpage, const struct mdoc_node *n)
+{
+ const char *start, *end;
+ size_t sz;
+
+ if (SEC_SYNOPSIS != n->sec ||
+ NULL == (n = n->child) ||
+ MDOC_TEXT != n->type)
+ return(0);
+
+ /*
+ * Only consider those `Fd' macro fields that begin with an
+ * "inclusion" token (versus, e.g., #define).
+ */
+
+ if (strcmp("#include", n->string))
+ return(0);
+
+ if (NULL == (n = n->next) || MDOC_TEXT != n->type)
+ return(0);
+
+ /*
+ * Strip away the enclosing angle brackets and make sure we're
+ * not zero-length.
+ */
+
+ start = n->string;
+ if ('<' == *start || '"' == *start)
+ start++;
+
+ if (0 == (sz = strlen(start)))
+ return(0);
+
+ end = &start[(int)sz - 1];
+ if ('>' == *end || '"' == *end)
+ end--;
+
+ if (end > start)
+ putkeys(mpage, start, end - start + 1, TYPE_In);
+ return(0);
+}
+
+static int
+parse_mdoc_Fn(struct mpage *mpage, const struct mdoc_node *n)
+{
+ char *cp;
+
+ if (NULL == (n = n->child) || MDOC_TEXT != n->type)
+ return(0);
+
+ /*
+ * Parse: .Fn "struct type *name" "char *arg".
+ * First strip away pointer symbol.
+ * Then store the function name, then type.
+ * Finally, store the arguments.
+ */
+
+ if (NULL == (cp = strrchr(n->string, ' ')))
+ cp = n->string;
+
+ while ('*' == *cp)
+ cp++;
+
+ putkey(mpage, cp, TYPE_Fn);
+
+ if (n->string < cp)
+ putkeys(mpage, n->string, cp - n->string, TYPE_Ft);
+
+ for (n = n->next; NULL != n; n = n->next)
+ if (MDOC_TEXT == n->type)
+ putkey(mpage, n->string, TYPE_Fa);
+
+ return(0);
+}
+
+static int
+parse_mdoc_Xr(struct mpage *mpage, const struct mdoc_node *n)
+{
+ char *cp;
+
+ if (NULL == (n = n->child))
+ return(0);
+
+ if (NULL == n->next) {
+ putkey(mpage, n->string, TYPE_Xr);
+ return(0);
+ }
+
+ mandoc_asprintf(&cp, "%s(%s)", n->string, n->next->string);
+ putkey(mpage, cp, TYPE_Xr);
+ free(cp);
+ return(0);
+}
+
+static int
+parse_mdoc_Nd(struct mpage *mpage, const struct mdoc_node *n)
+{
+
+ if (MDOC_BODY == n->type)
+ mdoc_deroff(&mpage->desc, n);
+ return(0);
+}
+
+static int
+parse_mdoc_Nm(struct mpage *mpage, const struct mdoc_node *n)
+{
+
+ if (SEC_NAME == n->sec)
+ putmdockey(mpage, n->child, NAME_TITLE);
+ else if (SEC_SYNOPSIS == n->sec && MDOC_HEAD == n->type)
+ putmdockey(mpage, n->child, NAME_SYN);
+ return(0);
+}
+
+static int
+parse_mdoc_Sh(struct mpage *mpage, const struct mdoc_node *n)
+{
+
+ return(SEC_CUSTOM == n->sec && MDOC_HEAD == n->type);
+}
+
+static int
+parse_mdoc_head(struct mpage *mpage, const struct mdoc_node *n)
+{
+
+ return(MDOC_HEAD == n->type);
+}
+
+static int
+parse_mdoc_body(struct mpage *mpage, const struct mdoc_node *n)
+{
+
+ return(MDOC_BODY == n->type);
+}
+
+/*
+ * Add a string to the hash table for the current manual.
+ * Each string has a bitmask telling which macros it belongs to.
+ * When we finish the manual, we'll dump the table.
+ */
+static void
+putkeys(const struct mpage *mpage,
+ const char *cp, size_t sz, uint64_t v)
+{
+ struct ohash *htab;
+ struct str *s;
+ const char *end;
+ unsigned int slot;
+ int i;
+
+ if (0 == sz)
+ return;
+
+ if (TYPE_Nm & v) {
+ htab = &names;
+ v &= name_mask;
+ name_mask &= ~NAME_FIRST;
+ if (debug > 1)
+ say(mpage->mlinks->file,
+ "Adding name %*s", sz, cp);
+ } else {
+ htab = &strings;
+ if (debug > 1)
+ for (i = 0; i < mansearch_keymax; i++)
+ if (1 << i & v)
+ say(mpage->mlinks->file,
+ "Adding key %s=%*s",
+ mansearch_keynames[i], sz, cp);
+ }
+
+ end = cp + sz;
+ slot = ohash_qlookupi(htab, cp, &end);
+ s = ohash_find(htab, slot);
+
+ if (NULL != s && mpage == s->mpage) {
+ s->mask |= v;
+ return;
+ } else if (NULL == s) {
+ s = mandoc_calloc(1, sizeof(struct str) + sz + 1);
+ memcpy(s->key, cp, sz);
+ ohash_insert(htab, slot, s);
+ }
+ s->mpage = mpage;
+ s->mask = v;
+}
+
+/*
+ * Take a Unicode codepoint and produce its UTF-8 encoding.
+ * This isn't the best way to do this, but it works.
+ * The magic numbers are from the UTF-8 packaging.
+ * They're not as scary as they seem: read the UTF-8 spec for details.
+ */
+static size_t
+utf8(unsigned int cp, char out[7])
+{
+ size_t rc;
+
+ rc = 0;
+ if (cp <= 0x0000007F) {
+ rc = 1;
+ out[0] = (char)cp;
+ } else if (cp <= 0x000007FF) {
+ rc = 2;
+ out[0] = (cp >> 6 & 31) | 192;
+ out[1] = (cp & 63) | 128;
+ } else if (cp <= 0x0000FFFF) {
+ rc = 3;
+ out[0] = (cp >> 12 & 15) | 224;
+ out[1] = (cp >> 6 & 63) | 128;
+ out[2] = (cp & 63) | 128;
+ } else if (cp <= 0x001FFFFF) {
+ rc = 4;
+ out[0] = (cp >> 18 & 7) | 240;
+ out[1] = (cp >> 12 & 63) | 128;
+ out[2] = (cp >> 6 & 63) | 128;
+ out[3] = (cp & 63) | 128;
+ } else if (cp <= 0x03FFFFFF) {
+ rc = 5;
+ out[0] = (cp >> 24 & 3) | 248;
+ out[1] = (cp >> 18 & 63) | 128;
+ out[2] = (cp >> 12 & 63) | 128;
+ out[3] = (cp >> 6 & 63) | 128;
+ out[4] = (cp & 63) | 128;
+ } else if (cp <= 0x7FFFFFFF) {
+ rc = 6;
+ out[0] = (cp >> 30 & 1) | 252;
+ out[1] = (cp >> 24 & 63) | 128;
+ out[2] = (cp >> 18 & 63) | 128;
+ out[3] = (cp >> 12 & 63) | 128;
+ out[4] = (cp >> 6 & 63) | 128;
+ out[5] = (cp & 63) | 128;
+ } else
+ return(0);
+
+ out[rc] = '\0';
+ return(rc);
+}
+
+/*
+ * Store the rendered version of a key, or alias the pointer
+ * if the key contains no escape sequences.
+ */
+static void
+render_key(struct mchars *mc, struct str *key)
+{
+ size_t sz, bsz, pos;
+ char utfbuf[7], res[6];
+ char *buf;
+ const char *seq, *cpp, *val;
+ int len, u;
+ enum mandoc_esc esc;
+
+ assert(NULL == key->rendered);
+
+ res[0] = '\\';
+ res[1] = '\t';
+ res[2] = ASCII_NBRSP;
+ res[3] = ASCII_HYPH;
+ res[4] = ASCII_BREAK;
+ res[5] = '\0';
+
+ val = key->key;
+ bsz = strlen(val);
+
+ /*
+ * Pre-check: if we have no stop-characters, then set the
+ * pointer as ourselvse and get out of here.
+ */
+ if (strcspn(val, res) == bsz) {
+ key->rendered = key->key;
+ return;
+ }
+
+ /* Pre-allocate by the length of the input */
+
+ buf = mandoc_malloc(++bsz);
+ pos = 0;
+
+ while ('\0' != *val) {
+ /*
+ * Halt on the first escape sequence.
+ * This also halts on the end of string, in which case
+ * we just copy, fallthrough, and exit the loop.
+ */
+ if ((sz = strcspn(val, res)) > 0) {
+ memcpy(&buf[pos], val, sz);
+ pos += sz;
+ val += sz;
+ }
+
+ switch (*val) {
+ case ASCII_HYPH:
+ buf[pos++] = '-';
+ val++;
+ continue;
+ case '\t':
+ /* FALLTHROUGH */
+ case ASCII_NBRSP:
+ buf[pos++] = ' ';
+ val++;
+ /* FALLTHROUGH */
+ case ASCII_BREAK:
+ continue;
+ default:
+ break;
+ }
+ if ('\\' != *val)
+ break;
+
+ /* Read past the slash. */
+
+ val++;
+
+ /*
+ * Parse the escape sequence and see if it's a
+ * predefined character or special character.
+ */
+
+ esc = mandoc_escape((const char **)&val,
+ &seq, &len);
+ if (ESCAPE_ERROR == esc)
+ break;
+ if (ESCAPE_SPECIAL != esc)
+ continue;
+
+ /*
+ * Render the special character
+ * as either UTF-8 or ASCII.
+ */
+
+ if (write_utf8) {
+ if (0 == (u = mchars_spec2cp(mc, seq, len)))
+ continue;
+ cpp = utfbuf;
+ if (0 == (sz = utf8(u, utfbuf)))
+ continue;
+ sz = strlen(cpp);
+ } else {
+ cpp = mchars_spec2str(mc, seq, len, &sz);
+ if (NULL == cpp)
+ continue;
+ if (ASCII_NBRSP == *cpp) {
+ cpp = " ";
+ sz = 1;
+ }
+ }
+
+ /* Copy the rendered glyph into the stream. */
+
+ bsz += sz;
+ buf = mandoc_realloc(buf, bsz);
+ memcpy(&buf[pos], cpp, sz);
+ pos += sz;
+ }
+
+ buf[pos] = '\0';
+ key->rendered = buf;
+}
+
+static void
+dbadd_mlink(const struct mlink *mlink)
+{
+ size_t i;
+
+ i = 1;
+ SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->dsec);
+ SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->arch);
+ SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->name);
+ SQL_BIND_INT64(stmts[STMT_INSERT_LINK], i, mlink->mpage->pageid);
+ SQL_STEP(stmts[STMT_INSERT_LINK]);
+ sqlite3_reset(stmts[STMT_INSERT_LINK]);
+}
+
+/*
+ * Flush the current page's terms (and their bits) into the database.
+ * Wrap the entire set of additions in a transaction to make sqlite be a
+ * little faster.
+ * Also, handle escape sequences at the last possible moment.
+ */
+static void
+dbadd(struct mpage *mpage, struct mchars *mc)
+{
+ struct mlink *mlink;
+ struct str *key;
+ size_t i;
+ unsigned int slot;
+
+ mlink = mpage->mlinks;
+
+ if (nodb) {
+ for (key = ohash_first(&names, &slot); NULL != key;
+ key = ohash_next(&names, &slot)) {
+ if (key->rendered != key->key)
+ free(key->rendered);
+ free(key);
+ }
+ for (key = ohash_first(&strings, &slot); NULL != key;
+ key = ohash_next(&strings, &slot)) {
+ if (key->rendered != key->key)
+ free(key->rendered);
+ free(key);
+ }
+ if (0 == debug)
+ return;
+ while (NULL != mlink) {
+ fputs(mlink->name, stdout);
+ if (NULL == mlink->next ||
+ strcmp(mlink->dsec, mlink->next->dsec) ||
+ strcmp(mlink->fsec, mlink->next->fsec) ||
+ strcmp(mlink->arch, mlink->next->arch)) {
+ putchar('(');
+ if ('\0' == *mlink->dsec)
+ fputs(mlink->fsec, stdout);
+ else
+ fputs(mlink->dsec, stdout);
+ if ('\0' != *mlink->arch)
+ printf("/%s", mlink->arch);
+ putchar(')');
+ }
+ mlink = mlink->next;
+ if (NULL != mlink)
+ fputs(", ", stdout);
+ }
+ printf(" - %s\n", mpage->desc);
+ return;
+ }
+
+ if (debug)
+ say(mlink->file, "Adding to database");
+
+ i = strlen(mpage->desc) + 1;
+ key = mandoc_calloc(1, sizeof(struct str) + i);
+ memcpy(key->key, mpage->desc, i);
+ render_key(mc, key);
+
+ i = 1;
+ SQL_BIND_TEXT(stmts[STMT_INSERT_PAGE], i, key->rendered);
+ SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, FORM_SRC == mpage->form);
+ SQL_STEP(stmts[STMT_INSERT_PAGE]);
+ mpage->pageid = sqlite3_last_insert_rowid(db);
+ sqlite3_reset(stmts[STMT_INSERT_PAGE]);
+
+ if (key->rendered != key->key)
+ free(key->rendered);
+ free(key);
+
+ while (NULL != mlink) {
+ dbadd_mlink(mlink);
+ mlink = mlink->next;
+ }
+ mlink = mpage->mlinks;
+
+ for (key = ohash_first(&names, &slot); NULL != key;
+ key = ohash_next(&names, &slot)) {
+ assert(key->mpage == mpage);
+ if (NULL == key->rendered)
+ render_key(mc, key);
+ i = 1;
+ SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, key->mask);
+ SQL_BIND_TEXT(stmts[STMT_INSERT_NAME], i, key->rendered);
+ SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, mpage->pageid);
+ SQL_STEP(stmts[STMT_INSERT_NAME]);
+ sqlite3_reset(stmts[STMT_INSERT_NAME]);
+ if (key->rendered != key->key)
+ free(key->rendered);
+ free(key);
+ }
+ for (key = ohash_first(&strings, &slot); NULL != key;
+ key = ohash_next(&strings, &slot)) {
+ assert(key->mpage == mpage);
+ if (NULL == key->rendered)
+ render_key(mc, key);
+ i = 1;
+ SQL_BIND_INT64(stmts[STMT_INSERT_KEY], i, key->mask);
+ SQL_BIND_TEXT(stmts[STMT_INSERT_KEY], i, key->rendered);
+ SQL_BIND_INT64(stmts[STMT_INSERT_KEY], i, mpage->pageid);
+ SQL_STEP(stmts[STMT_INSERT_KEY]);
+ sqlite3_reset(stmts[STMT_INSERT_KEY]);
+ if (key->rendered != key->key)
+ free(key->rendered);
+ free(key);
+ }
+}
+
+static void
+dbprune(void)
+{
+ struct mpage *mpage;
+ struct mlink *mlink;
+ size_t i;
+ unsigned int slot;
+
+ if (0 == nodb)
+ SQL_EXEC("BEGIN TRANSACTION");
+
+ for (mpage = ohash_first(&mpages, &slot); NULL != mpage;
+ mpage = ohash_next(&mpages, &slot)) {
+ mlink = mpage->mlinks;
+ if (debug)
+ say(mlink->file, "Deleting from database");
+ if (nodb)
+ continue;
+ for ( ; NULL != mlink; mlink = mlink->next) {
+ i = 1;
+ SQL_BIND_TEXT(stmts[STMT_DELETE_PAGE],
+ i, mlink->dsec);
+ SQL_BIND_TEXT(stmts[STMT_DELETE_PAGE],
+ i, mlink->arch);
+ SQL_BIND_TEXT(stmts[STMT_DELETE_PAGE],
+ i, mlink->name);
+ SQL_STEP(stmts[STMT_DELETE_PAGE]);
+ sqlite3_reset(stmts[STMT_DELETE_PAGE]);
+ }
+ }
+
+ if (0 == nodb)
+ SQL_EXEC("END TRANSACTION");
+}
+
+/*
+ * Close an existing database and its prepared statements.
+ * If "real" is not set, rename the temporary file into the real one.
+ */
+static void
+dbclose(int real)
+{
+ size_t i;
+ int status;
+ pid_t child;
+
+ if (nodb)
+ return;
+
+ for (i = 0; i < STMT__MAX; i++) {
+ sqlite3_finalize(stmts[i]);
+ stmts[i] = NULL;
+ }
+
+ sqlite3_close(db);
+ db = NULL;
+
+ if (real)
+ return;
+
+ if ('\0' == *tempfilename) {
+ if (-1 == rename(MANDOC_DB "~", MANDOC_DB)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(MANDOC_DB, "&rename");
+ }
+ return;
+ }
+
+ switch (child = fork()) {
+ case -1:
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&fork cmp");
+ return;
+ case 0:
+ execlp("cmp", "cmp", "-s",
+ tempfilename, MANDOC_DB, NULL);
+ say("", "&exec cmp");
+ exit(0);
+ default:
+ break;
+ }
+ if (-1 == waitpid(child, &status, 0)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&wait cmp");
+ } else if (WIFSIGNALED(status)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "cmp died from signal %d", WTERMSIG(status));
+ } else if (WEXITSTATUS(status)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(MANDOC_DB,
+ "Data changed, but cannot replace database");
+ }
+
+ *strrchr(tempfilename, '/') = '\0';
+ switch (child = fork()) {
+ case -1:
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&fork rm");
+ return;
+ case 0:
+ execlp("rm", "rm", "-rf", tempfilename, NULL);
+ say("", "&exec rm");
+ exit((int)MANDOCLEVEL_SYSERR);
+ default:
+ break;
+ }
+ if (-1 == waitpid(child, &status, 0)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&wait rm");
+ } else if (WIFSIGNALED(status) || WEXITSTATUS(status)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "%s: Cannot remove temporary directory",
+ tempfilename);
+ }
+}
+
+/*
+ * This is straightforward stuff.
+ * Open a database connection to a "temporary" database, then open a set
+ * of prepared statements we'll use over and over again.
+ * If "real" is set, we use the existing database; if not, we truncate a
+ * temporary one.
+ * Must be matched by dbclose().
+ */
+static int
+dbopen(int real)
+{
+ const char *sql;
+ int rc, ofl;
+
+ if (nodb)
+ return(1);
+
+ *tempfilename = '\0';
+ ofl = SQLITE_OPEN_READWRITE;
+
+ if (real) {
+ rc = sqlite3_open_v2(MANDOC_DB, &db, ofl, NULL);
+ if (SQLITE_OK != rc) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ if (SQLITE_CANTOPEN != rc)
+ say(MANDOC_DB, "%s", sqlite3_errstr(rc));
+ return(0);
+ }
+ goto prepare_statements;
+ }
+
+ ofl |= SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE;
+
+ remove(MANDOC_DB "~");
+ rc = sqlite3_open_v2(MANDOC_DB "~", &db, ofl, NULL);
+ if (SQLITE_OK == rc)
+ goto create_tables;
+ if (MPARSE_QUICK & mparse_options) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(MANDOC_DB "~", "%s", sqlite3_errstr(rc));
+ return(0);
+ }
+
+ (void)strlcpy(tempfilename, "/tmp/mandocdb.XXXXXX",
+ sizeof(tempfilename));
+ if (NULL == mkdtemp(tempfilename)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&%s", tempfilename);
+ return(0);
+ }
+ (void)strlcat(tempfilename, "/" MANDOC_DB,
+ sizeof(tempfilename));
+ rc = sqlite3_open_v2(tempfilename, &db, ofl, NULL);
+ if (SQLITE_OK != rc) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "%s: %s", tempfilename, sqlite3_errstr(rc));
+ return(0);
+ }
+
+create_tables:
+ sql = "CREATE TABLE \"mpages\" (\n"
+ " \"desc\" TEXT NOT NULL,\n"
+ " \"form\" INTEGER NOT NULL,\n"
+ " \"pageid\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n"
+ ");\n"
+ "\n"
+ "CREATE TABLE \"mlinks\" (\n"
+ " \"sec\" TEXT NOT NULL,\n"
+ " \"arch\" TEXT NOT NULL,\n"
+ " \"name\" TEXT NOT NULL,\n"
+ " \"pageid\" INTEGER NOT NULL REFERENCES mpages(pageid) "
+ "ON DELETE CASCADE\n"
+ ");\n"
+ "CREATE INDEX mlinks_pageid_idx ON mlinks (pageid);\n"
+ "\n"
+ "CREATE TABLE \"names\" (\n"
+ " \"bits\" INTEGER NOT NULL,\n"
+ " \"name\" TEXT NOT NULL,\n"
+ " \"pageid\" INTEGER NOT NULL REFERENCES mpages(pageid) "
+ "ON DELETE CASCADE\n"
+ ");\n"
+ "\n"
+ "CREATE TABLE \"keys\" (\n"
+ " \"bits\" INTEGER NOT NULL,\n"
+ " \"key\" TEXT NOT NULL,\n"
+ " \"pageid\" INTEGER NOT NULL REFERENCES mpages(pageid) "
+ "ON DELETE CASCADE\n"
+ ");\n"
+ "CREATE INDEX keys_pageid_idx ON keys (pageid);\n";
+
+ if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(MANDOC_DB, "%s", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return(0);
+ }
+
+prepare_statements:
+ if (SQLITE_OK != sqlite3_exec(db,
+ "PRAGMA foreign_keys = ON", NULL, NULL, NULL)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(MANDOC_DB, "PRAGMA foreign_keys: %s",
+ sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return(0);
+ }
+
+ sql = "DELETE FROM mpages WHERE pageid IN "
+ "(SELECT pageid FROM mlinks WHERE "
+ "sec=? AND arch=? AND name=?)";
+ sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_DELETE_PAGE], NULL);
+ sql = "INSERT INTO mpages "
+ "(desc,form) VALUES (?,?)";
+ sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_PAGE], NULL);
+ sql = "INSERT INTO mlinks "
+ "(sec,arch,name,pageid) VALUES (?,?,?,?)";
+ sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_LINK], NULL);
+ sql = "INSERT INTO names "
+ "(bits,name,pageid) VALUES (?,?,?)";
+ sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_NAME], NULL);
+ sql = "INSERT INTO keys "
+ "(bits,key,pageid) VALUES (?,?,?)";
+ sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_KEY], NULL);
+
+#ifndef __APPLE__
+ /*
+ * When opening a new database, we can turn off
+ * synchronous mode for much better performance.
+ */
+
+ if (real && SQLITE_OK != sqlite3_exec(db,
+ "PRAGMA synchronous = OFF", NULL, NULL, NULL)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(MANDOC_DB, "PRAGMA synchronous: %s",
+ sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return(0);
+ }
+#endif
+
+ return(1);
+}
+
+static void *
+hash_calloc(size_t n, size_t sz, void *arg)
+{
+
+ return(mandoc_calloc(n, sz));
+}
+
+static void *
+hash_alloc(size_t sz, void *arg)
+{
+
+ return(mandoc_malloc(sz));
+}
+
+static void
+hash_free(void *p, void *arg)
+{
+
+ free(p);
+}
+
+static int
+set_basedir(const char *targetdir)
+{
+ static char startdir[PATH_MAX];
+ static int getcwd_status; /* 1 = ok, 2 = failure */
+ static int chdir_status; /* 1 = changed directory */
+ char *cp;
+
+ /*
+ * Remember the original working directory, if possible.
+ * This will be needed if the second or a later directory
+ * on the command line is given as a relative path.
+ * Do not error out if the current directory is not
+ * searchable: Maybe it won't be needed after all.
+ */
+ if (0 == getcwd_status) {
+ if (NULL == getcwd(startdir, sizeof(startdir))) {
+ getcwd_status = 2;
+ (void)strlcpy(startdir, strerror(errno),
+ sizeof(startdir));
+ } else
+ getcwd_status = 1;
+ }
+
+ /*
+ * We are leaving the old base directory.
+ * Do not use it any longer, not even for messages.
+ */
+ *basedir = '\0';
+
+ /*
+ * If and only if the directory was changed earlier and
+ * the next directory to process is given as a relative path,
+ * first go back, or bail out if that is impossible.
+ */
+ if (chdir_status && '/' != *targetdir) {
+ if (2 == getcwd_status) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "getcwd: %s", startdir);
+ return(0);
+ }
+ if (-1 == chdir(startdir)) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "&chdir %s", startdir);
+ return(0);
+ }
+ }
+
+ /*
+ * Always resolve basedir to the canonicalized absolute
+ * pathname and append a trailing slash, such that
+ * we can reliably check whether files are inside.
+ */
+ if (NULL == realpath(targetdir, basedir)) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say("", "&%s: realpath", targetdir);
+ return(0);
+ } else if (-1 == chdir(basedir)) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say("", "&chdir");
+ return(0);
+ }
+ chdir_status = 1;
+ cp = strchr(basedir, '\0');
+ if ('/' != cp[-1]) {
+ if (cp - basedir >= PATH_MAX - 1) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say("", "Filename too long");
+ return(0);
+ }
+ *cp++ = '/';
+ *cp = '\0';
+ }
+ return(1);
+}
+
+static void
+say(const char *file, const char *format, ...)
+{
+ va_list ap;
+ int use_errno;
+
+ if ('\0' != *basedir)
+ fprintf(stderr, "%s", basedir);
+ if ('\0' != *basedir && '\0' != *file)
+ fputc('/', stderr);
+ if ('\0' != *file)
+ fprintf(stderr, "%s", file);
+
+ use_errno = 1;
+ if (NULL != format) {
+ switch (*format) {
+ case '&':
+ format++;
+ break;
+ case '\0':
+ format = NULL;
+ break;
+ default:
+ use_errno = 0;
+ break;
+ }
+ }
+ if (NULL != format) {
+ if ('\0' != *basedir || '\0' != *file)
+ fputs(": ", stderr);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ }
+ if (use_errno) {
+ if ('\0' != *basedir || '\0' != *file || NULL != format)
+ fputs(": ", stderr);
+ perror(NULL);
+ } else
+ fputc('\n', stderr);
+}
diff --git a/contrib/mdocml/manpage.c b/contrib/mdocml/manpage.c
new file mode 100644
index 0000000..00793cc
--- /dev/null
+++ b/contrib/mdocml/manpage.c
@@ -0,0 +1,190 @@
+/* $Id: manpage.c,v 1.7 2014/01/06 03:02:46 schwarze Exp $ */
+/*
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "manpath.h"
+#include "mansearch.h"
+
+static void show(const char *, const char *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, term;
+ size_t i, sz, len;
+ struct mansearch search;
+ struct manpage *res;
+ char *conf_file, *defpaths, *auxpaths, *cp;
+ char buf[PATH_MAX];
+ const char *cmd;
+ struct manpaths paths;
+ char *progname;
+ extern char *optarg;
+ extern int optind;
+
+ term = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
+
+ progname = strrchr(argv[0], '/');
+ if (progname == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ auxpaths = defpaths = conf_file = NULL;
+ memset(&paths, 0, sizeof(struct manpaths));
+ memset(&search, 0, sizeof(struct mansearch));
+
+ while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
+ switch (ch) {
+ case ('C'):
+ conf_file = optarg;
+ break;
+ case ('M'):
+ defpaths = optarg;
+ break;
+ case ('m'):
+ auxpaths = optarg;
+ break;
+ case ('S'):
+ search.arch = optarg;
+ break;
+ case ('s'):
+ search.sec = optarg;
+ break;
+ default:
+ goto usage;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (0 == argc)
+ goto usage;
+
+ search.deftype = TYPE_Nm | TYPE_Nd;
+
+ manpath_parse(&paths, conf_file, defpaths, auxpaths);
+ ch = mansearch(&search, &paths, argc, argv, "Nd", &res, &sz);
+ manpath_free(&paths);
+
+ if (0 == ch)
+ goto usage;
+
+ if (0 == sz) {
+ free(res);
+ return(EXIT_FAILURE);
+ } else if (1 == sz && term) {
+ i = 1;
+ goto show;
+ } else if (NULL == res)
+ return(EXIT_FAILURE);
+
+ for (i = 0; i < sz; i++) {
+ printf("%6zu %s: %s\n",
+ i + 1, res[i].names, res[i].output);
+ free(res[i].names);
+ free(res[i].output);
+ }
+
+ if (0 == term) {
+ for (i = 0; i < sz; i++)
+ free(res[i].file);
+ free(res);
+ return(EXIT_SUCCESS);
+ }
+
+ i = 1;
+ printf("Enter a choice [1]: ");
+ fflush(stdout);
+
+ if (NULL != (cp = fgetln(stdin, &len)))
+ if ('\n' == cp[--len] && len > 0) {
+ cp[len] = '\0';
+ if ((i = atoi(cp)) < 1 || i > sz)
+ i = 0;
+ }
+
+ if (0 == i) {
+ for (i = 0; i < sz; i++)
+ free(res[i].file);
+ free(res);
+ return(EXIT_SUCCESS);
+ }
+show:
+ cmd = res[i - 1].form ? "mandoc" : "cat";
+ strlcpy(buf, res[i - 1].file, PATH_MAX);
+ for (i = 0; i < sz; i++)
+ free(res[i].file);
+ free(res);
+
+ show(cmd, buf);
+ /* NOTREACHED */
+usage:
+ fprintf(stderr, "usage: %s [-C conf] "
+ "[-M paths] "
+ "[-m paths] "
+ "[-S arch] "
+ "[-s section] "
+ "expr ...\n",
+ progname);
+ return(EXIT_FAILURE);
+}
+
+static void
+show(const char *cmd, const char *file)
+{
+ int fds[2];
+ pid_t pid;
+
+ if (-1 == pipe(fds)) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ if (-1 == (pid = fork())) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ } else if (pid > 0) {
+ dup2(fds[0], STDIN_FILENO);
+ close(fds[1]);
+ cmd = NULL != getenv("MANPAGER") ?
+ getenv("MANPAGER") :
+ (NULL != getenv("PAGER") ?
+ getenv("PAGER") : "more");
+ execlp(cmd, cmd, (char *)NULL);
+ perror(cmd);
+ exit(EXIT_FAILURE);
+ }
+
+ dup2(fds[1], STDOUT_FILENO);
+ close(fds[0]);
+ execlp(cmd, cmd, file, (char *)NULL);
+ perror(cmd);
+ exit(EXIT_FAILURE);
+}
diff --git a/contrib/mdocml/manpath.c b/contrib/mdocml/manpath.c
new file mode 100644
index 0000000..61b2c7e0
--- /dev/null
+++ b/contrib/mdocml/manpath.c
@@ -0,0 +1,222 @@
+/* $Id: manpath.c,v 1.15 2014/04/23 21:06:41 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mandoc_aux.h"
+#include "manpath.h"
+
+#define MAN_CONF_FILE "/etc/man.conf"
+#define MAN_CONF_KEY "_whatdb"
+
+static void manpath_add(struct manpaths *, const char *);
+static void manpath_parseline(struct manpaths *, char *);
+
+void
+manpath_parse(struct manpaths *dirs, const char *file,
+ char *defp, char *auxp)
+{
+#ifdef USE_MANPATH
+ char cmd[(PATH_MAX * 3) + 20];
+ FILE *stream;
+ char *buf;
+ size_t sz, bsz;
+
+ strlcpy(cmd, "manpath", sizeof(cmd));
+ if (file) {
+ strlcat(cmd, " -C ", sizeof(cmd));
+ strlcat(cmd, file, sizeof(cmd));
+ }
+ if (auxp) {
+ strlcat(cmd, " -m ", sizeof(cmd));
+ strlcat(cmd, auxp, sizeof(cmd));
+ }
+ if (defp) {
+ strlcat(cmd, " -M ", sizeof(cmd));
+ strlcat(cmd, defp, sizeof(cmd));
+ }
+
+ /* Open manpath(1). Ignore errors. */
+
+ stream = popen(cmd, "r");
+ if (NULL == stream)
+ return;
+
+ buf = NULL;
+ bsz = 0;
+
+ /* Read in as much output as we can. */
+
+ do {
+ buf = mandoc_realloc(buf, bsz + 1024);
+ sz = fread(buf + bsz, 1, 1024, stream);
+ bsz += sz;
+ } while (sz > 0);
+
+ if ( ! ferror(stream) && feof(stream) &&
+ bsz && '\n' == buf[bsz - 1]) {
+ buf[bsz - 1] = '\0';
+ manpath_parseline(dirs, buf);
+ }
+
+ free(buf);
+ pclose(stream);
+#else
+ char *insert;
+
+ /* Always prepend -m. */
+ manpath_parseline(dirs, auxp);
+
+ /* If -M is given, it overrides everything else. */
+ if (NULL != defp) {
+ manpath_parseline(dirs, defp);
+ return;
+ }
+
+ /* MANPATH and man.conf(5) cooperate. */
+ defp = getenv("MANPATH");
+ if (NULL == file)
+ file = MAN_CONF_FILE;
+
+ /* No MANPATH; use man.conf(5) only. */
+ if (NULL == defp || '\0' == defp[0]) {
+ manpath_manconf(dirs, file);
+ return;
+ }
+
+ /* Prepend man.conf(5) to MANPATH. */
+ if (':' == defp[0]) {
+ manpath_manconf(dirs, file);
+ manpath_parseline(dirs, defp);
+ return;
+ }
+
+ /* Append man.conf(5) to MANPATH. */
+ if (':' == defp[strlen(defp) - 1]) {
+ manpath_parseline(dirs, defp);
+ manpath_manconf(dirs, file);
+ return;
+ }
+
+ /* Insert man.conf(5) into MANPATH. */
+ insert = strstr(defp, "::");
+ if (NULL != insert) {
+ *insert++ = '\0';
+ manpath_parseline(dirs, defp);
+ manpath_manconf(dirs, file);
+ manpath_parseline(dirs, insert + 1);
+ return;
+ }
+
+ /* MANPATH overrides man.conf(5) completely. */
+ manpath_parseline(dirs, defp);
+#endif
+}
+
+/*
+ * Parse a FULL pathname from a colon-separated list of arrays.
+ */
+static void
+manpath_parseline(struct manpaths *dirs, char *path)
+{
+ char *dir;
+
+ if (NULL == path)
+ return;
+
+ for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
+ manpath_add(dirs, dir);
+}
+
+/*
+ * Add a directory to the array, ignoring bad directories.
+ * Grow the array one-by-one for simplicity's sake.
+ */
+static void
+manpath_add(struct manpaths *dirs, const char *dir)
+{
+ char buf[PATH_MAX];
+ char *cp;
+ size_t i;
+
+ if (NULL == (cp = realpath(dir, buf)))
+ return;
+
+ for (i = 0; i < dirs->sz; i++)
+ if (0 == strcmp(dirs->paths[i], dir))
+ return;
+
+ dirs->paths = mandoc_reallocarray(dirs->paths,
+ dirs->sz + 1, sizeof(char *));
+
+ dirs->paths[dirs->sz++] = mandoc_strdup(cp);
+}
+
+void
+manpath_free(struct manpaths *p)
+{
+ size_t i;
+
+ for (i = 0; i < p->sz; i++)
+ free(p->paths[i]);
+
+ free(p->paths);
+}
+
+void
+manpath_manconf(struct manpaths *dirs, const char *file)
+{
+ FILE *stream;
+ char *p, *q;
+ size_t len, keysz;
+
+ keysz = strlen(MAN_CONF_KEY);
+ assert(keysz > 0);
+
+ if (NULL == (stream = fopen(file, "r")))
+ return;
+
+ while (NULL != (p = fgetln(stream, &len))) {
+ if (0 == len || '\n' != p[--len])
+ break;
+ p[len] = '\0';
+ while (isspace((unsigned char)*p))
+ p++;
+ if (strncmp(MAN_CONF_KEY, p, keysz))
+ continue;
+ p += keysz;
+ while (isspace((unsigned char)*p))
+ p++;
+ if ('\0' == *p)
+ continue;
+ if (NULL == (q = strrchr(p, '/')))
+ continue;
+ *q = '\0';
+ manpath_add(dirs, p);
+ }
+
+ fclose(stream);
+}
diff --git a/contrib/mdocml/manpath.h b/contrib/mdocml/manpath.h
new file mode 100644
index 0000000..2fe1b36
--- /dev/null
+++ b/contrib/mdocml/manpath.h
@@ -0,0 +1,38 @@
+/* $Id: manpath.h,v 1.6 2012/06/08 10:32:40 kristaps Exp $ */
+/*
+ * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef MANPATH_H
+#define MANPATH_H
+
+/*
+ * Unsorted list of unique, absolute paths to be searched for manual
+ * databases.
+ */
+struct manpaths {
+ size_t sz;
+ char **paths;
+};
+
+__BEGIN_DECLS
+
+void manpath_manconf(struct manpaths *, const char *);
+void manpath_parse(struct manpaths *, const char *, char *, char *);
+void manpath_free(struct manpaths *);
+
+__END_DECLS
+
+#endif /*!MANPATH_H*/
diff --git a/contrib/mdocml/mansearch.3 b/contrib/mdocml/mansearch.3
new file mode 100644
index 0000000..28590e5
--- /dev/null
+++ b/contrib/mdocml/mansearch.3
@@ -0,0 +1,228 @@
+.\" $Id: mansearch.3,v 1.2 2014/08/05 15:29:30 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: August 5 2014 $
+.Dt MANSEARCH 3
+.Os
+.Sh NAME
+.Nm mansearch ,
+.Nm mansearch_setup
+.Nd search manual page databases
+.Sh SYNOPSIS
+.In stdint.h
+.In manpath.h
+.In mansearch.h
+.Ft int
+.Fo mansearch_setup
+.Fa "int start"
+.Fc
+.Ft int
+.Fo mansearch
+.Fa "const struct mansearch *search"
+.Fa "const struct manpaths *paths"
+.Fa "int argc"
+.Fa "char *argv[]"
+.Fa "const char *outkey"
+.Fa "struct manpage **res"
+.Fa "size_t *sz"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mansearch
+function returns information about manuals matching a search query from a
+.Xr mandoc.db 5
+SQLite3 database.
+.Pp
+The query arguments are as follows:
+.Bl -tag -width Ds
+.It Fa "const struct mansearch *search"
+Search options, defined in
+.In mansearch.h .
+.It Fa "const struct manpaths *paths"
+Directories to be searched, defined in
+.In manpath.h .
+.It Fa "int argc" , "char *argv[]"
+Search criteria, usually taken from the command line.
+.El
+.Pp
+The
+.Fa "const char *outkey"
+selects which data to return in the
+.Va output
+field of the
+.Fa res
+structures.
+It takes any of the macro keys defined in
+.Pa mansearch_const.c
+and described in
+.Xr apropos 1 .
+.Pp
+The output arguments are as follows:
+.Bl -tag -width Ds
+.It Fa "struct manpage **res"
+Returns a pointer to an array of result structures defined in
+.In mansearch.h .
+The user is expected to call
+.Xr free 3
+on the
+.Va file ,
+.Va names ,
+and
+.Va output
+fields of all structures, as well as the
+.Fa res
+array itself.
+.It Fa "size_t *sz"
+Returns the number of result structures contained in
+.Fa res .
+.El
+.Pp
+To speed up searches, the
+.Fn mansearch_setup
+function can optionally be called with a
+.Fa start
+argument of 1 before
+.Fn mansearch
+to set up an SQLite3 pagecache.
+If it was called, it has to be called again with a
+.Fa start
+argument of 0 after the last call to
+.Fn mansearch
+to release the memory used for the pagecache.
+.Sh IMPLEMENTATION NOTES
+For each manual page tree, the search is done in two steps.
+In the first step, a list of pages matching the search criteria is built.
+In the second step, the requested information about these pages is
+retrieved from the database and assembled into the
+.Fa res
+array.
+.Pp
+All function mentioned here are defined in the file
+.Pa mansearch.c .
+No functions except
+.Fn mansearch
+and
+.Fn sql_statement
+build any SQL code, and no functions except
+.Fn mansearch ,
+.Fn buildnames ,
+and
+.Fn buildoutput
+execute it.
+.Ss Finding matches
+The query is built using the following grammar:
+.Bd -literal -offset indent
+<query> ::= "SELECT * FROM mpages WHERE" <condition>
+<condition> ::= "(" <condition> ")" |
+ <condition> "OR" <condition> |
+ <condition> "AND" <condition> |
+ "desc" <operator> "?" |
+ "id IN (SELECT pageid FROM" <subquery> ")"
+<subquery> ::= "names WHERE name" <operator> "?" |
+ "keys WHERE key" <operator> "? AND bits & ?"
+<operator> ::= "MATCH" | "REGEXP"
+.Ed
+.Pp
+The MATCH and REGEXP operators are implemented by the functions
+.Fn sql_match
+and
+.Fn sql_regexp ,
+respectively.
+This is required because SQLite3 natively neither supports
+case-insensitive substring matching nor regular expression matching,
+but only string identity, shell globbing, and the weird home-brewed
+LIKE operator.
+.Pp
+Command line parsing is done by the function
+.Fn exprcomp
+building a singly linked list of
+.Vt expr
+structures, using the helper functions
+.Fn exprterm
+and
+.Fn exprspec .
+The resulting SQL statement is assembled by the function
+.Fn sql_statement
+and evaluated in the main loop of the
+.Fn mansearch
+function.
+.Ss Assembling the results
+The names, sections, and architectures of the manuals found
+are assembled into the
+.Va names
+field of the result structure by the function
+.Fn buildnames ,
+using the following query:
+.Pp
+.Dl "SELECT * FROM mlinks WHERE pageid=? ORDER BY sec, arch, name"
+.Pp
+If the
+.Fa outkey
+differs from
+.Qq Nd ,
+the requested output data is assembled into the
+.Va output
+field of the result structure by the function
+.Fn buildoutput ,
+using the following query:
+.Pp
+.Dl "SELECT * FROM keys WHERE pageid=? AND bits & ?"
+.Sh FILES
+.Bl -tag -width mandoc.db -compact
+.It Pa mandoc.db
+The manual page database.
+.El
+.Sh EXAMPLES
+The simplest invocation
+.Pp
+.Dl apropos keyword
+.Pp
+results in the following SQL query:
+.Bd -literal
+SELECT * FROM mpages WHERE (
+ id IN (SELECT pageid FROM names WHERE name MATCH 'keyword') OR
+ desc MATCH 'keyword'
+);
+.Ed
+.Pp
+A more complicated request like
+.Pp
+.Dl apropos -s 2 Nm,Xr=getuid
+.Pp
+results in:
+.Bd -literal
+SELECT * FROM mpages WHERE (
+ id IN (SELECT pageid FROM names WHERE name MATCH 'getuid') OR
+ id IN (SELECT pageid FROM keys WHERE key MATCH 'getuid' AND bits & 4)
+) AND id IN (SELECT pageid FROM keys WHERE key REGEXP '^2$' AND bits & 2);
+.Ed
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr mandoc.db 5 ,
+.Xr makewhatis 8
+.Sh HISTORY
+The
+.Fn mansearch
+subsystem first appeared in
+.Ox 5.6 .
+.Sh AUTHORS
+.An -nosplit
+A module to search manual page databases was first written by
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+in 2011, at first using the Berkeley DB;
+he rewrote it for SQLite3 in 2012.
+The current version received major changes from
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/contrib/mdocml/mansearch.c b/contrib/mdocml/mansearch.c
new file mode 100644
index 0000000..e1226b1
--- /dev/null
+++ b/contrib/mdocml/mansearch.c
@@ -0,0 +1,861 @@
+/* $Id: mansearch.c,v 1.42 2014/08/09 14:24:53 schwarze Exp $ */
+/*
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/mman.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_OHASH
+#include <ohash.h>
+#else
+#include "compat_ohash.h"
+#endif
+#include <sqlite3.h>
+#ifndef SQLITE_DETERMINISTIC
+#define SQLITE_DETERMINISTIC 0
+#endif
+
+#include "mandoc.h"
+#include "mandoc_aux.h"
+#include "manpath.h"
+#include "mansearch.h"
+
+extern int mansearch_keymax;
+extern const char *const mansearch_keynames[];
+
+#define SQL_BIND_TEXT(_db, _s, _i, _v) \
+ do { if (SQLITE_OK != sqlite3_bind_text \
+ ((_s), (_i)++, (_v), -1, SQLITE_STATIC)) \
+ fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
+ } while (0)
+#define SQL_BIND_INT64(_db, _s, _i, _v) \
+ do { if (SQLITE_OK != sqlite3_bind_int64 \
+ ((_s), (_i)++, (_v))) \
+ fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
+ } while (0)
+#define SQL_BIND_BLOB(_db, _s, _i, _v) \
+ do { if (SQLITE_OK != sqlite3_bind_blob \
+ ((_s), (_i)++, (&_v), sizeof(_v), SQLITE_STATIC)) \
+ fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
+ } while (0)
+
+struct expr {
+ regex_t regexp; /* compiled regexp, if applicable */
+ const char *substr; /* to search for, if applicable */
+ struct expr *next; /* next in sequence */
+ uint64_t bits; /* type-mask */
+ int equal; /* equality, not subsring match */
+ int open; /* opening parentheses before */
+ int and; /* logical AND before */
+ int close; /* closing parentheses after */
+};
+
+struct match {
+ uint64_t pageid; /* identifier in database */
+ char *desc; /* manual page description */
+ int form; /* 0 == catpage */
+};
+
+static void buildnames(struct manpage *, sqlite3 *,
+ sqlite3_stmt *, uint64_t,
+ const char *, int form);
+static char *buildoutput(sqlite3 *, sqlite3_stmt *,
+ uint64_t, uint64_t);
+static void *hash_alloc(size_t, void *);
+static void hash_free(void *, void *);
+static void *hash_calloc(size_t, size_t, void *);
+static struct expr *exprcomp(const struct mansearch *,
+ int, char *[]);
+static void exprfree(struct expr *);
+static struct expr *exprspec(struct expr *, uint64_t,
+ const char *, const char *);
+static struct expr *exprterm(const struct mansearch *, char *, int);
+static int manpage_compare(const void *, const void *);
+static void sql_append(char **sql, size_t *sz,
+ const char *newstr, int count);
+static void sql_match(sqlite3_context *context,
+ int argc, sqlite3_value **argv);
+static void sql_regexp(sqlite3_context *context,
+ int argc, sqlite3_value **argv);
+static char *sql_statement(const struct expr *);
+
+
+int
+mansearch_setup(int start)
+{
+ static void *pagecache;
+ int c;
+
+#define PC_PAGESIZE 1280
+#define PC_NUMPAGES 256
+
+ if (start) {
+ if (NULL != pagecache) {
+ fprintf(stderr, "pagecache already enabled\n");
+ return((int)MANDOCLEVEL_BADARG);
+ }
+
+ pagecache = mmap(NULL, PC_PAGESIZE * PC_NUMPAGES,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANON, -1, 0);
+
+ if (MAP_FAILED == pagecache) {
+ perror("mmap");
+ pagecache = NULL;
+ return((int)MANDOCLEVEL_SYSERR);
+ }
+
+ c = sqlite3_config(SQLITE_CONFIG_PAGECACHE,
+ pagecache, PC_PAGESIZE, PC_NUMPAGES);
+
+ if (SQLITE_OK == c)
+ return((int)MANDOCLEVEL_OK);
+
+ fprintf(stderr, "pagecache: %s\n", sqlite3_errstr(c));
+
+ } else if (NULL == pagecache) {
+ fprintf(stderr, "pagecache missing\n");
+ return((int)MANDOCLEVEL_BADARG);
+ }
+
+ if (-1 == munmap(pagecache, PC_PAGESIZE * PC_NUMPAGES)) {
+ perror("munmap");
+ pagecache = NULL;
+ return((int)MANDOCLEVEL_SYSERR);
+ }
+
+ pagecache = NULL;
+ return((int)MANDOCLEVEL_OK);
+}
+
+int
+mansearch(const struct mansearch *search,
+ const struct manpaths *paths,
+ int argc, char *argv[],
+ const char *outkey,
+ struct manpage **res, size_t *sz)
+{
+ int fd, rc, c, indexbit;
+ int64_t pageid;
+ uint64_t outbit, iterbit;
+ char buf[PATH_MAX];
+ char *sql;
+ struct manpage *mpage;
+ struct expr *e, *ep;
+ sqlite3 *db;
+ sqlite3_stmt *s, *s2;
+ struct match *mp;
+ struct ohash_info info;
+ struct ohash htab;
+ unsigned int idx;
+ size_t i, j, cur, maxres;
+
+ info.calloc = hash_calloc;
+ info.alloc = hash_alloc;
+ info.free = hash_free;
+ info.key_offset = offsetof(struct match, pageid);
+
+ *sz = cur = maxres = 0;
+ sql = NULL;
+ *res = NULL;
+ fd = -1;
+ e = NULL;
+ rc = 0;
+
+ if (0 == argc)
+ goto out;
+ if (NULL == (e = exprcomp(search, argc, argv)))
+ goto out;
+
+ outbit = 0;
+ if (NULL != outkey) {
+ for (indexbit = 0, iterbit = 1;
+ indexbit < mansearch_keymax;
+ indexbit++, iterbit <<= 1) {
+ if (0 == strcasecmp(outkey,
+ mansearch_keynames[indexbit])) {
+ outbit = iterbit;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Save a descriptor to the current working directory.
+ * Since pathnames in the "paths" variable might be relative,
+ * and we'll be chdir()ing into them, we need to keep a handle
+ * on our current directory from which to start the chdir().
+ */
+
+ if (NULL == getcwd(buf, PATH_MAX)) {
+ perror("getcwd");
+ goto out;
+ } else if (-1 == (fd = open(buf, O_RDONLY, 0))) {
+ perror(buf);
+ goto out;
+ }
+
+ sql = sql_statement(e);
+
+ /*
+ * Loop over the directories (containing databases) for us to
+ * search.
+ * Don't let missing/bad databases/directories phase us.
+ * In each, try to open the resident database and, if it opens,
+ * scan it for our match expression.
+ */
+
+ for (i = 0; i < paths->sz; i++) {
+ if (-1 == fchdir(fd)) {
+ perror(buf);
+ free(*res);
+ break;
+ } else if (-1 == chdir(paths->paths[i])) {
+ perror(paths->paths[i]);
+ continue;
+ }
+
+ c = sqlite3_open_v2(MANDOC_DB, &db,
+ SQLITE_OPEN_READONLY, NULL);
+
+ if (SQLITE_OK != c) {
+ perror(MANDOC_DB);
+ sqlite3_close(db);
+ continue;
+ }
+
+ /*
+ * Define the SQL functions for substring
+ * and regular expression matching.
+ */
+
+ c = sqlite3_create_function(db, "match", 2,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+ NULL, sql_match, NULL, NULL);
+ assert(SQLITE_OK == c);
+ c = sqlite3_create_function(db, "regexp", 2,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+ NULL, sql_regexp, NULL, NULL);
+ assert(SQLITE_OK == c);
+
+ j = 1;
+ c = sqlite3_prepare_v2(db, sql, -1, &s, NULL);
+ if (SQLITE_OK != c)
+ fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+
+ for (ep = e; NULL != ep; ep = ep->next) {
+ if (NULL == ep->substr) {
+ SQL_BIND_BLOB(db, s, j, ep->regexp);
+ } else
+ SQL_BIND_TEXT(db, s, j, ep->substr);
+ if (0 == ((TYPE_Nd | TYPE_Nm) & ep->bits))
+ SQL_BIND_INT64(db, s, j, ep->bits);
+ }
+
+ memset(&htab, 0, sizeof(struct ohash));
+ ohash_init(&htab, 4, &info);
+
+ /*
+ * Hash each entry on its [unique] document identifier.
+ * This is a uint64_t.
+ * Instead of using a hash function, simply convert the
+ * uint64_t to a uint32_t, the hash value's type.
+ * This gives good performance and preserves the
+ * distribution of buckets in the table.
+ */
+ while (SQLITE_ROW == (c = sqlite3_step(s))) {
+ pageid = sqlite3_column_int64(s, 2);
+ idx = ohash_lookup_memory(&htab,
+ (char *)&pageid, sizeof(uint64_t),
+ (uint32_t)pageid);
+
+ if (NULL != ohash_find(&htab, idx))
+ continue;
+
+ mp = mandoc_calloc(1, sizeof(struct match));
+ mp->pageid = pageid;
+ mp->form = sqlite3_column_int(s, 1);
+ if (TYPE_Nd == outbit)
+ mp->desc = mandoc_strdup((const char *)
+ sqlite3_column_text(s, 0));
+ ohash_insert(&htab, idx, mp);
+ }
+
+ if (SQLITE_DONE != c)
+ fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+
+ sqlite3_finalize(s);
+
+ c = sqlite3_prepare_v2(db,
+ "SELECT sec, arch, name, pageid FROM mlinks "
+ "WHERE pageid=? ORDER BY sec, arch, name",
+ -1, &s, NULL);
+ if (SQLITE_OK != c)
+ fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+
+ c = sqlite3_prepare_v2(db,
+ "SELECT bits, key, pageid FROM keys "
+ "WHERE pageid=? AND bits & ?",
+ -1, &s2, NULL);
+ if (SQLITE_OK != c)
+ fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+
+ for (mp = ohash_first(&htab, &idx);
+ NULL != mp;
+ mp = ohash_next(&htab, &idx)) {
+ if (cur + 1 > maxres) {
+ maxres += 1024;
+ *res = mandoc_reallocarray(*res,
+ maxres, sizeof(struct manpage));
+ }
+ mpage = *res + cur;
+ mpage->sec = 10;
+ mpage->form = mp->form;
+ buildnames(mpage, db, s, mp->pageid,
+ paths->paths[i], mp->form);
+ mpage->output = TYPE_Nd & outbit ?
+ mp->desc : outbit ?
+ buildoutput(db, s2, mp->pageid, outbit) : NULL;
+
+ free(mp);
+ cur++;
+ }
+
+ sqlite3_finalize(s);
+ sqlite3_finalize(s2);
+ sqlite3_close(db);
+ ohash_delete(&htab);
+ }
+ qsort(*res, cur, sizeof(struct manpage), manpage_compare);
+ rc = 1;
+out:
+ if (-1 != fd) {
+ if (-1 == fchdir(fd))
+ perror(buf);
+ close(fd);
+ }
+ exprfree(e);
+ free(sql);
+ *sz = cur;
+ return(rc);
+}
+
+static int
+manpage_compare(const void *vp1, const void *vp2)
+{
+ const struct manpage *mp1, *mp2;
+ int diff;
+
+ mp1 = vp1;
+ mp2 = vp2;
+ diff = mp1->sec - mp2->sec;
+ return(diff ? diff : strcasecmp(mp1->names, mp2->names));
+}
+
+static void
+buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
+ uint64_t pageid, const char *path, int form)
+{
+ char *newnames, *prevsec, *prevarch;
+ const char *oldnames, *sep1, *name, *sec, *sep2, *arch, *fsec;
+ size_t i;
+ int c;
+
+ mpage->file = NULL;
+ mpage->names = NULL;
+ prevsec = prevarch = NULL;
+ i = 1;
+ SQL_BIND_INT64(db, s, i, pageid);
+ while (SQLITE_ROW == (c = sqlite3_step(s))) {
+
+ /* Decide whether we already have some names. */
+
+ if (NULL == mpage->names) {
+ oldnames = "";
+ sep1 = "";
+ } else {
+ oldnames = mpage->names;
+ sep1 = ", ";
+ }
+
+ /* Fetch the next name. */
+
+ sec = (const char *)sqlite3_column_text(s, 0);
+ arch = (const char *)sqlite3_column_text(s, 1);
+ name = (const char *)sqlite3_column_text(s, 2);
+
+ /* Remember the first section found. */
+
+ if (9 < mpage->sec && '1' <= *sec && '9' >= *sec)
+ mpage->sec = (*sec - '1') + 1;
+
+ /* If the section changed, append the old one. */
+
+ if (NULL != prevsec &&
+ (strcmp(sec, prevsec) ||
+ strcmp(arch, prevarch))) {
+ sep2 = '\0' == *prevarch ? "" : "/";
+ mandoc_asprintf(&newnames, "%s(%s%s%s)",
+ oldnames, prevsec, sep2, prevarch);
+ free(mpage->names);
+ oldnames = mpage->names = newnames;
+ free(prevsec);
+ free(prevarch);
+ prevsec = prevarch = NULL;
+ }
+
+ /* Save the new section, to append it later. */
+
+ if (NULL == prevsec) {
+ prevsec = mandoc_strdup(sec);
+ prevarch = mandoc_strdup(arch);
+ }
+
+ /* Append the new name. */
+
+ mandoc_asprintf(&newnames, "%s%s%s",
+ oldnames, sep1, name);
+ free(mpage->names);
+ mpage->names = newnames;
+
+ /* Also save the first file name encountered. */
+
+ if (NULL != mpage->file)
+ continue;
+
+ if (form) {
+ sep1 = "man";
+ fsec = sec;
+ } else {
+ sep1 = "cat";
+ fsec = "0";
+ }
+ sep2 = '\0' == *arch ? "" : "/";
+ mandoc_asprintf(&mpage->file, "%s/%s%s%s%s/%s.%s",
+ path, sep1, sec, sep2, arch, name, fsec);
+ }
+ if (SQLITE_DONE != c)
+ fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+ sqlite3_reset(s);
+
+ /* Append one final section to the names. */
+
+ if (NULL != prevsec) {
+ sep2 = '\0' == *prevarch ? "" : "/";
+ mandoc_asprintf(&newnames, "%s(%s%s%s)",
+ mpage->names, prevsec, sep2, prevarch);
+ free(mpage->names);
+ mpage->names = newnames;
+ free(prevsec);
+ free(prevarch);
+ }
+}
+
+static char *
+buildoutput(sqlite3 *db, sqlite3_stmt *s, uint64_t pageid, uint64_t outbit)
+{
+ char *output, *newoutput;
+ const char *oldoutput, *sep1, *data;
+ size_t i;
+ int c;
+
+ output = NULL;
+ i = 1;
+ SQL_BIND_INT64(db, s, i, pageid);
+ SQL_BIND_INT64(db, s, i, outbit);
+ while (SQLITE_ROW == (c = sqlite3_step(s))) {
+ if (NULL == output) {
+ oldoutput = "";
+ sep1 = "";
+ } else {
+ oldoutput = output;
+ sep1 = " # ";
+ }
+ data = (const char *)sqlite3_column_text(s, 1);
+ mandoc_asprintf(&newoutput, "%s%s%s",
+ oldoutput, sep1, data);
+ free(output);
+ output = newoutput;
+ }
+ if (SQLITE_DONE != c)
+ fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+ sqlite3_reset(s);
+ return(output);
+}
+
+/*
+ * Implement substring match as an application-defined SQL function.
+ * Using the SQL LIKE or GLOB operators instead would be a bad idea
+ * because that would require escaping metacharacters in the string
+ * being searched for.
+ */
+static void
+sql_match(sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+
+ assert(2 == argc);
+ sqlite3_result_int(context, NULL != strcasestr(
+ (const char *)sqlite3_value_text(argv[1]),
+ (const char *)sqlite3_value_text(argv[0])));
+}
+
+/*
+ * Implement regular expression match
+ * as an application-defined SQL function.
+ */
+static void
+sql_regexp(sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+
+ assert(2 == argc);
+ sqlite3_result_int(context, !regexec(
+ (regex_t *)sqlite3_value_blob(argv[0]),
+ (const char *)sqlite3_value_text(argv[1]),
+ 0, NULL, 0));
+}
+
+static void
+sql_append(char **sql, size_t *sz, const char *newstr, int count)
+{
+ size_t newsz;
+
+ newsz = 1 < count ? (size_t)count : strlen(newstr);
+ *sql = mandoc_realloc(*sql, *sz + newsz + 1);
+ if (1 < count)
+ memset(*sql + *sz, *newstr, (size_t)count);
+ else
+ memcpy(*sql + *sz, newstr, newsz);
+ *sz += newsz;
+ (*sql)[*sz] = '\0';
+}
+
+/*
+ * Prepare the search SQL statement.
+ */
+static char *
+sql_statement(const struct expr *e)
+{
+ char *sql;
+ size_t sz;
+ int needop;
+
+ sql = mandoc_strdup(
+ "SELECT desc, form, pageid FROM mpages WHERE ");
+ sz = strlen(sql);
+
+ for (needop = 0; NULL != e; e = e->next) {
+ if (e->and)
+ sql_append(&sql, &sz, " AND ", 1);
+ else if (needop)
+ sql_append(&sql, &sz, " OR ", 1);
+ if (e->open)
+ sql_append(&sql, &sz, "(", e->open);
+ sql_append(&sql, &sz,
+ TYPE_Nd & e->bits
+ ? (NULL == e->substr
+ ? "desc REGEXP ?"
+ : "desc MATCH ?")
+ : TYPE_Nm == e->bits
+ ? (NULL == e->substr
+ ? "pageid IN (SELECT pageid FROM names "
+ "WHERE name REGEXP ?)"
+ : e->equal
+ ? "pageid IN (SELECT pageid FROM names "
+ "WHERE name = ?)"
+ : "pageid IN (SELECT pageid FROM names "
+ "WHERE name MATCH ?)")
+ : (NULL == e->substr
+ ? "pageid IN (SELECT pageid FROM keys "
+ "WHERE key REGEXP ? AND bits & ?)"
+ : "pageid IN (SELECT pageid FROM keys "
+ "WHERE key MATCH ? AND bits & ?)"), 1);
+ if (e->close)
+ sql_append(&sql, &sz, ")", e->close);
+ needop = 1;
+ }
+
+ return(sql);
+}
+
+/*
+ * Compile a set of string tokens into an expression.
+ * Tokens in "argv" are assumed to be individual expression atoms (e.g.,
+ * "(", "foo=bar", etc.).
+ */
+static struct expr *
+exprcomp(const struct mansearch *search, int argc, char *argv[])
+{
+ uint64_t mask;
+ int i, toopen, logic, igncase, toclose;
+ struct expr *first, *prev, *cur, *next;
+
+ first = cur = NULL;
+ logic = igncase = toclose = 0;
+ toopen = NULL != search->sec || NULL != search->arch;
+
+ for (i = 0; i < argc; i++) {
+ if (0 == strcmp("(", argv[i])) {
+ if (igncase)
+ goto fail;
+ toopen++;
+ toclose++;
+ continue;
+ } else if (0 == strcmp(")", argv[i])) {
+ if (toopen || logic || igncase || NULL == cur)
+ goto fail;
+ cur->close++;
+ if (0 > --toclose)
+ goto fail;
+ continue;
+ } else if (0 == strcmp("-a", argv[i])) {
+ if (toopen || logic || igncase || NULL == cur)
+ goto fail;
+ logic = 1;
+ continue;
+ } else if (0 == strcmp("-o", argv[i])) {
+ if (toopen || logic || igncase || NULL == cur)
+ goto fail;
+ logic = 2;
+ continue;
+ } else if (0 == strcmp("-i", argv[i])) {
+ if (igncase)
+ goto fail;
+ igncase = 1;
+ continue;
+ }
+ next = exprterm(search, argv[i], !igncase);
+ if (NULL == next)
+ goto fail;
+ if (NULL == first)
+ first = next;
+ else
+ cur->next = next;
+ prev = cur = next;
+
+ /*
+ * Searching for descriptions must be split out
+ * because they are stored in the mpages table,
+ * not in the keys table.
+ */
+
+ for (mask = TYPE_Nm; mask <= TYPE_Nd; mask <<= 1) {
+ if (mask & cur->bits && ~mask & cur->bits) {
+ next = mandoc_calloc(1,
+ sizeof(struct expr));
+ memcpy(next, cur, sizeof(struct expr));
+ prev->open = 1;
+ cur->bits = mask;
+ cur->next = next;
+ cur = next;
+ cur->bits &= ~mask;
+ }
+ }
+ prev->and = (1 == logic);
+ prev->open += toopen;
+ if (cur != prev)
+ cur->close = 1;
+
+ toopen = logic = igncase = 0;
+ }
+ if (toopen || logic || igncase || toclose)
+ goto fail;
+
+ if (NULL != search->sec || NULL != search->arch)
+ cur->close++;
+ if (NULL != search->arch)
+ cur = exprspec(cur, TYPE_arch, search->arch, "^(%s|any)$");
+ if (NULL != search->sec)
+ exprspec(cur, TYPE_sec, search->sec, "^%s$");
+
+ return(first);
+
+fail:
+ if (NULL != first)
+ exprfree(first);
+ return(NULL);
+}
+
+static struct expr *
+exprspec(struct expr *cur, uint64_t key, const char *value,
+ const char *format)
+{
+ char errbuf[BUFSIZ];
+ char *cp;
+ int irc;
+
+ mandoc_asprintf(&cp, format, value);
+ cur->next = mandoc_calloc(1, sizeof(struct expr));
+ cur = cur->next;
+ cur->and = 1;
+ cur->bits = key;
+ if (0 != (irc = regcomp(&cur->regexp, cp,
+ REG_EXTENDED | REG_NOSUB | REG_ICASE))) {
+ regerror(irc, &cur->regexp, errbuf, sizeof(errbuf));
+ fprintf(stderr, "regcomp: %s\n", errbuf);
+ cur->substr = value;
+ }
+ free(cp);
+ return(cur);
+}
+
+static struct expr *
+exprterm(const struct mansearch *search, char *buf, int cs)
+{
+ char errbuf[BUFSIZ];
+ struct expr *e;
+ char *key, *val;
+ uint64_t iterbit;
+ int i, irc;
+
+ if ('\0' == *buf)
+ return(NULL);
+
+ e = mandoc_calloc(1, sizeof(struct expr));
+
+ if (MANSEARCH_MAN & search->flags) {
+ e->bits = search->deftype;
+ e->substr = buf;
+ e->equal = 1;
+ return(e);
+ }
+
+ /*
+ * Look for an '=' or '~' operator,
+ * unless forced to some fixed macro keys.
+ */
+
+ if (MANSEARCH_WHATIS & search->flags)
+ val = NULL;
+ else
+ val = strpbrk(buf, "=~");
+
+ if (NULL == val) {
+ e->bits = search->deftype;
+ e->substr = buf;
+
+ /*
+ * Found an operator.
+ * Regexp search is requested by !e->substr.
+ */
+
+ } else {
+ if (val == buf)
+ e->bits = search->deftype;
+ if ('=' == *val)
+ e->substr = val + 1;
+ *val++ = '\0';
+ if (NULL != strstr(buf, "arch"))
+ cs = 0;
+ }
+
+ /* Compile regular expressions. */
+
+ if (MANSEARCH_WHATIS & search->flags) {
+ e->substr = NULL;
+ mandoc_asprintf(&val, "[[:<:]]%s[[:>:]]", buf);
+ }
+
+ if (NULL == e->substr) {
+ irc = regcomp(&e->regexp, val,
+ REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE));
+ if (MANSEARCH_WHATIS & search->flags)
+ free(val);
+ if (irc) {
+ regerror(irc, &e->regexp, errbuf, sizeof(errbuf));
+ fprintf(stderr, "regcomp: %s\n", errbuf);
+ free(e);
+ return(NULL);
+ }
+ }
+
+ if (e->bits)
+ return(e);
+
+ /*
+ * Parse out all possible fields.
+ * If the field doesn't resolve, bail.
+ */
+
+ while (NULL != (key = strsep(&buf, ","))) {
+ if ('\0' == *key)
+ continue;
+ for (i = 0, iterbit = 1;
+ i < mansearch_keymax;
+ i++, iterbit <<= 1) {
+ if (0 == strcasecmp(key,
+ mansearch_keynames[i])) {
+ e->bits |= iterbit;
+ break;
+ }
+ }
+ if (i == mansearch_keymax) {
+ if (strcasecmp(key, "any")) {
+ free(e);
+ return(NULL);
+ }
+ e->bits |= ~0ULL;
+ }
+ }
+
+ return(e);
+}
+
+static void
+exprfree(struct expr *p)
+{
+ struct expr *pp;
+
+ while (NULL != p) {
+ pp = p->next;
+ free(p);
+ p = pp;
+ }
+}
+
+static void *
+hash_calloc(size_t nmemb, size_t sz, void *arg)
+{
+
+ return(mandoc_calloc(nmemb, sz));
+}
+
+static void *
+hash_alloc(size_t sz, void *arg)
+{
+
+ return(mandoc_malloc(sz));
+}
+
+static void
+hash_free(void *p, void *arg)
+{
+
+ free(p);
+}
diff --git a/contrib/mdocml/mansearch.h b/contrib/mdocml/mansearch.h
new file mode 100644
index 0000000..eff5e37
--- /dev/null
+++ b/contrib/mdocml/mansearch.h
@@ -0,0 +1,101 @@
+/* $Id: mansearch.h,v 1.15 2014/07/24 20:30:45 schwarze Exp $ */
+/*
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef MANSEARCH_H
+#define MANSEARCH_H
+
+#define MANDOC_DB "mandoc.db"
+
+#define TYPE_arch 0x0000000000000001ULL
+#define TYPE_sec 0x0000000000000002ULL
+#define TYPE_Xr 0x0000000000000004ULL
+#define TYPE_Ar 0x0000000000000008ULL
+#define TYPE_Fa 0x0000000000000010ULL
+#define TYPE_Fl 0x0000000000000020ULL
+#define TYPE_Dv 0x0000000000000040ULL
+#define TYPE_Fn 0x0000000000000080ULL
+#define TYPE_Ic 0x0000000000000100ULL
+#define TYPE_Pa 0x0000000000000200ULL
+#define TYPE_Cm 0x0000000000000400ULL
+#define TYPE_Li 0x0000000000000800ULL
+#define TYPE_Em 0x0000000000001000ULL
+#define TYPE_Cd 0x0000000000002000ULL
+#define TYPE_Va 0x0000000000004000ULL
+#define TYPE_Ft 0x0000000000008000ULL
+#define TYPE_Tn 0x0000000000010000ULL
+#define TYPE_Er 0x0000000000020000ULL
+#define TYPE_Ev 0x0000000000040000ULL
+#define TYPE_Sy 0x0000000000080000ULL
+#define TYPE_Sh 0x0000000000100000ULL
+#define TYPE_In 0x0000000000200000ULL
+#define TYPE_Ss 0x0000000000400000ULL
+#define TYPE_Ox 0x0000000000800000ULL
+#define TYPE_An 0x0000000001000000ULL
+#define TYPE_Mt 0x0000000002000000ULL
+#define TYPE_St 0x0000000004000000ULL
+#define TYPE_Bx 0x0000000008000000ULL
+#define TYPE_At 0x0000000010000000ULL
+#define TYPE_Nx 0x0000000020000000ULL
+#define TYPE_Fx 0x0000000040000000ULL
+#define TYPE_Lk 0x0000000080000000ULL
+#define TYPE_Ms 0x0000000100000000ULL
+#define TYPE_Bsx 0x0000000200000000ULL
+#define TYPE_Dx 0x0000000400000000ULL
+#define TYPE_Rs 0x0000000800000000ULL
+#define TYPE_Vt 0x0000001000000000ULL
+#define TYPE_Lb 0x0000002000000000ULL
+#define TYPE_Nm 0x0000004000000000ULL
+#define TYPE_Nd 0x0000008000000000ULL
+
+#define NAME_SYN 0x0000004000000001ULL
+#define NAME_FILE 0x0000004000000002ULL
+#define NAME_TITLE 0x000000400000000cULL
+#define NAME_FIRST 0x0000004000000008ULL
+#define NAME_HEAD 0x0000004000000010ULL
+#define NAME_MASK 0x000000000000001fULL
+
+__BEGIN_DECLS
+
+struct manpage {
+ char *file; /* to be prefixed by manpath */
+ char *names; /* a list of names with sections */
+ char *output; /* user-defined additional output */
+ int sec; /* section number, 10 means invalid */
+ int form; /* 0 == catpage */
+};
+
+struct mansearch {
+ const char *arch; /* architecture/NULL */
+ const char *sec; /* mansection/NULL */
+ uint64_t deftype; /* type if no key */
+ int flags;
+#define MANSEARCH_WHATIS 0x01 /* whatis(1) mode: whole words, no keys */
+#define MANSEARCH_MAN 0x02 /* man(1) mode: string equality, no keys */
+};
+
+int mansearch_setup(int);
+int mansearch(const struct mansearch *cfg, /* options */
+ const struct manpaths *paths, /* manpaths */
+ int argc, /* size of argv */
+ char *argv[], /* search terms */
+ const char *outkey, /* name of additional output key */
+ struct manpage **res, /* results */
+ size_t *ressz); /* results returned */
+
+__END_DECLS
+
+#endif /*!MANSEARCH_H*/
diff --git a/contrib/mdocml/mansearch_const.c b/contrib/mdocml/mansearch_const.c
new file mode 100644
index 0000000..1533f92
--- /dev/null
+++ b/contrib/mdocml/mansearch_const.c
@@ -0,0 +1,35 @@
+/* $Id: mansearch_const.c,v 1.5 2014/08/09 14:05:21 schwarze Exp $ */
+/*
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include "manpath.h"
+#include "mansearch.h"
+
+const int mansearch_keymax = 40;
+
+const char *const mansearch_keynames[40] = {
+ "arch", "sec", "Xr", "Ar", "Fa", "Fl", "Dv", "Fn",
+ "Ic", "Pa", "Cm", "Li", "Em", "Cd", "Va", "Ft",
+ "Tn", "Er", "Ev", "Sy", "Sh", "In", "Ss", "Ox",
+ "An", "Mt", "St", "Bx", "At", "Nx", "Fx", "Lk",
+ "Ms", "Bsx", "Dx", "Rs", "Vt", "Lb", "Nm", "Nd"
+};
diff --git a/contrib/mdocml/mchars_alloc.3 b/contrib/mdocml/mchars_alloc.3
new file mode 100644
index 0000000..8c3f853
--- /dev/null
+++ b/contrib/mdocml/mchars_alloc.3
@@ -0,0 +1,224 @@
+.\" $Id: mchars_alloc.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $
+.\"
+.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: August 5 2014 $
+.Dt MCHARS_ALLOC 3
+.Os
+.Sh NAME
+.Nm mchars_alloc ,
+.Nm mchars_free ,
+.Nm mchars_num2char ,
+.Nm mchars_num2uc ,
+.Nm mchars_spec2cp ,
+.Nm mchars_spec2str
+.Nd character table for mandoc
+.Sh LIBRARY
+.Lb libmandoc
+.Sh SYNOPSIS
+.In sys/types.h
+.In mandoc.h
+.Ft "struct mchars *"
+.Fn mchars_alloc "void"
+.Ft void
+.Fo mchars_free
+.Fa "struct mchars *table"
+.Fc
+.Ft char
+.Fo mchars_num2char
+.Fa "const char *decimal"
+.Fa "size_t sz"
+.Fc
+.Ft int
+.Fo mchars_num2uc
+.Fa "const char *hexadecimal"
+.Fa "size_t sz"
+.Fc
+.Ft int
+.Fo mchars_spec2cp
+.Fa "const struct mchars *table"
+.Fa "const char *name"
+.Fa "size_t sz"
+.Fc
+.Ft "const char *"
+.Fo mchars_spec2str
+.Fa "const struct mchars *table"
+.Fa "const char *name"
+.Fa "size_t sz"
+.Fa "size_t *rsz"
+.Fc
+.Sh DESCRIPTION
+These functions translate Unicode character numbers and
+.Xr roff 7
+character names into glyphs.
+See
+.Xr mandoc_char 7
+for a list of
+.Xr roff 7
+special characters.
+These functions are intended for external use by programs formatting
+.Xr mdoc 7
+and
+.Xr man 7
+pages for output, for example the
+.Xr mandoc 1
+output formatter modules and
+.Xr makewhatis 8 .
+The
+.Fa decimal ,
+.Fa hexadecimal ,
+.Fa name ,
+and
+.Fa size
+input arguments are usually obtained from the
+.Xr mandoc_escape 3
+parser function.
+.Pp
+The function
+.Fn mchars_num2char
+converts a
+.Fa decimal
+string representation of a character number consisting of
+.Fa sz
+digits into a printable ASCII character.
+If the input string is non-numeric or does not represent a printable
+ASCII character, the NUL character
+.Pq Sq \e0
+is returned.
+For example, the
+.Xr mandoc 1
+.Fl Tascii ,
+.Fl Tutf8 ,
+and
+.Fl Thtml
+output modules use this function to render
+.Xr roff 7
+.Ic \eN
+escape sequences.
+.Pp
+The function
+.Fn mchars_num2uc
+converts a
+.Fa hexadecimal
+string representation of a Unicode codepoint consisting of
+.Fa sz
+digits into an integer representation.
+If the input string is non-numeric or represents an ASCII character,
+the NUL character
+.Pq Sq \e0
+is returned.
+For example, the
+.Xr mandoc 1
+.Fl Tutf8
+and
+.Fl Thtml
+output modules use this function to render
+.Xr roff 7
+.Ic \e[u Ns Ar XXXX Ns Ic \&]
+and
+.Ic \eC\(aqu Ns Ar XXXX Ns Ic \(aq
+escape sequences.
+.Pp
+The function
+.Fn mchars_alloc
+allocates an opaque
+.Vt "struct mchars *"
+table object for subsequent use by the following two lookup functions.
+When no longer needed, this object can be destroyed with
+.Fn mchars_free .
+.Pp
+The function
+.Fn mchars_spec2cp
+looks up a
+.Xr roff 7
+special character
+.Fa name
+consisting of
+.Fa sz
+characters in the
+.Fa table
+and returns the corresponding Unicode codepoint.
+If the
+.Ar name
+is not recognized, \-1 is returned.
+For example, the
+.Xr mandoc 1
+.Fl Tutf8
+and
+.Fl Thtml
+output modules use this function to render
+.Xr roff 7
+.Ic \e[ Ns Ar name Ns Ic \&]
+and
+.Ic \eC\(aq Ns Ar name Ns Ic \(aq
+escape sequences.
+.Pp
+The function
+.Fn mchars_spec2str
+looks up a
+.Xr roff 7
+special character
+.Fa name
+consisting of
+.Fa sz
+characters in the
+.Fa table
+and returns an ASCII string representation.
+The length of the representation is returned in
+.Fa rsz .
+In many cases, the meaning of such ASCII representations
+is not quite obvious, so using
+.Xr roff 7
+special characters in documents intended for ASCII rendering
+is usually a bad idea.
+If the
+.Ar name
+is not recognized,
+.Dv NULL
+is returned.
+For example,
+.Xr makewhatis 8
+and the
+.Xr mandoc 1
+.Fl Tascii
+output module use this function to render
+.Xr roff 7
+.Ic \e[ Ns Ar name Ns Ic \&]
+and
+.Ic \eC\(aq Ns Ar name Ns Ic \(aq
+escape sequences.
+.Sh FILES
+These funtions are implemented in the file
+.Pa chars.c .
+.Sh SEE ALSO
+.Xr mandoc 1 ,
+.Xr mandoc_escape 3 ,
+.Xr mandoc_char 7 ,
+.Xr roff 7
+.Sh HISTORY
+These functions and their predecessors have been available since the
+following mandoc versions:
+.Bl -column "mchars_num2char()" "1.11.3" "chars_num2char()" "1.10.10"
+.It Sy function Ta since Ta Sy predecessor Ta since
+.It Fn mchars_alloc Ta 1.11.3 Ta Fn ascii2htab Ta 1.5.3
+.It Fn mchars_free Ta 1.11.2 Ta Fn asciifree Ta 1.6.0
+.It Fn mchars_num2char Ta 1.11.2 Ta Fn chars_num2char Ta 1.10.10
+.It Fn mchars_num2uc Ta 1.11.3 Ta \(em Ta \(em
+.It Fn mchars_spec2cp Ta 1.11.2 Ta Fn chars_spec2cp Ta 1.10.5
+.It Fn mchars_spec2str Ta 1.11.2 Ta Fn a2ascii Ta 1.5.3
+.El
+.Sh AUTHORS
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org
diff --git a/contrib/mdocml/mdoc.7 b/contrib/mdocml/mdoc.7
index 165c76b..a8c60d5 100644
--- a/contrib/mdocml/mdoc.7
+++ b/contrib/mdocml/mdoc.7
@@ -1,4 +1,4 @@
-.\" $Id: mdoc.7,v 1.223 2013/12/25 14:09:32 schwarze Exp $
+.\" $Id: mdoc.7,v 1.234 2014/08/08 16:38:06 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -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.
.\"
-.Dd $Mdocdate: December 25 2013 $
+.Dd $Mdocdate: August 8 2014 $
.Dt MDOC 7
.Os
.Sh NAME
@@ -125,7 +125,7 @@ file for a utility
\&.Nm progname
\&.Nd one line about what it does
\&.\e\(dq .Sh LIBRARY
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, and 9 only.
\&.\e\(dq Not used in OpenBSD.
\&.Sh SYNOPSIS
\&.Nm progname
@@ -135,20 +135,22 @@ file for a utility
The
\&.Nm
utility processes files ...
+\&.\e\(dq .Sh CONTEXT
+\&.\e\(dq For section 9 functions only.
\&.\e\(dq .Sh IMPLEMENTATION NOTES
\&.\e\(dq Not used in OpenBSD.
\&.\e\(dq .Sh RETURN VALUES
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, and 9 function return values only.
\&.\e\(dq .Sh ENVIRONMENT
-\&.\e\(dq For sections 1, 6, 7, & 8 only.
+\&.\e\(dq For sections 1, 6, 7, and 8 only.
\&.\e\(dq .Sh FILES
\&.\e\(dq .Sh EXIT STATUS
-\&.\e\(dq For sections 1, 6, & 8 only.
+\&.\e\(dq For sections 1, 6, and 8 only.
\&.\e\(dq .Sh EXAMPLES
\&.\e\(dq .Sh DIAGNOSTICS
-\&.\e\(dq For sections 1, 4, 6, 7, & 8 only.
+\&.\e\(dq For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
\&.\e\(dq .Sh ERRORS
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, 4, and 9 errno settings only.
\&.\e\(dq .Sh SEE ALSO
\&.\e\(dq .Xr foobar 1
\&.\e\(dq .Sh STANDARDS
@@ -318,6 +320,9 @@ macro followed by a non-standard section name, and each having
several subsections, like in the present
.Nm
manual.
+.It Em CONTEXT
+This section lists the contexts in which functions can be called in section 9.
+The contexts are autoconf, process, or interrupt.
.It Em IMPLEMENTATION NOTES
Implementation-specific notes should be kept here.
This is useful when implementing standard functions that may have side
@@ -358,8 +363,12 @@ Example usages.
This often contains snippets of well-formed, well-tested invocations.
Make sure that examples work properly!
.It Em DIAGNOSTICS
-Documents error conditions.
-This is most useful in section 4 manuals.
+Documents error messages.
+In section 4 and 9 manuals, these are usually messages printed by the
+kernel to the console and to the kernel log.
+In section 1, 6, 7, and 8, these are usually messages printed by
+userland programs to the standard error output.
+.Pp
Historically, this section was used in place of
.Em EXIT STATUS
for manuals in sections 1, 6, and 8; however, this practise is
@@ -369,7 +378,9 @@ See
.Sx \&Bl
.Fl diag .
.It Em ERRORS
-Documents error handling in sections 2, 3, and 9.
+Documents
+.Xr errno 2
+settings in sections 2, 3, 4, and 9.
.Pp
See
.Sx \&Er .
@@ -457,7 +468,7 @@ in the alphabetical
.It Sx \&Pf Ta prefix, no following horizontal space (one argument)
.It Sx \&Ns Ta roman font, no preceding horizontal space (no arguments)
.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments)
-.It Sx \&Sm Ta switch horizontal spacing mode: Cm on | off
+.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off
.It Sx \&Bk , \&Ek Ta keep block: Fl words
.It Sx \&br Ta force output line break in text mode (no arguments)
.It Sx \&sp Ta force vertical space: Op Ar height
@@ -502,7 +513,6 @@ in the alphabetical
.It Sx \&Cd Ta kernel configuration declaration (>0 arguments)
.It Sx \&Ad Ta memory address (>0 arguments)
.It Sx \&Ms Ta mathematical symbol (>0 arguments)
-.It Sx \&Tn Ta tradename (>0 arguments)
.El
.Ss Physical markup
.Bl -column "Brq, Bro, Brc" description
@@ -530,7 +540,6 @@ in the alphabetical
.It Sx \&Ex Fl std Ta standard command exit values: Op Ar utility ...
.It Sx \&Rv Fl std Ta standard function return values: Op Ar function ...
.It Sx \&St Ta reference to a standards document (one argument)
-.It Sx \&Ux Ta Ux
.It Sx \&At Ta At
.It Sx \&Bx Ta Bx
.It Sx \&Bsx Ta Bsx
@@ -741,9 +750,8 @@ See also
.Sx \&Dx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Bc
Close a
.Sx \&Bo
@@ -1107,10 +1115,10 @@ See also
.Sx \&Dx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Bt
+Supported only for compatibility, do not use this in new manuals.
Prints
.Dq is currently in beta test.
.Ss \&Bx
@@ -1130,9 +1138,8 @@ See also
.Sx \&Dx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Cd
Kernel configuration declaration.
This denotes strings accepted by
@@ -1188,7 +1195,7 @@ Close a
block.
Does not have any tail arguments.
.Ss \&Dd
-Document date.
+Document date for display in the page footer.
This is the mandatory first macro of any
.Nm
manual.
@@ -1217,8 +1224,11 @@ the special string
.Dq $\&Mdocdate$
can be given as an argument.
.It
-A few alternative date formats are accepted as well
-and converted to the standard form.
+The traditional, purely numeric
+.Xr man 7
+format
+.Ar year Ns \(en Ns Ar month Ns \(en Ns Ar day
+is accepted, too.
.It
If a date string cannot be parsed, it is used verbatim.
.It
@@ -1278,97 +1288,92 @@ See also
and
.Sx \&Do .
.Ss \&Dt
-Document title.
+Document title for display in the page header.
This is the mandatory second macro of any
.Nm
file.
Its syntax is as follows:
.Bd -ragged -offset indent
.Pf \. Sx \&Dt
-.Oo
-.Ar title
-.Oo
+.Ar TITLE
.Ar section
-.Op Ar volume
-.Op Ar arch
-.Oc
-.Oc
+.Op Ar volume | arch
.Ed
.Pp
Its arguments are as follows:
-.Bl -tag -width Ds -offset Ds
-.It Ar title
+.Bl -tag -width section -offset 2n
+.It Ar TITLE
The document's title (name), defaulting to
-.Dq UNKNOWN
+.Dq UNTITLED
if unspecified.
-It should be capitalised.
+To achieve a uniform appearance of page header lines,
+it should by convention be all caps.
.It Ar section
The manual section.
This may be one of
-.Ar 1
+.Cm 1
.Pq utilities ,
-.Ar 2
+.Cm 2
.Pq system calls ,
-.Ar 3
+.Cm 3
.Pq libraries ,
-.Ar 3p
+.Cm 3p
.Pq Perl libraries ,
-.Ar 4
+.Cm 4
.Pq devices ,
-.Ar 5
+.Cm 5
.Pq file formats ,
-.Ar 6
+.Cm 6
.Pq games ,
-.Ar 7
+.Cm 7
.Pq miscellaneous ,
-.Ar 8
+.Cm 8
.Pq system utilities ,
-.Ar 9
+.Cm 9
.Pq kernel functions ,
-.Ar X11
+.Cm X11
.Pq X Window System ,
-.Ar X11R6
+.Cm X11R6
.Pq X Window System ,
-.Ar unass
+.Cm unass
.Pq unassociated ,
-.Ar local
+.Cm local
.Pq local system ,
-.Ar draft
+.Cm draft
.Pq draft manual ,
or
-.Ar paper
+.Cm paper
.Pq paper .
It should correspond to the manual's filename suffix and defaults to
-.Dq 1
-if unspecified.
+the empty string if unspecified.
.It Ar volume
This overrides the volume inferred from
.Ar section .
This field is optional, and if specified, must be one of
-.Ar USD
+.Cm USD
.Pq users' supplementary documents ,
-.Ar PS1
+.Cm PS1
.Pq programmers' supplementary documents ,
-.Ar AMD
+.Cm AMD
.Pq administrators' supplementary documents ,
-.Ar SMM
+.Cm SMM
.Pq system managers' manuals ,
-.Ar URM
+.Cm URM
.Pq users' reference manuals ,
-.Ar PRM
+.Cm PRM
.Pq programmers' reference manuals ,
-.Ar KM
+.Cm KM
.Pq kernel manuals ,
-.Ar IND
+.Cm IND
.Pq master index ,
-.Ar MMI
+.Cm MMI
.Pq master index ,
-.Ar LOCAL
+.Cm LOCAL
.Pq local manuals ,
-.Ar LOC
+.Cm LOC
.Pq local manuals ,
or
-.Ar CON
+.Cm CON
.Pq contributed manuals .
.It Ar arch
This specifies the machine architecture a manual page applies to,
@@ -1430,9 +1435,8 @@ See also
.Sx \&Bx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Ec
Close a scope started by
.Sx \&Eo .
@@ -1481,8 +1485,14 @@ See also
and
.Sx \&Sy .
.Ss \&En
-This macro is obsolete and not implemented in
-.Xr mandoc 1 .
+This macro is obsolete.
+Use
+.Sx \&Eo
+or any of the other enclosure macros.
+.Pp
+It encloses its argument in the delimiters specified by the last
+.Sx \&Es
+macro.
.Ss \&Eo
An arbitrary enclosure.
Its syntax is as follows:
@@ -1508,7 +1518,14 @@ See also
.Sx \&Dv
for general constants.
.Ss \&Es
-This macro is obsolete and not implemented.
+This macro is obsolete.
+Use
+.Sx \&Eo
+or any of the other enclosure macros.
+.Pp
+It takes two arguments, defining the delimiters to be used by subsequent
+.Sx \&En
+macros.
.Ss \&Ev
Environmental variables such as those specified in
.Xr environ 7 .
@@ -1544,19 +1561,31 @@ Function argument.
Its syntax is as follows:
.Bd -ragged -offset indent
.Pf \. Sx \&Fa
-.Op Cm argtype
-.Cm argname
+.Qo
+.Op Ar argtype
+.Op Ar argname
+.Qc Ar \&...
.Ed
.Pp
-This may be invoked for names with or without the corresponding type.
-It is also used to specify the field name of a structure.
+Each argument may be a name and a type (recommended for the
+.Em SYNOPSIS
+section), a name alone (for function invocations),
+or a type alone (for function prototypes).
+If both a type and a name are given or if the type consists of multiple
+words, all words belonging to the same function argument have to be
+given in a single argument to the
+.Sx \&Fa
+macro.
+.Pp
+This macro is also used to specify the field name of a structure.
+.Pp
Most often, the
.Sx \&Fa
macro is used in the
.Em SYNOPSIS
within
.Sx \&Fo
-section when documenting multi-line function prototypes.
+blocks when documenting multi-line function prototypes.
If invoked with multiple arguments, the arguments are separated by a
comma.
Furthermore, if the following macro is another
@@ -1566,7 +1595,7 @@ the last argument will also have a trailing comma.
Examples:
.Dl \&.Fa \(dqconst char *p\(dq
.Dl \&.Fa \(dqint a\(dq \(dqint b\(dq \(dqint c\(dq
-.Dl \&.Fa foo
+.Dl \&.Fa \(dqchar *\(dq size_t
.Pp
See also
.Sx \&Fo .
@@ -1669,7 +1698,7 @@ Invocations usually occur in the following context:
.br
.Pf \. Sx \&Fo Ar funcname
.br
-.Pf \. Sx \&Fa Oo Ar argtype Oc Ar argname
+.Pf \. Sx \&Fa Qq Ar argtype Ar argname
.br
\&.\.\.
.br
@@ -1688,13 +1717,10 @@ See also
and
.Sx \&Ft .
.Ss \&Fr
-This macro is obsolete and not implemented in
-.Xr mandoc 1 .
-.Pp
-It was used to show function return values.
-The syntax was:
+This macro is obsolete.
+No replacement markup is needed.
.Pp
-.Dl Pf . Sx \&Fr Ar value
+It was used to show numerical function return values in an italic font.
.Ss \&Ft
A function type.
Its syntax is as follows:
@@ -1733,9 +1759,8 @@ See also
.Sx \&Bx ,
.Sx \&Dx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Hf
This macro is not implemented in
.Xr mandoc 1 .
@@ -2053,9 +2078,8 @@ See also
.Sx \&Bx ,
.Sx \&Dx ,
.Sx \&Fx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Oc
Close multi-line
.Sx \&Oo
@@ -2084,7 +2108,7 @@ Examples:
See also
.Sx \&Oo .
.Ss \&Os
-Document operating system version.
+Operating system version for display in the page footer.
This is the mandatory third macro of
any
.Nm
@@ -2109,8 +2133,12 @@ See also
and
.Sx \&Dt .
.Ss \&Ot
-This macro is obsolete and not implemented in
-.Xr mandoc 1 .
+This macro is obsolete.
+Use
+.Sx \&Ft
+instead; with
+.Xr mandoc 1 ,
+both have the same effect.
.Pp
Historical
.Nm
@@ -2132,9 +2160,8 @@ See also
.Sx \&Bx ,
.Sx \&Dx ,
.Sx \&Fx ,
-.Sx \&Nx ,
and
-.Sx \&Ux .
+.Sx \&Nx .
.Ss \&Pa
An absolute or relative file system path, or a file or directory name.
If an argument is not provided, the character
@@ -2308,7 +2335,7 @@ and
Switches the spacing mode for output generated from macros.
Its syntax is as follows:
.Pp
-.D1 Pf \. Sx \&Sm Cm on | off
+.D1 Pf \. Sx \&Sm Op Cm on | off
.Pp
By default, spacing is
.Cm on .
@@ -2317,6 +2344,11 @@ When switched
no white space is inserted between macro arguments and between the
output generated from adjacent macros, but text lines
still get normal spacing between words and sentences.
+.Pp
+When called without an argument, the
+.Sx \&Sm
+macro toggles the spacing mode.
+Using this is not recommended because it makes the code harder to read.
.Ss \&So
Multi-line version of
.Sx \&Sq .
@@ -2354,113 +2386,243 @@ and
.Sx \&Sx .
.Ss \&St
Replace an abbreviation for a standard with the full form.
-The following standards are recognised:
-.Pp
-.Bl -tag -width "-p1003.1g-2000X" -compact
-.It \-p1003.1-88
-.St -p1003.1-88
-.It \-p1003.1-90
-.St -p1003.1-90
-.It \-p1003.1-96
-.St -p1003.1-96
-.It \-p1003.1-2001
-.St -p1003.1-2001
-.It \-p1003.1-2004
-.St -p1003.1-2004
-.It \-p1003.1-2008
-.St -p1003.1-2008
-.It \-p1003.1
-.St -p1003.1
-.It \-p1003.1b
-.St -p1003.1b
-.It \-p1003.1b-93
-.St -p1003.1b-93
-.It \-p1003.1c-95
-.St -p1003.1c-95
-.It \-p1003.1d-99
-.St -p1003.1d-99
-.It \-p1003.1g-2000
-.St -p1003.1g-2000
-.It \-p1003.1i-95
-.St -p1003.1i-95
-.It \-p1003.1j-2000
-.St -p1003.1j-2000
-.It \-p1003.1q-2000
-.St -p1003.1q-2000
-.It \-p1003.2
-.St -p1003.2
-.It \-p1003.2-92
-.St -p1003.2-92
-.It \-p1003.2a-92
-.St -p1003.2a-92
-.It \-p1387.2
-.St -p1387.2
-.It \-p1387.2-95
-.St -p1387.2-95
+The following standards are recognised.
+Where multiple lines are given without a blank line in between,
+they all refer to the same standard, and using the first form
+is recommended.
+.Bl -tag -width 1n
+.It C language standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-ansiC
+.St -ansiC
+.It \-ansiC-89
+.St -ansiC-89
.It \-isoC
.St -isoC
.It \-isoC-90
.St -isoC-90
+.br
+The original C standard.
+.Pp
.It \-isoC-amd1
.St -isoC-amd1
+.Pp
.It \-isoC-tcor1
.St -isoC-tcor1
+.Pp
.It \-isoC-tcor2
.St -isoC-tcor2
+.Pp
.It \-isoC-99
.St -isoC-99
+.It \-ansiC-99
+.St -ansiC-99
+.br
+The second major version of the C language standard.
+.Pp
.It \-isoC-2011
.St -isoC-2011
+.br
+The third major version of the C language standard.
+.El
+.It POSIX.1 before the Single UNIX Specification
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-p1003.1-88
+.St -p1003.1-88
+.It \-p1003.1
+.St -p1003.1
+.br
+The original POSIX standard, based on ANSI C.
+.Pp
+.It \-p1003.1-90
+.St -p1003.1-90
.It \-iso9945-1-90
.St -iso9945-1-90
+.br
+The first update of POSIX.1.
+.Pp
+.It \-p1003.1b-93
+.St -p1003.1b-93
+.It \-p1003.1b
+.St -p1003.1b
+.br
+Real-time extensions.
+.Pp
+.It \-p1003.1c-95
+.St -p1003.1c-95
+.br
+POSIX thread interfaces.
+.Pp
+.It \-p1003.1i-95
+.St -p1003.1i-95
+.br
+Technical Corrigendum.
+.Pp
+.It \-p1003.1-96
+.St -p1003.1-96
.It \-iso9945-1-96
.St -iso9945-1-96
-.It \-iso9945-2-93
-.St -iso9945-2-93
-.It \-ansiC
-.St -ansiC
-.It \-ansiC-89
-.St -ansiC-89
-.It \-ansiC-99
-.St -ansiC-99
-.It \-ieee754
-.St -ieee754
-.It \-iso8802-3
-.St -iso8802-3
-.It \-iso8601
-.St -iso8601
-.It \-ieee1275-94
-.St -ieee1275-94
+.br
+Includes POSIX.1-1990, 1b, 1c, and 1i.
+.El
+.It X/Open Portability Guide version 4 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
.It \-xpg3
.St -xpg3
+.br
+An XPG4 precursor, published in 1989.
+.Pp
+.It \-p1003.2
+.St -p1003.2
+.It \-p1003.2-92
+.St -p1003.2-92
+.It \-iso9945-2-93
+.St -iso9945-2-93
+.br
+An XCU4 precursor.
+.Pp
+.It \-p1003.2a-92
+.St -p1003.2a-92
+.br
+Updates to POSIX.2.
+.Pp
.It \-xpg4
.St -xpg4
+.br
+Based on POSIX.1 and POSIX.2, published in 1992.
+.El
+.It Single UNIX Specification version 1 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
.It \-xpg4.2
.St -xpg4.2
+.br
+This standard was published in 1994 and is also called SUSv1.
+It was used as the basis for UNIX 95 certification.
+The following three refer to parts of it.
+.Pp
+.It \-xsh4.2
+.St -xsh4.2
+.Pp
+.It \-xcurses4.2
+.St -xcurses4.2
+.Pp
+.It \-p1003.1g-2000
+.St -p1003.1g-2000
+.br
+Networking APIs, including sockets.
+.Pp
.It \-xpg4.3
.St -xpg4.3
+.Pp
+.It \-svid4
+.St -svid4 ,
+.br
+Published in 1995.
+.El
+.It Single UNIX Specification version 2 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-susv2
+.St -susv2
+This Standard was published in 1997
+and is also called X/Open Portability Guide version 5.
+It was used as the basis for UNIX 98 certification.
+The following refer to parts of it.
+.Pp
.It \-xbd5
.St -xbd5
-.It \-xcu5
-.St -xcu5
-.It \-xsh4.2
-.St -xsh4.2
+.Pp
.It \-xsh5
.St -xsh5
+.Pp
+.It \-xcu5
+.St -xcu5
+.Pp
.It \-xns5
.St -xns5
-.It \-xns5.2
-.St -xns5.2
.It \-xns5.2d2.0
.St -xns5.2d2.0
-.It \-xcurses4.2
-.St -xcurses4.2
-.It \-susv2
-.St -susv2
+.It \-xns5.2
+.St -xns5.2
+.Pp
+.It \-p1387.2
+.St -p1387.2
+.It \-p1387.2-95
+.St -p1387.2-95
+.br
+POSIX software administration.
+.El
+.It Single UNIX Specification version 3 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000X" -compact
+.It \-p1003.1d-99
+.St -p1003.1d-99
+.br
+Additional real-time extensions.
+.Pp
+.It \-p1003.1j-2000
+.St -p1003.1j-2000
+.br
+Advanced real-time extensions.
+.Pp
+.It \-p1003.1q-2000
+.St -p1003.1q-2000
+.br
+Amendment 7: Tracing [C Language].
+.Pp
+.It \-p1003.1-2001
+.St -p1003.1-2001
.It \-susv3
.St -susv3
-.It \-svid4
-.St -svid4
+.br
+This standard is based on C99, SUSv2, POSIX.1-1996, 1d, and 1j.
+It is also called X/Open Portability Guide version 6.
+It is used as the basis for UNIX 03 certification.
+.Pp
+.It \-p1003.1-2004
+.St -p1003.1-2004
+.br
+The second and last Technical Corrigendum.
+.El
+.It Single UNIX Specification version 4
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-p1003.1-2008
+.St -p1003.1-2008
+.br
+This standard is also called SUSv4 and
+X/Open Portability Guide version 7.
+.Pp
+.It \-p1003.1-2013
+.St -p1003.1-2013
+.br
+This is the first Technical Corrigendum.
+.El
+.It Other standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-ieee754
+.St -ieee754
+.br
+Floating-point arithmetic.
+.Pp
+.It \-iso8601
+.St -iso8601
+.br
+Representation of dates and times, published in 1988.
+.Pp
+.It \-iso8802-3
+.St -iso8802-3
+.br
+Ethernet local area networks.
+.Pp
+.It \-ieee1275-94
+.St -ieee1275-94
+.El
.El
.Ss \&Sx
Reference a section or subsection in the same manual page.
@@ -2492,36 +2654,19 @@ Table cell separator in
lists; can only be used below
.Sx \&It .
.Ss \&Tn
-Format a tradename.
-.Pp
-Since this macro is often implemented to use a small caps font,
-it has historically been used for acronyms (like ASCII) as well.
-Such usage is not recommended because it would use the same macro
-sometimes for semantical annotation, sometimes for physical formatting.
-.Pp
-Examples:
-.Dl \&.Tn IBM
+Supported only for compatibility, do not use this in new manuals.
+Even though the macro name
+.Pq Dq tradename
+suggests a semantic function, historic usage is inconsistent, mostly
+using it as a presentation-level macro to request a small caps font.
.Ss \&Ud
+Supported only for compatibility, do not use this in new manuals.
Prints out
.Dq currently under development.
.Ss \&Ux
-Format the
-.Ux
-name.
-Accepts no argument.
-.Pp
-Examples:
-.Dl \&.Ux
-.Pp
-See also
-.Sx \&At ,
-.Sx \&Bsx ,
-.Sx \&Bx ,
-.Sx \&Dx ,
-.Sx \&Fx ,
-.Sx \&Nx ,
-and
-.Sx \&Ox .
+Supported only for compatibility, do not use this in new manuals.
+Prints out
+.Dq Ux .
.Ss \&Va
A variable name.
.Pp
@@ -2773,6 +2918,7 @@ end of the line.
.It Sx \&D1 Ta \&No Ta \&Yes
.It Sx \&Dl Ta \&No Ta Yes
.It Sx \&Dq Ta Yes Ta Yes
+.It Sx \&En Ta Yes Ta Yes
.It Sx \&Op Ta Yes Ta Yes
.It Sx \&Pq Ta Yes Ta Yes
.It Sx \&Ql Ta Yes Ta Yes
@@ -2850,16 +2996,15 @@ then the macro accepts an arbitrary number of arguments.
.It Sx \&Dv Ta Yes Ta Yes Ta >0
.It Sx \&Dx Ta Yes Ta Yes Ta n
.It Sx \&Em Ta Yes Ta Yes Ta >0
-.It Sx \&En Ta \&No Ta \&No Ta 0
.It Sx \&Er Ta Yes Ta Yes Ta >0
-.It Sx \&Es Ta \&No Ta \&No Ta 0
+.It Sx \&Es Ta Yes Ta Yes Ta 2
.It Sx \&Ev Ta Yes Ta Yes Ta >0
.It Sx \&Ex Ta \&No Ta \&No Ta n
.It Sx \&Fa Ta Yes Ta Yes Ta >0
.It Sx \&Fd Ta \&No Ta \&No Ta >0
.It Sx \&Fl Ta Yes Ta Yes Ta n
.It Sx \&Fn Ta Yes Ta Yes Ta >0
-.It Sx \&Fr Ta \&No Ta \&No Ta n
+.It Sx \&Fr Ta Yes Ta Yes Ta >0
.It Sx \&Ft Ta Yes Ta Yes Ta >0
.It Sx \&Fx Ta Yes Ta Yes Ta n
.It Sx \&Hf Ta \&No Ta \&No Ta n
@@ -2876,13 +3021,13 @@ then the macro accepts an arbitrary number of arguments.
.It Sx \&Ns Ta Yes Ta Yes Ta 0
.It Sx \&Nx Ta Yes Ta Yes Ta n
.It Sx \&Os Ta \&No Ta \&No Ta n
-.It Sx \&Ot Ta \&No Ta \&No Ta n
+.It Sx \&Ot Ta Yes Ta Yes Ta >0
.It Sx \&Ox Ta Yes Ta Yes Ta n
.It Sx \&Pa Ta Yes Ta Yes Ta n
.It Sx \&Pf Ta Yes Ta Yes Ta 1
.It Sx \&Pp Ta \&No Ta \&No Ta 0
.It Sx \&Rv Ta \&No Ta \&No Ta n
-.It Sx \&Sm Ta \&No Ta \&No Ta 1
+.It Sx \&Sm Ta \&No Ta \&No Ta <2
.It Sx \&St Ta \&No Ta Yes Ta 1
.It Sx \&Sx Ta Yes Ta Yes Ta >0
.It Sx \&Sy Ta Yes Ta Yes Ta >0
@@ -2998,8 +3143,9 @@ Manually switching the font using the
.Ql \ef
font escape sequences is never required.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other
-troff implementations, at this time limited to GNU troff
+This section provides an incomplete list of compatibility issues
+between mandoc and other troff implementations, at this time limited
+to GNU troff
.Pq Qq groff .
The term
.Qq historic groff
@@ -3108,7 +3254,7 @@ certain list types.
can only be called by other macros, but not at the beginning of a line.
.It
.Sx \&%C
-is not implemented.
+is not implemented (up to and including groff-1.22.2).
.It
Historic groff only allows up to eight or nine arguments per macro input
line, depending on the exact situation.
@@ -3126,7 +3272,7 @@ in new groff and mandoc.
.Sq \ef
.Pq font face
and
-.Sq \ef
+.Sq \eF
.Pq font family face
.Sx Text Decoration
escapes behave irregularly when specified within line-macro scopes.
@@ -3143,41 +3289,11 @@ The following features are unimplemented in mandoc:
.Fl file Ar file .
.It
.Sx \&Bd
-.Fl offset Ar center
+.Fl offset Cm center
and
-.Fl offset Ar right .
+.Fl offset Cm right .
Groff does not implement centred and flush-right rendering either,
but produces large indentations.
-.It
-The
-.Sq \eh
-.Pq horizontal position ,
-.Sq \ev
-.Pq vertical position ,
-.Sq \em
-.Pq text colour ,
-.Sq \eM
-.Pq text filling colour ,
-.Sq \ez
-.Pq zero-length character ,
-.Sq \ew
-.Pq string length ,
-.Sq \ek
-.Pq horizontal position marker ,
-.Sq \eo
-.Pq text overstrike ,
-and
-.Sq \es
-.Pq text size
-escape sequences are all discarded in mandoc.
-.It
-The
-.Sq \ef
-scaling unit is accepted by mandoc, but rendered as the default unit.
-.It
-In quoted literals, groff allows pairwise double-quotes to produce a
-standalone double-quote in formatted output.
-This is not supported by mandoc.
.El
.Sh SEE ALSO
.Xr man 1 ,
diff --git a/contrib/mdocml/mdoc.c b/contrib/mdocml/mdoc.c
index 87b3587..e8143bf 100644
--- a/contrib/mdocml/mdoc.c
+++ b/contrib/mdocml/mdoc.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.223 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -30,10 +31,11 @@
#include "mdoc.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmdoc.h"
#include "libmandoc.h"
-const char *const __mdoc_macronames[MDOC_MAX] = {
+const char *const __mdoc_macronames[MDOC_MAX + 1] = {
"Ap", "Dd", "Dt", "Os",
"Sh", "Ss", "Pp", "D1",
"Dl", "Bd", "Ed", "Bl",
@@ -44,11 +46,8 @@ const char *const __mdoc_macronames[MDOC_MAX] = {
"Ic", "In", "Li", "Nd",
"Nm", "Op", "Ot", "Pa",
"Rv", "St", "Va", "Vt",
- /* LINTED */
"Xr", "%A", "%B", "%D",
- /* LINTED */
"%I", "%J", "%N", "%O",
- /* LINTED */
"%P", "%R", "%T", "%V",
"Ac", "Ao", "Aq", "At",
"Bc", "Bf", "Bo", "Bq",
@@ -65,22 +64,19 @@ const char *const __mdoc_macronames[MDOC_MAX] = {
"Bk", "Ek", "Bt", "Hf",
"Fr", "Ud", "Lb", "Lp",
"Lk", "Mt", "Brq", "Bro",
- /* LINTED */
"Brc", "%C", "Es", "En",
- /* LINTED */
"Dx", "%Q", "br", "sp",
- /* LINTED */
- "%U", "Ta"
+ "%U", "Ta", "ll", "text",
};
-const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
+const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"split", "nosplit", "ragged",
- "unfilled", "literal", "file",
- "offset", "bullet", "dash",
- "hyphen", "item", "enum",
- "tag", "diag", "hang",
- "ohang", "inset", "column",
- "width", "compact", "std",
+ "unfilled", "literal", "file",
+ "offset", "bullet", "dash",
+ "hyphen", "item", "enum",
+ "tag", "diag", "hang",
+ "ohang", "inset", "column",
+ "width", "compact", "std",
"filled", "words", "emphasis",
"symbolic", "nested", "centered"
};
@@ -89,13 +85,13 @@ const char * const *mdoc_macronames = __mdoc_macronames;
const char * const *mdoc_argnames = __mdoc_argnames;
static void mdoc_node_free(struct mdoc_node *);
-static void mdoc_node_unlink(struct mdoc *,
+static void mdoc_node_unlink(struct mdoc *,
struct mdoc_node *);
static void mdoc_free1(struct mdoc *);
static void mdoc_alloc1(struct mdoc *);
-static struct mdoc_node *node_alloc(struct mdoc *, int, int,
+static struct mdoc_node *node_alloc(struct mdoc *, int, int,
enum mdoct, enum mdoc_type);
-static int node_append(struct mdoc *,
+static int node_append(struct mdoc *,
struct mdoc_node *);
#if 0
static int mdoc_preptext(struct mdoc *, int, char *, int);
@@ -103,24 +99,21 @@ static int mdoc_preptext(struct mdoc *, int, char *, int);
static int mdoc_ptext(struct mdoc *, int, char *, int);
static int mdoc_pmacro(struct mdoc *, int, char *, int);
+
const struct mdoc_node *
mdoc_node(const struct mdoc *mdoc)
{
- assert( ! (MDOC_HALT & mdoc->flags));
return(mdoc->first);
}
-
const struct mdoc_meta *
mdoc_meta(const struct mdoc *mdoc)
{
- assert( ! (MDOC_HALT & mdoc->flags));
return(&mdoc->meta);
}
-
/*
* Frees volatile resources (parse tree, meta-data, fields).
*/
@@ -130,23 +123,15 @@ mdoc_free1(struct mdoc *mdoc)
if (mdoc->first)
mdoc_node_delete(mdoc, mdoc->first);
- if (mdoc->meta.title)
- free(mdoc->meta.title);
- if (mdoc->meta.os)
- free(mdoc->meta.os);
- if (mdoc->meta.name)
- free(mdoc->meta.name);
- if (mdoc->meta.arch)
- free(mdoc->meta.arch);
- if (mdoc->meta.vol)
- free(mdoc->meta.vol);
- if (mdoc->meta.msec)
- free(mdoc->meta.msec);
- if (mdoc->meta.date)
- free(mdoc->meta.date);
+ free(mdoc->meta.msec);
+ free(mdoc->meta.vol);
+ free(mdoc->meta.arch);
+ free(mdoc->meta.date);
+ free(mdoc->meta.title);
+ free(mdoc->meta.os);
+ free(mdoc->meta.name);
}
-
/*
* Allocate all volatile resources (parse tree, meta-data, fields).
*/
@@ -164,7 +149,6 @@ mdoc_alloc1(struct mdoc *mdoc)
mdoc->next = MDOC_NEXT_CHILD;
}
-
/*
* Free up volatile resources (see mdoc_free1()) then re-initialises the
* data with mdoc_alloc1(). After invocation, parse data has been reset
@@ -179,7 +163,6 @@ mdoc_reset(struct mdoc *mdoc)
mdoc_alloc1(mdoc);
}
-
/*
* Completely free up all volatile and non-volatile parse resources.
* After invocation, the pointer is no longer usable.
@@ -192,12 +175,12 @@ mdoc_free(struct mdoc *mdoc)
free(mdoc);
}
-
/*
- * Allocate volatile and non-volatile parse resources.
+ * Allocate volatile and non-volatile parse resources.
*/
struct mdoc *
-mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
+mdoc_alloc(struct roff *roff, struct mparse *parse,
+ const char *defos, int quick)
{
struct mdoc *p;
@@ -205,6 +188,7 @@ mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
p->parse = parse;
p->defos = defos;
+ p->quick = quick;
p->roff = roff;
mdoc_hash_init();
@@ -212,20 +196,11 @@ mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
return(p);
}
-
-/*
- * Climb back up the parse tree, validating open scopes. Mostly calls
- * through to macro_end() in macro.c.
- */
int
mdoc_endparse(struct mdoc *mdoc)
{
- assert( ! (MDOC_HALT & mdoc->flags));
- if (mdoc_macroend(mdoc))
- return(1);
- mdoc->flags |= MDOC_HALT;
- return(0);
+ return(mdoc_macroend(mdoc));
}
int
@@ -233,15 +208,6 @@ mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep)
{
struct mdoc_node *n;
- assert( ! (MDOC_HALT & mdoc->flags));
-
- /* No text before an initial macro. */
-
- if (SEC_NONE == mdoc->lastnamed) {
- mdoc_pmsg(mdoc, ep->ln, ep->pos, MANDOCERR_NOTEXT);
- return(1);
- }
-
n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
n->eqn = ep;
@@ -257,15 +223,6 @@ mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
{
struct mdoc_node *n;
- assert( ! (MDOC_HALT & mdoc->flags));
-
- /* No text before an initial macro. */
-
- if (SEC_NONE == mdoc->lastnamed) {
- mdoc_pmsg(mdoc, sp->line, 0, MANDOCERR_NOTEXT);
- return(1);
- }
-
n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL);
n->span = sp;
@@ -276,7 +233,6 @@ mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
return(1);
}
-
/*
* Main parse routine. Parses a single line -- really just hands off to
* the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
@@ -285,8 +241,6 @@ int
mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
{
- assert( ! (MDOC_HALT & mdoc->flags));
-
mdoc->flags |= MDOC_NEWLINE;
/*
@@ -301,8 +255,8 @@ mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
mdoc->flags &= ~MDOC_SYNOPSIS;
return(roff_getcontrol(mdoc->roff, buf, &offs) ?
- mdoc_pmacro(mdoc, ln, buf, offs) :
- mdoc_ptext(mdoc, ln, buf, offs));
+ mdoc_pmacro(mdoc, ln, buf, offs) :
+ mdoc_ptext(mdoc, ln, buf, offs));
}
int
@@ -310,30 +264,22 @@ mdoc_macro(MACRO_PROT_ARGS)
{
assert(tok < MDOC_MAX);
- /* If we're in the body, deny prologue calls. */
-
- if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
- MDOC_PBODY & mdoc->flags) {
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADBODY);
- return(1);
- }
-
- /* If we're in the prologue, deny "body" macros. */
-
- if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
- ! (MDOC_PBODY & mdoc->flags)) {
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADPROLOG);
- if (NULL == mdoc->meta.msec)
- mdoc->meta.msec = mandoc_strdup("1");
- if (NULL == mdoc->meta.title)
- mdoc->meta.title = mandoc_strdup("UNKNOWN");
+ if (mdoc->flags & MDOC_PBODY) {
+ if (tok == MDOC_Dt) {
+ mandoc_vmsg(MANDOCERR_DT_LATE,
+ mdoc->parse, line, ppos,
+ "Dt %s", buf + *pos);
+ return(1);
+ }
+ } else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) {
+ if (mdoc->meta.title == NULL) {
+ mandoc_vmsg(MANDOCERR_DT_NOTITLE,
+ mdoc->parse, line, ppos, "%s %s",
+ mdoc_macronames[tok], buf + *pos);
+ mdoc->meta.title = mandoc_strdup("UNTITLED");
+ }
if (NULL == mdoc->meta.vol)
mdoc->meta.vol = mandoc_strdup("LOCAL");
- if (NULL == mdoc->meta.os)
- mdoc->meta.os = mandoc_strdup("LOCAL");
- if (NULL == mdoc->meta.date)
- mdoc->meta.date = mandoc_normdate
- (mdoc->parse, NULL, line, ppos);
mdoc->flags |= MDOC_PBODY;
}
@@ -350,12 +296,12 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
assert(MDOC_ROOT != p->type);
switch (mdoc->next) {
- case (MDOC_NEXT_SIBLING):
+ case MDOC_NEXT_SIBLING:
mdoc->last->next = p;
p->prev = mdoc->last;
p->parent = mdoc->last->parent;
break;
- case (MDOC_NEXT_CHILD):
+ case MDOC_NEXT_CHILD:
mdoc->last->child = p;
p->parent = mdoc->last;
break;
@@ -372,13 +318,13 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
*/
switch (p->type) {
- case (MDOC_BODY):
+ case MDOC_BODY:
if (ENDBODY_NOT != p->end)
break;
/* FALLTHROUGH */
- case (MDOC_TAIL):
+ case MDOC_TAIL:
/* FALLTHROUGH */
- case (MDOC_HEAD):
+ case MDOC_HEAD:
p->norm = p->parent->norm;
break;
default:
@@ -389,15 +335,15 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
return(0);
switch (p->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
assert(MDOC_BLOCK == p->parent->type);
p->parent->head = p;
break;
- case (MDOC_TAIL):
+ case MDOC_TAIL:
assert(MDOC_BLOCK == p->parent->type);
p->parent->tail = p;
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
if (p->end)
break;
assert(MDOC_BLOCK == p->parent->type);
@@ -410,9 +356,9 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
mdoc->last = p;
switch (p->type) {
- case (MDOC_TBL):
+ case MDOC_TBL:
/* FALLTHROUGH */
- case (MDOC_TEXT):
+ case MDOC_TEXT:
if ( ! mdoc_valid_post(mdoc))
return(0);
break;
@@ -423,9 +369,8 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
return(1);
}
-
static struct mdoc_node *
-node_alloc(struct mdoc *mdoc, int line, int pos,
+node_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, enum mdoc_type type)
{
struct mdoc_node *p;
@@ -451,7 +396,6 @@ node_alloc(struct mdoc *mdoc, int line, int pos,
return(p);
}
-
int
mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
@@ -464,7 +408,6 @@ mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
return(1);
}
-
int
mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
@@ -480,7 +423,6 @@ mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
return(1);
}
-
int
mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
@@ -493,7 +435,6 @@ mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
return(1);
}
-
int
mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
struct mdoc_node *body, enum mdoc_endbody end)
@@ -510,9 +451,8 @@ mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
return(1);
}
-
int
-mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
+mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
{
struct mdoc_node *p;
@@ -523,13 +463,15 @@ mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
(args->refcnt)++;
switch (tok) {
- case (MDOC_Bd):
+ case MDOC_Bd:
+ /* FALLTHROUGH */
+ case MDOC_Bf:
/* FALLTHROUGH */
- case (MDOC_Bf):
+ case MDOC_Bl:
/* FALLTHROUGH */
- case (MDOC_Bl):
+ case MDOC_En:
/* FALLTHROUGH */
- case (MDOC_Rs):
+ case MDOC_Rs:
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
break;
default:
@@ -542,9 +484,8 @@ mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
return(1);
}
-
int
-mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
+mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
{
struct mdoc_node *p;
@@ -555,7 +496,7 @@ mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
(args->refcnt)++;
switch (tok) {
- case (MDOC_An):
+ case MDOC_An:
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
break;
default:
@@ -591,10 +532,7 @@ mdoc_word_append(struct mdoc *mdoc, const char *p)
n = mdoc->last;
addstr = roff_strdup(mdoc->roff, p);
- if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
+ mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
free(addstr);
free(n->string);
n->string = newstr;
@@ -614,7 +552,6 @@ mdoc_node_free(struct mdoc_node *p)
free(p);
}
-
static void
mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
{
@@ -652,7 +589,6 @@ mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
mdoc->first = NULL;
}
-
void
mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
{
@@ -723,7 +659,7 @@ mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs)
if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff)))
return(0);
offs += (end - (buf + offs));
- }
+ }
return(1);
}
@@ -739,13 +675,6 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
char *c, *ws, *end;
struct mdoc_node *n;
- /* No text before an initial macro. */
-
- if (SEC_NONE == mdoc->lastnamed) {
- mdoc_pmsg(mdoc, line, offs, MANDOCERR_NOTEXT);
- return(1);
- }
-
assert(mdoc->last);
n = mdoc->last;
@@ -757,16 +686,16 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
*/
if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->norm->Bl.type) {
+ LIST_column == n->norm->Bl.type) {
/* `Bl' is open without any children. */
mdoc->flags |= MDOC_FREECOL;
return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
}
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
- NULL != n->parent &&
- MDOC_Bl == n->parent->tok &&
- LIST_column == n->parent->norm->Bl.type) {
+ NULL != n->parent &&
+ MDOC_Bl == n->parent->tok &&
+ LIST_column == n->parent->norm->Bl.type) {
/* `Bl' has block-level `It' children. */
mdoc->flags |= MDOC_FREECOL;
return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
@@ -814,10 +743,12 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
*end = '\0';
if (ws)
- mdoc_pmsg(mdoc, line, (int)(ws-buf), MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ line, (int)(ws-buf), NULL);
if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) {
- mdoc_pmsg(mdoc, line, (int)(c-buf), MANDOCERR_NOBLANKLN);
+ mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
+ line, (int)(c - buf), NULL);
/*
* Insert a `sp' in the case of a blank line. Technically,
@@ -846,13 +777,12 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
assert(buf < end);
- if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0))
+ if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
mdoc->last->flags |= MDOC_EOS;
return(1);
}
-
/*
* Parse a macro line, that is, a line beginning with the control
* character.
@@ -868,30 +798,31 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
/* Empty post-control lines are ignored. */
if ('"' == buf[offs]) {
- mdoc_pmsg(mdoc, ln, offs, MANDOCERR_BADCOMMENT);
+ mandoc_msg(MANDOCERR_COMMENT_BAD, mdoc->parse,
+ ln, offs, NULL);
return(1);
} else if ('\0' == buf[offs])
return(1);
sv = offs;
- /*
+ /*
* Copy the first word into a nil-terminated buffer.
* Stop copying when a tab, space, or eoln is encountered.
*/
i = 0;
- while (i < 4 && '\0' != buf[offs] &&
- ' ' != buf[offs] && '\t' != buf[offs])
+ while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] &&
+ '\t' != buf[offs])
mac[i++] = buf[offs++];
mac[i] = '\0';
- tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
+ tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
if (MDOC_MAX == tok) {
- mandoc_vmsg(MANDOCERR_MACRO, mdoc->parse,
- ln, sv, "%s", buf + sv - 1);
+ mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
+ ln, sv, buf + sv - 1);
return(1);
}
@@ -905,24 +836,22 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
while (buf[offs] && ' ' == buf[offs])
offs++;
- /*
+ /*
* Trailing whitespace. Note that tabs are allowed to be passed
* into the parser as "text", so we only warn about spaces here.
*/
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
- mdoc_pmsg(mdoc, ln, offs - 1, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ ln, offs - 1, NULL);
/*
* If an initial macro or a list invocation, divert directly
* into macro processing.
*/
- if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
- if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
- goto err;
- return(1);
- }
+ if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok)
+ return(mdoc_macro(mdoc, tok, ln, sv, &offs, buf));
n = mdoc->last;
assert(mdoc->last);
@@ -933,11 +862,9 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
*/
if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->norm->Bl.type) {
+ LIST_column == n->norm->Bl.type) {
mdoc->flags |= MDOC_FREECOL;
- if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf))
- goto err;
- return(1);
+ return(mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf));
}
/*
@@ -947,26 +874,25 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
*/
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
- NULL != n->parent &&
- MDOC_Bl == n->parent->tok &&
- LIST_column == n->parent->norm->Bl.type) {
+ NULL != n->parent &&
+ MDOC_Bl == n->parent->tok &&
+ LIST_column == n->parent->norm->Bl.type) {
mdoc->flags |= MDOC_FREECOL;
- if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf))
- goto err;
- return(1);
+ return(mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf));
}
/* Normal processing of a macro. */
- if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
- goto err;
+ if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
+ return(0);
- return(1);
+ /* In quick mode (for mandocdb), abort after the NAME section. */
-err: /* Error out. */
+ if (mdoc->quick && MDOC_Sh == tok &&
+ SEC_NAME != mdoc->last->sec)
+ return(2);
- mdoc->flags |= MDOC_HALT;
- return(0);
+ return(1);
}
enum mdelim
@@ -978,27 +904,27 @@ mdoc_isdelim(const char *p)
if ('\0' == p[1])
switch (p[0]) {
- case('('):
+ case '(':
/* FALLTHROUGH */
- case('['):
+ case '[':
return(DELIM_OPEN);
- case('|'):
+ case '|':
return(DELIM_MIDDLE);
- case('.'):
+ case '.':
/* FALLTHROUGH */
- case(','):
+ case ',':
/* FALLTHROUGH */
- case(';'):
+ case ';':
/* FALLTHROUGH */
- case(':'):
+ case ':':
/* FALLTHROUGH */
- case('?'):
+ case '?':
/* FALLTHROUGH */
- case('!'):
+ case '!':
/* FALLTHROUGH */
- case(')'):
+ case ')':
/* FALLTHROUGH */
- case(']'):
+ case ']':
return(DELIM_CLOSE);
default:
return(DELIM_NONE);
@@ -1014,3 +940,42 @@ mdoc_isdelim(const char *p)
return(DELIM_NONE);
}
+
+void
+mdoc_deroff(char **dest, const struct mdoc_node *n)
+{
+ char *cp;
+ size_t sz;
+
+ if (MDOC_TEXT != n->type) {
+ for (n = n->child; n; n = n->next)
+ mdoc_deroff(dest, n);
+ return;
+ }
+
+ /* Skip leading whitespace. */
+
+ for (cp = n->string; '\0' != *cp; cp++)
+ if (0 == isspace((unsigned char)*cp))
+ break;
+
+ /* Skip trailing whitespace. */
+
+ for (sz = strlen(cp); sz; sz--)
+ if (0 == isspace((unsigned char)cp[sz-1]))
+ break;
+
+ /* Skip empty strings. */
+
+ if (0 == sz)
+ return;
+
+ if (NULL == *dest) {
+ *dest = mandoc_strndup(cp, sz);
+ return;
+ }
+
+ mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
+ free(*dest);
+ *dest = cp;
+}
diff --git a/contrib/mdocml/mdoc.h b/contrib/mdocml/mdoc.h
index d0153b4..58ad813 100644
--- a/contrib/mdocml/mdoc.h
+++ b/contrib/mdocml/mdoc.h
@@ -1,4 +1,4 @@
-/* $Id: mdoc.h,v 1.125 2013/12/24 19:11:45 schwarze Exp $ */
+/* $Id: mdoc.h,v 1.131 2014/07/29 13:58:18 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -140,6 +140,7 @@ enum mdoct {
MDOC_sp,
MDOC__U,
MDOC_Ta,
+ MDOC_ll,
MDOC_MAX
};
@@ -186,7 +187,7 @@ enum mdoc_type {
MDOC_ROOT
};
-/*
+/*
* Section (named/unnamed) of `Sh'. Note that these appear in the
* conventional order imposed by mdoc.7. In the case of SEC_NONE, no
* section has been invoked (this shouldn't happen). SEC_CUSTOM refers
@@ -198,6 +199,7 @@ enum mdoc_sec {
SEC_LIBRARY, /* LIBRARY */
SEC_SYNOPSIS, /* SYNOPSIS */
SEC_DESCRIPTION, /* DESCRIPTION */
+ SEC_CONTEXT, /* CONTEXT */
SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */
SEC_RETURN_VALUES, /* RETURN VALUES */
SEC_ENVIRONMENT, /* ENVIRONMENT */
@@ -214,7 +216,7 @@ enum mdoc_sec {
SEC_CAVEATS, /* CAVEATS */
SEC_BUGS, /* BUGS */
SEC_SECURITY, /* SECURITY */
- SEC_CUSTOM,
+ SEC_CUSTOM,
SEC__MAX
};
@@ -228,11 +230,11 @@ struct mdoc_meta {
char *name; /* leading `Nm' name */
};
-/*
- * An argument to a macro (multiple values = `-column xxx yyy').
+/*
+ * An argument to a macro (multiple values = `-column xxx yyy').
*/
struct mdoc_argv {
- enum mdocargt arg; /* type of argument */
+ enum mdocargt arg; /* type of argument */
int line;
int pos;
size_t sz; /* elements in "value" */
@@ -244,7 +246,7 @@ struct mdoc_argv {
* blocks have multiple instances of the same arguments spread across
* the HEAD, BODY, TAIL, and BLOCK node types.
*/
-struct mdoc_arg {
+struct mdoc_arg {
size_t argc;
struct mdoc_argv *argv;
unsigned int refcnt;
@@ -278,7 +280,7 @@ enum mdoc_list {
enum mdoc_disp {
DISP__NONE = 0,
- DISP_centred, /* -centered */
+ DISP_centered, /* -centered */
DISP_ragged, /* -ragged */
DISP_unfilled, /* -unfilled */
DISP_filled, /* -filled */
@@ -332,15 +334,16 @@ struct mdoc_rs {
* provided, etc.
*/
union mdoc_data {
- struct mdoc_an An;
+ struct mdoc_an An;
struct mdoc_bd Bd;
struct mdoc_bf Bf;
struct mdoc_bl Bl;
+ struct mdoc_node *Es;
struct mdoc_rs Rs;
};
-/*
- * Single node in tree-linked AST.
+/*
+ * Single node in tree-linked AST.
*/
struct mdoc_node {
struct mdoc_node *parent; /* parent AST node */
@@ -389,6 +392,7 @@ struct mdoc;
const struct mdoc_node *mdoc_node(const struct mdoc *);
const struct mdoc_meta *mdoc_meta(const struct mdoc *);
+void mdoc_deroff(char **, const struct mdoc_node *);
__END_DECLS
diff --git a/contrib/mdocml/mdoc_argv.c b/contrib/mdocml/mdoc_argv.c
index bb9bc6c..e48516c 100644
--- a/contrib/mdocml/mdoc_argv.c
+++ b/contrib/mdocml/mdoc_argv.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp $ */
+/* $Id: mdoc_argv.c,v 1.95 2014/07/06 19:09:00 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
@@ -28,11 +28,12 @@
#include "mdoc.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmdoc.h"
#include "libmandoc.h"
#define MULTI_STEP 5 /* pre-allocate argument values */
-#define DELIMSZ 6 /* max possible size of a delimiter */
+#define DELIMSZ 6 /* max possible size of a delimiter */
enum argsflag {
ARGSFL_NONE = 0,
@@ -52,12 +53,12 @@ struct mdocarg {
};
static void argn_free(struct mdoc_arg *, int);
-static enum margserr args(struct mdoc *, int, int *,
+static enum margserr args(struct mdoc *, int, int *,
char *, enum argsflag, char **);
static int args_checkpunct(const char *, int);
-static int argv_multi(struct mdoc *, int,
+static int argv_multi(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
-static int argv_single(struct mdoc *, int,
+static int argv_single(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
static const enum argvflag argvflags[MDOC_ARG_MAX] = {
@@ -149,8 +150,8 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* Dt */
{ ARGSFL_NONE, NULL }, /* Os */
{ ARGSFL_NONE, NULL }, /* Sh */
- { ARGSFL_NONE, NULL }, /* Ss */
- { ARGSFL_NONE, NULL }, /* Pp */
+ { ARGSFL_NONE, NULL }, /* Ss */
+ { ARGSFL_NONE, NULL }, /* Pp */
{ ARGSFL_DELIM, NULL }, /* D1 */
{ ARGSFL_DELIM, NULL }, /* Dl */
{ ARGSFL_NONE, args_Bd }, /* Bd */
@@ -158,32 +159,32 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, args_Bl }, /* Bl */
{ ARGSFL_NONE, NULL }, /* El */
{ ARGSFL_NONE, NULL }, /* It */
- { ARGSFL_DELIM, NULL }, /* Ad */
+ { ARGSFL_DELIM, NULL }, /* Ad */
{ ARGSFL_DELIM, args_An }, /* An */
{ ARGSFL_DELIM, NULL }, /* Ar */
{ ARGSFL_DELIM, NULL }, /* Cd */
{ ARGSFL_DELIM, NULL }, /* Cm */
- { ARGSFL_DELIM, NULL }, /* Dv */
- { ARGSFL_DELIM, NULL }, /* Er */
- { ARGSFL_DELIM, NULL }, /* Ev */
+ { ARGSFL_DELIM, NULL }, /* Dv */
+ { ARGSFL_DELIM, NULL }, /* Er */
+ { ARGSFL_DELIM, NULL }, /* Ev */
{ ARGSFL_NONE, args_Ex }, /* Ex */
- { ARGSFL_DELIM, NULL }, /* Fa */
- { ARGSFL_NONE, NULL }, /* Fd */
+ { ARGSFL_DELIM, NULL }, /* Fa */
+ { ARGSFL_NONE, NULL }, /* Fd */
{ ARGSFL_DELIM, NULL }, /* Fl */
- { ARGSFL_DELIM, NULL }, /* Fn */
- { ARGSFL_DELIM, NULL }, /* Ft */
- { ARGSFL_DELIM, NULL }, /* Ic */
- { ARGSFL_DELIM, NULL }, /* In */
+ { ARGSFL_DELIM, NULL }, /* Fn */
+ { ARGSFL_DELIM, NULL }, /* Ft */
+ { ARGSFL_DELIM, NULL }, /* Ic */
+ { ARGSFL_DELIM, NULL }, /* In */
{ ARGSFL_DELIM, NULL }, /* Li */
- { ARGSFL_NONE, NULL }, /* Nd */
- { ARGSFL_DELIM, NULL }, /* Nm */
+ { ARGSFL_NONE, NULL }, /* Nd */
+ { ARGSFL_DELIM, NULL }, /* Nm */
{ ARGSFL_DELIM, NULL }, /* Op */
- { ARGSFL_NONE, NULL }, /* Ot */
+ { ARGSFL_DELIM, NULL }, /* Ot */
{ ARGSFL_DELIM, NULL }, /* Pa */
{ ARGSFL_NONE, args_Ex }, /* Rv */
- { ARGSFL_DELIM, NULL }, /* St */
+ { ARGSFL_DELIM, NULL }, /* St */
{ ARGSFL_DELIM, NULL }, /* Va */
- { ARGSFL_DELIM, NULL }, /* Vt */
+ { ARGSFL_DELIM, NULL }, /* Vt */
{ ARGSFL_DELIM, NULL }, /* Xr */
{ ARGSFL_NONE, NULL }, /* %A */
{ ARGSFL_NONE, NULL }, /* %B */
@@ -201,7 +202,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Aq */
{ ARGSFL_DELIM, NULL }, /* At */
{ ARGSFL_DELIM, NULL }, /* Bc */
- { ARGSFL_NONE, args_Bf }, /* Bf */
+ { ARGSFL_NONE, args_Bf }, /* Bf */
{ ARGSFL_NONE, NULL }, /* Bo */
{ ARGSFL_DELIM, NULL }, /* Bq */
{ ARGSFL_DELIM, NULL }, /* Bsx */
@@ -212,7 +213,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Dq */
{ ARGSFL_DELIM, NULL }, /* Ec */
{ ARGSFL_NONE, NULL }, /* Ef */
- { ARGSFL_DELIM, NULL }, /* Em */
+ { ARGSFL_DELIM, NULL }, /* Em */
{ ARGSFL_NONE, NULL }, /* Eo */
{ ARGSFL_DELIM, NULL }, /* Fx */
{ ARGSFL_DELIM, NULL }, /* Ms */
@@ -240,15 +241,15 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Ux */
{ ARGSFL_DELIM, NULL }, /* Xc */
{ ARGSFL_NONE, NULL }, /* Xo */
- { ARGSFL_NONE, NULL }, /* Fo */
- { ARGSFL_DELIM, NULL }, /* Fc */
+ { ARGSFL_NONE, NULL }, /* Fo */
+ { ARGSFL_DELIM, NULL }, /* Fc */
{ ARGSFL_NONE, NULL }, /* Oo */
{ ARGSFL_DELIM, NULL }, /* Oc */
{ ARGSFL_NONE, args_Bk }, /* Bk */
{ ARGSFL_NONE, NULL }, /* Ek */
{ ARGSFL_NONE, NULL }, /* Bt */
{ ARGSFL_NONE, NULL }, /* Hf */
- { ARGSFL_NONE, NULL }, /* Fr */
+ { ARGSFL_DELIM, NULL }, /* Fr */
{ ARGSFL_NONE, NULL }, /* Ud */
{ ARGSFL_DELIM, NULL }, /* Lb */
{ ARGSFL_NONE, NULL }, /* Lp */
@@ -259,13 +260,14 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Brc */
{ ARGSFL_NONE, NULL }, /* %C */
{ ARGSFL_NONE, NULL }, /* Es */
- { ARGSFL_NONE, NULL }, /* En */
+ { ARGSFL_DELIM, NULL }, /* En */
{ ARGSFL_DELIM, NULL }, /* Dx */
{ ARGSFL_NONE, NULL }, /* %Q */
{ ARGSFL_NONE, NULL }, /* br */
{ ARGSFL_NONE, NULL }, /* sp */
{ ARGSFL_NONE, NULL }, /* %U */
{ ARGSFL_NONE, NULL }, /* Ta */
+ { ARGSFL_NONE, NULL }, /* ll */
};
@@ -300,14 +302,14 @@ mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
if (' ' == buf[*pos] && '\\' != buf[*pos - 1])
break;
- /*
+ /*
* We want to nil-terminate the word to look it up (it's easier
* that way). But we may not have a flag, in which case we need
* to restore the line as-is. So keep around the stray byte,
* which we'll reset upon exiting (if necessary).
*/
- if ('\0' != (sv = buf[*pos]))
+ if ('\0' != (sv = buf[*pos]))
buf[(*pos)++] = '\0';
/*
@@ -326,7 +328,7 @@ mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
break;
if (MDOC_ARG_MAX == tmp.arg) {
- /*
+ /*
* The flag was not found.
* Restore saved zeroed byte and return as a word.
*/
@@ -341,15 +343,15 @@ mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
(*pos)++;
switch (argvflags[tmp.arg]) {
- case (ARGV_SINGLE):
+ case ARGV_SINGLE:
if ( ! argv_single(mdoc, line, &tmp, pos, buf))
return(ARGV_ERROR);
break;
- case (ARGV_MULTI):
+ case ARGV_MULTI:
if ( ! argv_multi(mdoc, line, &tmp, pos, buf))
return(ARGV_ERROR);
break;
- case (ARGV_NONE):
+ case ARGV_NONE:
break;
}
@@ -357,11 +359,11 @@ mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
arg->argc++;
- arg->argv = mandoc_realloc
- (arg->argv, arg->argc * sizeof(struct mdoc_argv));
+ arg->argv = mandoc_reallocarray(arg->argv,
+ arg->argc, sizeof(struct mdoc_argv));
- memcpy(&arg->argv[(int)arg->argc - 1],
- &tmp, sizeof(struct mdoc_argv));
+ memcpy(&arg->argv[(int)arg->argc - 1], &tmp,
+ sizeof(struct mdoc_argv));
return(ARGV_ARG);
}
@@ -397,7 +399,7 @@ argn_free(struct mdoc_arg *p, int iarg)
arg = &p->argv[iarg];
if (arg->sz && arg->value) {
- for (j = (int)arg->sz - 1; j >= 0; j--)
+ for (j = (int)arg->sz - 1; j >= 0; j--)
free(arg->value[j]);
free(arg->value);
}
@@ -414,7 +416,7 @@ mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v)
}
enum margserr
-mdoc_args(struct mdoc *mdoc, int line, int *pos,
+mdoc_args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum mdoct tok, char **v)
{
enum argsflag fl;
@@ -443,7 +445,7 @@ mdoc_args(struct mdoc *mdoc, int line, int *pos,
}
static enum margserr
-args(struct mdoc *mdoc, int line, int *pos,
+args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum argsflag fl, char **v)
{
char *p, *pp;
@@ -459,7 +461,8 @@ args(struct mdoc *mdoc, int line, int *pos,
* is unterminated.
*/
if (MDOC_PHRASELIT & mdoc->flags)
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
+ mandoc_msg(MANDOCERR_ARG_QUOTE,
+ mdoc->parse, line, *pos, NULL);
mdoc->flags &= ~MDOC_PHRASELIT;
return(ARGS_EOLN);
@@ -484,7 +487,7 @@ args(struct mdoc *mdoc, int line, int *pos,
pp = NULL;
/* Scan ahead to unescaped `Ta'. */
- if ( ! (MDOC_PHRASELIT & mdoc->flags))
+ if ( ! (MDOC_PHRASELIT & mdoc->flags))
for (pp = *v; ; pp++) {
if (NULL == (pp = strstr(pp, "Ta")))
break;
@@ -497,7 +500,7 @@ args(struct mdoc *mdoc, int line, int *pos,
/* By default, assume a phrase. */
rc = ARGS_PHRASE;
- /*
+ /*
* Adjust new-buffer position to be beyond delimiter
* mark (e.g., Ta -> end + 2).
*/
@@ -518,7 +521,8 @@ args(struct mdoc *mdoc, int line, int *pos,
/* Whitespace check for eoln case... */
if ('\0' == *p && ' ' == *(p - 1))
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ line, *pos, NULL);
*pos += (int)(p - *v);
@@ -573,7 +577,8 @@ args(struct mdoc *mdoc, int line, int *pos,
if ('\0' == buf[*pos]) {
if (MDOC_PPHRASE & mdoc->flags)
return(ARGS_QWORD);
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
+ mandoc_msg(MANDOCERR_ARG_QUOTE,
+ mdoc->parse, line, *pos, NULL);
return(ARGS_QWORD);
}
@@ -587,7 +592,8 @@ args(struct mdoc *mdoc, int line, int *pos,
(*pos)++;
if ('\0' == buf[*pos])
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ line, *pos, NULL);
return(ARGS_QWORD);
}
@@ -598,7 +604,7 @@ args(struct mdoc *mdoc, int line, int *pos,
return(ARGS_WORD);
}
-/*
+/*
* Check if the string consists only of space-separated closing
* delimiters. This is a bit of a dance: the first must be a close
* delimiter, but it may be followed by middle delimiters. Arbitrary
@@ -627,7 +633,7 @@ args_checkpunct(const char *buf, int i)
i++;
/* Remaining must NOT be open/none. */
-
+
while (buf[i]) {
j = 0;
while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
@@ -649,7 +655,7 @@ args_checkpunct(const char *buf, int i)
}
static int
-argv_multi(struct mdoc *mdoc, int line,
+argv_multi(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
@@ -665,8 +671,8 @@ argv_multi(struct mdoc *mdoc, int line,
break;
if (0 == v->sz % MULTI_STEP)
- v->value = mandoc_realloc(v->value,
- (v->sz + MULTI_STEP) * sizeof(char *));
+ v->value = mandoc_reallocarray(v->value,
+ v->sz + MULTI_STEP, sizeof(char *));
v->value[(int)v->sz] = mandoc_strdup(p);
}
@@ -675,7 +681,7 @@ argv_multi(struct mdoc *mdoc, int line,
}
static int
-argv_single(struct mdoc *mdoc, int line,
+argv_single(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
diff --git a/contrib/mdocml/mdoc_hash.c b/contrib/mdocml/mdoc_hash.c
index 59a8d26..db30ee6 100644
--- a/contrib/mdocml/mdoc_hash.c
+++ b/contrib/mdocml/mdoc_hash.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_hash.c,v 1.18 2011/07/24 18:15:14 kristaps Exp $ */
+/* $Id: mdoc_hash.c,v 1.20 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -28,11 +28,11 @@
#include <string.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
static unsigned char table[27 * 12];
+
/*
* XXX - this hash has global scope, so if intended for use as a library
* with multiple callers, it will need re-invocation protection.
@@ -77,7 +77,7 @@ mdoc_hash_find(const char *p)
major = 12 * (tolower((unsigned char)p[1]) - 97);
else if ('1' == p[1])
major = 12 * 26;
- else
+ else
return(MDOC_MAX);
if (p[2] && p[3])
diff --git a/contrib/mdocml/mdoc_html.c b/contrib/mdocml/mdoc_html.c
index a7aa722..9fe241e 100644
--- a/contrib/mdocml/mdoc_html.c
+++ b/contrib/mdocml/mdoc_html.c
@@ -1,6 +1,7 @@
-/* $Id: mdoc_html.c,v 1.186 2013/12/24 20:45:27 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.195 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +29,7 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "html.h"
#include "mdoc.h"
@@ -52,7 +54,7 @@ static void print_mdoc(MDOC_ARGS);
static void print_mdoc_head(MDOC_ARGS);
static void print_mdoc_node(MDOC_ARGS);
static void print_mdoc_nodelist(MDOC_ARGS);
-static void synopsis_pre(struct html *,
+static void synopsis_pre(struct html *,
const struct mdoc_node *);
static void a2width(const char *, struct roffsu *);
@@ -108,6 +110,7 @@ static int mdoc_quote_pre(MDOC_ARGS);
static int mdoc_rs_pre(MDOC_ARGS);
static int mdoc_rv_pre(MDOC_ARGS);
static int mdoc_sh_pre(MDOC_ARGS);
+static int mdoc_skip_pre(MDOC_ARGS);
static int mdoc_sm_pre(MDOC_ARGS);
static int mdoc_sp_pre(MDOC_ARGS);
static int mdoc_ss_pre(MDOC_ARGS);
@@ -125,8 +128,8 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{NULL, NULL}, /* Dt */
{NULL, NULL}, /* Os */
{mdoc_sh_pre, NULL }, /* Sh */
- {mdoc_ss_pre, NULL }, /* Ss */
- {mdoc_pp_pre, NULL}, /* Pp */
+ {mdoc_ss_pre, NULL }, /* Ss */
+ {mdoc_pp_pre, NULL}, /* Pp */
{mdoc_d1_pre, NULL}, /* D1 */
{mdoc_d1_pre, NULL}, /* Dl */
{mdoc_bd_pre, NULL}, /* Bd */
@@ -134,32 +137,32 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_bl_pre, NULL}, /* Bl */
{NULL, NULL}, /* El */
{mdoc_it_pre, NULL}, /* It */
- {mdoc_ad_pre, NULL}, /* Ad */
+ {mdoc_ad_pre, NULL}, /* Ad */
{mdoc_an_pre, NULL}, /* An */
{mdoc_ar_pre, NULL}, /* Ar */
{mdoc_cd_pre, NULL}, /* Cd */
{mdoc_fl_pre, NULL}, /* Cm */
- {mdoc_dv_pre, NULL}, /* Dv */
- {mdoc_er_pre, NULL}, /* Er */
- {mdoc_ev_pre, NULL}, /* Ev */
+ {mdoc_dv_pre, NULL}, /* Dv */
+ {mdoc_er_pre, NULL}, /* Er */
+ {mdoc_ev_pre, NULL}, /* Ev */
{mdoc_ex_pre, NULL}, /* Ex */
- {mdoc_fa_pre, NULL}, /* Fa */
- {mdoc_fd_pre, NULL}, /* Fd */
+ {mdoc_fa_pre, NULL}, /* Fa */
+ {mdoc_fd_pre, NULL}, /* Fd */
{mdoc_fl_pre, NULL}, /* Fl */
- {mdoc_fn_pre, NULL}, /* Fn */
- {mdoc_ft_pre, NULL}, /* Ft */
- {mdoc_ic_pre, NULL}, /* Ic */
- {mdoc_in_pre, NULL}, /* In */
+ {mdoc_fn_pre, NULL}, /* Fn */
+ {mdoc_ft_pre, NULL}, /* Ft */
+ {mdoc_ic_pre, NULL}, /* Ic */
+ {mdoc_in_pre, NULL}, /* In */
{mdoc_li_pre, NULL}, /* Li */
- {mdoc_nd_pre, NULL}, /* Nd */
- {mdoc_nm_pre, NULL}, /* Nm */
+ {mdoc_nd_pre, NULL}, /* Nd */
+ {mdoc_nm_pre, NULL}, /* Nm */
{mdoc_quote_pre, mdoc_quote_post}, /* Op */
- {NULL, NULL}, /* Ot */
+ {mdoc_ft_pre, NULL}, /* Ot */
{mdoc_pa_pre, NULL}, /* Pa */
{mdoc_rv_pre, NULL}, /* Rv */
- {NULL, NULL}, /* St */
+ {NULL, NULL}, /* St */
{mdoc_va_pre, NULL}, /* Va */
- {mdoc_vt_pre, NULL}, /* Vt */
+ {mdoc_vt_pre, NULL}, /* Vt */
{mdoc_xr_pre, NULL}, /* Xr */
{mdoc__x_pre, mdoc__x_post}, /* %A */
{mdoc__x_pre, mdoc__x_post}, /* %B */
@@ -177,7 +180,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
{NULL, NULL}, /* At */
{NULL, NULL}, /* Bc */
- {mdoc_bf_pre, NULL}, /* Bf */
+ {mdoc_bf_pre, NULL}, /* Bf */
{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
{mdoc_xx_pre, NULL}, /* Bsx */
@@ -188,7 +191,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
{NULL, NULL}, /* Ec */ /* FIXME: no space */
{NULL, NULL}, /* Ef */
- {mdoc_em_pre, NULL}, /* Em */
+ {mdoc_em_pre, NULL}, /* Em */
{mdoc_quote_pre, mdoc_quote_post}, /* Eo */
{mdoc_xx_pre, NULL}, /* Fx */
{mdoc_ms_pre, NULL}, /* Ms */
@@ -209,39 +212,40 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{NULL, NULL}, /* Sc */
{mdoc_quote_pre, mdoc_quote_post}, /* So */
{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
- {mdoc_sm_pre, NULL}, /* Sm */
+ {mdoc_sm_pre, NULL}, /* Sm */
{mdoc_sx_pre, NULL}, /* Sx */
{mdoc_sy_pre, NULL}, /* Sy */
{NULL, NULL}, /* Tn */
{mdoc_xx_pre, NULL}, /* Ux */
{NULL, NULL}, /* Xc */
{NULL, NULL}, /* Xo */
- {mdoc_fo_pre, mdoc_fo_post}, /* Fo */
- {NULL, NULL}, /* Fc */
+ {mdoc_fo_pre, mdoc_fo_post}, /* Fo */
+ {NULL, NULL}, /* Fc */
{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
{NULL, NULL}, /* Oc */
{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
{NULL, NULL}, /* Ek */
{mdoc_bt_pre, NULL}, /* Bt */
{NULL, NULL}, /* Hf */
- {NULL, NULL}, /* Fr */
+ {mdoc_em_pre, NULL}, /* Fr */
{mdoc_ud_pre, NULL}, /* Ud */
{mdoc_lb_pre, NULL}, /* Lb */
- {mdoc_pp_pre, NULL}, /* Lp */
- {mdoc_lk_pre, NULL}, /* Lk */
- {mdoc_mt_pre, NULL}, /* Mt */
- {mdoc_quote_pre, mdoc_quote_post}, /* Brq */
- {mdoc_quote_pre, mdoc_quote_post}, /* Bro */
- {NULL, NULL}, /* Brc */
- {mdoc__x_pre, mdoc__x_post}, /* %C */
- {NULL, NULL}, /* Es */ /* TODO */
- {NULL, NULL}, /* En */ /* TODO */
- {mdoc_xx_pre, NULL}, /* Dx */
- {mdoc__x_pre, mdoc__x_post}, /* %Q */
+ {mdoc_pp_pre, NULL}, /* Lp */
+ {mdoc_lk_pre, NULL}, /* Lk */
+ {mdoc_mt_pre, NULL}, /* Mt */
+ {mdoc_quote_pre, mdoc_quote_post}, /* Brq */
+ {mdoc_quote_pre, mdoc_quote_post}, /* Bro */
+ {NULL, NULL}, /* Brc */
+ {mdoc__x_pre, mdoc__x_post}, /* %C */
+ {mdoc_skip_pre, NULL}, /* Es */
+ {mdoc_quote_pre, mdoc_quote_post}, /* En */
+ {mdoc_xx_pre, NULL}, /* Dx */
+ {mdoc__x_pre, mdoc__x_post}, /* %Q */
{mdoc_sp_pre, NULL}, /* br */
- {mdoc_sp_pre, NULL}, /* sp */
- {mdoc__x_pre, mdoc__x_post}, /* %U */
- {NULL, NULL}, /* Ta */
+ {mdoc_sp_pre, NULL}, /* sp */
+ {mdoc__x_pre, mdoc__x_post}, /* %U */
+ {NULL, NULL}, /* Ta */
+ {mdoc_skip_pre, NULL}, /* ll */
};
static const char * const lists[LIST_MAX] = {
@@ -259,16 +263,16 @@ static const char * const lists[LIST_MAX] = {
"list-tag"
};
+
void
html_mdoc(void *arg, const struct mdoc *mdoc)
{
print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc),
- (struct html *)arg);
+ (struct html *)arg);
putchar('\n');
}
-
/*
* Calculate the scaling unit passed in a `-width' argument. This uses
* either a native scaling unit (e.g., 1i, 2m) or the string length of
@@ -284,7 +288,6 @@ a2width(const char *p, struct roffsu *su)
}
}
-
/*
* See the same function in mdoc_term.c for documentation.
*/
@@ -295,27 +298,27 @@ synopsis_pre(struct html *h, const struct mdoc_node *n)
if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
return;
- if (n->prev->tok == n->tok &&
- MDOC_Fo != n->tok &&
- MDOC_Ft != n->tok &&
- MDOC_Fn != n->tok) {
+ if (n->prev->tok == n->tok &&
+ MDOC_Fo != n->tok &&
+ MDOC_Ft != n->tok &&
+ MDOC_Fn != n->tok) {
print_otag(h, TAG_BR, 0, NULL);
return;
}
switch (n->prev->tok) {
- case (MDOC_Fd):
+ case MDOC_Fd:
/* FALLTHROUGH */
- case (MDOC_Fn):
+ case MDOC_Fn:
/* FALLTHROUGH */
- case (MDOC_Fo):
+ case MDOC_Fo:
/* FALLTHROUGH */
- case (MDOC_In):
+ case MDOC_In:
/* FALLTHROUGH */
- case (MDOC_Vt):
+ case MDOC_Vt:
print_otag(h, TAG_P, 0, NULL);
break;
- case (MDOC_Ft):
+ case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
print_otag(h, TAG_P, 0, NULL);
break;
@@ -327,7 +330,6 @@ synopsis_pre(struct html *h, const struct mdoc_node *n)
}
}
-
/*
* Calculate the scaling unit passed in an `-offset' argument. This
* uses either a native scaling unit (e.g., 1i, 2m), one of a set of
@@ -349,7 +351,6 @@ a2offs(const char *p, struct roffsu *su)
SCALE_HS_INIT(su, html_strlen(p));
}
-
static void
print_mdoc(MDOC_ARGS)
{
@@ -366,23 +367,22 @@ print_mdoc(MDOC_ARGS)
print_tagq(h, tt);
print_otag(h, TAG_BODY, 0, NULL);
print_otag(h, TAG_DIV, 1, &tag);
- } else
+ } else
t = print_otag(h, TAG_DIV, 1, &tag);
print_mdoc_nodelist(meta, n, h);
print_tagq(h, t);
}
-
-/* ARGSUSED */
static void
print_mdoc_head(MDOC_ARGS)
{
print_gen_head(h);
bufinit(h);
- bufcat_fmt(h, "%s(%s)", meta->title, meta->msec);
-
+ bufcat(h, meta->title);
+ if (meta->msec)
+ bufcat_fmt(h, "(%s)", meta->msec);
if (meta->arch)
bufcat_fmt(h, " (%s)", meta->arch);
@@ -390,7 +390,6 @@ print_mdoc_head(MDOC_ARGS)
print_text(h, h->buf);
}
-
static void
print_mdoc_nodelist(MDOC_ARGS)
{
@@ -400,7 +399,6 @@ print_mdoc_nodelist(MDOC_ARGS)
print_mdoc_nodelist(meta, n->next, h);
}
-
static void
print_mdoc_node(MDOC_ARGS)
{
@@ -411,10 +409,10 @@ print_mdoc_node(MDOC_ARGS)
t = h->tags.head;
switch (n->type) {
- case (MDOC_ROOT):
+ case MDOC_ROOT:
child = mdoc_root_pre(meta, n, h);
break;
- case (MDOC_TEXT):
+ case MDOC_TEXT:
/* No tables in this mode... */
assert(NULL == h->tblt);
@@ -431,10 +429,10 @@ print_mdoc_node(MDOC_ARGS)
if (MDOC_DELIMO & n->flags)
h->flags |= HTML_NOSPACE;
return;
- case (MDOC_EQN):
+ case MDOC_EQN:
print_eqn(h, n->eqn);
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
/*
* This will take care of initialising all of the table
* state data for the first table, then tearing it down
@@ -473,10 +471,10 @@ print_mdoc_node(MDOC_ARGS)
print_stagq(h, t);
switch (n->type) {
- case (MDOC_ROOT):
+ case MDOC_ROOT:
mdoc_root_post(meta, n, h);
break;
- case (MDOC_EQN):
+ case MDOC_EQN:
break;
default:
if (mdocs[n->tok].post && ENDBODY_NOT == n->end)
@@ -485,7 +483,6 @@ print_mdoc_node(MDOC_ARGS)
}
}
-/* ARGSUSED */
static void
mdoc_root_post(MDOC_ARGS)
{
@@ -516,24 +513,24 @@ mdoc_root_post(MDOC_ARGS)
print_tagq(h, t);
}
-
-/* ARGSUSED */
static int
mdoc_root_pre(MDOC_ARGS)
{
struct htmlpair tag[3];
struct tag *t, *tt;
- char b[BUFSIZ], title[BUFSIZ];
-
- strlcpy(b, meta->vol, BUFSIZ);
+ char *volume, *title;
- if (meta->arch) {
- strlcat(b, " (", BUFSIZ);
- strlcat(b, meta->arch, BUFSIZ);
- strlcat(b, ")", BUFSIZ);
- }
+ if (NULL == meta->arch)
+ volume = mandoc_strdup(meta->vol);
+ else
+ mandoc_asprintf(&volume, "%s (%s)",
+ meta->vol, meta->arch);
- snprintf(title, BUFSIZ - 1, "%s(%s)", meta->title, meta->msec);
+ if (NULL == meta->msec)
+ title = mandoc_strdup(meta->title);
+ else
+ mandoc_asprintf(&title, "%s(%s)",
+ meta->title, meta->msec);
PAIR_SUMMARY_INIT(&tag[0], "Document Header");
PAIR_CLASS_INIT(&tag[1], "head");
@@ -556,7 +553,7 @@ mdoc_root_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag[0], "head-vol");
PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
print_otag(h, TAG_TD, 2, tag);
- print_text(h, b);
+ print_text(h, volume);
print_stagq(h, tt);
PAIR_CLASS_INIT(&tag[0], "head-rtitle");
@@ -564,11 +561,12 @@ mdoc_root_pre(MDOC_ARGS)
print_otag(h, TAG_TD, 2, tag);
print_text(h, title);
print_tagq(h, t);
+
+ free(title);
+ free(volume);
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_sh_pre(MDOC_ARGS)
{
@@ -599,7 +597,6 @@ mdoc_sh_pre(MDOC_ARGS)
return(1);
}
-/* ARGSUSED */
static int
mdoc_ss_pre(MDOC_ARGS)
{
@@ -630,8 +627,6 @@ mdoc_ss_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_fl_pre(MDOC_ARGS)
{
@@ -655,8 +650,6 @@ mdoc_fl_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_nd_pre(MDOC_ARGS)
{
@@ -673,7 +666,6 @@ mdoc_nd_pre(MDOC_ARGS)
return(1);
}
-
static int
mdoc_nm_pre(MDOC_ARGS)
{
@@ -682,19 +674,19 @@ mdoc_nm_pre(MDOC_ARGS)
int len;
switch (n->type) {
- case (MDOC_ELEM):
+ case MDOC_ELEM:
synopsis_pre(h, n);
PAIR_CLASS_INIT(&tag, "name");
print_otag(h, TAG_B, 1, &tag);
if (NULL == n->child && meta->name)
print_text(h, meta->name);
return(1);
- case (MDOC_HEAD):
+ case MDOC_HEAD:
print_otag(h, TAG_TD, 0, NULL);
if (NULL == n->child && meta->name)
print_text(h, meta->name);
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
print_otag(h, TAG_TD, 0, NULL);
return(1);
default:
@@ -712,7 +704,7 @@ mdoc_nm_pre(MDOC_ARGS)
if (0 == len && meta->name)
len = html_strlen(meta->name);
- SCALE_HS_INIT(&su, (double)len);
+ SCALE_HS_INIT(&su, len);
bufinit(h);
bufcat_su(h, "width", &su);
PAIR_STYLE_INIT(&tag, h);
@@ -723,8 +715,6 @@ mdoc_nm_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_xr_pre(MDOC_ARGS)
{
@@ -736,9 +726,9 @@ mdoc_xr_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag[0], "link-man");
if (h->base_man) {
- buffmt_man(h, n->child->string,
- n->child->next ?
- n->child->next->string : NULL);
+ buffmt_man(h, n->child->string,
+ n->child->next ?
+ n->child->next->string : NULL);
PAIR_HREF_INIT(&tag[1], h->buf);
print_otag(h, TAG_A, 2, tag);
} else
@@ -759,8 +749,6 @@ mdoc_xr_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_ns_pre(MDOC_ARGS)
{
@@ -770,8 +758,6 @@ mdoc_ns_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ar_pre(MDOC_ARGS)
{
@@ -782,8 +768,6 @@ mdoc_ar_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_xx_pre(MDOC_ARGS)
{
@@ -792,22 +776,22 @@ mdoc_xx_pre(MDOC_ARGS)
int flags;
switch (n->tok) {
- case (MDOC_Bsx):
+ case MDOC_Bsx:
pp = "BSD/OS";
break;
- case (MDOC_Dx):
+ case MDOC_Dx:
pp = "DragonFly";
break;
- case (MDOC_Fx):
+ case MDOC_Fx:
pp = "FreeBSD";
break;
- case (MDOC_Nx):
+ case MDOC_Nx:
pp = "NetBSD";
break;
- case (MDOC_Ox):
+ case MDOC_Ox:
pp = "OpenBSD";
break;
- case (MDOC_Ux):
+ case MDOC_Ux:
pp = "UNIX";
break;
default:
@@ -827,8 +811,6 @@ mdoc_xx_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_bx_pre(MDOC_ARGS)
{
@@ -856,7 +838,6 @@ mdoc_bx_pre(MDOC_ARGS)
return(0);
}
-/* ARGSUSED */
static int
mdoc_it_pre(MDOC_ARGS)
{
@@ -880,25 +861,25 @@ mdoc_it_pre(MDOC_ARGS)
if (MDOC_HEAD == n->type) {
switch (type) {
- case(LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case(LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case(LIST_item):
+ case LIST_item:
/* FALLTHROUGH */
- case(LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case(LIST_enum):
+ case LIST_enum:
return(0);
- case(LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case(LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case(LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case(LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case(LIST_tag):
+ case LIST_tag:
SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
bufcat_su(h, "margin-top", &su);
PAIR_STYLE_INIT(&tag[1], h);
@@ -908,36 +889,36 @@ mdoc_it_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag[0], "diag");
print_otag(h, TAG_B, 1, tag);
break;
- case(LIST_column):
+ case LIST_column:
break;
default:
break;
}
} else if (MDOC_BODY == n->type) {
switch (type) {
- case(LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case(LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case(LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case(LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case(LIST_item):
+ case LIST_item:
SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
bufcat_su(h, "margin-top", &su);
PAIR_STYLE_INIT(&tag[1], h);
print_otag(h, TAG_LI, 2, tag);
break;
- case(LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case(LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case(LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case(LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case(LIST_tag):
+ case LIST_tag:
if (NULL == bl->norm->Bl.width) {
print_otag(h, TAG_DD, 1, tag);
break;
@@ -947,7 +928,7 @@ mdoc_it_pre(MDOC_ARGS)
PAIR_STYLE_INIT(&tag[1], h);
print_otag(h, TAG_DD, 2, tag);
break;
- case(LIST_column):
+ case LIST_column:
SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
bufcat_su(h, "margin-top", &su);
PAIR_STYLE_INIT(&tag[1], h);
@@ -958,7 +939,7 @@ mdoc_it_pre(MDOC_ARGS)
}
} else {
switch (type) {
- case (LIST_column):
+ case LIST_column:
print_otag(h, TAG_TR, 1, tag);
break;
default:
@@ -969,7 +950,6 @@ mdoc_it_pre(MDOC_ARGS)
return(1);
}
-/* ARGSUSED */
static int
mdoc_bl_pre(MDOC_ARGS)
{
@@ -1016,8 +996,8 @@ mdoc_bl_pre(MDOC_ARGS)
PAIR_STYLE_INIT(&tag[0], h);
assert(lists[n->norm->Bl.type]);
- strlcpy(buf, "list ", BUFSIZ);
- strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
+ (void)strlcpy(buf, "list ", BUFSIZ);
+ (void)strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
PAIR_INIT(&tag[1], ATTR_CLASS, buf);
/* Set the block's left-hand margin. */
@@ -1028,30 +1008,30 @@ mdoc_bl_pre(MDOC_ARGS)
}
switch (n->norm->Bl.type) {
- case(LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case(LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case(LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case(LIST_item):
+ case LIST_item:
print_otag(h, TAG_UL, 2, tag);
break;
- case(LIST_enum):
+ case LIST_enum:
print_otag(h, TAG_OL, 2, tag);
break;
- case(LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case(LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case(LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case(LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case(LIST_tag):
+ case LIST_tag:
print_otag(h, TAG_DL, 2, tag);
break;
- case(LIST_column):
+ case LIST_column:
print_otag(h, TAG_TABLE, 2, tag);
break;
default:
@@ -1062,7 +1042,6 @@ mdoc_bl_pre(MDOC_ARGS)
return(1);
}
-/* ARGSUSED */
static int
mdoc_ex_pre(MDOC_ARGS)
{
@@ -1095,16 +1074,14 @@ mdoc_ex_pre(MDOC_ARGS)
}
if (nchild > 1)
- print_text(h, "utilities exit");
+ print_text(h, "utilities exit\\~0");
else
- print_text(h, "utility exits");
+ print_text(h, "utility exits\\~0");
- print_text(h, "0 on success, and >0 if an error occurs.");
+ print_text(h, "on success, and\\~>0 if an error occurs.");
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_em_pre(MDOC_ARGS)
{
@@ -1115,8 +1092,6 @@ mdoc_em_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_d1_pre(MDOC_ARGS)
{
@@ -1141,13 +1116,11 @@ mdoc_d1_pre(MDOC_ARGS)
if (MDOC_Dl == n->tok) {
PAIR_CLASS_INIT(&tag[0], "lit");
print_otag(h, TAG_CODE, 1, tag);
- }
+ }
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_sx_pre(MDOC_ARGS)
{
@@ -1170,13 +1143,11 @@ mdoc_sx_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_bd_pre(MDOC_ARGS)
{
- struct htmlpair tag[2];
- int comp, sv;
+ struct htmlpair tag[2];
+ int comp, sv;
const struct mdoc_node *nn;
struct roffsu su;
@@ -1201,13 +1172,13 @@ mdoc_bd_pre(MDOC_ARGS)
SCALE_HS_INIT(&su, 0);
if (n->norm->Bd.offs)
a2offs(n->norm->Bd.offs, &su);
-
+
bufinit(h);
bufcat_su(h, "margin-left", &su);
PAIR_STYLE_INIT(&tag[0], h);
- if (DISP_unfilled != n->norm->Bd.type &&
- DISP_literal != n->norm->Bd.type) {
+ if (DISP_unfilled != n->norm->Bd.type &&
+ DISP_literal != n->norm->Bd.type) {
PAIR_CLASS_INIT(&tag[1], "display");
print_otag(h, TAG_DIV, 2, tag);
return(1);
@@ -1230,21 +1201,21 @@ mdoc_bd_pre(MDOC_ARGS)
* anyway, so don't sweat it.
*/
switch (nn->tok) {
- case (MDOC_Sm):
+ case MDOC_Sm:
/* FALLTHROUGH */
- case (MDOC_br):
+ case MDOC_br:
/* FALLTHROUGH */
- case (MDOC_sp):
+ case MDOC_sp:
/* FALLTHROUGH */
- case (MDOC_Bl):
+ case MDOC_Bl:
/* FALLTHROUGH */
- case (MDOC_D1):
+ case MDOC_D1:
/* FALLTHROUGH */
- case (MDOC_Dl):
+ case MDOC_Dl:
/* FALLTHROUGH */
- case (MDOC_Lp):
+ case MDOC_Lp:
/* FALLTHROUGH */
- case (MDOC_Pp):
+ case MDOC_Pp:
continue;
default:
break;
@@ -1263,8 +1234,6 @@ mdoc_bd_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_pa_pre(MDOC_ARGS)
{
@@ -1275,8 +1244,6 @@ mdoc_pa_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ad_pre(MDOC_ARGS)
{
@@ -1287,8 +1254,6 @@ mdoc_ad_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_an_pre(MDOC_ARGS)
{
@@ -1301,8 +1266,6 @@ mdoc_an_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_cd_pre(MDOC_ARGS)
{
@@ -1314,8 +1277,6 @@ mdoc_cd_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_dv_pre(MDOC_ARGS)
{
@@ -1326,8 +1287,6 @@ mdoc_dv_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ev_pre(MDOC_ARGS)
{
@@ -1338,8 +1297,6 @@ mdoc_ev_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_er_pre(MDOC_ARGS)
{
@@ -1350,8 +1307,6 @@ mdoc_er_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_fa_pre(MDOC_ARGS)
{
@@ -1383,8 +1338,6 @@ mdoc_fa_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_fd_pre(MDOC_ARGS)
{
@@ -1413,21 +1366,30 @@ mdoc_fd_pre(MDOC_ARGS)
if (NULL != (n = n->next)) {
assert(MDOC_TEXT == n->type);
- strlcpy(buf, '<' == *n->string || '"' == *n->string ?
- n->string + 1 : n->string, BUFSIZ);
+
+ /*
+ * XXX This is broken and not easy to fix.
+ * When using -Oincludes, truncation may occur.
+ * Dynamic allocation wouldn't help because
+ * passing long strings to buffmt_includes()
+ * does not work either.
+ */
+
+ strlcpy(buf, '<' == *n->string || '"' == *n->string ?
+ n->string + 1 : n->string, BUFSIZ);
sz = strlen(buf);
if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1]))
buf[sz - 1] = '\0';
PAIR_CLASS_INIT(&tag[0], "link-includes");
-
+
i = 1;
if (h->base_includes) {
buffmt_includes(h, buf);
PAIR_HREF_INIT(&tag[i], h->buf);
i++;
- }
+ }
t = print_otag(h, TAG_A, i, tag);
print_text(h, n->string);
@@ -1444,8 +1406,6 @@ mdoc_fd_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_vt_pre(MDOC_ARGS)
{
@@ -1464,8 +1424,6 @@ mdoc_vt_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ft_pre(MDOC_ARGS)
{
@@ -1477,8 +1435,6 @@ mdoc_ft_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_fn_pre(MDOC_ARGS)
{
@@ -1499,7 +1455,7 @@ mdoc_fn_pre(MDOC_ARGS)
if (NULL != ep) {
PAIR_CLASS_INIT(&tag[0], "ftype");
t = print_otag(h, TAG_I, 1, tag);
-
+
while (ep) {
sz = MIN((int)(ep - sp), BUFSIZ - 1);
(void)memcpy(nbuf, sp, (size_t)sz);
@@ -1531,10 +1487,8 @@ mdoc_fn_pre(MDOC_ARGS)
t = print_otag(h, TAG_B, 1, tag);
- if (sp) {
- strlcpy(nbuf, sp, BUFSIZ);
- print_text(h, nbuf);
- }
+ if (sp)
+ print_text(h, sp);
print_tagq(h, t);
@@ -1571,43 +1525,38 @@ mdoc_fn_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_sm_pre(MDOC_ARGS)
{
- assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string)) {
- /*
- * FIXME: no p->col to check. Thus, if we have
- * .Bd -literal
- * .Sm off
- * 1 2
- * .Sm on
- * 3
- * .Ed
- * the "3" is preceded by a space.
- */
- h->flags &= ~HTML_NOSPACE;
+ if (NULL == n->child)
+ h->flags ^= HTML_NONOSPACE;
+ else if (0 == strcmp("on", n->child->string))
h->flags &= ~HTML_NONOSPACE;
- } else
+ else
h->flags |= HTML_NONOSPACE;
+ if ( ! (HTML_NONOSPACE & h->flags))
+ h->flags &= ~HTML_NOSPACE;
+
+ return(0);
+}
+
+static int
+mdoc_skip_pre(MDOC_ARGS)
+{
+
return(0);
}
-/* ARGSUSED */
static int
mdoc_pp_pre(MDOC_ARGS)
{
print_otag(h, TAG_P, 0, NULL);
return(0);
-
}
-/* ARGSUSED */
static int
mdoc_sp_pre(MDOC_ARGS)
{
@@ -1621,7 +1570,7 @@ mdoc_sp_pre(MDOC_ARGS)
if ( ! a2roffsu(n->string, &su, SCALE_VS))
SCALE_VS_INIT(&su, atoi(n->string));
} else
- su.scale = 0;
+ su.scale = 0.0;
bufinit(h);
bufcat_su(h, "height", &su);
@@ -1635,7 +1584,6 @@ mdoc_sp_pre(MDOC_ARGS)
}
-/* ARGSUSED */
static int
mdoc_lk_pre(MDOC_ARGS)
{
@@ -1660,8 +1608,6 @@ mdoc_lk_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_mt_pre(MDOC_ARGS)
{
@@ -1682,12 +1628,10 @@ mdoc_mt_pre(MDOC_ARGS)
print_text(h, n->string);
print_tagq(h, t);
}
-
+
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_fo_pre(MDOC_ARGS)
{
@@ -1716,8 +1660,6 @@ mdoc_fo_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
mdoc_fo_post(MDOC_ARGS)
{
@@ -1730,8 +1672,6 @@ mdoc_fo_post(MDOC_ARGS)
print_text(h, ";");
}
-
-/* ARGSUSED */
static int
mdoc_in_pre(MDOC_ARGS)
{
@@ -1767,7 +1707,7 @@ mdoc_in_pre(MDOC_ARGS)
buffmt_includes(h, n->string);
PAIR_HREF_INIT(&tag[i], h->buf);
i++;
- }
+ }
t = print_otag(h, TAG_A, i, tag);
print_text(h, n->string);
@@ -1787,8 +1727,6 @@ mdoc_in_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_ic_pre(MDOC_ARGS)
{
@@ -1799,8 +1737,6 @@ mdoc_ic_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_rv_pre(MDOC_ARGS)
{
@@ -1813,46 +1749,50 @@ mdoc_rv_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag, "fname");
- print_text(h, "The");
-
nchild = n->nchild;
- for (n = n->child; n; n = n->next) {
- assert(MDOC_TEXT == n->type);
+ if (nchild > 0) {
+ print_text(h, "The");
- t = print_otag(h, TAG_B, 1, &tag);
- print_text(h, n->string);
- print_tagq(h, t);
-
- h->flags |= HTML_NOSPACE;
- print_text(h, "()");
+ for (n = n->child; n; n = n->next) {
+ t = print_otag(h, TAG_B, 1, &tag);
+ print_text(h, n->string);
+ print_tagq(h, t);
- if (nchild > 2 && n->next) {
h->flags |= HTML_NOSPACE;
- print_text(h, ",");
+ print_text(h, "()");
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ h->flags |= HTML_NOSPACE;
+ print_text(h, ",");
+ }
+ if (n->next->next == NULL)
+ print_text(h, "and");
}
- if (n->next && NULL == n->next->next)
- print_text(h, "and");
- }
+ if (nchild > 1)
+ print_text(h, "functions return");
+ else
+ print_text(h, "function returns");
- if (nchild > 1)
- print_text(h, "functions return");
- else
- print_text(h, "function returns");
+ print_text(h, "the value\\~0 if successful;");
+ } else
+ print_text(h, "Upon successful completion,"
+ " the value\\~0 is returned;");
- print_text(h, "the value 0 if successful; otherwise the value "
- "-1 is returned and the global variable");
+ print_text(h, "otherwise the value\\~\\-1 is returned"
+ " and the global variable");
PAIR_CLASS_INIT(&tag, "var");
t = print_otag(h, TAG_B, 1, &tag);
print_text(h, "errno");
print_tagq(h, t);
- print_text(h, "is set to indicate the error.");
+ print_text(h, "is set to indicate the error.");
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_va_pre(MDOC_ARGS)
{
@@ -1863,20 +1803,16 @@ mdoc_va_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ap_pre(MDOC_ARGS)
{
-
+
h->flags |= HTML_NOSPACE;
print_text(h, "\\(aq");
h->flags |= HTML_NOSPACE;
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_bf_pre(MDOC_ARGS)
{
@@ -1888,18 +1824,18 @@ mdoc_bf_pre(MDOC_ARGS)
else if (MDOC_BODY != n->type)
return(1);
- if (FONT_Em == n->norm->Bf.font)
+ if (FONT_Em == n->norm->Bf.font)
PAIR_CLASS_INIT(&tag[0], "emph");
- else if (FONT_Sy == n->norm->Bf.font)
+ else if (FONT_Sy == n->norm->Bf.font)
PAIR_CLASS_INIT(&tag[0], "symb");
- else if (FONT_Li == n->norm->Bf.font)
+ else if (FONT_Li == n->norm->Bf.font)
PAIR_CLASS_INIT(&tag[0], "lit");
else
PAIR_CLASS_INIT(&tag[0], "none");
- /*
+ /*
* We want this to be inline-formatted, but needs to be div to
- * accept block children.
+ * accept block children.
*/
bufinit(h);
bufcat_style(h, "display", "inline");
@@ -1911,8 +1847,6 @@ mdoc_bf_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ms_pre(MDOC_ARGS)
{
@@ -1923,8 +1857,6 @@ mdoc_ms_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_igndelim_pre(MDOC_ARGS)
{
@@ -1933,8 +1865,6 @@ mdoc_igndelim_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc_pf_post(MDOC_ARGS)
{
@@ -1942,8 +1872,6 @@ mdoc_pf_post(MDOC_ARGS)
h->flags |= HTML_NOSPACE;
}
-
-/* ARGSUSED */
static int
mdoc_rs_pre(MDOC_ARGS)
{
@@ -1960,9 +1888,6 @@ mdoc_rs_pre(MDOC_ARGS)
return(1);
}
-
-
-/* ARGSUSED */
static int
mdoc_li_pre(MDOC_ARGS)
{
@@ -1973,8 +1898,6 @@ mdoc_li_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_sy_pre(MDOC_ARGS)
{
@@ -1985,8 +1908,6 @@ mdoc_sy_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_bt_pre(MDOC_ARGS)
{
@@ -1995,8 +1916,6 @@ mdoc_bt_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_ud_pre(MDOC_ARGS)
{
@@ -2005,8 +1924,6 @@ mdoc_ud_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_lb_pre(MDOC_ARGS)
{
@@ -2020,8 +1937,6 @@ mdoc_lb_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc__x_pre(MDOC_ARGS)
{
@@ -2031,52 +1946,52 @@ mdoc__x_pre(MDOC_ARGS)
t = TAG_SPAN;
switch (n->tok) {
- case(MDOC__A):
+ case MDOC__A:
PAIR_CLASS_INIT(&tag[0], "ref-auth");
if (n->prev && MDOC__A == n->prev->tok)
if (NULL == n->next || MDOC__A != n->next->tok)
print_text(h, "and");
break;
- case(MDOC__B):
+ case MDOC__B:
PAIR_CLASS_INIT(&tag[0], "ref-book");
t = TAG_I;
break;
- case(MDOC__C):
+ case MDOC__C:
PAIR_CLASS_INIT(&tag[0], "ref-city");
break;
- case(MDOC__D):
+ case MDOC__D:
PAIR_CLASS_INIT(&tag[0], "ref-date");
break;
- case(MDOC__I):
+ case MDOC__I:
PAIR_CLASS_INIT(&tag[0], "ref-issue");
t = TAG_I;
break;
- case(MDOC__J):
+ case MDOC__J:
PAIR_CLASS_INIT(&tag[0], "ref-jrnl");
t = TAG_I;
break;
- case(MDOC__N):
+ case MDOC__N:
PAIR_CLASS_INIT(&tag[0], "ref-num");
break;
- case(MDOC__O):
+ case MDOC__O:
PAIR_CLASS_INIT(&tag[0], "ref-opt");
break;
- case(MDOC__P):
+ case MDOC__P:
PAIR_CLASS_INIT(&tag[0], "ref-page");
break;
- case(MDOC__Q):
+ case MDOC__Q:
PAIR_CLASS_INIT(&tag[0], "ref-corp");
break;
- case(MDOC__R):
+ case MDOC__R:
PAIR_CLASS_INIT(&tag[0], "ref-rep");
break;
- case(MDOC__T):
+ case MDOC__T:
PAIR_CLASS_INIT(&tag[0], "ref-title");
break;
- case(MDOC__U):
+ case MDOC__U:
PAIR_CLASS_INIT(&tag[0], "link-ref");
break;
- case(MDOC__V):
+ case MDOC__V:
PAIR_CLASS_INIT(&tag[0], "ref-vol");
break;
default:
@@ -2095,8 +2010,6 @@ mdoc__x_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc__x_post(MDOC_ARGS)
{
@@ -2115,18 +2028,16 @@ mdoc__x_post(MDOC_ARGS)
print_text(h, n->next ? "," : ".");
}
-
-/* ARGSUSED */
static int
mdoc_bk_pre(MDOC_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
return(0);
- case (MDOC_BODY):
+ case MDOC_BODY:
if (n->parent->args || 0 == n->prev->nchild)
h->flags |= HTML_PREKEEP;
break;
@@ -2138,8 +2049,6 @@ mdoc_bk_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc_bk_post(MDOC_ARGS)
{
@@ -2148,8 +2057,6 @@ mdoc_bk_post(MDOC_ARGS)
h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
}
-
-/* ARGSUSED */
static int
mdoc_quote_pre(MDOC_ARGS)
{
@@ -2159,54 +2066,60 @@ mdoc_quote_pre(MDOC_ARGS)
return(1);
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
+ case MDOC_Aq:
print_text(h, "\\(la");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
print_text(h, "\\(lC");
break;
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
print_text(h, "\\(lB");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
print_text(h, "\\(lB");
h->flags |= HTML_NOSPACE;
PAIR_CLASS_INIT(&tag, "opt");
print_otag(h, TAG_SPAN, 1, &tag);
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child)
+ return(1);
+ print_text(h, n->norm->Es->child->string);
break;
- case (MDOC_Do):
+ case MDOC_Eo:
+ break;
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
+ case MDOC_Dq:
/* FALLTHROUGH */
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
print_text(h, "\\(lq");
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
print_text(h, "(");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
print_text(h, "\\(oq");
h->flags |= HTML_NOSPACE;
PAIR_CLASS_INIT(&tag, "lit");
print_otag(h, TAG_CODE, 1, &tag);
break;
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
print_text(h, "\\(oq");
break;
default:
@@ -2218,8 +2131,6 @@ mdoc_quote_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc_quote_post(MDOC_ARGS)
{
@@ -2227,49 +2138,58 @@ mdoc_quote_post(MDOC_ARGS)
if (MDOC_BODY != n->type)
return;
- h->flags |= HTML_NOSPACE;
+ if (MDOC_En != n->tok)
+ h->flags |= HTML_NOSPACE;
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
+ case MDOC_Aq:
print_text(h, "\\(ra");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
print_text(h, "\\(rC");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
/* FALLTHROUGH */
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
print_text(h, "\\(rB");
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (NULL != n->norm->Es &&
+ NULL != n->norm->Es->child &&
+ NULL != n->norm->Es->child->next) {
+ h->flags |= HTML_NOSPACE;
+ print_text(h, n->norm->Es->child->next->string);
+ }
break;
- case (MDOC_Qo):
+ case MDOC_Eo:
+ break;
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
/* FALLTHROUGH */
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
+ case MDOC_Dq:
print_text(h, "\\(rq");
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
print_text(h, ")");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
/* FALLTHROUGH */
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
print_text(h, "\\(cq");
break;
default:
@@ -2277,5 +2197,3 @@ mdoc_quote_post(MDOC_ARGS)
/* NOTREACHED */
}
}
-
-
diff --git a/contrib/mdocml/mdoc_macro.c b/contrib/mdocml/mdoc_macro.c
index 2a63ca9..0f5b557 100644
--- a/contrib/mdocml/mdoc_macro.c
+++ b/contrib/mdocml/mdoc_macro.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_macro.c,v 1.125 2013/12/24 20:45:27 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.139 2014/08/01 17:27:44 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -40,33 +40,32 @@ enum rew { /* see rew_dohalt() */
REWIND_ERROR
};
-static int blk_full(MACRO_PROT_ARGS);
-static int blk_exp_close(MACRO_PROT_ARGS);
-static int blk_part_exp(MACRO_PROT_ARGS);
-static int blk_part_imp(MACRO_PROT_ARGS);
-static int ctx_synopsis(MACRO_PROT_ARGS);
-static int in_line_eoln(MACRO_PROT_ARGS);
-static int in_line_argn(MACRO_PROT_ARGS);
-static int in_line(MACRO_PROT_ARGS);
-static int obsolete(MACRO_PROT_ARGS);
-static int phrase_ta(MACRO_PROT_ARGS);
+static int blk_full(MACRO_PROT_ARGS);
+static int blk_exp_close(MACRO_PROT_ARGS);
+static int blk_part_exp(MACRO_PROT_ARGS);
+static int blk_part_imp(MACRO_PROT_ARGS);
+static int ctx_synopsis(MACRO_PROT_ARGS);
+static int in_line_eoln(MACRO_PROT_ARGS);
+static int in_line_argn(MACRO_PROT_ARGS);
+static int in_line(MACRO_PROT_ARGS);
+static int phrase_ta(MACRO_PROT_ARGS);
static int dword(struct mdoc *, int, int, const char *,
enum mdelim, int);
-static int append_delims(struct mdoc *,
+static int append_delims(struct mdoc *,
int, int *, char *);
static enum mdoct lookup(enum mdoct, const char *);
static enum mdoct lookup_raw(const char *);
static int make_pending(struct mdoc_node *, enum mdoct,
struct mdoc *, int, int);
-static int phrase(struct mdoc *, int, int, char *);
-static enum mdoct rew_alt(enum mdoct);
-static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
+static int phrase(struct mdoc *, int, int, char *);
+static enum mdoct rew_alt(enum mdoct);
+static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
const struct mdoc_node *);
-static int rew_elem(struct mdoc *, enum mdoct);
-static int rew_last(struct mdoc *,
+static int rew_elem(struct mdoc *, enum mdoct);
+static int rew_last(struct mdoc *,
const struct mdoc_node *);
-static int rew_sub(enum mdoc_type, struct mdoc *,
+static int rew_sub(enum mdoc_type, struct mdoc *,
enum mdoct, int, int);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
@@ -87,7 +86,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
- { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
@@ -98,13 +97,13 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
- { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ic */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */
{ blk_full, MDOC_JOIN }, /* Nd */
{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
- { obsolete, 0 }, /* Ot */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ot */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
{ in_line_eoln, 0 }, /* Rv */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
@@ -191,7 +190,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */
{ in_line_eoln, 0 }, /* Bt */
{ in_line_eoln, 0 }, /* Hf */
- { obsolete, 0 }, /* Fr */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fr */
{ in_line_eoln, 0 }, /* Ud */
{ in_line, 0 }, /* Lb */
{ in_line_eoln, 0 }, /* Lp */
@@ -203,14 +202,15 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */
{ in_line_eoln, MDOC_JOIN }, /* %C */
- { obsolete, 0 }, /* Es */
- { obsolete, 0 }, /* En */
+ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Es */
+ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
{ in_line_eoln, MDOC_JOIN }, /* %Q */
{ in_line_eoln, 0 }, /* br */
{ in_line_eoln, 0 }, /* sp */
{ in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
+ { in_line_eoln, 0 }, /* ll */
};
const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
@@ -229,19 +229,19 @@ mdoc_macroend(struct mdoc *mdoc)
/* Scan for open explicit scopes. */
n = MDOC_VALID & mdoc->last->flags ?
- mdoc->last->parent : mdoc->last;
+ mdoc->last->parent : mdoc->last;
for ( ; n; n = n->parent)
if (MDOC_BLOCK == n->type &&
MDOC_EXPLICIT & mdoc_macros[n->tok].flags)
- mdoc_nmsg(mdoc, n, MANDOCERR_SCOPEEXIT);
+ mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
/* Rewind to the first. */
return(rew_last(mdoc, mdoc->first));
}
-
/*
* Look up a macro from within a subsequent context.
*/
@@ -254,7 +254,6 @@ lookup(enum mdoct from, const char *p)
return(lookup_raw(p));
}
-
/*
* Lookup a macro following the initial line macro.
*/
@@ -270,7 +269,6 @@ lookup_raw(const char *p)
return(MDOC_MAX);
}
-
static int
rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
{
@@ -279,7 +277,7 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
assert(to);
mdoc->next = MDOC_NEXT_SIBLING;
- /* LINTED */
+
while (mdoc->last != to) {
/*
* Save the parent here, because we may delete the
@@ -299,7 +297,6 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
return(mdoc_valid_post(mdoc));
}
-
/*
* For a block closing macro, return the corresponding opening one.
* Otherwise, return the macro itself.
@@ -308,37 +305,37 @@ static enum mdoct
rew_alt(enum mdoct tok)
{
switch (tok) {
- case (MDOC_Ac):
+ case MDOC_Ac:
return(MDOC_Ao);
- case (MDOC_Bc):
+ case MDOC_Bc:
return(MDOC_Bo);
- case (MDOC_Brc):
+ case MDOC_Brc:
return(MDOC_Bro);
- case (MDOC_Dc):
+ case MDOC_Dc:
return(MDOC_Do);
- case (MDOC_Ec):
+ case MDOC_Ec:
return(MDOC_Eo);
- case (MDOC_Ed):
+ case MDOC_Ed:
return(MDOC_Bd);
- case (MDOC_Ef):
+ case MDOC_Ef:
return(MDOC_Bf);
- case (MDOC_Ek):
+ case MDOC_Ek:
return(MDOC_Bk);
- case (MDOC_El):
+ case MDOC_El:
return(MDOC_Bl);
- case (MDOC_Fc):
+ case MDOC_Fc:
return(MDOC_Fo);
- case (MDOC_Oc):
+ case MDOC_Oc:
return(MDOC_Oo);
- case (MDOC_Pc):
+ case MDOC_Pc:
return(MDOC_Po);
- case (MDOC_Qc):
+ case MDOC_Qc:
return(MDOC_Qo);
- case (MDOC_Re):
+ case MDOC_Re:
return(MDOC_Rs);
- case (MDOC_Sc):
+ case MDOC_Sc:
return(MDOC_So);
- case (MDOC_Xc):
+ case MDOC_Xc:
return(MDOC_Xo);
default:
return(tok);
@@ -346,7 +343,6 @@ rew_alt(enum mdoct tok)
/* NOTREACHED */
}
-
/*
* Rewinding to tok, how do we have to handle *p?
* REWIND_NONE: *p would delimit tok, but no tok scope is open
@@ -358,7 +354,7 @@ rew_alt(enum mdoct tok)
* REWIND_ERROR: No tok block is open at all.
*/
static enum rew
-rew_dohalt(enum mdoct tok, enum mdoc_type type,
+rew_dohalt(enum mdoct tok, enum mdoc_type type,
const struct mdoc_node *p)
{
@@ -374,7 +370,7 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
REWIND_ERROR : REWIND_NONE);
/*
- * When starting to rewind, skip plain text
+ * When starting to rewind, skip plain text
* and nodes that have already been rewound.
*/
if (MDOC_TEXT == p->type || MDOC_VALID & p->flags)
@@ -398,14 +394,14 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
/*
* Blocks delimited by our target token get REWIND_MORE.
- * Blocks delimiting our target token get REWIND_NONE.
+ * Blocks delimiting our target token get REWIND_NONE.
*/
switch (tok) {
- case (MDOC_Bl):
+ case MDOC_Bl:
if (MDOC_It == p->tok)
return(REWIND_MORE);
break;
- case (MDOC_It):
+ case MDOC_It:
if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
return(REWIND_NONE);
break;
@@ -415,19 +411,21 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
* This is an incomplete and extremely ugly workaround,
* required to let the OpenBSD tree build.
*/
- case (MDOC_Oo):
+ case MDOC_Oo:
if (MDOC_Op == p->tok)
return(REWIND_MORE);
break;
- case (MDOC_Nm):
+ case MDOC_Nm:
return(REWIND_NONE);
- case (MDOC_Nd):
+ case MDOC_Nd:
/* FALLTHROUGH */
- case (MDOC_Ss):
+ case MDOC_Ss:
if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
return(REWIND_NONE);
/* FALLTHROUGH */
- case (MDOC_Sh):
+ case MDOC_Sh:
+ if (MDOC_ROOT == p->parent->type)
+ return(REWIND_THIS);
if (MDOC_Nd == p->tok || MDOC_Ss == p->tok ||
MDOC_Sh == p->tok)
return(REWIND_MORE);
@@ -456,7 +454,6 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
REWIND_FORCE : REWIND_LATER);
}
-
static int
rew_elem(struct mdoc *mdoc, enum mdoct tok)
{
@@ -471,7 +468,6 @@ rew_elem(struct mdoc *mdoc, enum mdoct tok)
return(rew_last(mdoc, n));
}
-
/*
* We are trying to close a block identified by tok,
* but the child block *broken is still open.
@@ -535,9 +531,9 @@ make_pending(struct mdoc_node *broken, enum mdoct tok,
taker->pending = broken->pending;
}
broken->pending = breaker;
- mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos,
- "%s breaks %s", mdoc_macronames[tok],
- mdoc_macronames[broken->tok]);
+ mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos,
+ "%s breaks %s", mdoc_macronames[tok],
+ mdoc_macronames[broken->tok]);
return(1);
}
@@ -548,9 +544,8 @@ make_pending(struct mdoc_node *broken, enum mdoct tok,
return(0);
}
-
static int
-rew_sub(enum mdoc_type t, struct mdoc *mdoc,
+rew_sub(enum mdoc_type t, struct mdoc *mdoc,
enum mdoct tok, int line, int ppos)
{
struct mdoc_node *n;
@@ -558,31 +553,33 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc,
n = mdoc->last;
while (n) {
switch (rew_dohalt(tok, t, n)) {
- case (REWIND_NONE):
+ case REWIND_NONE:
return(1);
- case (REWIND_THIS):
+ case REWIND_THIS:
n->lastline = line -
(MDOC_NEWLINE & mdoc->flags &&
! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
break;
- case (REWIND_FORCE):
- mandoc_vmsg(MANDOCERR_SCOPEBROKEN, mdoc->parse,
- line, ppos, "%s breaks %s",
- mdoc_macronames[tok],
- mdoc_macronames[n->tok]);
+ case REWIND_FORCE:
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse,
+ line, ppos, "%s breaks %s",
+ mdoc_macronames[tok],
+ mdoc_macronames[n->tok]);
/* FALLTHROUGH */
- case (REWIND_MORE):
+ case REWIND_MORE:
n->lastline = line -
(MDOC_NEWLINE & mdoc->flags ? 1 : 0);
n = n->parent;
continue;
- case (REWIND_LATER):
+ case REWIND_LATER:
if (make_pending(n, tok, mdoc, line, ppos) ||
MDOC_BLOCK != t)
return(1);
/* FALLTHROUGH */
- case (REWIND_ERROR):
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_NOSCOPE);
+ case REWIND_ERROR:
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN,
+ mdoc->parse, line, ppos,
+ mdoc_macronames[tok]);
return(1);
}
break;
@@ -615,7 +612,7 @@ static int
dword(struct mdoc *mdoc, int line, int col, const char *p,
enum mdelim d, int may_append)
{
-
+
if (DELIM_MAX == d)
d = mdoc_isdelim(p);
@@ -644,8 +641,8 @@ dword(struct mdoc *mdoc, int line, int col, const char *p,
*/
else if (DELIM_CLOSE == d && mdoc->last->prev &&
- mdoc->last->prev->tok != MDOC_No &&
- mdoc->last->parent->tok != MDOC_Fd)
+ mdoc->last->prev->tok != MDOC_No &&
+ mdoc->last->parent->tok != MDOC_Fd)
mdoc->last->flags |= MDOC_DELIMC;
return(1);
@@ -683,16 +680,15 @@ append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
* knowing which symbols break this behaviour, for
* example, `. ;' shouldn't propagate the double-space.
*/
- if (mandoc_eos(p, strlen(p), 0))
+ if (mandoc_eos(p, strlen(p)))
mdoc->last->flags |= MDOC_EOS;
}
return(1);
}
-
/*
- * Close out block partial/full explicit.
+ * Close out block partial/full explicit.
*/
static int
blk_exp_close(MACRO_PROT_ARGS)
@@ -701,7 +697,7 @@ blk_exp_close(MACRO_PROT_ARGS)
struct mdoc_node *later; /* A sub-block starting later. */
struct mdoc_node *n; /* For searching backwards. */
- int j, lastarg, maxargs, flushed, nl;
+ int j, lastarg, maxargs, flushed, nl;
enum margserr ac;
enum mdoct atok, ntok;
char *p;
@@ -709,10 +705,10 @@ blk_exp_close(MACRO_PROT_ARGS)
nl = MDOC_NEWLINE & mdoc->flags;
switch (tok) {
- case (MDOC_Ec):
+ case MDOC_Ec:
maxargs = 1;
break;
- case (MDOC_Ek):
+ case MDOC_Ek:
mdoc->flags &= ~MDOC_KEEP;
default:
maxargs = 0;
@@ -749,7 +745,7 @@ blk_exp_close(MACRO_PROT_ARGS)
if (NULL == later)
break;
- /*
+ /*
* When there is a pending sub block,
* postpone closing out the current block
* until the rew_sub() closing out the sub-block.
@@ -778,11 +774,12 @@ blk_exp_close(MACRO_PROT_ARGS)
later = n;
}
- if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
- /* FIXME: do this in validate */
- if (buf[*pos])
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_ARGSLOST);
-
+ if ( ! (MDOC_PARSED & mdoc_macros[tok].flags)) {
+ if ('\0' != buf[*pos])
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, line, ppos,
+ "%s %s", mdoc_macronames[tok],
+ buf + *pos);
if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
return(0);
return(rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos));
@@ -791,7 +788,7 @@ blk_exp_close(MACRO_PROT_ARGS)
if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
return(0);
- if (NULL == later && maxargs > 0)
+ if (NULL == later && maxargs > 0)
if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok)))
return(0);
@@ -843,7 +840,6 @@ blk_exp_close(MACRO_PROT_ARGS)
return(append_delims(mdoc, line, pos, buf));
}
-
static int
in_line(MACRO_PROT_ARGS)
{
@@ -863,17 +859,17 @@ in_line(MACRO_PROT_ARGS)
*/
switch (tok) {
- case (MDOC_An):
+ case MDOC_An:
/* FALLTHROUGH */
- case (MDOC_Ar):
+ case MDOC_Ar:
/* FALLTHROUGH */
- case (MDOC_Fl):
+ case MDOC_Fl:
/* FALLTHROUGH */
- case (MDOC_Mt):
+ case MDOC_Mt:
/* FALLTHROUGH */
- case (MDOC_Nm):
+ case MDOC_Nm:
/* FALLTHROUGH */
- case (MDOC_Pa):
+ case MDOC_Pa:
nc = 1;
break;
default:
@@ -888,7 +884,7 @@ in_line(MACRO_PROT_ARGS)
if (ARGV_WORD == av) {
*pos = la;
break;
- }
+ }
if (ARGV_EOLN == av)
break;
if (ARGV_ARG == av)
@@ -911,7 +907,7 @@ in_line(MACRO_PROT_ARGS)
ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
- /*
+ /*
* In this case, we've located a submacro and must
* execute it. Close out scope, if open. If no
* elements have been generated, either create one (nc)
@@ -922,15 +918,16 @@ in_line(MACRO_PROT_ARGS)
if (scope && ! rew_elem(mdoc, tok))
return(0);
if (nc && 0 == cnt) {
- if ( ! mdoc_elem_alloc(mdoc, line,
- ppos, tok, arg))
+ if ( ! mdoc_elem_alloc(mdoc,
+ line, ppos, tok, arg))
return(0);
if ( ! rew_last(mdoc, mdoc->last))
return(0);
} else if ( ! nc && 0 == cnt) {
mdoc_argv_free(arg);
- mdoc_pmsg(mdoc, line, ppos,
- MANDOCERR_MACROEMPTY);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
+ mdoc->parse, line, ppos,
+ mdoc_macronames[tok]);
}
if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
@@ -938,12 +935,12 @@ in_line(MACRO_PROT_ARGS)
if ( ! nl)
return(1);
return(append_delims(mdoc, line, pos, buf));
- }
+ }
- /*
+ /*
* Non-quote-enclosed punctuation. Set up our scope, if
* a word; rewind the scope, if a delimiter; then append
- * the word.
+ * the word.
*/
d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
@@ -957,13 +954,13 @@ in_line(MACRO_PROT_ARGS)
* this once per invocation. There may be more
* of these (all of them?).
*/
- if (0 == cnt && (nc || MDOC_Li == tok) &&
- DELIM_CLOSE == d && ! scope) {
- if ( ! mdoc_elem_alloc(mdoc, line,
- ppos, tok, arg))
+ if (0 == cnt && (nc || MDOC_Li == tok) &&
+ DELIM_CLOSE == d && ! scope) {
+ if ( ! mdoc_elem_alloc(mdoc,
+ line, ppos, tok, arg))
return(0);
- if (MDOC_Ar == tok || MDOC_Li == tok ||
- MDOC_Fl == tok)
+ if (MDOC_Ar == tok || MDOC_Li == tok ||
+ MDOC_Fl == tok)
cnt++;
scope = 1;
}
@@ -1015,7 +1012,8 @@ in_line(MACRO_PROT_ARGS)
return(0);
} else if ( ! nc && 0 == cnt) {
mdoc_argv_free(arg);
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROEMPTY);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
}
if ( ! nl)
@@ -1023,7 +1021,6 @@ in_line(MACRO_PROT_ARGS)
return(append_delims(mdoc, line, pos, buf));
}
-
static int
blk_full(MACRO_PROT_ARGS)
{
@@ -1040,6 +1037,22 @@ blk_full(MACRO_PROT_ARGS)
nl = MDOC_NEWLINE & mdoc->flags;
+ /* Skip items outside lists. */
+
+ if (tok == MDOC_It) {
+ for (n = mdoc->last; n; n = n->parent)
+ if (n->tok == MDOC_Bl)
+ break;
+ if (n == NULL) {
+ mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
+ line, ppos, "It %s", buf + *pos);
+ if ( ! mdoc_elem_alloc(mdoc, line, ppos,
+ MDOC_br, NULL))
+ return(0);
+ return(rew_elem(mdoc, MDOC_br));
+ }
+ }
+
/* Close out prior implicit scope. */
if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
@@ -1065,7 +1078,7 @@ blk_full(MACRO_PROT_ARGS)
if (ARGV_WORD == av) {
*pos = la;
break;
- }
+ }
if (ARGV_EOLN == av)
break;
@@ -1086,8 +1099,8 @@ blk_full(MACRO_PROT_ARGS)
* parsed, even though `It' macros in general are parsed.
*/
nparsed = MDOC_It == tok &&
- MDOC_Bl == mdoc->last->parent->tok &&
- LIST_diag == mdoc->last->parent->norm->Bl.type;
+ MDOC_Bl == mdoc->last->parent->tok &&
+ LIST_diag == mdoc->last->parent->norm->Bl.type;
/*
* The `Nd' macro has all arguments in its body: it's a hybrid
@@ -1140,17 +1153,17 @@ blk_full(MACRO_PROT_ARGS)
break;
}
- /*
+ /*
* Emit leading punctuation (i.e., punctuation before
* the MDOC_HEAD) for non-phrase types.
*/
- if (NULL == head &&
- ARGS_PEND != ac &&
- ARGS_PHRASE != ac &&
- ARGS_PPHRASE != ac &&
- ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
+ if (NULL == head &&
+ ARGS_PEND != ac &&
+ ARGS_PHRASE != ac &&
+ ARGS_PPHRASE != ac &&
+ ARGS_QWORD != ac &&
+ DELIM_OPEN == mdoc_isdelim(p)) {
if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
return(0);
continue;
@@ -1164,9 +1177,9 @@ blk_full(MACRO_PROT_ARGS)
head = mdoc->last;
}
- if (ARGS_PHRASE == ac ||
- ARGS_PEND == ac ||
- ARGS_PPHRASE == ac) {
+ if (ARGS_PHRASE == ac ||
+ ARGS_PEND == ac ||
+ ARGS_PPHRASE == ac) {
/*
* If we haven't opened a body yet, rewind the
* head; if we have, rewind that instead.
@@ -1175,7 +1188,7 @@ blk_full(MACRO_PROT_ARGS)
mtt = body ? MDOC_BODY : MDOC_HEAD;
if ( ! rew_sub(mtt, mdoc, tok, line, ppos))
return(0);
-
+
/* Then allocate our body context. */
if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
@@ -1200,8 +1213,8 @@ blk_full(MACRO_PROT_ARGS)
continue;
}
- ntok = nparsed || ARGS_QWORD == ac ?
- MDOC_MAX : lookup(tok, p);
+ ntok = nparsed || ARGS_QWORD == ac ?
+ MDOC_MAX : lookup(tok, p);
if (MDOC_MAX == ntok) {
if ( ! dword(mdoc, line, la, p, DELIM_MAX,
@@ -1220,7 +1233,7 @@ blk_full(MACRO_PROT_ARGS)
return(0);
head = mdoc->last;
}
-
+
if (nl && ! append_delims(mdoc, line, pos, buf))
return(0);
@@ -1236,9 +1249,9 @@ blk_full(MACRO_PROT_ARGS)
* sub-block.
*/
for (n = mdoc->last; n && n != head; n = n->parent) {
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
- ! (MDOC_VALID & n->flags)) {
+ if (MDOC_BLOCK == n->type &&
+ MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
+ ! (MDOC_VALID & n->flags)) {
n->pending = head;
return(1);
}
@@ -1264,7 +1277,6 @@ out:
return(1);
}
-
static int
blk_part_imp(MACRO_PROT_ARGS)
{
@@ -1315,7 +1327,7 @@ blk_part_imp(MACRO_PROT_ARGS)
break;
if (NULL == body && ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
+ DELIM_OPEN == mdoc_isdelim(p)) {
if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
return(0);
continue;
@@ -1349,32 +1361,13 @@ blk_part_imp(MACRO_PROT_ARGS)
body = mdoc->last;
}
- for (n = body->child; n && n->next; n = n->next)
- /* Do nothing. */ ;
-
- /*
- * End of sentence spacing: if the last node is a text node and
- * has a trailing period, then mark it as being end-of-sentence.
- */
-
- if (n && MDOC_TEXT == n->type && n->string)
- if (mandoc_eos(n->string, strlen(n->string), 1))
- n->flags |= MDOC_EOS;
-
- /* Up-propagate the end-of-space flag. */
-
- if (n && (MDOC_EOS & n->flags)) {
- body->flags |= MDOC_EOS;
- body->parent->flags |= MDOC_EOS;
- }
-
/*
* If there is an open sub-block requiring explicit close-out,
* postpone closing out the current block
* until the rew_sub() call closing out the sub-block.
*/
for (n = mdoc->last; n && n != body && n != blk->parent;
- n = n->parent) {
+ n = n->parent) {
if (MDOC_BLOCK == n->type &&
MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
! (MDOC_VALID & n->flags)) {
@@ -1385,18 +1378,9 @@ blk_part_imp(MACRO_PROT_ARGS)
return(1);
}
}
+ assert(n == body);
- /*
- * If we can't rewind to our body, then our scope has already
- * been closed by another macro (like `Oc' closing `Op'). This
- * is ugly behaviour nodding its head to OpenBSD's overwhelming
- * crufty use of `Op' breakage.
- */
- if (n != body)
- mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos,
- "%s broken", mdoc_macronames[tok]);
-
- if (n && ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
+ if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
return(0);
/* Standard appending of delimiters. */
@@ -1406,7 +1390,7 @@ blk_part_imp(MACRO_PROT_ARGS)
/* Rewind scope, if applicable. */
- if (n && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
+ if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
return(0);
/* Move trailing .Ns out of scope. */
@@ -1419,7 +1403,6 @@ blk_part_imp(MACRO_PROT_ARGS)
return(1);
}
-
static int
blk_part_exp(MACRO_PROT_ARGS)
{
@@ -1439,7 +1422,7 @@ blk_part_exp(MACRO_PROT_ARGS)
*/
if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
- return(0);
+ return(0);
for (head = body = NULL; ; ) {
la = *pos;
@@ -1455,7 +1438,7 @@ blk_part_exp(MACRO_PROT_ARGS)
/* Flush out leading punctuation. */
if (NULL == head && ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
+ DELIM_OPEN == mdoc_isdelim(p)) {
assert(NULL == body);
if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
return(0);
@@ -1527,8 +1510,6 @@ blk_part_exp(MACRO_PROT_ARGS)
return(append_delims(mdoc, line, pos, buf));
}
-
-/* ARGSUSED */
static int
in_line_argn(MACRO_PROT_ARGS)
{
@@ -1550,18 +1531,20 @@ in_line_argn(MACRO_PROT_ARGS)
*/
switch (tok) {
- case (MDOC_Ap):
+ case MDOC_Ap:
/* FALLTHROUGH */
- case (MDOC_No):
+ case MDOC_No:
/* FALLTHROUGH */
- case (MDOC_Ns):
+ case MDOC_Ns:
/* FALLTHROUGH */
- case (MDOC_Ux):
+ case MDOC_Ux:
maxargs = 0;
break;
- case (MDOC_Bx):
+ case MDOC_Bx:
/* FALLTHROUGH */
- case (MDOC_Xr):
+ case MDOC_Es:
+ /* FALLTHROUGH */
+ case MDOC_Xr:
maxargs = 2;
break;
default:
@@ -1576,7 +1559,7 @@ in_line_argn(MACRO_PROT_ARGS)
if (ARGV_WORD == av) {
*pos = la;
break;
- }
+ }
if (ARGV_EOLN == av)
break;
@@ -1598,14 +1581,14 @@ in_line_argn(MACRO_PROT_ARGS)
if (ARGS_EOLN == ac)
break;
- if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
- ARGS_QWORD != ac && 0 == j &&
- DELIM_OPEN == mdoc_isdelim(p)) {
+ if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
+ ARGS_QWORD != ac && 0 == j &&
+ DELIM_OPEN == mdoc_isdelim(p)) {
if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
return(0);
continue;
} else if (0 == j)
- if ( ! mdoc_elem_alloc(mdoc, line, la, tok, arg))
+ if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
return(0);
if (j == maxargs && ! flushed) {
@@ -1627,9 +1610,9 @@ in_line_argn(MACRO_PROT_ARGS)
}
if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
- ARGS_QWORD != ac &&
- ! flushed &&
- DELIM_NONE != mdoc_isdelim(p)) {
+ ARGS_QWORD != ac &&
+ ! flushed &&
+ DELIM_NONE != mdoc_isdelim(p)) {
if ( ! rew_elem(mdoc, tok))
return(0);
flushed = 1;
@@ -1641,7 +1624,7 @@ in_line_argn(MACRO_PROT_ARGS)
j++;
}
- if (0 == j && ! mdoc_elem_alloc(mdoc, line, la, tok, arg))
+ if (0 == j && ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
return(0);
/* Close out in a consistent state. */
@@ -1653,7 +1636,6 @@ in_line_argn(MACRO_PROT_ARGS)
return(append_delims(mdoc, line, pos, buf));
}
-
static int
in_line_eoln(MACRO_PROT_ARGS)
{
@@ -1679,7 +1661,7 @@ in_line_eoln(MACRO_PROT_ARGS)
*pos = la;
break;
}
- if (ARGV_EOLN == av)
+ if (ARGV_EOLN == av)
break;
if (ARGV_ARG == av)
continue;
@@ -1723,8 +1705,6 @@ in_line_eoln(MACRO_PROT_ARGS)
return(rew_elem(mdoc, tok));
}
-
-/* ARGSUSED */
static int
ctx_synopsis(MACRO_PROT_ARGS)
{
@@ -1751,17 +1731,6 @@ ctx_synopsis(MACRO_PROT_ARGS)
return(blk_part_imp(mdoc, tok, line, ppos, pos, buf));
}
-
-/* ARGSUSED */
-static int
-obsolete(MACRO_PROT_ARGS)
-{
-
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROOBS);
- return(1);
-}
-
-
/*
* Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
* They're unusual because they're basically free-form text until a
@@ -1801,8 +1770,6 @@ phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
return(1);
}
-
-/* ARGSUSED */
static int
phrase_ta(MACRO_PROT_ARGS)
{
@@ -1817,7 +1784,8 @@ phrase_ta(MACRO_PROT_ARGS)
while (NULL != n && MDOC_Bl != n->tok)
n = n->parent;
if (NULL == n || LIST_column != n->norm->Bl.type) {
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA);
+ mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
+ line, ppos, "Ta");
return(1);
}
diff --git a/contrib/mdocml/mdoc_man.c b/contrib/mdocml/mdoc_man.c
index 6ee8b3a..8ef6908 100644
--- a/contrib/mdocml/mdoc_man.c
+++ b/contrib/mdocml/mdoc_man.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_man.c,v 1.57 2013/12/25 22:00:45 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.68 2014/08/06 15:09:05 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +23,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "man.h"
#include "mdoc.h"
@@ -50,6 +51,7 @@ static void post_bf(DECL_ARGS);
static void post_bk(DECL_ARGS);
static void post_bl(DECL_ARGS);
static void post_dl(DECL_ARGS);
+static void post_en(DECL_ARGS);
static void post_enc(DECL_ARGS);
static void post_eo(DECL_ARGS);
static void post_fa(DECL_ARGS);
@@ -77,8 +79,11 @@ static int pre_bl(DECL_ARGS);
static int pre_br(DECL_ARGS);
static int pre_bx(DECL_ARGS);
static int pre_dl(DECL_ARGS);
+static int pre_en(DECL_ARGS);
static int pre_enc(DECL_ARGS);
static int pre_em(DECL_ARGS);
+static int pre_es(DECL_ARGS);
+static int pre_ex(DECL_ARGS);
static int pre_fa(DECL_ARGS);
static int pre_fd(DECL_ARGS);
static int pre_fl(DECL_ARGS);
@@ -89,11 +94,13 @@ static int pre_in(DECL_ARGS);
static int pre_it(DECL_ARGS);
static int pre_lk(DECL_ARGS);
static int pre_li(DECL_ARGS);
+static int pre_ll(DECL_ARGS);
static int pre_nm(DECL_ARGS);
static int pre_no(DECL_ARGS);
static int pre_ns(DECL_ARGS);
static int pre_pp(DECL_ARGS);
static int pre_rs(DECL_ARGS);
+static int pre_rv(DECL_ARGS);
static int pre_sm(DECL_ARGS);
static int pre_sp(DECL_ARGS);
static int pre_sect(DECL_ARGS);
@@ -134,9 +141,7 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre_li, post_font, NULL, NULL }, /* Dv */
{ NULL, pre_li, post_font, NULL, NULL }, /* Er */
{ NULL, pre_li, post_font, NULL, NULL }, /* Ev */
- { NULL, pre_enc, post_enc, "The \\fB",
- "\\fP\nutility exits 0 on success, and >0 if an error occurs."
- }, /* Ex */
+ { NULL, pre_ex, NULL, NULL, NULL }, /* Ex */
{ NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
@@ -148,13 +153,9 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
- { NULL, NULL, NULL, NULL, NULL }, /* Ot */
+ { NULL, pre_ft, post_font, NULL, NULL }, /* Ot */
{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
- { NULL, pre_enc, post_enc, "The \\fB",
- "\\fP\nfunction returns the value 0 if successful;\n"
- "otherwise the value -1 is returned and the global\n"
- "variable \\fIerrno\\fP is set to indicate the error."
- }, /* Rv */
+ { NULL, pre_rv, NULL, NULL, NULL }, /* Rv */
{ NULL, NULL, NULL, NULL, NULL }, /* St */
{ NULL, pre_em, post_font, NULL, NULL }, /* Va */
{ NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
@@ -222,7 +223,7 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
{ NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */
{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
- { NULL, NULL, NULL, NULL, NULL }, /* Fr */
+ { NULL, pre_em, post_font, NULL, NULL }, /* Fr */
{ NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */
{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
@@ -232,14 +233,15 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
- { NULL, NULL, NULL, NULL, NULL }, /* Es */
- { NULL, NULL, NULL, NULL, NULL }, /* En */
+ { NULL, pre_es, NULL, NULL, NULL }, /* Es */
+ { cond_body, pre_en, post_en, NULL, NULL }, /* En */
{ NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */
{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
{ NULL, pre_br, NULL, NULL, NULL }, /* br */
{ NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
+ { NULL, pre_ll, post_sp, NULL, NULL }, /* ll */
{ NULL, NULL, NULL, NULL, NULL }, /* ROOT */
};
@@ -271,6 +273,7 @@ static struct {
size_t size;
} fontqueue;
+
static void
font_push(char newfont)
{
@@ -278,7 +281,7 @@ font_push(char newfont)
if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
fontqueue.size += 8;
fontqueue.head = mandoc_realloc(fontqueue.head,
- fontqueue.size);
+ fontqueue.size);
}
*fontqueue.tail = newfont;
print_word("");
@@ -304,7 +307,7 @@ print_word(const char *s)
{
if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
- /*
+ /*
* If we need a newline, print it now and start afresh.
*/
if (MMAN_PP & outflags) {
@@ -359,13 +362,16 @@ print_word(const char *s)
for ( ; *s; s++) {
switch (*s) {
- case (ASCII_NBRSP):
+ case ASCII_NBRSP:
printf("\\ ");
break;
- case (ASCII_HYPH):
+ case ASCII_HYPH:
putchar('-');
break;
- case (' '):
+ case ASCII_BREAK:
+ printf("\\:");
+ break;
+ case ' ':
if (MMAN_nbrword & outflags) {
printf("\\ ");
break;
@@ -450,7 +456,7 @@ print_offs(const char *v)
if (Bl_stack_len)
sz += Bl_stack[Bl_stack_len - 1];
- snprintf(buf, sizeof(buf), "%zun", sz);
+ (void)snprintf(buf, sizeof(buf), "%zun", sz);
print_word(buf);
outflags |= MMAN_nl;
}
@@ -458,7 +464,7 @@ print_offs(const char *v)
/*
* Set up the indentation for a list item; used from pre_it().
*/
-void
+static void
print_width(const char *v, const struct mdoc_node *child, size_t defsz)
{
char buf[24];
@@ -484,7 +490,7 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
/* XXX Rough estimation, might have multiple parts. */
chsz = (NULL != child && MDOC_TEXT == child->type) ?
- strlen(child->string) : 0;
+ strlen(child->string) : 0;
/* Maybe we are inside an enclosing list? */
mid_it();
@@ -503,19 +509,19 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
remain = sz + 2;
}
if (numeric) {
- snprintf(buf, sizeof(buf), "%zun", sz + 2);
+ (void)snprintf(buf, sizeof(buf), "%zun", sz + 2);
print_word(buf);
} else
print_word(v);
TPremain = remain;
}
-void
+static void
print_count(int *count)
{
- char buf[12];
+ char buf[24];
- snprintf(buf, sizeof(buf), "%d.", ++*count);
+ (void)snprintf(buf, sizeof(buf), "%d.", ++*count);
print_word(buf);
}
@@ -542,8 +548,9 @@ man_mdoc(void *arg, const struct mdoc *mdoc)
n = mdoc_node(mdoc);
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
- meta->title, meta->msec, meta->date,
- meta->os, meta->vol);
+ meta->title,
+ (meta->msec == NULL ? "" : meta->msec),
+ meta->date, meta->os, meta->vol);
/* Disable hyphenation and if nroff, disable justification. */
printf(".nh\n.if n .ad l");
@@ -581,8 +588,8 @@ print_node(DECL_ARGS)
* Make sure that we don't happen to start with a
* control character at the start of a line.
*/
- if (MMAN_nl & outflags && ('.' == *n->string ||
- '\'' == *n->string)) {
+ if (MMAN_nl & outflags &&
+ ('.' == *n->string || '\'' == *n->string)) {
print_word("");
printf("\\&");
outflags &= ~MMAN_spc;
@@ -595,11 +602,11 @@ print_node(DECL_ARGS)
*/
act = manacts + n->tok;
cond = NULL == act->cond || (*act->cond)(meta, n);
- if (cond && act->pre)
+ if (cond && act->pre && ENDBODY_NOT == n->end)
do_sub = (*act->pre)(meta, n);
}
- /*
+ /*
* Conditionally run all child nodes.
* Note that this iterates over children instead of using
* recursion. This prevents unnecessary depth in the stack.
@@ -611,8 +618,17 @@ print_node(DECL_ARGS)
/*
* Lastly, conditionally run the post-node handler.
*/
+ if (MDOC_ENDED & n->flags)
+ return;
+
if (cond && act->post)
(*act->post)(meta, n);
+
+ if (ENDBODY_NOT != n->end)
+ n->pending->flags |= MDOC_ENDED;
+
+ if (ENDBODY_NOSPACE == n->end)
+ outflags &= ~(MMAN_spc | MMAN_nl);
}
static int
@@ -650,10 +666,46 @@ post_enc(DECL_ARGS)
suffix = manacts[n->tok].suffix;
if (NULL == suffix)
return;
- outflags &= ~MMAN_spc;
+ outflags &= ~(MMAN_spc | MMAN_nl);
print_word(suffix);
}
+static int
+pre_ex(DECL_ARGS)
+{
+ int nchild;
+
+ outflags |= MMAN_br | MMAN_nl;
+
+ print_word("The");
+
+ nchild = n->nchild;
+ for (n = n->child; n; n = n->next) {
+ font_push('B');
+ print_word(n->string);
+ font_pop();
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ outflags &= ~MMAN_spc;
+ print_word(",");
+ }
+ if (n->next->next == NULL)
+ print_word("and");
+ }
+
+ if (nchild > 1)
+ print_word("utilities exit\\~0");
+ else
+ print_word("utility exits\\~0");
+
+ print_word("on success, and\\~>0 if an error occurs.");
+ outflags |= MMAN_nl;
+ return(0);
+}
+
static void
post_font(DECL_ARGS)
{
@@ -682,8 +734,8 @@ static int
pre__t(DECL_ARGS)
{
- if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T) {
+ if (n->parent && MDOC_Rs == n->parent->tok &&
+ n->parent->norm->Rs.quote_T) {
print_word("");
putchar('\"');
outflags &= ~MMAN_spc;
@@ -696,8 +748,8 @@ static void
post__t(DECL_ARGS)
{
- if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T) {
+ if (n->parent && MDOC_Rs == n->parent->tok &&
+ n->parent->norm->Rs.quote_T) {
outflags &= ~MMAN_spc;
print_word("");
putchar('\"');
@@ -749,26 +801,26 @@ pre_syn(const struct mdoc_node *n)
return;
if (n->prev->tok == n->tok &&
- MDOC_Ft != n->tok &&
- MDOC_Fo != n->tok &&
- MDOC_Fn != n->tok) {
+ MDOC_Ft != n->tok &&
+ MDOC_Fo != n->tok &&
+ MDOC_Fn != n->tok) {
outflags |= MMAN_br;
return;
}
switch (n->prev->tok) {
- case (MDOC_Fd):
+ case MDOC_Fd:
/* FALLTHROUGH */
- case (MDOC_Fn):
+ case MDOC_Fn:
/* FALLTHROUGH */
- case (MDOC_Fo):
+ case MDOC_Fo:
/* FALLTHROUGH */
- case (MDOC_In):
+ case MDOC_In:
/* FALLTHROUGH */
- case (MDOC_Vt):
+ case MDOC_Vt:
outflags |= MMAN_sp;
break;
- case (MDOC_Ft):
+ case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
outflags |= MMAN_sp;
break;
@@ -785,11 +837,11 @@ pre_an(DECL_ARGS)
{
switch (n->norm->An.auth) {
- case (AUTH_split):
+ case AUTH_split:
outflags &= ~MMAN_An_nosplit;
outflags |= MMAN_An_split;
return(0);
- case (AUTH_nosplit):
+ case AUTH_nosplit:
outflags &= ~MMAN_An_split;
outflags |= MMAN_An_nosplit;
return(0);
@@ -848,18 +900,18 @@ pre_bf(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
break;
default:
return(0);
}
switch (n->norm->Bf.font) {
- case (FONT_Em):
+ case FONT_Em:
font_push('I');
break;
- case (FONT_Sy):
+ case FONT_Sy:
font_push('B');
break;
default:
@@ -882,9 +934,9 @@ pre_bk(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
outflags |= MMAN_Bk;
return(1);
default:
@@ -916,10 +968,10 @@ pre_bl(DECL_ARGS)
}
switch (n->norm->Bl.type) {
- case (LIST_enum):
+ case LIST_enum:
n->norm->Bl.count = 0;
return(1);
- case (LIST_column):
+ case LIST_column:
break;
default:
return(1);
@@ -938,10 +990,10 @@ post_bl(DECL_ARGS)
{
switch (n->norm->Bl.type) {
- case (LIST_column):
+ case LIST_column:
print_line(".TE", 0);
break;
- case (LIST_enum):
+ case LIST_enum:
n->norm->Bl.count = 0;
break;
default:
@@ -1019,6 +1071,33 @@ pre_em(DECL_ARGS)
return(1);
}
+static int
+pre_en(DECL_ARGS)
+{
+
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child)
+ return(1);
+
+ print_word(n->norm->Es->child->string);
+ outflags &= ~MMAN_spc;
+ return(1);
+}
+
+static void
+post_en(DECL_ARGS)
+{
+
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child ||
+ NULL == n->norm->Es->child->next)
+ return;
+
+ outflags &= ~MMAN_spc;
+ print_word(n->norm->Es->child->next->string);
+ return;
+}
+
static void
post_eo(DECL_ARGS)
{
@@ -1028,6 +1107,13 @@ post_eo(DECL_ARGS)
}
static int
+pre_es(DECL_ARGS)
+{
+
+ return(0);
+}
+
+static int
pre_fa(DECL_ARGS)
{
int am_Fa;
@@ -1136,15 +1222,15 @@ pre_fo(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
pre_syn(n);
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
if (MDOC_SYNPRETTY & n->flags)
print_block(".HP 4n", MMAN_nl);
font_push('B');
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
outflags &= ~MMAN_spc;
print_word("(");
outflags &= ~MMAN_spc;
@@ -1160,10 +1246,10 @@ post_fo(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
font_pop();
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
post_fn(meta, n);
break;
default:
@@ -1219,7 +1305,7 @@ pre_it(DECL_ARGS)
const struct mdoc_node *bln;
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
outflags |= MMAN_PP | MMAN_nl;
bln = n->parent->parent;
if (0 == bln->norm->Bl.comp ||
@@ -1228,24 +1314,24 @@ pre_it(DECL_ARGS)
outflags |= MMAN_sp;
outflags &= ~MMAN_br;
switch (bln->norm->Bl.type) {
- case (LIST_item):
+ case LIST_item:
return(0);
- case (LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case (LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case (LIST_ohang):
+ case LIST_ohang:
if (bln->norm->Bl.type == LIST_diag)
print_line(".B \"", 0);
else
print_line(".R \"", 0);
outflags &= ~MMAN_spc;
return(1);
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
print_width(bln->norm->Bl.width, NULL, 0);
TPremain = 0;
outflags |= MMAN_nl;
@@ -1255,18 +1341,21 @@ pre_it(DECL_ARGS)
else
print_word("-");
font_pop();
- break;
- case (LIST_enum):
+ outflags |= MMAN_nl;
+ return(0);
+ case LIST_enum:
print_width(bln->norm->Bl.width, NULL, 0);
TPremain = 0;
outflags |= MMAN_nl;
print_count(&bln->norm->Bl.count);
- break;
- case (LIST_hang):
+ outflags |= MMAN_nl;
+ return(0);
+ case LIST_hang:
print_width(bln->norm->Bl.width, n->child, 6);
TPremain = 0;
- break;
- case (LIST_tag):
+ outflags |= MMAN_nl;
+ return(1);
+ case LIST_tag:
print_width(bln->norm->Bl.width, n->child, 0);
putchar('\n');
outflags &= ~MMAN_spc;
@@ -1274,7 +1363,6 @@ pre_it(DECL_ARGS)
default:
return(1);
}
- outflags |= MMAN_nl;
default:
break;
}
@@ -1300,7 +1388,8 @@ mid_it(void)
/* Restore the indentation of the enclosing list. */
print_line(".RS", MMAN_Bk_susp);
- snprintf(buf, sizeof(buf), "%zun", Bl_stack[Bl_stack_len - 1]);
+ (void)snprintf(buf, sizeof(buf), "%zun",
+ Bl_stack[Bl_stack_len - 1]);
print_word(buf);
/* Remeber to close out this .RS block later. */
@@ -1315,32 +1404,32 @@ post_it(DECL_ARGS)
bln = n->parent->parent;
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
switch (bln->norm->Bl.type) {
- case (LIST_diag):
+ case LIST_diag:
outflags &= ~MMAN_spc;
print_word("\\ ");
break;
- case (LIST_ohang):
+ case LIST_ohang:
outflags |= MMAN_br;
break;
default:
break;
}
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
switch (bln->norm->Bl.type) {
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case (LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case (LIST_tag):
+ case LIST_tag:
assert(Bl_stack_len);
Bl_stack[--Bl_stack_len] = 0;
@@ -1354,7 +1443,7 @@ post_it(DECL_ARGS)
Bl_stack_post[Bl_stack_len] = 0;
}
break;
- case (LIST_column):
+ case LIST_column:
if (NULL != n->next) {
putchar('\t');
outflags &= ~MMAN_spc;
@@ -1402,6 +1491,14 @@ pre_lk(DECL_ARGS)
}
static int
+pre_ll(DECL_ARGS)
+{
+
+ print_line(".ll", 0);
+ return(1);
+}
+
+static int
pre_li(DECL_ARGS)
{
@@ -1441,13 +1538,14 @@ post_nm(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
outflags &= ~MMAN_Bk;
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
/* FALLTHROUGH */
- case (MDOC_ELEM):
- font_pop();
+ case MDOC_ELEM:
+ if (n->child != NULL || meta->name != NULL)
+ font_pop();
break;
default:
break;
@@ -1500,14 +1598,71 @@ pre_rs(DECL_ARGS)
}
static int
+pre_rv(DECL_ARGS)
+{
+ int nchild;
+
+ outflags |= MMAN_br | MMAN_nl;
+
+ nchild = n->nchild;
+ if (nchild > 0) {
+ print_word("The");
+
+ for (n = n->child; n; n = n->next) {
+ font_push('B');
+ print_word(n->string);
+ font_pop();
+
+ outflags &= ~MMAN_spc;
+ print_word("()");
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ outflags &= ~MMAN_spc;
+ print_word(",");
+ }
+ if (n->next->next == NULL)
+ print_word("and");
+ }
+
+ if (nchild > 1)
+ print_word("functions return");
+ else
+ print_word("function returns");
+
+ print_word("the value\\~0 if successful;");
+ } else
+ print_word("Upon successful completion, "
+ "the value\\~0 is returned;");
+
+ print_word("otherwise the value\\~\\-1 is returned"
+ " and the global variable");
+
+ font_push('I');
+ print_word("errno");
+ font_pop();
+
+ print_word("is set to indicate the error.");
+ outflags |= MMAN_nl;
+ return(0);
+}
+
+static int
pre_sm(DECL_ARGS)
{
- assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string))
- outflags |= MMAN_Sm | MMAN_spc;
+ if (NULL == n->child)
+ outflags ^= MMAN_Sm;
+ else if (0 == strcmp("on", n->child->string))
+ outflags |= MMAN_Sm;
else
outflags &= ~MMAN_Sm;
+
+ if (MMAN_Sm & outflags)
+ outflags |= MMAN_spc;
+
return(0);
}
@@ -1544,10 +1699,10 @@ pre_vt(DECL_ARGS)
if (MDOC_SYNPRETTY & n->flags) {
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
pre_syn(n);
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
break;
default:
return(0);
diff --git a/contrib/mdocml/mdoc_term.c b/contrib/mdocml/mdoc_term.c
index 268fcae..eda3622 100644
--- a/contrib/mdocml/mdoc_term.c
+++ b/contrib/mdocml/mdoc_term.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_term.c,v 1.258 2013/12/25 21:24:12 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.275 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -30,6 +30,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
#include "mdoc.h"
@@ -42,7 +43,7 @@ struct termpair {
#define DECL_ARGS struct termp *p, \
struct termpair *pair, \
- const struct mdoc_meta *meta, \
+ const struct mdoc_meta *meta, \
struct mdoc_node *n
struct termact {
@@ -57,11 +58,11 @@ static size_t a2offs(const struct termp *, const char *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
const struct mdoc_node *);
-static void print_mdoc_node(DECL_ARGS);
+static void print_mdoc_node(DECL_ARGS);
static void print_mdoc_nodelist(DECL_ARGS);
static void print_mdoc_head(struct termp *, const void *);
static void print_mdoc_foot(struct termp *, const void *);
-static void synopsis_pre(struct termp *,
+static void synopsis_pre(struct termp *,
const struct mdoc_node *);
static void termp____post(DECL_ARGS);
@@ -94,6 +95,7 @@ static int termp_bt_pre(DECL_ARGS);
static int termp_bx_pre(DECL_ARGS);
static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
+static int termp_es_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
@@ -104,6 +106,7 @@ static int termp_ft_pre(DECL_ARGS);
static int termp_in_pre(DECL_ARGS);
static int termp_it_pre(DECL_ARGS);
static int termp_li_pre(DECL_ARGS);
+static int termp_ll_pre(DECL_ARGS);
static int termp_lk_pre(DECL_ARGS);
static int termp_nd_pre(DECL_ARGS);
static int termp_nm_pre(DECL_ARGS);
@@ -127,8 +130,8 @@ static const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* Dt */
{ NULL, NULL }, /* Os */
{ termp_sh_pre, termp_sh_post }, /* Sh */
- { termp_ss_pre, termp_ss_post }, /* Ss */
- { termp_sp_pre, NULL }, /* Pp */
+ { termp_ss_pre, termp_ss_post }, /* Ss */
+ { termp_sp_pre, NULL }, /* Pp */
{ termp_d1_pre, termp_bl_post }, /* D1 */
{ termp_d1_pre, termp_bl_post }, /* Dl */
{ termp_bd_pre, termp_bd_post }, /* Bd */
@@ -136,30 +139,30 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_bl_pre, termp_bl_post }, /* Bl */
{ NULL, NULL }, /* El */
{ termp_it_pre, termp_it_post }, /* It */
- { termp_under_pre, NULL }, /* Ad */
+ { termp_under_pre, NULL }, /* Ad */
{ termp_an_pre, termp_an_post }, /* An */
{ termp_under_pre, NULL }, /* Ar */
{ termp_cd_pre, NULL }, /* Cd */
{ termp_bold_pre, NULL }, /* Cm */
- { NULL, NULL }, /* Dv */
- { NULL, NULL }, /* Er */
- { NULL, NULL }, /* Ev */
+ { NULL, NULL }, /* Dv */
+ { NULL, NULL }, /* Er */
+ { NULL, NULL }, /* Ev */
{ termp_ex_pre, NULL }, /* Ex */
- { termp_fa_pre, NULL }, /* Fa */
- { termp_fd_pre, termp_fd_post }, /* Fd */
+ { termp_fa_pre, NULL }, /* Fa */
+ { termp_fd_pre, termp_fd_post }, /* Fd */
{ termp_fl_pre, NULL }, /* Fl */
- { termp_fn_pre, NULL }, /* Fn */
- { termp_ft_pre, NULL }, /* Ft */
- { termp_bold_pre, NULL }, /* Ic */
- { termp_in_pre, termp_in_post }, /* In */
+ { termp_fn_pre, NULL }, /* Fn */
+ { termp_ft_pre, NULL }, /* Ft */
+ { termp_bold_pre, NULL }, /* Ic */
+ { termp_in_pre, termp_in_post }, /* In */
{ termp_li_pre, NULL }, /* Li */
- { termp_nd_pre, NULL }, /* Nd */
- { termp_nm_pre, termp_nm_post }, /* Nm */
+ { termp_nd_pre, NULL }, /* Nd */
+ { termp_nm_pre, termp_nm_post }, /* Nm */
{ termp_quote_pre, termp_quote_post }, /* Op */
- { NULL, NULL }, /* Ot */
+ { termp_ft_pre, NULL }, /* Ot */
{ termp_under_pre, NULL }, /* Pa */
{ termp_rv_pre, NULL }, /* Rv */
- { NULL, NULL }, /* St */
+ { NULL, NULL }, /* St */
{ termp_under_pre, NULL }, /* Va */
{ termp_vt_pre, NULL }, /* Vt */
{ termp_xr_pre, NULL }, /* Xr */
@@ -179,7 +182,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Aq */
{ NULL, NULL }, /* At */
{ NULL, NULL }, /* Bc */
- { termp_bf_pre, NULL }, /* Bf */
+ { termp_bf_pre, NULL }, /* Bf */
{ termp_quote_pre, termp_quote_post }, /* Bo */
{ termp_quote_pre, termp_quote_post }, /* Bq */
{ termp_xx_pre, NULL }, /* Bsx */
@@ -190,7 +193,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Dq */
{ NULL, NULL }, /* Ec */ /* FIXME: no space */
{ NULL, NULL }, /* Ef */
- { termp_under_pre, NULL }, /* Em */
+ { termp_under_pre, NULL }, /* Em */
{ termp_quote_pre, termp_quote_post }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
@@ -218,32 +221,33 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_xx_pre, NULL }, /* Ux */
{ NULL, NULL }, /* Xc */
{ NULL, NULL }, /* Xo */
- { termp_fo_pre, termp_fo_post }, /* Fo */
- { NULL, NULL }, /* Fc */
+ { termp_fo_pre, termp_fo_post }, /* Fo */
+ { NULL, NULL }, /* Fc */
{ termp_quote_pre, termp_quote_post }, /* Oo */
{ NULL, NULL }, /* Oc */
{ termp_bk_pre, termp_bk_post }, /* Bk */
{ NULL, NULL }, /* Ek */
{ termp_bt_pre, NULL }, /* Bt */
{ NULL, NULL }, /* Hf */
- { NULL, NULL }, /* Fr */
+ { termp_under_pre, NULL }, /* Fr */
{ termp_ud_pre, NULL }, /* Ud */
{ NULL, termp_lb_post }, /* Lb */
- { termp_sp_pre, NULL }, /* Lp */
- { termp_lk_pre, NULL }, /* Lk */
- { termp_under_pre, NULL }, /* Mt */
- { termp_quote_pre, termp_quote_post }, /* Brq */
- { termp_quote_pre, termp_quote_post }, /* Bro */
- { NULL, NULL }, /* Brc */
- { NULL, termp____post }, /* %C */
- { NULL, NULL }, /* Es */ /* TODO */
- { NULL, NULL }, /* En */ /* TODO */
- { termp_xx_pre, NULL }, /* Dx */
- { NULL, termp____post }, /* %Q */
+ { termp_sp_pre, NULL }, /* Lp */
+ { termp_lk_pre, NULL }, /* Lk */
+ { termp_under_pre, NULL }, /* Mt */
+ { termp_quote_pre, termp_quote_post }, /* Brq */
+ { termp_quote_pre, termp_quote_post }, /* Bro */
+ { NULL, NULL }, /* Brc */
+ { NULL, termp____post }, /* %C */
+ { termp_es_pre, NULL }, /* Es */
+ { termp_quote_pre, termp_quote_post }, /* En */
+ { termp_xx_pre, NULL }, /* Dx */
+ { NULL, termp____post }, /* %Q */
{ termp_sp_pre, NULL }, /* br */
- { termp_sp_pre, NULL }, /* sp */
- { NULL, termp____post }, /* %U */
- { NULL, NULL }, /* Ta */
+ { termp_sp_pre, NULL }, /* sp */
+ { NULL, termp____post }, /* %U */
+ { NULL, NULL }, /* Ta */
+ { termp_ll_pre, NULL }, /* ll */
};
@@ -271,13 +275,15 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc)
term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
- if (n->child)
+ if (n->child) {
+ if (MDOC_Sh != n->child->tok)
+ term_vspace(p);
print_mdoc_nodelist(p, NULL, meta, n->child);
+ }
term_end(p);
}
-
static void
print_mdoc_nodelist(DECL_ARGS)
{
@@ -287,8 +293,6 @@ print_mdoc_nodelist(DECL_ARGS)
print_mdoc_nodelist(p, pair, meta, n->next);
}
-
-/* ARGSUSED */
static void
print_mdoc_node(DECL_ARGS)
{
@@ -323,7 +327,7 @@ print_mdoc_node(DECL_ARGS)
*/
switch (n->type) {
- case (MDOC_TEXT):
+ case MDOC_TEXT:
if (' ' == *n->string && MDOC_LINE & n->flags)
term_newln(p);
if (MDOC_DELIMC & n->flags)
@@ -332,10 +336,10 @@ print_mdoc_node(DECL_ARGS)
if (MDOC_DELIMO & n->flags)
p->flags |= TERMP_NOSPACE;
break;
- case (MDOC_EQN):
+ case MDOC_EQN:
term_eqn(p, n->eqn);
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
term_tbl(p, n->span);
break;
default:
@@ -352,11 +356,11 @@ print_mdoc_node(DECL_ARGS)
(ENDBODY_NOT == n->end ? n : n->pending)->prev_font);
switch (n->type) {
- case (MDOC_TEXT):
+ case MDOC_TEXT:
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
break;
- case (MDOC_EQN):
+ case MDOC_EQN:
break;
default:
if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags)
@@ -384,11 +388,12 @@ print_mdoc_node(DECL_ARGS)
if (MDOC_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
- p->offset = offset;
- p->rmargin = rmargin;
+ if (MDOC_ll != n->tok) {
+ p->offset = offset;
+ p->rmargin = rmargin;
+ }
}
-
static void
print_mdoc_foot(struct termp *p, const void *arg)
{
@@ -398,7 +403,7 @@ print_mdoc_foot(struct termp *p, const void *arg)
term_fontrepl(p, TERMFONT_NONE);
- /*
+ /*
* Output the footer in new-groff style, that is, three columns
* with the middle being the manual date and flanking columns
* being the operating system:
@@ -409,8 +414,8 @@ print_mdoc_foot(struct termp *p, const void *arg)
term_vspace(p);
p->offset = 0;
- p->rmargin = (p->maxrmargin -
- term_strlen(p, meta->date) + term_len(p, 1)) / 2;
+ p->rmargin = (p->maxrmargin -
+ term_strlen(p, meta->date) + term_len(p, 1)) / 2;
p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
@@ -438,13 +443,12 @@ print_mdoc_foot(struct termp *p, const void *arg)
p->flags = 0;
}
-
static void
print_mdoc_head(struct termp *p, const void *arg)
{
- char buf[BUFSIZ], title[BUFSIZ];
- size_t buflen, titlen;
- const struct mdoc_meta *meta;
+ const struct mdoc_meta *meta;
+ char *volume, *title;
+ size_t vollen, titlen;
meta = (const struct mdoc_meta *)arg;
@@ -465,35 +469,36 @@ print_mdoc_head(struct termp *p, const void *arg)
p->rmargin = p->maxrmargin;
assert(meta->vol);
- strlcpy(buf, meta->vol, BUFSIZ);
- buflen = term_strlen(p, buf);
-
- if (meta->arch) {
- strlcat(buf, " (", BUFSIZ);
- strlcat(buf, meta->arch, BUFSIZ);
- strlcat(buf, ")", BUFSIZ);
- }
+ if (NULL == meta->arch)
+ volume = mandoc_strdup(meta->vol);
+ else
+ mandoc_asprintf(&volume, "%s (%s)",
+ meta->vol, meta->arch);
+ vollen = term_strlen(p, volume);
- snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+ if (NULL == meta->msec)
+ title = mandoc_strdup(meta->title);
+ else
+ mandoc_asprintf(&title, "%s(%s)",
+ meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->offset = 0;
- p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
- (p->maxrmargin -
- term_strlen(p, buf) + term_len(p, 1)) / 2 :
- p->maxrmargin - buflen;
+ p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
+ (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
+ p->maxrmargin - vollen;
term_word(p, title);
term_flushln(p);
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
- p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
+ p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
p->maxrmargin - titlen : p->maxrmargin;
- term_word(p, buf);
+ term_word(p, volume);
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
@@ -509,9 +514,10 @@ print_mdoc_head(struct termp *p, const void *arg)
p->flags &= ~TERMP_NOSPACE;
p->offset = 0;
p->rmargin = p->maxrmargin;
+ free(title);
+ free(volume);
}
-
static size_t
a2height(const struct termp *p, const char *v)
{
@@ -525,7 +531,6 @@ a2height(const struct termp *p, const char *v)
return(term_vspan(p, &su));
}
-
static size_t
a2width(const struct termp *p, const char *v)
{
@@ -538,7 +543,6 @@ a2width(const struct termp *p, const char *v)
return(term_hspan(p, &su));
}
-
static size_t
a2offs(const struct termp *p, const char *v)
{
@@ -558,16 +562,15 @@ a2offs(const struct termp *p, const char *v)
return(term_hspan(p, &su));
}
-
/*
* Determine how much space to print out before block elements of `It'
* (and thus `Bl') and `Bd'. And then go ahead and print that space,
* too.
*/
static void
-print_bvspace(struct termp *p,
- const struct mdoc_node *bl,
- const struct mdoc_node *n)
+print_bvspace(struct termp *p,
+ const struct mdoc_node *bl,
+ const struct mdoc_node *n)
{
const struct mdoc_node *nn;
@@ -613,14 +616,21 @@ print_bvspace(struct termp *p,
}
-/* ARGSUSED */
+static int
+termp_ll_pre(DECL_ARGS)
+{
+
+ term_setwidth(p, n->nchild ? n->child->string : NULL);
+ return(0);
+}
+
static int
termp_it_pre(DECL_ARGS)
{
const struct mdoc_node *bl, *nn;
- char buf[7];
- int i;
- size_t width, offset, ncols, dcol;
+ char buf[24];
+ int i;
+ size_t width, offset, ncols, dcol;
enum mdoc_list type;
if (MDOC_BLOCK == n->type) {
@@ -631,7 +641,7 @@ termp_it_pre(DECL_ARGS)
bl = n->parent->parent->parent;
type = bl->norm->Bl.type;
- /*
+ /*
* First calculate width and offset. This is pretty easy unless
* we're a -column list, in which case all prior columns must
* be accounted for.
@@ -643,7 +653,7 @@ termp_it_pre(DECL_ARGS)
offset = a2offs(p, bl->norm->Bl.offs);
switch (type) {
- case (LIST_column):
+ case LIST_column:
if (MDOC_HEAD == n->type)
break;
@@ -657,21 +667,19 @@ termp_it_pre(DECL_ARGS)
* - For more than 5 columns, add only one column.
*/
ncols = bl->norm->Bl.ncols;
-
- /* LINTED */
- dcol = ncols < 5 ? term_len(p, 4) :
- ncols == 5 ? term_len(p, 3) : term_len(p, 1);
+ dcol = ncols < 5 ? term_len(p, 4) :
+ ncols == 5 ? term_len(p, 3) : term_len(p, 1);
/*
* Calculate the offset by applying all prior MDOC_BODY,
* so we stop at the MDOC_HEAD (NULL == nn->prev).
*/
- for (i = 0, nn = n->prev;
- nn->prev && i < (int)ncols;
- nn = nn->prev, i++)
- offset += dcol + a2width
- (p, bl->norm->Bl.cols[i]);
+ for (i = 0, nn = n->prev;
+ nn->prev && i < (int)ncols;
+ nn = nn->prev, i++)
+ offset += dcol + a2width(p,
+ bl->norm->Bl.cols[i]);
/*
* When exceeding the declared number of columns, leave
@@ -692,7 +700,7 @@ termp_it_pre(DECL_ARGS)
if (NULL == bl->norm->Bl.width)
break;
- /*
+ /*
* Note: buffer the width by 2, which is groff's magic
* number for buffering single arguments. See the above
* handling for column for how this changes.
@@ -702,30 +710,30 @@ termp_it_pre(DECL_ARGS)
break;
}
- /*
+ /*
* List-type can override the width in the case of fixed-head
* values (bullet, dash/hyphen, enum). Tags need a non-zero
* offset.
*/
switch (type) {
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
if (width < term_len(p, 2))
width = term_len(p, 2);
break;
- case (LIST_hang):
+ case LIST_hang:
if (0 == width)
width = term_len(p, 8);
break;
- case (LIST_column):
+ case LIST_column:
/* FALLTHROUGH */
- case (LIST_tag):
+ case LIST_tag:
if (0 == width)
width = term_len(p, 10);
break;
@@ -733,7 +741,7 @@ termp_it_pre(DECL_ARGS)
break;
}
- /*
+ /*
* Whitespace control. Inset bodies need an initial space,
* while diagonal bodies need two.
*/
@@ -741,12 +749,12 @@ termp_it_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
switch (type) {
- case (LIST_diag):
+ case LIST_diag:
if (MDOC_BODY == n->type)
term_word(p, "\\ \\ ");
break;
- case (LIST_inset):
- if (MDOC_BODY == n->type)
+ case LIST_inset:
+ if (MDOC_BODY == n->type && n->parent->head->nchild)
term_word(p, "\\ ");
break;
default:
@@ -756,7 +764,7 @@ termp_it_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
switch (type) {
- case (LIST_diag):
+ case LIST_diag:
if (MDOC_HEAD == n->type)
term_fontpush(p, TERMFONT_BOLD);
break;
@@ -772,7 +780,7 @@ termp_it_pre(DECL_ARGS)
*/
switch (type) {
- case (LIST_enum):
+ case LIST_enum:
/*
* Weird special case.
* Very narrow enum lists actually hang.
@@ -780,17 +788,17 @@ termp_it_pre(DECL_ARGS)
if (width == term_len(p, 2))
p->flags |= TERMP_HANG;
/* FALLTHROUGH */
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case (LIST_hang):
+ case LIST_hang:
if (MDOC_HEAD != n->type)
break;
@@ -800,25 +808,25 @@ termp_it_pre(DECL_ARGS)
* the "overstep" effect in term_flushln() and treat
* this as a `-ohang' list instead.
*/
- if (n->next->child &&
- (MDOC_Bl == n->next->child->tok ||
- MDOC_Bd == n->next->child->tok))
+ if (n->next->child &&
+ (MDOC_Bl == n->next->child->tok ||
+ MDOC_Bd == n->next->child->tok))
break;
- p->flags |= TERMP_NOBREAK | TERMP_HANG;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
p->trailspace = 1;
break;
- case (LIST_tag):
+ case LIST_tag:
if (MDOC_HEAD != n->type)
break;
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
if (NULL == n->next || NULL == n->next->child)
p->flags |= TERMP_DANGLE;
break;
- case (LIST_column):
+ case LIST_column:
if (MDOC_HEAD == n->type)
break;
@@ -831,17 +839,17 @@ termp_it_pre(DECL_ARGS)
}
break;
- case (LIST_diag):
+ case LIST_diag:
if (MDOC_HEAD != n->type)
break;
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 1;
break;
default:
break;
}
- /*
+ /*
* Margin control. Set-head-width lists have their right
* margins shortened. The body for these lists has the offset
* necessarily lengthened. Everybody gets the offset.
@@ -850,36 +858,39 @@ termp_it_pre(DECL_ARGS)
p->offset += offset;
switch (type) {
- case (LIST_hang):
+ case LIST_hang:
/*
* Same stipulation as above, regarding `-hang'. We
* don't want to recalculate rmargin and offsets when
* using `Bd' or `Bl' within `-hang' overstep lists.
*/
if (MDOC_HEAD == n->type && n->next->child &&
- (MDOC_Bl == n->next->child->tok ||
- MDOC_Bd == n->next->child->tok))
+ (MDOC_Bl == n->next->child->tok ||
+ MDOC_Bd == n->next->child->tok))
break;
/* FALLTHROUGH */
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_tag):
+ case LIST_tag:
assert(width);
if (MDOC_HEAD == n->type)
p->rmargin = p->offset + width;
- else
+ else {
p->offset += width;
+ if (p->rmargin < p->offset)
+ p->rmargin = p->offset;
+ }
break;
- case (LIST_column):
+ case LIST_column:
assert(width);
p->rmargin = p->offset + width;
- /*
+ /*
* XXX - this behaviour is not documented: the
* right-most column is filled to the right margin.
*/
@@ -892,53 +903,53 @@ termp_it_pre(DECL_ARGS)
break;
}
- /*
+ /*
* The dash, hyphen, bullet and enum lists all have a special
- * HEAD character (temporarily bold, in some cases).
+ * HEAD character (temporarily bold, in some cases).
*/
if (MDOC_HEAD == n->type)
switch (type) {
- case (LIST_bullet):
+ case LIST_bullet:
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\[bu]");
term_fontpop(p);
break;
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\(hy");
term_fontpop(p);
break;
- case (LIST_enum):
+ case LIST_enum:
(pair->ppair->ppair->count)++;
- snprintf(buf, sizeof(buf), "%d.",
- pair->ppair->ppair->count);
+ (void)snprintf(buf, sizeof(buf), "%d.",
+ pair->ppair->ppair->count);
term_word(p, buf);
break;
default:
break;
}
- /*
+ /*
* If we're not going to process our children, indicate so here.
*/
switch (type) {
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_item):
+ case LIST_item:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
if (MDOC_HEAD == n->type)
return(0);
break;
- case (LIST_column):
+ case LIST_column:
if (MDOC_HEAD == n->type)
return(0);
break;
@@ -949,8 +960,6 @@ termp_it_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_it_post(DECL_ARGS)
{
@@ -962,15 +971,15 @@ termp_it_post(DECL_ARGS)
type = n->parent->parent->parent->norm->Bl.type;
switch (type) {
- case (LIST_item):
+ case LIST_item:
/* FALLTHROUGH */
- case (LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case (LIST_inset):
+ case LIST_inset:
if (MDOC_BODY == n->type)
term_newln(p);
break;
- case (LIST_column):
+ case LIST_column:
if (MDOC_BODY == n->type)
term_flushln(p);
break;
@@ -979,20 +988,17 @@ termp_it_post(DECL_ARGS)
break;
}
- /*
+ /*
* Now that our output is flushed, we can reset our tags. Since
* only `It' sets these flags, we're free to assume that nobody
* has munged them in the meanwhile.
*/
- p->flags &= ~TERMP_DANGLE;
- p->flags &= ~TERMP_NOBREAK;
- p->flags &= ~TERMP_HANG;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
+ TERMP_DANGLE | TERMP_HANG);
p->trailspace = 0;
}
-
-/* ARGSUSED */
static int
termp_nm_pre(DECL_ARGS)
{
@@ -1012,6 +1018,8 @@ termp_nm_pre(DECL_ARGS)
MDOC_TEXT == n->prev->child->type ?
term_strlen(p, n->prev->child->string) :
term_len(p, 5));
+ if (p->rmargin < p->offset)
+ p->rmargin = p->offset;
return(1);
}
@@ -1022,7 +1030,7 @@ termp_nm_pre(DECL_ARGS)
synopsis_pre(p, n->parent);
if (MDOC_HEAD == n->type && n->next->child) {
- p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 1;
p->rmargin = p->offset + term_len(p, 1);
if (NULL == n->child) {
@@ -1043,8 +1051,6 @@ termp_nm_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_nm_post(DECL_ARGS)
{
@@ -1053,14 +1059,12 @@ termp_nm_post(DECL_ARGS)
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
} else if (MDOC_HEAD == n->type && n->next->child) {
term_flushln(p);
- p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->trailspace = 0;
} else if (MDOC_BODY == n->type && n->child)
term_flushln(p);
}
-
-/* ARGSUSED */
static int
termp_fl_pre(DECL_ARGS)
{
@@ -1076,8 +1080,6 @@ termp_fl_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp__a_pre(DECL_ARGS)
{
@@ -1089,8 +1091,6 @@ termp__a_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_an_pre(DECL_ARGS)
{
@@ -1106,7 +1106,7 @@ termp_an_pre(DECL_ARGS)
* with other macros/text, are split. -split, in this case,
* will override the condition of the implied first -nosplit.
*/
-
+
if (n->sec == SEC_AUTHORS) {
if ( ! (TERMP_ANPREC & p->flags)) {
if (TERMP_SPLIT & p->flags)
@@ -1125,8 +1125,6 @@ termp_an_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_an_post(DECL_ARGS)
{
@@ -1147,8 +1145,6 @@ termp_an_post(DECL_ARGS)
}
-
-/* ARGSUSED */
static int
termp_ns_pre(DECL_ARGS)
{
@@ -1158,8 +1154,6 @@ termp_ns_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_rs_pre(DECL_ARGS)
{
@@ -1171,54 +1165,59 @@ termp_rs_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_rv_pre(DECL_ARGS)
{
int nchild;
term_newln(p);
- term_word(p, "The");
nchild = n->nchild;
- for (n = n->child; n; n = n->next) {
- term_fontpush(p, TERMFONT_BOLD);
- term_word(p, n->string);
- term_fontpop(p);
+ if (nchild > 0) {
+ term_word(p, "The");
- p->flags |= TERMP_NOSPACE;
- term_word(p, "()");
+ for (n = n->child; n; n = n->next) {
+ term_fontpush(p, TERMFONT_BOLD);
+ term_word(p, n->string);
+ term_fontpop(p);
- if (nchild > 2 && n->next) {
p->flags |= TERMP_NOSPACE;
- term_word(p, ",");
+ term_word(p, "()");
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, ",");
+ }
+ if (n->next->next == NULL)
+ term_word(p, "and");
}
- if (n->next && NULL == n->next->next)
- term_word(p, "and");
- }
+ if (nchild > 1)
+ term_word(p, "functions return");
+ else
+ term_word(p, "function returns");
- if (nchild > 1)
- term_word(p, "functions return");
- else
- term_word(p, "function returns");
+ term_word(p, "the value\\~0 if successful;");
+ } else
+ term_word(p, "Upon successful completion,"
+ " the value\\~0 is returned;");
- term_word(p, "the value 0 if successful; otherwise the value "
- "-1 is returned and the global variable");
+ term_word(p, "otherwise the value\\~\\-1 is returned"
+ " and the global variable");
term_fontpush(p, TERMFONT_UNDER);
term_word(p, "errno");
term_fontpop(p);
- term_word(p, "is set to indicate the error.");
+ term_word(p, "is set to indicate the error.");
p->flags |= TERMP_SENTENCE;
return(0);
}
-
-/* ARGSUSED */
static int
termp_ex_pre(DECL_ARGS)
{
@@ -1243,18 +1242,16 @@ termp_ex_pre(DECL_ARGS)
}
if (nchild > 1)
- term_word(p, "utilities exit");
+ term_word(p, "utilities exit\\~0");
else
- term_word(p, "utility exits");
+ term_word(p, "utility exits\\~0");
- term_word(p, "0 on success, and >0 if an error occurs.");
+ term_word(p, "on success, and\\~>0 if an error occurs.");
p->flags |= TERMP_SENTENCE;
return(0);
}
-
-/* ARGSUSED */
static int
termp_nd_pre(DECL_ARGS)
{
@@ -1270,8 +1267,6 @@ termp_nd_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_bl_pre(DECL_ARGS)
{
@@ -1279,8 +1274,6 @@ termp_bl_pre(DECL_ARGS)
return(MDOC_HEAD != n->type);
}
-
-/* ARGSUSED */
static void
termp_bl_post(DECL_ARGS)
{
@@ -1289,7 +1282,6 @@ termp_bl_post(DECL_ARGS)
term_newln(p);
}
-/* ARGSUSED */
static int
termp_xr_pre(DECL_ARGS)
{
@@ -1300,7 +1292,7 @@ termp_xr_pre(DECL_ARGS)
assert(MDOC_TEXT == n->type);
term_word(p, n->string);
- if (NULL == (n = n->next))
+ if (NULL == (n = n->next))
return(0);
p->flags |= TERMP_NOSPACE;
@@ -1324,7 +1316,7 @@ termp_xr_pre(DECL_ARGS)
static void
synopsis_pre(struct termp *p, const struct mdoc_node *n)
{
- /*
+ /*
* Obviously, if we're not in a SYNOPSIS or no prior macros
* exist, do nothing.
*/
@@ -1336,10 +1328,10 @@ synopsis_pre(struct termp *p, const struct mdoc_node *n)
* newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
* case we soldier on.
*/
- if (n->prev->tok == n->tok &&
- MDOC_Ft != n->tok &&
- MDOC_Fo != n->tok &&
- MDOC_Fn != n->tok) {
+ if (n->prev->tok == n->tok &&
+ MDOC_Ft != n->tok &&
+ MDOC_Fo != n->tok &&
+ MDOC_Fn != n->tok) {
term_newln(p);
return;
}
@@ -1350,18 +1342,18 @@ synopsis_pre(struct termp *p, const struct mdoc_node *n)
* vertical space, else only newline and move on.
*/
switch (n->prev->tok) {
- case (MDOC_Fd):
+ case MDOC_Fd:
/* FALLTHROUGH */
- case (MDOC_Fn):
+ case MDOC_Fn:
/* FALLTHROUGH */
- case (MDOC_Fo):
+ case MDOC_Fo:
/* FALLTHROUGH */
- case (MDOC_In):
+ case MDOC_In:
/* FALLTHROUGH */
- case (MDOC_Vt):
+ case MDOC_Vt:
term_vspace(p);
break;
- case (MDOC_Ft):
+ case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
term_vspace(p);
break;
@@ -1373,7 +1365,6 @@ synopsis_pre(struct termp *p, const struct mdoc_node *n)
}
}
-
static int
termp_vt_pre(DECL_ARGS)
{
@@ -1390,8 +1381,6 @@ termp_vt_pre(DECL_ARGS)
return(termp_under_pre(p, pair, meta, n));
}
-
-/* ARGSUSED */
static int
termp_bold_pre(DECL_ARGS)
{
@@ -1400,8 +1389,6 @@ termp_bold_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_fd_pre(DECL_ARGS)
{
@@ -1410,8 +1397,6 @@ termp_fd_pre(DECL_ARGS)
return(termp_bold_pre(p, pair, meta, n));
}
-
-/* ARGSUSED */
static void
termp_fd_post(DECL_ARGS)
{
@@ -1419,8 +1404,6 @@ termp_fd_post(DECL_ARGS)
term_newln(p);
}
-
-/* ARGSUSED */
static int
termp_sh_pre(DECL_ARGS)
{
@@ -1428,16 +1411,16 @@ termp_sh_pre(DECL_ARGS)
/* No vspace between consecutive `Sh' calls. */
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
if (n->prev && MDOC_Sh == n->prev->tok)
if (NULL == n->prev->body->child)
break;
term_vspace(p);
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
term_fontpush(p, TERMFONT_BOLD);
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
p->offset = term_len(p, p->defindent);
if (SEC_AUTHORS == n->sec)
p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
@@ -1448,17 +1431,15 @@ termp_sh_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_sh_post(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
term_newln(p);
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
term_newln(p);
p->offset = 0;
break;
@@ -1467,8 +1448,6 @@ termp_sh_post(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
termp_bt_pre(DECL_ARGS)
{
@@ -1478,8 +1457,6 @@ termp_bt_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_lb_post(DECL_ARGS)
{
@@ -1488,8 +1465,6 @@ termp_lb_post(DECL_ARGS)
term_newln(p);
}
-
-/* ARGSUSED */
static int
termp_ud_pre(DECL_ARGS)
{
@@ -1499,8 +1474,6 @@ termp_ud_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_d1_pre(DECL_ARGS)
{
@@ -1512,8 +1485,6 @@ termp_d1_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_ft_pre(DECL_ARGS)
{
@@ -1524,8 +1495,6 @@ termp_ft_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_fn_pre(DECL_ARGS)
{
@@ -1542,7 +1511,7 @@ termp_fn_pre(DECL_ARGS)
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
- p->flags |= TERMP_NOBREAK | TERMP_HANG;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
}
assert(MDOC_TEXT == n->type);
@@ -1552,7 +1521,7 @@ termp_fn_pre(DECL_ARGS)
if (pretty) {
term_flushln(p);
- p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
}
@@ -1587,8 +1556,6 @@ termp_fn_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_fa_pre(DECL_ARGS)
{
@@ -1614,12 +1581,10 @@ termp_fa_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_bd_pre(DECL_ARGS)
{
- size_t tabwidth, rm, rmax;
+ size_t tabwidth, lm, len, rm, rmax;
struct mdoc_node *nn;
if (MDOC_BLOCK == n->type) {
@@ -1638,20 +1603,31 @@ termp_bd_pre(DECL_ARGS)
* for macro lines, a newline is appended to the line. Blank
* lines are allowed.
*/
-
- if (DISP_literal != n->norm->Bd.type &&
- DISP_unfilled != n->norm->Bd.type)
+
+ if (DISP_literal != n->norm->Bd.type &&
+ DISP_unfilled != n->norm->Bd.type &&
+ DISP_centered != n->norm->Bd.type)
return(1);
tabwidth = p->tabwidth;
if (DISP_literal == n->norm->Bd.type)
p->tabwidth = term_len(p, 8);
+ lm = p->offset;
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
for (nn = n->child; nn; nn = nn->next) {
+ if (DISP_centered == n->norm->Bd.type) {
+ if (MDOC_TEXT == nn->type) {
+ len = term_strlen(p, nn->string);
+ p->offset = len >= rm ? 0 :
+ lm + len >= rm ? rm - len :
+ (lm + rm - len) / 2;
+ } else
+ p->offset = lm;
+ }
print_mdoc_node(p, pair, meta, nn);
/*
* If the printed node flushes its own line, then we
@@ -1660,21 +1636,21 @@ termp_bd_pre(DECL_ARGS)
* anyway, so don't sweat it.
*/
switch (nn->tok) {
- case (MDOC_Sm):
+ case MDOC_Sm:
/* FALLTHROUGH */
- case (MDOC_br):
+ case MDOC_br:
/* FALLTHROUGH */
- case (MDOC_sp):
+ case MDOC_sp:
/* FALLTHROUGH */
- case (MDOC_Bl):
+ case MDOC_Bl:
/* FALLTHROUGH */
- case (MDOC_D1):
+ case MDOC_D1:
/* FALLTHROUGH */
- case (MDOC_Dl):
+ case MDOC_Dl:
/* FALLTHROUGH */
- case (MDOC_Lp):
+ case MDOC_Lp:
/* FALLTHROUGH */
- case (MDOC_Pp):
+ case MDOC_Pp:
continue;
default:
break;
@@ -1691,21 +1667,19 @@ termp_bd_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_bd_post(DECL_ARGS)
{
size_t rm, rmax;
- if (MDOC_BODY != n->type)
+ if (MDOC_BODY != n->type)
return;
rm = p->rmargin;
rmax = p->maxrmargin;
- if (DISP_literal == n->norm->Bd.type ||
- DISP_unfilled == n->norm->Bd.type)
+ if (DISP_literal == n->norm->Bd.type ||
+ DISP_unfilled == n->norm->Bd.type)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
@@ -1715,8 +1689,6 @@ termp_bd_post(DECL_ARGS)
p->maxrmargin = rmax;
}
-
-/* ARGSUSED */
static int
termp_bx_pre(DECL_ARGS)
{
@@ -1740,8 +1712,6 @@ termp_bx_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_xx_pre(DECL_ARGS)
{
@@ -1750,22 +1720,22 @@ termp_xx_pre(DECL_ARGS)
pp = NULL;
switch (n->tok) {
- case (MDOC_Bsx):
+ case MDOC_Bsx:
pp = "BSD/OS";
break;
- case (MDOC_Dx):
+ case MDOC_Dx:
pp = "DragonFly";
break;
- case (MDOC_Fx):
+ case MDOC_Fx:
pp = "FreeBSD";
break;
- case (MDOC_Nx):
+ case MDOC_Nx:
pp = "NetBSD";
break;
- case (MDOC_Ox):
+ case MDOC_Ox:
pp = "OpenBSD";
break;
- case (MDOC_Ux):
+ case MDOC_Ux:
pp = "UNIX";
break;
default:
@@ -1783,8 +1753,6 @@ termp_xx_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_pf_post(DECL_ARGS)
{
@@ -1792,22 +1760,23 @@ termp_pf_post(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
}
-
-/* ARGSUSED */
static int
termp_ss_pre(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
term_newln(p);
if (n->prev)
term_vspace(p);
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
term_fontpush(p, TERMFONT_BOLD);
p->offset = term_len(p, (p->defindent+1)/2);
break;
+ case MDOC_BODY:
+ p->offset = term_len(p, p->defindent);
+ break;
default:
break;
}
@@ -1815,18 +1784,14 @@ termp_ss_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_ss_post(DECL_ARGS)
{
- if (MDOC_HEAD == n->type)
+ if (n->type == MDOC_HEAD || n->type == MDOC_BODY)
term_newln(p);
}
-
-/* ARGSUSED */
static int
termp_cd_pre(DECL_ARGS)
{
@@ -1836,8 +1801,6 @@ termp_cd_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_in_pre(DECL_ARGS)
{
@@ -1857,8 +1820,6 @@ termp_in_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_in_post(DECL_ARGS)
{
@@ -1873,18 +1834,16 @@ termp_in_post(DECL_ARGS)
term_fontpop(p);
}
-
-/* ARGSUSED */
static int
termp_sp_pre(DECL_ARGS)
{
size_t i, len;
switch (n->tok) {
- case (MDOC_sp):
+ case MDOC_sp:
len = n->child ? a2height(p, n->child->string) : 1;
break;
- case (MDOC_br):
+ case MDOC_br:
len = 0;
break;
default:
@@ -1900,8 +1859,13 @@ termp_sp_pre(DECL_ARGS)
return(0);
}
+static int
+termp_es_pre(DECL_ARGS)
+{
+
+ return(0);
+}
-/* ARGSUSED */
static int
termp_quote_pre(DECL_ARGS)
{
@@ -1910,49 +1874,55 @@ termp_quote_pre(DECL_ARGS)
return(1);
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
+ case MDOC_Aq:
term_word(p, "<");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
term_word(p, "{");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
/* FALLTHROUGH */
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
term_word(p, "[");
break;
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
+ case MDOC_Dq:
term_word(p, "\\(lq");
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child)
+ return(1);
+ term_word(p, n->norm->Es->child->string);
+ break;
+ case MDOC_Eo:
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
term_word(p, "(");
break;
- case (MDOC__T):
+ case MDOC__T:
/* FALLTHROUGH */
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
term_word(p, "\"");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
/* FALLTHROUGH */
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
term_word(p, "\\(oq");
break;
default:
@@ -1964,8 +1934,6 @@ termp_quote_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_quote_post(DECL_ARGS)
{
@@ -1973,52 +1941,61 @@ termp_quote_post(DECL_ARGS)
if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
return;
- p->flags |= TERMP_NOSPACE;
+ if (MDOC_En != n->tok)
+ p->flags |= TERMP_NOSPACE;
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
+ case MDOC_Aq:
term_word(p, ">");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
term_word(p, "}");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
/* FALLTHROUGH */
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
term_word(p, "]");
break;
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
+ case MDOC_Dq:
term_word(p, "\\(rq");
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (NULL != n->norm->Es &&
+ NULL != n->norm->Es->child &&
+ NULL != n->norm->Es->child->next) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, n->norm->Es->child->next->string);
+ }
+ break;
+ case MDOC_Eo:
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
term_word(p, ")");
break;
- case (MDOC__T):
+ case MDOC__T:
/* FALLTHROUGH */
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
term_word(p, "\"");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
/* FALLTHROUGH */
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
term_word(p, "\\(cq");
break;
default:
@@ -2027,8 +2004,6 @@ termp_quote_post(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
termp_fo_pre(DECL_ARGS)
{
@@ -2044,14 +2019,16 @@ termp_fo_pre(DECL_ARGS)
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
- p->flags |= TERMP_NOBREAK | TERMP_HANG;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND |
+ TERMP_HANG;
}
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
if (pretty) {
term_flushln(p);
- p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
+ TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
}
@@ -2069,13 +2046,11 @@ termp_fo_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_fo_post(DECL_ARGS)
{
- if (MDOC_BODY != n->type)
+ if (MDOC_BODY != n->type)
return;
p->flags |= TERMP_NOSPACE;
@@ -2088,8 +2063,6 @@ termp_fo_post(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
termp_bf_pre(DECL_ARGS)
{
@@ -2099,35 +2072,33 @@ termp_bf_pre(DECL_ARGS)
else if (MDOC_BODY != n->type)
return(1);
- if (FONT_Em == n->norm->Bf.font)
+ if (FONT_Em == n->norm->Bf.font)
term_fontpush(p, TERMFONT_UNDER);
- else if (FONT_Sy == n->norm->Bf.font)
+ else if (FONT_Sy == n->norm->Bf.font)
term_fontpush(p, TERMFONT_BOLD);
- else
+ else
term_fontpush(p, TERMFONT_NONE);
return(1);
}
-
-/* ARGSUSED */
static int
termp_sm_pre(DECL_ARGS)
{
- assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string)) {
- if (p->col)
- p->flags &= ~TERMP_NOSPACE;
+ if (NULL == n->child)
+ p->flags ^= TERMP_NONOSPACE;
+ else if (0 == strcmp("on", n->child->string))
p->flags &= ~TERMP_NONOSPACE;
- } else
+ else
p->flags |= TERMP_NONOSPACE;
+ if (p->col && ! (TERMP_NONOSPACE & p->flags))
+ p->flags &= ~TERMP_NOSPACE;
+
return(0);
}
-
-/* ARGSUSED */
static int
termp_ap_pre(DECL_ARGS)
{
@@ -2138,8 +2109,6 @@ termp_ap_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp____post(DECL_ARGS)
{
@@ -2167,8 +2136,6 @@ termp____post(DECL_ARGS)
term_word(p, ",");
}
-
-/* ARGSUSED */
static int
termp_li_pre(DECL_ARGS)
{
@@ -2177,8 +2144,6 @@ termp_li_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_lk_pre(DECL_ARGS)
{
@@ -2205,18 +2170,16 @@ termp_lk_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_bk_pre(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
return(0);
- case (MDOC_BODY):
+ case MDOC_BODY:
if (n->parent->args || 0 == n->prev->nchild)
p->flags |= TERMP_PREKEEP;
break;
@@ -2228,8 +2191,6 @@ termp_bk_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_bk_post(DECL_ARGS)
{
@@ -2238,7 +2199,6 @@ termp_bk_post(DECL_ARGS)
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
}
-/* ARGSUSED */
static void
termp__t_post(DECL_ARGS)
{
@@ -2248,13 +2208,12 @@ termp__t_post(DECL_ARGS)
* us instead of underlining us (for disambiguation).
*/
if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T)
+ n->parent->norm->Rs.quote_T)
termp_quote_post(p, pair, meta, n);
termp____post(p, pair, meta, n);
}
-/* ARGSUSED */
static int
termp__t_pre(DECL_ARGS)
{
@@ -2264,14 +2223,13 @@ termp__t_pre(DECL_ARGS)
* us instead of underlining us (for disambiguation).
*/
if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T)
+ n->parent->norm->Rs.quote_T)
return(termp_quote_pre(p, pair, meta, n));
term_fontpush(p, TERMFONT_UNDER);
return(1);
}
-/* ARGSUSED */
static int
termp_under_pre(DECL_ARGS)
{
diff --git a/contrib/mdocml/mdoc_validate.c b/contrib/mdocml/mdoc_validate.c
index 588c070..78b64cf 100644
--- a/contrib/mdocml/mdoc_validate.c
+++ b/contrib/mdocml/mdoc_validate.c
@@ -1,7 +1,8 @@
-/* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.243 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -35,6 +36,7 @@
#include "mdoc.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmdoc.h"
#include "libmandoc.h"
@@ -43,9 +45,6 @@
#define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
#define POST_ARGS struct mdoc *mdoc
-#define NUMSIZ 32
-#define DATESIZE 32
-
enum check_ineq {
CHECK_LT,
CHECK_GT,
@@ -61,18 +60,16 @@ typedef int (*v_pre)(PRE_ARGS);
typedef int (*v_post)(POST_ARGS);
struct valids {
- v_pre *pre;
- v_post *post;
+ v_pre pre;
+ v_post post;
};
-static int check_count(struct mdoc *, enum mdoc_type,
+static int check_count(struct mdoc *, enum mdoc_type,
enum check_lvl, enum check_ineq, int);
-static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
static void check_text(struct mdoc *, int, int, char *);
-static void check_argv(struct mdoc *,
+static void check_argv(struct mdoc *,
struct mdoc_node *, struct mdoc_argv *);
static void check_args(struct mdoc *, struct mdoc_node *);
-static int concat(char *, const struct mdoc_node *, size_t);
static enum mdoc_sec a2sec(const char *);
static size_t macro2len(enum mdoct);
@@ -86,38 +83,43 @@ static int ewarn_le1(POST_ARGS);
static int hwarn_eq0(POST_ARGS);
static int hwarn_eq1(POST_ARGS);
static int hwarn_ge1(POST_ARGS);
-static int hwarn_le1(POST_ARGS);
static int post_an(POST_ARGS);
static int post_at(POST_ARGS);
static int post_bf(POST_ARGS);
+static int post_bk(POST_ARGS);
static int post_bl(POST_ARGS);
static int post_bl_block(POST_ARGS);
static int post_bl_block_width(POST_ARGS);
static int post_bl_block_tag(POST_ARGS);
static int post_bl_head(POST_ARGS);
static int post_bx(POST_ARGS);
+static int post_d1(POST_ARGS);
static int post_defaults(POST_ARGS);
static int post_dd(POST_ARGS);
static int post_dt(POST_ARGS);
+static int post_en(POST_ARGS);
+static int post_es(POST_ARGS);
static int post_eoln(POST_ARGS);
+static int post_ex(POST_ARGS);
+static int post_fo(POST_ARGS);
static int post_hyph(POST_ARGS);
+static int post_hyphtext(POST_ARGS);
static int post_ignpar(POST_ARGS);
static int post_it(POST_ARGS);
static int post_lb(POST_ARGS);
static int post_literal(POST_ARGS);
+static int post_nd(POST_ARGS);
static int post_nm(POST_ARGS);
static int post_ns(POST_ARGS);
static int post_os(POST_ARGS);
static int post_par(POST_ARGS);
-static int post_prol(POST_ARGS);
static int post_root(POST_ARGS);
static int post_rs(POST_ARGS);
static int post_sh(POST_ARGS);
static int post_sh_body(POST_ARGS);
static int post_sh_head(POST_ARGS);
static int post_st(POST_ARGS);
-static int post_std(POST_ARGS);
static int post_vt(POST_ARGS);
static int pre_an(PRE_ARGS);
static int pre_bd(PRE_ARGS);
@@ -125,141 +127,91 @@ static int pre_bl(PRE_ARGS);
static int pre_dd(PRE_ARGS);
static int pre_display(PRE_ARGS);
static int pre_dt(PRE_ARGS);
-static int pre_it(PRE_ARGS);
static int pre_literal(PRE_ARGS);
+static int pre_obsolete(PRE_ARGS);
static int pre_os(PRE_ARGS);
static int pre_par(PRE_ARGS);
-static int pre_sh(PRE_ARGS);
-static int pre_ss(PRE_ARGS);
static int pre_std(PRE_ARGS);
-static v_post posts_an[] = { post_an, NULL };
-static v_post posts_at[] = { post_at, post_defaults, NULL };
-static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
-static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
-static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
-static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
-static v_post posts_bx[] = { post_bx, NULL };
-static v_post posts_bool[] = { ebool, NULL };
-static v_post posts_eoln[] = { post_eoln, NULL };
-static v_post posts_defaults[] = { post_defaults, NULL };
-static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
-static v_post posts_dd[] = { post_dd, post_prol, NULL };
-static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
-static v_post posts_dt[] = { post_dt, post_prol, NULL };
-static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
-static v_post posts_hyph[] = { post_hyph, NULL };
-static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
-static v_post posts_it[] = { post_it, NULL };
-static v_post posts_lb[] = { post_lb, NULL };
-static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
-static v_post posts_nm[] = { post_nm, NULL };
-static v_post posts_notext[] = { ewarn_eq0, NULL };
-static v_post posts_ns[] = { post_ns, NULL };
-static v_post posts_os[] = { post_os, post_prol, NULL };
-static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
-static v_post posts_rs[] = { post_rs, NULL };
-static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
-static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
-static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
-static v_post posts_st[] = { post_st, NULL };
-static v_post posts_std[] = { post_std, NULL };
-static v_post posts_text[] = { ewarn_ge1, NULL };
-static v_post posts_text1[] = { ewarn_eq1, NULL };
-static v_post posts_vt[] = { post_vt, NULL };
-static v_pre pres_an[] = { pre_an, NULL };
-static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
-static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
-static v_pre pres_d1[] = { pre_display, NULL };
-static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
-static v_pre pres_dd[] = { pre_dd, NULL };
-static v_pre pres_dt[] = { pre_dt, NULL };
-static v_pre pres_it[] = { pre_it, pre_par, NULL };
-static v_pre pres_os[] = { pre_os, NULL };
-static v_pre pres_pp[] = { pre_par, NULL };
-static v_pre pres_sh[] = { pre_sh, NULL };
-static v_pre pres_ss[] = { pre_ss, NULL };
-static v_pre pres_std[] = { pre_std, NULL };
-
static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Ap */
- { pres_dd, posts_dd }, /* Dd */
- { pres_dt, posts_dt }, /* Dt */
- { pres_os, posts_os }, /* Os */
- { pres_sh, posts_sh }, /* Sh */
- { pres_ss, posts_ss }, /* Ss */
- { pres_pp, posts_pp }, /* Pp */
- { pres_d1, posts_d1 }, /* D1 */
- { pres_dl, posts_dl }, /* Dl */
- { pres_bd, posts_bd }, /* Bd */
+ { pre_dd, post_dd }, /* Dd */
+ { pre_dt, post_dt }, /* Dt */
+ { pre_os, post_os }, /* Os */
+ { NULL, post_sh }, /* Sh */
+ { NULL, post_ignpar }, /* Ss */
+ { pre_par, post_par }, /* Pp */
+ { pre_display, post_d1 }, /* D1 */
+ { pre_literal, post_literal }, /* Dl */
+ { pre_bd, post_literal }, /* Bd */
{ NULL, NULL }, /* Ed */
- { pres_bl, posts_bl }, /* Bl */
+ { pre_bl, post_bl }, /* Bl */
{ NULL, NULL }, /* El */
- { pres_it, posts_it }, /* It */
- { NULL, NULL }, /* Ad */
- { pres_an, posts_an }, /* An */
- { NULL, posts_defaults }, /* Ar */
- { NULL, NULL }, /* Cd */
+ { pre_par, post_it }, /* It */
+ { NULL, NULL }, /* Ad */
+ { pre_an, post_an }, /* An */
+ { NULL, post_defaults }, /* Ar */
+ { NULL, NULL }, /* Cd */
{ NULL, NULL }, /* Cm */
- { NULL, NULL }, /* Dv */
- { NULL, NULL }, /* Er */
- { NULL, NULL }, /* Ev */
- { pres_std, posts_std }, /* Ex */
- { NULL, NULL }, /* Fa */
- { NULL, posts_text }, /* Fd */
+ { NULL, NULL }, /* Dv */
+ { NULL, NULL }, /* Er */
+ { NULL, NULL }, /* Ev */
+ { pre_std, post_ex }, /* Ex */
+ { NULL, NULL }, /* Fa */
+ { NULL, ewarn_ge1 }, /* Fd */
{ NULL, NULL }, /* Fl */
- { NULL, NULL }, /* Fn */
- { NULL, NULL }, /* Ft */
- { NULL, NULL }, /* Ic */
- { NULL, posts_text1 }, /* In */
- { NULL, posts_defaults }, /* Li */
- { NULL, posts_nd }, /* Nd */
- { NULL, posts_nm }, /* Nm */
+ { NULL, NULL }, /* Fn */
+ { NULL, NULL }, /* Ft */
+ { NULL, NULL }, /* Ic */
+ { NULL, ewarn_eq1 }, /* In */
+ { NULL, post_defaults }, /* Li */
+ { NULL, post_nd }, /* Nd */
+ { NULL, post_nm }, /* Nm */
{ NULL, NULL }, /* Op */
- { NULL, NULL }, /* Ot */
- { NULL, posts_defaults }, /* Pa */
- { pres_std, posts_std }, /* Rv */
- { NULL, posts_st }, /* St */
+ { pre_obsolete, NULL }, /* Ot */
+ { NULL, post_defaults }, /* Pa */
+ { pre_std, NULL }, /* Rv */
+ { NULL, post_st }, /* St */
{ NULL, NULL }, /* Va */
- { NULL, posts_vt }, /* Vt */
- { NULL, posts_text }, /* Xr */
- { NULL, posts_text }, /* %A */
- { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
- { NULL, posts_text }, /* %D */
- { NULL, posts_text }, /* %I */
- { NULL, posts_text }, /* %J */
- { NULL, posts_hyphtext }, /* %N */
- { NULL, posts_hyphtext }, /* %O */
- { NULL, posts_text }, /* %P */
- { NULL, posts_hyphtext }, /* %R */
- { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
- { NULL, posts_text }, /* %V */
+ { NULL, post_vt }, /* Vt */
+ { NULL, ewarn_ge1 }, /* Xr */
+ { NULL, ewarn_ge1 }, /* %A */
+ { NULL, post_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
+ { NULL, ewarn_ge1 }, /* %D */
+ { NULL, ewarn_ge1 }, /* %I */
+ { NULL, ewarn_ge1 }, /* %J */
+ { NULL, post_hyphtext }, /* %N */
+ { NULL, post_hyphtext }, /* %O */
+ { NULL, ewarn_ge1 }, /* %P */
+ { NULL, post_hyphtext }, /* %R */
+ { NULL, post_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
+ { NULL, ewarn_ge1 }, /* %V */
{ NULL, NULL }, /* Ac */
{ NULL, NULL }, /* Ao */
{ NULL, NULL }, /* Aq */
- { NULL, posts_at }, /* At */
+ { NULL, post_at }, /* At */
{ NULL, NULL }, /* Bc */
- { NULL, posts_bf }, /* Bf */
+ { NULL, post_bf }, /* Bf */
{ NULL, NULL }, /* Bo */
{ NULL, NULL }, /* Bq */
{ NULL, NULL }, /* Bsx */
- { NULL, posts_bx }, /* Bx */
- { NULL, posts_bool }, /* Db */
+ { NULL, post_bx }, /* Bx */
+ { NULL, ebool }, /* Db */
{ NULL, NULL }, /* Dc */
{ NULL, NULL }, /* Do */
{ NULL, NULL }, /* Dq */
{ NULL, NULL }, /* Ec */
- { NULL, NULL }, /* Ef */
- { NULL, NULL }, /* Em */
+ { NULL, NULL }, /* Ef */
+ { NULL, NULL }, /* Em */
{ NULL, NULL }, /* Eo */
{ NULL, NULL }, /* Fx */
- { NULL, NULL }, /* Ms */
- { NULL, posts_notext }, /* No */
- { NULL, posts_ns }, /* Ns */
+ { NULL, NULL }, /* Ms */
+ { NULL, ewarn_eq0 }, /* No */
+ { NULL, post_ns }, /* Ns */
{ NULL, NULL }, /* Nx */
{ NULL, NULL }, /* Ox */
{ NULL, NULL }, /* Pc */
- { NULL, posts_text1 }, /* Pf */
+ { NULL, ewarn_eq1 }, /* Pf */
{ NULL, NULL }, /* Po */
{ NULL, NULL }, /* Pq */
{ NULL, NULL }, /* Qc */
@@ -267,43 +219,44 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Qo */
{ NULL, NULL }, /* Qq */
{ NULL, NULL }, /* Re */
- { NULL, posts_rs }, /* Rs */
+ { NULL, post_rs }, /* Rs */
{ NULL, NULL }, /* Sc */
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
- { NULL, posts_bool }, /* Sm */
- { NULL, posts_hyph }, /* Sx */
+ { NULL, ebool }, /* Sm */
+ { NULL, post_hyph }, /* Sx */
{ NULL, NULL }, /* Sy */
{ NULL, NULL }, /* Tn */
{ NULL, NULL }, /* Ux */
{ NULL, NULL }, /* Xc */
{ NULL, NULL }, /* Xo */
- { NULL, posts_fo }, /* Fo */
- { NULL, NULL }, /* Fc */
+ { NULL, post_fo }, /* Fo */
+ { NULL, NULL }, /* Fc */
{ NULL, NULL }, /* Oo */
{ NULL, NULL }, /* Oc */
- { NULL, posts_bk }, /* Bk */
+ { NULL, post_bk }, /* Bk */
{ NULL, NULL }, /* Ek */
- { NULL, posts_eoln }, /* Bt */
+ { NULL, post_eoln }, /* Bt */
{ NULL, NULL }, /* Hf */
- { NULL, NULL }, /* Fr */
- { NULL, posts_eoln }, /* Ud */
- { NULL, posts_lb }, /* Lb */
- { pres_pp, posts_pp }, /* Lp */
- { NULL, NULL }, /* Lk */
- { NULL, posts_defaults }, /* Mt */
- { NULL, NULL }, /* Brq */
- { NULL, NULL }, /* Bro */
- { NULL, NULL }, /* Brc */
- { NULL, posts_text }, /* %C */
- { NULL, NULL }, /* Es */
- { NULL, NULL }, /* En */
+ { pre_obsolete, NULL }, /* Fr */
+ { NULL, post_eoln }, /* Ud */
+ { NULL, post_lb }, /* Lb */
+ { pre_par, post_par }, /* Lp */
+ { NULL, NULL }, /* Lk */
+ { NULL, post_defaults }, /* Mt */
+ { NULL, NULL }, /* Brq */
+ { NULL, NULL }, /* Bro */
+ { NULL, NULL }, /* Brc */
+ { NULL, ewarn_ge1 }, /* %C */
+ { pre_obsolete, post_es }, /* Es */
+ { pre_obsolete, post_en }, /* En */
{ NULL, NULL }, /* Dx */
- { NULL, posts_text }, /* %Q */
- { NULL, posts_pp }, /* br */
- { NULL, posts_sp }, /* sp */
- { NULL, posts_text1 }, /* %U */
+ { NULL, ewarn_ge1 }, /* %Q */
+ { NULL, post_par }, /* br */
+ { NULL, post_par }, /* sp */
+ { NULL, ewarn_eq1 }, /* %U */
{ NULL, NULL }, /* Ta */
+ { NULL, NULL }, /* ll */
};
#define RSORD_MAX 14 /* Number of `Rs' blocks. */
@@ -331,6 +284,7 @@ static const char * const secnames[SEC__MAX] = {
"LIBRARY",
"SYNOPSIS",
"DESCRIPTION",
+ "CONTEXT",
"IMPLEMENTATION NOTES",
"RETURN VALUES",
"ENVIRONMENT",
@@ -350,74 +304,59 @@ static const char * const secnames[SEC__MAX] = {
NULL
};
+
int
mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
{
- v_pre *p;
- int line, pos;
- char *tp;
+ v_pre p;
switch (n->type) {
- case (MDOC_TEXT):
- tp = n->string;
- line = n->line;
- pos = n->pos;
- check_text(mdoc, line, pos, tp);
+ case MDOC_TEXT:
+ check_text(mdoc, n->line, n->pos, n->string);
/* FALLTHROUGH */
- case (MDOC_TBL):
+ case MDOC_TBL:
/* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_EQN:
/* FALLTHROUGH */
- case (MDOC_ROOT):
+ case MDOC_ROOT:
return(1);
default:
break;
}
check_args(mdoc, n);
-
- if (NULL == mdoc_valids[n->tok].pre)
- return(1);
- for (p = mdoc_valids[n->tok].pre; *p; p++)
- if ( ! (*p)(mdoc, n))
- return(0);
- return(1);
+ p = mdoc_valids[n->tok].pre;
+ return(*p ? (*p)(mdoc, n) : 1);
}
-
int
mdoc_valid_post(struct mdoc *mdoc)
{
- v_post *p;
+ struct mdoc_node *n;
+ v_post p;
- if (MDOC_VALID & mdoc->last->flags)
+ n = mdoc->last;
+ if (n->flags & MDOC_VALID)
return(1);
- mdoc->last->flags |= MDOC_VALID;
+ n->flags |= MDOC_VALID;
- switch (mdoc->last->type) {
- case (MDOC_TEXT):
+ switch (n->type) {
+ case MDOC_TEXT:
/* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_EQN:
/* FALLTHROUGH */
- case (MDOC_TBL):
+ case MDOC_TBL:
return(1);
- case (MDOC_ROOT):
+ case MDOC_ROOT:
return(post_root(mdoc));
default:
- break;
+ p = mdoc_valids[n->tok].post;
+ return(*p ? (*p)(mdoc) : 1);
}
-
- if (NULL == mdoc_valids[mdoc->last->tok].post)
- return(1);
- for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
- if ( ! (*p)(mdoc))
- return(0);
-
- return(1);
}
static int
-check_count(struct mdoc *mdoc, enum mdoc_type type,
+check_count(struct mdoc *mdoc, enum mdoc_type type,
enum check_lvl lvl, enum check_ineq ineq, int val)
{
const char *p;
@@ -425,19 +364,19 @@ check_count(struct mdoc *mdoc, enum mdoc_type type,
if (mdoc->last->type != type)
return(1);
-
+
switch (ineq) {
- case (CHECK_LT):
+ case CHECK_LT:
p = "less than ";
if (mdoc->last->nchild < val)
return(1);
break;
- case (CHECK_GT):
+ case CHECK_GT:
p = "more than ";
if (mdoc->last->nchild > val)
return(1);
break;
- case (CHECK_EQ):
+ case CHECK_EQ:
p = "";
if (val == mdoc->last->nchild)
return(1);
@@ -448,9 +387,9 @@ check_count(struct mdoc *mdoc, enum mdoc_type type,
}
t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
- mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
- "want %s%d children (have %d)",
- p, val, mdoc->last->nchild);
+ mandoc_vmsg(t, mdoc->parse, mdoc->last->line,
+ mdoc->last->pos, "want %s%d children (have %d)",
+ p, val, mdoc->last->nchild);
return(1);
}
@@ -509,12 +448,6 @@ hwarn_ge1(POST_ARGS)
return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
}
-static int
-hwarn_le1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
-}
-
static void
check_args(struct mdoc *mdoc, struct mdoc_node *n)
{
@@ -535,12 +468,6 @@ check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
for (i = 0; i < (int)v->sz; i++)
check_text(mdoc, v->line, v->pos, v->value[i]);
-
- /* FIXME: move to post_std(). */
-
- if (MDOC_Std == v->arg)
- if ( ! (v->sz || mdoc->meta.name))
- mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
}
static void
@@ -552,26 +479,11 @@ check_text(struct mdoc *mdoc, int ln, int pos, char *p)
return;
for (cp = p; NULL != (p = strchr(p, '\t')); p++)
- mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
+ mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
+ ln, pos + (int)(p - cp), NULL);
}
static int
-check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
-{
-
- assert(n->parent);
- if ((MDOC_ROOT == t || tok == n->parent->tok) &&
- (t == n->parent->type))
- return(1);
-
- mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
- n->pos, "want parent %s", MDOC_ROOT == t ?
- "<root>" : mdoc_macronames[tok]);
- return(0);
-}
-
-
-static int
pre_display(PRE_ARGS)
{
struct mdoc_node *node;
@@ -579,25 +491,27 @@ pre_display(PRE_ARGS)
if (MDOC_BLOCK != n->type)
return(1);
- for (node = mdoc->last->parent; node; node = node->parent)
+ for (node = mdoc->last->parent; node; node = node->parent)
if (MDOC_BLOCK == node->type)
if (MDOC_Bd == node->tok)
break;
if (node)
- mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
+ mandoc_vmsg(MANDOCERR_BD_NEST,
+ mdoc->parse, n->line, n->pos,
+ "%s in Bd", mdoc_macronames[n->tok]);
return(1);
}
-
static int
pre_bl(PRE_ARGS)
{
- int i, comp, dup;
- const char *offs, *width;
- enum mdoc_list lt;
struct mdoc_node *np;
+ struct mdoc_argv *argv, *wa;
+ int i;
+ enum mdocargt mdoclt;
+ enum mdoc_list lt;
if (MDOC_BLOCK != n->type) {
if (ENDBODY_NOT != n->end) {
@@ -612,128 +526,131 @@ pre_bl(PRE_ARGS)
return(1);
}
- /*
+ /*
* First figure out which kind of list to use: bind ourselves to
* the first mentioned list type and warn about any remaining
* ones. If we find no list type, we default to LIST_item.
*/
- /* LINTED */
+ wa = n->args->argv;
+ mdoclt = MDOC_ARG_MAX;
for (i = 0; n->args && i < (int)n->args->argc; i++) {
+ argv = n->args->argv + i;
lt = LIST__NONE;
- dup = comp = 0;
- width = offs = NULL;
- switch (n->args->argv[i].arg) {
+ switch (argv->arg) {
/* Set list types. */
- case (MDOC_Bullet):
+ case MDOC_Bullet:
lt = LIST_bullet;
break;
- case (MDOC_Dash):
+ case MDOC_Dash:
lt = LIST_dash;
break;
- case (MDOC_Enum):
+ case MDOC_Enum:
lt = LIST_enum;
break;
- case (MDOC_Hyphen):
+ case MDOC_Hyphen:
lt = LIST_hyphen;
break;
- case (MDOC_Item):
+ case MDOC_Item:
lt = LIST_item;
break;
- case (MDOC_Tag):
+ case MDOC_Tag:
lt = LIST_tag;
break;
- case (MDOC_Diag):
+ case MDOC_Diag:
lt = LIST_diag;
break;
- case (MDOC_Hang):
+ case MDOC_Hang:
lt = LIST_hang;
break;
- case (MDOC_Ohang):
+ case MDOC_Ohang:
lt = LIST_ohang;
break;
- case (MDOC_Inset):
+ case MDOC_Inset:
lt = LIST_inset;
break;
- case (MDOC_Column):
+ case MDOC_Column:
lt = LIST_column;
break;
/* Set list arguments. */
- case (MDOC_Compact):
- dup = n->norm->Bl.comp;
- comp = 1;
+ case MDOC_Compact:
+ if (n->norm->Bl.comp)
+ mandoc_msg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -compact");
+ n->norm->Bl.comp = 1;
break;
- case (MDOC_Width):
- /* NB: this can be empty! */
- if (n->args->argv[i].sz) {
- width = n->args->argv[i].value[0];
- dup = (NULL != n->norm->Bl.width);
+ case MDOC_Width:
+ wa = argv;
+ if (0 == argv->sz) {
+ mandoc_msg(MANDOCERR_ARG_EMPTY,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -width");
+ n->norm->Bl.width = "0n";
break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ if (NULL != n->norm->Bl.width)
+ mandoc_vmsg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -width %s",
+ argv->value[0]);
+ n->norm->Bl.width = argv->value[0];
break;
- case (MDOC_Offset):
- /* NB: this can be empty! */
- if (n->args->argv[i].sz) {
- offs = n->args->argv[i].value[0];
- dup = (NULL != n->norm->Bl.offs);
+ case MDOC_Offset:
+ if (0 == argv->sz) {
+ mandoc_msg(MANDOCERR_ARG_EMPTY,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -offset");
break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ if (NULL != n->norm->Bl.offs)
+ mandoc_vmsg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -offset %s",
+ argv->value[0]);
+ n->norm->Bl.offs = argv->value[0];
break;
default:
continue;
}
-
- /* Check: duplicate auxiliary arguments. */
-
- if (dup)
- mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
-
- if (comp && ! dup)
- n->norm->Bl.comp = comp;
- if (offs && ! dup)
- n->norm->Bl.offs = offs;
- if (width && ! dup)
- n->norm->Bl.width = width;
+ if (LIST__NONE == lt)
+ continue;
+ mdoclt = argv->arg;
/* Check: multiple list types. */
- if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
- mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
-
- /* Assign list type. */
-
- if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
- n->norm->Bl.type = lt;
- /* Set column information, too. */
- if (LIST_column == lt) {
- n->norm->Bl.ncols =
- n->args->argv[i].sz;
- n->norm->Bl.cols = (void *)
- n->args->argv[i].value;
- }
+ if (LIST__NONE != n->norm->Bl.type) {
+ mandoc_vmsg(MANDOCERR_BL_REP,
+ mdoc->parse, n->line, n->pos,
+ "Bl -%s", mdoc_argnames[argv->arg]);
+ continue;
}
/* The list type should come first. */
- if (n->norm->Bl.type == LIST__NONE)
- if (n->norm->Bl.width ||
- n->norm->Bl.offs ||
- n->norm->Bl.comp)
- mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
-
- continue;
+ if (n->norm->Bl.width ||
+ n->norm->Bl.offs ||
+ n->norm->Bl.comp)
+ mandoc_vmsg(MANDOCERR_BL_LATETYPE,
+ mdoc->parse, n->line, n->pos, "Bl -%s",
+ mdoc_argnames[n->args->argv[0].arg]);
+
+ n->norm->Bl.type = lt;
+ if (LIST_column == lt) {
+ n->norm->Bl.ncols = argv->sz;
+ n->norm->Bl.cols = (void *)argv->value;
+ }
}
/* Allow lists to default to LIST_item. */
if (LIST__NONE == n->norm->Bl.type) {
- mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
+ mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
+ n->line, n->pos, "Bl");
n->norm->Bl.type = LIST_item;
}
- /*
+ /*
* Validate the width field. Some list types don't need width
* types and should be warned about them. Others should have it
* and must also be warned. Yet others have a default and need
@@ -741,31 +658,34 @@ pre_bl(PRE_ARGS)
*/
switch (n->norm->Bl.type) {
- case (LIST_tag):
+ case LIST_tag:
if (NULL == n->norm->Bl.width)
- mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
+ mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
+ n->line, n->pos, "Bl -tag");
break;
- case (LIST_column):
+ case LIST_column:
/* FALLTHROUGH */
- case (LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case (LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case (LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case (LIST_item):
+ case LIST_item:
if (n->norm->Bl.width)
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
+ wa->line, wa->pos, "Bl -%s",
+ mdoc_argnames[mdoclt]);
break;
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
if (NULL == n->norm->Bl.width)
n->norm->Bl.width = "2n";
break;
- case (LIST_enum):
+ case LIST_enum:
if (NULL == n->norm->Bl.width)
n->norm->Bl.width = "3n";
break;
@@ -773,17 +693,18 @@ pre_bl(PRE_ARGS)
break;
}
- return(1);
+ return(pre_par(mdoc, n));
}
-
static int
pre_bd(PRE_ARGS)
{
- int i, dup, comp;
- enum mdoc_disp dt;
- const char *offs;
struct mdoc_node *np;
+ struct mdoc_argv *argv;
+ int i;
+ enum mdoc_disp dt;
+
+ pre_literal(mdoc, n);
if (MDOC_BLOCK != n->type) {
if (ENDBODY_NOT != n->end) {
@@ -798,127 +719,95 @@ pre_bd(PRE_ARGS)
return(1);
}
- /* LINTED */
for (i = 0; n->args && i < (int)n->args->argc; i++) {
+ argv = n->args->argv + i;
dt = DISP__NONE;
- dup = comp = 0;
- offs = NULL;
- switch (n->args->argv[i].arg) {
- case (MDOC_Centred):
- dt = DISP_centred;
+ switch (argv->arg) {
+ case MDOC_Centred:
+ dt = DISP_centered;
break;
- case (MDOC_Ragged):
+ case MDOC_Ragged:
dt = DISP_ragged;
break;
- case (MDOC_Unfilled):
+ case MDOC_Unfilled:
dt = DISP_unfilled;
break;
- case (MDOC_Filled):
+ case MDOC_Filled:
dt = DISP_filled;
break;
- case (MDOC_Literal):
+ case MDOC_Literal:
dt = DISP_literal;
break;
- case (MDOC_File):
- mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
+ case MDOC_File:
+ mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
+ n->line, n->pos, NULL);
return(0);
- case (MDOC_Offset):
- /* NB: this can be empty! */
- if (n->args->argv[i].sz) {
- offs = n->args->argv[i].value[0];
- dup = (NULL != n->norm->Bd.offs);
+ case MDOC_Offset:
+ if (0 == argv->sz) {
+ mandoc_msg(MANDOCERR_ARG_EMPTY,
+ mdoc->parse, argv->line,
+ argv->pos, "Bd -offset");
break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ if (NULL != n->norm->Bd.offs)
+ mandoc_vmsg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bd -offset %s",
+ argv->value[0]);
+ n->norm->Bd.offs = argv->value[0];
break;
- case (MDOC_Compact):
- comp = 1;
- dup = n->norm->Bd.comp;
+ case MDOC_Compact:
+ if (n->norm->Bd.comp)
+ mandoc_msg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bd -compact");
+ n->norm->Bd.comp = 1;
break;
default:
abort();
/* NOTREACHED */
}
+ if (DISP__NONE == dt)
+ continue;
- /* Check whether we have duplicates. */
-
- if (dup)
- mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
-
- /* Make our auxiliary assignments. */
-
- if (offs && ! dup)
- n->norm->Bd.offs = offs;
- if (comp && ! dup)
- n->norm->Bd.comp = comp;
-
- /* Check whether a type has already been assigned. */
-
- if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
- mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
-
- /* Make our type assignment. */
-
- if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
+ if (DISP__NONE == n->norm->Bd.type)
n->norm->Bd.type = dt;
+ else
+ mandoc_vmsg(MANDOCERR_BD_REP,
+ mdoc->parse, n->line, n->pos,
+ "Bd -%s", mdoc_argnames[argv->arg]);
}
if (DISP__NONE == n->norm->Bd.type) {
- mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
+ mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
+ n->line, n->pos, "Bd");
n->norm->Bd.type = DISP_ragged;
}
- return(1);
+ return(pre_par(mdoc, n));
}
-
-static int
-pre_ss(PRE_ARGS)
-{
-
- if (MDOC_BLOCK != n->type)
- return(1);
- return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
-}
-
-
-static int
-pre_sh(PRE_ARGS)
-{
-
- if (MDOC_BLOCK != n->type)
- return(1);
- return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
-}
-
-
-static int
-pre_it(PRE_ARGS)
-{
-
- if (MDOC_BLOCK != n->type)
- return(1);
-
- return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
-}
-
-
static int
pre_an(PRE_ARGS)
{
- int i;
+ struct mdoc_argv *argv;
+ size_t i;
- if (NULL == n->args)
+ if (n->args == NULL)
return(1);
-
- for (i = 1; i < (int)n->args->argc; i++)
- mdoc_pmsg(mdoc, n->args->argv[i].line,
- n->args->argv[i].pos, MANDOCERR_IGNARGV);
- if (MDOC_Split == n->args->argv[0].arg)
+ for (i = 1; i < n->args->argc; i++) {
+ argv = n->args->argv + i;
+ mandoc_vmsg(MANDOCERR_AN_REP,
+ mdoc->parse, argv->line, argv->pos,
+ "An -%s", mdoc_argnames[argv->arg]);
+ }
+
+ argv = n->args->argv;
+ if (argv->arg == MDOC_Split)
n->norm->An.auth = AUTH_split;
- else if (MDOC_Nosplit == n->args->argv[0].arg)
+ else if (argv->arg == MDOC_Nosplit)
n->norm->An.auth = AUTH_nosplit;
else
abort();
@@ -934,20 +823,31 @@ pre_std(PRE_ARGS)
if (MDOC_Std == n->args->argv[0].arg)
return(1);
- mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
+ mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
return(1);
}
static int
-pre_dt(PRE_ARGS)
+pre_obsolete(PRE_ARGS)
{
- if (NULL == mdoc->meta.date || mdoc->meta.os)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
+ if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type)
+ mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
+ return(1);
+}
- if (mdoc->meta.title)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
+static int
+pre_dt(PRE_ARGS)
+{
+ if (mdoc->meta.title != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+ n->line, n->pos, "Dt");
+ else if (mdoc->meta.os != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ n->line, n->pos, "Dt after Os");
return(1);
}
@@ -955,12 +855,12 @@ static int
pre_os(PRE_ARGS)
{
- if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
-
- if (mdoc->meta.os)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
-
+ if (mdoc->meta.os != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+ n->line, n->pos, "Os");
+ else if (mdoc->flags & MDOC_PBODY)
+ mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
+ n->line, n->pos, "Os");
return(1);
}
@@ -968,20 +868,25 @@ static int
pre_dd(PRE_ARGS)
{
- if (mdoc->meta.title || mdoc->meta.os)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
-
- if (mdoc->meta.date)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
-
+ if (mdoc->meta.date != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+ n->line, n->pos, "Dd");
+ else if (mdoc->flags & MDOC_PBODY)
+ mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
+ n->line, n->pos, "Dd");
+ else if (mdoc->meta.title != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ n->line, n->pos, "Dd after Dt");
+ else if (mdoc->meta.os != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ n->line, n->pos, "Dd after Os");
return(1);
}
-
static int
post_bf(POST_ARGS)
{
- struct mdoc_node *np;
+ struct mdoc_node *np, *nch;
enum mdocargt arg;
/*
@@ -995,7 +900,7 @@ post_bf(POST_ARGS)
np = mdoc->last->pending->parent->head;
} else if (MDOC_BLOCK != mdoc->last->type) {
np = mdoc->last->parent->head;
- } else
+ } else
np = mdoc->last->head;
assert(np);
@@ -1008,21 +913,23 @@ post_bf(POST_ARGS)
assert(MDOC_BLOCK == np->parent->type);
assert(MDOC_Bf == np->parent->tok);
- /*
- * Cannot have both argument and parameter.
- * If neither is specified, let it through with a warning.
- */
+ /* Check the number of arguments. */
- if (np->parent->args && np->child) {
- mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
- return(0);
- } else if (NULL == np->parent->args && NULL == np->child) {
- mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
- return(1);
+ nch = np->child;
+ if (NULL == np->parent->args) {
+ if (NULL == nch) {
+ mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
+ np->line, np->pos, "Bf");
+ return(1);
+ }
+ nch = nch->next;
}
+ if (NULL != nch)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nch->line, nch->pos, "Bf ... %s", nch->string);
/* Extract argument into data. */
-
+
if (np->parent->args) {
arg = np->parent->args->argv[0].arg;
if (MDOC_Emphasis == arg)
@@ -1044,8 +951,10 @@ post_bf(POST_ARGS)
np->norm->Bf.font = FONT_Li;
else if (0 == strcmp(np->child->string, "Sy"))
np->norm->Bf.font = FONT_Sy;
- else
- mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
+ else
+ mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
+ np->child->line, np->child->pos,
+ "Bf %s", np->child->string);
return(1);
}
@@ -1053,46 +962,50 @@ post_bf(POST_ARGS)
static int
post_lb(POST_ARGS)
{
- const char *p;
- char *buf;
- size_t sz;
+ struct mdoc_node *n;
+ const char *stdlibname;
+ char *libname;
check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
- assert(mdoc->last->child);
- assert(MDOC_TEXT == mdoc->last->child->type);
-
- p = mdoc_a2lib(mdoc->last->child->string);
-
- /* If lookup ok, replace with table value. */
+ n = mdoc->last->child;
- if (p) {
- free(mdoc->last->child->string);
- mdoc->last->child->string = mandoc_strdup(p);
- return(1);
- }
+ assert(n);
+ assert(MDOC_TEXT == n->type);
- /* If not, use "library ``xxxx''. */
+ if (NULL == (stdlibname = mdoc_a2lib(n->string)))
+ mandoc_asprintf(&libname,
+ "library \\(lq%s\\(rq", n->string);
+ else
+ libname = mandoc_strdup(stdlibname);
- sz = strlen(mdoc->last->child->string) +
- 2 + strlen("\\(lqlibrary\\(rq");
- buf = mandoc_malloc(sz);
- snprintf(buf, sz, "library \\(lq%s\\(rq",
- mdoc->last->child->string);
- free(mdoc->last->child->string);
- mdoc->last->child->string = buf;
+ free(n->string);
+ n->string = libname;
return(1);
}
static int
post_eoln(POST_ARGS)
{
+ const struct mdoc_node *n;
- if (mdoc->last->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
+ n = mdoc->last;
+ if (n->child)
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, n->line, n->pos,
+ "%s %s", mdoc_macronames[n->tok],
+ n->child->string);
return(1);
}
+static int
+post_fo(POST_ARGS)
+{
+
+ hwarn_eq1(mdoc);
+ bwarn_ge1(mdoc);
+ return(1);
+}
static int
post_vt(POST_ARGS)
@@ -1109,51 +1022,54 @@ post_vt(POST_ARGS)
if (MDOC_BODY != mdoc->last->type)
return(1);
-
+
for (n = mdoc->last->child; n; n = n->next)
- if (MDOC_TEXT != n->type)
- mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
+ if (MDOC_TEXT != n->type)
+ mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
return(1);
}
-
static int
post_nm(POST_ARGS)
{
- char buf[BUFSIZ];
- int c;
if (NULL != mdoc->meta.name)
return(1);
- /* Try to use our children for setting the meta name. */
+ mdoc_deroff(&mdoc->meta.name, mdoc->last);
- if (NULL != mdoc->last->child) {
- buf[0] = '\0';
- c = concat(buf, mdoc->last->child, BUFSIZ);
- } else
- c = 0;
-
- switch (c) {
- case (-1):
- mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
- return(0);
- case (0):
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
- mdoc->meta.name = mandoc_strdup("UNKNOWN");
- break;
- default:
- mdoc->meta.name = mandoc_strdup(buf);
- break;
- }
+ if (NULL == mdoc->meta.name)
+ mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, "Nm");
return(1);
}
static int
+post_nd(POST_ARGS)
+{
+
+ berr_ge1(mdoc);
+ return(post_hyph(mdoc));
+}
+
+static int
+post_d1(POST_ARGS)
+{
+
+ bwarn_ge1(mdoc);
+ return(post_hyph(mdoc));
+}
+
+static int
post_literal(POST_ARGS)
{
-
+
+ if (mdoc->last->tok == MDOC_Bd)
+ hwarn_eq0(mdoc);
+ bwarn_ge1(mdoc);
+
/*
* The `Dl' (note "el" not "one") and `Bd' macros unset the
* MDOC_LITERAL flag as they leave. Note that `Bd' only sets
@@ -1180,37 +1096,31 @@ post_defaults(POST_ARGS)
if (mdoc->last->child)
return(1);
-
+
nn = mdoc->last;
mdoc->next = MDOC_NEXT_CHILD;
switch (nn->tok) {
- case (MDOC_Ar):
+ case MDOC_Ar:
if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
return(0);
if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
return(0);
break;
- case (MDOC_At):
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
- return(0);
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
- return(0);
- break;
- case (MDOC_Li):
+ case MDOC_Li:
if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
return(0);
break;
- case (MDOC_Pa):
+ case MDOC_Pa:
/* FALLTHROUGH */
- case (MDOC_Mt):
+ case MDOC_Mt:
if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
return(0);
break;
default:
abort();
/* NOTREACHED */
- }
+ }
mdoc->last = nn;
return(1);
@@ -1219,37 +1129,36 @@ post_defaults(POST_ARGS)
static int
post_at(POST_ARGS)
{
- const char *p, *q;
- char *buf;
- size_t sz;
+ struct mdoc_node *n;
+ const char *std_att;
+ char *att;
+
+ n = mdoc->last;
+ if (n->child == NULL) {
+ mdoc->next = MDOC_NEXT_CHILD;
+ if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"))
+ return(0);
+ mdoc->last = n;
+ return(1);
+ }
/*
* If we have a child, look it up in the standard keys. If a
* key exist, use that instead of the child; if it doesn't,
* prefix "AT&T UNIX " to the existing data.
*/
-
- if (NULL == mdoc->last->child)
- return(1);
-
- assert(MDOC_TEXT == mdoc->last->child->type);
- p = mdoc_a2att(mdoc->last->child->string);
- if (p) {
- free(mdoc->last->child->string);
- mdoc->last->child->string = mandoc_strdup(p);
- } else {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
- p = "AT&T UNIX ";
- q = mdoc->last->child->string;
- sz = strlen(p) + strlen(q) + 1;
- buf = mandoc_malloc(sz);
- strlcpy(buf, p, sz);
- strlcat(buf, q, sz);
- free(mdoc->last->child->string);
- mdoc->last->child->string = buf;
- }
+ n = n->child;
+ assert(MDOC_TEXT == n->type);
+ if (NULL == (std_att = mdoc_a2att(n->string))) {
+ mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
+ n->line, n->pos, "At %s", n->string);
+ mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
+ } else
+ att = mandoc_strdup(std_att);
+ free(n->string);
+ n->string = att;
return(1);
}
@@ -1268,89 +1177,95 @@ post_an(POST_ARGS)
return(1);
}
+static int
+post_en(POST_ARGS)
+{
+
+ if (MDOC_BLOCK == mdoc->last->type)
+ mdoc->last->norm->Es = mdoc->last_es;
+ return(1);
+}
+
+static int
+post_es(POST_ARGS)
+{
+
+ mdoc->last_es = mdoc->last;
+ return(1);
+}
static int
post_it(POST_ARGS)
{
int i, cols;
enum mdoc_list lt;
- struct mdoc_node *n, *c;
- enum mandocerr er;
+ struct mdoc_node *nbl, *nit, *nch;
- if (MDOC_BLOCK != mdoc->last->type)
+ nit = mdoc->last;
+ if (MDOC_BLOCK != nit->type)
return(1);
- n = mdoc->last->parent->parent;
- lt = n->norm->Bl.type;
-
- if (LIST__NONE == lt) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
- return(1);
- }
+ nbl = nit->parent->parent;
+ lt = nbl->norm->Bl.type;
switch (lt) {
- case (LIST_tag):
- if (mdoc->last->head->child)
- break;
- /* FIXME: give this a dummy value. */
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
- break;
- case (LIST_hang):
+ case LIST_tag:
/* FALLTHROUGH */
- case (LIST_ohang):
+ case LIST_hang:
/* FALLTHROUGH */
- case (LIST_inset):
+ case LIST_ohang:
/* FALLTHROUGH */
- case (LIST_diag):
- if (NULL == mdoc->last->head->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
+ case LIST_inset:
+ /* FALLTHROUGH */
+ case LIST_diag:
+ if (NULL == nit->head->child)
+ mandoc_vmsg(MANDOCERR_IT_NOHEAD,
+ mdoc->parse, nit->line, nit->pos,
+ "Bl -%s It",
+ mdoc_argnames[nbl->args->argv[0].arg]);
break;
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case (LIST_hyphen):
- if (NULL == mdoc->last->body->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
+ case LIST_hyphen:
+ if (NULL == nit->body->child)
+ mandoc_vmsg(MANDOCERR_IT_NOBODY,
+ mdoc->parse, nit->line, nit->pos,
+ "Bl -%s It",
+ mdoc_argnames[nbl->args->argv[0].arg]);
/* FALLTHROUGH */
- case (LIST_item):
- if (mdoc->last->head->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
+ case LIST_item:
+ if (NULL != nit->head->child)
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, nit->line, nit->pos,
+ "It %s", nit->head->child->string);
break;
- case (LIST_column):
- cols = (int)n->norm->Bl.ncols;
-
- assert(NULL == mdoc->last->head->child);
+ case LIST_column:
+ cols = (int)nbl->norm->Bl.ncols;
- if (NULL == mdoc->last->body->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
+ assert(NULL == nit->head->child);
- for (i = 0, c = mdoc->last->child; c; c = c->next)
- if (MDOC_BODY == c->type)
+ for (i = 0, nch = nit->child; nch; nch = nch->next)
+ if (MDOC_BODY == nch->type)
i++;
- if (i < cols)
- er = MANDOCERR_ARGCOUNT;
- else if (i == cols || i == cols + 1)
- break;
- else
- er = MANDOCERR_SYNTARGCOUNT;
-
- mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
- mdoc->last->pos,
- "columns == %d (have %d)", cols, i);
- return(MANDOCERR_ARGCOUNT == er);
- default:
+ if (i < cols || i > cols + 1)
+ mandoc_vmsg(MANDOCERR_ARGCOUNT,
+ mdoc->parse, nit->line, nit->pos,
+ "columns == %d (have %d)", cols, i);
break;
+ default:
+ abort();
}
return(1);
}
static int
-post_bl_block(POST_ARGS)
+post_bl_block(POST_ARGS)
{
struct mdoc_node *n, *ni, *nc;
@@ -1364,8 +1279,8 @@ post_bl_block(POST_ARGS)
n = mdoc->last;
- if (LIST_tag == n->norm->Bl.type &&
- NULL == n->norm->Bl.width) {
+ if (LIST_tag == n->norm->Bl.type &&
+ NULL == n->norm->Bl.width) {
if ( ! post_bl_block_tag(mdoc))
return(0);
assert(n->norm->Bl.width);
@@ -1381,23 +1296,28 @@ post_bl_block(POST_ARGS)
nc = ni->body->last;
while (NULL != nc) {
switch (nc->tok) {
- case (MDOC_Pp):
+ case MDOC_Pp:
/* FALLTHROUGH */
- case (MDOC_Lp):
+ case MDOC_Lp:
/* FALLTHROUGH */
- case (MDOC_br):
+ case MDOC_br:
break;
default:
nc = NULL;
continue;
}
if (NULL == ni->next) {
- mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
+ mandoc_msg(MANDOCERR_PAR_MOVE,
+ mdoc->parse, nc->line, nc->pos,
+ mdoc_macronames[nc->tok]);
if ( ! mdoc_node_relink(mdoc, nc))
return(0);
} else if (0 == n->norm->Bl.comp &&
LIST_column != n->norm->Bl.type) {
- mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ mdoc->parse, nc->line, nc->pos,
+ "%s before It",
+ mdoc_macronames[nc->tok]);
mdoc_node_delete(mdoc, nc);
} else
break;
@@ -1414,7 +1334,7 @@ post_bl_block_width(POST_ARGS)
int i;
enum mdoct tok;
struct mdoc_node *n;
- char buf[NUMSIZ];
+ char buf[24];
n = mdoc->last;
@@ -1431,22 +1351,20 @@ post_bl_block_width(POST_ARGS)
width = 6;
else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
return(1);
- else if (0 == (width = macro2len(tok))) {
- mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
- return(1);
- }
+ else
+ width = macro2len(tok);
/* The value already exists: free and reallocate it. */
assert(n->args);
- for (i = 0; i < (int)n->args->argc; i++)
+ for (i = 0; i < (int)n->args->argc; i++)
if (MDOC_Width == n->args->argv[i].arg)
break;
assert(i < (int)n->args->argc);
- snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
+ (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width);
free(n->args->argv[i].value[0]);
n->args->argv[i].value[0] = mandoc_strdup(buf);
@@ -1461,7 +1379,7 @@ post_bl_block_tag(POST_ARGS)
struct mdoc_node *n, *nn;
size_t sz, ssz;
int i;
- char buf[NUMSIZ];
+ char buf[24];
/*
* Calculate the -width for a `Bl -tag' list if it hasn't been
@@ -1492,11 +1410,11 @@ post_bl_block_tag(POST_ARGS)
sz = ssz;
break;
- }
+ }
/* Defaults to ten ens. */
- snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
+ (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
/*
* We have to dynamically add this to the macro's argument list.
@@ -1506,8 +1424,8 @@ post_bl_block_tag(POST_ARGS)
assert(n->args);
i = (int)(n->args->argc)++;
- n->args->argv = mandoc_realloc(n->args->argv,
- n->args->argc * sizeof(struct mdoc_argv));
+ n->args->argv = mandoc_reallocarray(n->args->argv,
+ n->args->argc, sizeof(struct mdoc_argv));
n->args->argv[i].arg = MDOC_Width;
n->args->argv[i].line = n->line;
@@ -1521,11 +1439,11 @@ post_bl_block_tag(POST_ARGS)
return(1);
}
-
static int
-post_bl_head(POST_ARGS)
+post_bl_head(POST_ARGS)
{
struct mdoc_node *np, *nn, *nnp;
+ struct mdoc_argv *argv;
int i, j;
if (LIST_column != mdoc->last->norm->Bl.type)
@@ -1533,33 +1451,22 @@ post_bl_head(POST_ARGS)
return(hwarn_eq0(mdoc));
/*
- * Convert old-style lists, where the column width specifiers
+ * Append old-style lists, where the column width specifiers
* trail as macro parameters, to the new-style ("normal-form")
* lists where they're argument values following -column.
*/
- /* First, disallow both types and allow normal-form. */
-
- /*
- * TODO: technically, we can accept both and just merge the two
- * lists, but I'll leave that for another day.
- */
-
- if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
- return(0);
- } else if (NULL == mdoc->last->child)
+ if (mdoc->last->child == NULL)
return(1);
np = mdoc->last->parent;
assert(np->args);
- for (j = 0; j < (int)np->args->argc; j++)
+ for (j = 0; j < (int)np->args->argc; j++)
if (MDOC_Column == np->args->argv[j].arg)
break;
assert(j < (int)np->args->argc);
- assert(0 == np->args->argv[j].sz);
/*
* Accommodate for new-style groff column syntax. Shuffle the
@@ -1567,15 +1474,17 @@ post_bl_head(POST_ARGS)
* column field. Then, delete the head children.
*/
- np->args->argv[j].sz = (size_t)mdoc->last->nchild;
- np->args->argv[j].value = mandoc_malloc
- ((size_t)mdoc->last->nchild * sizeof(char *));
+ argv = np->args->argv + j;
+ i = argv->sz;
+ argv->sz += mdoc->last->nchild;
+ argv->value = mandoc_reallocarray(argv->value,
+ argv->sz, sizeof(char *));
- mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
- mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
+ mdoc->last->norm->Bl.ncols = argv->sz;
+ mdoc->last->norm->Bl.cols = (void *)argv->value;
- for (i = 0, nn = mdoc->last->child; nn; i++) {
- np->args->argv[j].value[i] = nn->string;
+ for (nn = mdoc->last->child; nn; i++) {
+ argv->value[i] = nn->string;
nn->string = NULL;
nnp = nn;
nn = nn->next;
@@ -1597,16 +1506,18 @@ post_bl(POST_ARGS)
nbody = mdoc->last;
switch (nbody->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
return(post_bl_block(mdoc));
- case (MDOC_HEAD):
+ case MDOC_HEAD:
return(post_bl_head(mdoc));
- case (MDOC_BODY):
+ case MDOC_BODY:
break;
default:
return(1);
}
+ bwarn_ge1(mdoc);
+
nchild = nbody->child;
while (NULL != nchild) {
if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
@@ -1614,7 +1525,9 @@ post_bl(POST_ARGS)
continue;
}
- mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
+ mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
+ nchild->line, nchild->pos,
+ mdoc_macronames[nchild->tok]);
/*
* Move the node out of the Bl block.
@@ -1662,86 +1575,118 @@ post_bl(POST_ARGS)
}
static int
+post_bk(POST_ARGS)
+{
+
+ hwarn_eq0(mdoc);
+ bwarn_ge1(mdoc);
+ return(1);
+}
+
+static int
ebool(struct mdoc *mdoc)
{
+ struct mdoc_node *nch;
+ enum mdoct tok;
+
+ tok = mdoc->last->tok;
+ nch = mdoc->last->child;
- if (NULL == mdoc->last->child) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
- mdoc_node_delete(mdoc, mdoc->last);
+ if (NULL == nch) {
+ if (MDOC_Sm == tok)
+ mdoc->flags ^= MDOC_SMOFF;
return(1);
}
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
- assert(MDOC_TEXT == mdoc->last->child->type);
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
- if (0 == strcmp(mdoc->last->child->string, "on")) {
- if (MDOC_Sm == mdoc->last->tok)
+ assert(MDOC_TEXT == nch->type);
+
+ if (0 == strcmp(nch->string, "on")) {
+ if (MDOC_Sm == tok)
mdoc->flags &= ~MDOC_SMOFF;
return(1);
}
- if (0 == strcmp(mdoc->last->child->string, "off")) {
- if (MDOC_Sm == mdoc->last->tok)
+ if (0 == strcmp(nch->string, "off")) {
+ if (MDOC_Sm == tok)
mdoc->flags |= MDOC_SMOFF;
return(1);
}
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
- return(1);
+ mandoc_vmsg(MANDOCERR_SM_BAD,
+ mdoc->parse, nch->line, nch->pos,
+ "%s %s", mdoc_macronames[tok], nch->string);
+ return(mdoc_node_relink(mdoc, nch));
}
static int
post_root(POST_ARGS)
{
- int erc;
struct mdoc_node *n;
- erc = 0;
+ /* Add missing prologue data. */
- /* Check that we have a finished prologue. */
+ if (mdoc->meta.date == NULL)
+ mdoc->meta.date = mdoc->quick ?
+ mandoc_strdup("") :
+ mandoc_normdate(mdoc->parse, NULL, 0, 0);
- if ( ! (MDOC_PBODY & mdoc->flags)) {
- erc++;
- mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
+ if (mdoc->meta.title == NULL) {
+ mandoc_msg(MANDOCERR_DT_NOTITLE,
+ mdoc->parse, 0, 0, "EOF");
+ mdoc->meta.title = mandoc_strdup("UNTITLED");
+ }
+
+ if (mdoc->meta.vol == NULL)
+ mdoc->meta.vol = mandoc_strdup("LOCAL");
+
+ if (mdoc->meta.os == NULL) {
+ mandoc_msg(MANDOCERR_OS_MISSING,
+ mdoc->parse, 0, 0, NULL);
+ mdoc->meta.os = mandoc_strdup("");
}
n = mdoc->first;
assert(n);
-
+
/* Check that we begin with a proper `Sh'. */
- if (NULL == n->child) {
- erc++;
- mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
- } else if (MDOC_BLOCK != n->child->type ||
- MDOC_Sh != n->child->tok) {
- erc++;
- /* Can this be lifted? See rxdebug.1 for example. */
- mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
- }
+ if (NULL == n->child)
+ mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse,
+ n->line, n->pos, NULL);
+ else if (MDOC_Sh != n->child->tok)
+ mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
+ n->child->line, n->child->pos,
+ mdoc_macronames[n->child->tok]);
- return(erc ? 0 : 1);
+ return(1);
}
static int
post_st(POST_ARGS)
{
- struct mdoc_node *ch;
+ struct mdoc_node *n, *nch;
const char *p;
- if (NULL == (ch = mdoc->last->child)) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
- mdoc_node_delete(mdoc, mdoc->last);
+ n = mdoc->last;
+ nch = n->child;
+
+ if (NULL == nch) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
+ mdoc_node_delete(mdoc, n);
return(1);
}
- assert(MDOC_TEXT == ch->type);
+ assert(MDOC_TEXT == nch->type);
- if (NULL == (p = mdoc_a2st(ch->string))) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
- mdoc_node_delete(mdoc, mdoc->last);
+ if (NULL == (p = mdoc_a2st(nch->string))) {
+ mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
+ nch->line, nch->pos, "St %s", nch->string);
+ mdoc_node_delete(mdoc, n);
} else {
- free(ch->string);
- ch->string = mandoc_strdup(p);
+ free(nch->string);
+ nch->string = mandoc_strdup(p);
}
return(1);
@@ -1754,10 +1699,10 @@ post_rs(POST_ARGS)
int i, j;
switch (mdoc->last->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
if (mdoc->last->child)
break;
check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
@@ -1767,41 +1712,9 @@ post_rs(POST_ARGS)
}
/*
- * Make sure only certain types of nodes are allowed within the
- * the `Rs' body. Delete offending nodes and raise a warning.
- * Do this before re-ordering for the sake of clarity.
- */
-
- next = NULL;
- for (nn = mdoc->last->child; nn; nn = next) {
- for (i = 0; i < RSORD_MAX; i++)
- if (nn->tok == rsord[i])
- break;
-
- if (i < RSORD_MAX) {
- if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
- mdoc->last->norm->Rs.quote_T++;
- next = nn->next;
- continue;
- }
-
- next = nn->next;
- mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
- mdoc_node_delete(mdoc, nn);
- }
-
- /*
- * Nothing to sort if only invalid nodes were found
- * inside the `Rs' body.
- */
-
- if (NULL == mdoc->last->child)
- return(1);
-
- /*
* The full `Rs' block needs special handling to order the
* sub-elements according to `rsord'. Pick through each element
- * and correctly order it. This is a insertion sort.
+ * and correctly order it. This is an insertion sort.
*/
next = NULL;
@@ -1811,13 +1724,21 @@ post_rs(POST_ARGS)
if (rsord[i] == nn->tok)
break;
- /*
+ if (i == RSORD_MAX) {
+ mandoc_msg(MANDOCERR_RS_BAD,
+ mdoc->parse, nn->line, nn->pos,
+ mdoc_macronames[nn->tok]);
+ i = -1;
+ } else if (MDOC__J == nn->tok || MDOC__B == nn->tok)
+ mdoc->last->norm->Rs.quote_T++;
+
+ /*
* Remove `nn' from the chain. This somewhat
* repeats mdoc_node_unlink(), but since we're
* just re-ordering, there's no need for the
* full unlink process.
*/
-
+
if (NULL != (next = nn->next))
next->prev = nn->prev;
@@ -1826,7 +1747,7 @@ post_rs(POST_ARGS)
nn->prev = nn->next = NULL;
- /*
+ /*
* Scan back until we reach a node that's
* ordered before `nn'.
*/
@@ -1836,6 +1757,8 @@ post_rs(POST_ARGS)
for (j = 0; j < RSORD_MAX; j++)
if (rsord[j] == prev->tok)
break;
+ if (j == RSORD_MAX)
+ j = -1;
if (j <= i)
break;
@@ -1875,15 +1798,15 @@ post_hyph(POST_ARGS)
n = mdoc->last;
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
break;
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
break;
return(1);
- case (MDOC_ELEM):
+ case MDOC_ELEM:
break;
default:
return(1);
@@ -1893,7 +1816,7 @@ post_hyph(POST_ARGS)
if (MDOC_TEXT != nch->type)
continue;
cp = nch->string;
- if (3 > strnlen(cp, 3))
+ if ('\0' == *cp)
continue;
while ('\0' != *(++cp))
if ('-' == *cp &&
@@ -1905,11 +1828,20 @@ post_hyph(POST_ARGS)
}
static int
+post_hyphtext(POST_ARGS)
+{
+
+ ewarn_ge1(mdoc);
+ return(post_hyph(mdoc));
+}
+
+static int
post_ns(POST_ARGS)
{
if (MDOC_LINE & mdoc->last->flags)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
+ mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
return(1);
}
@@ -1917,6 +1849,8 @@ static int
post_sh(POST_ARGS)
{
+ post_ignpar(mdoc);
+
if (MDOC_HEAD == mdoc->last->type)
return(post_sh_head(mdoc));
if (MDOC_BODY == mdoc->last->type)
@@ -1940,7 +1874,8 @@ post_sh_body(POST_ARGS)
*/
if (NULL == (n = mdoc->last->child)) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
+ mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, "empty");
return(1);
}
@@ -1949,24 +1884,26 @@ post_sh_body(POST_ARGS)
continue;
if (MDOC_TEXT == n->type)
continue;
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
+ mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
}
assert(n);
if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
return(1);
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
+ mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
return(1);
}
static int
post_sh_head(POST_ARGS)
{
- char buf[BUFSIZ];
struct mdoc_node *n;
+ const char *goodsec;
+ char *secname;
enum mdoc_sec sec;
- int c;
/*
* Process a new section. Sections are either "named" or
@@ -1975,18 +1912,17 @@ post_sh_head(POST_ARGS)
* manual sections.
*/
+ secname = NULL;
sec = SEC_CUSTOM;
- buf[0] = '\0';
- if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
- mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
- return(0);
- } else if (1 == c)
- sec = a2sec(buf);
+ mdoc_deroff(&secname, mdoc->last);
+ sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
/* The NAME should be first. */
if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
+ mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s", secname);
/* The SYNOPSIS gets special attention in other areas. */
@@ -2018,8 +1954,10 @@ post_sh_head(POST_ARGS)
/* We don't care about custom sections after this. */
- if (SEC_CUSTOM == sec)
+ if (SEC_CUSTOM == sec) {
+ free(secname);
return(1);
+ }
/*
* Check whether our non-custom section is being repeated or is
@@ -2027,10 +1965,14 @@ post_sh_head(POST_ARGS)
*/
if (sec == mdoc->lastnamed)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP);
+ mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s", secname);
if (sec < mdoc->lastnamed)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO);
+ mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s", secname);
/* Mark the last named section. */
@@ -2038,27 +1980,42 @@ post_sh_head(POST_ARGS)
/* Check particular section/manual conventions. */
- assert(mdoc->meta.msec);
+ if (mdoc->meta.msec == NULL) {
+ free(secname);
+ return(1);
+ }
+ goodsec = NULL;
switch (sec) {
- case (SEC_RETURN_VALUES):
+ case SEC_ERRORS:
+ if (*mdoc->meta.msec == '4')
+ break;
+ goodsec = "2, 3, 4, 9";
/* FALLTHROUGH */
- case (SEC_ERRORS):
+ case SEC_RETURN_VALUES:
/* FALLTHROUGH */
- case (SEC_LIBRARY):
+ case SEC_LIBRARY:
if (*mdoc->meta.msec == '2')
break;
if (*mdoc->meta.msec == '3')
break;
+ if (NULL == goodsec)
+ goodsec = "2, 3, 9";
+ /* FALLTHROUGH */
+ case SEC_CONTEXT:
if (*mdoc->meta.msec == '9')
break;
- mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
- mdoc->last->line, mdoc->last->pos, buf);
+ if (NULL == goodsec)
+ goodsec = "9";
+ mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s for %s only", secname, goodsec);
break;
default:
break;
}
+ free(secname);
return(1);
}
@@ -2067,18 +2024,27 @@ post_ignpar(POST_ARGS)
{
struct mdoc_node *np;
+ hwarn_ge1(mdoc);
+ post_hyph(mdoc);
+
if (MDOC_BODY != mdoc->last->type)
return(1);
if (NULL != (np = mdoc->last->child))
if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
- mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ mdoc->parse, np->line, np->pos,
+ "%s after %s", mdoc_macronames[np->tok],
+ mdoc_macronames[mdoc->last->tok]);
mdoc_node_delete(mdoc, np);
}
if (NULL != (np = mdoc->last->last))
if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
- mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
+ np->line, np->pos, "%s at the end of %s",
+ mdoc_macronames[np->tok],
+ mdoc_macronames[mdoc->last->tok]);
mdoc_node_delete(mdoc, np);
}
@@ -2094,7 +2060,7 @@ pre_par(PRE_ARGS)
if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
return(1);
- /*
+ /*
* Don't allow prior `Lp' or `Pp' prior to a paragraph-type
* block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
*/
@@ -2110,7 +2076,10 @@ pre_par(PRE_ARGS)
if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
return(1);
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "%s before %s", mdoc_macronames[mdoc->last->tok],
+ mdoc_macronames[n->tok]);
mdoc_node_delete(mdoc, mdoc->last);
return(1);
}
@@ -2118,25 +2087,32 @@ pre_par(PRE_ARGS)
static int
post_par(POST_ARGS)
{
+ struct mdoc_node *np;
+
+ if (mdoc->last->tok == MDOC_sp)
+ ewarn_le1(mdoc);
+ else
+ ewarn_eq0(mdoc);
if (MDOC_ELEM != mdoc->last->type &&
MDOC_BLOCK != mdoc->last->type)
return(1);
- if (NULL == mdoc->last->prev) {
- if (MDOC_Sh != mdoc->last->parent->tok &&
- MDOC_Ss != mdoc->last->parent->tok)
+ if (NULL == (np = mdoc->last->prev)) {
+ np = mdoc->last->parent;
+ if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
return(1);
} else {
- if (MDOC_Pp != mdoc->last->prev->tok &&
- MDOC_Lp != mdoc->last->prev->tok &&
+ if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
(MDOC_br != mdoc->last->tok ||
- (MDOC_sp != mdoc->last->prev->tok &&
- MDOC_br != mdoc->last->prev->tok)))
+ (MDOC_sp != np->tok && MDOC_br != np->tok)))
return(1);
}
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "%s after %s", mdoc_macronames[mdoc->last->tok],
+ mdoc_macronames[np->tok]);
mdoc_node_delete(mdoc, mdoc->last);
return(1);
}
@@ -2145,6 +2121,8 @@ static int
pre_literal(PRE_ARGS)
{
+ pre_display(mdoc, n);
+
if (MDOC_BODY != n->type)
return(1);
@@ -2154,10 +2132,10 @@ pre_literal(PRE_ARGS)
*/
switch (n->tok) {
- case (MDOC_Dl):
+ case MDOC_Dl:
mdoc->flags |= MDOC_LITERAL;
break;
- case (MDOC_Bd):
+ case MDOC_Bd:
if (DISP_literal == n->norm->Bd.type)
mdoc->flags |= MDOC_LITERAL;
if (DISP_unfilled == n->norm->Bd.type)
@@ -2167,37 +2145,37 @@ pre_literal(PRE_ARGS)
abort();
/* NOTREACHED */
}
-
+
return(1);
}
static int
post_dd(POST_ARGS)
{
- char buf[DATESIZE];
struct mdoc_node *n;
- int c;
+ char *datestr;
if (mdoc->meta.date)
free(mdoc->meta.date);
n = mdoc->last;
if (NULL == n->child || '\0' == n->child->string[0]) {
- mdoc->meta.date = mandoc_normdate
- (mdoc->parse, NULL, n->line, n->pos);
- return(1);
+ mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
+ mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
+ goto out;
}
- buf[0] = '\0';
- if (-1 == (c = concat(buf, n->child, DATESIZE))) {
- mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
- return(0);
+ datestr = NULL;
+ mdoc_deroff(&datestr, n);
+ if (mdoc->quick)
+ mdoc->meta.date = datestr;
+ else {
+ mdoc->meta.date = mandoc_normdate(mdoc->parse,
+ datestr, n->line, n->pos);
+ free(datestr);
}
-
- assert(c);
- mdoc->meta.date = mandoc_normdate
- (mdoc->parse, buf, n->line, n->pos);
-
+out:
+ mdoc_node_delete(mdoc, n);
return(1);
}
@@ -2210,63 +2188,57 @@ post_dt(POST_ARGS)
n = mdoc->last;
- if (mdoc->meta.title)
- free(mdoc->meta.title);
- if (mdoc->meta.vol)
- free(mdoc->meta.vol);
- if (mdoc->meta.arch)
- free(mdoc->meta.arch);
+ free(mdoc->meta.title);
+ free(mdoc->meta.msec);
+ free(mdoc->meta.vol);
+ free(mdoc->meta.arch);
- mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
+ mdoc->meta.title = NULL;
+ mdoc->meta.msec = NULL;
+ mdoc->meta.vol = NULL;
+ mdoc->meta.arch = NULL;
- /* First make all characters uppercase. */
+ /* First check that all characters are uppercase. */
if (NULL != (nn = n->child))
for (p = nn->string; *p; p++) {
if (toupper((unsigned char)*p) == *p)
continue;
-
- /*
- * FIXME: don't be lazy: have this make all
- * characters be uppercase and just warn once.
- */
- mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
+ mandoc_vmsg(MANDOCERR_TITLE_CASE,
+ mdoc->parse, nn->line,
+ nn->pos + (p - nn->string),
+ "Dt %s", nn->string);
break;
}
- /* Handles: `.Dt'
- * --> title = unknown, volume = local, msec = 0, arch = NULL
- */
+ /* No argument: msec and arch remain NULL. */
if (NULL == (nn = n->child)) {
- /* XXX: make these macro values. */
- /* FIXME: warn about missing values. */
- mdoc->meta.title = mandoc_strdup("UNKNOWN");
+ mandoc_msg(MANDOCERR_DT_NOTITLE,
+ mdoc->parse, n->line, n->pos, "Dt");
+ mdoc->meta.title = mandoc_strdup("UNTITLED");
mdoc->meta.vol = mandoc_strdup("LOCAL");
- mdoc->meta.msec = mandoc_strdup("1");
- return(1);
+ goto out;
}
- /* Handles: `.Dt TITLE'
- * --> title = TITLE, volume = local, msec = 0, arch = NULL
- */
+ /* One argument: msec and arch remain NULL. */
- mdoc->meta.title = mandoc_strdup
- ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
+ mdoc->meta.title = mandoc_strdup(
+ '\0' == nn->string[0] ? "UNTITLED" : nn->string);
if (NULL == (nn = nn->next)) {
- /* FIXME: warn about missing msec. */
- /* XXX: make this a macro value. */
+ mandoc_vmsg(MANDOCERR_MSEC_MISSING,
+ mdoc->parse, n->line, n->pos,
+ "Dt %s", mdoc->meta.title);
mdoc->meta.vol = mandoc_strdup("LOCAL");
- mdoc->meta.msec = mandoc_strdup("1");
- return(1);
+ goto out;
}
/* Handles: `.Dt TITLE SEC'
- * --> title = TITLE, volume = SEC is msec ?
- * format(msec) : SEC,
- * msec = SEC is msec ? atoi(msec) : 0,
- * arch = NULL
+ * title = TITLE,
+ * volume = SEC is msec ? format(msec) : SEC,
+ * msec = SEC is msec ? atoi(msec) : 0,
+ * arch = NULL
*/
cp = mandoc_a2msec(nn->string);
@@ -2274,19 +2246,20 @@ post_dt(POST_ARGS)
mdoc->meta.vol = mandoc_strdup(cp);
mdoc->meta.msec = mandoc_strdup(nn->string);
} else {
- mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
+ mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
+ nn->line, nn->pos, "Dt ... %s", nn->string);
mdoc->meta.vol = mandoc_strdup(nn->string);
mdoc->meta.msec = mandoc_strdup(nn->string);
- }
+ }
if (NULL == (nn = nn->next))
- return(1);
+ goto out;
/* Handles: `.Dt TITLE SEC VOL'
- * --> title = TITLE, volume = VOL is vol ?
- * format(VOL) :
- * VOL is arch ? format(arch) :
- * VOL
+ * title = TITLE,
+ * volume = VOL is vol ? format(VOL) :
+ * VOL is arch ? format(arch) :
+ * VOL
*/
cp = mdoc_a2vol(nn->string);
@@ -2296,32 +2269,18 @@ post_dt(POST_ARGS)
} else {
cp = mdoc_a2arch(nn->string);
if (NULL == cp) {
- mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
+ mandoc_vmsg(MANDOCERR_ARCH_BAD, mdoc->parse,
+ nn->line, nn->pos, "Dt ... %s", nn->string);
free(mdoc->meta.vol);
mdoc->meta.vol = mandoc_strdup(nn->string);
- } else
+ } else
mdoc->meta.arch = mandoc_strdup(cp);
- }
+ }
/* Ignore any subsequent parameters... */
/* FIXME: warn about subsequent parameters. */
-
- return(1);
-}
-
-static int
-post_prol(POST_ARGS)
-{
- /*
- * Remove prologue macros from the document after they're
- * processed. The final document uses mdoc_meta for these
- * values and discards the originals.
- */
-
- mdoc_node_delete(mdoc, mdoc->last);
- if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
- mdoc->flags |= MDOC_PBODY;
-
+out:
+ mdoc_node_delete(mdoc, n);
return(1);
}
@@ -2330,7 +2289,7 @@ post_bx(POST_ARGS)
{
struct mdoc_node *n;
- /*
+ /*
* Make `Bx's second argument always start with an uppercase
* letter. Groff checks if it's an "accepted" term, but we just
* uppercase blindly.
@@ -2338,8 +2297,7 @@ post_bx(POST_ARGS)
n = mdoc->last->child;
if (n && NULL != (n = n->next))
- *n->string = (char)toupper
- ((unsigned char)*n->string);
+ *n->string = (char)toupper((unsigned char)*n->string);
return(1);
}
@@ -2347,12 +2305,11 @@ post_bx(POST_ARGS)
static int
post_os(POST_ARGS)
{
- struct mdoc_node *n;
- char buf[BUFSIZ];
- int c;
#ifndef OSNAME
struct utsname utsname;
+ static char *defbuf;
#endif
+ struct mdoc_node *n;
n = mdoc->last;
@@ -2363,114 +2320,74 @@ post_os(POST_ARGS)
* 2. the -Ios=foo command line argument, if provided
* 3. -DOSNAME="\"foo\"", if provided during compilation
* 4. "sysname release" from uname(3)
- */
+ */
free(mdoc->meta.os);
+ mdoc->meta.os = NULL;
+ mdoc_deroff(&mdoc->meta.os, n);
+ if (mdoc->meta.os)
+ goto out;
- buf[0] = '\0';
- if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
- mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
- return(0);
+ if (mdoc->defos) {
+ mdoc->meta.os = mandoc_strdup(mdoc->defos);
+ goto out;
}
- assert(c);
-
- if ('\0' == buf[0]) {
- if (mdoc->defos) {
- mdoc->meta.os = mandoc_strdup(mdoc->defos);
- return(1);
- }
#ifdef OSNAME
- if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
+ mdoc->meta.os = mandoc_strdup(OSNAME);
#else /*!OSNAME */
+ if (NULL == defbuf) {
if (-1 == uname(&utsname)) {
- mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
- mdoc->meta.os = mandoc_strdup("UNKNOWN");
- return(post_prol(mdoc));
- }
-
- if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
- if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
- if (0 == strcmp(utsname.sysname, "FreeBSD"))
- strtok(utsname.release, "-");
- if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
-#endif /*!OSNAME*/
+ mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
+ n->line, n->pos, "Os");
+ defbuf = mandoc_strdup("UNKNOWN");
+ } else
+ mandoc_asprintf(&defbuf, "%s %s",
+ utsname.sysname, utsname.release);
}
+ mdoc->meta.os = mandoc_strdup(defbuf);
+#endif /*!OSNAME*/
- mdoc->meta.os = mandoc_strdup(buf);
+out:
+ mdoc_node_delete(mdoc, n);
return(1);
}
+/*
+ * If no argument is provided,
+ * fill in the name of the current manual page.
+ */
static int
-post_std(POST_ARGS)
+post_ex(POST_ARGS)
{
- struct mdoc_node *nn, *n;
+ struct mdoc_node *n;
n = mdoc->last;
- /*
- * Macros accepting `-std' as an argument have the name of the
- * current document (`Nm') filled in as the argument if it's not
- * provided.
- */
-
if (n->child)
return(1);
- if (NULL == mdoc->meta.name)
+ if (mdoc->meta.name == NULL) {
+ mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
+ n->line, n->pos, "Ex");
return(1);
-
- nn = n;
+ }
+
mdoc->next = MDOC_NEXT_CHILD;
if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
return(0);
- mdoc->last = nn;
- return(1);
-}
-
-/*
- * Concatenate a node, stopping at the first non-text.
- * Concatenation is separated by a single whitespace.
- * Returns -1 on fatal (string overrun) error, 0 if child nodes were
- * encountered, 1 otherwise.
- */
-static int
-concat(char *p, const struct mdoc_node *n, size_t sz)
-{
-
- for ( ; NULL != n; n = n->next) {
- if (MDOC_TEXT != n->type)
- return(0);
- if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
- return(-1);
- if (strlcat(p, n->string, sz) >= sz)
- return(-1);
- concat(p, n->child, sz);
- }
-
+ mdoc->last = n;
return(1);
}
-static enum mdoc_sec
+static enum mdoc_sec
a2sec(const char *p)
{
int i;
- for (i = 0; i < (int)SEC__MAX; i++)
+ for (i = 0; i < (int)SEC__MAX; i++)
if (secnames[i] && 0 == strcmp(p, secnames[i]))
return((enum mdoc_sec)i);
@@ -2482,87 +2399,87 @@ macro2len(enum mdoct macro)
{
switch (macro) {
- case(MDOC_Ad):
+ case MDOC_Ad:
return(12);
- case(MDOC_Ao):
+ case MDOC_Ao:
return(12);
- case(MDOC_An):
+ case MDOC_An:
return(12);
- case(MDOC_Aq):
+ case MDOC_Aq:
return(12);
- case(MDOC_Ar):
+ case MDOC_Ar:
return(12);
- case(MDOC_Bo):
+ case MDOC_Bo:
return(12);
- case(MDOC_Bq):
+ case MDOC_Bq:
return(12);
- case(MDOC_Cd):
+ case MDOC_Cd:
return(12);
- case(MDOC_Cm):
+ case MDOC_Cm:
return(10);
- case(MDOC_Do):
+ case MDOC_Do:
return(10);
- case(MDOC_Dq):
+ case MDOC_Dq:
return(12);
- case(MDOC_Dv):
+ case MDOC_Dv:
return(12);
- case(MDOC_Eo):
+ case MDOC_Eo:
return(12);
- case(MDOC_Em):
+ case MDOC_Em:
return(10);
- case(MDOC_Er):
+ case MDOC_Er:
return(17);
- case(MDOC_Ev):
+ case MDOC_Ev:
return(15);
- case(MDOC_Fa):
+ case MDOC_Fa:
return(12);
- case(MDOC_Fl):
+ case MDOC_Fl:
return(10);
- case(MDOC_Fo):
+ case MDOC_Fo:
return(16);
- case(MDOC_Fn):
+ case MDOC_Fn:
return(16);
- case(MDOC_Ic):
+ case MDOC_Ic:
return(10);
- case(MDOC_Li):
+ case MDOC_Li:
return(16);
- case(MDOC_Ms):
+ case MDOC_Ms:
return(6);
- case(MDOC_Nm):
+ case MDOC_Nm:
return(10);
- case(MDOC_No):
+ case MDOC_No:
return(12);
- case(MDOC_Oo):
+ case MDOC_Oo:
return(10);
- case(MDOC_Op):
+ case MDOC_Op:
return(14);
- case(MDOC_Pa):
+ case MDOC_Pa:
return(32);
- case(MDOC_Pf):
+ case MDOC_Pf:
return(12);
- case(MDOC_Po):
+ case MDOC_Po:
return(12);
- case(MDOC_Pq):
+ case MDOC_Pq:
return(12);
- case(MDOC_Ql):
+ case MDOC_Ql:
return(16);
- case(MDOC_Qo):
+ case MDOC_Qo:
return(12);
- case(MDOC_So):
+ case MDOC_So:
return(12);
- case(MDOC_Sq):
+ case MDOC_Sq:
return(12);
- case(MDOC_Sy):
+ case MDOC_Sy:
return(6);
- case(MDOC_Sx):
+ case MDOC_Sx:
return(16);
- case(MDOC_Tn):
+ case MDOC_Tn:
return(10);
- case(MDOC_Va):
+ case MDOC_Va:
return(12);
- case(MDOC_Vt):
+ case MDOC_Vt:
return(12);
- case(MDOC_Xr):
+ case MDOC_Xr:
return(10);
default:
break;
diff --git a/contrib/mdocml/msec.c b/contrib/mdocml/msec.c
index dd7d11c..3db04d6 100644
--- a/contrib/mdocml/msec.c
+++ b/contrib/mdocml/msec.c
@@ -1,4 +1,4 @@
-/* $Id: msec.c,v 1.10 2011/12/02 01:37:14 schwarze Exp $ */
+/* $Id: msec.c,v 1.11 2014/03/23 11:25:26 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,7 +18,6 @@
#include "config.h"
#endif
-#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
diff --git a/contrib/mdocml/out.c b/contrib/mdocml/out.c
index c931664..0e5a63c 100644
--- a/contrib/mdocml/out.c
+++ b/contrib/mdocml/out.c
@@ -1,4 +1,4 @@
-/* $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
+/* $Id: out.c,v 1.49 2014/08/01 19:25:52 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -28,6 +28,7 @@
#include <string.h>
#include <time.h>
+#include "mandoc_aux.h"
#include "mandoc.h"
#include "out.h"
@@ -38,7 +39,8 @@ static void tblcalc_literal(struct rofftbl *, struct roffcol *,
static void tblcalc_number(struct rofftbl *, struct roffcol *,
const struct tbl_opts *, const struct tbl_dat *);
-/*
+
+/*
* Convert a `scaling unit' to a consistent form, or fail. Scaling
* units are documented in groff.7, mdoc.7, man.7.
*/
@@ -55,10 +57,10 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
i = hasd = 0;
switch (*src) {
- case ('+'):
+ case '+':
src++;
break;
- case ('-'):
+ case '-':
buf[i++] = *src++;
break;
default:
@@ -86,39 +88,39 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
buf[i] = '\0';
switch (*src) {
- case ('c'):
+ case 'c':
unit = SCALE_CM;
break;
- case ('i'):
+ case 'i':
unit = SCALE_IN;
break;
- case ('P'):
+ case 'P':
unit = SCALE_PC;
break;
- case ('p'):
+ case 'p':
unit = SCALE_PT;
break;
- case ('f'):
+ case 'f':
unit = SCALE_FS;
break;
- case ('v'):
+ case 'v':
unit = SCALE_VS;
break;
- case ('m'):
+ case 'm':
unit = SCALE_EM;
break;
- case ('\0'):
+ case '\0':
if (SCALE_MAX == def)
return(0);
unit = SCALE_BU;
break;
- case ('u'):
+ case 'u':
unit = SCALE_BU;
break;
- case ('M'):
+ case 'M':
unit = SCALE_MM;
break;
- case ('n'):
+ case 'n':
unit = SCALE_EN;
break;
default:
@@ -126,8 +128,8 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
}
/* FIXME: do this in the caller. */
- if ((dst->scale = atof(buf)) < 0)
- dst->scale = 0;
+ if ((dst->scale = atof(buf)) < 0.0)
+ dst->scale = 0.0;
dst->unit = unit;
return(1);
}
@@ -152,8 +154,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
*/
assert(NULL == tbl->cols);
- tbl->cols = mandoc_calloc
- ((size_t)sp->opts->cols, sizeof(struct roffcol));
+ tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
+ sizeof(struct roffcol));
for ( ; sp; sp = sp->next) {
if (TBL_SPAN_DATA != sp->pos)
@@ -186,26 +188,26 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
/* Branch down into data sub-types. */
switch (dp->layout->pos) {
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
/* FALLTHROUGH */
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
sz = (*tbl->len)(1, tbl->arg);
if (col->width < sz)
col->width = sz;
break;
- case (TBL_CELL_LONG):
+ case TBL_CELL_LONG:
/* FALLTHROUGH */
- case (TBL_CELL_CENTRE):
+ case TBL_CELL_CENTRE:
/* FALLTHROUGH */
- case (TBL_CELL_LEFT):
+ case TBL_CELL_LEFT:
/* FALLTHROUGH */
- case (TBL_CELL_RIGHT):
+ case TBL_CELL_RIGHT:
tblcalc_literal(tbl, col, dp);
break;
- case (TBL_CELL_NUMBER):
+ case TBL_CELL_NUMBER:
tblcalc_number(tbl, col, opts, dp);
break;
- case (TBL_CELL_DOWN):
+ case TBL_CELL_DOWN:
break;
default:
abort();
@@ -231,7 +233,7 @@ static void
tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_opts *opts, const struct tbl_dat *dp)
{
- int i;
+ int i;
size_t sz, psz, ssz, d;
const char *str;
char *cp;
diff --git a/contrib/mdocml/out.h b/contrib/mdocml/out.h
index 1c18c6c..514db3f 100644
--- a/contrib/mdocml/out.h
+++ b/contrib/mdocml/out.h
@@ -1,4 +1,4 @@
-/* $Id: out.h,v 1.21 2011/07/17 15:24:25 kristaps Exp $ */
+/* $Id: out.h,v 1.22 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -63,8 +63,8 @@ __BEGIN_DECLS
(p)->scale = (v); } \
while (/* CONSTCOND */ 0)
-int a2roffsu(const char *, struct roffsu *, enum roffscale);
-void tblcalc(struct rofftbl *tbl, const struct tbl_span *);
+int a2roffsu(const char *, struct roffsu *, enum roffscale);
+void tblcalc(struct rofftbl *tbl, const struct tbl_span *);
__END_DECLS
diff --git a/contrib/mdocml/read.c b/contrib/mdocml/read.c
index 511ba7d..9466838 100644
--- a/contrib/mdocml/read.c
+++ b/contrib/mdocml/read.c
@@ -1,7 +1,8 @@
-/* $Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */
+/* $Id: read.c,v 1.79 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,6 +27,7 @@
#include <assert.h>
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
@@ -35,6 +37,7 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "mdoc.h"
#include "man.h"
@@ -43,7 +46,7 @@
#define REPARSE_LIMIT 1000
struct buf {
- char *buf; /* binary input buffer */
+ char *buf; /* binary input buffer */
size_t sz; /* size of binary buffer */
};
@@ -51,24 +54,25 @@ struct mparse {
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
int line; /* line number in the file */
- enum mparset inttype; /* which parser to use */
+ int options; /* parser options */
struct man *pman; /* persistent man parser */
struct mdoc *pmdoc; /* persistent mdoc parser */
struct man *man; /* man parser */
struct mdoc *mdoc; /* mdoc parser */
struct roff *roff; /* roff parser (!NULL) */
+ char *sodest; /* filename pointed to by .so */
int reparse_count; /* finite interp. stack */
mandocmsg mmsg; /* warning/error message handler */
- void *arg; /* argument to mmsg */
- const char *file;
+ const char *file;
struct buf *secondary;
- char *defos; /* default operating system */
+ const char *defos; /* default operating system */
};
static void resize_buf(struct buf *, size_t);
static void mparse_buf_r(struct mparse *, struct buf, int);
static void pset(const char *, int, struct mparse *);
-static int read_whole_file(const char *, int, struct buf *, int *);
+static int read_whole_file(struct mparse *, const char *, int,
+ struct buf *, int *);
static void mparse_end(struct mparse *);
static void mparse_parse_buffer(struct mparse *, struct buf,
const char *);
@@ -89,67 +93,79 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"generic warning",
/* related to the prologue */
- "no title in document",
- "document title should be all caps",
+ "missing manual title, using UNTITLED",
+ "missing manual title, using \"\"",
+ "lower case character in document title",
+ "missing manual section, using \"\"",
"unknown manual section",
"unknown manual volume or arch",
- "date missing, using today's date",
+ "missing date, using today's date",
"cannot parse date, using it verbatim",
- "prologue macros out of order",
+ "missing Os macro, using \"\"",
"duplicate prologue macro",
- "macro not allowed in prologue",
- "macro not allowed in body",
+ "late prologue macro",
+ "skipping late title macro",
+ "prologue macros out of order",
/* related to document structure */
".so is fragile, better use ln(1)",
- "NAME section must come first",
+ "no document body",
+ "content before first section header",
+ "first section is not \"NAME\"",
"bad NAME section contents",
"sections out of conventional order",
- "duplicate section name",
- "section header suited to sections 2, 3, and 9 only",
+ "duplicate section title",
+ "unexpected section",
/* related to macros and nesting */
- "skipping obsolete macro",
+ "obsolete macro",
"skipping paragraph macro",
"moving paragraph macro out of list",
"skipping no-space macro",
"blocks badly nested",
- "child violates parent syntax",
"nested displays are not portable",
- "already in literal mode",
+ "moving content out of list",
+ ".Vt block has child macro",
+ "fill mode already enabled, skipping",
+ "fill mode already disabled, skipping",
"line scope broken",
/* related to missing macro arguments */
+ "skipping empty request",
+ "conditional request controls empty scope",
"skipping empty macro",
+ "empty argument, using 0n",
"argument count wrong",
- "missing display type",
- "list type must come first",
- "tag lists require a width argument",
- "missing font type",
- "skipping end of block that is not open",
+ "missing display type, using -ragged",
+ "list type is not the first argument",
+ "missing -width in -tag list, using 8n",
+ "missing utility name, using \"\"",
+ "empty head in list item",
+ "empty list item",
+ "missing font type, using \\fR",
+ "unknown font type, using \\fR",
+ "missing -std argument, adding it",
/* related to bad macro arguments */
- "skipping argument",
+ "unterminated quoted argument",
"duplicate argument",
- "duplicate display type",
- "duplicate list type",
+ "skipping duplicate argument",
+ "skipping duplicate display type",
+ "skipping duplicate list type",
+ "skipping -width argument",
"unknown AT&T UNIX version",
- "bad Boolean value",
- "unknown font",
- "unknown standard specifier",
- "bad width argument",
+ "invalid content in Rs block",
+ "invalid Boolean argument",
+ "unknown font, skipping request",
/* related to plain text */
- "blank line in non-literal context",
- "tab in non-literal context",
- "end of line whitespace",
+ "blank line in fill mode, using .sp",
+ "tab in filled text",
+ "whitespace at end of input line",
"bad comment style",
- "bad escape sequence",
- "unterminated quoted string",
+ "invalid escape sequence",
+ "undefined string, using \"\"",
- /* related to equations */
- "unexpected literal in equation",
-
"generic error",
/* related to equations */
@@ -169,39 +185,38 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"data block still open",
"ignoring extra data cells",
+ /* related to document structure and macros */
"input stack limit exceeded, infinite loop?",
"skipping bad character",
- "escaped character not allowed in a name",
- "manual name not yet set",
- "skipping text before the first section header",
"skipping unknown macro",
- "NOT IMPLEMENTED, please use groff: skipping request",
- "argument count wrong",
+ "skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
- "missing end of block",
- "scope open on exit",
- "uname(3) system call failed",
- "macro requires line argument(s)",
- "macro requires body argument(s)",
- "macro requires argument(s)",
- "request requires a numeric argument",
- "missing list type",
- "line argument(s) will be lost",
- "body argument(s) will be lost",
+ "inserting missing end of block",
+ "appending missing end of block",
+
+ /* related to request and macro arguments */
+ "escaped character not allowed in a name",
+ "argument count wrong",
+ "missing list type, using -item",
+ "missing manual name, using \"\"",
+ "uname(3) system call failed, using UNKNOWN",
+ "unknown standard specifier",
+ "skipping request without numeric argument",
+ "skipping all arguments",
+ "skipping excess arguments",
"generic fatal error",
- "not a manual",
- "column syntax is inconsistent",
- "NOT IMPLEMENTED: .Bd -file",
- "argument count wrong, violates syntax",
- "child violates parent syntax",
- "argument count wrong, violates syntax",
+ "input too large",
+ "NOT IMPLEMENTED: Bd -file",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
- "no document body",
- "no document prologue",
- "static buffer exhausted",
+ ".so request failed",
+
+ /* system errors */
+ NULL,
+ "cannot stat file",
+ "cannot read file",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
@@ -214,6 +229,7 @@ static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"SYSERR"
};
+
static void
resize_buf(struct buf *buf, size_t initial)
{
@@ -246,35 +262,27 @@ pset(const char *buf, int pos, struct mparse *curp)
return;
}
- switch (curp->inttype) {
- case (MPARSE_MDOC):
- if (NULL == curp->pmdoc)
- curp->pmdoc = mdoc_alloc(curp->roff, curp,
- curp->defos);
- assert(curp->pmdoc);
+ if (MPARSE_MDOC & curp->options) {
curp->mdoc = curp->pmdoc;
return;
- case (MPARSE_MAN):
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp);
- assert(curp->pman);
+ } else if (MPARSE_MAN & curp->options) {
curp->man = curp->pman;
return;
- default:
- break;
}
if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
- if (NULL == curp->pmdoc)
- curp->pmdoc = mdoc_alloc(curp->roff, curp,
- curp->defos);
+ if (NULL == curp->pmdoc)
+ curp->pmdoc = mdoc_alloc(
+ curp->roff, curp, curp->defos,
+ MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pmdoc);
curp->mdoc = curp->pmdoc;
return;
- }
+ }
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp);
+ if (NULL == curp->pman)
+ curp->pman = man_alloc(curp->roff, curp,
+ MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pman);
curp->man = curp->pman;
}
@@ -297,8 +305,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
memset(&ln, 0, sizeof(struct buf));
- lnn = curp->line;
- pos = 0;
+ lnn = curp->line;
+ pos = 0;
for (i = 0; i < (int)blk.sz; ) {
if (0 == pos && '\0' == blk.buf[i])
@@ -335,7 +343,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
if (pos + 2 >= (int)ln.sz)
resize_buf(&ln, 256);
- /*
+ /*
* Warn about bogus characters. If you're using
* non-ASCII encoding, you're screwing your
* readers. Since I'd rather this not happen,
@@ -346,10 +354,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
c = (unsigned char) blk.buf[i];
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ if ( ! (isascii(c) &&
+ (isgraph(c) || isblank(c)))) {
+ mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ curp->line, pos, "0x%x", c);
i++;
ln.buf[pos++] = '?';
continue;
@@ -403,10 +411,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
c = (unsigned char) blk.buf[i+1];
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ if ( ! (isascii(c) &&
+ (isgraph(c) || isblank(c)))) {
+ mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ curp->line, pos, "0x%x", c);
i += 2;
ln.buf[pos++] = '?';
continue;
@@ -418,7 +426,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
ln.buf[pos++] = blk.buf[i++];
}
- if (pos >= (int)ln.sz)
+ if (pos >= (int)ln.sz)
resize_buf(&ln, 256);
ln.buf[pos] = '\0';
@@ -441,13 +449,12 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
*/
if (curp->secondary) {
- curp->secondary->buf =
- mandoc_realloc
- (curp->secondary->buf,
- curp->secondary->sz + pos + 2);
- memcpy(curp->secondary->buf +
- curp->secondary->sz,
- ln.buf, pos);
+ curp->secondary->buf = mandoc_realloc(
+ curp->secondary->buf,
+ curp->secondary->sz + pos + 2);
+ memcpy(curp->secondary->buf +
+ curp->secondary->sz,
+ ln.buf, pos);
curp->secondary->sz += pos;
curp->secondary->buf
[curp->secondary->sz] = '\n';
@@ -456,41 +463,50 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
[curp->secondary->sz] = '\0';
}
rerun:
- rr = roff_parseln
- (curp->roff, curp->line,
- &ln.buf, &ln.sz, of, &of);
+ rr = roff_parseln(curp->roff, curp->line,
+ &ln.buf, &ln.sz, of, &of);
switch (rr) {
- case (ROFF_REPARSE):
+ case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count)
mparse_buf_r(curp, ln, 0);
else
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
- curp->line, pos, NULL);
+ curp->line, pos, NULL);
pos = 0;
continue;
- case (ROFF_APPEND):
+ case ROFF_APPEND:
pos = (int)strlen(ln.buf);
continue;
- case (ROFF_RERUN):
+ case ROFF_RERUN:
goto rerun;
- case (ROFF_IGN):
+ case ROFF_IGN:
pos = 0;
continue;
- case (ROFF_ERR):
+ case ROFF_ERR:
assert(MANDOCLEVEL_FATAL <= curp->file_status);
break;
- case (ROFF_SO):
+ case ROFF_SO:
+ if (0 == (MPARSE_SO & curp->options) &&
+ (i >= (int)blk.sz || '\0' == blk.buf[i])) {
+ curp->sodest = mandoc_strdup(ln.buf + of);
+ free(ln.buf);
+ return;
+ }
/*
* We remove `so' clauses from our lookaside
* buffer because we're going to descend into
* the file recursively.
*/
- if (curp->secondary)
+ if (curp->secondary)
curp->secondary->sz -= pos + 1;
mparse_readfd(curp, -1, ln.buf + of);
- if (MANDOCLEVEL_FATAL <= curp->file_status)
+ if (MANDOCLEVEL_FATAL <= curp->file_status) {
+ mandoc_vmsg(MANDOCERR_SO_FAIL,
+ curp, curp->line, pos,
+ ".so %s", ln.buf + of);
break;
+ }
pos = 0;
continue;
default:
@@ -515,7 +531,7 @@ rerun:
if ( ! (curp->man || curp->mdoc))
pset(ln.buf + of, pos - of, curp);
- /*
+ /*
* Lastly, push down into the parsers themselves. One
* of these will have already been set in the pset()
* routine.
@@ -531,28 +547,29 @@ rerun:
if (ROFF_TBL == rr)
while (NULL != (span = roff_span(curp->roff))) {
rc = curp->man ?
- man_addspan(curp->man, span) :
- mdoc_addspan(curp->mdoc, span);
+ man_addspan(curp->man, span) :
+ mdoc_addspan(curp->mdoc, span);
if (0 == rc)
break;
}
else if (ROFF_EQN == rr)
- rc = curp->mdoc ?
- mdoc_addeqn(curp->mdoc,
- roff_eqn(curp->roff)) :
- man_addeqn(curp->man,
- roff_eqn(curp->roff));
+ rc = curp->mdoc ?
+ mdoc_addeqn(curp->mdoc,
+ roff_eqn(curp->roff)) :
+ man_addeqn(curp->man,
+ roff_eqn(curp->roff));
else if (curp->man || curp->mdoc)
rc = curp->man ?
- man_parseln(curp->man,
- curp->line, ln.buf, of) :
- mdoc_parseln(curp->mdoc,
- curp->line, ln.buf, of);
+ man_parseln(curp->man,
+ curp->line, ln.buf, of) :
+ mdoc_parseln(curp->mdoc,
+ curp->line, ln.buf, of);
if (0 == rc) {
assert(MANDOCLEVEL_FATAL <= curp->file_status);
break;
- }
+ } else if (2 == rc)
+ break;
/* Temporary buffers typically are not full. */
@@ -568,7 +585,8 @@ rerun:
}
static int
-read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
+read_whole_file(struct mparse *curp, const char *file, int fd,
+ struct buf *fb, int *with_mmap)
{
size_t off;
ssize_t ssz;
@@ -576,7 +594,10 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
#ifdef HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
- perror(file);
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_SYSSTAT, curp->file_status,
+ file, 0, 0, strerror(errno));
return(0);
}
@@ -589,7 +610,10 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
if (S_ISREG(st.st_mode)) {
if (st.st_size >= (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", file);
+ curp->file_status = MANDOCLEVEL_FATAL;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_TOOLARGE,
+ curp->file_status, file, 0, 0, NULL);
return(0);
}
*with_mmap = 1;
@@ -612,7 +636,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", file);
+ curp->file_status = MANDOCLEVEL_FATAL;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_TOOLARGE,
+ curp->file_status,
+ file, 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
@@ -623,7 +651,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
return(1);
}
if (ssz == -1) {
- perror(file);
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_SYSREAD,
+ curp->file_status, file, 0, 0,
+ strerror(errno));
break;
}
off += (size_t)ssz;
@@ -641,6 +673,19 @@ mparse_end(struct mparse *curp)
if (MANDOCLEVEL_FATAL <= curp->file_status)
return;
+ if (curp->mdoc == NULL &&
+ curp->man == NULL &&
+ curp->sodest == NULL) {
+ if (curp->options & MPARSE_MDOC)
+ curp->mdoc = curp->pmdoc;
+ else {
+ if (curp->pman == NULL)
+ curp->pman = man_alloc(curp->roff, curp,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+ curp->man = curp->pman;
+ }
+ }
+
if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
assert(MANDOCLEVEL_FATAL <= curp->file_status);
return;
@@ -651,12 +696,6 @@ mparse_end(struct mparse *curp)
return;
}
- if ( ! (curp->man || curp->mdoc)) {
- mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
- curp->file_status = MANDOCLEVEL_FATAL;
- return;
- }
-
roff_endparse(curp->roff);
}
@@ -704,12 +743,15 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
struct buf blk;
int with_mmap;
- if (-1 == fd)
- if (-1 == (fd = open(file, O_RDONLY, 0))) {
- perror(file);
- curp->file_status = MANDOCLEVEL_SYSERR;
- goto out;
- }
+ if (-1 == fd && -1 == (fd = open(file, O_RDONLY, 0))) {
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_SYSOPEN,
+ curp->file_status,
+ file, 0, 0, strerror(errno));
+ goto out;
+ }
+
/*
* Run for each opened file; may be called more than once for
* each full parse sequence if the opened file is nested (i.e.,
@@ -717,10 +759,8 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
* the parse phase for the file.
*/
- if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
- curp->file_status = MANDOCLEVEL_SYSERR;
+ if ( ! read_whole_file(curp, file, fd, &blk, &with_mmap))
goto out;
- }
mparse_parse_buffer(curp, blk, file);
@@ -738,8 +778,8 @@ out:
}
struct mparse *
-mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
- mandocmsg mmsg, void *arg, char *defos)
+mparse_alloc(int options, enum mandoclevel wlevel,
+ mandocmsg mmsg, const char *defos)
{
struct mparse *curp;
@@ -747,13 +787,20 @@ mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
curp = mandoc_calloc(1, sizeof(struct mparse));
+ curp->options = options;
curp->wlevel = wlevel;
curp->mmsg = mmsg;
- curp->arg = arg;
- curp->inttype = inttype;
curp->defos = defos;
- curp->roff = roff_alloc(inttype, curp);
+ curp->roff = roff_alloc(curp, options);
+ if (curp->options & MPARSE_MDOC)
+ curp->pmdoc = mdoc_alloc(
+ curp->roff, curp, curp->defos,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+ if (curp->options & MPARSE_MAN)
+ curp->pman = man_alloc(curp->roff, curp,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+
return(curp);
}
@@ -773,6 +820,9 @@ mparse_reset(struct mparse *curp)
curp->file_status = MANDOCLEVEL_OK;
curp->mdoc = NULL;
curp->man = NULL;
+
+ free(curp->sodest);
+ curp->sodest = NULL;
}
void
@@ -789,13 +839,20 @@ mparse_free(struct mparse *curp)
free(curp->secondary->buf);
free(curp->secondary);
+ free(curp->sodest);
free(curp);
}
void
-mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
+mparse_result(struct mparse *curp,
+ struct mdoc **mdoc, struct man **man, char **sodest)
{
+ if (sodest && NULL != (*sodest = curp->sodest)) {
+ *mdoc = NULL;
+ *man = NULL;
+ return;
+ }
if (mdoc)
*mdoc = curp->mdoc;
if (man)
@@ -810,14 +867,14 @@ mandoc_vmsg(enum mandocerr t, struct mparse *m,
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+ (void)vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
mandoc_msg(t, m, ln, pos, buf);
}
void
-mandoc_msg(enum mandocerr er, struct mparse *m,
+mandoc_msg(enum mandocerr er, struct mparse *m,
int ln, int col, const char *msg)
{
enum mandoclevel level;
diff --git a/contrib/mdocml/roff.7 b/contrib/mdocml/roff.7
index 48e16dd..bc2f24e 100644
--- a/contrib/mdocml/roff.7
+++ b/contrib/mdocml/roff.7
@@ -1,7 +1,7 @@
-.\" $Id: roff.7,v 1.46 2013/12/26 02:43:18 schwarze Exp $
+.\" $Id: roff.7,v 1.55 2014/07/07 11:35:06 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011, 2013 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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.
.\"
-.Dd $Mdocdate: December 26 2013 $
+.Dd $Mdocdate: July 7 2014 $
.Dt ROFF 7
.Os
.Sh NAME
@@ -409,24 +409,27 @@ and the number of arguments is not checked.
Append to a macro definition.
The syntax of this request is the same as that of
.Sx \&de .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
.Ss \&ami
Append to a macro definition, specifying the macro name indirectly.
The syntax of this request is the same as that of
.Sx \&dei .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
.Ss \&am1
Append to a macro definition, switching roff compatibility mode off
during macro execution.
The syntax of this request is the same as that of
.Sx \&de1 .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&am .
+.Ss \&as
+Append to a user-defined string.
+The syntax of this request is the same as that of
+.Sx \&ds .
+If a user-defined string with the specified name does not yet exist,
+it is set to the empty string before appending.
.Ss \&cc
Changes the control character.
Its syntax is as follows:
@@ -439,6 +442,12 @@ If
is not specified, the control character is reset to
.Sq \&. .
Trailing characters are ignored.
+.Ss \&ce
+Center some lines.
+This line-scoped request is intended to take one integer argument,
+specifying how many lines to center.
+Currently, it is ignored including its arguments, and the number
+of arguments is not checked.
.Ss \&de
Define a
.Nm
@@ -542,9 +551,13 @@ Define a
macro, specifying the macro name indirectly.
The syntax of this request is the same as that of
.Sx \&de .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
+The request
+.Pp
+.D1 Pf . Cm \&dei Ar name Op Ar end
+.Pp
+has the same effect as:
+.Pp
+.D1 Pf . Cm \&de No \e* Ns Bo Ar name Bc Op \e* Ns Bq Ar end
.Ss \&de1
Define a
.Nm
@@ -647,6 +660,34 @@ This line-scoped request is intended to have one argument specifying
the font family to be selected.
It is a groff extension, and currently, it is ignored including its
arguments, and the number of arguments is not checked.
+.Ss \&ft
+Change the font.
+Its syntax is as follows:
+.Pp
+.D1 Pf . Cm \&ft Op Ar font
+.Pp
+The following
+.Ar font
+arguments are supported:
+.Bl -tag -width 4n -offset indent
+.It Cm B , BI , 3 , 4
+switches to
+.Sy bold
+font
+.It Cm I , 2
+switches to
+.Em underlined
+font
+.It Cm R , CW , 1
+switches to normal font
+.It Cm P No "or no argument"
+switches back to the previous font
+.El
+.Pp
+This request takes effect only locally, may be overridden by macros
+and escape sequences, and is only supported in
+.Xr man 7
+for now.
.Ss \&hw
Specify hyphenation points in words.
This line-scoped request is currently ignored.
@@ -665,10 +706,67 @@ Its syntax is equivalent to
.Sx \&if .
.Ss \&if
Begins a conditional.
-Right now, the conditional evaluates to true
-if and only if it starts with the letter
-.Sy n ,
-indicating processing in nroff style as opposed to troff style.
+This request has the following syntax:
+.Bd -literal -offset indent
+\&.if COND BODY
+.Ed
+.Bd -literal -offset indent
+\&.if COND \e{BODY
+BODY...\e}
+.Ed
+.Bd -literal -offset indent
+\&.if COND \e{\e
+BODY...
+\&.\e}
+.Ed
+.Pp
+COND is a conditional statement.
+Currently,
+.Xr mandoc 1
+supports the following subset of roff conditionals:
+.Bl -bullet
+.It
+If
+.Sq \&!
+is prefixed to COND, the condition is logically inverted.
+.It
+If the first character of COND is
+.Sq n
+.Pq nroff mode
+or
+.Sq o
+.Pq odd page ,
+COND evaluates to true.
+.It
+If the first character of COND is
+.Sq c
+.Pq character available ,
+.Sq d
+.Pq string defined ,
+.Sq e
+.Pq even page ,
+.Sq r
+.Pq register accessed ,
+or
+.Sq t
+.Pq troff mode ,
+COND evaluates to false.
+.It
+If COND starts with a parenthesis or with an optionally signed
+integer number, it is evaluated according to the rules of
+.Sx Numerical expressions
+explained below.
+It evaluates to true if the the result is positive,
+or to false if the result is zero or negative.
+.It
+Otherwise, the first character of COND is regarded as a delimiter
+and COND evaluates to true if the string extending from its first
+to its second occurrence is equal to the string extending from its
+second to its third occurrence.
+.It
+If COND cannot be parsed, it evaluates to false.
+.El
+.Pp
If a conditional is false, its children are not processed, but are
syntactically interpreted to preserve the integrity of the input
document.
@@ -686,44 +784,12 @@ will continue to syntactically interpret to the block close of the final
conditional.
Sub-conditionals, in this case, obviously inherit the truth value of
the parent.
-This request has the following syntax:
-.Bd -literal -offset indent
-\&.if COND \e{\e
-BODY...
-\&.\e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e{ BODY
-BODY... \e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e{ BODY
-BODY...
-\&.\e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e
-BODY
-.Ed
-.Pp
-COND is a conditional statement.
-roff allows for complicated conditionals; mandoc is much simpler.
-At this time, mandoc supports only
-.Sq n ,
-evaluating to true;
-and
-.Sq t ,
-.Sq e ,
-and
-.Sq o ,
-evaluating to false.
-All other invocations are read up to the next end of line or space and
-evaluate as false.
.Pp
If the BODY section is begun by an escaped brace
.Sq \e{ ,
-scope continues until a closing-brace escape sequence
-.Sq \.\e} .
+scope continues until the end of the input line containing the
+matching closing-brace escape sequence
+.Sq \e} .
If the BODY is not enclosed in braces, scope continues until
the end of the line.
If the COND is followed by a BODY on the same line, whether after a
@@ -803,6 +869,23 @@ Otherwise, it only terminates the
and arguments following it or the
.Sq \&..
request are discarded.
+.Ss \&ll
+Change the output line length.
+Its syntax is as follows:
+.Pp
+.D1 Pf . Cm \&ll Op Oo +|- Oc Ns Ar width
+.Pp
+If the
+.Ar width
+argument is omitted, the line length is reset to its previous value.
+The default setting for terminal output is 78n.
+If a sign is given, the line length is added to or subtracted from;
+otherwise, it is set to the provided value.
+Using this request in new manuals is discouraged for several reasons,
+among others because it overrides the
+.Xr mandoc 1
+.Fl O Cm width
+command line option.
.Ss \&ne
Declare the need for the specified minimum vertical space
before the next trap or the bottom of the page.
@@ -810,23 +893,19 @@ This line-scoped request is currently ignored.
.Ss \&nh
Turn off automatic hyphenation mode.
This line-scoped request is currently ignored.
-.Ss \&rm
-Remove a request, macro or string.
-This request is intended to have one argument,
-the name of the request, macro or string to be undefined.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
.Ss \&nr
Define or change a register.
A register is an arbitrary string value that defines some sort of state,
which influences parsing and/or formatting.
Its syntax is as follows:
.Pp
-.D1 Pf \. Cm \&nr Ar name Oo +|- Oc Ns Ar value
+.D1 Pf \. Cm \&nr Ar name Oo +|- Oc Ns Ar expression
.Pp
-The
-.Ar value
-may, at the moment, only be an integer.
+For the syntax of
+.Ar expression ,
+see
+.Sx Numerical expressions
+below.
If it is prefixed by a sign, the register will be
incremented or decremented instead of assigned to.
.Pp
@@ -861,6 +940,16 @@ Change point size.
This line-scoped request is intended to take one numerical argument.
Currently, it is ignored including its arguments,
and the number of arguments is not checked.
+.Ss \&rm
+Remove a request, macro or string.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Cm \&rm Ar name
+.Ss \&rr
+Remove a register.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Cm \&rr Ar name
.Ss \&so
Include a source file.
Its syntax is as follows:
@@ -929,6 +1018,73 @@ Begin a table, which formats input in aligned rows and columns.
See
.Xr tbl 7
for a description of the tbl language.
+.Ss Numerical expressions
+The
+.Sx \&nr ,
+.Sx \&if ,
+and
+.Sx \&ie
+requests accept integer numerical expressions as arguments.
+These are always evaluated using the C
+.Vt int
+type; integer overflow works the same way as in the C language.
+Numbers consist of an arbitrary number of digits
+.Sq 0
+to
+.Sq 9
+prefixed by an optional sign
+.Sq +
+or
+.Sq - .
+.Pp
+The following binary operators are implemented.
+Unless otherwise stated, they behave as in the C language:
+.Pp
+.Bl -tag -width 2n -compact
+.It Ic +
+addition
+.It Ic -
+subtraction
+.It Ic *
+multiplication
+.It Ic /
+division
+.It Ic %
+remainder of division
+.It Ic <
+less than
+.It Ic >
+greater than
+.It Ic ==
+equal to
+.It Ic =
+equal to, same effect as
+.Ic ==
+(this differs from C)
+.It Ic <=
+less than or equal to
+.It Ic >=
+greater than or equal to
+.It Ic <>
+not equal to (corresponds to C
+.Ic != ;
+this one is of limited portability, it is supported by Heirloom roff,
+but not by groff)
+.It Ic &
+logical and (corresponds to C
+.Ic && )
+.It Ic \&:
+logical or (corresponds to C
+.Ic \&|| )
+.It Ic <?
+minimum (not available in C)
+.It Ic >?
+maximum (not available in C)
+.El
+.Pp
+There is no concept of precendence; evaluation proceeds from left to right,
+except when subexpressions are enclosed in parantheses.
+Inside parentheses, whitespace is ignored.
.Sh ESCAPE SEQUENCE REFERENCE
The
.Xr mandoc 1
@@ -1017,10 +1173,15 @@ Digit width space character.
Anchor definition; ignored by
.Xr mandoc 1 .
.Ss \eB\(aq Ns Ar string Ns \(aq
-Test whether
+Interpolate
+.Sq 1
+if
.Ar string
-is a numerical expession; ignored by
-.Xr mandoc 1 .
+conforms to the syntax of
+.Sx Numerical expressions
+explained above and
+.Sq 0
+otherwise.
.Ss \eb\(aq Ns Ar string Ns \(aq
Bracket building function; ignored by
.Xr mandoc 1 .
@@ -1144,9 +1305,13 @@ Vertical motion; ignored by
.Xr mandoc 1 .
.Ss \ew\(aq Ns Ar string Ns \(aq
Interpolate the width of the
-.Ar string ;
-ignored by
-.Xr mandoc 1 .
+.Ar string .
+The
+.Xr mandoc 1
+implementation assumes that after expansion of user-defined strings, the
+.Ar string
+only contains normal characters, no escape sequences, and that each
+character has a width of 24 basic units.
.Ss \eX\(aq Ns Ar string Ns \(aq
Output
.Ar string
diff --git a/contrib/mdocml/roff.c b/contrib/mdocml/roff.c
index 42240d2..4903ee8 100644
--- a/contrib/mdocml/roff.c
+++ b/contrib/mdocml/roff.c
@@ -1,7 +1,7 @@
-/* $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */
+/* $Id: roff.c,v 1.224 2014/08/01 17:27:44 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,6 +26,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libroff.h"
#include "libmandoc.h"
@@ -40,7 +41,9 @@ enum rofft {
ROFF_am,
ROFF_ami,
ROFF_am1,
+ ROFF_as,
ROFF_cc,
+ ROFF_ce,
ROFF_de,
ROFF_dei,
ROFF_de1,
@@ -59,6 +62,7 @@ enum rofft {
ROFF_ns,
ROFF_ps,
ROFF_rm,
+ ROFF_rr,
ROFF_so,
ROFF_ta,
ROFF_tr,
@@ -70,16 +74,10 @@ enum rofft {
ROFF_EQ,
ROFF_EN,
ROFF_cblock,
- ROFF_ccond,
ROFF_USERDEF,
ROFF_MAX
};
-enum roffrule {
- ROFFRULE_DENY,
- ROFFRULE_ALLOW
-};
-
/*
* An incredibly-simple string buffer.
*/
@@ -107,12 +105,9 @@ struct roffreg {
};
struct roff {
- enum mparset parsetype; /* requested parse type */
struct mparse *parse; /* parse point */
struct roffnode *last; /* leaf of stack */
- enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
- char control; /* control character */
- int rstackpos; /* position in rstack */
+ int *rstack; /* stack of inverted `ie' values */
struct roffreg *regtab; /* number registers */
struct roffkv *strtab; /* user-defined strings & macros */
struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
@@ -124,6 +119,10 @@ struct roff {
struct eqn_node *last_eqn; /* last equation parsed */
struct eqn_node *first_eqn; /* first equation parsed */
struct eqn_node *eqn; /* current equation being parsed */
+ int options; /* parse options */
+ int rstacksz; /* current size limit of rstack */
+ int rstackpos; /* position in rstack */
+ char control; /* control character */
};
struct roffnode {
@@ -134,12 +133,12 @@ struct roffnode {
char *name; /* node name, e.g. macro name */
char *end; /* end-rules: custom token */
int endspan; /* end-rules: next-line or infty */
- enum roffrule rule; /* current evaluation rule */
+ int rule; /* current evaluation rule */
};
#define ROFF_ARGS struct roff *r, /* parse ctx */ \
enum rofft tok, /* tok of macro */ \
- char **bufp, /* input buffer */ \
+ char **bufp, /* input buffer */ \
size_t *szp, /* size of input buffer */ \
int ln, /* parse line */ \
int ppos, /* original pos in buffer */ \
@@ -177,35 +176,41 @@ static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_cc(ROFF_ARGS);
-static enum rofferr roff_ccond(ROFF_ARGS);
+static void roff_ccond(struct roff *, int, int);
static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static enum rofferr roff_ds(ROFF_ARGS);
-static enum roffrule roff_evalcond(const char *, int *);
+static int roff_evalcond(const char *, int *);
+static int roff_evalnum(const char *, int *, int *, int);
+static int roff_evalpar(const char *, int *, int *);
+static int roff_evalstrcond(const char *, int *);
static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
-static char *roff_getname(struct roff *, char **, int, int);
+static size_t roff_getname(struct roff *, char **, int, int);
static int roff_getnum(const char *, int *, int *);
static int roff_getop(const char *, int *, char *);
static int roff_getregn(const struct roff *,
const char *, size_t);
-static const char *roff_getstrn(const struct roff *,
+static int roff_getregro(const char *name);
+static const char *roff_getstrn(const struct roff *,
const char *, size_t);
static enum rofferr roff_it(ROFF_ARGS);
static enum rofferr roff_line_ignore(ROFF_ARGS);
static enum rofferr roff_nr(ROFF_ARGS);
static void roff_openeqn(struct roff *, const char *,
int, int, const char *);
-static enum rofft roff_parse(struct roff *, const char *, int *);
+static enum rofft roff_parse(struct roff *, char *, int *,
+ int, int);
static enum rofferr roff_parsetext(char **, size_t *, int, int *);
-static enum rofferr roff_res(struct roff *,
+static enum rofferr roff_res(struct roff *,
char **, size_t *, int, int);
static enum rofferr roff_rm(ROFF_ARGS);
+static enum rofferr roff_rr(ROFF_ARGS);
static void roff_setstr(struct roff *,
const char *, const char *, int);
-static void roff_setstrn(struct roffkv **, const char *,
+static void roff_setstrn(struct roffkv **, const char *,
size_t, const char *, size_t, int);
static enum rofferr roff_so(ROFF_ARGS);
static enum rofferr roff_tr(ROFF_ARGS);
@@ -231,7 +236,9 @@ static struct roffmac roffs[ROFF_MAX] = {
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "as", roff_ds, NULL, NULL, 0, NULL },
{ "cc", roff_cc, NULL, NULL, 0, NULL },
+ { "ce", roff_line_ignore, NULL, NULL, 0, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
@@ -250,6 +257,7 @@ static struct roffmac roffs[ROFF_MAX] = {
{ "ns", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ps", roff_line_ignore, NULL, NULL, 0, NULL },
{ "rm", roff_rm, NULL, NULL, 0, NULL },
+ { "rr", roff_rr, NULL, NULL, 0, NULL },
{ "so", roff_so, NULL, NULL, 0, NULL },
{ "ta", roff_line_ignore, NULL, NULL, 0, NULL },
{ "tr", roff_tr, NULL, NULL, 0, NULL },
@@ -261,38 +269,39 @@ static struct roffmac roffs[ROFF_MAX] = {
{ "EQ", roff_EQ, NULL, NULL, 0, NULL },
{ "EN", roff_EN, NULL, NULL, 0, NULL },
{ ".", roff_cblock, NULL, NULL, 0, NULL },
- { "\\}", roff_ccond, NULL, NULL, 0, NULL },
{ NULL, roff_userdef, NULL, NULL, 0, NULL },
};
+/* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
const char *const __mdoc_reserved[] = {
"Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
"Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
"Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
"Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
- "Ds", "Dt", "Dv", "Dx", "D1",
- "Ec", "Ed", "Ef", "Ek", "El", "Em", "em",
- "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex",
+ "Dt", "Dv", "Dx", "D1",
+ "Ec", "Ed", "Ef", "Ek", "El", "Em",
+ "En", "Eo", "Er", "Es", "Ev", "Ex",
"Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
- "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP",
- "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
+ "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
+ "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
"Oc", "Oo", "Op", "Os", "Ot", "Ox",
- "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq",
- "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv",
- "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq",
+ "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
+ "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
+ "Sc", "Sh", "Sm", "So", "Sq",
"Ss", "St", "Sx", "Sy",
"Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
- "%A", "%B", "%D", "%I", "%J", "%N", "%O",
+ "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
"%P", "%Q", "%R", "%T", "%U", "%V",
NULL
};
+/* not currently implemented: BT DE DS ME MT PT SY TQ YS */
const char *const __man_reserved[] = {
- "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT",
- "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR",
- "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT",
- "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY",
- "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS",
+ "AT", "B", "BI", "BR", "DT",
+ "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
+ "LP", "OP", "P", "PD", "PP",
+ "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
+ "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
NULL
};
@@ -308,6 +317,7 @@ static const struct predef predefs[PREDEFS_MAX] = {
static int roffit_lines; /* number of lines to delay */
static char *roffit_macro; /* nil-terminated macro line */
+
static void
roffhash_init(void)
{
@@ -360,7 +370,6 @@ roffhash_find(const char *p, size_t s)
return(ROFF_MAX);
}
-
/*
* Pop the current node off of the stack of roff instructions currently
* pending.
@@ -371,7 +380,7 @@ roffnode_pop(struct roff *r)
struct roffnode *p;
assert(r->last);
- p = r->last;
+ p = r->last;
r->last = r->last->parent;
free(p->name);
@@ -379,7 +388,6 @@ roffnode_pop(struct roff *r)
free(p);
}
-
/*
* Push a roff node onto the instruction stack. This must later be
* removed with roffnode_pop().
@@ -397,12 +405,11 @@ roffnode_push(struct roff *r, enum rofft tok, const char *name,
p->parent = r->last;
p->line = line;
p->col = col;
- p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
+ p->rule = p->parent ? p->parent->rule : 0;
r->last = p;
}
-
static void
roff_free1(struct roff *r)
{
@@ -414,32 +421,32 @@ roff_free1(struct roff *r)
r->first_tbl = tbl->next;
tbl_free(tbl);
}
-
r->first_tbl = r->last_tbl = r->tbl = NULL;
while (NULL != (e = r->first_eqn)) {
r->first_eqn = e->next;
eqn_free(e);
}
-
r->first_eqn = r->last_eqn = r->eqn = NULL;
while (r->last)
roffnode_pop(r);
- roff_freestr(r->strtab);
- roff_freestr(r->xmbtab);
-
- r->strtab = r->xmbtab = NULL;
+ free (r->rstack);
+ r->rstack = NULL;
+ r->rstacksz = 0;
+ r->rstackpos = -1;
roff_freereg(r->regtab);
-
r->regtab = NULL;
+ roff_freestr(r->strtab);
+ roff_freestr(r->xmbtab);
+ r->strtab = r->xmbtab = NULL;
+
if (r->xtab)
for (i = 0; i < 128; i++)
free(r->xtab[i].p);
-
free(r->xtab);
r->xtab = NULL;
}
@@ -447,17 +454,11 @@ roff_free1(struct roff *r)
void
roff_reset(struct roff *r)
{
- int i;
roff_free1(r);
-
r->control = 0;
-
- for (i = 0; i < PREDEFS_MAX; i++)
- roff_setstr(r, predefs[i].name, predefs[i].str, 0);
}
-
void
roff_free(struct roff *r)
{
@@ -466,78 +467,93 @@ roff_free(struct roff *r)
free(r);
}
-
struct roff *
-roff_alloc(enum mparset type, struct mparse *parse)
+roff_alloc(struct mparse *parse, int options)
{
struct roff *r;
- int i;
r = mandoc_calloc(1, sizeof(struct roff));
- r->parsetype = type;
r->parse = parse;
+ r->options = options;
r->rstackpos = -1;
-
- roffhash_init();
- for (i = 0; i < PREDEFS_MAX; i++)
- roff_setstr(r, predefs[i].name, predefs[i].str, 0);
+ roffhash_init();
return(r);
}
/*
- * In the current line, expand user-defined strings ("\*")
- * and references to number registers ("\n").
- * Also check the syntax of other escape sequences.
+ * In the current line, expand escape sequences that tend to get
+ * used in numerical expressions and conditional requests.
+ * Also check the syntax of the remaining escape sequences.
*/
static enum rofferr
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
{
- char ubuf[12]; /* buffer to print the number */
- const char *stesc; /* start of an escape sequence ('\\') */
+ char ubuf[24]; /* buffer to print the number */
+ const char *start; /* start of the string to process */
+ char *stesc; /* start of an escape sequence ('\\') */
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
const char *res; /* the string to be substituted */
char *nbuf; /* new buffer to copy bufp to */
- size_t nsz; /* size of the new buffer */
size_t maxl; /* expected length of the escape name */
size_t naml; /* actual length of the escape name */
int expand_count; /* to avoid infinite loops */
+ int npos; /* position in numeric expression */
+ int arg_complete; /* argument not interrupted by eol */
+ char term; /* character terminating the escape */
expand_count = 0;
+ start = *bufp + pos;
+ stesc = strchr(start, '\0') - 1;
+ while (stesc-- > start) {
-again:
- cp = *bufp + pos;
- while (NULL != (cp = strchr(cp, '\\'))) {
- stesc = cp++;
+ /* Search backwards for the next backslash. */
- /*
- * The second character must be an asterisk or an n.
- * If it isn't, skip it anyway: It is escaped,
- * so it can't start another escape sequence.
- */
+ if ('\\' != *stesc)
+ continue;
+
+ /* If it is escaped, skip it. */
- if ('\0' == *cp)
- return(ROFF_CONT);
+ for (cp = stesc - 1; cp >= start; cp--)
+ if ('\\' != *cp)
+ break;
+ if (0 == (stesc - cp) % 2) {
+ stesc = (char *)cp;
+ continue;
+ }
+
+ /* Decide whether to expand or to check only. */
+
+ term = '\0';
+ cp = stesc + 1;
switch (*cp) {
- case ('*'):
+ case '*':
res = NULL;
break;
- case ('n'):
+ case 'B':
+ /* FALLTHROUGH */
+ case 'w':
+ term = cp[1];
+ /* FALLTHROUGH */
+ case 'n':
res = ubuf;
break;
default:
- if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
- continue;
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
- return(ROFF_CONT);
+ if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
+ mandoc_vmsg(MANDOCERR_ESC_BAD,
+ r->parse, ln, (int)(stesc - *bufp),
+ "%.*s", (int)(cp - stesc), stesc);
+ continue;
}
- cp++;
+ if (EXPAND_LIMIT < ++expand_count) {
+ mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+ ln, (int)(stesc - *bufp), NULL);
+ return(ROFF_IGN);
+ }
/*
* The third character decides the length
@@ -545,35 +561,44 @@ again:
* Save a pointer to the name.
*/
- switch (*cp) {
- case ('\0'):
- return(ROFF_CONT);
- case ('('):
- cp++;
- maxl = 2;
- break;
- case ('['):
- cp++;
+ if ('\0' == term) {
+ switch (*++cp) {
+ case '\0':
+ maxl = 0;
+ break;
+ case '(':
+ cp++;
+ maxl = 2;
+ break;
+ case '[':
+ cp++;
+ term = ']';
+ maxl = 0;
+ break;
+ default:
+ maxl = 1;
+ break;
+ }
+ } else {
+ cp += 2;
maxl = 0;
- break;
- default:
- maxl = 1;
- break;
}
stnam = cp;
/* Advance to the end of the name. */
+ arg_complete = 1;
for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
if ('\0' == *cp) {
- mandoc_msg
- (MANDOCERR_BADESCAPE,
- r->parse, ln,
- (int)(stesc - *bufp), NULL);
- return(ROFF_CONT);
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(stesc - *bufp), stesc);
+ arg_complete = 0;
+ break;
}
- if (0 == maxl && ']' == *cp)
+ if (0 == maxl && *cp == term) {
+ cp++;
break;
+ }
}
/*
@@ -581,41 +606,51 @@ again:
* undefined, resume searching for escapes.
*/
- if (NULL == res)
- res = roff_getstrn(r, stnam, naml);
- else
- snprintf(ubuf, sizeof(ubuf), "%d",
- roff_getregn(r, stnam, naml));
+ switch (stesc[1]) {
+ case '*':
+ if (arg_complete)
+ res = roff_getstrn(r, stnam, naml);
+ break;
+ case 'B':
+ npos = 0;
+ ubuf[0] = arg_complete &&
+ roff_evalnum(stnam, &npos, NULL, 0) &&
+ stnam + npos + 1 == cp ? '1' : '0';
+ ubuf[1] = '\0';
+ break;
+ case 'n':
+ if (arg_complete)
+ (void)snprintf(ubuf, sizeof(ubuf), "%d",
+ roff_getregn(r, stnam, naml));
+ else
+ ubuf[0] = '\0';
+ break;
+ case 'w':
+ /* use even incomplete args */
+ (void)snprintf(ubuf, sizeof(ubuf), "%d",
+ 24 * (int)naml);
+ break;
+ }
if (NULL == res) {
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(stesc - *bufp),
+ "%.*s", (int)naml, stnam);
res = "";
}
/* Replace the escape sequence by the string. */
- pos = stesc - *bufp;
+ *stesc = '\0';
+ *szp = mandoc_asprintf(&nbuf, "%s%s%s",
+ *bufp, res, cp) + 1;
- nsz = *szp + strlen(res) + 1;
- nbuf = mandoc_malloc(nsz);
-
- strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
- strlcat(nbuf, res, nsz);
- strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
+ /* Prepare for the next replacement. */
+ start = nbuf + pos;
+ stesc = nbuf + (stesc - *bufp) + strlen(res);
free(*bufp);
-
*bufp = nbuf;
- *szp = nsz;
-
- if (EXPAND_LIMIT >= ++expand_count)
- goto again;
-
- /* Just leave the string unexpanded. */
- mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
- return(ROFF_IGN);
}
return(ROFF_CONT);
}
@@ -663,11 +698,7 @@ roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
/* Spring the input line trap. */
if (1 == roffit_lines) {
- isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
- if (-1 == isz) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
+ isz = mandoc_asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
free(*bufp);
*bufp = p;
*szp = isz + 1;
@@ -681,7 +712,7 @@ roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
}
enum rofferr
-roff_parseln(struct roff *r, int ln, char **bufp,
+roff_parseln(struct roff *r, int ln, char **bufp,
size_t *szp, int pos, int *offs)
{
enum rofft t;
@@ -712,8 +743,7 @@ roff_parseln(struct roff *r, int ln, char **bufp,
if (r->last && ! ctl) {
t = r->last->tok;
assert(roffs[t].text);
- e = (*roffs[t].text)
- (r, t, bufp, szp, ln, pos, pos, offs);
+ e = (*roffs[t].text)(r, t, bufp, szp, ln, pos, pos, offs);
assert(ROFF_IGN == e || ROFF_CONT == e);
if (ROFF_CONT != e)
return(e);
@@ -735,9 +765,8 @@ roff_parseln(struct roff *r, int ln, char **bufp,
if (r->last) {
t = r->last->tok;
assert(roffs[t].sub);
- return((*roffs[t].sub)
- (r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].sub)(r, t, bufp, szp,
+ ln, ppos, pos, offs));
}
/*
@@ -746,33 +775,31 @@ roff_parseln(struct roff *r, int ln, char **bufp,
* the compilers handle it.
*/
- if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
+ if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos, ln, ppos)))
return(ROFF_CONT);
assert(roffs[t].proc);
- return((*roffs[t].proc)
- (r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs));
}
-
void
roff_endparse(struct roff *r)
{
if (r->last)
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->last->line, r->last->col, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->last->line, r->last->col,
+ roffs[r->last->tok].name);
if (r->eqn) {
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->eqn->eqn.ln, r->eqn->eqn.pos, "EQ");
eqn_end(&r->eqn);
}
if (r->tbl) {
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->tbl->line, r->tbl->pos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->tbl->line, r->tbl->pos, "TS");
tbl_end(&r->tbl);
}
}
@@ -782,37 +809,30 @@ roff_endparse(struct roff *r)
* form of ".foo xxx" in the usual way.
*/
static enum rofft
-roff_parse(struct roff *r, const char *buf, int *pos)
+roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
{
+ char *cp;
const char *mac;
size_t maclen;
enum rofft t;
- if ('\0' == buf[*pos] || '"' == buf[*pos] ||
- '\t' == buf[*pos] || ' ' == buf[*pos])
- return(ROFF_MAX);
+ cp = buf + *pos;
- /*
- * We stop the macro parse at an escape, tab, space, or nil.
- * However, `\}' is also a valid macro, so make sure we don't
- * clobber it by seeing the `\' as the end of token.
- */
+ if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
+ return(ROFF_MAX);
- mac = buf + *pos;
- maclen = strcspn(mac + 1, " \\\t\0") + 1;
+ mac = cp;
+ maclen = roff_getname(r, &cp, ln, ppos);
t = (r->current_string = roff_getstrn(r, mac, maclen))
? ROFF_USERDEF : roffhash_find(mac, maclen);
- *pos += (int)maclen;
-
- while (buf[*pos] && ' ' == buf[*pos])
- (*pos)++;
+ if (ROFF_MAX != t)
+ *pos = cp - buf;
return(t);
}
-/* ARGSUSED */
static enum rofferr
roff_cblock(ROFF_ARGS)
{
@@ -823,31 +843,33 @@ roff_cblock(ROFF_ARGS)
*/
if (NULL == r->last) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "..");
return(ROFF_IGN);
}
switch (r->last->tok) {
- case (ROFF_am):
- /* FALLTHROUGH */
- case (ROFF_ami):
+ case ROFF_am:
+ /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
/* FALLTHROUGH */
- case (ROFF_am1):
+ case ROFF_ami:
/* FALLTHROUGH */
- case (ROFF_de):
+ case ROFF_de:
/* ROFF_de1 is remapped to ROFF_de in roff_block(). */
/* FALLTHROUGH */
- case (ROFF_dei):
+ case ROFF_dei:
/* FALLTHROUGH */
- case (ROFF_ig):
+ case ROFF_ig:
break;
default:
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "..");
return(ROFF_IGN);
}
if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ ".. %s", *bufp + pos);
roffnode_pop(r);
roffnode_cleanscope(r);
@@ -855,7 +877,6 @@ roff_cblock(ROFF_ARGS)
}
-
static void
roffnode_cleanscope(struct roff *r)
{
@@ -867,77 +888,83 @@ roffnode_cleanscope(struct roff *r)
}
}
-
-/* ARGSUSED */
-static enum rofferr
-roff_ccond(ROFF_ARGS)
+static void
+roff_ccond(struct roff *r, int ln, int ppos)
{
if (NULL == r->last) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
+ return;
}
switch (r->last->tok) {
- case (ROFF_el):
+ case ROFF_el:
/* FALLTHROUGH */
- case (ROFF_ie):
+ case ROFF_ie:
/* FALLTHROUGH */
- case (ROFF_if):
+ case ROFF_if:
break;
default:
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
+ return;
}
if (r->last->endspan > -1) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
+ return;
}
- if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
-
roffnode_pop(r);
roffnode_cleanscope(r);
- return(ROFF_IGN);
+ return;
}
-
-/* ARGSUSED */
static enum rofferr
roff_block(ROFF_ARGS)
{
- int sv;
- size_t sz;
- char *name;
+ const char *name;
+ char *iname, *cp;
+ size_t namesz;
- name = NULL;
+ /* Ignore groff compatibility mode for now. */
- if (ROFF_ig != tok) {
- if ('\0' == (*bufp)[pos]) {
- mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
- }
+ if (ROFF_de1 == tok)
+ tok = ROFF_de;
+ else if (ROFF_am1 == tok)
+ tok = ROFF_am;
- /*
- * Re-write `de1', since we don't really care about
- * groff's strange compatibility mode, into `de'.
- */
+ /* Parse the macro name argument. */
+
+ cp = *bufp + pos;
+ if (ROFF_ig == tok) {
+ iname = NULL;
+ namesz = 0;
+ } else {
+ iname = cp;
+ namesz = roff_getname(r, &cp, ln, ppos);
+ iname[namesz] = '\0';
+ }
- if (ROFF_de1 == tok)
- tok = ROFF_de;
- if (ROFF_de == tok)
- name = *bufp + pos;
- else
- mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
- roffs[tok].name);
+ /* Resolve the macro name argument if it is indirect. */
- while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
- pos++;
+ if (namesz && (ROFF_dei == tok || ROFF_ami == tok)) {
+ if (NULL == (name = roff_getstrn(r, iname, namesz))) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(iname - *bufp),
+ "%.*s", (int)namesz, iname);
+ namesz = 0;
+ } else
+ namesz = strlen(name);
+ } else
+ name = iname;
- while (isspace((unsigned char)(*bufp)[pos]))
- (*bufp)[pos++] = '\0';
+ if (0 == namesz && ROFF_ig != tok) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
}
roffnode_push(r, tok, name, ln, ppos);
@@ -945,46 +972,43 @@ roff_block(ROFF_ARGS)
/*
* At the beginning of a `de' macro, clear the existing string
* with the same name, if there is one. New content will be
- * added from roff_block_text() in multiline mode.
+ * appended from roff_block_text() in multiline mode.
*/
- if (ROFF_de == tok)
- roff_setstr(r, name, "", 0);
+ if (ROFF_de == tok || ROFF_dei == tok)
+ roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
- if ('\0' == (*bufp)[pos])
+ if ('\0' == *cp)
return(ROFF_IGN);
- /* If present, process the custom end-of-line marker. */
+ /* Get the custom end marker. */
- sv = pos;
- while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
- pos++;
+ iname = cp;
+ namesz = roff_getname(r, &cp, ln, ppos);
- /*
- * Note: groff does NOT like escape characters in the input.
- * Instead of detecting this, we're just going to let it fly and
- * to hell with it.
- */
+ /* Resolve the end marker if it is indirect. */
- assert(pos > sv);
- sz = (size_t)(pos - sv);
-
- if (1 == sz && '.' == (*bufp)[sv])
- return(ROFF_IGN);
-
- r->last->end = mandoc_malloc(sz + 1);
+ if (namesz && (ROFF_dei == tok || ROFF_ami == tok)) {
+ if (NULL == (name = roff_getstrn(r, iname, namesz))) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(iname - *bufp),
+ "%.*s", (int)namesz, iname);
+ namesz = 0;
+ } else
+ namesz = strlen(name);
+ } else
+ name = iname;
- memcpy(r->last->end, *bufp + sv, sz);
- r->last->end[(int)sz] = '\0';
+ if (namesz)
+ r->last->end = mandoc_strndup(name, namesz);
- if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+ if ('\0' != *cp)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ ln, pos, ".%s ... %s", roffs[tok].name, cp);
return(ROFF_IGN);
}
-
-/* ARGSUSED */
static enum rofferr
roff_block_sub(ROFF_ARGS)
{
@@ -1005,10 +1029,10 @@ roff_block_sub(ROFF_ARGS)
if ((*bufp)[i] != r->last->end[j])
break;
- if ('\0' == r->last->end[j] &&
- ('\0' == (*bufp)[i] ||
- ' ' == (*bufp)[i] ||
- '\t' == (*bufp)[i])) {
+ if ('\0' == r->last->end[j] &&
+ ('\0' == (*bufp)[i] ||
+ ' ' == (*bufp)[i] ||
+ '\t' == (*bufp)[i])) {
roffnode_pop(r);
roffnode_cleanscope(r);
@@ -1016,7 +1040,7 @@ roff_block_sub(ROFF_ARGS)
i++;
pos = i;
- if (ROFF_MAX != roff_parse(r, *bufp, &pos))
+ if (ROFF_MAX != roff_parse(r, *bufp, &pos, ln, ppos))
return(ROFF_RERUN);
return(ROFF_IGN);
}
@@ -1027,47 +1051,38 @@ roff_block_sub(ROFF_ARGS)
* pulling it out of the hashtable.
*/
- t = roff_parse(r, *bufp, &pos);
+ t = roff_parse(r, *bufp, &pos, ln, ppos);
- /*
- * Macros other than block-end are only significant
- * in `de' blocks; elsewhere, simply throw them away.
- */
if (ROFF_cblock != t) {
- if (ROFF_de == tok)
- roff_setstr(r, r->last->name, *bufp + ppos, 1);
+ if (ROFF_ig != tok)
+ roff_setstr(r, r->last->name, *bufp + ppos, 2);
return(ROFF_IGN);
}
assert(roffs[t].proc);
- return((*roffs[t].proc)(r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs));
}
-
-/* ARGSUSED */
static enum rofferr
roff_block_text(ROFF_ARGS)
{
- if (ROFF_de == tok)
- roff_setstr(r, r->last->name, *bufp + pos, 1);
+ if (ROFF_ig != tok)
+ roff_setstr(r, r->last->name, *bufp + pos, 2);
return(ROFF_IGN);
}
-
-/* ARGSUSED */
static enum rofferr
roff_cond_sub(ROFF_ARGS)
{
enum rofft t;
- enum roffrule rr;
char *ep;
+ int rr;
rr = r->last->rule;
roffnode_cleanscope(r);
- t = roff_parse(r, *bufp, &pos);
+ t = roff_parse(r, *bufp, &pos, ln, ppos);
/*
* Fully handle known macros when they are structurally
@@ -1075,65 +1090,66 @@ roff_cond_sub(ROFF_ARGS)
*/
if ((ROFF_MAX != t) &&
- (ROFF_ccond == t || ROFFRULE_ALLOW == rr ||
- ROFFMAC_STRUCT & roffs[t].flags)) {
+ (rr || ROFFMAC_STRUCT & roffs[t].flags)) {
assert(roffs[t].proc);
return((*roffs[t].proc)(r, t, bufp, szp,
- ln, ppos, pos, offs));
+ ln, ppos, pos, offs));
}
- /* Always check for the closing delimiter `\}'. */
-
- ep = &(*bufp)[pos];
- while (NULL != (ep = strchr(ep, '\\'))) {
- if ('}' != *(++ep))
- continue;
+ /*
+ * If `\}' occurs on a macro line without a preceding macro,
+ * drop the line completely.
+ */
- /*
- * If we're at the end of line, then just chop
- * off the \} and resize the buffer.
- * If we aren't, then convert it to spaces.
- */
+ ep = *bufp + pos;
+ if ('\\' == ep[0] && '}' == ep[1])
+ rr = 0;
- if ('\0' == *(ep + 1)) {
- *--ep = '\0';
- *szp -= 2;
- } else
- *(ep - 1) = *ep = ' ';
+ /* Always check for the closing delimiter `\}'. */
- roff_ccond(r, ROFF_ccond, bufp, szp,
- ln, pos, pos + 2, offs);
- break;
+ while (NULL != (ep = strchr(ep, '\\'))) {
+ if ('}' == *(++ep)) {
+ *ep = '&';
+ roff_ccond(r, ln, ep - *bufp - 1);
+ }
+ ++ep;
}
- return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+ return(rr ? ROFF_CONT : ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_cond_text(ROFF_ARGS)
{
char *ep;
- enum roffrule rr;
+ int rr;
rr = r->last->rule;
roffnode_cleanscope(r);
- ep = &(*bufp)[pos];
- for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
- ep++;
- if ('}' != *ep)
- continue;
- *ep = '&';
- roff_ccond(r, ROFF_ccond, bufp, szp,
- ln, pos, pos + 2, offs);
+ ep = *bufp + pos;
+ while (NULL != (ep = strchr(ep, '\\'))) {
+ if ('}' == *(++ep)) {
+ *ep = '&';
+ roff_ccond(r, ln, ep - *bufp - 1);
+ }
+ ++ep;
}
- return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+ return(rr ? ROFF_CONT : ROFF_IGN);
}
+/*
+ * Parse a single signed integer number. Stop at the first non-digit.
+ * If there is at least one digit, return success and advance the
+ * parse point, else return failure and let the parse point unchanged.
+ * Ignore overflows, treat them just like the C language.
+ */
static int
roff_getnum(const char *v, int *pos, int *res)
{
- int p, n;
+ int myres, n, p;
+
+ if (NULL == res)
+ res = &myres;
p = *pos;
n = v[p] == '-';
@@ -1141,7 +1157,7 @@ roff_getnum(const char *v, int *pos, int *res)
p++;
for (*res = 0; isdigit((unsigned char)v[p]); p++)
- *res += 10 * *res + v[p] - '0';
+ *res = 10 * *res + v[p] - '0';
if (p == *pos + n)
return 0;
@@ -1152,95 +1168,91 @@ roff_getnum(const char *v, int *pos, int *res)
return 1;
}
+/*
+ * Evaluate a string comparison condition.
+ * The first character is the delimiter.
+ * Succeed if the string up to its second occurrence
+ * matches the string up to its third occurence.
+ * Advance the cursor after the third occurrence
+ * or lacking that, to the end of the line.
+ */
static int
-roff_getop(const char *v, int *pos, char *res)
+roff_evalstrcond(const char *v, int *pos)
{
- int e;
+ const char *s1, *s2, *s3;
+ int match;
- *res = v[*pos];
- e = v[*pos + 1] == '=';
+ match = 0;
+ s1 = v + *pos; /* initial delimiter */
+ s2 = s1 + 1; /* for scanning the first string */
+ s3 = strchr(s2, *s1); /* for scanning the second string */
- switch (*res) {
- case '=':
- break;
- case '>':
- if (e)
- *res = 'g';
- break;
- case '<':
- if (e)
- *res = 'l';
- break;
- default:
- return(0);
- }
+ if (NULL == s3) /* found no middle delimiter */
+ goto out;
- *pos += 1 + e;
+ while ('\0' != *++s3) {
+ if (*s2 != *s3) { /* mismatch */
+ s3 = strchr(s3, *s1);
+ break;
+ }
+ if (*s3 == *s1) { /* found the final delimiter */
+ match = 1;
+ break;
+ }
+ s2++;
+ }
- return(*res);
+out:
+ if (NULL == s3)
+ s3 = strchr(s2, '\0');
+ else
+ s3++;
+ *pos = s3 - v;
+ return(match);
}
-static enum roffrule
+/*
+ * Evaluate an optionally negated single character, numerical,
+ * or string condition.
+ */
+static int
roff_evalcond(const char *v, int *pos)
{
- int not, lh, rh;
- char op;
+ int wanttrue, number;
+
+ if ('!' == v[*pos]) {
+ wanttrue = 0;
+ (*pos)++;
+ } else
+ wanttrue = 1;
switch (v[*pos]) {
- case ('n'):
+ case 'n':
+ /* FALLTHROUGH */
+ case 'o':
(*pos)++;
- return(ROFFRULE_ALLOW);
- case ('e'):
+ return(wanttrue);
+ case 'c':
/* FALLTHROUGH */
- case ('o'):
+ case 'd':
/* FALLTHROUGH */
- case ('t'):
- (*pos)++;
- return(ROFFRULE_DENY);
- case ('!'):
+ case 'e':
+ /* FALLTHROUGH */
+ case 'r':
+ /* FALLTHROUGH */
+ case 't':
(*pos)++;
- not = 1;
- break;
+ return(!wanttrue);
default:
- not = 0;
break;
}
- if (!roff_getnum(v, pos, &lh))
- return ROFFRULE_DENY;
- if (!roff_getop(v, pos, &op)) {
- if (lh < 0)
- lh = 0;
- goto out;
- }
- if (!roff_getnum(v, pos, &rh))
- return ROFFRULE_DENY;
- switch (op) {
- case 'g':
- lh = lh >= rh;
- break;
- case 'l':
- lh = lh <= rh;
- break;
- case '=':
- lh = lh == rh;
- break;
- case '>':
- lh = lh > rh;
- break;
- case '<':
- lh = lh < rh;
- break;
- default:
- return ROFFRULE_DENY;
- }
-out:
- if (not)
- lh = !lh;
- return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
+ if (roff_evalnum(v, pos, &number, 0))
+ return((number > 0) == wanttrue);
+ else
+ return(roff_evalstrcond(v, pos) == wanttrue);
}
-/* ARGSUSED */
static enum rofferr
roff_line_ignore(ROFF_ARGS)
{
@@ -1248,25 +1260,23 @@ roff_line_ignore(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_cond(ROFF_ARGS)
{
roffnode_push(r, tok, NULL, ln, ppos);
- /*
+ /*
* An `.el' has no conditional body: it will consume the value
* of the current rstack entry set in prior `ie' calls or
- * defaults to DENY.
+ * defaults to DENY.
*
* If we're not an `el', however, then evaluate the conditional.
*/
r->last->rule = ROFF_el == tok ?
- (r->rstackpos < 0 ?
- ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
- roff_evalcond(*bufp, &pos);
+ (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
+ roff_evalcond(*bufp, &pos);
/*
* An if-else will put the NEGATION of the current evaluated
@@ -1274,20 +1284,18 @@ roff_cond(ROFF_ARGS)
*/
if (ROFF_ie == tok) {
- if (r->rstackpos == RSTACK_MAX - 1) {
- mandoc_msg(MANDOCERR_MEM,
- r->parse, ln, ppos, NULL);
- return(ROFF_ERR);
+ if (r->rstackpos + 1 == r->rstacksz) {
+ r->rstacksz += 16;
+ r->rstack = mandoc_reallocarray(r->rstack,
+ r->rstacksz, sizeof(int));
}
- r->rstack[++r->rstackpos] =
- ROFFRULE_DENY == r->last->rule ?
- ROFFRULE_ALLOW : ROFFRULE_DENY;
+ r->rstack[++r->rstackpos] = !r->last->rule;
}
/* If the parent has false as its rule, then so do we. */
- if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
- r->last->rule = ROFFRULE_DENY;
+ if (r->last->parent && !r->last->parent->rule)
+ r->last->rule = 0;
/*
* Determine scope.
@@ -1309,7 +1317,7 @@ roff_cond(ROFF_ARGS)
r->last->endspan = -1;
pos += 2;
goto out;
- }
+ }
/*
* Anything else following the conditional causes
@@ -1318,7 +1326,8 @@ roff_cond(ROFF_ARGS)
*/
if ('\0' == (*bufp)[pos])
- mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_COND_EMPTY, r->parse,
+ ln, ppos, roffs[tok].name);
r->last->endspan = 1;
@@ -1327,37 +1336,235 @@ out:
return(ROFF_RERUN);
}
-
-/* ARGSUSED */
static enum rofferr
roff_ds(ROFF_ARGS)
{
- char *name, *string;
+ char *string;
+ const char *name;
+ size_t namesz;
/*
- * A symbol is named by the first word following the macro
- * invocation up to a space. Its value is anything after the
- * name's trailing whitespace and optional double-quote. Thus,
- *
- * [.ds foo "bar " ]
- *
- * will have `bar " ' as its value.
+ * The first word is the name of the string.
+ * If it is empty or terminated by an escape sequence,
+ * abort the `ds' request without defining anything.
*/
- string = *bufp + pos;
- name = roff_getname(r, &string, ln, pos);
+ name = string = *bufp + pos;
if ('\0' == *name)
return(ROFF_IGN);
- /* Read past initial double-quote. */
+ namesz = roff_getname(r, &string, ln, pos);
+ if ('\\' == name[namesz])
+ return(ROFF_IGN);
+
+ /* Read past the initial double-quote, if any. */
if ('"' == *string)
string++;
/* The rest is the value. */
- roff_setstr(r, name, string, 0);
+ roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
+ ROFF_as == tok);
return(ROFF_IGN);
}
+/*
+ * Parse a single operator, one or two characters long.
+ * If the operator is recognized, return success and advance the
+ * parse point, else return failure and let the parse point unchanged.
+ */
+static int
+roff_getop(const char *v, int *pos, char *res)
+{
+
+ *res = v[*pos];
+
+ switch (*res) {
+ case '+':
+ /* FALLTHROUGH */
+ case '-':
+ /* FALLTHROUGH */
+ case '*':
+ /* FALLTHROUGH */
+ case '/':
+ /* FALLTHROUGH */
+ case '%':
+ /* FALLTHROUGH */
+ case '&':
+ /* FALLTHROUGH */
+ case ':':
+ break;
+ case '<':
+ switch (v[*pos + 1]) {
+ case '=':
+ *res = 'l';
+ (*pos)++;
+ break;
+ case '>':
+ *res = '!';
+ (*pos)++;
+ break;
+ case '?':
+ *res = 'i';
+ (*pos)++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case '>':
+ switch (v[*pos + 1]) {
+ case '=':
+ *res = 'g';
+ (*pos)++;
+ break;
+ case '?':
+ *res = 'a';
+ (*pos)++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case '=':
+ if ('=' == v[*pos + 1])
+ (*pos)++;
+ break;
+ default:
+ return(0);
+ }
+ (*pos)++;
+
+ return(*res);
+}
+
+/*
+ * Evaluate either a parenthesized numeric expression
+ * or a single signed integer number.
+ */
+static int
+roff_evalpar(const char *v, int *pos, int *res)
+{
+
+ if ('(' != v[*pos])
+ return(roff_getnum(v, pos, res));
+
+ (*pos)++;
+ if ( ! roff_evalnum(v, pos, res, 1))
+ return(0);
+
+ /*
+ * Omission of the closing parenthesis
+ * is an error in validation mode,
+ * but ignored in evaluation mode.
+ */
+
+ if (')' == v[*pos])
+ (*pos)++;
+ else if (NULL == res)
+ return(0);
+
+ return(1);
+}
+
+/*
+ * Evaluate a complete numeric expression.
+ * Proceed left to right, there is no concept of precedence.
+ */
+static int
+roff_evalnum(const char *v, int *pos, int *res, int skipwhite)
+{
+ int mypos, operand2;
+ char operator;
+
+ if (NULL == pos) {
+ mypos = 0;
+ pos = &mypos;
+ }
+
+ if (skipwhite)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if ( ! roff_evalpar(v, pos, res))
+ return(0);
+
+ while (1) {
+ if (skipwhite)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if ( ! roff_getop(v, pos, &operator))
+ break;
+
+ if (skipwhite)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if ( ! roff_evalpar(v, pos, &operand2))
+ return(0);
+
+ if (skipwhite)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if (NULL == res)
+ continue;
+
+ switch (operator) {
+ case '+':
+ *res += operand2;
+ break;
+ case '-':
+ *res -= operand2;
+ break;
+ case '*':
+ *res *= operand2;
+ break;
+ case '/':
+ *res /= operand2;
+ break;
+ case '%':
+ *res %= operand2;
+ break;
+ case '<':
+ *res = *res < operand2;
+ break;
+ case '>':
+ *res = *res > operand2;
+ break;
+ case 'l':
+ *res = *res <= operand2;
+ break;
+ case 'g':
+ *res = *res >= operand2;
+ break;
+ case '=':
+ *res = *res == operand2;
+ break;
+ case '!':
+ *res = *res != operand2;
+ break;
+ case '&':
+ *res = *res && operand2;
+ break;
+ case ':':
+ *res = *res || operand2;
+ break;
+ case 'i':
+ if (operand2 < *res)
+ *res = operand2;
+ break;
+ case 'a':
+ if (operand2 > *res)
+ *res = operand2;
+ break;
+ default:
+ abort();
+ }
+ }
+ return(1);
+}
+
void
roff_setreg(struct roff *r, const char *name, int val, char sign)
{
@@ -1387,10 +1594,45 @@ roff_setreg(struct roff *r, const char *name, int val, char sign)
reg->val = val;
}
+/*
+ * Handle some predefined read-only number registers.
+ * For now, return -1 if the requested register is not predefined;
+ * in case a predefined read-only register having the value -1
+ * were to turn up, another special value would have to be chosen.
+ */
+static int
+roff_getregro(const char *name)
+{
+
+ switch (*name) {
+ case 'A': /* ASCII approximation mode is always off. */
+ return(0);
+ case 'g': /* Groff compatibility mode is always on. */
+ return(1);
+ case 'H': /* Fixed horizontal resolution. */
+ return (24);
+ case 'j': /* Always adjust left margin only. */
+ return(0);
+ case 'T': /* Some output device is always defined. */
+ return(1);
+ case 'V': /* Fixed vertical resolution. */
+ return (40);
+ default:
+ return (-1);
+ }
+}
+
int
roff_getreg(const struct roff *r, const char *name)
{
struct roffreg *reg;
+ int val;
+
+ if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
+ val = roff_getregro(name + 1);
+ if (-1 != val)
+ return (val);
+ }
for (reg = r->regtab; reg; reg = reg->next)
if (0 == strcmp(name, reg->key.p))
@@ -1403,6 +1645,13 @@ static int
roff_getregn(const struct roff *r, const char *name, size_t len)
{
struct roffreg *reg;
+ int val;
+
+ if ('.' == name[0] && 2 == len) {
+ val = roff_getregro(name + 1);
+ if (-1 != val)
+ return (val);
+ }
for (reg = r->regtab; reg; reg = reg->next)
if (len == reg->key.sz &&
@@ -1425,48 +1674,79 @@ roff_freereg(struct roffreg *reg)
}
}
-/* ARGSUSED */
static enum rofferr
roff_nr(ROFF_ARGS)
{
- const char *key;
- char *val;
- size_t sz;
+ char *key, *val;
+ size_t keysz;
int iv;
char sign;
- val = *bufp + pos;
- key = roff_getname(r, &val, ln, pos);
+ key = val = *bufp + pos;
+ if ('\0' == *key)
+ return(ROFF_IGN);
+
+ keysz = roff_getname(r, &val, ln, pos);
+ if ('\\' == key[keysz])
+ return(ROFF_IGN);
+ key[keysz] = '\0';
sign = *val;
if ('+' == sign || '-' == sign)
val++;
- sz = strspn(val, "0123456789");
- iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
+ if (roff_evalnum(val, NULL, &iv, 0))
+ roff_setreg(r, key, iv, sign);
+
+ return(ROFF_IGN);
+}
- roff_setreg(r, key, iv, sign);
+static enum rofferr
+roff_rr(ROFF_ARGS)
+{
+ struct roffreg *reg, **prev;
+ char *name, *cp;
+ size_t namesz;
+ name = cp = *bufp + pos;
+ if ('\0' == *name)
+ return(ROFF_IGN);
+ namesz = roff_getname(r, &cp, ln, pos);
+ name[namesz] = '\0';
+
+ prev = &r->regtab;
+ while (1) {
+ reg = *prev;
+ if (NULL == reg || !strcmp(name, reg->key.p))
+ break;
+ prev = &reg->next;
+ }
+ if (NULL != reg) {
+ *prev = reg->next;
+ free(reg->key.p);
+ free(reg);
+ }
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_rm(ROFF_ARGS)
{
const char *name;
char *cp;
+ size_t namesz;
cp = *bufp + pos;
while ('\0' != *cp) {
- name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
- if ('\0' != *name)
- roff_setstr(r, name, NULL, 0);
+ name = cp;
+ namesz = roff_getname(r, &cp, ln, (int)(cp - *bufp));
+ roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
+ if ('\\' == name[namesz])
+ break;
}
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_it(ROFF_ARGS)
{
@@ -1479,8 +1759,8 @@ roff_it(ROFF_ARGS)
len = strcspn(cp, " \t");
cp[len] = '\0';
if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
- mandoc_msg(MANDOCERR_NUMERIC, r->parse,
- ln, ppos, *bufp + 1);
+ mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
+ ln, ppos, *bufp + 1);
return(ROFF_IGN);
}
cp += len + 1;
@@ -1491,52 +1771,50 @@ roff_it(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_Dd(ROFF_ARGS)
{
const char *const *cp;
- if (MPARSE_MDOC != r->parsetype)
+ if (0 == ((MPARSE_MDOC | MPARSE_QUICK) & r->options))
for (cp = __mdoc_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
return(ROFF_CONT);
}
-/* ARGSUSED */
static enum rofferr
roff_TH(ROFF_ARGS)
{
const char *const *cp;
- if (MPARSE_MDOC != r->parsetype)
+ if (0 == (MPARSE_QUICK & r->options))
for (cp = __man_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
return(ROFF_CONT);
}
-/* ARGSUSED */
static enum rofferr
roff_TE(ROFF_ARGS)
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "TE");
else
tbl_end(&r->tbl);
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_T_(ROFF_ARGS)
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "T&");
else
tbl_restart(ppos, ln, r->tbl);
@@ -1553,7 +1831,7 @@ roff_closeeqn(struct roff *r)
#endif
static void
-roff_openeqn(struct roff *r, const char *name, int line,
+roff_openeqn(struct roff *r, const char *name, int line,
int offs, const char *buf)
{
struct eqn_node *e;
@@ -1575,7 +1853,6 @@ roff_openeqn(struct roff *r, const char *name, int line,
}
}
-/* ARGSUSED */
static enum rofferr
roff_EQ(ROFF_ARGS)
{
@@ -1584,23 +1861,22 @@ roff_EQ(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_EN(ROFF_ARGS)
{
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_TS(ROFF_ARGS)
{
struct tbl_node *tbl;
if (r->tbl) {
- mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
+ ln, ppos, "TS breaks TS");
tbl_end(&r->tbl);
}
@@ -1615,7 +1891,6 @@ roff_TS(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_cc(ROFF_ARGS)
{
@@ -1632,7 +1907,6 @@ roff_cc(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_tr(ROFF_ARGS)
{
@@ -1654,9 +1928,8 @@ roff_tr(ROFF_ARGS)
if ('\\' == *first) {
esc = mandoc_escape(&p, NULL, NULL);
if (ESCAPE_ERROR == esc) {
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(p - *bufp), NULL);
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(p - *bufp), first);
return(ROFF_IGN);
}
fsz = (size_t)(p - first);
@@ -1666,28 +1939,27 @@ roff_tr(ROFF_ARGS)
if ('\\' == *second) {
esc = mandoc_escape(&p, NULL, NULL);
if (ESCAPE_ERROR == esc) {
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(p - *bufp), NULL);
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(p - *bufp), second);
return(ROFF_IGN);
}
ssz = (size_t)(p - second);
} else if ('\0' == *second) {
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
- ln, (int)(p - *bufp), NULL);
+ mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
+ ln, (int)(p - *bufp), NULL);
second = " ";
p--;
}
if (fsz > 1) {
- roff_setstrn(&r->xmbtab, first,
- fsz, second, ssz, 0);
+ roff_setstrn(&r->xmbtab, first, fsz,
+ second, ssz, 0);
continue;
}
if (NULL == r->xtab)
- r->xtab = mandoc_calloc
- (128, sizeof(struct roffstr));
+ r->xtab = mandoc_calloc(128,
+ sizeof(struct roffstr));
free(r->xtab[(int)*first].p);
r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
@@ -1697,13 +1969,13 @@ roff_tr(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_so(ROFF_ARGS)
{
char *name;
- mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
+ name = *bufp + pos;
+ mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
/*
* Handle `so'. Be EXTREMELY careful, as we shouldn't be
@@ -1712,9 +1984,9 @@ roff_so(ROFF_ARGS)
* or using absolute paths.
*/
- name = *bufp + pos;
if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
- mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
+ mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
+ ".so %s", name);
return(ROFF_ERR);
}
@@ -1722,7 +1994,6 @@ roff_so(ROFF_ARGS)
return(ROFF_SO);
}
-/* ARGSUSED */
static enum rofferr
roff_userdef(ROFF_ARGS)
{
@@ -1751,14 +2022,9 @@ roff_userdef(ROFF_ARGS)
cp += 2;
continue;
}
-
- *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
- n2 = mandoc_malloc(*szp);
-
- strlcpy(n2, n1, (size_t)(cp - n1 + 1));
- strlcat(n2, arg[i], *szp);
- strlcat(n2, cp + 3, *szp);
-
+ *cp = '\0';
+ *szp = mandoc_asprintf(&n2, "%s%s%s",
+ n1, arg[i], cp + 3) + 1;
cp = n2 + (cp - n1);
free(n1);
n1 = n2;
@@ -1777,57 +2043,63 @@ roff_userdef(ROFF_ARGS)
ROFF_REPARSE : ROFF_APPEND);
}
-static char *
+static size_t
roff_getname(struct roff *r, char **cpp, int ln, int pos)
{
char *name, *cp;
+ size_t namesz;
name = *cpp;
if ('\0' == *name)
- return(name);
+ return(0);
- /* Read until end of name. */
- for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
+ /* Read until end of name and terminate it with NUL. */
+ for (cp = name; 1; cp++) {
+ if ('\0' == *cp || ' ' == *cp) {
+ namesz = cp - name;
+ break;
+ }
if ('\\' != *cp)
continue;
+ namesz = cp - name;
+ if ('{' == cp[1] || '}' == cp[1])
+ break;
cp++;
if ('\\' == *cp)
continue;
- mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
- *cp = '\0';
- name = cp;
+ mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
+ "%.*s", (int)(cp - name + 1), name);
+ mandoc_escape((const char **)&cp, NULL, NULL);
+ break;
}
- /* Nil-terminate name. */
- if ('\0' != *cp)
- *(cp++) = '\0';
-
/* Read past spaces. */
while (' ' == *cp)
cp++;
*cpp = cp;
- return(name);
+ return(namesz);
}
/*
* Store *string into the user-defined string called *name.
- * In multiline mode, append to an existing entry and append '\n';
- * else replace the existing entry, if there is one.
* To clear an existing entry, call with (*r, *name, NULL, 0).
+ * append == 0: replace mode
+ * append == 1: single-line append mode
+ * append == 2: multiline append mode, append '\n' after each call
*/
static void
roff_setstr(struct roff *r, const char *name, const char *string,
- int multiline)
+ int append)
{
roff_setstrn(&r->strtab, name, strlen(name), string,
- string ? strlen(string) : 0, multiline);
+ string ? strlen(string) : 0, append);
}
static void
roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
- const char *string, size_t stringsz, int multiline)
+ const char *string, size_t stringsz, int append)
{
struct roffkv *n;
char *c;
@@ -1837,7 +2109,8 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
/* Search for an existing string with the same name. */
n = *r;
- while (n && strcmp(name, n->key.p))
+ while (n && (namesz != n->key.sz ||
+ strncmp(n->key.p, name, namesz)))
n = n->next;
if (NULL == n) {
@@ -1849,8 +2122,7 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
n->val.sz = 0;
n->next = *r;
*r = n;
- } else if (0 == multiline) {
- /* In multiline mode, append; else replace. */
+ } else if (0 == append) {
free(n->val.p);
n->val.p = NULL;
n->val.sz = 0;
@@ -1863,7 +2135,7 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
* One additional byte for the '\n' in multiline mode,
* and one for the terminating '\0'.
*/
- newch = stringsz + (multiline ? 2u : 1u);
+ newch = stringsz + (1 < append ? 2u : 1u);
if (NULL == n->val.p) {
n->val.p = mandoc_malloc(newch);
@@ -1890,7 +2162,7 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
}
/* Append terminating bytes. */
- if (multiline)
+ if (1 < append)
*c++ = '\n';
*c = '\0';
@@ -1901,12 +2173,18 @@ static const char *
roff_getstrn(const struct roff *r, const char *name, size_t len)
{
const struct roffkv *n;
+ int i;
for (n = r->strtab; n; n = n->next)
- if (0 == strncmp(name, n->key.p, len) &&
- '\0' == n->key.p[(int)len])
+ if (0 == strncmp(name, n->key.p, len) &&
+ '\0' == n->key.p[(int)len])
return(n->val.p);
+ for (i = 0; i < PREDEFS_MAX; i++)
+ if (0 == strncmp(name, predefs[i].name, len) &&
+ '\0' == predefs[i].name[(int)len])
+ return(predefs[i].str);
+
return(NULL);
}
@@ -1926,14 +2204,14 @@ roff_freestr(struct roffkv *r)
const struct tbl_span *
roff_span(const struct roff *r)
{
-
+
return(r->tbl ? tbl_span(r->tbl) : NULL);
}
const struct eqn *
roff_eqn(const struct roff *r)
{
-
+
return(r->last_eqn ? &r->last_eqn->eqn : NULL);
}
@@ -1992,8 +2270,8 @@ roff_strdup(const struct roff *r, const char *p)
* Append the match to the array and move
* forward by its keysize.
*/
- res = mandoc_realloc
- (res, ssz + cp->val.sz + 1);
+ res = mandoc_realloc(res,
+ ssz + cp->val.sz + 1);
memcpy(res + ssz, cp->val.p, cp->val.sz);
ssz += cp->val.sz;
p += (int)cp->key.sz;
@@ -2014,8 +2292,8 @@ roff_strdup(const struct roff *r, const char *p)
memcpy(res + ssz, pp, sz);
break;
}
- /*
- * We bail out on bad escapes.
+ /*
+ * We bail out on bad escapes.
* No need to warn: we already did so when
* roff_res() was called.
*/
@@ -2030,7 +2308,7 @@ roff_strdup(const struct roff *r, const char *p)
}
/*
- * Find out whether a line is a macro line or not.
+ * Find out whether a line is a macro line or not.
* If it is, adjust the current position and return one; if it isn't,
* return zero and don't change the current position.
* If the control character has been set with `.cc', then let that grain
diff --git a/contrib/mdocml/st.c b/contrib/mdocml/st.c
index 70c21a2..ab6f0f2 100644
--- a/contrib/mdocml/st.c
+++ b/contrib/mdocml/st.c
@@ -1,4 +1,4 @@
-/* $Id: st.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: st.c,v 1.10 2014/03/23 11:25:26 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,12 +18,9 @@
#include "config.h"
#endif
-#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
diff --git a/contrib/mdocml/st.in b/contrib/mdocml/st.in
index c52ddab..481e44e 100644
--- a/contrib/mdocml/st.in
+++ b/contrib/mdocml/st.in
@@ -1,4 +1,4 @@
-/* $Id: st.in,v 1.22 2013/12/25 14:09:32 schwarze Exp $ */
+/* $Id: st.in,v 1.24 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -22,7 +22,7 @@
* the formatted output string.
*
* Be sure to escape strings.
- * The non-breaking blanks prevent ending an output line right before
+ * The non-breaking blanks prevent ending an output line right before
* a number. Groff prevent line breaks at the same places.
*
* REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
@@ -34,6 +34,7 @@ LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
+LINE("-p1003.1-2013", "IEEE Std 1003.1-2008/Cor 1-2013 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
diff --git a/contrib/mdocml/tbl.c b/contrib/mdocml/tbl.c
index b244ac8..3c94d7e 100644
--- a/contrib/mdocml/tbl.c
+++ b/contrib/mdocml/tbl.c
@@ -1,4 +1,4 @@
-/* $Id: tbl.c,v 1.27 2013/05/31 22:08:09 schwarze Exp $ */
+/* $Id: tbl.c,v 1.29 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -26,9 +26,11 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
+
enum rofferr
tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs)
{
@@ -52,11 +54,11 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs)
/* Now process each logical section of the table. */
switch (tbl->part) {
- case (TBL_PART_OPTS):
+ case TBL_PART_OPTS:
return(tbl_option(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
- case (TBL_PART_LAYOUT):
+ case TBL_PART_LAYOUT:
return(tbl_layout(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
- case (TBL_PART_CDATA):
+ case TBL_PART_CDATA:
return(tbl_cdata(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
default:
break;
@@ -128,8 +130,8 @@ void
tbl_restart(int line, int pos, struct tbl_node *tbl)
{
if (TBL_PART_CDATA == tbl->part)
- mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
+ tbl->line, tbl->pos, NULL);
tbl->part = TBL_PART_LAYOUT;
tbl->line = line;
@@ -137,7 +139,7 @@ tbl_restart(int line, int pos, struct tbl_node *tbl)
if (NULL == tbl->first_span || NULL == tbl->first_span->first)
mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ tbl->line, tbl->pos, NULL);
}
const struct tbl_span *
@@ -162,14 +164,13 @@ tbl_end(struct tbl_node **tblp)
*tblp = NULL;
if (NULL == tbl->first_span || NULL == tbl->first_span->first)
- mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
+ tbl->line, tbl->pos, NULL);
if (tbl->last_span)
tbl->last_span->flags |= TBL_SPAN_LAST;
if (TBL_PART_CDATA == tbl->part)
- mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
+ tbl->line, tbl->pos, NULL);
}
-
diff --git a/contrib/mdocml/tbl_data.c b/contrib/mdocml/tbl_data.c
index 7413aa2..1db24a6 100644
--- a/contrib/mdocml/tbl_data.c
+++ b/contrib/mdocml/tbl_data.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_data.c,v 1.27 2013/06/01 04:56:50 schwarze Exp $ */
+/* $Id: tbl_data.c,v 1.31 2014/04/23 16:08:33 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -26,16 +26,18 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
-static int data(struct tbl_node *, struct tbl_span *,
+static int getdata(struct tbl_node *, struct tbl_span *,
int, const char *, int *);
-static struct tbl_span *newspan(struct tbl_node *, int,
+static struct tbl_span *newspan(struct tbl_node *, int,
struct tbl_row *);
+
static int
-data(struct tbl_node *tbl, struct tbl_span *dp,
+getdata(struct tbl_node *tbl, struct tbl_span *dp,
int ln, const char *p, int *pos)
{
struct tbl_dat *dat;
@@ -48,7 +50,7 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
else if (NULL == dp->last)
cp = dp->layout->first;
- /*
+ /*
* Skip over spanners, since
* we want to match data with data layout cells in the header.
*/
@@ -62,8 +64,8 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
*/
if (NULL == cp) {
- mandoc_msg(MANDOCERR_TBLEXTRADAT,
- tbl->parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBLEXTRADAT, tbl->parse,
+ ln, *pos, NULL);
/* Skip to the end... */
while (p[*pos])
(*pos)++;
@@ -81,7 +83,7 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
spans++;
else
break;
-
+
dat->spans = spans;
if (dp->last) {
@@ -126,21 +128,20 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
dat->pos = TBL_DATA_DATA;
if (TBL_CELL_HORIZ == dat->layout->pos ||
- TBL_CELL_DHORIZ == dat->layout->pos ||
- TBL_CELL_DOWN == dat->layout->pos)
+ TBL_CELL_DHORIZ == dat->layout->pos ||
+ TBL_CELL_DOWN == dat->layout->pos)
if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
- mandoc_msg(MANDOCERR_TBLIGNDATA,
- tbl->parse, ln, sv, NULL);
+ mandoc_msg(MANDOCERR_TBLIGNDATA,
+ tbl->parse, ln, sv, NULL);
return(1);
}
-/* ARGSUSED */
int
tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
{
struct tbl_dat *dat;
- size_t sz;
+ size_t sz;
int pos;
pos = 0;
@@ -152,7 +153,7 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
if (p[pos] == tbl->opts.tab) {
tbl->part = TBL_PART_DATA;
pos++;
- return(data(tbl, tbl->last_span, ln, p, &pos));
+ return(getdata(tbl, tbl->last_span, ln, p, &pos));
} else if ('\0' == p[pos]) {
tbl->part = TBL_PART_DATA;
return(1);
@@ -166,14 +167,14 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
if (dat->string) {
sz = strlen(p) + strlen(dat->string) + 2;
dat->string = mandoc_realloc(dat->string, sz);
- strlcat(dat->string, " ", sz);
- strlcat(dat->string, p, sz);
+ (void)strlcat(dat->string, " ", sz);
+ (void)strlcat(dat->string, p, sz);
} else
dat->string = mandoc_strdup(p);
- if (TBL_CELL_DOWN == dat->layout->pos)
- mandoc_msg(MANDOCERR_TBLIGNDATA,
- tbl->parse, ln, pos, NULL);
+ if (TBL_CELL_DOWN == dat->layout->pos)
+ mandoc_msg(MANDOCERR_TBLIGNDATA, tbl->parse,
+ ln, pos, NULL);
return(0);
}
@@ -215,7 +216,7 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
return(0);
}
- /*
+ /*
* Choose a layout row: take the one following the last parsed
* span's. If that doesn't exist, use the last parsed span's.
* If there's no last parsed span, use the first row. Lastly,
@@ -229,11 +230,11 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
for (rp = tbl->last_span->layout->next;
rp && rp->first; rp = rp->next) {
switch (rp->first->pos) {
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
dp = newspan(tbl, ln, rp);
dp->pos = TBL_SPAN_HORIZ;
continue;
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
dp = newspan(tbl, ln, rp);
dp->pos = TBL_SPAN_DHORIZ;
continue;
@@ -267,7 +268,7 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
/* This returns 0 when TBL_PART_CDATA is entered. */
while ('\0' != p[pos])
- if ( ! data(tbl, dp, ln, p, &pos))
+ if ( ! getdata(tbl, dp, ln, p, &pos))
return(0);
return(1);
diff --git a/contrib/mdocml/tbl_html.c b/contrib/mdocml/tbl_html.c
index 6b8ced7..4b85d06 100644
--- a/contrib/mdocml/tbl_html.c
+++ b/contrib/mdocml/tbl_html.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_html.c,v 1.10 2012/05/27 17:54:54 schwarze Exp $ */
+/* $Id: tbl_html.c,v 1.11 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -31,15 +31,14 @@ static void html_tblopen(struct html *, const struct tbl_span *);
static size_t html_tbl_len(size_t, void *);
static size_t html_tbl_strlen(const char *, void *);
-/* ARGSUSED */
+
static size_t
html_tbl_len(size_t sz, void *arg)
{
-
+
return(sz);
}
-/* ARGSUSED */
static size_t
html_tbl_strlen(const char *p, void *arg)
{
@@ -107,9 +106,9 @@ print_tbl(struct html *h, const struct tbl_span *sp)
tt = print_otag(h, TAG_TR, 0, NULL);
switch (sp->pos) {
- case (TBL_SPAN_HORIZ):
+ case TBL_SPAN_HORIZ:
/* FALLTHROUGH */
- case (TBL_SPAN_DHORIZ):
+ case TBL_SPAN_DHORIZ:
PAIR_INIT(&tag, ATTR_COLSPAN, "0");
print_otag(h, TAG_TD, 1, &tag);
break;
diff --git a/contrib/mdocml/tbl_layout.c b/contrib/mdocml/tbl_layout.c
index 6cce977..f025823 100644
--- a/contrib/mdocml/tbl_layout.c
+++ b/contrib/mdocml/tbl_layout.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_layout.c,v 1.23 2012/05/27 17:54:54 schwarze Exp $ */
+/* $Id: tbl_layout.c,v 1.26 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,13 +19,13 @@
#include "config.h"
#endif
-#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
@@ -55,16 +55,17 @@ static const struct tbl_phrase keys[KEYS_MAX] = {
{ '=', TBL_CELL_DHORIZ }
};
-static int mods(struct tbl_node *, struct tbl_cell *,
+static int mods(struct tbl_node *, struct tbl_cell *,
int, const char *, int *);
-static int cell(struct tbl_node *, struct tbl_row *,
+static int cell(struct tbl_node *, struct tbl_row *,
int, const char *, int *);
static void row(struct tbl_node *, int, const char *, int *);
static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
enum tbl_cellt, int vert);
+
static int
-mods(struct tbl_node *tbl, struct tbl_cell *cp,
+mods(struct tbl_node *tbl, struct tbl_cell *cp,
int ln, const char *p, int *pos)
{
char buf[5];
@@ -73,33 +74,35 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
/* Not all types accept modifiers. */
switch (cp->pos) {
- case (TBL_CELL_DOWN):
+ case TBL_CELL_DOWN:
/* FALLTHROUGH */
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
/* FALLTHROUGH */
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
return(1);
default:
break;
}
mod:
- /*
+ /*
* XXX: since, at least for now, modifiers are non-conflicting
* (are separable by value, regardless of position), we let
* modifiers come in any order. The existing tbl doesn't let
* this happen.
*/
switch (p[*pos]) {
- case ('\0'):
+ case '\0':
+ /* FALLTHROUGH */
+ case ' ':
/* FALLTHROUGH */
- case (' '):
+ case '\t':
/* FALLTHROUGH */
- case ('\t'):
+ case ',':
/* FALLTHROUGH */
- case (','):
+ case '.':
/* FALLTHROUGH */
- case ('.'):
+ case '|':
return(1);
default:
break;
@@ -115,8 +118,8 @@ mod:
(*pos)++;
goto mod;
}
- mandoc_msg(MANDOCERR_TBLLAYOUT,
- tbl->parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
+ ln, *pos, NULL);
return(0);
}
@@ -133,8 +136,8 @@ mod:
/* No greater than 4 digits. */
if (4 == i) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBLLAYOUT,
+ tbl->parse, ln, *pos, NULL);
return(0);
}
@@ -143,69 +146,69 @@ mod:
goto mod;
/* NOTREACHED */
- }
+ }
/* TODO: GNU has many more extensions. */
switch (tolower((unsigned char)p[(*pos)++])) {
- case ('z'):
+ case 'z':
cp->flags |= TBL_CELL_WIGN;
goto mod;
- case ('u'):
+ case 'u':
cp->flags |= TBL_CELL_UP;
goto mod;
- case ('e'):
+ case 'e':
cp->flags |= TBL_CELL_EQUAL;
goto mod;
- case ('t'):
+ case 't':
cp->flags |= TBL_CELL_TALIGN;
goto mod;
- case ('d'):
+ case 'd':
cp->flags |= TBL_CELL_BALIGN;
goto mod;
- case ('w'): /* XXX for now, ignore minimal column width */
+ case 'w': /* XXX for now, ignore minimal column width */
goto mod;
- case ('f'):
+ case 'f':
break;
- case ('r'):
+ case 'r':
/* FALLTHROUGH */
- case ('b'):
+ case 'b':
/* FALLTHROUGH */
- case ('i'):
+ case 'i':
(*pos)--;
break;
default:
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos - 1, NULL);
+ ln, *pos - 1, NULL);
return(0);
}
switch (tolower((unsigned char)p[(*pos)++])) {
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('b'):
+ case 'b':
cp->flags |= TBL_CELL_BOLD;
goto mod;
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('i'):
+ case 'i':
cp->flags |= TBL_CELL_ITALIC;
goto mod;
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('r'):
+ case 'r':
goto mod;
default:
break;
}
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos - 1, NULL);
+ ln, *pos - 1, NULL);
return(0);
}
static int
-cell(struct tbl_node *tbl, struct tbl_row *rp,
+cell(struct tbl_node *tbl, struct tbl_row *rp,
int ln, const char *p, int *pos)
{
int vert, i;
@@ -218,6 +221,13 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
while (' ' == p[*pos])
(*pos)++;
+ /* Handle trailing vertical lines */
+
+ if ('.' == p[*pos] || '\0' == p[*pos]) {
+ rp->vert = vert;
+ return(1);
+ }
+
/* Parse the column position (`c', `l', `r', ...). */
for (i = 0; i < KEYS_MAX; i++)
@@ -225,8 +235,8 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
break;
if (KEYS_MAX == i) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
+ ln, *pos, NULL);
return(0);
}
@@ -243,14 +253,15 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
if (TBL_CELL_SPAN == c) {
if (NULL == rp->first) {
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
+ ln, *pos, NULL);
return(0);
} else if (rp->last)
switch (rp->last->pos) {
- case (TBL_CELL_HORIZ):
- case (TBL_CELL_DHORIZ):
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
+ case TBL_CELL_HORIZ:
+ /* FALLTHROUGH */
+ case TBL_CELL_DHORIZ:
+ mandoc_msg(MANDOCERR_TBLLAYOUT,
+ tbl->parse, ln, *pos, NULL);
return(0);
default:
break;
@@ -281,7 +292,6 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos));
}
-
static void
row(struct tbl_node *tbl, int ln, const char *p, int *pos)
{
@@ -312,9 +322,9 @@ cell:
if ('.' == p[*pos]) {
tbl->part = TBL_PART_DATA;
- if (NULL == tbl->first_row)
- mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse,
- ln, *pos, NULL);
+ if (NULL == tbl->first_row)
+ mandoc_msg(MANDOCERR_TBLNOLAYOUT,
+ tbl->parse, ln, *pos, NULL);
(*pos)++;
return;
}
diff --git a/contrib/mdocml/tbl_opts.c b/contrib/mdocml/tbl_opts.c
index 5bd67f8..ae4df4a 100644
--- a/contrib/mdocml/tbl_opts.c
+++ b/contrib/mdocml/tbl_opts.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_opts.c,v 1.12 2011/09/18 14:14:15 schwarze Exp $ */
+/* $Id: tbl_opts.c,v 1.13 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -62,10 +62,10 @@ struct tbl_phrase {
static const struct tbl_phrase keys[KEY_MAXKEYS] = {
{ "center", TBL_OPT_CENTRE, KEY_CENTRE},
{ "centre", TBL_OPT_CENTRE, KEY_CENTRE},
- { "delim", 0, KEY_DELIM},
+ { "delim", 0, KEY_DELIM},
{ "expand", TBL_OPT_EXPAND, KEY_EXPAND},
- { "box", TBL_OPT_BOX, KEY_BOX},
- { "doublebox", TBL_OPT_DBOX, KEY_DBOX},
+ { "box", TBL_OPT_BOX, KEY_BOX},
+ { "doublebox", TBL_OPT_DBOX, KEY_DBOX},
{ "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX},
{ "frame", TBL_OPT_BOX, KEY_FRAME},
{ "doubleframe", TBL_OPT_DBOX, KEY_DFRAME},
@@ -76,11 +76,12 @@ static const struct tbl_phrase keys[KEY_MAXKEYS] = {
{ "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE},
};
-static int arg(struct tbl_node *, int,
+static int arg(struct tbl_node *, int,
const char *, int *, enum tbl_ident);
-static void opt(struct tbl_node *, int,
+static void opt(struct tbl_node *, int,
const char *, int *);
+
static int
arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
{
@@ -93,8 +94,8 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
/* Arguments always begin with a parenthesis. */
if ('(' != p[*pos]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBL, tbl->parse,
+ ln, *pos, NULL);
return(0);
}
@@ -107,27 +108,27 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
*/
switch (key) {
- case (KEY_DELIM):
+ case KEY_DELIM:
if ('\0' == p[(*pos)++]) {
mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
+ ln, *pos - 1, NULL);
return(0);
- }
+ }
if ('\0' == p[(*pos)++]) {
mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
+ ln, *pos - 1, NULL);
return(0);
- }
+ }
break;
- case (KEY_TAB):
+ case KEY_TAB:
if ('\0' != (tbl->opts.tab = p[(*pos)++]))
break;
mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
+ ln, *pos - 1, NULL);
return(0);
- case (KEY_LINESIZE):
+ case KEY_LINESIZE:
for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {
buf[i] = p[*pos];
if ( ! isdigit((unsigned char)buf[i]))
@@ -142,12 +143,12 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
return(0);
- case (KEY_DPOINT):
+ case KEY_DPOINT:
if ('\0' != (tbl->opts.decimal = p[(*pos)++]))
break;
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
+ mandoc_msg(MANDOCERR_TBL, tbl->parse,
+ ln, *pos - 1, NULL);
return(0);
default:
abort();
@@ -182,7 +183,7 @@ again: /*
* options ::= option_list [:space:]* [;][\n]
* option_list ::= option option_tail
* option_tail ::= [:space:]+ option_list |
- * ::= epsilon
+ * ::= epsilon
* option ::= [:alpha:]+ args
* args ::= [:space:]* [(] [:alpha:]+ [)]
*/
@@ -215,7 +216,7 @@ again: /*
while (isspace((unsigned char)p[*pos]))
(*pos)++;
- /*
+ /*
* Look through all of the available keys to find one that
* matches the input. FIXME: hashtable this.
*/
@@ -231,7 +232,7 @@ again: /*
* of the sequence altogether.
*/
- if (keys[i].key)
+ if (keys[i].key)
tbl->opts.opts |= keys[i].key;
else if ( ! arg(tbl, ln, p, pos, keys[i].ident))
return;
@@ -239,7 +240,7 @@ again: /*
break;
}
- /*
+ /*
* Allow us to recover from bad options by continuing to another
* parse sequence.
*/
diff --git a/contrib/mdocml/tbl_term.c b/contrib/mdocml/tbl_term.c
index e8411ff..e52831b 100644
--- a/contrib/mdocml/tbl_term.c
+++ b/contrib/mdocml/tbl_term.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */
+/* $Id: tbl_term.c,v 1.27 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -32,14 +32,14 @@ static size_t term_tbl_len(size_t, void *);
static size_t term_tbl_strlen(const char *, void *);
static void tbl_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *,
- const struct tbl_dat *,
+ const struct tbl_dat *,
const struct roffcol *);
static size_t tbl_rulewidth(struct termp *, const struct tbl_head *);
static void tbl_hframe(struct termp *, const struct tbl_span *, int);
-static void tbl_literal(struct termp *, const struct tbl_dat *,
+static void tbl_literal(struct termp *, const struct tbl_dat *,
const struct roffcol *);
-static void tbl_number(struct termp *, const struct tbl_opts *,
- const struct tbl_dat *,
+static void tbl_number(struct termp *, const struct tbl_opts *,
+ const struct tbl_dat *,
const struct roffcol *);
static void tbl_hrule(struct termp *, const struct tbl_span *);
static void tbl_vrule(struct termp *, const struct tbl_head *);
@@ -66,7 +66,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
const struct tbl_dat *dp;
struct roffcol *col;
int spans;
- size_t rmargin, maxrmargin;
+ size_t rmargin, maxrmargin;
rmargin = tp->rmargin;
maxrmargin = tp->maxrmargin;
@@ -105,9 +105,10 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Vertical frame at the start of each row. */
- if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
+ if ((TBL_OPT_BOX | TBL_OPT_DBOX) & sp->opts->opts ||
+ sp->head->vert)
term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
- TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
+ TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
/*
* Now print the actual data itself depending on the span type.
@@ -116,18 +117,18 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
*/
switch (sp->pos) {
- case (TBL_SPAN_HORIZ):
+ case TBL_SPAN_HORIZ:
/* FALLTHROUGH */
- case (TBL_SPAN_DHORIZ):
+ case TBL_SPAN_DHORIZ:
tbl_hrule(tp, sp);
break;
- case (TBL_SPAN_DATA):
+ case TBL_SPAN_DATA:
/* Iterate over template headers. */
dp = sp->first;
spans = 0;
for (hp = sp->head; hp; hp = hp->next) {
- /*
+ /*
* If the current data header is invoked during
* a spanner ("spans" > 0), don't emit anything
* at all.
@@ -144,7 +145,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
col = &tp->tbl.cols[hp->ident];
tbl_data(tp, sp->opts, dp, col);
- /*
+ /*
* Go to the next data cell and assign the
* number of subsequent spans, if applicable.
*/
@@ -159,9 +160,10 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Vertical frame at the end of each row. */
- if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
+ if ((TBL_OPT_BOX | TBL_OPT_DBOX) & sp->opts->opts ||
+ sp->layout->vert)
term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
- TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
+ TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
term_flushln(tp);
/*
@@ -255,8 +257,8 @@ tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
static void
tbl_data(struct termp *tp, const struct tbl_opts *opts,
- const struct tbl_dat *dp,
- const struct roffcol *col)
+ const struct tbl_dat *dp,
+ const struct roffcol *col)
{
if (NULL == dp) {
@@ -266,43 +268,43 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
assert(dp->layout);
switch (dp->pos) {
- case (TBL_DATA_NONE):
+ case TBL_DATA_NONE:
tbl_char(tp, ASCII_NBRSP, col->width);
return;
- case (TBL_DATA_HORIZ):
+ case TBL_DATA_HORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_NHORIZ):
+ case TBL_DATA_NHORIZ:
tbl_char(tp, '-', col->width);
return;
- case (TBL_DATA_NDHORIZ):
+ case TBL_DATA_NDHORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_DHORIZ):
+ case TBL_DATA_DHORIZ:
tbl_char(tp, '=', col->width);
return;
default:
break;
}
-
+
switch (dp->layout->pos) {
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
tbl_char(tp, '-', col->width);
break;
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
tbl_char(tp, '=', col->width);
break;
- case (TBL_CELL_LONG):
+ case TBL_CELL_LONG:
/* FALLTHROUGH */
- case (TBL_CELL_CENTRE):
+ case TBL_CELL_CENTRE:
/* FALLTHROUGH */
- case (TBL_CELL_LEFT):
+ case TBL_CELL_LEFT:
/* FALLTHROUGH */
- case (TBL_CELL_RIGHT):
+ case TBL_CELL_RIGHT:
tbl_literal(tp, dp, col);
break;
- case (TBL_CELL_NUMBER):
+ case TBL_CELL_NUMBER:
tbl_number(tp, opts, dp, col);
break;
- case (TBL_CELL_DOWN):
+ case TBL_CELL_DOWN:
tbl_char(tp, ASCII_NBRSP, col->width);
break;
default:
@@ -338,7 +340,7 @@ tbl_char(struct termp *tp, char c, size_t len)
}
static void
-tbl_literal(struct termp *tp, const struct tbl_dat *dp,
+tbl_literal(struct termp *tp, const struct tbl_dat *dp,
const struct roffcol *col)
{
struct tbl_head *hp;
@@ -357,17 +359,17 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
padl = 0;
switch (dp->layout->pos) {
- case (TBL_CELL_LONG):
+ case TBL_CELL_LONG:
padl = term_len(tp, 1);
padr = padr > padl ? padr - padl : 0;
break;
- case (TBL_CELL_CENTRE):
+ case TBL_CELL_CENTRE:
if (2 > padr)
break;
padl = padr / 2;
padr -= padl;
break;
- case (TBL_CELL_RIGHT):
+ case TBL_CELL_RIGHT:
padl = padr;
padr = 0;
break;
diff --git a/contrib/mdocml/term.c b/contrib/mdocml/term.c
index e7b9557..4d50856 100644
--- a/contrib/mdocml/term.c
+++ b/contrib/mdocml/term.c
@@ -1,7 +1,7 @@
-/* $Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */
+/* $Id: term.c,v 1.226 2014/08/01 19:38:29 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,12 +23,12 @@
#include <assert.h>
#include <ctype.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
#include "main.h"
@@ -39,6 +39,7 @@ static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int);
+
void
term_free(struct termp *p)
{
@@ -51,9 +52,8 @@ term_free(struct termp *p)
free(p);
}
-
void
-term_begin(struct termp *p, term_margin head,
+term_begin(struct termp *p, term_margin head,
term_margin foot, const void *arg)
{
@@ -63,7 +63,6 @@ term_begin(struct termp *p, term_margin head,
(*p->begin)(p);
}
-
void
term_end(struct termp *p)
{
@@ -72,34 +71,27 @@ term_end(struct termp *p)
}
/*
- * Flush a line of text. A "line" is loosely defined as being something
- * that should be followed by a newline, regardless of whether it's
- * broken apart by newlines getting there. A line can also be a
- * fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
- * not have a trailing newline.
- *
+ * Flush a chunk of text. By default, break the output line each time
+ * the right margin is reached, and continue output on the next line
+ * at the same offset as the chunk itself. By default, also break the
+ * output line at the end of the chunk.
* The following flags may be specified:
*
- * - TERMP_NOBREAK: this is the most important and is used when making
- * columns. In short: don't print a newline and instead expect the
- * next call to do the padding up to the start of the next column.
- * p->trailspace may be set to 0, 1, or 2, depending on how many
- * space characters are required at the end of the column.
- *
- * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
- * the line is overrun, and don't pad-right if it's underrun.
- *
- * - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
- * overrunning, instead save the position and continue at that point
- * when the next invocation.
- *
- * In-line line breaking:
- *
- * If TERMP_NOBREAK is specified and the line overruns the right
- * margin, it will break and pad-right to the right margin after
- * writing. If maxrmargin is violated, it will break and continue
- * writing from the right-margin, which will lead to the above scenario
- * upon exit. Otherwise, the line will break at the right margin.
+ * - TERMP_NOBREAK: Do not break the output line at the right margin,
+ * but only at the max right margin. Also, do not break the output
+ * line at the end of the chunk, such that the next call can pad to
+ * the next column. However, if less than p->trailspace blanks,
+ * which can be 0, 1, or 2, remain to the right margin, the line
+ * will be broken.
+ * - TERMP_BRIND: If the chunk does not fit and the output line has
+ * to be broken, start the next line at the right margin instead
+ * of at the offset. Used together with TERMP_NOBREAK for the tags
+ * in various kinds of tagged lists.
+ * - TERMP_DANGLE: Do not break the output line at the right margin,
+ * append the next chunk after it even if this one is too long.
+ * To be used together with TERMP_NOBREAK.
+ * - TERMP_HANG: Like TERMP_DANGLE, and also suppress padding before
+ * the next chunk if this column is not full.
*/
void
term_flushln(struct termp *p)
@@ -178,10 +170,18 @@ term_flushln(struct termp *p)
/* Regular word. */
/* Break at the hyphen point if we overrun. */
- if (vend > vis && vend < bp &&
- ASCII_HYPH == p->buf[j])
+ if (vend > vis && vend < bp &&
+ (ASCII_HYPH == p->buf[j] ||
+ ASCII_BREAK == p->buf[j]))
jhy = j;
+ /*
+ * Hyphenation now decided, put back a real
+ * hyphen such that we get the correct width.
+ */
+ if (ASCII_HYPH == p->buf[j])
+ p->buf[j] = '-';
+
vend += (*p->width)(p, p->buf[j]);
}
@@ -193,7 +193,7 @@ term_flushln(struct termp *p)
vend -= vis;
(*p->endline)(p);
p->viscol = 0;
- if (TERMP_NOBREAK & p->flags) {
+ if (TERMP_BRIND & p->flags) {
vbl = p->rmargin;
vend += p->rmargin - p->offset;
} else
@@ -233,6 +233,8 @@ term_flushln(struct termp *p)
vbl += (*p->width)(p, ' ');
continue;
}
+ if (ASCII_BREAK == p->buf[i])
+ continue;
/*
* Now we definitely know there will be
@@ -245,16 +247,10 @@ term_flushln(struct termp *p)
vbl = 0;
}
- if (ASCII_HYPH == p->buf[i]) {
- (*p->letter)(p, '-');
- p->viscol += (*p->width)(p, '-');
- continue;
- }
-
(*p->letter)(p, p->buf[i]);
if (8 == p->buf[i])
p->viscol -= (*p->width)(p, p->buf[i-1]);
- else
+ else
p->viscol += (*p->width)(p, p->buf[i]);
}
vis = vend;
@@ -278,7 +274,7 @@ term_flushln(struct termp *p)
if (TERMP_HANG & p->flags) {
p->overstep = (int)(vis - maxvis +
- p->trailspace * (*p->width)(p, ' '));
+ p->trailspace * (*p->width)(p, ' '));
/*
* If we have overstepped the margin, temporarily move
@@ -301,8 +297,7 @@ term_flushln(struct termp *p)
}
}
-
-/*
+/*
* A newline only breaks an existing line; it won't assert vertical
* space. All data in the output buffer is flushed prior to the newline
* assertion.
@@ -316,7 +311,6 @@ term_newln(struct termp *p)
term_flushln(p);
}
-
/*
* Asserts a vertical space (a full, empty line-break between lines).
* Note that if used twice, this will cause two blank spaces and so on.
@@ -345,7 +339,6 @@ term_fontlast(struct termp *p)
p->fontq[p->fonti] = f;
}
-
void
term_fontrepl(struct termp *p, enum termfont f)
{
@@ -354,7 +347,6 @@ term_fontrepl(struct termp *p, enum termfont f)
p->fontq[p->fonti] = f;
}
-
void
term_fontpush(struct termp *p, enum termfont f)
{
@@ -364,7 +356,6 @@ term_fontpush(struct termp *p, enum termfont f)
p->fontq[++p->fonti] = f;
}
-
const void *
term_fontq(struct termp *p)
{
@@ -372,7 +363,6 @@ term_fontq(struct termp *p)
return(&p->fontq[p->fonti]);
}
-
enum termfont
term_fonttop(struct termp *p)
{
@@ -380,7 +370,6 @@ term_fonttop(struct termp *p)
return(p->fontq[p->fonti]);
}
-
void
term_fontpopq(struct termp *p, const void *key)
{
@@ -390,7 +379,6 @@ term_fontpopq(struct termp *p, const void *key)
assert(p->fonti >= 0);
}
-
void
term_fontpop(struct termp *p)
{
@@ -456,17 +444,17 @@ term_word(struct termp *p, const char *word)
word++;
esc = mandoc_escape(&word, &seq, &sz);
if (ESCAPE_ERROR == esc)
- break;
+ continue;
if (TERMENC_ASCII != p->enc)
switch (esc) {
- case (ESCAPE_UNICODE):
+ case ESCAPE_UNICODE:
uc = mchars_num2uc(seq + 1, sz - 1);
if ('\0' == uc)
break;
encode1(p, uc);
continue;
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
uc = mchars_spec2cp(p->symtab, seq, sz);
if (uc <= 0)
break;
@@ -477,45 +465,45 @@ term_word(struct termp *p, const char *word)
}
switch (esc) {
- case (ESCAPE_UNICODE):
+ case ESCAPE_UNICODE:
encode1(p, '?');
break;
- case (ESCAPE_NUMBERED):
+ case ESCAPE_NUMBERED:
c = mchars_num2char(seq, sz);
if ('\0' != c)
encode(p, &c, 1);
break;
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
cp = mchars_spec2str(p->symtab, seq, sz, &ssz);
- if (NULL != cp)
+ if (NULL != cp)
encode(p, cp, ssz);
else if (1 == ssz)
encode(p, seq, sz);
break;
- case (ESCAPE_FONTBOLD):
+ case ESCAPE_FONTBOLD:
term_fontrepl(p, TERMFONT_BOLD);
break;
- case (ESCAPE_FONTITALIC):
+ case ESCAPE_FONTITALIC:
term_fontrepl(p, TERMFONT_UNDER);
break;
- case (ESCAPE_FONTBI):
+ case ESCAPE_FONTBI:
term_fontrepl(p, TERMFONT_BI);
break;
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
/* FALLTHROUGH */
- case (ESCAPE_FONTROMAN):
+ case ESCAPE_FONTROMAN:
term_fontrepl(p, TERMFONT_NONE);
break;
- case (ESCAPE_FONTPREV):
+ case ESCAPE_FONTPREV:
term_fontlast(p);
break;
- case (ESCAPE_NOSPACE):
+ case ESCAPE_NOSPACE:
if (TERMP_SKIPCHAR & p->flags)
p->flags &= ~TERMP_SKIPCHAR;
else if ('\0' == *word)
p->flags |= TERMP_NOSPACE;
break;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SKIPCHAR:
p->flags |= TERMP_SKIPCHAR;
break;
default:
@@ -534,7 +522,7 @@ adjbuf(struct termp *p, size_t sz)
while (sz >= p->maxcols)
p->maxcols <<= 2;
- p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols);
+ p->buf = mandoc_reallocarray(p->buf, p->maxcols, sizeof(int));
}
static void
@@ -598,7 +586,7 @@ encode(struct termp *p, const char *word, size_t sz)
*/
if (TERMFONT_NONE == term_fonttop(p)) {
- if (p->col + sz >= p->maxcols)
+ if (p->col + sz >= p->maxcols)
adjbuf(p, p->col + sz);
for (i = 0; i < sz; i++)
p->buf[p->col++] = word[i];
@@ -619,6 +607,36 @@ encode(struct termp *p, const char *word, size_t sz)
}
}
+void
+term_setwidth(struct termp *p, const char *wstr)
+{
+ struct roffsu su;
+ size_t width;
+ int iop;
+
+ iop = 0;
+ width = 0;
+ if (NULL != wstr) {
+ switch (*wstr) {
+ case '+':
+ iop = 1;
+ wstr++;
+ break;
+ case '-':
+ iop = -1;
+ wstr++;
+ break;
+ default:
+ break;
+ }
+ if (a2roffsu(wstr, &su, SCALE_MAX))
+ width = term_hspan(p, &su);
+ else
+ iop = 0;
+ }
+ (*p->setwidth)(p, iop, width);
+}
+
size_t
term_len(const struct termp *p, size_t sz)
{
@@ -644,7 +662,8 @@ term_strlen(const struct termp *p, const char *cp)
int ssz, skip, c;
const char *seq, *rhs;
enum mandoc_esc esc;
- static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
+ static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH,
+ ASCII_BREAK, '\0' };
/*
* Account for escaped sequences within string length
@@ -659,26 +678,25 @@ term_strlen(const struct termp *p, const char *cp)
for (i = 0; i < rsz; i++)
sz += cond_width(p, *cp++, &skip);
- c = 0;
switch (*cp) {
- case ('\\'):
+ case '\\':
cp++;
esc = mandoc_escape(&cp, &seq, &ssz);
if (ESCAPE_ERROR == esc)
- return(sz);
+ continue;
if (TERMENC_ASCII != p->enc)
switch (esc) {
- case (ESCAPE_UNICODE):
- c = mchars_num2uc
- (seq + 1, ssz - 1);
+ case ESCAPE_UNICODE:
+ c = mchars_num2uc(seq + 1,
+ ssz - 1);
if ('\0' == c)
break;
sz += cond_width(p, c, &skip);
continue;
- case (ESCAPE_SPECIAL):
- c = mchars_spec2cp
- (p->symtab, seq, ssz);
+ case ESCAPE_SPECIAL:
+ c = mchars_spec2cp(p->symtab,
+ seq, ssz);
if (c <= 0)
break;
sz += cond_width(p, c, &skip);
@@ -690,17 +708,17 @@ term_strlen(const struct termp *p, const char *cp)
rhs = NULL;
switch (esc) {
- case (ESCAPE_UNICODE):
+ case ESCAPE_UNICODE:
sz += cond_width(p, '?', &skip);
break;
- case (ESCAPE_NUMBERED):
+ case ESCAPE_NUMBERED:
c = mchars_num2char(seq, ssz);
if ('\0' != c)
sz += cond_width(p, c, &skip);
break;
- case (ESCAPE_SPECIAL):
- rhs = mchars_spec2str
- (p->symtab, seq, ssz, &rsz);
+ case ESCAPE_SPECIAL:
+ rhs = mchars_spec2str(p->symtab,
+ seq, ssz, &rsz);
if (ssz != 1 || rhs)
break;
@@ -708,7 +726,7 @@ term_strlen(const struct termp *p, const char *cp)
rhs = seq;
rsz = ssz;
break;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SKIPCHAR:
skip = 1;
break;
default:
@@ -726,13 +744,15 @@ term_strlen(const struct termp *p, const char *cp)
for (i = 0; i < rsz; i++)
sz += (*p->width)(p, *rhs++);
break;
- case (ASCII_NBRSP):
+ case ASCII_NBRSP:
sz += cond_width(p, ' ', &skip);
cp++;
break;
- case (ASCII_HYPH):
+ case ASCII_HYPH:
sz += cond_width(p, '-', &skip);
cp++;
+ /* FALLTHROUGH */
+ case ASCII_BREAK:
break;
default:
break;
@@ -742,40 +762,38 @@ term_strlen(const struct termp *p, const char *cp)
return(sz);
}
-/* ARGSUSED */
size_t
term_vspan(const struct termp *p, const struct roffsu *su)
{
double r;
switch (su->unit) {
- case (SCALE_CM):
- r = su->scale * 2;
+ case SCALE_CM:
+ r = su->scale * 2.0;
break;
- case (SCALE_IN):
- r = su->scale * 6;
+ case SCALE_IN:
+ r = su->scale * 6.0;
break;
- case (SCALE_PC):
+ case SCALE_PC:
r = su->scale;
break;
- case (SCALE_PT):
- r = su->scale / 8;
+ case SCALE_PT:
+ r = su->scale / 8.0;
break;
- case (SCALE_MM):
- r = su->scale / 1000;
+ case SCALE_MM:
+ r = su->scale / 1000.0;
break;
- case (SCALE_VS):
+ case SCALE_VS:
r = su->scale;
break;
default:
- r = su->scale - 1;
+ r = su->scale - 1.0;
break;
}
if (r < 0.0)
r = 0.0;
- return(/* LINTED */(size_t)
- r);
+ return((size_t)(r + 0.0005));
}
size_t
@@ -783,9 +801,8 @@ term_hspan(const struct termp *p, const struct roffsu *su)
{
double v;
- v = ((*p->hspan)(p, su));
+ v = (*p->hspan)(p, su);
if (v < 0.0)
v = 0.0;
- return((size_t) /* LINTED */
- v);
+ return((size_t)(v + 0.0005));
}
diff --git a/contrib/mdocml/term.h b/contrib/mdocml/term.h
index 8cad4be..decd7f4 100644
--- a/contrib/mdocml/term.h
+++ b/contrib/mdocml/term.h
@@ -1,7 +1,7 @@
-/* $Id: term.h,v 1.97 2013/12/25 00:39:31 schwarze Exp $ */
+/* $Id: term.h,v 1.101 2014/04/20 16:46:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -57,6 +57,7 @@ struct termp {
int mdocstyle; /* imitate mdoc(7) output */
size_t defindent; /* Default indent for text. */
size_t defrmargin; /* Right margin of the device. */
+ size_t lastrmargin; /* Right margin before the last ll. */
size_t rmargin; /* Current right margin. */
size_t maxrmargin; /* Max right margin. */
size_t maxcols; /* Max size of buf. */
@@ -76,11 +77,12 @@ struct termp {
#define TERMP_PREKEEP (1 << 6) /* ...starting with the next one. */
#define TERMP_SKIPCHAR (1 << 7) /* Skip the next character. */
#define TERMP_NOBREAK (1 << 8) /* See term_flushln(). */
-#define TERMP_DANGLE (1 << 9) /* See term_flushln(). */
-#define TERMP_HANG (1 << 10) /* See term_flushln(). */
-#define TERMP_NOSPLIT (1 << 11) /* See termp_an_pre/post(). */
-#define TERMP_SPLIT (1 << 12) /* See termp_an_pre/post(). */
-#define TERMP_ANPREC (1 << 13) /* See termp_an_pre(). */
+#define TERMP_BRIND (1 << 9) /* See term_flushln(). */
+#define TERMP_DANGLE (1 << 10) /* See term_flushln(). */
+#define TERMP_HANG (1 << 11) /* See term_flushln(). */
+#define TERMP_NOSPLIT (1 << 12) /* See termp_an_pre/post(). */
+#define TERMP_SPLIT (1 << 13) /* See termp_an_pre/post(). */
+#define TERMP_ANPREC (1 << 14) /* See termp_an_pre(). */
int *buf; /* Output buffer. */
enum termenc enc; /* Type of encoding. */
struct mchars *symtab; /* Encoded-symbol table. */
@@ -94,6 +96,7 @@ struct termp {
void (*end)(struct termp *);
void (*endline)(struct termp *);
void (*advance)(struct termp *, size_t);
+ void (*setwidth)(struct termp *, int, size_t);
size_t (*width)(const struct termp *, int);
double (*hspan)(const struct termp *,
const struct roffsu *);
@@ -108,11 +111,12 @@ void term_newln(struct termp *);
void term_vspace(struct termp *);
void term_word(struct termp *, const char *);
void term_flushln(struct termp *);
-void term_begin(struct termp *, term_margin,
+void term_begin(struct termp *, term_margin,
term_margin, const void *);
void term_end(struct termp *);
-size_t term_hspan(const struct termp *,
+void term_setwidth(struct termp *, const char *);
+size_t term_hspan(const struct termp *,
const struct roffsu *);
size_t term_vspan(const struct termp *,
const struct roffsu *);
diff --git a/contrib/mdocml/term_ascii.c b/contrib/mdocml/term_ascii.c
index cb7ac29..b1e328c 100644
--- a/contrib/mdocml/term_ascii.c
+++ b/contrib/mdocml/term_ascii.c
@@ -1,6 +1,7 @@
-/* $Id: term_ascii.c,v 1.21 2013/06/01 14:27:20 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.27 2014/08/01 19:25:52 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +21,6 @@
#include <sys/types.h>
-#include <assert.h>
#ifdef USE_WCHAR
# include <locale.h>
#endif
@@ -33,6 +33,7 @@
#endif
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
#include "main.h"
@@ -57,6 +58,7 @@ static void ascii_begin(struct termp *);
static void ascii_end(struct termp *);
static void ascii_endline(struct termp *);
static void ascii_letter(struct termp *, int);
+static void ascii_setwidth(struct termp *, int, size_t);
#ifdef USE_WCHAR
static void locale_advance(struct termp *, size_t);
@@ -65,6 +67,7 @@ static void locale_letter(struct termp *, int);
static size_t locale_width(const struct termp *, int);
#endif
+
static struct termp *
ascii_init(enum termenc enc, char *outopts)
{
@@ -75,7 +78,7 @@ ascii_init(enum termenc enc, char *outopts)
p = mandoc_calloc(1, sizeof(struct termp));
p->tabwidth = 5;
- p->defrmargin = 78;
+ p->defrmargin = p->lastrmargin = 78;
p->begin = ascii_begin;
p->end = ascii_end;
@@ -86,13 +89,14 @@ ascii_init(enum termenc enc, char *outopts)
p->advance = ascii_advance;
p->endline = ascii_endline;
p->letter = ascii_letter;
+ p->setwidth = ascii_setwidth;
p->width = ascii_width;
#ifdef USE_WCHAR
if (TERMENC_ASCII != enc) {
v = TERMENC_LOCALE == enc ?
- setlocale(LC_ALL, "") :
- setlocale(LC_CTYPE, "en_US.UTF-8");
+ setlocale(LC_ALL, "") :
+ setlocale(LC_CTYPE, "en_US.UTF-8");
if (NULL != v && MB_CUR_MAX > 1) {
p->enc = enc;
p->advance = locale_advance;
@@ -110,13 +114,13 @@ ascii_init(enum termenc enc, char *outopts)
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
- case (0):
+ case 0:
p->defindent = (size_t)atoi(v);
break;
- case (1):
+ case 1:
p->defrmargin = (size_t)atoi(v);
break;
- case (2):
+ case 2:
/*
* Temporary, undocumented mode
* to imitate mdoc(7) output style.
@@ -149,7 +153,6 @@ utf8_alloc(char *outopts)
return(ascii_init(TERMENC_UTF8, outopts));
}
-
void *
locale_alloc(char *outopts)
{
@@ -157,7 +160,21 @@ locale_alloc(char *outopts)
return(ascii_init(TERMENC_LOCALE, outopts));
}
-/* ARGSUSED */
+static void
+ascii_setwidth(struct termp *p, int iop, size_t width)
+{
+
+ p->rmargin = p->defrmargin;
+ if (0 < iop)
+ p->defrmargin += width;
+ else if (0 > iop)
+ p->defrmargin -= width;
+ else
+ p->defrmargin = width ? width : p->lastrmargin;
+ p->lastrmargin = p->rmargin;
+ p->rmargin = p->maxrmargin = p->defrmargin;
+}
+
static size_t
ascii_width(const struct termp *p, int c)
{
@@ -172,11 +189,10 @@ ascii_free(void *arg)
term_free((struct termp *)arg);
}
-/* ARGSUSED */
static void
ascii_letter(struct termp *p, int c)
{
-
+
putchar(c);
}
@@ -194,7 +210,6 @@ ascii_end(struct termp *p)
(*p->footf)(p, p->argf);
}
-/* ARGSUSED */
static void
ascii_endline(struct termp *p)
{
@@ -202,17 +217,15 @@ ascii_endline(struct termp *p)
putchar('\n');
}
-/* ARGSUSED */
static void
ascii_advance(struct termp *p, size_t len)
{
- size_t i;
+ size_t i;
for (i = 0; i < len; i++)
putchar(' ');
}
-/* ARGSUSED */
static double
ascii_hspan(const struct termp *p, const struct roffsu *su)
{
@@ -224,23 +237,23 @@ ascii_hspan(const struct termp *p, const struct roffsu *su)
*/
switch (su->unit) {
- case (SCALE_CM):
- r = 4 * su->scale;
+ case SCALE_CM:
+ r = su->scale * 4.0;
break;
- case (SCALE_IN):
- r = 10 * su->scale;
+ case SCALE_IN:
+ r = su->scale * 10.0;
break;
- case (SCALE_PC):
- r = (10 * su->scale) / 6;
+ case SCALE_PC:
+ r = (su->scale * 10.0) / 6.0;
break;
- case (SCALE_PT):
- r = (10 * su->scale) / 72;
+ case SCALE_PT:
+ r = (su->scale * 10.0) / 72.0;
break;
- case (SCALE_MM):
- r = su->scale / 1000;
+ case SCALE_MM:
+ r = su->scale / 1000.0;
break;
- case (SCALE_VS):
- r = su->scale * 2 - 1;
+ case SCALE_VS:
+ r = su->scale * 2.0 - 1.0;
break;
default:
r = su->scale;
@@ -251,26 +264,28 @@ ascii_hspan(const struct termp *p, const struct roffsu *su)
}
#ifdef USE_WCHAR
-/* ARGSUSED */
static size_t
locale_width(const struct termp *p, int c)
{
int rc;
- return((rc = wcwidth(c)) < 0 ? 0 : rc);
+ if (c == ASCII_NBRSP)
+ c = ' ';
+ rc = wcwidth(c);
+ if (rc < 0)
+ rc = 0;
+ return(rc);
}
-/* ARGSUSED */
static void
locale_advance(struct termp *p, size_t len)
{
- size_t i;
+ size_t i;
for (i = 0; i < len; i++)
putwchar(L' ');
}
-/* ARGSUSED */
static void
locale_endline(struct termp *p)
{
@@ -278,11 +293,10 @@ locale_endline(struct termp *p)
putwchar(L'\n');
}
-/* ARGSUSED */
static void
locale_letter(struct termp *p, int c)
{
-
+
putwchar(c);
}
#endif
diff --git a/contrib/mdocml/term_ps.c b/contrib/mdocml/term_ps.c
index e8a9068..96edc6d 100644
--- a/contrib/mdocml/term_ps.c
+++ b/contrib/mdocml/term_ps.c
@@ -1,6 +1,7 @@
-/* $Id: term_ps.c,v 1.54 2011/10/16 12:20:34 schwarze Exp $ */
+/* $Id: term_ps.c,v 1.62 2014/08/01 19:25:52 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -30,6 +31,7 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "main.h"
#include "term.h"
@@ -38,11 +40,11 @@
#define PS_BUFSLOP 128
/* Convert PostScript point "x" to an AFM unit. */
-#define PNT2AFM(p, x) /* LINTED */ \
+#define PNT2AFM(p, x) \
(size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale))
/* Convert an AFM unit "x" to a PostScript points */
-#define AFM2PNT(p, x) /* LINTED */ \
+#define AFM2PNT(p, x) \
((double)(x) / (1000.0 / (double)(p)->ps->scale))
struct glyph {
@@ -74,10 +76,11 @@ struct termp_ps {
size_t bottom; /* body bottom (AFM units) */
size_t height; /* page height (AFM units */
size_t width; /* page width (AFM units) */
+ size_t lastwidth; /* page width before last ll */
size_t left; /* body left (AFM units) */
size_t header; /* header pos (AFM units) */
size_t footer; /* footer pos (AFM units) */
- size_t pdfbytes; /* current output byte */
+ size_t pdfbytes; /* current output byte */
size_t pdflastpg; /* byte of last page mark */
size_t pdfbody; /* start of body object */
size_t *pdfobjs; /* table of object offsets */
@@ -97,9 +100,13 @@ static void ps_growbuf(struct termp *, size_t);
static void ps_letter(struct termp *, int);
static void ps_pclose(struct termp *);
static void ps_pletter(struct termp *, int);
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 2, 3)))
+#endif
static void ps_printf(struct termp *, const char *, ...);
static void ps_putchar(struct termp *, char);
static void ps_setfont(struct termp *, enum termfont);
+static void ps_setwidth(struct termp *, int, size_t);
static struct termp *pspdf_alloc(char *);
static void pdf_obj(struct termp *, size_t);
@@ -445,8 +452,9 @@ pspdf_alloc(char *outopts)
p->endline = ps_endline;
p->hspan = ps_hspan;
p->letter = ps_letter;
+ p->setwidth = ps_setwidth;
p->width = ps_width;
-
+
toks[0] = "paper";
toks[1] = NULL;
@@ -454,7 +462,7 @@ pspdf_alloc(char *outopts)
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
- case (0):
+ case 0:
pp = v;
break;
default:
@@ -490,7 +498,7 @@ pspdf_alloc(char *outopts)
fprintf(stderr, "%s: Unknown paper\n", pp);
}
- /*
+ /*
* This MUST be defined before any PNT2AFM or AFM2PNT
* calculations occur.
*/
@@ -504,16 +512,14 @@ pspdf_alloc(char *outopts)
/* Margins are 1/9 the page x and y. */
- marginx = /* LINTED */
- (size_t)((double)pagex / 9.0);
- marginy = /* LINTED */
- (size_t)((double)pagey / 9.0);
+ marginx = (size_t)((double)pagex / 9.0);
+ marginy = (size_t)((double)pagey / 9.0);
/* Line-height is 1.4em. */
lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4));
- p->ps->width = (size_t)pagex;
+ p->ps->width = p->ps->lastwidth = (size_t)pagex;
p->ps->height = (size_t)pagey;
p->ps->header = pagey - (marginy / 2) - (lineheight / 2);
p->ps->top = pagey - marginy;
@@ -526,6 +532,20 @@ pspdf_alloc(char *outopts)
return(p);
}
+static void
+ps_setwidth(struct termp *p, int iop, size_t width)
+{
+ size_t lastwidth;
+
+ lastwidth = p->ps->width;
+ if (0 < iop)
+ p->ps->width += width;
+ else if (0 > iop)
+ p->ps->width -= width;
+ else
+ p->ps->width = width ? width : p->ps->lastwidth;
+ p->ps->lastwidth = lastwidth;
+}
void
pspdf_free(void *arg)
@@ -543,7 +563,6 @@ pspdf_free(void *arg)
term_free(p);
}
-
static void
ps_printf(struct termp *p, const char *fmt, ...)
{
@@ -561,12 +580,11 @@ ps_printf(struct termp *p, const char *fmt, ...)
if ( ! (PS_MARGINS & p->ps->flags)) {
len = vprintf(fmt, ap);
va_end(ap);
- p->ps->pdfbytes += /* LINTED */
- len < 0 ? 0 : (size_t)len;
+ p->ps->pdfbytes += len < 0 ? 0 : (size_t)len;
return;
}
- /*
+ /*
* XXX: I assume that the in-margin print won't exceed
* PS_BUFSLOP (128 bytes), which is reasonable but still an
* assumption that will cause pukeage if it's not the case.
@@ -582,7 +600,6 @@ ps_printf(struct termp *p, const char *fmt, ...)
p->ps->psmargcur = strlen(p->ps->psmarg);
}
-
static void
ps_putchar(struct termp *p, char c)
{
@@ -591,7 +608,6 @@ ps_putchar(struct termp *p, char c)
/* See ps_printf(). */
if ( ! (PS_MARGINS & p->ps->flags)) {
- /* LINTED */
putchar(c);
p->ps->pdfbytes++;
return;
@@ -604,7 +620,6 @@ ps_putchar(struct termp *p, char c)
p->ps->psmarg[pos] = '\0';
}
-
static void
pdf_obj(struct termp *p, size_t obj)
{
@@ -613,20 +628,14 @@ pdf_obj(struct termp *p, size_t obj)
if ((obj - 1) >= p->ps->pdfobjsz) {
p->ps->pdfobjsz = obj + 128;
- p->ps->pdfobjs = realloc
- (p->ps->pdfobjs,
- p->ps->pdfobjsz * sizeof(size_t));
- if (NULL == p->ps->pdfobjs) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
+ p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs,
+ p->ps->pdfobjsz, sizeof(size_t));
}
p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes;
ps_printf(p, "%zu 0 obj\n", obj);
}
-
static void
ps_closepage(struct termp *p)
{
@@ -659,7 +668,7 @@ ps_closepage(struct termp *p)
pdf_obj(p, base + 2);
ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n");
ps_printf(p, "/Font <<\n");
- for (i = 0; i < (int)TERMFONT__MAX; i++)
+ for (i = 0; i < (int)TERMFONT__MAX; i++)
ps_printf(p, "/F%d %d 0 R\n", i, 3 + i);
ps_printf(p, ">>\n>>\n");
@@ -680,8 +689,6 @@ ps_closepage(struct termp *p)
p->ps->flags |= PS_NEWPAGE;
}
-
-/* ARGSUSED */
static void
ps_end(struct termp *p)
{
@@ -704,7 +711,7 @@ ps_end(struct termp *p)
ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages);
ps_printf(p, "%%%%EOF\n");
return;
- }
+ }
pdf_obj(p, 2);
ps_printf(p, "<<\n/Type /Pages\n");
@@ -716,11 +723,9 @@ ps_end(struct termp *p)
ps_printf(p, "/Kids [");
for (i = 0; i < p->ps->pages; i++)
- ps_printf(p, " %zu 0 R", i * 4 +
- p->ps->pdfbody + 3);
+ ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3);
- base = (p->ps->pages - 1) * 4 +
- p->ps->pdfbody + 4;
+ base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4;
ps_printf(p, "]\n>>\nendobj\n");
pdf_obj(p, base);
@@ -734,8 +739,8 @@ ps_end(struct termp *p)
ps_printf(p, "0000000000 65535 f \n");
for (i = 0; i < base; i++)
- ps_printf(p, "%.10zu 00000 n \n",
- p->ps->pdfobjs[(int)i]);
+ ps_printf(p, "%.10zu 00000 n \n",
+ p->ps->pdfobjs[(int)i]);
ps_printf(p, "trailer\n");
ps_printf(p, "<<\n");
@@ -748,14 +753,13 @@ ps_end(struct termp *p)
ps_printf(p, "%%%%EOF\n");
}
-
static void
ps_begin(struct termp *p)
{
time_t t;
int i;
- /*
+ /*
* Print margins into margin buffer. Nothing gets output to the
* screen yet, so we don't need to initialise the primary state.
*/
@@ -788,7 +792,7 @@ ps_begin(struct termp *p)
assert(p->ps->psmarg);
assert('\0' != p->ps->psmarg[0]);
- /*
+ /*
* Print header and initialise page state. Following this,
* stuff gets printed to the screen, so make sure we're sane.
*/
@@ -803,9 +807,9 @@ ps_begin(struct termp *p)
ps_printf(p, "%%%%Pages: (atend)\n");
ps_printf(p, "%%%%PageOrder: Ascend\n");
ps_printf(p, "%%%%DocumentMedia: "
- "Default %zu %zu 0 () ()\n",
- (size_t)AFM2PNT(p, p->ps->width),
- (size_t)AFM2PNT(p, p->ps->height));
+ "Default %zu %zu 0 () ()\n",
+ (size_t)AFM2PNT(p, p->ps->width),
+ (size_t)AFM2PNT(p, p->ps->height));
ps_printf(p, "%%%%DocumentNeededResources: font");
for (i = 0; i < (int)TERMFONT__MAX; i++)
@@ -824,7 +828,7 @@ ps_begin(struct termp *p)
ps_printf(p, "<<\n");
ps_printf(p, "/Type /Font\n");
ps_printf(p, "/Subtype /Type1\n");
- ps_printf(p, "/Name /F%zu\n", i);
+ ps_printf(p, "/Name /F%d\n", i);
ps_printf(p, "/BaseFont /%s\n", fonts[i].name);
ps_printf(p, ">>\n");
}
@@ -837,7 +841,6 @@ ps_begin(struct termp *p)
ps_setfont(p, TERMFONT_NONE);
}
-
static void
ps_pletter(struct termp *p, int c)
{
@@ -850,25 +853,23 @@ ps_pletter(struct termp *p, int c)
if (PS_NEWPAGE & p->ps->flags) {
if (TERMTYPE_PS == p->type) {
- ps_printf(p, "%%%%Page: %zu %zu\n",
- p->ps->pages + 1,
- p->ps->pages + 1);
- ps_printf(p, "/%s %zu selectfont\n",
- fonts[(int)p->ps->lastf].name,
- p->ps->scale);
+ ps_printf(p, "%%%%Page: %zu %zu\n",
+ p->ps->pages + 1, p->ps->pages + 1);
+ ps_printf(p, "/%s %zu selectfont\n",
+ fonts[(int)p->ps->lastf].name,
+ p->ps->scale);
} else {
- pdf_obj(p, p->ps->pdfbody +
- p->ps->pages * 4);
+ pdf_obj(p, p->ps->pdfbody +
+ p->ps->pages * 4);
ps_printf(p, "<<\n");
- ps_printf(p, "/Length %zu 0 R\n",
- p->ps->pdfbody + 1 +
- p->ps->pages * 4);
+ ps_printf(p, "/Length %zu 0 R\n",
+ p->ps->pdfbody + 1 + p->ps->pages * 4);
ps_printf(p, ">>\nstream\n");
}
p->ps->pdflastpg = p->ps->pdfbytes;
p->ps->flags &= ~PS_NEWPAGE;
}
-
+
/*
* If we're not in a PostScript "word" context, then open one
* now at the current cursor.
@@ -876,16 +877,15 @@ ps_pletter(struct termp *p, int c)
if ( ! (PS_INLINE & p->ps->flags)) {
if (TERMTYPE_PS != p->type) {
- ps_printf(p, "BT\n/F%d %zu Tf\n",
- (int)p->ps->lastf,
- p->ps->scale);
+ ps_printf(p, "BT\n/F%d %zu Tf\n",
+ (int)p->ps->lastf, p->ps->scale);
ps_printf(p, "%.3f %.3f Td\n(",
- AFM2PNT(p, p->ps->pscol),
- AFM2PNT(p, p->ps->psrow));
+ AFM2PNT(p, p->ps->pscol),
+ AFM2PNT(p, p->ps->psrow));
} else
- ps_printf(p, "%.3f %.3f moveto\n(",
- AFM2PNT(p, p->ps->pscol),
- AFM2PNT(p, p->ps->psrow));
+ ps_printf(p, "%.3f %.3f moveto\n(",
+ AFM2PNT(p, p->ps->pscol),
+ AFM2PNT(p, p->ps->psrow));
p->ps->flags |= PS_INLINE;
}
@@ -899,11 +899,11 @@ ps_pletter(struct termp *p, int c)
*/
switch (c) {
- case ('('):
+ case '(':
/* FALLTHROUGH */
- case (')'):
+ case ')':
/* FALLTHROUGH */
- case ('\\'):
+ case '\\':
ps_putchar(p, '\\');
break;
default:
@@ -914,23 +914,19 @@ ps_pletter(struct termp *p, int c)
f = (int)p->ps->lastf;
- if (c <= 32 || (c - 32 >= MAXCHAR)) {
- ps_putchar(p, ' ');
- p->ps->pscol += (size_t)fonts[f].gly[0].wx;
- return;
- }
+ if (c <= 32 || c - 32 >= MAXCHAR)
+ c = 32;
ps_putchar(p, (char)c);
c -= 32;
p->ps->pscol += (size_t)fonts[f].gly[c].wx;
}
-
static void
ps_pclose(struct termp *p)
{
- /*
+ /*
* Spit out that we're exiting a word context (this is a
* "partial close" because we don't check the last-char buffer
* or anything).
@@ -938,7 +934,7 @@ ps_pclose(struct termp *p)
if ( ! (PS_INLINE & p->ps->flags))
return;
-
+
if (TERMTYPE_PS != p->type) {
ps_printf(p, ") Tj\nET\n");
} else
@@ -947,7 +943,6 @@ ps_pclose(struct termp *p)
p->ps->flags &= ~PS_INLINE;
}
-
static void
ps_fclose(struct termp *p)
{
@@ -975,13 +970,11 @@ ps_fclose(struct termp *p)
ps_pclose(p);
}
-
static void
ps_letter(struct termp *p, int arg)
{
char cc, c;
- /* LINTED */
c = arg >= 128 || arg <= 0 ? '?' : arg;
/*
@@ -1026,7 +1019,6 @@ ps_letter(struct termp *p, int arg)
ps_pletter(p, c);
}
-
static void
ps_advance(struct termp *p, size_t len)
{
@@ -1042,7 +1034,6 @@ ps_advance(struct termp *p, size_t len)
p->ps->pscol += len;
}
-
static void
ps_endline(struct termp *p)
{
@@ -1054,7 +1045,7 @@ ps_endline(struct termp *p)
/*
* If we're in the margin, don't try to recalculate our current
* row. XXX: if the column tries to be fancy with multiple
- * lines, we'll do nasty stuff.
+ * lines, we'll do nasty stuff.
*/
if (PS_MARGINS & p->ps->flags)
@@ -1074,8 +1065,7 @@ ps_endline(struct termp *p)
* showpage and restart our row.
*/
- if (p->ps->psrow >= p->ps->lineheight +
- p->ps->bottom) {
+ if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) {
p->ps->psrow -= p->ps->lineheight;
return;
}
@@ -1083,14 +1073,13 @@ ps_endline(struct termp *p)
ps_closepage(p);
}
-
static void
ps_setfont(struct termp *p, enum termfont f)
{
assert(f < TERMFONT__MAX);
p->ps->lastf = f;
-
+
/*
* If we're still at the top of the page, let the font-setting
* be delayed until we actually have stuff to print.
@@ -1100,64 +1089,60 @@ ps_setfont(struct termp *p, enum termfont f)
return;
if (TERMTYPE_PS == p->type)
- ps_printf(p, "/%s %zu selectfont\n",
- fonts[(int)f].name,
- p->ps->scale);
+ ps_printf(p, "/%s %zu selectfont\n",
+ fonts[(int)f].name, p->ps->scale);
else
- ps_printf(p, "/F%d %zu Tf\n",
- (int)f,
- p->ps->scale);
+ ps_printf(p, "/F%d %zu Tf\n",
+ (int)f, p->ps->scale);
}
-
-/* ARGSUSED */
static size_t
ps_width(const struct termp *p, int c)
{
if (c <= 32 || c - 32 >= MAXCHAR)
- return((size_t)fonts[(int)TERMFONT_NONE].gly[0].wx);
+ c = 0;
+ else
+ c -= 32;
- c -= 32;
return((size_t)fonts[(int)TERMFONT_NONE].gly[c].wx);
}
-
static double
ps_hspan(const struct termp *p, const struct roffsu *su)
{
double r;
-
+
/*
* All of these measurements are derived by converting from the
* native measurement to AFM units.
*/
switch (su->unit) {
- case (SCALE_CM):
+ case SCALE_CM:
r = PNT2AFM(p, su->scale * 28.34);
break;
- case (SCALE_IN):
- r = PNT2AFM(p, su->scale * 72);
+ case SCALE_IN:
+ r = PNT2AFM(p, su->scale * 72.0);
break;
- case (SCALE_PC):
- r = PNT2AFM(p, su->scale * 12);
+ case SCALE_PC:
+ r = PNT2AFM(p, su->scale * 12.0);
break;
- case (SCALE_PT):
- r = PNT2AFM(p, su->scale * 100);
+ case SCALE_PT:
+ r = PNT2AFM(p, su->scale * 100.0);
break;
- case (SCALE_EM):
+ case SCALE_EM:
r = su->scale *
- fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
+ fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
break;
- case (SCALE_MM):
+ case SCALE_MM:
r = PNT2AFM(p, su->scale * 2.834);
break;
- case (SCALE_EN):
+ case SCALE_EN:
r = su->scale *
- fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
+ fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
break;
- case (SCALE_VS):
+ case SCALE_VS:
r = su->scale * p->ps->lineheight;
break;
default:
@@ -1178,8 +1163,5 @@ ps_growbuf(struct termp *p, size_t sz)
sz = PS_BUFSLOP;
p->ps->psmargsz += sz;
-
- p->ps->psmarg = mandoc_realloc
- (p->ps->psmarg, p->ps->psmargsz);
+ p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz);
}
-
diff --git a/contrib/mdocml/test-fgetln.c b/contrib/mdocml/test-fgetln.c
new file mode 100644
index 0000000..ac225a1
--- /dev/null
+++ b/contrib/mdocml/test-fgetln.c
@@ -0,0 +1,11 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+ size_t sz;
+ fclose(stdin);
+ return(NULL != fgetln(stdin, &sz));
+}
diff --git a/contrib/mdocml/test-getsubopt.c b/contrib/mdocml/test-getsubopt.c
new file mode 100644
index 0000000..2da9823
--- /dev/null
+++ b/contrib/mdocml/test-getsubopt.c
@@ -0,0 +1,19 @@
+#if defined(__linux__) || defined(__MINT__)
+# define _GNU_SOURCE /* getsubopt() */
+#endif
+
+#include <stdlib.h>
+
+extern char *suboptarg;
+
+int
+main(void)
+{
+ char buf[] = "k=v";
+ char *options = buf;
+ char token0[] = "k";
+ char *const tokens[] = { token0, NULL };
+ char *value = NULL;
+ return( ! (0 == getsubopt(&options, tokens, &value)
+ && suboptarg == buf && value == buf+2 && options == buf+3));
+}
diff --git a/contrib/mdocml/test-mmap.c b/contrib/mdocml/test-mmap.c
new file mode 100644
index 0000000..c322a34
--- /dev/null
+++ b/contrib/mdocml/test-mmap.c
@@ -0,0 +1,9 @@
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stddef.h>
+
+int
+main(void)
+{
+ return(MAP_FAILED != mmap(NULL, 1, PROT_READ, MAP_SHARED, -1, 0));
+}
diff --git a/contrib/mdocml/test-ohash.c b/contrib/mdocml/test-ohash.c
new file mode 100644
index 0000000..522ad70
--- /dev/null
+++ b/contrib/mdocml/test-ohash.c
@@ -0,0 +1,21 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ohash.h>
+
+void *xmalloc(size_t sz, void *arg) { return(calloc(1,sz)); }
+void *xcalloc(size_t nmemb, size_t sz, void *arg) { return(calloc(nmemb,sz)); }
+void xfree(void *p, void *arg) { free(p); }
+
+int
+main(void)
+{
+ struct ohash h;
+ struct ohash_info i;
+ i.alloc = xmalloc;
+ i.calloc = xcalloc;
+ i.free = xfree;
+ ohash_init(&h, 2, &i);
+ ohash_delete(&h);
+ return 0;
+}
diff --git a/contrib/mdocml/test-reallocarray.c b/contrib/mdocml/test-reallocarray.c
new file mode 100644
index 0000000..9a514e8
--- /dev/null
+++ b/contrib/mdocml/test-reallocarray.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+int
+main(void)
+{
+ return( ! reallocarray(NULL, 2, 2));
+}
diff --git a/contrib/mdocml/test-sqlite3_errstr.c b/contrib/mdocml/test-sqlite3_errstr.c
new file mode 100644
index 0000000..041bf62
--- /dev/null
+++ b/contrib/mdocml/test-sqlite3_errstr.c
@@ -0,0 +1,8 @@
+#include <string.h>
+#include <sqlite3.h>
+
+int
+main(void)
+{
+ return(strcmp(sqlite3_errstr(SQLITE_OK), "not an error"));
+}
diff --git a/contrib/mdocml/test-strcasestr.c b/contrib/mdocml/test-strcasestr.c
new file mode 100644
index 0000000..479ba91
--- /dev/null
+++ b/contrib/mdocml/test-strcasestr.c
@@ -0,0 +1,13 @@
+#if defined(__linux__) || defined(__MINT__)
+# define _GNU_SOURCE /* strcasestr() */
+#endif
+
+#include <string.h>
+
+int
+main(void)
+{
+ const char *big = "BigString";
+ char *cp = strcasestr(big, "Gst");
+ return(big + 2 != cp);
+}
diff --git a/contrib/mdocml/test-strlcat.c b/contrib/mdocml/test-strlcat.c
new file mode 100644
index 0000000..b74ce6f
--- /dev/null
+++ b/contrib/mdocml/test-strlcat.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+int
+main(void)
+{
+ char buf[3] = "a";
+ return( ! (2 == strlcat(buf, "b", sizeof(buf)) &&
+ 'a' == buf[0] && 'b' == buf[1] && '\0' == buf[2]));
+}
diff --git a/contrib/mdocml/test-strlcpy.c b/contrib/mdocml/test-strlcpy.c
new file mode 100644
index 0000000..05fa509
--- /dev/null
+++ b/contrib/mdocml/test-strlcpy.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+int
+main(void)
+{
+ char buf[2] = "";
+ return( ! (1 == strlcpy(buf, "a", sizeof(buf)) &&
+ 'a' == buf[0] && '\0' == buf[1]));
+}
diff --git a/contrib/mdocml/test-strsep.c b/contrib/mdocml/test-strsep.c
new file mode 100644
index 0000000..4c57c13
--- /dev/null
+++ b/contrib/mdocml/test-strsep.c
@@ -0,0 +1,10 @@
+#include <string.h>
+
+int
+main(void)
+{
+ char buf[6] = "aybxc";
+ char *workp = buf;
+ char *retp = strsep(&workp, "xy");
+ return( ! (retp == buf && '\0' == buf[1] && buf + 2 == workp));
+}
diff --git a/contrib/mdocml/tree.c b/contrib/mdocml/tree.c
index fdb70e1..7574209 100644
--- a/contrib/mdocml/tree.c
+++ b/contrib/mdocml/tree.c
@@ -1,7 +1,7 @@
-/* $Id: tree.c,v 1.50 2013/12/24 19:11:46 schwarze Exp $ */
+/* $Id: tree.c,v 1.53 2014/07/02 07:10:38 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -36,7 +36,6 @@ static void print_mdoc(const struct mdoc_node *, int);
static void print_span(const struct tbl_span *, int);
-/* ARGSUSED */
void
tree_mdoc(void *arg, const struct mdoc *mdoc)
{
@@ -44,8 +43,6 @@ tree_mdoc(void *arg, const struct mdoc *mdoc)
print_mdoc(mdoc_node(mdoc), 0);
}
-
-/* ARGSUSED */
void
tree_man(void *arg, const struct man *man)
{
@@ -53,7 +50,6 @@ tree_man(void *arg, const struct man *man)
print_man(man_node(man), 0);
}
-
static void
print_mdoc(const struct mdoc_node *n, int indent)
{
@@ -67,33 +63,33 @@ print_mdoc(const struct mdoc_node *n, int indent)
t = p = NULL;
switch (n->type) {
- case (MDOC_ROOT):
+ case MDOC_ROOT:
t = "root";
break;
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
t = "block";
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
t = "block-head";
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
if (n->end)
t = "body-end";
else
t = "block-body";
break;
- case (MDOC_TAIL):
+ case MDOC_TAIL:
t = "block-tail";
break;
- case (MDOC_ELEM):
+ case MDOC_ELEM:
t = "elem";
break;
- case (MDOC_TEXT):
+ case MDOC_TEXT:
t = "text";
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
/* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_EQN:
break;
default:
abort();
@@ -101,37 +97,37 @@ print_mdoc(const struct mdoc_node *n, int indent)
}
switch (n->type) {
- case (MDOC_TEXT):
+ case MDOC_TEXT:
p = n->string;
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
p = mdoc_macronames[n->tok];
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
p = mdoc_macronames[n->tok];
break;
- case (MDOC_TAIL):
+ case MDOC_TAIL:
p = mdoc_macronames[n->tok];
break;
- case (MDOC_ELEM):
+ case MDOC_ELEM:
p = mdoc_macronames[n->tok];
if (n->args) {
argv = n->args->argv;
argc = n->args->argc;
}
break;
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
p = mdoc_macronames[n->tok];
if (n->args) {
argv = n->args->argv;
argc = n->args->argc;
}
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
/* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_EQN:
break;
- case (MDOC_ROOT):
+ case MDOC_ROOT:
p = "root";
break;
default:
@@ -164,7 +160,7 @@ print_mdoc(const struct mdoc_node *n, int indent)
putchar(' ');
if (MDOC_LINE & n->flags)
putchar('*');
- printf("%d:%d", n->line, n->pos);
+ printf("%d:%d", n->line, n->pos + 1);
if (n->lastline != n->line)
printf("-%d", n->lastline);
putchar('\n');
@@ -176,7 +172,6 @@ print_mdoc(const struct mdoc_node *n, int indent)
print_mdoc(n->next, indent);
}
-
static void
print_man(const struct man_node *n, int indent)
{
@@ -186,30 +181,30 @@ print_man(const struct man_node *n, int indent)
t = p = NULL;
switch (n->type) {
- case (MAN_ROOT):
+ case MAN_ROOT:
t = "root";
break;
- case (MAN_ELEM):
+ case MAN_ELEM:
t = "elem";
break;
- case (MAN_TEXT):
+ case MAN_TEXT:
t = "text";
break;
- case (MAN_BLOCK):
+ case MAN_BLOCK:
t = "block";
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
t = "block-head";
break;
- case (MAN_BODY):
+ case MAN_BODY:
t = "block-body";
break;
- case (MAN_TAIL):
+ case MAN_TAIL:
t = "block-tail";
break;
- case (MAN_TBL):
+ case MAN_TBL:
/* FALLTHROUGH */
- case (MAN_EQN):
+ case MAN_EQN:
break;
default:
abort();
@@ -217,26 +212,26 @@ print_man(const struct man_node *n, int indent)
}
switch (n->type) {
- case (MAN_TEXT):
+ case MAN_TEXT:
p = n->string;
break;
- case (MAN_ELEM):
+ case MAN_ELEM:
/* FALLTHROUGH */
- case (MAN_BLOCK):
+ case MAN_BLOCK:
/* FALLTHROUGH */
- case (MAN_HEAD):
+ case MAN_HEAD:
/* FALLTHROUGH */
- case (MAN_TAIL):
+ case MAN_TAIL:
/* FALLTHROUGH */
- case (MAN_BODY):
+ case MAN_BODY:
p = man_macronames[n->tok];
break;
- case (MAN_ROOT):
+ case MAN_ROOT:
p = "root";
break;
- case (MAN_TBL):
+ case MAN_TBL:
/* FALLTHROUGH */
- case (MAN_EQN):
+ case MAN_EQN:
break;
default:
abort();
@@ -252,7 +247,10 @@ print_man(const struct man_node *n, int indent)
} else {
for (i = 0; i < indent; i++)
putchar('\t');
- printf("%s (%s) %d:%d\n", p, t, n->line, n->pos);
+ printf("%s (%s) ", p, t);
+ if (MAN_LINE & n->flags)
+ putchar('*');
+ printf("%d:%d\n", n->line, n->pos + 1);
}
if (n->child)
@@ -274,30 +272,30 @@ print_box(const struct eqn_box *ep, int indent)
t = NULL;
switch (ep->type) {
- case (EQN_ROOT):
+ case EQN_ROOT:
t = "eqn-root";
break;
- case (EQN_LIST):
+ case EQN_LIST:
t = "eqn-list";
break;
- case (EQN_SUBEXPR):
+ case EQN_SUBEXPR:
t = "eqn-expr";
break;
- case (EQN_TEXT):
+ case EQN_TEXT:
t = "eqn-text";
break;
- case (EQN_MATRIX):
+ case EQN_MATRIX:
t = "eqn-matrix";
break;
}
assert(t);
- printf("%s(%d, %d, %d, %d, %d, \"%s\", \"%s\") %s\n",
- t, EQN_DEFSIZE == ep->size ? 0 : ep->size,
- ep->pos, ep->font, ep->mark, ep->pile,
- ep->left ? ep->left : "",
- ep->right ? ep->right : "",
- ep->text ? ep->text : "");
+ printf("%s(%d, %d, %d, %d, %d, \"%s\", \"%s\") %s\n",
+ t, EQN_DEFSIZE == ep->size ? 0 : ep->size,
+ ep->pos + 1, ep->font, ep->mark, ep->pile,
+ ep->left ? ep->left : "",
+ ep->right ? ep->right : "",
+ ep->text ? ep->text : "");
print_box(ep->first, indent + 1);
print_box(ep->next, indent);
@@ -313,10 +311,10 @@ print_span(const struct tbl_span *sp, int indent)
putchar('\t');
switch (sp->pos) {
- case (TBL_SPAN_HORIZ):
+ case TBL_SPAN_HORIZ:
putchar('-');
return;
- case (TBL_SPAN_DHORIZ):
+ case TBL_SPAN_DHORIZ:
putchar('=');
return;
default:
@@ -325,14 +323,14 @@ print_span(const struct tbl_span *sp, int indent)
for (dp = sp->first; dp; dp = dp->next) {
switch (dp->pos) {
- case (TBL_DATA_HORIZ):
+ case TBL_DATA_HORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_NHORIZ):
+ case TBL_DATA_NHORIZ:
putchar('-');
continue;
- case (TBL_DATA_DHORIZ):
+ case TBL_DATA_DHORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_NDHORIZ):
+ case TBL_DATA_NDHORIZ:
putchar('=');
continue;
default:
diff --git a/contrib/mdocml/vol.c b/contrib/mdocml/vol.c
index 3ea7441..7658ea4 100644
--- a/contrib/mdocml/vol.c
+++ b/contrib/mdocml/vol.c
@@ -1,4 +1,4 @@
-/* $Id: vol.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: vol.c,v 1.10 2014/03/23 11:25:26 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,12 +18,9 @@
#include "config.h"
#endif
-#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
OpenPOWER on IntegriCloud