Import mandoc 1.13.1
This commit is contained in:
parent
53f5f26c3e
commit
52c0e9552d
187
INSTALL
Normal file
187
INSTALL
Normal file
@ -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>
|
44
LICENSE
Normal file
44
LICENSE
Normal file
@ -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.
|
505
Makefile
505
Makefile
@ -1,15 +1,30 @@
|
||||
.PHONY: clean install installwww
|
||||
.SUFFIXES: .sgml .html .md5 .h .h.html
|
||||
.SUFFIXES: .1 .3 .7 .8
|
||||
.SUFFIXES: .1.html .3.html .7.html .8.html
|
||||
# $Id: Makefile,v 1.435 2014/08/10 02:45:04 schwarze Exp $
|
||||
#
|
||||
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
# Copyright (c) 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
VERSION = 1.13.1
|
||||
|
||||
# === USER SETTINGS ====================================================
|
||||
|
||||
# --- user settings relevant for all builds ----------------------------
|
||||
|
||||
# Specify this if you want to hard-code the operating system to appear
|
||||
# in the lower-left hand corner of -mdoc manuals.
|
||||
#
|
||||
# CFLAGS += -DOSNAME="\"OpenBSD 5.4\""
|
||||
|
||||
VERSION = 1.12.3
|
||||
VDATE = 31 December 2013
|
||||
# CFLAGS += -DOSNAME="\"OpenBSD 5.5\""
|
||||
|
||||
# IFF your system supports multi-byte functions (setlocale(), wcwidth(),
|
||||
# putwchar()) AND has __STDC_ISO_10646__ (that is, wchar_t is simply a
|
||||
@ -19,113 +34,136 @@ VDATE = 31 December 2013
|
||||
#
|
||||
CFLAGS += -DUSE_WCHAR
|
||||
|
||||
# If your system has manpath(1), uncomment this. This is most any
|
||||
# system that's not OpenBSD or NetBSD. If uncommented, apropos(1),
|
||||
# mandocdb(8), and man.cgi will popen(3) manpath(1) to get the MANPATH
|
||||
# variable.
|
||||
#CFLAGS += -DUSE_MANPATH
|
||||
|
||||
# If your system does not support static binaries, comment this,
|
||||
# for example on Mac OS X.
|
||||
STATIC = -static
|
||||
# Linux requires -pthread to statically link with libdb.
|
||||
#STATIC += -pthread
|
||||
|
||||
CFLAGS += -g -DHAVE_CONFIG_H
|
||||
CFLAGS += -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings
|
||||
PREFIX = /usr/local
|
||||
WWWPREFIX = /var/www
|
||||
HTDOCDIR = $(WWWPREFIX)/htdocs
|
||||
CGIBINDIR = $(WWWPREFIX)/cgi-bin
|
||||
BINDIR = $(PREFIX)/bin
|
||||
INCLUDEDIR = $(PREFIX)/include/mandoc
|
||||
LIBDIR = $(PREFIX)/lib/mandoc
|
||||
MANDIR = $(PREFIX)/man
|
||||
EXAMPLEDIR = $(PREFIX)/share/examples/mandoc
|
||||
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL) -m 0755
|
||||
INSTALL_PROGRAM = $(INSTALL) -m 0555
|
||||
INSTALL_DATA = $(INSTALL) -m 0444
|
||||
INSTALL_LIB = $(INSTALL) -m 0644
|
||||
INSTALL_LIB = $(INSTALL) -m 0444
|
||||
INSTALL_SOURCE = $(INSTALL) -m 0644
|
||||
INSTALL_MAN = $(INSTALL_DATA)
|
||||
|
||||
# Non-BSD systems (Linux, etc.) need -ldb to compile mandocdb and
|
||||
# apropos.
|
||||
# However, if you don't have -ldb at all (or it's not native), then
|
||||
# comment out apropos and mandocdb.
|
||||
# --- user settings related to database support ------------------------
|
||||
|
||||
# Building apropos(1) and makewhatis(8) requires both SQLite3 and fts(3).
|
||||
# To avoid those dependencies, comment the following line.
|
||||
# Be careful: the fts(3) implementation in glibc is broken on 32bit
|
||||
# machines, see: https://sourceware.org/bugzilla/show_bug.cgi?id=15838
|
||||
#
|
||||
#DBLIB = -ldb
|
||||
DBBIN = apropos mandocdb man.cgi catman whatis
|
||||
DBLN = llib-lapropos.ln llib-lmandocdb.ln llib-lman.cgi.ln llib-lcatman.ln
|
||||
BUILD_TARGETS += db-build
|
||||
|
||||
all: mandoc preconv demandoc $(DBBIN)
|
||||
# The remaining settings in this section
|
||||
# are only relevant if db-build is enabled.
|
||||
# Otherwise, they have no effect either way.
|
||||
|
||||
SRCS = Makefile \
|
||||
NEWS \
|
||||
TODO \
|
||||
apropos.1 \
|
||||
apropos.c \
|
||||
apropos_db.c \
|
||||
apropos_db.h \
|
||||
# If your system has manpath(1), uncomment this. This is most any
|
||||
# system that's not OpenBSD or NetBSD. If uncommented, apropos(1)
|
||||
# and makewhatis(8) will use manpath(1) to get the MANPATH variable.
|
||||
#
|
||||
#CFLAGS += -DUSE_MANPATH
|
||||
|
||||
# On some systems, SQLite3 may be installed below /usr/local.
|
||||
# In that case, uncomment the following two lines.
|
||||
#
|
||||
#CFLAGS += -I/usr/local/include
|
||||
#DBLIB += -L/usr/local/lib
|
||||
|
||||
# OpenBSD has the ohash functions in libutil.
|
||||
# Comment the following line if your system doesn't.
|
||||
#
|
||||
DBLIB += -lutil
|
||||
|
||||
SBINDIR = $(PREFIX)/sbin
|
||||
|
||||
# --- user settings related to man.cgi ---------------------------------
|
||||
|
||||
# To build man.cgi, copy cgi.h.example to cgi.h, edit it,
|
||||
# and enable the following line.
|
||||
# Obviously, this requires that db-build is enabled, too.
|
||||
#
|
||||
#BUILD_TARGETS += cgi-build
|
||||
|
||||
# The remaining settings in this section
|
||||
# are only relevant if cgi-build is enabled.
|
||||
# Otherwise, they have no effect either way.
|
||||
|
||||
# If your system does not support static binaries, comment this,
|
||||
# for example on Mac OS X.
|
||||
#
|
||||
STATIC = -static
|
||||
|
||||
# Linux requires -pthread for statical linking.
|
||||
#
|
||||
#STATIC += -pthread
|
||||
|
||||
WWWPREFIX = /var/www
|
||||
HTDOCDIR = $(WWWPREFIX)/htdocs
|
||||
CGIBINDIR = $(WWWPREFIX)/cgi-bin
|
||||
|
||||
# === END OF USER SETTINGS =============================================
|
||||
|
||||
INSTALL_TARGETS = $(BUILD_TARGETS:-build=-install)
|
||||
|
||||
BASEBIN = mandoc preconv demandoc
|
||||
DBBIN = apropos makewhatis
|
||||
CGIBIN = man.cgi
|
||||
|
||||
DBLIB += -lsqlite3
|
||||
|
||||
TESTSRCS = test-fgetln.c \
|
||||
test-getsubopt.c \
|
||||
test-mmap.c \
|
||||
test-ohash.c \
|
||||
test-reallocarray.c \
|
||||
test-sqlite3_errstr.c \
|
||||
test-strcasestr.c \
|
||||
test-strlcat.c \
|
||||
test-strlcpy.c \
|
||||
test-strptime.c \
|
||||
test-strsep.c
|
||||
|
||||
SRCS = apropos.c \
|
||||
arch.c \
|
||||
arch.in \
|
||||
att.c \
|
||||
att.in \
|
||||
catman.8 \
|
||||
catman.c \
|
||||
cgi.c \
|
||||
chars.c \
|
||||
chars.in \
|
||||
compat_fgetln.c \
|
||||
compat_getsubopt.c \
|
||||
compat_ohash.c \
|
||||
compat_reallocarray.c \
|
||||
compat_sqlite3_errstr.c \
|
||||
compat_strcasestr.c \
|
||||
compat_strlcat.c \
|
||||
compat_strlcpy.c \
|
||||
config.h.post \
|
||||
config.h.pre \
|
||||
demandoc.1 \
|
||||
compat_strsep.c \
|
||||
demandoc.c \
|
||||
eqn.7 \
|
||||
eqn.c \
|
||||
eqn_html.c \
|
||||
eqn_term.c \
|
||||
example.style.css \
|
||||
external.png \
|
||||
gmdiff \
|
||||
html.c \
|
||||
html.h \
|
||||
index.css \
|
||||
index.sgml \
|
||||
lib.c \
|
||||
lib.in \
|
||||
libman.h \
|
||||
libmandoc.h \
|
||||
libmdoc.h \
|
||||
libroff.h \
|
||||
main.c \
|
||||
main.h \
|
||||
man.7 \
|
||||
man.c \
|
||||
man.cgi.7 \
|
||||
man-cgi.css \
|
||||
man.h \
|
||||
man_hash.c \
|
||||
man_html.c \
|
||||
man_macro.c \
|
||||
man_term.c \
|
||||
man_validate.c \
|
||||
mandoc.1 \
|
||||
mandoc.3 \
|
||||
mandoc.c \
|
||||
mandoc.h \
|
||||
mandoc_char.7 \
|
||||
mandocdb.8 \
|
||||
mandoc_aux.c \
|
||||
mandocdb.c \
|
||||
mandocdb.h \
|
||||
manpage.c \
|
||||
manpath.c \
|
||||
manpath.h \
|
||||
mdoc.7 \
|
||||
mansearch.c \
|
||||
mansearch_const.c \
|
||||
mdoc.c \
|
||||
mdoc.h \
|
||||
mdoc_argv.c \
|
||||
mdoc_hash.c \
|
||||
mdoc_html.c \
|
||||
@ -134,20 +172,11 @@ SRCS = Makefile \
|
||||
mdoc_term.c \
|
||||
mdoc_validate.c \
|
||||
msec.c \
|
||||
msec.in \
|
||||
out.c \
|
||||
out.h \
|
||||
preconv.1 \
|
||||
preconv.c \
|
||||
predefs.in \
|
||||
read.c \
|
||||
roff.7 \
|
||||
roff.c \
|
||||
st.c \
|
||||
st.in \
|
||||
style.css \
|
||||
tbl.3 \
|
||||
tbl.7 \
|
||||
tbl.c \
|
||||
tbl_data.c \
|
||||
tbl_html.c \
|
||||
@ -155,20 +184,70 @@ SRCS = Makefile \
|
||||
tbl_opts.c \
|
||||
tbl_term.c \
|
||||
term.c \
|
||||
term.h \
|
||||
term_ascii.c \
|
||||
term_ps.c \
|
||||
test-betoh64.c \
|
||||
test-fgetln.c \
|
||||
test-getsubopt.c \
|
||||
test-mmap.c \
|
||||
test-strlcat.c \
|
||||
test-strlcpy.c \
|
||||
test-strptime.c \
|
||||
tree.c \
|
||||
vol.c \
|
||||
$(TESTSRCS)
|
||||
|
||||
DISTFILES = INSTALL \
|
||||
LICENSE \
|
||||
Makefile \
|
||||
Makefile.depend \
|
||||
NEWS \
|
||||
TODO \
|
||||
apropos.1 \
|
||||
arch.in \
|
||||
att.in \
|
||||
cgi.h.example \
|
||||
chars.in \
|
||||
compat_ohash.h \
|
||||
config.h.post \
|
||||
config.h.pre \
|
||||
configure \
|
||||
demandoc.1 \
|
||||
eqn.7 \
|
||||
example.style.css \
|
||||
gmdiff \
|
||||
html.h \
|
||||
lib.in \
|
||||
libman.h \
|
||||
libmandoc.h \
|
||||
libmdoc.h \
|
||||
libroff.h \
|
||||
main.h \
|
||||
makewhatis.8 \
|
||||
man-cgi.css \
|
||||
man.7 \
|
||||
man.cgi.8 \
|
||||
man.h \
|
||||
mandoc.1 \
|
||||
mandoc.3 \
|
||||
mandoc.db.5 \
|
||||
mandoc.h \
|
||||
mandoc_aux.h \
|
||||
mandoc_char.7 \
|
||||
mandoc_escape.3 \
|
||||
mandoc_html.3 \
|
||||
mandoc_malloc.3 \
|
||||
manpath.h \
|
||||
mansearch.3 \
|
||||
mansearch.h \
|
||||
mchars_alloc.3 \
|
||||
mdoc.7 \
|
||||
mdoc.h \
|
||||
msec.in \
|
||||
out.h \
|
||||
preconv.1 \
|
||||
predefs.in \
|
||||
roff.7 \
|
||||
st.in \
|
||||
style.css \
|
||||
tbl.3 \
|
||||
tbl.7 \
|
||||
term.h \
|
||||
vol.in \
|
||||
whatis.1
|
||||
$(SRCS)
|
||||
|
||||
LIBMAN_OBJS = man.o \
|
||||
man_hash.o \
|
||||
@ -198,35 +277,25 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
|
||||
$(LIBROFF_OBJS) \
|
||||
chars.o \
|
||||
mandoc.o \
|
||||
mandoc_aux.o \
|
||||
msec.o \
|
||||
read.o
|
||||
|
||||
COMPAT_OBJS = compat_fgetln.o \
|
||||
compat_getsubopt.o \
|
||||
compat_ohash.o \
|
||||
compat_reallocarray.o \
|
||||
compat_sqlite3_errstr.o \
|
||||
compat_strcasestr.o \
|
||||
compat_strlcat.o \
|
||||
compat_strlcpy.o
|
||||
|
||||
arch.o: arch.in
|
||||
att.o: att.in
|
||||
chars.o: chars.in
|
||||
lib.o: lib.in
|
||||
msec.o: msec.in
|
||||
roff.o: predefs.in
|
||||
st.o: st.in
|
||||
vol.o: vol.in
|
||||
|
||||
$(LIBMAN_OBJS): libman.h
|
||||
$(LIBMDOC_OBJS): libmdoc.h
|
||||
$(LIBROFF_OBJS): libroff.h
|
||||
$(LIBMANDOC_OBJS): mandoc.h mdoc.h man.h libmandoc.h config.h
|
||||
$(COMPAT_OBJS): config.h
|
||||
compat_strlcpy.o \
|
||||
compat_strsep.o
|
||||
|
||||
MANDOC_HTML_OBJS = eqn_html.o \
|
||||
html.o \
|
||||
man_html.o \
|
||||
mdoc_html.o \
|
||||
tbl_html.o
|
||||
$(MANDOC_HTML_OBJS): html.h
|
||||
|
||||
MANDOC_MAN_OBJS = mdoc_man.o
|
||||
|
||||
@ -237,7 +306,6 @@ MANDOC_TERM_OBJS = eqn_term.o \
|
||||
term_ascii.o \
|
||||
term_ps.o \
|
||||
tbl_term.o
|
||||
$(MANDOC_TERM_OBJS): term.h
|
||||
|
||||
MANDOC_OBJS = $(MANDOC_HTML_OBJS) \
|
||||
$(MANDOC_MAN_OBJS) \
|
||||
@ -245,76 +313,85 @@ MANDOC_OBJS = $(MANDOC_HTML_OBJS) \
|
||||
main.o \
|
||||
out.o \
|
||||
tree.o
|
||||
$(MANDOC_OBJS): main.h mandoc.h mdoc.h man.h config.h out.h
|
||||
|
||||
MANDOCDB_OBJS = mandocdb.o manpath.o
|
||||
$(MANDOCDB_OBJS): mandocdb.h mandoc.h mdoc.h man.h config.h manpath.h
|
||||
MAKEWHATIS_OBJS = mandocdb.o mansearch_const.o manpath.o
|
||||
|
||||
PRECONV_OBJS = preconv.o
|
||||
$(PRECONV_OBJS): config.h
|
||||
|
||||
APROPOS_OBJS = apropos.o apropos_db.o manpath.o
|
||||
$(APROPOS_OBJS): config.h mandoc.h apropos_db.h manpath.h mandocdb.h
|
||||
APROPOS_OBJS = apropos.o mansearch.o mansearch_const.o manpath.o
|
||||
|
||||
CGI_OBJS = $(MANDOC_HTML_OBJS) \
|
||||
$(MANDOC_MAN_OBJS) \
|
||||
$(MANDOC_TERM_OBJS) \
|
||||
cgi.o \
|
||||
apropos_db.o \
|
||||
manpath.o \
|
||||
out.o \
|
||||
tree.o
|
||||
$(CGI_OBJS): main.h mdoc.h man.h out.h config.h mandoc.h apropos_db.h manpath.h mandocdb.h
|
||||
mansearch.o \
|
||||
mansearch_const.o \
|
||||
out.o
|
||||
|
||||
CATMAN_OBJS = catman.o manpath.o
|
||||
$(CATMAN_OBJS): config.h mandoc.h manpath.h mandocdb.h
|
||||
MANPAGE_OBJS = manpage.o mansearch.o mansearch_const.o manpath.o
|
||||
|
||||
DEMANDOC_OBJS = demandoc.o
|
||||
$(DEMANDOC_OBJS): config.h
|
||||
|
||||
INDEX_MANS = apropos.1.html \
|
||||
catman.8.html \
|
||||
WWW_MANS = apropos.1.html \
|
||||
demandoc.1.html \
|
||||
mandoc.1.html \
|
||||
whatis.1.html \
|
||||
preconv.1.html \
|
||||
mandoc.3.html \
|
||||
mandoc_escape.3.html \
|
||||
mandoc_html.3.html \
|
||||
mandoc_malloc.3.html \
|
||||
mansearch.3.html \
|
||||
mchars_alloc.3.html \
|
||||
tbl.3.html \
|
||||
mandoc.db.5.html \
|
||||
eqn.7.html \
|
||||
man.7.html \
|
||||
man.cgi.7.html \
|
||||
mandoc_char.7.html \
|
||||
mdoc.7.html \
|
||||
preconv.1.html \
|
||||
roff.7.html \
|
||||
tbl.7.html \
|
||||
mandocdb.8.html
|
||||
|
||||
$(INDEX_MANS): mandoc
|
||||
|
||||
INDEX_OBJS = $(INDEX_MANS) \
|
||||
makewhatis.8.html \
|
||||
man.cgi.8.html \
|
||||
man.h.html \
|
||||
mandoc.h.html \
|
||||
mdoc.h.html \
|
||||
mdocml.tar.gz \
|
||||
mdocml.md5
|
||||
mandoc_aux.h.html \
|
||||
manpath.h.html \
|
||||
mansearch.h.html \
|
||||
mdoc.h.html
|
||||
|
||||
www: index.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 mandocdb $(MANDOCDB_OBJS)
|
||||
rm -f apropos $(APROPOS_OBJS)
|
||||
rm -f makewhatis $(MAKEWHATIS_OBJS)
|
||||
rm -f preconv $(PRECONV_OBJS)
|
||||
rm -f apropos whatis $(APROPOS_OBJS)
|
||||
rm -f man.cgi $(CGI_OBJS)
|
||||
rm -f catman $(CATMAN_OBJS)
|
||||
rm -f manpage $(MANPAGE_OBJS)
|
||||
rm -f demandoc $(DEMANDOC_OBJS)
|
||||
rm -f mandoc $(MANDOC_OBJS)
|
||||
rm -f config.h config.log $(COMPAT_OBJS)
|
||||
rm -f mdocml.tar.gz
|
||||
rm -f index.html $(INDEX_OBJS)
|
||||
rm -f $(WWW_MANS) $(WWW_OBJS)
|
||||
rm -rf *.dSYM
|
||||
|
||||
install: all
|
||||
base-install: base-build
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
mkdir -p $(DESTDIR)$(EXAMPLEDIR)
|
||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
@ -322,31 +399,59 @@ install: all
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man3
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man7
|
||||
$(INSTALL_PROGRAM) mandoc preconv demandoc $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL_PROGRAM) $(BASEBIN) $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL_LIB) man.h mdoc.h mandoc.h $(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h \
|
||||
$(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL_MAN) mandoc.1 preconv.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
|
||||
$(INSTALL_MAN) mandoc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
|
||||
$(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 $(DESTDIR)$(MANDIR)/man7
|
||||
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
|
||||
mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
|
||||
$(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 \
|
||||
$(DESTDIR)$(MANDIR)/man7
|
||||
$(INSTALL_DATA) example.style.css $(DESTDIR)$(EXAMPLEDIR)
|
||||
|
||||
installcgi: all
|
||||
db-install: db-build
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
mkdir -p $(DESTDIR)$(SBINDIR)
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man3
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL_PROGRAM) apropos $(DESTDIR)$(BINDIR)
|
||||
ln -f $(DESTDIR)$(BINDIR)/apropos $(DESTDIR)$(BINDIR)/whatis
|
||||
$(INSTALL_PROGRAM) makewhatis $(DESTDIR)$(SBINDIR)
|
||||
$(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1
|
||||
ln -f $(DESTDIR)$(MANDIR)/man1/apropos.1 \
|
||||
$(DESTDIR)$(MANDIR)/man1/whatis.1
|
||||
$(INSTALL_MAN) mansearch.3 $(DESTDIR)$(MANDIR)/man3
|
||||
$(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5
|
||||
$(INSTALL_MAN) makewhatis.8 $(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
cgi-install: cgi-build
|
||||
mkdir -p $(DESTDIR)$(CGIBINDIR)
|
||||
mkdir -p $(DESTDIR)$(HTDOCDIR)
|
||||
mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1
|
||||
mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8
|
||||
$(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR)
|
||||
$(INSTALL_DATA) example.style.css $(DESTDIR)$(HTDOCDIR)/man.css
|
||||
$(INSTALL_DATA) man-cgi.css $(DESTDIR)$(HTDOCDIR)
|
||||
$(INSTALL_MAN) apropos.1 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1/
|
||||
$(INSTALL_MAN) man.cgi.8 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8/
|
||||
|
||||
installwww: www
|
||||
mkdir -p $(PREFIX)/snapshots
|
||||
mkdir -p $(PREFIX)/binaries
|
||||
$(INSTALL_DATA) index.html external.png index.css $(PREFIX)
|
||||
$(INSTALL_DATA) $(INDEX_MANS) style.css $(PREFIX)
|
||||
$(INSTALL_DATA) mandoc.h.html man.h.html mdoc.h.html $(PREFIX)
|
||||
$(INSTALL_DATA) mdocml.tar.gz $(PREFIX)/snapshots
|
||||
$(INSTALL_DATA) mdocml.md5 $(PREFIX)/snapshots
|
||||
$(INSTALL_DATA) mdocml.tar.gz $(PREFIX)/snapshots/mdocml-$(VERSION).tar.gz
|
||||
$(INSTALL_DATA) mdocml.md5 $(PREFIX)/snapshots/mdocml-$(VERSION).md5
|
||||
www-install: www
|
||||
mkdir -p $(DESTDIR)$(HTDOCDIR)/snapshots
|
||||
$(INSTALL_DATA) $(WWW_MANS) style.css $(DESTDIR)$(HTDOCDIR)
|
||||
$(INSTALL_DATA) $(WWW_OBJS) $(DESTDIR)$(HTDOCDIR)/snapshots
|
||||
$(INSTALL_DATA) mdocml.tar.gz \
|
||||
$(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).tar.gz
|
||||
$(INSTALL_DATA) mdocml.sha256 \
|
||||
$(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).sha256
|
||||
|
||||
depend: config.h
|
||||
mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
|
||||
perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \
|
||||
s|\\\n||g; s| +| |g; print;' Makefile.depend > Makefile.tmp
|
||||
mv Makefile.tmp Makefile.depend
|
||||
|
||||
libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
|
||||
$(AR) rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
|
||||
@ -354,81 +459,47 @@ libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
|
||||
mandoc: $(MANDOC_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(MANDOC_OBJS) libmandoc.a
|
||||
|
||||
mandocdb: $(MANDOCDB_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(MANDOCDB_OBJS) libmandoc.a $(DBLIB)
|
||||
makewhatis: $(MAKEWHATIS_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(MAKEWHATIS_OBJS) libmandoc.a $(DBLIB)
|
||||
|
||||
preconv: $(PRECONV_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(PRECONV_OBJS)
|
||||
|
||||
whatis: apropos
|
||||
cp -f apropos whatis
|
||||
manpage: $(MANPAGE_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(MANPAGE_OBJS) libmandoc.a $(DBLIB)
|
||||
|
||||
apropos: $(APROPOS_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(APROPOS_OBJS) libmandoc.a $(DBLIB)
|
||||
|
||||
catman: $(CATMAN_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(CATMAN_OBJS) libmandoc.a $(DBLIB)
|
||||
|
||||
man.cgi: $(CGI_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
|
||||
|
||||
demandoc: $(DEMANDOC_OBJS) libmandoc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a
|
||||
|
||||
mdocml.md5: mdocml.tar.gz
|
||||
md5 mdocml.tar.gz >$@
|
||||
mdocml.sha256: mdocml.tar.gz
|
||||
sha256 mdocml.tar.gz > $@
|
||||
|
||||
mdocml.tar.gz: $(SRCS)
|
||||
mdocml.tar.gz: $(DISTFILES)
|
||||
mkdir -p .dist/mdocml-$(VERSION)/
|
||||
$(INSTALL_SOURCE) $(SRCS) .dist/mdocml-$(VERSION)
|
||||
( cd .dist/ && tar zcf ../$@ ./ )
|
||||
$(INSTALL_SOURCE) $(DISTFILES) .dist/mdocml-$(VERSION)
|
||||
chmod 755 .dist/mdocml-$(VERSION)/configure
|
||||
( cd .dist/ && tar zcf ../$@ mdocml-$(VERSION) )
|
||||
rm -rf .dist/
|
||||
|
||||
index.html: $(INDEX_OBJS)
|
||||
|
||||
config.h: config.h.pre config.h.post
|
||||
config.h: configure config.h.pre config.h.post $(TESTSRCS)
|
||||
rm -f config.log
|
||||
( cat config.h.pre; \
|
||||
echo; \
|
||||
echo '#define VERSION "$(VERSION)"'; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-fgetln test-fgetln.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_FGETLN'; \
|
||||
rm test-fgetln; \
|
||||
fi; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strptime test-strptime.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_STRPTIME'; \
|
||||
rm test-strptime; \
|
||||
fi; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-getsubopt test-getsubopt.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_GETSUBOPT'; \
|
||||
rm test-getsubopt; \
|
||||
fi; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strlcat test-strlcat.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_STRLCAT'; \
|
||||
rm test-strlcat; \
|
||||
fi; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-mmap test-mmap.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_MMAP'; \
|
||||
rm test-mmap; \
|
||||
fi; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strlcpy test-strlcpy.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_STRLCPY'; \
|
||||
rm test-strlcpy; \
|
||||
fi; \
|
||||
if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-betoh64 test-betoh64.c >> config.log 2>&1; then \
|
||||
echo '#define HAVE_BETOH64'; \
|
||||
rm test-betoh64; \
|
||||
fi; \
|
||||
echo; \
|
||||
cat config.h.post \
|
||||
) > $@
|
||||
CC="$(CC)" CFLAGS="$(CFLAGS)" DBLIB="$(DBLIB)" \
|
||||
VERSION="$(VERSION)" ./configure
|
||||
|
||||
.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 $< >$@
|
||||
highlight -I $< > $@
|
||||
|
||||
.1.1.html .3.3.html .7.7.html .8.8.html:
|
||||
./mandoc -Thtml -Wall,stop -Ostyle=style.css,man=%N.%S.html,includes=%I.html $< >$@
|
||||
|
||||
.sgml.html:
|
||||
validate --warn $<
|
||||
sed -e "s!@VERSION@!$(VERSION)!" -e "s!@VDATE@!$(VDATE)!" $< >$@
|
||||
.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
|
||||
./mandoc -Thtml -Wall,stop \
|
||||
-Ostyle=style.css,man=%N.%S.html,includes=%I.html $< > $@
|
||||
|
70
Makefile.depend
Normal file
70
Makefile.depend
Normal file
@ -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
|
82
NEWS
82
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
|
||||
|
175
TODO
175
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
|
||||
@ -298,10 +351,58 @@ None known.
|
||||
operate in batch mode
|
||||
in dig(1).
|
||||
|
||||
************************************************************************
|
||||
* warning issues
|
||||
************************************************************************
|
||||
|
||||
- check that MANDOCERR_BADTAB is thrown in the right cases,
|
||||
i.e. when finding a literal tab character in fill mode,
|
||||
and possibly change the wording of the warning message
|
||||
to refer to fill mode, not literal mode
|
||||
See the mail from Werner LEMBERG on the groff list,
|
||||
Fri, 14 Feb 2014 18:54:42 +0100 (CET)
|
||||
|
||||
- warn about "new sentence, new line"
|
||||
|
||||
- mandoc_special does not really check the escape sequence,
|
||||
but just the overall format
|
||||
|
||||
- integrate mdoclint into mandoc ("end-of-line whitespace" thread)
|
||||
from jmc@ Mon, 13 Jul 2009 17:12:09 +0100
|
||||
from kristaps@ Mon, 13 Jul 2009 18:34:53 +0200
|
||||
from jmc@ Mon, 13 Jul 2009 17:45:37 +0059
|
||||
from kristaps@ Mon, 13 Jul 2009 19:02:03 +0200
|
||||
|
||||
- -Tlint parser errors and warnings to stdout
|
||||
to tech@mdocml, naddy@ Wed, 28 Sep 2011 11:21:46 +0200
|
||||
wait! kristaps@ Sun, 02 Oct 2011 17:12:52 +0200
|
||||
|
||||
- for system errors, use errno/strerror/warn/err
|
||||
|
||||
************************************************************************
|
||||
* documentation issues
|
||||
************************************************************************
|
||||
|
||||
- mention hyphenation rules:
|
||||
breaking at letter-letter in text mode (not macro args)
|
||||
proper hyphenation is unimplemented
|
||||
|
||||
- talk about spacing around delimiters
|
||||
to jmc@, kristaps@ Sat, 23 Apr 2011 17:41:27 +0200
|
||||
|
||||
- mark macros as: page structure domain, manual domain, general text domain
|
||||
is this useful?
|
||||
|
||||
- mention /usr/share/misc/mdoc.template in mdoc(7)?
|
||||
|
||||
************************************************************************
|
||||
* performance issues
|
||||
************************************************************************
|
||||
|
||||
- Why are we using MAP_SHARED, not MAP_PRIVATE for mmap(2)?
|
||||
How does SQLITE_CONFIG_PAGECACHE actually work? Document it!
|
||||
from kristaps@ Sat, 09 Aug 2014 13:51:36 +0200
|
||||
|
||||
Several areas can be cleaned up to make mandoc even faster. These are
|
||||
|
||||
- improve hashing mechanism for macros (quite important: performance)
|
||||
@ -328,3 +429,9 @@ Several areas can be cleaned up to make mandoc even faster. These are
|
||||
Decide which formats should be recognized where.
|
||||
Update both mdoc(7) and man(7) documentation.
|
||||
Triggered by Tim van der Molen Tue, 22 Feb 2011 20:30:45 +0100
|
||||
|
||||
- Consider creating some views that will make the database more
|
||||
readable from the sqlite3 shell. Consider using them to
|
||||
abstract from the database structure, too.
|
||||
suggested by espie@ Sat, 19 Apr 2014 14:52:57 +0200
|
||||
|
||||
|
222
apropos.1
222
apropos.1
@ -1,6 +1,7 @@
|
||||
.\" $Id: apropos.1,v 1.16.2.3 2013/10/05 01:25:20 schwarze Exp $
|
||||
.\" $Id: apropos.1,v 1.29 2014/04/24 00:28:19 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
@ -14,41 +15,49 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: October 5 2013 $
|
||||
.Dd $Mdocdate: April 24 2014 $
|
||||
.Dt APROPOS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm apropos
|
||||
.Nm apropos ,
|
||||
.Nm whatis
|
||||
.Nd search manual page databases
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl C Ar file
|
||||
.Op Fl M Ar path
|
||||
.Op Fl m Ar path
|
||||
.Op Fl O Ar outkey
|
||||
.Op Fl S Ar arch
|
||||
.Op Fl s Ar section
|
||||
.Ar expression ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility queries manual page databases generated by
|
||||
.Xr mandocdb 8 ,
|
||||
evaluating on
|
||||
.Nm apropos
|
||||
and
|
||||
.Nm whatis
|
||||
utilities query manual page databases generated by
|
||||
.Xr makewhatis 8 ,
|
||||
evaluating
|
||||
.Ar expression
|
||||
for each file in each database.
|
||||
By default, it displays the names, section numbers, and description lines
|
||||
of all matching manuals.
|
||||
.Pp
|
||||
By default,
|
||||
.Nm
|
||||
searches for
|
||||
.Xr mandocdb 8
|
||||
.Xr makewhatis 8
|
||||
databases in the default paths stipulated by
|
||||
.Xr man 1 ,
|
||||
parses terms as case-sensitive regular expressions
|
||||
.Pq the Li \&~ operator
|
||||
.Xr man 1
|
||||
and uses case-insensitive substring matching
|
||||
.Pq the Cm = No operator
|
||||
over manual names and descriptions
|
||||
.Pq the Li \&Nm No and Li \&Nd No macro keys .
|
||||
Multiple terms imply pairwise
|
||||
.Fl o .
|
||||
.Nm whatis
|
||||
maps terms only to case-sensitive manual names.
|
||||
.Pp
|
||||
Its arguments are as follows:
|
||||
.Bl -tag -width Ds
|
||||
@ -61,22 +70,32 @@ format.
|
||||
.It Fl M Ar path
|
||||
Use the colon-separated path instead of the default list of paths
|
||||
searched for
|
||||
.Xr mandocdb 8
|
||||
.Xr makewhatis 8
|
||||
databases.
|
||||
Invalid paths, or paths without manual databases, are ignored.
|
||||
.It Fl m Ar path
|
||||
Prepend the colon-separated paths to the list of paths searched
|
||||
for
|
||||
.Xr mandocdb 8
|
||||
.Xr makewhatis 8
|
||||
databases.
|
||||
Invalid paths, or paths without manual databases, are ignored.
|
||||
.It Fl O Ar outkey
|
||||
Show the values associated with the key
|
||||
.Ar outkey
|
||||
instead of the manual descriptions.
|
||||
.It Fl S Ar arch
|
||||
Search only for a particular architecture.
|
||||
.It Fl s Ar cat
|
||||
Search only for a manual section.
|
||||
Restrict the search to pages for the specified
|
||||
.Xr machine 1
|
||||
architecture.
|
||||
.Ar arch
|
||||
is case insensitive.
|
||||
By default, pages for all architectures are shown.
|
||||
.It Fl s Ar section
|
||||
Restrict the search to the specified section of the manual.
|
||||
By default, pages from all sections are shown.
|
||||
See
|
||||
.Xr man 1
|
||||
for a listing of manual sections.
|
||||
for a listing of sections.
|
||||
.El
|
||||
.Pp
|
||||
An
|
||||
@ -103,34 +122,40 @@ True if both
|
||||
and
|
||||
.Ar expr2
|
||||
are true (logical
|
||||
.Qq and ) .
|
||||
.Sq and ) .
|
||||
.It Ar expr1 Oo Fl o Oc Ar expr2
|
||||
True if
|
||||
.Ar expr1
|
||||
and/or
|
||||
.Ar expr2
|
||||
evaluate to true (logical
|
||||
.Qq or ) .
|
||||
.Sq or ) .
|
||||
.It Ar term
|
||||
True if
|
||||
.Ar term
|
||||
is satisfied.
|
||||
This has syntax
|
||||
.Li [key[,key]*(=~)]?val ,
|
||||
where operand
|
||||
.Cm key
|
||||
.Sm off
|
||||
.Oo
|
||||
.Op Ar key Op , Ar key ...
|
||||
.Pq Cm = | ~
|
||||
.Oc
|
||||
.Ar val ,
|
||||
.Sm on
|
||||
where
|
||||
.Ar key
|
||||
is an
|
||||
.Xr mdoc 7
|
||||
macro to query and
|
||||
.Cm val
|
||||
.Ar val
|
||||
is its value.
|
||||
See
|
||||
.Sx Macro Keys
|
||||
for a list of available keys.
|
||||
Operator
|
||||
.Li \&=
|
||||
.Cm =
|
||||
evaluates a substring, while
|
||||
.Li \&~
|
||||
.Cm ~
|
||||
evaluates a regular expression.
|
||||
.It Fl i Ar term
|
||||
If
|
||||
@ -140,34 +165,38 @@ is evaluated case-insensitively.
|
||||
Has no effect on substring terms.
|
||||
.El
|
||||
.Pp
|
||||
Results are sorted by manual title, with output formatted as
|
||||
.Nm whatis
|
||||
considers an
|
||||
.Ar expression
|
||||
to consist of an opaque keyword.
|
||||
.Pp
|
||||
.D1 title(sec) \- description
|
||||
Results are sorted by manual sections and names, with output formatted as
|
||||
.Pp
|
||||
.D1 name[, name...](sec) \- description
|
||||
.Pp
|
||||
Where
|
||||
.Qq title
|
||||
is the manual's title (note multiple manual names may exist for one
|
||||
title),
|
||||
.Qq sec
|
||||
.Dq name
|
||||
is the manual's name,
|
||||
.Dq sec
|
||||
is the manual section, and
|
||||
.Qq description
|
||||
.Dq description
|
||||
is the manual's short description.
|
||||
If an architecture is specified for the manual, it is displayed as
|
||||
.Pp
|
||||
.D1 title(cat/arch) \- description
|
||||
.D1 name(sec/arch) \- description
|
||||
.Pp
|
||||
Resulting manuals may be accessed as
|
||||
.Pp
|
||||
.Dl $ man \-s sec title
|
||||
.Dl $ man \-s sec name
|
||||
.Pp
|
||||
If an architecture is specified in the output, use
|
||||
.Pp
|
||||
.Dl $ man \-s sec \-S arch title
|
||||
.Dl $ man \-s sec \-S arch name
|
||||
.Ss Macro Keys
|
||||
Queries evaluate over a subset of
|
||||
.Xr mdoc 7
|
||||
macros indexed by
|
||||
.Xr mandocdb 8 .
|
||||
.Xr makewhatis 8 .
|
||||
In addition to the macro keys listed below, the special key
|
||||
.Cm any
|
||||
may be used to match any available macro key.
|
||||
@ -176,6 +205,8 @@ Names and description:
|
||||
.Bl -column "xLix" description -offset indent -compact
|
||||
.It Li \&Nm Ta manual name
|
||||
.It Li \&Nd Ta one-line manual description
|
||||
.It Li arch Ta machine architecture (case-insensitive)
|
||||
.It Li sec Ta manual section number
|
||||
.El
|
||||
.Pp
|
||||
Sections and cross references:
|
||||
@ -239,35 +270,31 @@ Text production:
|
||||
.It Li \&Dx Ta Dx No version reference
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Ds
|
||||
.Bl -tag -width MANPATH
|
||||
.It Ev MANPATH
|
||||
Colon-separated paths modifying the default list of paths searched for
|
||||
manual databases.
|
||||
The standard search path used by
|
||||
.Xr man 1
|
||||
may be changed by specifying a path in the
|
||||
.Ev MANPATH
|
||||
environment variable.
|
||||
Invalid paths, or paths without manual databases, are ignored.
|
||||
Overridden by
|
||||
.Fl M .
|
||||
If
|
||||
.Ev MANPATH
|
||||
begins with a
|
||||
.Sq \&: ,
|
||||
it is appended to the default list;
|
||||
else if it ends with
|
||||
.Sq \&: ,
|
||||
it is prepended to the default list; else if it contains
|
||||
.Sq \&:: ,
|
||||
the default list is inserted between the colons.
|
||||
If none of these conditions are met, it overrides the default list.
|
||||
begins with a colon, it is appended to the default list;
|
||||
if it ends with a colon, it is prepended to the default list;
|
||||
or if it contains two adjacent colons,
|
||||
the standard search path is inserted between the colons.
|
||||
If none of these conditions are met, it overrides the
|
||||
standard search path.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/etc/man.conf" -compact
|
||||
.It Pa mandoc.db
|
||||
name of the
|
||||
.Xr mandocdb 8
|
||||
.Xr makewhatis 8
|
||||
keyword database
|
||||
.It Pa mandoc.index
|
||||
name of the
|
||||
.Xr mandocdb 8
|
||||
filename database
|
||||
.It Pa /etc/man.conf
|
||||
default
|
||||
.Xr man 1
|
||||
@ -277,35 +304,84 @@ configuration file
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
Search for
|
||||
.Qq mdoc
|
||||
as a substring and regular expression
|
||||
within each manual name and description:
|
||||
.Qq .cf
|
||||
as a substring of manual names and descriptions:
|
||||
.Pp
|
||||
.Dl $ apropos mdoc
|
||||
.Dl $ apropos ~^mdoc$
|
||||
.Dl $ apropos .cf
|
||||
.Pp
|
||||
Include matches for
|
||||
.Qq roff
|
||||
.Qq .cnf
|
||||
and
|
||||
.Qq man
|
||||
for the regular expression case:
|
||||
.Qq .conf
|
||||
as well:
|
||||
.Pp
|
||||
.Dl $ apropos ~^mdoc$ roff man
|
||||
.Dl $ apropos ~^mdoc$ \-o roff \-o man
|
||||
.Dl $ apropos .cf .cnf .conf
|
||||
.Pp
|
||||
Search for
|
||||
Search in names and descriptions using a regular expression:
|
||||
.Pp
|
||||
.Dl $ apropos '~set.?[ug]id'
|
||||
.Pp
|
||||
Search for manuals in the library section mentioning both the
|
||||
.Qq optind
|
||||
and
|
||||
and the
|
||||
.Qq optarg
|
||||
as variable names in the library category:
|
||||
variables:
|
||||
.Pp
|
||||
.Dl $ apropos \-s 3 Va~^optind \-a Va~^optarg$
|
||||
.Dl $ apropos \-s 3 Va=optind \-a Va=optarg
|
||||
.Pp
|
||||
Do exactly the same as calling
|
||||
.Xr whatis 1
|
||||
with the argument
|
||||
.Qq ssh :
|
||||
.Pp
|
||||
.Dl $ apropos \-\- \-i 'Nm~[[:<:]]ssh[[:>:]]'
|
||||
.Pp
|
||||
The following two invocations are equivalent:
|
||||
.Pp
|
||||
.D1 Li $ apropos -S Ar arch Li -s Ar section expression
|
||||
.Bd -ragged -offset indent
|
||||
.Li $ apropos \e( Ar expression Li \e)
|
||||
.Li -a arch~^( Ns Ar arch Ns Li |any)$
|
||||
.Li -a sec~^ Ns Ar section Ns Li $
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr man 1 ,
|
||||
.Xr re_format 7 ,
|
||||
.Xr mandocdb 8
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Xr makewhatis 8
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
|
||||
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 .
|
||||
|
121
apropos.c
121
apropos.c
@ -1,7 +1,7 @@
|
||||
/* $Id: apropos.c,v 1.27.2.1 2013/09/17 23:23:10 schwarze Exp $ */
|
||||
/* $Id: apropos.c,v 1.39 2014/04/20 16:46:04 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -22,30 +22,28 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "apropos_db.h"
|
||||
#include "mandoc.h"
|
||||
#include "manpath.h"
|
||||
#include "mansearch.h"
|
||||
|
||||
static int cmp(const void *, const void *);
|
||||
static void list(struct res *, size_t, void *);
|
||||
|
||||
static char *progname;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch, rc, whatis;
|
||||
struct res *res;
|
||||
int ch, whatis;
|
||||
struct mansearch search;
|
||||
size_t i, sz;
|
||||
struct manpage *res;
|
||||
struct manpaths paths;
|
||||
size_t terms, ressz;
|
||||
struct opts opts;
|
||||
struct expr *e;
|
||||
char *defpaths, *auxpaths;
|
||||
char *conf_file;
|
||||
char *progname;
|
||||
const char *outkey;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
@ -58,30 +56,31 @@ main(int argc, char *argv[])
|
||||
whatis = (0 == strncmp(progname, "whatis", 6));
|
||||
|
||||
memset(&paths, 0, sizeof(struct manpaths));
|
||||
memset(&opts, 0, sizeof(struct opts));
|
||||
memset(&search, 0, sizeof(struct mansearch));
|
||||
|
||||
ressz = 0;
|
||||
res = NULL;
|
||||
auxpaths = defpaths = NULL;
|
||||
conf_file = NULL;
|
||||
e = NULL;
|
||||
outkey = "Nd";
|
||||
|
||||
while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
|
||||
while (-1 != (ch = getopt(argc, argv, "C:M:m:O:S:s:")))
|
||||
switch (ch) {
|
||||
case ('C'):
|
||||
case 'C':
|
||||
conf_file = optarg;
|
||||
break;
|
||||
case ('M'):
|
||||
case 'M':
|
||||
defpaths = optarg;
|
||||
break;
|
||||
case ('m'):
|
||||
case 'm':
|
||||
auxpaths = optarg;
|
||||
break;
|
||||
case ('S'):
|
||||
opts.arch = optarg;
|
||||
case 'O':
|
||||
outkey = optarg;
|
||||
break;
|
||||
case ('s'):
|
||||
opts.cat = optarg;
|
||||
case 'S':
|
||||
search.arch = optarg;
|
||||
break;
|
||||
case 's':
|
||||
search.sec = optarg;
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
@ -93,64 +92,32 @@ main(int argc, char *argv[])
|
||||
if (0 == argc)
|
||||
goto usage;
|
||||
|
||||
rc = 0;
|
||||
search.deftype = whatis ? TYPE_Nm : TYPE_Nm | TYPE_Nd;
|
||||
search.flags = whatis ? MANSEARCH_WHATIS : 0;
|
||||
|
||||
manpath_parse(&paths, conf_file, defpaths, auxpaths);
|
||||
|
||||
e = whatis ? termcomp(argc, argv, &terms) :
|
||||
exprcomp(argc, argv, &terms);
|
||||
|
||||
if (NULL == e) {
|
||||
fprintf(stderr, "%s: Bad expression\n", progname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = apropos_search
|
||||
(paths.sz, paths.paths, &opts,
|
||||
e, terms, NULL, &ressz, &res, list);
|
||||
|
||||
if (0 == rc) {
|
||||
fprintf(stderr, "%s: Bad database\n", progname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mansearch_setup(1);
|
||||
ch = mansearch(&search, &paths, argc, argv, outkey, &res, &sz);
|
||||
manpath_free(&paths);
|
||||
resfree(res, ressz);
|
||||
exprfree(e);
|
||||
return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
list(struct res *res, size_t sz, void *arg)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
qsort(res, sz, sizeof(struct res), cmp);
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
if ( ! res[i].matched)
|
||||
continue;
|
||||
printf("%s(%s%s%s) - %.70s\n",
|
||||
res[i].title,
|
||||
res[i].cat,
|
||||
*res[i].arch ? "/" : "",
|
||||
*res[i].arch ? res[i].arch : "",
|
||||
res[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmp(const void *p1, const void *p2)
|
||||
{
|
||||
|
||||
return(strcasecmp(((const struct res *)p1)->title,
|
||||
((const struct res *)p2)->title));
|
||||
}
|
||||
|
884
apropos_db.c
884
apropos_db.c
@ -1,884 +0,0 @@
|
||||
/* $Id: apropos_db.c,v 1.32.2.3 2013/10/10 23:43:04 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <libkern/OSByteOrder.h>
|
||||
#elif defined(__linux__)
|
||||
# include <endian.h>
|
||||
#elif defined(__sun)
|
||||
# include <sys/byteorder.h>
|
||||
#else
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__sun)
|
||||
# include <db_185.h>
|
||||
#else
|
||||
# include <db.h>
|
||||
#endif
|
||||
|
||||
#include "mandocdb.h"
|
||||
#include "apropos_db.h"
|
||||
#include "mandoc.h"
|
||||
|
||||
#define RESFREE(_x) \
|
||||
do { \
|
||||
free((_x)->file); \
|
||||
free((_x)->cat); \
|
||||
free((_x)->title); \
|
||||
free((_x)->arch); \
|
||||
free((_x)->desc); \
|
||||
free((_x)->matches); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
struct expr {
|
||||
int regex; /* is regex? */
|
||||
int index; /* index in match array */
|
||||
uint64_t mask; /* type-mask */
|
||||
int and; /* is rhs of logical AND? */
|
||||
char *v; /* search value */
|
||||
regex_t re; /* compiled re, if regex */
|
||||
struct expr *next; /* next in sequence */
|
||||
struct expr *subexpr;
|
||||
};
|
||||
|
||||
struct type {
|
||||
uint64_t mask;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct rectree {
|
||||
struct res *node; /* record array for dir tree */
|
||||
int len; /* length of record array */
|
||||
};
|
||||
|
||||
static const struct type types[] = {
|
||||
{ TYPE_An, "An" },
|
||||
{ TYPE_Ar, "Ar" },
|
||||
{ TYPE_At, "At" },
|
||||
{ TYPE_Bsx, "Bsx" },
|
||||
{ TYPE_Bx, "Bx" },
|
||||
{ TYPE_Cd, "Cd" },
|
||||
{ TYPE_Cm, "Cm" },
|
||||
{ TYPE_Dv, "Dv" },
|
||||
{ TYPE_Dx, "Dx" },
|
||||
{ TYPE_Em, "Em" },
|
||||
{ TYPE_Er, "Er" },
|
||||
{ TYPE_Ev, "Ev" },
|
||||
{ TYPE_Fa, "Fa" },
|
||||
{ TYPE_Fl, "Fl" },
|
||||
{ TYPE_Fn, "Fn" },
|
||||
{ TYPE_Fn, "Fo" },
|
||||
{ TYPE_Ft, "Ft" },
|
||||
{ TYPE_Fx, "Fx" },
|
||||
{ TYPE_Ic, "Ic" },
|
||||
{ TYPE_In, "In" },
|
||||
{ TYPE_Lb, "Lb" },
|
||||
{ TYPE_Li, "Li" },
|
||||
{ TYPE_Lk, "Lk" },
|
||||
{ TYPE_Ms, "Ms" },
|
||||
{ TYPE_Mt, "Mt" },
|
||||
{ TYPE_Nd, "Nd" },
|
||||
{ TYPE_Nm, "Nm" },
|
||||
{ TYPE_Nx, "Nx" },
|
||||
{ TYPE_Ox, "Ox" },
|
||||
{ TYPE_Pa, "Pa" },
|
||||
{ TYPE_Rs, "Rs" },
|
||||
{ TYPE_Sh, "Sh" },
|
||||
{ TYPE_Ss, "Ss" },
|
||||
{ TYPE_St, "St" },
|
||||
{ TYPE_Sy, "Sy" },
|
||||
{ TYPE_Tn, "Tn" },
|
||||
{ TYPE_Va, "Va" },
|
||||
{ TYPE_Va, "Vt" },
|
||||
{ TYPE_Xr, "Xr" },
|
||||
{ UINT64_MAX, "any" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static DB *btree_open(void);
|
||||
static int btree_read(const DBT *, const DBT *,
|
||||
const struct mchars *,
|
||||
uint64_t *, recno_t *, char **);
|
||||
static int expreval(const struct expr *, int *);
|
||||
static void exprexec(const struct expr *,
|
||||
const char *, uint64_t, struct res *);
|
||||
static int exprmark(const struct expr *,
|
||||
const char *, uint64_t, int *);
|
||||
static struct expr *exprexpr(int, char *[], int *, int *, size_t *);
|
||||
static struct expr *exprterm(char *, int);
|
||||
static DB *index_open(void);
|
||||
static int index_read(const DBT *, const DBT *, int,
|
||||
const struct mchars *, struct res *);
|
||||
static void norm_string(const char *,
|
||||
const struct mchars *, char **);
|
||||
static size_t norm_utf8(unsigned int, char[7]);
|
||||
static int single_search(struct rectree *, const struct opts *,
|
||||
const struct expr *, size_t terms,
|
||||
struct mchars *, int);
|
||||
|
||||
/*
|
||||
* Open the keyword mandoc-db database.
|
||||
*/
|
||||
static DB *
|
||||
btree_open(void)
|
||||
{
|
||||
BTREEINFO info;
|
||||
DB *db;
|
||||
|
||||
memset(&info, 0, sizeof(BTREEINFO));
|
||||
info.lorder = 4321;
|
||||
info.flags = R_DUP;
|
||||
|
||||
db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info);
|
||||
if (NULL != db)
|
||||
return(db);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a keyword from the database and normalise it.
|
||||
* Return 0 if the database is insane, else 1.
|
||||
*/
|
||||
static int
|
||||
btree_read(const DBT *k, const DBT *v, const struct mchars *mc,
|
||||
uint64_t *mask, recno_t *rec, char **buf)
|
||||
{
|
||||
uint64_t vbuf[2];
|
||||
|
||||
/* Are our sizes sane? */
|
||||
if (k->size < 2 || sizeof(vbuf) != v->size)
|
||||
return(0);
|
||||
|
||||
/* Is our string nil-terminated? */
|
||||
if ('\0' != ((const char *)k->data)[(int)k->size - 1])
|
||||
return(0);
|
||||
|
||||
norm_string((const char *)k->data, mc, buf);
|
||||
memcpy(vbuf, v->data, v->size);
|
||||
*mask = betoh64(vbuf[0]);
|
||||
*rec = betoh64(vbuf[1]);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a Unicode codepoint and produce its UTF-8 encoding.
|
||||
* This isn't the best way to do this, but it works.
|
||||
* The magic numbers are from the UTF-8 packaging.
|
||||
* They're not as scary as they seem: read the UTF-8 spec for details.
|
||||
*/
|
||||
static size_t
|
||||
norm_utf8(unsigned int cp, char out[7])
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = 0;
|
||||
|
||||
if (cp <= 0x0000007F) {
|
||||
rc = 1;
|
||||
out[0] = (char)cp;
|
||||
} else if (cp <= 0x000007FF) {
|
||||
rc = 2;
|
||||
out[0] = (cp >> 6 & 31) | 192;
|
||||
out[1] = (cp & 63) | 128;
|
||||
} else if (cp <= 0x0000FFFF) {
|
||||
rc = 3;
|
||||
out[0] = (cp >> 12 & 15) | 224;
|
||||
out[1] = (cp >> 6 & 63) | 128;
|
||||
out[2] = (cp & 63) | 128;
|
||||
} else if (cp <= 0x001FFFFF) {
|
||||
rc = 4;
|
||||
out[0] = (cp >> 18 & 7) | 240;
|
||||
out[1] = (cp >> 12 & 63) | 128;
|
||||
out[2] = (cp >> 6 & 63) | 128;
|
||||
out[3] = (cp & 63) | 128;
|
||||
} else if (cp <= 0x03FFFFFF) {
|
||||
rc = 5;
|
||||
out[0] = (cp >> 24 & 3) | 248;
|
||||
out[1] = (cp >> 18 & 63) | 128;
|
||||
out[2] = (cp >> 12 & 63) | 128;
|
||||
out[3] = (cp >> 6 & 63) | 128;
|
||||
out[4] = (cp & 63) | 128;
|
||||
} else if (cp <= 0x7FFFFFFF) {
|
||||
rc = 6;
|
||||
out[0] = (cp >> 30 & 1) | 252;
|
||||
out[1] = (cp >> 24 & 63) | 128;
|
||||
out[2] = (cp >> 18 & 63) | 128;
|
||||
out[3] = (cp >> 12 & 63) | 128;
|
||||
out[4] = (cp >> 6 & 63) | 128;
|
||||
out[5] = (cp & 63) | 128;
|
||||
} else
|
||||
return(0);
|
||||
|
||||
out[rc] = '\0';
|
||||
return((size_t)rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalise strings from the index and database.
|
||||
* These strings are escaped as defined by mandoc_char(7) along with
|
||||
* other goop in mandoc.h (e.g., soft hyphens).
|
||||
* This function normalises these into a nice UTF-8 string.
|
||||
* Returns 0 if the database is fucked.
|
||||
*/
|
||||
static void
|
||||
norm_string(const char *val, const struct mchars *mc, char **buf)
|
||||
{
|
||||
size_t sz, bsz;
|
||||
char utfbuf[7];
|
||||
const char *seq, *cpp;
|
||||
int len, u, pos;
|
||||
enum mandoc_esc esc;
|
||||
static const char res[] = { '\\', '\t',
|
||||
ASCII_NBRSP, ASCII_HYPH, '\0' };
|
||||
|
||||
/* Pre-allocate by the length of the input */
|
||||
|
||||
bsz = strlen(val) + 1;
|
||||
*buf = mandoc_realloc(*buf, bsz);
|
||||
pos = 0;
|
||||
|
||||
while ('\0' != *val) {
|
||||
/*
|
||||
* Halt on the first escape sequence.
|
||||
* This also halts on the end of string, in which case
|
||||
* we just copy, fallthrough, and exit the loop.
|
||||
*/
|
||||
if ((sz = strcspn(val, res)) > 0) {
|
||||
memcpy(&(*buf)[pos], val, sz);
|
||||
pos += (int)sz;
|
||||
val += (int)sz;
|
||||
}
|
||||
|
||||
if (ASCII_HYPH == *val) {
|
||||
(*buf)[pos++] = '-';
|
||||
val++;
|
||||
continue;
|
||||
} else if ('\t' == *val || ASCII_NBRSP == *val) {
|
||||
(*buf)[pos++] = ' ';
|
||||
val++;
|
||||
continue;
|
||||
} else if ('\\' != *val)
|
||||
break;
|
||||
|
||||
/* Read past the slash. */
|
||||
|
||||
val++;
|
||||
u = 0;
|
||||
|
||||
/*
|
||||
* Parse the escape sequence and see if it's a
|
||||
* predefined character or special character.
|
||||
*/
|
||||
|
||||
esc = mandoc_escape(&val, &seq, &len);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
break;
|
||||
|
||||
/*
|
||||
* XXX - this just does UTF-8, but we need to know
|
||||
* beforehand whether we should do text substitution.
|
||||
*/
|
||||
|
||||
switch (esc) {
|
||||
case (ESCAPE_SPECIAL):
|
||||
if (0 != (u = mchars_spec2cp(mc, seq, len)))
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a Unicode codepoint, try to convert that
|
||||
* to a UTF-8 byte string.
|
||||
*/
|
||||
|
||||
cpp = utfbuf;
|
||||
if (0 == (sz = norm_utf8(u, utfbuf)))
|
||||
continue;
|
||||
|
||||
/* Copy the rendered glyph into the stream. */
|
||||
|
||||
sz = strlen(cpp);
|
||||
bsz += sz;
|
||||
|
||||
*buf = mandoc_realloc(*buf, bsz);
|
||||
|
||||
memcpy(&(*buf)[pos], cpp, sz);
|
||||
pos += (int)sz;
|
||||
}
|
||||
|
||||
(*buf)[pos] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the filename-index mandoc-db database.
|
||||
* Returns NULL if opening failed.
|
||||
*/
|
||||
static DB *
|
||||
index_open(void)
|
||||
{
|
||||
DB *db;
|
||||
|
||||
db = dbopen(MANDOC_IDX, O_RDONLY, 0, DB_RECNO, NULL);
|
||||
if (NULL != db)
|
||||
return(db);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Safely unpack from an index file record into the structure.
|
||||
* Returns 1 if an entry was unpacked, 0 if the database is insane.
|
||||
*/
|
||||
static int
|
||||
index_read(const DBT *key, const DBT *val, int index,
|
||||
const struct mchars *mc, struct res *rec)
|
||||
{
|
||||
size_t left;
|
||||
char *np, *cp;
|
||||
char type;
|
||||
|
||||
#define INDEX_BREAD(_dst) \
|
||||
do { \
|
||||
if (NULL == (np = memchr(cp, '\0', left))) \
|
||||
return(0); \
|
||||
norm_string(cp, mc, &(_dst)); \
|
||||
left -= (np - cp) + 1; \
|
||||
cp = np + 1; \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
if (0 == (left = val->size))
|
||||
return(0);
|
||||
|
||||
cp = val->data;
|
||||
assert(sizeof(recno_t) == key->size);
|
||||
memcpy(&rec->rec, key->data, key->size);
|
||||
rec->volume = index;
|
||||
|
||||
if ('d' == (type = *cp++))
|
||||
rec->type = RESTYPE_MDOC;
|
||||
else if ('a' == type)
|
||||
rec->type = RESTYPE_MAN;
|
||||
else if ('c' == type)
|
||||
rec->type = RESTYPE_CAT;
|
||||
else
|
||||
return(0);
|
||||
|
||||
left--;
|
||||
INDEX_BREAD(rec->file);
|
||||
INDEX_BREAD(rec->cat);
|
||||
INDEX_BREAD(rec->title);
|
||||
INDEX_BREAD(rec->arch);
|
||||
INDEX_BREAD(rec->desc);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search mandocdb databases in paths for expression "expr".
|
||||
* Filter out by "opts".
|
||||
* Call "res" with the results, which may be zero.
|
||||
* Return 0 if there was a database error, else return 1.
|
||||
*/
|
||||
int
|
||||
apropos_search(int pathsz, char **paths, const struct opts *opts,
|
||||
const struct expr *expr, size_t terms, void *arg,
|
||||
size_t *sz, struct res **resp,
|
||||
void (*res)(struct res *, size_t, void *))
|
||||
{
|
||||
struct rectree tree;
|
||||
struct mchars *mc;
|
||||
int i;
|
||||
|
||||
memset(&tree, 0, sizeof(struct rectree));
|
||||
|
||||
mc = mchars_alloc();
|
||||
*sz = 0;
|
||||
*resp = NULL;
|
||||
|
||||
/*
|
||||
* Main loop. Change into the directory containing manpage
|
||||
* databases. Run our expession over each database in the set.
|
||||
*/
|
||||
|
||||
for (i = 0; i < pathsz; i++) {
|
||||
assert('/' == paths[i][0]);
|
||||
if (chdir(paths[i]))
|
||||
continue;
|
||||
if (single_search(&tree, opts, expr, terms, mc, i))
|
||||
continue;
|
||||
|
||||
resfree(tree.node, tree.len);
|
||||
mchars_free(mc);
|
||||
return(0);
|
||||
}
|
||||
|
||||
(*res)(tree.node, tree.len, arg);
|
||||
*sz = tree.len;
|
||||
*resp = tree.node;
|
||||
mchars_free(mc);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
single_search(struct rectree *tree, const struct opts *opts,
|
||||
const struct expr *expr, size_t terms,
|
||||
struct mchars *mc, int vol)
|
||||
{
|
||||
int root, leaf, ch;
|
||||
DBT key, val;
|
||||
DB *btree, *idx;
|
||||
char *buf;
|
||||
struct res *rs;
|
||||
struct res r;
|
||||
uint64_t mask;
|
||||
recno_t rec;
|
||||
|
||||
root = -1;
|
||||
leaf = -1;
|
||||
btree = NULL;
|
||||
idx = NULL;
|
||||
buf = NULL;
|
||||
rs = tree->node;
|
||||
|
||||
memset(&r, 0, sizeof(struct res));
|
||||
|
||||
if (NULL == (btree = btree_open()))
|
||||
return(1);
|
||||
|
||||
if (NULL == (idx = index_open())) {
|
||||
(*btree->close)(btree);
|
||||
return(1);
|
||||
}
|
||||
|
||||
while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
|
||||
if ( ! btree_read(&key, &val, mc, &mask, &rec, &buf))
|
||||
break;
|
||||
|
||||
/*
|
||||
* See if this keyword record matches any of the
|
||||
* expressions we have stored.
|
||||
*/
|
||||
if ( ! exprmark(expr, buf, mask, NULL))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* O(log n) scan for prior records. Since a record
|
||||
* number is unbounded, this has decent performance over
|
||||
* a complex hash function.
|
||||
*/
|
||||
|
||||
for (leaf = root; leaf >= 0; )
|
||||
if (rec > rs[leaf].rec &&
|
||||
rs[leaf].rhs >= 0)
|
||||
leaf = rs[leaf].rhs;
|
||||
else if (rec < rs[leaf].rec &&
|
||||
rs[leaf].lhs >= 0)
|
||||
leaf = rs[leaf].lhs;
|
||||
else
|
||||
break;
|
||||
|
||||
/*
|
||||
* If we find a record, see if it has already evaluated
|
||||
* to true. If it has, great, just keep going. If not,
|
||||
* try to evaluate it now and continue anyway.
|
||||
*/
|
||||
|
||||
if (leaf >= 0 && rs[leaf].rec == rec) {
|
||||
if (0 == rs[leaf].matched)
|
||||
exprexec(expr, buf, mask, &rs[leaf]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a new file to examine.
|
||||
* Extract the manpage's metadata from the index
|
||||
* database, then begin partial evaluation.
|
||||
*/
|
||||
|
||||
key.data = &rec;
|
||||
key.size = sizeof(recno_t);
|
||||
|
||||
if (0 != (*idx->get)(idx, &key, &val, 0))
|
||||
break;
|
||||
|
||||
r.lhs = r.rhs = -1;
|
||||
if ( ! index_read(&key, &val, vol, mc, &r))
|
||||
break;
|
||||
|
||||
/* XXX: this should be elsewhere, I guess? */
|
||||
|
||||
if (opts->cat && strcasecmp(opts->cat, r.cat))
|
||||
continue;
|
||||
|
||||
if (opts->arch && *r.arch)
|
||||
if (strcasecmp(opts->arch, r.arch))
|
||||
continue;
|
||||
|
||||
tree->node = rs = mandoc_realloc
|
||||
(rs, (tree->len + 1) * sizeof(struct res));
|
||||
|
||||
memcpy(&rs[tree->len], &r, sizeof(struct res));
|
||||
memset(&r, 0, sizeof(struct res));
|
||||
rs[tree->len].matches =
|
||||
mandoc_calloc(terms, sizeof(int));
|
||||
|
||||
exprexec(expr, buf, mask, &rs[tree->len]);
|
||||
|
||||
/* Append to our tree. */
|
||||
|
||||
if (leaf >= 0) {
|
||||
if (rec > rs[leaf].rec)
|
||||
rs[leaf].rhs = tree->len;
|
||||
else
|
||||
rs[leaf].lhs = tree->len;
|
||||
} else
|
||||
root = tree->len;
|
||||
|
||||
tree->len++;
|
||||
}
|
||||
|
||||
(*btree->close)(btree);
|
||||
(*idx->close)(idx);
|
||||
|
||||
free(buf);
|
||||
RESFREE(&r);
|
||||
return(1 == ch);
|
||||
}
|
||||
|
||||
void
|
||||
resfree(struct res *rec, size_t sz)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
RESFREE(&rec[i]);
|
||||
free(rec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile a list of straight-up terms.
|
||||
* The arguments are re-written into ~[[:<:]]term[[:>:]], or "term"
|
||||
* surrounded by word boundaries, then pumped through exprterm().
|
||||
* Terms are case-insensitive.
|
||||
* This emulates whatis(1) behaviour.
|
||||
*/
|
||||
struct expr *
|
||||
termcomp(int argc, char *argv[], size_t *tt)
|
||||
{
|
||||
char *buf;
|
||||
int pos;
|
||||
struct expr *e, *next;
|
||||
size_t sz;
|
||||
|
||||
buf = NULL;
|
||||
e = NULL;
|
||||
*tt = 0;
|
||||
|
||||
for (pos = argc - 1; pos >= 0; pos--) {
|
||||
sz = strlen(argv[pos]) + 18;
|
||||
buf = mandoc_realloc(buf, sz);
|
||||
strlcpy(buf, "Nm~[[:<:]]", sz);
|
||||
strlcat(buf, argv[pos], sz);
|
||||
strlcat(buf, "[[:>:]]", sz);
|
||||
if (NULL == (next = exprterm(buf, 0))) {
|
||||
free(buf);
|
||||
exprfree(e);
|
||||
return(NULL);
|
||||
}
|
||||
next->next = e;
|
||||
e = next;
|
||||
(*tt)++;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile a sequence of logical expressions.
|
||||
* See apropos.1 for a grammar of this sequence.
|
||||
*/
|
||||
struct expr *
|
||||
exprcomp(int argc, char *argv[], size_t *tt)
|
||||
{
|
||||
int pos, lvl;
|
||||
struct expr *e;
|
||||
|
||||
pos = lvl = 0;
|
||||
*tt = 0;
|
||||
|
||||
e = exprexpr(argc, argv, &pos, &lvl, tt);
|
||||
|
||||
if (0 == lvl && pos >= argc)
|
||||
return(e);
|
||||
|
||||
exprfree(e);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile an array of tokens into an expression.
|
||||
* An informal expression grammar is defined in apropos(1).
|
||||
* Return NULL if we fail doing so. All memory will be cleaned up.
|
||||
* Return the root of the expression sequence if alright.
|
||||
*/
|
||||
static struct expr *
|
||||
exprexpr(int argc, char *argv[], int *pos, int *lvl, size_t *tt)
|
||||
{
|
||||
struct expr *e, *first, *next;
|
||||
int log;
|
||||
|
||||
first = next = NULL;
|
||||
|
||||
for ( ; *pos < argc; (*pos)++) {
|
||||
e = next;
|
||||
|
||||
/*
|
||||
* Close out a subexpression.
|
||||
*/
|
||||
|
||||
if (NULL != e && 0 == strcmp(")", argv[*pos])) {
|
||||
if (--(*lvl) < 0)
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Small note: if we're just starting, don't let "-a"
|
||||
* and "-o" be considered logical operators: they're
|
||||
* just tokens unless pairwise joining, in which case we
|
||||
* record their existence (or assume "OR").
|
||||
*/
|
||||
log = 0;
|
||||
|
||||
if (NULL != e && 0 == strcmp("-a", argv[*pos]))
|
||||
log = 1;
|
||||
else if (NULL != e && 0 == strcmp("-o", argv[*pos]))
|
||||
log = 2;
|
||||
|
||||
if (log > 0 && ++(*pos) >= argc)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Now we parse the term part. This can begin with
|
||||
* "-i", in which case the expression is case
|
||||
* insensitive.
|
||||
*/
|
||||
|
||||
if (0 == strcmp("(", argv[*pos])) {
|
||||
++(*pos);
|
||||
++(*lvl);
|
||||
next = mandoc_calloc(1, sizeof(struct expr));
|
||||
next->subexpr = exprexpr(argc, argv, pos, lvl, tt);
|
||||
if (NULL == next->subexpr) {
|
||||
free(next);
|
||||
next = NULL;
|
||||
}
|
||||
} else if (0 == strcmp("-i", argv[*pos])) {
|
||||
if (++(*pos) >= argc)
|
||||
goto err;
|
||||
next = exprterm(argv[*pos], 0);
|
||||
} else
|
||||
next = exprterm(argv[*pos], 1);
|
||||
|
||||
if (NULL == next)
|
||||
goto err;
|
||||
|
||||
next->and = log == 1;
|
||||
next->index = (int)(*tt)++;
|
||||
|
||||
/* Append to our chain of expressions. */
|
||||
|
||||
if (NULL == first) {
|
||||
assert(NULL == e);
|
||||
first = next;
|
||||
} else {
|
||||
assert(NULL != e);
|
||||
e->next = next;
|
||||
}
|
||||
}
|
||||
|
||||
return(first);
|
||||
err:
|
||||
exprfree(first);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a terminal expression with the grammar as defined in
|
||||
* apropos(1).
|
||||
* Return NULL if we fail the parse.
|
||||
*/
|
||||
static struct expr *
|
||||
exprterm(char *buf, int cs)
|
||||
{
|
||||
struct expr e;
|
||||
struct expr *p;
|
||||
char *key;
|
||||
int i;
|
||||
|
||||
memset(&e, 0, sizeof(struct expr));
|
||||
|
||||
/* Choose regex or substring match. */
|
||||
|
||||
if (NULL == (e.v = strpbrk(buf, "=~"))) {
|
||||
e.regex = 0;
|
||||
e.v = buf;
|
||||
} else {
|
||||
e.regex = '~' == *e.v;
|
||||
*e.v++ = '\0';
|
||||
}
|
||||
|
||||
/* Determine the record types to search for. */
|
||||
|
||||
e.mask = 0;
|
||||
if (buf < e.v) {
|
||||
while (NULL != (key = strsep(&buf, ","))) {
|
||||
i = 0;
|
||||
while (types[i].mask &&
|
||||
strcmp(types[i].name, key))
|
||||
i++;
|
||||
e.mask |= types[i].mask;
|
||||
}
|
||||
}
|
||||
if (0 == e.mask)
|
||||
e.mask = TYPE_Nm | TYPE_Nd;
|
||||
|
||||
if (e.regex) {
|
||||
i = REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE);
|
||||
if (regcomp(&e.re, e.v, i))
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
e.v = mandoc_strdup(e.v);
|
||||
|
||||
p = mandoc_calloc(1, sizeof(struct expr));
|
||||
memcpy(p, &e, sizeof(struct expr));
|
||||
return(p);
|
||||
}
|
||||
|
||||
void
|
||||
exprfree(struct expr *p)
|
||||
{
|
||||
struct expr *pp;
|
||||
|
||||
while (NULL != p) {
|
||||
if (p->subexpr)
|
||||
exprfree(p->subexpr);
|
||||
if (p->regex)
|
||||
regfree(&p->re);
|
||||
free(p->v);
|
||||
pp = p->next;
|
||||
free(p);
|
||||
p = pp;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
exprmark(const struct expr *p, const char *cp,
|
||||
uint64_t mask, int *ms)
|
||||
{
|
||||
|
||||
for ( ; p; p = p->next) {
|
||||
if (p->subexpr) {
|
||||
if (exprmark(p->subexpr, cp, mask, ms))
|
||||
return(1);
|
||||
continue;
|
||||
} else if ( ! (mask & p->mask))
|
||||
continue;
|
||||
|
||||
if (p->regex) {
|
||||
if (regexec(&p->re, cp, 0, NULL, 0))
|
||||
continue;
|
||||
} else if (NULL == strcasestr(cp, p->v))
|
||||
continue;
|
||||
|
||||
if (NULL == ms)
|
||||
return(1);
|
||||
else
|
||||
ms[p->index] = 1;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
expreval(const struct expr *p, int *ms)
|
||||
{
|
||||
int match;
|
||||
|
||||
/*
|
||||
* AND has precedence over OR. Analysis is left-right, though
|
||||
* it doesn't matter because there are no side-effects.
|
||||
* Thus, step through pairwise ANDs and accumulate their Boolean
|
||||
* evaluation. If we encounter a single true AND collection or
|
||||
* standalone term, the whole expression is true (by definition
|
||||
* of OR).
|
||||
*/
|
||||
|
||||
for (match = 0; p && ! match; p = p->next) {
|
||||
/* Evaluate a subexpression, if applicable. */
|
||||
if (p->subexpr && ! ms[p->index])
|
||||
ms[p->index] = expreval(p->subexpr, ms);
|
||||
|
||||
match = ms[p->index];
|
||||
for ( ; p->next && p->next->and; p = p->next) {
|
||||
/* Evaluate a subexpression, if applicable. */
|
||||
if (p->next->subexpr && ! ms[p->next->index])
|
||||
ms[p->next->index] =
|
||||
expreval(p->next->subexpr, ms);
|
||||
match = match && ms[p->next->index];
|
||||
}
|
||||
}
|
||||
|
||||
return(match);
|
||||
}
|
||||
|
||||
/*
|
||||
* First, update the array of terms for which this expression evaluates
|
||||
* to true.
|
||||
* Second, logically evaluate all terms over the updated array of truth
|
||||
* values.
|
||||
* If this evaluates to true, mark the expression as satisfied.
|
||||
*/
|
||||
static void
|
||||
exprexec(const struct expr *e, const char *cp,
|
||||
uint64_t mask, struct res *r)
|
||||
{
|
||||
|
||||
assert(0 == r->matched);
|
||||
exprmark(e, cp, mask, r->matches);
|
||||
r->matched = expreval(e, r->matches);
|
||||
}
|
73
apropos_db.h
73
apropos_db.h
@ -1,73 +0,0 @@
|
||||
/* $Id: apropos_db.h,v 1.13 2012/03/24 01:46:25 kristaps Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef APROPOS_H
|
||||
#define APROPOS_H
|
||||
|
||||
enum restype {
|
||||
RESTYPE_MAN, /* man(7) file */
|
||||
RESTYPE_MDOC, /* mdoc(7) file */
|
||||
RESTYPE_CAT /* pre-formatted file */
|
||||
};
|
||||
|
||||
struct res {
|
||||
enum restype type; /* input file type */
|
||||
char *file; /* file in file-system */
|
||||
char *cat; /* category (3p, 3, etc.) */
|
||||
char *title; /* title (FOO, etc.) */
|
||||
char *arch; /* arch (or empty string) */
|
||||
char *desc; /* description (from Nd) */
|
||||
unsigned int rec; /* record in index */
|
||||
/*
|
||||
* The index volume. This indexes into the array of directories
|
||||
* searched for manual page databases.
|
||||
*/
|
||||
unsigned int volume;
|
||||
/*
|
||||
* The following fields are used internally.
|
||||
*
|
||||
* Maintain a binary tree for checking the uniqueness of `rec'
|
||||
* when adding elements to the results array.
|
||||
* Since the results array is dynamic, use offset in the array
|
||||
* instead of a pointer to the structure.
|
||||
*/
|
||||
int lhs;
|
||||
int rhs;
|
||||
int matched; /* expression is true */
|
||||
int *matches; /* partial truth evaluations */
|
||||
};
|
||||
|
||||
struct opts {
|
||||
const char *arch; /* restrict to architecture */
|
||||
const char *cat; /* restrict to manual section */
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct expr;
|
||||
|
||||
int apropos_search(int, char **, const struct opts *,
|
||||
const struct expr *, size_t,
|
||||
void *, size_t *, struct res **,
|
||||
void (*)(struct res *, size_t, void *));
|
||||
struct expr *exprcomp(int, char *[], size_t *);
|
||||
void exprfree(struct expr *);
|
||||
void resfree(struct res *, size_t);
|
||||
struct expr *termcomp(int, char *[], size_t *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /*!APROPOS_H*/
|
8
arch.c
8
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);
|
||||
}
|
||||
|
6
arch.in
6
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")
|
||||
|
8
att.c
8
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);
|
||||
}
|
||||
|
111
catman.8
111
catman.8
@ -1,111 +0,0 @@
|
||||
.\" $Id: catman.8,v 1.5 2011/12/25 19:35:44 kristaps Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: December 25 2011 $
|
||||
.Dt CATMAN 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm catman
|
||||
.Nd update a man.cgi manpage cache
|
||||
.Sh SYNOPSIS
|
||||
.Nm catman
|
||||
.Op Fl fv
|
||||
.Op Fl C Ar file
|
||||
.Op Fl M Ar manpath
|
||||
.Op Fl m Ar manpath
|
||||
.Op Fl o Ar path
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility updates cached manpages for a jailed
|
||||
.Xr man.cgi 7 .
|
||||
.Pp
|
||||
By default,
|
||||
.Nm
|
||||
searches for
|
||||
.Xr mandocdb 8
|
||||
databases in the default paths stipulated by
|
||||
.Xr man 1
|
||||
and updates the cache in
|
||||
.Pa /var/www/cache/man.cgi .
|
||||
.Pp
|
||||
Its arguments are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl f
|
||||
Force an update to all files.
|
||||
.It Fl v
|
||||
Print each file being updated.
|
||||
.It Fl C Ar file
|
||||
Specify an alternative configuration
|
||||
.Ar file
|
||||
in
|
||||
.Xr man.conf 5
|
||||
format.
|
||||
.It Fl M Ar manpath
|
||||
Use the colon-separated path instead of the default list of paths
|
||||
searched for
|
||||
.Xr mandocdb 8
|
||||
databases.
|
||||
Invalid paths, or paths without manual databases, are ignored.
|
||||
.It Fl m Ar manpath
|
||||
Prepend the colon-separated paths to the list of paths searched
|
||||
for
|
||||
.Xr mandocdb 8
|
||||
databases.
|
||||
Invalid paths, or paths without manual databases, are ignored.
|
||||
.It Fl o Ar path
|
||||
Update into the directory tree under
|
||||
.Ar path .
|
||||
.El
|
||||
.Pp
|
||||
Cache updates occur when a
|
||||
.Xr mandocdb 8
|
||||
database is older than the cached copy unless
|
||||
.Fl f
|
||||
is specified, in which case files are always considered out of date.
|
||||
Cached manual pages are only updated if older than the master copy.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Ds
|
||||
.It Ev MANPATH
|
||||
Colon-separated paths modifying the default list of paths searched for
|
||||
manual databases.
|
||||
Invalid paths, or paths without manual databases, are ignored.
|
||||
Overridden by
|
||||
.Fl M .
|
||||
If
|
||||
.Ev MANPATH
|
||||
begins with a
|
||||
.Sq \&: ,
|
||||
it is appended to the default list;
|
||||
else if it ends with
|
||||
.Sq \&: ,
|
||||
it is prepended to the default list; else if it contains
|
||||
.Sq \&:: ,
|
||||
the default list is inserted between the colons.
|
||||
If none of these conditions are met, it overrides the default list.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr mandoc 1 ,
|
||||
.Xr man.cgi 7 ,
|
||||
.Xr mandocdb 8
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
509
catman.c
509
catman.c
@ -1,509 +0,0 @@
|
||||
/* $Id: catman.c,v 1.11.2.2 2013/10/11 00:06:48 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(__linux__) || defined(__sun)
|
||||
# include <db_185.h>
|
||||
#else
|
||||
# include <db.h>
|
||||
#endif
|
||||
|
||||
#include "manpath.h"
|
||||
#include "mandocdb.h"
|
||||
|
||||
#define xstrlcpy(_dst, _src, _sz) \
|
||||
do if (strlcpy((_dst), (_src), (_sz)) >= (_sz)) { \
|
||||
fprintf(stderr, "%s: Path too long", (_dst)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
#define xstrlcat(_dst, _src, _sz) \
|
||||
do if (strlcat((_dst), (_src), (_sz)) >= (_sz)) { \
|
||||
fprintf(stderr, "%s: Path too long", (_dst)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
static int indexhtml(char *, size_t, char *, size_t);
|
||||
static int manup(const struct manpaths *, char *);
|
||||
static int mkpath(char *, mode_t, mode_t);
|
||||
static int treecpy(char *, char *);
|
||||
static int update(char *, char *);
|
||||
static void usage(void);
|
||||
|
||||
static const char *progname;
|
||||
static int verbose;
|
||||
static int force;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
char *aux, *base, *conf_file;
|
||||
struct manpaths dirs;
|
||||
char buf[MAXPATHLEN];
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
progname = strrchr(argv[0], '/');
|
||||
if (progname == NULL)
|
||||
progname = argv[0];
|
||||
else
|
||||
++progname;
|
||||
|
||||
aux = base = conf_file = NULL;
|
||||
xstrlcpy(buf, "/var/www/cache/man.cgi", MAXPATHLEN);
|
||||
|
||||
while (-1 != (ch = getopt(argc, argv, "C:fm:M:o:v")))
|
||||
switch (ch) {
|
||||
case ('C'):
|
||||
conf_file = optarg;
|
||||
break;
|
||||
case ('f'):
|
||||
force = 1;
|
||||
break;
|
||||
case ('m'):
|
||||
aux = optarg;
|
||||
break;
|
||||
case ('M'):
|
||||
base = optarg;
|
||||
break;
|
||||
case ('o'):
|
||||
xstrlcpy(buf, optarg, MAXPATHLEN);
|
||||
break;
|
||||
case ('v'):
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 0) {
|
||||
usage();
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(&dirs, 0, sizeof(struct manpaths));
|
||||
manpath_parse(&dirs, conf_file, base, aux);
|
||||
ch = manup(&dirs, buf);
|
||||
manpath_free(&dirs);
|
||||
return(ch ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "usage: %s "
|
||||
"[-fv] "
|
||||
"[-C file] "
|
||||
"[-o path] "
|
||||
"[-m manpath] "
|
||||
"[-M manpath]\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
/*
|
||||
* If "src" file doesn't exist (errors out), return -1. Otherwise,
|
||||
* return 1 if "src" is newer (which also happens "dst" doesn't exist)
|
||||
* and 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
isnewer(const char *dst, const char *src)
|
||||
{
|
||||
struct stat s1, s2;
|
||||
|
||||
if (-1 == stat(src, &s1))
|
||||
return(-1);
|
||||
if (force)
|
||||
return(1);
|
||||
|
||||
return(-1 == stat(dst, &s2) ? 1 : s1.st_mtime > s2.st_mtime);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the contents of one file into another.
|
||||
* Returns 0 on failure, 1 on success.
|
||||
*/
|
||||
static int
|
||||
filecpy(const char *dst, const char *src)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
int sfd, dfd, rc;
|
||||
ssize_t rsz, wsz;
|
||||
|
||||
sfd = dfd = -1;
|
||||
rc = 0;
|
||||
|
||||
if (-1 == (dfd = open(dst, O_CREAT|O_TRUNC|O_WRONLY, 0644))) {
|
||||
perror(dst);
|
||||
goto out;
|
||||
} else if (-1 == (sfd = open(src, O_RDONLY, 0))) {
|
||||
perror(src);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((rsz = read(sfd, buf, BUFSIZ)) > 0)
|
||||
if (-1 == (wsz = write(dfd, buf, (size_t)rsz))) {
|
||||
perror(dst);
|
||||
goto out;
|
||||
} else if (wsz < rsz) {
|
||||
fprintf(stderr, "%s: Short write\n", dst);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rsz < 0)
|
||||
perror(src);
|
||||
else
|
||||
rc = 1;
|
||||
out:
|
||||
if (-1 != sfd)
|
||||
close(sfd);
|
||||
if (-1 != dfd)
|
||||
close(dfd);
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass over the recno database and re-create HTML pages if they're
|
||||
* found to be out of date.
|
||||
* Returns -1 on fatal error, 1 on success.
|
||||
*/
|
||||
static int
|
||||
indexhtml(char *src, size_t ssz, char *dst, size_t dsz)
|
||||
{
|
||||
DB *idx;
|
||||
DBT key, val;
|
||||
int c, rc;
|
||||
unsigned int fl;
|
||||
const char *f;
|
||||
char *d;
|
||||
char fname[MAXPATHLEN];
|
||||
|
||||
xstrlcpy(fname, dst, MAXPATHLEN);
|
||||
xstrlcat(fname, "/", MAXPATHLEN);
|
||||
xstrlcat(fname, MANDOC_IDX, MAXPATHLEN);
|
||||
|
||||
idx = dbopen(fname, O_RDONLY, 0, DB_RECNO, NULL);
|
||||
if (NULL == idx) {
|
||||
perror(fname);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fl = R_FIRST;
|
||||
while (0 == (c = (*idx->seq)(idx, &key, &val, fl))) {
|
||||
fl = R_NEXT;
|
||||
/*
|
||||
* If the record is zero-length, then it's unassigned.
|
||||
* Skip past these.
|
||||
*/
|
||||
if (0 == val.size)
|
||||
continue;
|
||||
|
||||
f = (const char *)val.data + 1;
|
||||
if (NULL == memchr(f, '\0', val.size - 1))
|
||||
break;
|
||||
|
||||
src[(int)ssz] = dst[(int)dsz] = '\0';
|
||||
|
||||
xstrlcat(dst, "/", MAXPATHLEN);
|
||||
xstrlcat(dst, f, MAXPATHLEN);
|
||||
|
||||
xstrlcat(src, "/", MAXPATHLEN);
|
||||
xstrlcat(src, f, MAXPATHLEN);
|
||||
|
||||
if (-1 == (rc = isnewer(dst, src))) {
|
||||
fprintf(stderr, "%s: File missing\n", f);
|
||||
break;
|
||||
} else if (0 == rc)
|
||||
continue;
|
||||
|
||||
d = strrchr(dst, '/');
|
||||
assert(NULL != d);
|
||||
*d = '\0';
|
||||
|
||||
if (-1 == mkpath(dst, 0755, 0755)) {
|
||||
perror(dst);
|
||||
break;
|
||||
}
|
||||
|
||||
*d = '/';
|
||||
|
||||
if ( ! filecpy(dst, src))
|
||||
break;
|
||||
if (verbose)
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
|
||||
(*idx->close)(idx);
|
||||
|
||||
if (c < 0)
|
||||
perror(fname);
|
||||
else if (0 == c)
|
||||
fprintf(stderr, "%s: Corrupt index\n", fname);
|
||||
|
||||
return(1 == c ? 1 : -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy both recno and btree databases into the destination.
|
||||
* Call in to begin recreating HTML files.
|
||||
* Return -1 on fatal error and 1 if the update went well.
|
||||
*/
|
||||
static int
|
||||
update(char *dst, char *src)
|
||||
{
|
||||
size_t dsz, ssz;
|
||||
|
||||
dsz = strlen(dst);
|
||||
ssz = strlen(src);
|
||||
|
||||
xstrlcat(src, "/", MAXPATHLEN);
|
||||
xstrlcat(dst, "/", MAXPATHLEN);
|
||||
|
||||
xstrlcat(src, MANDOC_DB, MAXPATHLEN);
|
||||
xstrlcat(dst, MANDOC_DB, MAXPATHLEN);
|
||||
|
||||
if ( ! filecpy(dst, src))
|
||||
return(-1);
|
||||
if (verbose)
|
||||
printf("%s\n", dst);
|
||||
|
||||
dst[(int)dsz] = src[(int)ssz] = '\0';
|
||||
|
||||
xstrlcat(src, "/", MAXPATHLEN);
|
||||
xstrlcat(dst, "/", MAXPATHLEN);
|
||||
|
||||
xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
|
||||
xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);
|
||||
|
||||
if ( ! filecpy(dst, src))
|
||||
return(-1);
|
||||
if (verbose)
|
||||
printf("%s\n", dst);
|
||||
|
||||
dst[(int)dsz] = src[(int)ssz] = '\0';
|
||||
|
||||
return(indexhtml(src, ssz, dst, dsz));
|
||||
}
|
||||
|
||||
/*
|
||||
* See if btree or recno databases in the destination are out of date
|
||||
* with respect to a single manpath component.
|
||||
* Return -1 on fatal error, 0 if the source is no longer valid (and
|
||||
* shouldn't be listed), and 1 if the update went well.
|
||||
*/
|
||||
static int
|
||||
treecpy(char *dst, char *src)
|
||||
{
|
||||
size_t dsz, ssz;
|
||||
int rc;
|
||||
|
||||
dsz = strlen(dst);
|
||||
ssz = strlen(src);
|
||||
|
||||
xstrlcat(src, "/", MAXPATHLEN);
|
||||
xstrlcat(dst, "/", MAXPATHLEN);
|
||||
|
||||
xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
|
||||
xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);
|
||||
|
||||
if (-1 == (rc = isnewer(dst, src)))
|
||||
return(0);
|
||||
|
||||
dst[(int)dsz] = src[(int)ssz] = '\0';
|
||||
|
||||
if (1 == rc)
|
||||
return(update(dst, src));
|
||||
|
||||
xstrlcat(src, "/", MAXPATHLEN);
|
||||
xstrlcat(dst, "/", MAXPATHLEN);
|
||||
|
||||
xstrlcat(src, MANDOC_DB, MAXPATHLEN);
|
||||
xstrlcat(dst, MANDOC_DB, MAXPATHLEN);
|
||||
|
||||
if (-1 == (rc = isnewer(dst, src)))
|
||||
return(0);
|
||||
else if (rc == 0)
|
||||
return(1);
|
||||
|
||||
dst[(int)dsz] = src[(int)ssz] = '\0';
|
||||
|
||||
return(update(dst, src));
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the destination's file-tree with respect to changes in the
|
||||
* source manpath components.
|
||||
* "Change" is defined by an updated index or btree database.
|
||||
* Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
static int
|
||||
manup(const struct manpaths *dirs, char *base)
|
||||
{
|
||||
char dst[MAXPATHLEN],
|
||||
src[MAXPATHLEN];
|
||||
const char *path;
|
||||
size_t i;
|
||||
int c;
|
||||
size_t sz;
|
||||
FILE *f;
|
||||
|
||||
/* Create the path and file for the catman.conf file. */
|
||||
|
||||
sz = strlen(base);
|
||||
xstrlcpy(dst, base, MAXPATHLEN);
|
||||
xstrlcat(dst, "/etc", MAXPATHLEN);
|
||||
if (-1 == mkpath(dst, 0755, 0755)) {
|
||||
perror(dst);
|
||||
return(0);
|
||||
}
|
||||
|
||||
xstrlcat(dst, "/catman.conf", MAXPATHLEN);
|
||||
if (NULL == (f = fopen(dst, "w"))) {
|
||||
perror(dst);
|
||||
return(0);
|
||||
} else if (verbose)
|
||||
printf("%s\n", dst);
|
||||
|
||||
for (i = 0; i < dirs->sz; i++) {
|
||||
path = dirs->paths[i];
|
||||
dst[(int)sz] = '\0';
|
||||
xstrlcat(dst, path, MAXPATHLEN);
|
||||
if (-1 == mkpath(dst, 0755, 0755)) {
|
||||
perror(dst);
|
||||
break;
|
||||
}
|
||||
|
||||
xstrlcpy(src, path, MAXPATHLEN);
|
||||
if (-1 == (c = treecpy(dst, src)))
|
||||
break;
|
||||
else if (0 == c)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We want to use a relative path here because manpath.h
|
||||
* will realpath() when invoked with man.cgi, and we'll
|
||||
* make sure to chdir() into the cache directory before.
|
||||
*
|
||||
* This allows the cache directory to be in an arbitrary
|
||||
* place, working in both chroot() and non-chroot()
|
||||
* "safe" modes.
|
||||
*/
|
||||
assert('/' == path[0]);
|
||||
fprintf(f, "_whatdb %s/whatis.db\n", path + 1);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return(i == dirs->sz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
static int
|
||||
mkpath(char *path, mode_t mode, mode_t dir_mode)
|
||||
{
|
||||
struct stat sb;
|
||||
char *slash;
|
||||
int done, exists;
|
||||
|
||||
slash = path;
|
||||
|
||||
for (;;) {
|
||||
/* LINTED */
|
||||
slash += strspn(slash, "/");
|
||||
/* LINTED */
|
||||
slash += strcspn(slash, "/");
|
||||
|
||||
done = (*slash == '\0');
|
||||
*slash = '\0';
|
||||
|
||||
/* skip existing path components */
|
||||
exists = !stat(path, &sb);
|
||||
if (!done && exists && S_ISDIR(sb.st_mode)) {
|
||||
*slash = '/';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mkdir(path, done ? mode : dir_mode) == 0) {
|
||||
if (mode > 0777 && chmod(path, mode) < 0)
|
||||
return (-1);
|
||||
} else {
|
||||
if (!exists) {
|
||||
/* Not there */
|
||||
return (-1);
|
||||
}
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
/* Is there, but isn't a directory */
|
||||
errno = ENOTDIR;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (done)
|
||||
break;
|
||||
|
||||
*slash = '/';
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
9
cgi.h.example
Normal file
9
cgi.h.example
Normal file
@ -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
|
35
chars.c
35
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);
|
||||
|
44
chars.in
44
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)
|
||||
|
||||
|
339
compat_ohash.c
Normal file
339
compat_ohash.c
Normal file
@ -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*/
|
73
compat_ohash.h
Normal file
73
compat_ohash.h
Normal file
@ -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
|
45
compat_reallocarray.c
Normal file
45
compat_reallocarray.c
Normal file
@ -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*/
|
18
compat_sqlite3_errstr.c
Normal file
18
compat_sqlite3_errstr.c
Normal file
@ -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
|
74
compat_strcasestr.c
Normal file
74
compat_strcasestr.c
Normal file
@ -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
|
80
compat_strsep.c
Normal file
80
compat_strsep.c
Normal file
@ -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
|
@ -1,5 +1,3 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined(__BEGIN_DECLS)
|
||||
# ifdef __cplusplus
|
||||
# define __BEGIN_DECLS extern "C" {
|
||||
@ -15,30 +13,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 */
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define MANDOC_CONFIG_H
|
||||
|
||||
#if defined(__linux__) || defined(__MINT__)
|
||||
# define _GNU_SOURCE /* strptime(), getsubopt() */
|
||||
# define _GNU_SOURCE /* getsubopt(), strcasestr(), strptime() */
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
49
configure
vendored
Executable file
49
configure
vendored
Executable file
@ -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
|
@ -1,4 +1,4 @@
|
||||
/* $Id: demandoc.c,v 1.7 2012/05/31 22:27:14 schwarze Exp $ */
|
||||
/* $Id: demandoc.c,v 1.10 2014/03/19 22:20:43 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
@ -76,7 +76,7 @@ main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL, NULL);
|
||||
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, NULL);
|
||||
assert(mp);
|
||||
|
||||
if (0 == argc)
|
||||
@ -110,7 +110,7 @@ pmandoc(struct mparse *mp, int fd, const char *fn, int list)
|
||||
return;
|
||||
}
|
||||
|
||||
mparse_result(mp, &mdoc, &man);
|
||||
mparse_result(mp, &mdoc, &man, NULL);
|
||||
line = 1;
|
||||
col = 0;
|
||||
|
||||
|
73
eqn.c
73
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 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
|
||||
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 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
|
||||
}
|
||||
|
||||
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);
|
||||
|
10
eqn_html.c
10
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);
|
||||
|
||||
|
@ -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)
|
||||
|
BIN
external.png
BIN
external.png
Binary file not shown.
Before Width: | Height: | Size: 165 B |
9
gmdiff
9
gmdiff
@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
|
||||
# Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
@ -27,8 +27,11 @@ while [ -n "$1" ]; do
|
||||
file=$1
|
||||
shift
|
||||
echo " ========== $file ========== "
|
||||
tbl $file | groff -mandoc -Tascii -P -c 2>&1 > /tmp/groff.out
|
||||
mandoc -Ios='OpenBSD ports' -Werror $file 2>&1 > /tmp/mandoc.out
|
||||
tbl $file | groff -mandoc -Tascii -P -c 2> /tmp/groff.err > /tmp/groff.out
|
||||
mandoc -Ios='OpenBSD ports' -Werror $file 2> /tmp/mandoc.err > /tmp/mandoc.out
|
||||
for i in groff mandoc; do
|
||||
[[ -s /tmp/$i.err ]] && echo "$i errors:" && cat /tmp/$i.err
|
||||
done
|
||||
diff -au /tmp/groff.out /tmp/mandoc.out 2>&1
|
||||
done
|
||||
|
||||
|
183
html.c
183
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:
|
||||
@ -324,6 +324,37 @@ html_strlen(const char *cp)
|
||||
return(sz);
|
||||
}
|
||||
|
||||
static int
|
||||
print_escape(char c)
|
||||
{
|
||||
|
||||
switch (c) {
|
||||
case '<':
|
||||
printf("<");
|
||||
break;
|
||||
case '>':
|
||||
printf(">");
|
||||
break;
|
||||
case '&':
|
||||
printf("&");
|
||||
break;
|
||||
case '"':
|
||||
printf(""");
|
||||
break;
|
||||
case ASCII_NBRSP:
|
||||
putchar('-');
|
||||
break;
|
||||
case ASCII_HYPH:
|
||||
putchar('-');
|
||||
/* FALLTHROUGH */
|
||||
case ASCII_BREAK:
|
||||
break;
|
||||
default:
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
print_encode(struct html *h, const char *p, int norecurse)
|
||||
{
|
||||
@ -331,7 +362,8 @@ print_encode(struct html *h, const char *p, int norecurse)
|
||||
int c, len, nospace;
|
||||
const char *seq;
|
||||
enum mandoc_esc esc;
|
||||
static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
|
||||
static const char rejs[9] = { '\\', '<', '>', '&', '"',
|
||||
ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
|
||||
|
||||
nospace = 0;
|
||||
|
||||
@ -350,43 +382,29 @@ print_encode(struct html *h, const char *p, int norecurse)
|
||||
if ('\0' == *p)
|
||||
break;
|
||||
|
||||
switch (*p++) {
|
||||
case ('<'):
|
||||
printf("<");
|
||||
if (print_escape(*p++))
|
||||
continue;
|
||||
case ('>'):
|
||||
printf(">");
|
||||
continue;
|
||||
case ('&'):
|
||||
printf("&");
|
||||
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);
|
||||
|
17
html.h
17
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 *);
|
||||
|
||||
|
48
index.css
48
index.css
@ -1,48 +0,0 @@
|
||||
html { min-width: 40em;
|
||||
margin-top: 2em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 80%; }
|
||||
|
||||
body { text-align: justify;
|
||||
font-family: Helvetica,Arial,sans-serif;
|
||||
line-height: 120%;
|
||||
font-size: small; }
|
||||
|
||||
p,ul,table { margin-left: 3em; }
|
||||
|
||||
p.head,
|
||||
p.subhead,
|
||||
p.foot { margin-left: 0.0em; margin-right: 0.0em; }
|
||||
|
||||
p.news { margin-left: 2.0em; }
|
||||
|
||||
li { margin: 0.25em; }
|
||||
|
||||
h1 { font-size: 110%; }
|
||||
h2 { font-size: 105%; margin-left: 1.5em }
|
||||
|
||||
p.head { margin-bottom: 0.5em;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
padding-bottom: 0.2em; }
|
||||
|
||||
p.subhead { margin-top: 0em;
|
||||
margin-bottom: 1.75em; }
|
||||
|
||||
p.foot { border-top: 1px solid #dddddd;
|
||||
color: #666666;
|
||||
padding-top: 0.2em;
|
||||
margin-top: 1.75em; }
|
||||
|
||||
span.nm { color: green; }
|
||||
|
||||
span.file { font-style: italic; }
|
||||
|
||||
span.attn { font-weight: bold; }
|
||||
|
||||
span.flag { font-weight: bold; }
|
||||
|
||||
a { text-decoration: none; }
|
||||
|
||||
a.external { background: transparent url(external.png) center right no-repeat;
|
||||
padding-right: 12px; }
|
438
index.sgml
438
index.sgml
@ -1,438 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
|
||||
<LINK REL="stylesheet" HREF="index.css" TYPE="text/css" MEDIA="all">
|
||||
<TITLE>mdocml | UNIX manpage compiler</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<P CLASS="head">
|
||||
<A HREF="http://www.openbsd.org/"><IMG SRC="puffy.gif" ALT="Puffy" WIDTH="100" HEIGHT="91" STYLE="float: right"></A>
|
||||
<B>mdocml</B> – UNIX manpage compiler, current version @VERSION@ (@VDATE@)
|
||||
</P>
|
||||
<P CLASS="subhead">
|
||||
Sources: <A HREF="/snapshots/mdocml.tar.gz">current</A>,
|
||||
<A HREF="/cgi-bin/cvsweb/?cvsroot=mdocml">cvsweb</A>
|
||||
(<A HREF="/snapshots/">archives</A>)
|
||||
</P>
|
||||
<H1>
|
||||
<A NAME="description">Description</A>
|
||||
</H1>
|
||||
<P>
|
||||
<SPAN CLASS="nm">mdocml</SPAN> is a suite of tools compiling <I><A HREF="mdoc.7.html">mdoc</A></I>, the roff macro
|
||||
package of choice for BSD manual pages, and <I><A HREF="man.7.html">man</A></I>, the predominant historical package for
|
||||
UNIX manuals.
|
||||
It is small, ISO C, <A CLASS="external" HREF="http://www.isc.org/software/license">ISC</A>-licensed, and quite fast.
|
||||
</P>
|
||||
<P>
|
||||
The tool set features <A HREF="mandoc.1.html">mandoc</A>,
|
||||
based on the <A HREF="mandoc.3.html">libmandoc</A> validating compiler,
|
||||
to format output for UNIX terminals (with
|
||||
support for wide-character locales), XHTML, HTML, PostScript, and PDF.
|
||||
It also includes <A HREF="preconv.1.html">preconv</A>, for recoding multibyte manuals;
|
||||
<A HREF="demandoc.1.html">demandoc</A>, for emitting only text parts of manuals;
|
||||
<A HREF="mandocdb.8.html">mandocdb</A>, for indexing manuals; and
|
||||
<A HREF="apropos.1.html">apropos</A>, <A HREF="whatis.1.html">whatis</A>, and
|
||||
<A HREF="man.cgi.7.html">man.cgi</A> (via <A HREF="catman.8.html">catman</A>) for semantic search of manual content.
|
||||
</P>
|
||||
<P>
|
||||
<SPAN CLASS="nm">mdocml</SPAN> has predominantly been developed on OpenBSD
|
||||
and is both an <A CLASS="external" HREF="http://www.openbsd.org/">OpenBSD</A>
|
||||
and a <A CLASS="external" HREF="http://bsd.lv/">BSD.lv</A> project.
|
||||
We strive to support all interested free operating systems, in particular
|
||||
<A CLASS="external" HREF="http://www.dragonflybsd.org/">DragonFly</A>,
|
||||
<A CLASS="external" HREF="http://www.netbsd.org/">NetBSD</A>,
|
||||
<A CLASS="external" HREF="http://www.freebsd.org/">FreeBSD</A>,
|
||||
<A CLASS="external" HREF="http://www.minix3.org/">Minix 3</A>,
|
||||
and <A CLASS="external" HREF="http://www.gnu.org/">GNU</A>/Linux,
|
||||
as well as all systems running the <A CLASS="external" HREF="http://www.pkgsrc.org/">pkgsrc</A> portable package build system.
|
||||
All of these projects have helped to make <SPAN CLASS="nm">mdocml</SPAN> better, by providing feedback and advice,
|
||||
bug reports, and patches.
|
||||
</P>
|
||||
<P>
|
||||
<I>Disambiguation</I>: <SPAN CLASS="nm">mdocml</SPAN> is often referred to by its installed binary, <Q>mandoc</Q>.
|
||||
</P>
|
||||
<H2>
|
||||
<A NAME="sources">Sources</A>
|
||||
</H2>
|
||||
<P>
|
||||
<SPAN CLASS="nm">mdocml</SPAN> should build and run on any modern system with
|
||||
<A HREF="http://www.oracle.com/technetwork/database/berkeleydb/overview/index.html">libdb</A>
|
||||
(this is installed by default on BSD UNIX systems — see the <I>Makefile</I> if you're running Linux).
|
||||
To build and install into <I>/usr/local/</I>, just run <CODE>make install</CODE>.
|
||||
Be careful: the <B>preconv</B>, <B>apropos</B>, and <B>whatis</B> installed binary names
|
||||
may be taken by existing utilities.
|
||||
</P>
|
||||
<H2>
|
||||
Downstream
|
||||
</H2>
|
||||
<P>
|
||||
Several systems come bundled with <SPAN CLASS="nm">mdocml</SPAN> utilities.
|
||||
If your system does not appear below, the maintainers have not contacted me and it should not be considered
|
||||
<Q>official</Q>, so please <A HREF="#contact">contact us</A> if you plan on maintaining a downstream version!
|
||||
</P>
|
||||
<TABLE WIDTH="100%" SUMMARY="Downstream Sources">
|
||||
<COL WIDTH="175">
|
||||
<COL>
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD>DragonFly BSD</TD>
|
||||
<TD>
|
||||
<A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/contrib/mdocml" CLASS="external">contrib/mdocml</A> (1.12.3 sources)
|
||||
<A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/lib/libmandoc" CLASS="external">lib/libmandoc</A>
|
||||
<A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/usr.bin/mandoc" CLASS="external">usr.bin/mandoc</A> (build system)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>FreeBSD 10.0, -CURRENT</TD>
|
||||
<TD>
|
||||
<A HREF="http://svnweb.freebsd.org/base/head/contrib/mdocml/" CLASS="external">contrib/mdocml</A> (1.12.1 sources)
|
||||
<A HREF="http://svnweb.freebsd.org/base/head/usr.bin/mandoc/" CLASS="external">usr.bin/mandoc</A> (build system)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>FreeBSD 9.x, 8.x</TD>
|
||||
<TD>
|
||||
<A HREF="http://svnweb.freebsd.org/ports/head/textproc/mdocml/" CLASS="external">ports/textproc/mdocml</A> (1.12.2 port)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>NetBSD</TD>
|
||||
<TD>
|
||||
<A HREF="http://cvsweb.netbsd.org/bsdweb.cgi/src/external/bsd/mdocml/" CLASS="external">src/external/bsd/mdocml</A> (1.12.1 sources plus patches and build system)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>OpenBSD</TD>
|
||||
<TD>
|
||||
<A HREF="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/mandoc/" CLASS="external">src/usr.bin/mandoc</A> (1.12.3 sources under active development and build system)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>pkgsrc</TD>
|
||||
<TD>
|
||||
<A HREF="http://pkgsrc.se/textproc/mdocml" CLASS="external">textproc/mdocml</A> (1.12.2 port)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>Minix3</TD>
|
||||
<TD>
|
||||
<A HREF="http://git.minix3.org/?p=minix.git;a=tree;f=external/bsd/mdocml" CLASS="external">external/bsd/mdocml</A> (1.10.9 sources and build system)
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>Alpine Linux</TD>
|
||||
<TD>
|
||||
<A HREF="http://git.alpinelinux.org/cgit/aports/tree/main/mdocml" CLASS="external">aports/main/mdocml</A> (1.12.2 port)
|
||||
</TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<H1>
|
||||
<A NAME="documentation">Documentation</A>
|
||||
</H1>
|
||||
<P>
|
||||
These manuals are generated automatically and refer to the current release.
|
||||
They are the authoritative documentation for the <SPAN CLASS="nm">mdocml</SPAN> system.
|
||||
</P>
|
||||
|
||||
<TABLE WIDTH="100%" SUMMARY="Documentation">
|
||||
<COL WIDTH="175">
|
||||
<COL>
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="apropos.1.html">apropos(1)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
search the manual page database
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="demandoc.1.html">demandoc(1)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
emit only text of UNIX manuals
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="mandoc.1.html">mandoc(1)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
format and display UNIX manuals
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="preconv.1.html">preconv(1)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
recode multibyte UNIX manuals
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="whatis.1.html">whatis(1)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
search the manual page database
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="mandoc.3.html">mandoc(3)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
mandoc macro compiler library
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="tbl.3.html">tbl(3)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
roff table parser library for mandoc
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="eqn.7.html">eqn(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
eqn-mandoc language reference
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="man.7.html">man(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
man language reference
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="man.cgi.7.html">man.cgi(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
cgi for manpage query and display
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="mandoc_char.7.html">mandoc_char(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
mandoc special characters
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="mdoc.7.html">mdoc(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
mdoc language reference
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="roff.7.html">roff(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
roff-mandoc language reference
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="tbl.7.html">tbl(7)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
tbl-mandoc language reference
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="catman.8.html">catman(8)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
update a man.cgi manpage cache
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VALIGN="top"><A HREF="mandocdb.8.html">mandocdb(8)</A></TD>
|
||||
<TD VALIGN="top">
|
||||
index UNIX manuals
|
||||
</TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<H2>
|
||||
<A NAME="links">Supplementary Information</A>
|
||||
</H2>
|
||||
<UL>
|
||||
<LI>
|
||||
<A HREF="http://manpages.bsd.lv/">Practical UNIX Manuals</A>: mdoc tutorial by Kristaps Dzonsons
|
||||
</LI>
|
||||
<LI>
|
||||
<A HREF="http://www.openbsd.org/faq/ports/specialtopics.html#Mandoc" CLASS="external">OpenBSD porting guide</A>
|
||||
chapter regarding manual pages
|
||||
</LI>
|
||||
<LI>
|
||||
<A HREF="press.html">Publications and media coverage</A>
|
||||
concerning mdocml and mandoc
|
||||
</LI>
|
||||
<LI>
|
||||
<A HREF="http://manpages.bsd.lv/history.html">History of UNIX Manpages</A>: a comprehensive overview by Kristaps Dzonsons
|
||||
</LI>
|
||||
</UL>
|
||||
<H1>
|
||||
<A NAME="contact">Contact</A>
|
||||
</H1>
|
||||
<P>
|
||||
Use the mailing lists for bug-reports, patches, questions, etc. Please check the
|
||||
<A HREF="http://mdocml.bsd.lv/cgi-bin/cvsweb/TODO?cvsroot=mdocml">TODO</A> for known issues
|
||||
before posting. All lists are subscription-only: send a blank e-mail to the listed address to subscribe. Beyond that,
|
||||
contact Kristaps at <A HREF="http://mailhide.recaptcha.net/d?k=01M6h_w7twDp58ZgH57eWC_w==&c=Q2DBUt401ePlSeupJFrq_Q==" TITLE="Reveal
|
||||
this e-mail address">kris...</A>@bsd.lv. Archives are available at <A HREF="http://gmane.org/" CLASS="external">Gmane</A>.
|
||||
</P>
|
||||
<TABLE WIDTH="100%" SUMMARY="Mailing Lists">
|
||||
<COL WIDTH="175">
|
||||
<COL>
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD>
|
||||
disc<A CLASS="external" TITLE="Reveal this e-mail address"
|
||||
HREF="http://www.google.com/recaptcha/mailhide/d?k=01KQ80PFH5n3BBNpF5Gs4sRg==&c=EV1QytpQqTHSItc2IXvZyocgYLPnG5K0JKw_gwMC9yc=">...</A>@mdocml.bsd.lv
|
||||
</TD>
|
||||
<TD>
|
||||
bug-reports, general questions, and announcements
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>
|
||||
tec<A CLASS="external" TITLE="Reveal this e-mail address"
|
||||
HREF="http://www.google.com/recaptcha/mailhide/d?k=01qDX_iV0RlUOarEvb6mR28g==&c=gRXsTjza0NNCFPaYu-Taj2tF0pmYZSc90EZkFkhkxgo=">...</A>@mdocml.bsd.lv
|
||||
</TD>
|
||||
<TD>
|
||||
patches and system discussions
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>
|
||||
sou<A CLASS="external" TITLE="Reveal this e-mail address"
|
||||
HREF="http://www.google.com/recaptcha/mailhide/d?k=01prQrAZhhl2EbIwVcRfABsQ==&c=KtTW4Yic9xk-8g40KzJoca4fR3MYXv28g8NC6OQV-T8=">...</A>@mdocml.bsd.lv
|
||||
</TD>
|
||||
<TD>
|
||||
source commit messages
|
||||
</TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<H1>
|
||||
<A NAME="news">News</A>
|
||||
</H1>
|
||||
<P CLASS="news">
|
||||
31-12-2013: version 1.12.3
|
||||
</P>
|
||||
<P>
|
||||
In the <A HREF="mdoc.7.html">mdoc(7)</A> SYNOPSIS, line breaks and hanging indentation
|
||||
now work correctly for .Fo/.Fa/.Fc and .Fn blocks.
|
||||
Thanks to Franco Fichtner for doing part of the work.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="mdoc.7.html">mdoc(7)</A> .Bk macro got some addititonal bugfixes.
|
||||
</P>
|
||||
<P>
|
||||
In <A HREF="mdoc.7.html">mdoc(7)</A> macro arguments, double quotes can now be quoted
|
||||
by doubling them, just like in <A HREF="man.7.html">man(7)</A>.
|
||||
Thanks to Tsugutomo ENAMI for the patch.
|
||||
</P>
|
||||
<P>
|
||||
At the end of <A HREF="man.7.html">man(7)</A> macro lines, end-of-sentence spacing
|
||||
now works. Thanks to Franco Fichtner for the patch.
|
||||
</P>
|
||||
<P>
|
||||
For backward compatibility, the <A HREF="man.7.html">man(7)</A> parser now supports the
|
||||
man-ext .UR/.UE (uniform resource identifier) block macros.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="man.7.html">man(7)</A> parser now handles closing blocks that are not open
|
||||
more gracefully.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="man.7.html">man(7)</A> parser now ignores blank lines right after .SH and .SS.
|
||||
</P>
|
||||
<P>
|
||||
In the <A HREF="man.7.html">man(7)</A> formatter, reset indentation when leaving a block,
|
||||
not just when entering the next one.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="roff.7.html">roff(7)</A> .nr request now supports incrementing and decrementing
|
||||
number registers and stops parsing the number right before the first non-digit character.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="roff.7.html">roff(7)</A> parser now supports the alternative escape sequence
|
||||
syntax \C'uXXXX' for Unicode characters.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="roff.7.html">roff(7)</A> parser now parses and ignores the .fam (font family)
|
||||
and .hw (hyphenation points) requests and the \d and \u escape sequences.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="roff.7.html">roff(7)</A> manual got a new ESCAPE SEQUENCE REFERENCE.
|
||||
</P>
|
||||
<P CLASS="news">
|
||||
05-10-2013: version 1.12.2
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="mdoc.7.html">mdoc(7)</A> to <A HREF="man.7.html">man(7)</A> converter,
|
||||
to be called as <CODE>mandoc -Tman</CODE>, is now fully functional.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="mandoc.1.html">mandoc(1)</A> utility now supports the <CODE>-Ios</CODE> (default operating system)
|
||||
input option, and the <CODE>-Tutf8</CODE> output mode now actually works.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="mandocdb.8.html">mandocdb(8)</A> utility no longer truncates existing databases when starting to build new ones,
|
||||
but only replaces them when the build actually succeeds.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="man.7.html">man(7)</A> parser now supports the <EM>PD</EM> macro (paragraph distance),
|
||||
and (for GNU man-ext compatibility only) <EM>EX</EM> (example block) and <EM>EE</EM> (example end).
|
||||
Plus several bugfixes regarding indentation, line breaks, and vertical spacing,
|
||||
and regarding <EM>RS</EM> following <EM>TP</EM>.
|
||||
</P>
|
||||
<P>
|
||||
The <A HREF="roff.7.html">roff(7)</A> parser now supports the <EM>\f(BI</EM> (bold+italic) font escape,
|
||||
the <EM>\z</EM> (zero cursor advance) escape and the <EM>cc</EM> (change control character)
|
||||
and <EM>it</EM> (input line trap) requests.
|
||||
Plus bugfixes regarding the <EM>\t</EM> (tab) escape, nested escape sequences, and conditional requests.
|
||||
</P>
|
||||
<P>
|
||||
In <A HREF="mdoc.7.html">mdoc(7)</A>, several bugs were fixed related to UTF-8 output of quoting enclosures,
|
||||
delimiter handling, list indentation and horizontal and vertical spacing,
|
||||
formatting of the <EM>Lk</EM>, <EM>%U</EM>, and <EM>%C</EM> macros,
|
||||
plus some bugfixes related to the handling of syntax errors like badly nested font blocks,
|
||||
stray <EM>Ta</EM> macros outside column lists, unterminated <EM>It Xo</EM> blocks,
|
||||
and non-text children of <EM>Nm</EM> blocks.
|
||||
</P>
|
||||
<P>
|
||||
In <A HREF="tbl.7.html">tbl(7)</A>, the width of horizontal spans and the vertical spacing around tables was corrected,
|
||||
and in <A HREF="man.7.html">man(7)</A> files, a crash was fixed that was triggered by some particular unclosed <EM>T{</EM> macros.
|
||||
</P>
|
||||
<P>
|
||||
For mandoc developers, we now provide a <A HREF="tbl.3.html">tbl(3)</A> library manual and <CODE>gmdiff</CODE>,
|
||||
a very small, very simplistic groff-versus-mandoc output comparison tool.
|
||||
</P>
|
||||
<H2>
|
||||
<A>History</A>
|
||||
</H2>
|
||||
<UL>
|
||||
<LI>
|
||||
<A HREF="NEWS">Release notes</A> going back to release 1.9.15, February 18, 2010.
|
||||
Briefly explaining the most important changes in each release in relatively easy terms.
|
||||
Very many changes are not mentioned here.
|
||||
</LI>
|
||||
<LI>
|
||||
<A HREF="history.html">Development history</A> going back to the beginning of the project, November 22, 2008.
|
||||
One-line entries for important commits, releases, merges, hackathons and talks.
|
||||
Makes it easy to find out who did what, and when, and when it became available where.
|
||||
However, this is still incomplete, mentioning only a small fraction of all commits,
|
||||
and to keep the size down, the individual entries are extremely terse and technical.
|
||||
Feel free to look up more details and longer explanations about individual entries
|
||||
in the ChangeLog or in CVS.
|
||||
</LI>
|
||||
<LI>
|
||||
<A HREF="ChangeLog">CVS ChangeLog</A> going back to the beginning of the project.
|
||||
Very technical information of varying quality, strictly chronological.
|
||||
All commits are mentioned, but some messages neglect to mention some changes.
|
||||
Partly terse, partly detailed and verbose. In any case, the ChangeLog is very long -
|
||||
more than 25,000 lines, more than 700 kB.
|
||||
</LI>
|
||||
<LI>
|
||||
<A HREF="/cgi-bin/cvsweb/?cvsroot=mdocml">CVS</A> web interface, going back to the beginning of the project.
|
||||
Source code, diffs and commit messages for each source file. The real thing.
|
||||
</LI>
|
||||
</UL>
|
||||
<P CLASS="foot">
|
||||
<SMALL>
|
||||
Copyright © 2008–2011
|
||||
<A CLASS="external" HREF="http://kristaps.bsd.lv">Kristaps Dzonsons</A>,
|
||||
© 2013 Ingo Schwarze,
|
||||
$Date: 2013/12/31 $
|
||||
</SMALL>
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
5
lib.c
5
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) \
|
||||
|
3
lib.in
3
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
|
||||
|
14
libman.h
14
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
|
||||
|
||||
|
36
libmandoc.h
36
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
|
||||
|
19
libmdoc.h
19
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 *);
|
||||
|
@ -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
|
||||
|
131
main.c
131
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:%d:%d: %s: %s",
|
||||
file, line, col + 1,
|
||||
mparse_strlevel(lvl),
|
||||
mparse_strerror(t));
|
||||
fprintf(stderr, "%s: %s:", progname, file);
|
||||
|
||||
if (line)
|
||||
fprintf(stderr, "%d:%d:", line, col + 1);
|
||||
|
||||
fprintf(stderr, " %s", mparse_strlevel(lvl));
|
||||
|
||||
if (NULL != (mparse_msg = mparse_strerror(t)))
|
||||
fprintf(stderr, ": %s", mparse_msg);
|
||||
|
||||
if (msg)
|
||||
fprintf(stderr, ": %s", msg);
|
||||
|
4
main.h
4
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
|
||||
|
217
makewhatis.8
Normal file
217
makewhatis.8
Normal file
@ -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 .
|
116
man.7
116
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
|
||||
|
218
man.c
218
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;
|
||||
}
|
||||
|
122
man.cgi.7
122
man.cgi.7
@ -1,122 +0,0 @@
|
||||
.Dd $Mdocdate: July 13 2013 $
|
||||
.Dt MAN.CGI 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm man.cgi
|
||||
.Nd cgi for manpage query and display
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
script queries and displays manual pages.
|
||||
It interfaces with
|
||||
.Xr mandocdb 8
|
||||
databases cached with
|
||||
.Xr catman 8 .
|
||||
.Pp
|
||||
To use
|
||||
.Nm ,
|
||||
create a manual cache in
|
||||
.Xr catman 8 .
|
||||
Assign this directory to the environment variable
|
||||
.Ev CACHE_DIR ,
|
||||
defaulting to
|
||||
.Pa /cache/man.cgi .
|
||||
Copy the
|
||||
.Pa man.cgi
|
||||
script into your CGI directory (see
|
||||
.Sx FILES
|
||||
for other relevant files).
|
||||
.Pp
|
||||
Multiple
|
||||
.Xr catman 8
|
||||
trees may be managed by
|
||||
.Nm :
|
||||
directories under
|
||||
.Ev CACHE_DIR
|
||||
containing
|
||||
.Pa etc/catman.conf
|
||||
are identified as
|
||||
.Qq manroots .
|
||||
The path of a manroot under
|
||||
.Ev CACHE_DIR
|
||||
is converted to a name by replacing path separators with spaces.
|
||||
.Pp
|
||||
Thus, if
|
||||
.Ev CACHE_DIR
|
||||
is the default
|
||||
.Pa /cache/man.cgi ,
|
||||
the web-server is jailed to
|
||||
.Pa /var/www ,
|
||||
and cache subdirectories
|
||||
.Pa ./foo/1
|
||||
and
|
||||
.Pa ./bar/2
|
||||
contain
|
||||
.Pa etc/catman.conf ,
|
||||
.Nm
|
||||
will assign these to manroots
|
||||
.Qq foo 1
|
||||
and
|
||||
.Qq bar 2 ,
|
||||
respectively.
|
||||
These names will appear as choices when searching for manuals.
|
||||
.Pp
|
||||
If
|
||||
.Nm
|
||||
finds only one manroot, or none, then the selection box is omitted.
|
||||
If no manroot is specified during search, the first manroot is used by
|
||||
default.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Ds
|
||||
.It Ev CACHE_DIR
|
||||
The absolute path of the
|
||||
.Xr catman 8
|
||||
cache directory.
|
||||
This must not have a trailing slash.
|
||||
.It Ev CSS_DIR
|
||||
Prepended to CSS file links in outputted HTML files.
|
||||
This must not have a trailing slash.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa etc/catman.conf
|
||||
Built by
|
||||
.Xr catman 8
|
||||
and must exist at least once under the configuration directory root.
|
||||
.It Pa man.css
|
||||
Should be visible in the server document root or within
|
||||
.Ev CSS_DIR .
|
||||
Included in each page after
|
||||
.Pa man-cgi.css ,
|
||||
ostensibly for
|
||||
.Xr mandoc 1
|
||||
HTML output styling.
|
||||
.It Pa man.cgi.css
|
||||
Should be visible in the server document root or within
|
||||
.Ev CSS_DIR .
|
||||
Included in each page, ostensibly for general
|
||||
.Nm
|
||||
styling.
|
||||
.El
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Nm
|
||||
script is call-compatible with queries from the traditional
|
||||
.Pa man.cgi
|
||||
script by Wolfram Schneider.
|
||||
However, the results may not be quite the same.
|
||||
.Sh SEE ALSO
|
||||
.Xr catman 8 ,
|
||||
.Xr mandocdb 8
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
|
||||
.Sh CAVEATS
|
||||
If you're running in a jailed web-server, make sure the
|
||||
.Pa /tmp
|
||||
directory exists and is writable.
|
||||
The databases may need this for scratch space.
|
409
man.cgi.8
Normal file
409
man.cgi.8
Normal file
@ -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 .
|
6
man.h
6
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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
102
man_html.c
102
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)
|
||||
{
|
||||
|
155
man_macro.c
155
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
|
||||
|
274
man_term.c
274
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 @@ print_man_node(DECL_ARGS)
|
||||
* 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);
|
||||
}
|
||||
|
368
man_validate.c
368
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 int post_UR(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 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);
|
||||
mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
|
||||
n->pos, "want one child (have %d)", n->nchild);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_sec(CHKARGS)
|
||||
{
|
||||
|
||||
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.
|
||||
*/
|
||||
|
875
mandoc.1
875
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 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 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 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
|
||||
|
341
mandoc.3
341
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 ,
|
||||
|
226
mandoc.c
226
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:
|
||||
|
144
mandoc.db.5
Normal file
144
mandoc.db.5
Normal file
@ -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.
|
212
mandoc.h
212
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 */
|
||||
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 macro arguments */
|
||||
MANDOCERR_MACROEMPTY, /* skipping empty 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 */
|
||||
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 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 */
|
||||
/* 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);
|
||||
|
121
mandoc_aux.c
Normal file
121
mandoc_aux.c
Normal file
@ -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);
|
||||
}
|
33
mandoc_aux.h
Normal file
33
mandoc_aux.h
Normal file
@ -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*/
|
362
mandoc_escape.3
Normal file
362
mandoc_escape.3
Normal file
@ -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.
|
||||
..
|
249
mandoc_html.3
Normal file
249
mandoc_html.3
Normal file
@ -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 .
|
197
mandoc_malloc.3
Normal file
197
mandoc_malloc.3
Normal file
@ -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
|
324
mandocdb.8
324
mandocdb.8
@ -1,324 +0,0 @@
|
||||
.\" $Id: mandocdb.8,v 1.17.2.1 2013/09/18 01:04:07 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.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 18 2013 $
|
||||
.Dt MANDOCDB 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mandocdb
|
||||
.Nd index UNIX manuals
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl avW
|
||||
.Op Fl C Ar file
|
||||
.Nm
|
||||
.Op Fl avW
|
||||
.Ar dir ...
|
||||
.Nm
|
||||
.Op Fl vW
|
||||
.Fl d Ar dir
|
||||
.Op Ar
|
||||
.Nm
|
||||
.Op Fl vW
|
||||
.Fl u Ar dir
|
||||
.Op Ar
|
||||
.Nm
|
||||
.Fl t Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility extracts keywords from
|
||||
.Ux
|
||||
manuals and indexes them in a
|
||||
.Sx Keyword Database
|
||||
and
|
||||
.Sx Index 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 databases 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 truncated.
|
||||
If
|
||||
.Ar dir
|
||||
is not provided,
|
||||
.Nm
|
||||
uses the default paths stipulated by
|
||||
.Xr man 1 .
|
||||
.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 Ar dir
|
||||
Merge (remove and re-add)
|
||||
.Ar
|
||||
to the database in
|
||||
.Ar dir
|
||||
without truncating it.
|
||||
.It Fl t Ar
|
||||
Check the given
|
||||
.Ar files
|
||||
for potential problems.
|
||||
No databases are modified.
|
||||
Implies
|
||||
.Fl a
|
||||
and
|
||||
.Fl W .
|
||||
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
|
||||
without truncating it.
|
||||
.It Fl v
|
||||
Display all files added or removed to the index.
|
||||
.It Fl W
|
||||
Print warnings about potential problems with manual pages
|
||||
to the standard error output.
|
||||
.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.
|
||||
.Ss Index Database
|
||||
The index database,
|
||||
.Pa mandoc.index ,
|
||||
is a
|
||||
.Xr recno 3
|
||||
database with record values consisting of
|
||||
.Pp
|
||||
.Bl -enum -compact
|
||||
.It
|
||||
the character
|
||||
.Cm d ,
|
||||
.Cm a ,
|
||||
or
|
||||
.Cm c
|
||||
to indicate the file type
|
||||
.Po
|
||||
.Xr mdoc 7 ,
|
||||
.Xr man 7 ,
|
||||
and post-formatted, respectively
|
||||
.Pc ,
|
||||
.It
|
||||
the filename relative to the databases' path,
|
||||
.It
|
||||
the manual section,
|
||||
.It
|
||||
the manual title,
|
||||
.It
|
||||
the architecture
|
||||
.Pq often empty ,
|
||||
.It
|
||||
and the description.
|
||||
.El
|
||||
.Pp
|
||||
Each of the above is NUL-terminated.
|
||||
.Pp
|
||||
If the record value is zero-length, it is unassigned.
|
||||
.Ss Keyword Database
|
||||
The keyword database,
|
||||
.Pa mandoc.db ,
|
||||
is a
|
||||
.Xr btree 3
|
||||
database of NUL-terminated keywords (record length is non-zero string
|
||||
length plus one) mapping to a 16-byte binary field consisting of the
|
||||
64-bit keyword type and the 64-bit
|
||||
.Sx Index Database
|
||||
record number, both in network-byte order.
|
||||
.Pp
|
||||
The type bit-mask consists of the following
|
||||
values mapping into
|
||||
.Xr mdoc 7
|
||||
macro identifiers:
|
||||
.Pp
|
||||
.Bl -column "x0x0000000000000001ULLx" "xLix" -offset indent -compact
|
||||
.It Li 0x0000000000000001ULL Ta \&An
|
||||
.It Li 0x0000000000000002ULL Ta \&Ar
|
||||
.It Li 0x0000000000000004ULL Ta \&At
|
||||
.It Li 0x0000000000000008ULL Ta \&Bsx
|
||||
.It Li 0x0000000000000010ULL Ta \&Bx
|
||||
.It Li 0x0000000000000020ULL Ta \&Cd
|
||||
.It Li 0x0000000000000040ULL Ta \&Cm
|
||||
.It Li 0x0000000000000080ULL Ta \&Dv
|
||||
.It Li 0x0000000000000100ULL Ta \&Dx
|
||||
.It Li 0x0000000000000200ULL Ta \&Em
|
||||
.It Li 0x0000000000000400ULL Ta \&Er
|
||||
.It Li 0x0000000000000800ULL Ta \&Ev
|
||||
.It Li 0x0000000000001000ULL Ta \&Fa
|
||||
.It Li 0x0000000000002000ULL Ta \&Fl
|
||||
.It Li 0x0000000000004000ULL Ta \&Fn
|
||||
.It Li 0x0000000000008000ULL Ta \&Ft
|
||||
.It Li 0x0000000000010000ULL Ta \&Fx
|
||||
.It Li 0x0000000000020000ULL Ta \&Ic
|
||||
.It Li 0x0000000000040000ULL Ta \&In
|
||||
.It Li 0x0000000000080000ULL Ta \&Lb
|
||||
.It Li 0x0000000000100000ULL Ta \&Li
|
||||
.It Li 0x0000000000200000ULL Ta \&Lk
|
||||
.It Li 0x0000000000400000ULL Ta \&Ms
|
||||
.It Li 0x0000000000800000ULL Ta \&Mt
|
||||
.It Li 0x0000000001000000ULL Ta \&Nd
|
||||
.It Li 0x0000000002000000ULL Ta \&Nm
|
||||
.It Li 0x0000000004000000ULL Ta \&Nx
|
||||
.It Li 0x0000000008000000ULL Ta \&Ox
|
||||
.It Li 0x0000000010000000ULL Ta \&Pa
|
||||
.It Li 0x0000000020000000ULL Ta \&Rs
|
||||
.It Li 0x0000000040000000ULL Ta \&Sh
|
||||
.It Li 0x0000000080000000ULL Ta \&Ss
|
||||
.It Li 0x0000000100000000ULL Ta \&St
|
||||
.It Li 0x0000000200000000ULL Ta \&Sy
|
||||
.It Li 0x0000000400000000ULL Ta \&Tn
|
||||
.It Li 0x0000000800000000ULL Ta \&Va
|
||||
.It Li 0x0000001000000000ULL Ta \&Vt
|
||||
.It Li 0x0000002000000000ULL Ta \&Xr
|
||||
.El
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
The time to construct a new database pair grows linearly with the
|
||||
number of keywords in the input files.
|
||||
However, removing or updating entries with
|
||||
.Fl u
|
||||
or
|
||||
.Fl d ,
|
||||
respectively, grows as a multiple of the index length and input size.
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It Pa mandoc.db
|
||||
A
|
||||
.Xr btree 3
|
||||
keyword database mapping keywords to a type and file reference in
|
||||
.Pa mandoc.index .
|
||||
.It Pa mandoc.index
|
||||
A
|
||||
.Xr recno 3
|
||||
database of indexed file-names.
|
||||
.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 DIAGNOSTICS
|
||||
If the following errors occur, the
|
||||
.Nm
|
||||
databases should be rebuilt.
|
||||
.Bl -diag
|
||||
.It "%s: Corrupt database"
|
||||
The keyword database file indicated by
|
||||
.Pa %s
|
||||
is unreadable.
|
||||
.It "%s: Corrupt index"
|
||||
The index database file indicated by
|
||||
.Pa %s
|
||||
is unreadable.
|
||||
.It "%s: Path too long"
|
||||
The file
|
||||
.Pa %s
|
||||
is too long.
|
||||
This usually indicates database corruption or invalid command-line
|
||||
arguments.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr apropos 1 ,
|
||||
.Xr man 1 ,
|
||||
.Xr whatis 1 ,
|
||||
.Xr btree 3 ,
|
||||
.Xr recno 3 ,
|
||||
.Xr man.conf 5
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm makewhatis
|
||||
utility first appeared in
|
||||
.Bx 2 .
|
||||
It was rewritten in
|
||||
.Xr perl 1
|
||||
for
|
||||
.Ox 2.7
|
||||
and in C for
|
||||
.Ox 5.1 .
|
||||
.Pp
|
||||
The
|
||||
.Ar dir
|
||||
argument first appeared in
|
||||
.Nx 1.0 ;
|
||||
the options
|
||||
.Fl dtu
|
||||
in
|
||||
.Ox 2.7 ;
|
||||
and the options
|
||||
.Fl aCvW
|
||||
in
|
||||
.Ox 5.1 .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
.An Bill Joy
|
||||
wrote the original
|
||||
.Bx
|
||||
.Nm makewhatis
|
||||
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 .
|
3855
mandocdb.c
3855
mandocdb.c
File diff suppressed because it is too large
Load Diff
62
mandocdb.h
62
mandocdb.h
@ -1,62 +0,0 @@
|
||||
/* $Id: mandocdb.h,v 1.6.2.1 2013/09/18 00:54:20 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.
|
||||
*/
|
||||
#ifndef MANDOCDB_H
|
||||
#define MANDOCDB_H
|
||||
|
||||
#define MANDOC_DB "mandoc.db"
|
||||
#define MANDOC_IDX "mandoc.index"
|
||||
|
||||
#define TYPE_An 0x0000000000000001ULL
|
||||
#define TYPE_Ar 0x0000000000000002ULL
|
||||
#define TYPE_At 0x0000000000000004ULL
|
||||
#define TYPE_Bsx 0x0000000000000008ULL
|
||||
#define TYPE_Bx 0x0000000000000010ULL
|
||||
#define TYPE_Cd 0x0000000000000020ULL
|
||||
#define TYPE_Cm 0x0000000000000040ULL
|
||||
#define TYPE_Dv 0x0000000000000080ULL
|
||||
#define TYPE_Dx 0x0000000000000100ULL
|
||||
#define TYPE_Em 0x0000000000000200ULL
|
||||
#define TYPE_Er 0x0000000000000400ULL
|
||||
#define TYPE_Ev 0x0000000000000800ULL
|
||||
#define TYPE_Fa 0x0000000000001000ULL
|
||||
#define TYPE_Fl 0x0000000000002000ULL
|
||||
#define TYPE_Fn 0x0000000000004000ULL
|
||||
#define TYPE_Ft 0x0000000000008000ULL
|
||||
#define TYPE_Fx 0x0000000000010000ULL
|
||||
#define TYPE_Ic 0x0000000000020000ULL
|
||||
#define TYPE_In 0x0000000000040000ULL
|
||||
#define TYPE_Lb 0x0000000000080000ULL
|
||||
#define TYPE_Li 0x0000000000100000ULL
|
||||
#define TYPE_Lk 0x0000000000200000ULL
|
||||
#define TYPE_Ms 0x0000000000400000ULL
|
||||
#define TYPE_Mt 0x0000000000800000ULL
|
||||
#define TYPE_Nd 0x0000000001000000ULL
|
||||
#define TYPE_Nm 0x0000000002000000ULL
|
||||
#define TYPE_Nx 0x0000000004000000ULL
|
||||
#define TYPE_Ox 0x0000000008000000ULL
|
||||
#define TYPE_Pa 0x0000000010000000ULL
|
||||
#define TYPE_Rs 0x0000000020000000ULL
|
||||
#define TYPE_Sh 0x0000000040000000ULL
|
||||
#define TYPE_Ss 0x0000000080000000ULL
|
||||
#define TYPE_St 0x0000000100000000ULL
|
||||
#define TYPE_Sy 0x0000000200000000ULL
|
||||
#define TYPE_Tn 0x0000000400000000ULL
|
||||
#define TYPE_Va 0x0000000800000000ULL
|
||||
#define TYPE_Vt 0x0000001000000000ULL
|
||||
#define TYPE_Xr 0x0000002000000000ULL
|
||||
|
||||
#endif /*!MANDOCDB_H */
|
190
manpage.c
Normal file
190
manpage.c
Normal file
@ -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);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $Id: manpath.c,v 1.12 2013/11/21 01:49:18 schwarze Exp $ */
|
||||
/* $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>
|
||||
@ -26,7 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "mandoc_aux.h"
|
||||
#include "manpath.h"
|
||||
|
||||
#define MAN_CONF_FILE "/etc/man.conf"
|
||||
@ -169,9 +169,8 @@ manpath_add(struct manpaths *dirs, const char *dir)
|
||||
if (0 == strcmp(dirs->paths[i], dir))
|
||||
return;
|
||||
|
||||
dirs->paths = mandoc_realloc
|
||||
(dirs->paths,
|
||||
(dirs->sz + 1) * sizeof(char *));
|
||||
dirs->paths = mandoc_reallocarray(dirs->paths,
|
||||
dirs->sz + 1, sizeof(char *));
|
||||
|
||||
dirs->paths[dirs->sz++] = mandoc_strdup(cp);
|
||||
}
|
||||
|
228
mansearch.3
Normal file
228
mansearch.3
Normal file
@ -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 .
|
861
mansearch.c
Normal file
861
mansearch.c
Normal file
@ -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);
|
||||
}
|
101
mansearch.h
Normal file
101
mansearch.h
Normal file
@ -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*/
|
35
mansearch_const.c
Normal file
35
mansearch_const.c
Normal file
@ -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"
|
||||
};
|
224
mchars_alloc.3
Normal file
224
mchars_alloc.3
Normal file
@ -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
|
608
mdoc.7
608
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 .
|
||||
This macro is obsolete.
|
||||
No replacement markup is needed.
|
||||
.Pp
|
||||
It was used to show function return values.
|
||||
The syntax was:
|
||||
.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:
|
||||
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-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
|
||||
.It \-isoC
|
||||
.St -isoC
|
||||
.It \-isoC-90
|
||||
.St -isoC-90
|
||||
.It \-isoC-amd1
|
||||
.St -isoC-amd1
|
||||
.It \-isoC-tcor1
|
||||
.St -isoC-tcor1
|
||||
.It \-isoC-tcor2
|
||||
.St -isoC-tcor2
|
||||
.It \-isoC-99
|
||||
.St -isoC-99
|
||||
.It \-isoC-2011
|
||||
.St -isoC-2011
|
||||
.It \-iso9945-1-90
|
||||
.St -iso9945-1-90
|
||||
.It \-iso9945-1-96
|
||||
.St -iso9945-1-96
|
||||
.It \-iso9945-2-93
|
||||
.St -iso9945-2-93
|
||||
.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
|
||||
.It \-ieee754
|
||||
.St -ieee754
|
||||
.It \-iso8802-3
|
||||
.St -iso8802-3
|
||||
.It \-iso8601
|
||||
.St -iso8601
|
||||
.It \-ieee1275-94
|
||||
.St -ieee1275-94
|
||||
.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
|
||||
.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
|
||||
.It \-xpg4.3
|
||||
.St -xpg4.3
|
||||
.It \-xbd5
|
||||
.St -xbd5
|
||||
.It \-xcu5
|
||||
.St -xcu5
|
||||
.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
|
||||
.It \-xsh5
|
||||
.St -xsh5
|
||||
.It \-xns5
|
||||
.St -xns5
|
||||
.It \-xns5.2
|
||||
.St -xns5.2
|
||||
.It \-xns5.2d2.0
|
||||
.St -xns5.2d2.0
|
||||
.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
|
||||
.Pp
|
||||
.It \-xsh5
|
||||
.St -xsh5
|
||||
.Pp
|
||||
.It \-xcu5
|
||||
.St -xcu5
|
||||
.Pp
|
||||
.It \-xns5
|
||||
.St -xns5
|
||||
.It \-xns5.2d2.0
|
||||
.St -xns5.2d2.0
|
||||
.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 ,
|
||||
|
341
mdoc.c
341
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):
|
||||
case MDOC_Bf:
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_Bl):
|
||||
case MDOC_Bl:
|
||||
/* FALLTHROUGH */
|
||||
case (MDOC_Rs):
|
||||
case MDOC_En:
|
||||
/* FALLTHROUGH */
|
||||
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);
|
||||
|
||||
/* In quick mode (for mandocdb), abort after the NAME section. */
|
||||
|
||||
if (mdoc->quick && MDOC_Sh == tok &&
|
||||
SEC_NAME != mdoc->last->sec)
|
||||
return(2);
|
||||
|
||||
return(1);
|
||||
|
||||
err: /* Error out. */
|
||||
|
||||
mdoc->flags |= MDOC_HALT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
26
mdoc.h
26
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
|
||||
|
||||
|
112
mdoc_argv.c
112
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;
|
||||
|
@ -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])
|
||||
|
646
mdoc_html.c
646
mdoc_html.c
File diff suppressed because it is too large
Load Diff
384
mdoc_macro.c
384
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 @@ blk_full(MACRO_PROT_ARGS)
|
||||
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);
|
||||
}
|
||||
|
||||
|
353
mdoc_man.c
353
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)
|
||||
{
|
||||
@ -1027,6 +1106,13 @@ post_eo(DECL_ARGS)
|
||||
outflags &= ~MMAN_spc;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_es(DECL_ARGS)
|
||||
{
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pre_fa(DECL_ARGS)
|
||||
{
|
||||
@ -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;
|
||||
@ -1401,6 +1490,14 @@ pre_lk(DECL_ARGS)
|
||||
return(0);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1499,15 +1597,72 @@ pre_rs(DECL_ARGS)
|
||||
return(1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
732
mdoc_term.c
732
mdoc_term.c
File diff suppressed because it is too large
Load Diff
1763
mdoc_validate.c
1763
mdoc_validate.c
File diff suppressed because it is too large
Load Diff
3
msec.c
3
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"
|
||||
|
58
out.c
58
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;
|
||||
|
6
out.h
6
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
|
||||
|
||||
|
365
read.c
365
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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
|
||||
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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
|
||||
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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
|
||||
}
|
||||
|
||||
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 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
|
||||
}
|
||||
|
||||
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;
|
||||
|
305
roff.7
305
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
|
||||
|
5
st.c
5
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) \
|
||||
|
5
st.in
5
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)")
|
||||
|
25
tbl.c
25
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);
|
||||
}
|
||||
|
||||
|
49
tbl_data.c
49
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);
|
||||
|
11
tbl_html.c
11
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;
|
||||
|
110
tbl_layout.c
110
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 (' '):
|
||||
case ' ':
|
||||
/* FALLTHROUGH */
|
||||
case ('\t'):
|
||||
case '\t':
|
||||
/* FALLTHROUGH */
|
||||
case (','):
|
||||
case ',':
|
||||
/* FALLTHROUGH */
|
||||
case ('.'):
|
||||
case '.':
|
||||
/* FALLTHROUGH */
|
||||
case '|':
|
||||
return(1);
|
||||
default:
|
||||
break;
|
||||
@ -115,8 +118,8 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
(*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 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
/* 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 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
|
||||
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 @@ row(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
|
||||
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;
|
||||
}
|
||||
|
47
tbl_opts.c
47
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 @@ opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
* 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 @@ opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
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 @@ opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
* 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 @@ opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Allow us to recover from bad options by continuing to another
|
||||
* parse sequence.
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user