aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2014-12-02 07:34:06 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2014-12-02 07:34:06 +0000
commit81bffeeaab8522951713b1d92166c2c877ceedc3 (patch)
tree95f51dd036cb6d9094d95488706762fc8414d115
parent52c0e9552d2c7c67a39132a9eb3dc5a876a7429e (diff)
downloadsrc-81bffeeaab8522951713b1d92166c2c877ceedc3.tar.gz
src-81bffeeaab8522951713b1d92166c2c877ceedc3.zip
Import CVS version of mandoc as of 20141201vendor/mandoc/20141201
Notes
Notes: svn path=/vendor/mdocml/dist/; revision=275397 svn path=/vendor/mdocml/20141201/; revision=275398; tag=vendor/mandoc/20141201
-rw-r--r--INSTALL93
-rw-r--r--LICENSE8
-rw-r--r--Makefile194
-rw-r--r--Makefile.depend60
-rw-r--r--NEWS5
-rw-r--r--TODO176
-rw-r--r--apropos.1131
-rw-r--r--apropos.c123
-rw-r--r--arch.in112
-rw-r--r--att.c22
-rw-r--r--att.in40
-rw-r--r--cgi.c133
-rw-r--r--chars.c53
-rw-r--r--chars.in230
-rw-r--r--compat_fgetln.c7
-rw-r--r--compat_fts.c826
-rw-r--r--compat_fts.h106
-rw-r--r--compat_getsubopt.c14
-rw-r--r--compat_ohash.c6
-rw-r--r--compat_reallocarray.c4
-rw-r--r--compat_sqlite3_errstr.c4
-rw-r--r--compat_strcasestr.c4
-rw-r--r--compat_strlcat.c4
-rw-r--r--compat_strlcpy.c4
-rw-r--r--compat_strsep.c4
-rw-r--r--config.h.post42
-rw-r--r--config.h.pre9
-rwxr-xr-xconfigure388
-rw-r--r--configure.local.example189
-rw-r--r--demandoc.16
-rw-r--r--demandoc.c11
-rw-r--r--eqn.7250
-rw-r--r--eqn.c1364
-rw-r--r--eqn_html.c189
-rw-r--r--eqn_term.c87
-rw-r--r--example.style.css9
-rw-r--r--html.c159
-rw-r--r--html.h43
-rw-r--r--lib.c6
-rw-r--r--libman.h24
-rw-r--r--libmandoc.h31
-rw-r--r--libmdoc.h44
-rw-r--r--libroff.h28
-rw-r--r--main.c537
-rw-r--r--main.h15
-rw-r--r--makewhatis.86
-rw-r--r--man.1402
-rw-r--r--man.c244
-rw-r--r--man.cgi.812
-rw-r--r--man.h3
-rw-r--r--man_hash.c4
-rw-r--r--man_html.c63
-rw-r--r--man_macro.c171
-rw-r--r--man_term.c77
-rw-r--r--man_validate.c117
-rw-r--r--mandoc.1254
-rw-r--r--mandoc.389
-rw-r--r--mandoc.c37
-rw-r--r--mandoc.db.523
-rw-r--r--mandoc.h68
-rw-r--r--mandoc_aux.c4
-rw-r--r--mandoc_escape.334
-rw-r--r--mandocdb.c186
-rw-r--r--manpage.c11
-rw-r--r--manpath.c55
-rw-r--r--mansearch.c104
-rw-r--r--mansearch.h36
-rw-r--r--mansearch_const.c5
-rw-r--r--mchars_alloc.315
-rw-r--r--mdoc.7175
-rw-r--r--mdoc.c229
-rw-r--r--mdoc_argv.c200
-rw-r--r--mdoc_hash.c4
-rw-r--r--mdoc_html.c181
-rw-r--r--mdoc_macro.c1168
-rw-r--r--mdoc_man.c97
-rw-r--r--mdoc_term.c274
-rw-r--r--mdoc_validate.c839
-rw-r--r--msec.c6
-rw-r--r--msec.in6
-rw-r--r--out.c80
-rw-r--r--out.h8
-rw-r--r--preconv.1157
-rw-r--r--preconv.c458
-rw-r--r--read.c422
-rw-r--r--roff.727
-rw-r--r--roff.c507
-rw-r--r--st.c6
-rw-r--r--st.in9
-rw-r--r--style.css9
-rw-r--r--tbl.762
-rw-r--r--tbl.c6
-rw-r--r--tbl_data.c6
-rw-r--r--tbl_html.c8
-rw-r--r--tbl_layout.c111
-rw-r--r--tbl_opts.c10
-rw-r--r--tbl_term.c30
-rw-r--r--term.c190
-rw-r--r--term.h12
-rw-r--r--term_ascii.c171
-rw-r--r--term_ps.c288
-rw-r--r--test-dirent-namlen.c10
-rw-r--r--test-fts.c42
-rw-r--r--test-getsubopt.c23
-rw-r--r--test-sqlite3.c (renamed from arch.c)44
-rw-r--r--test-wchar.c63
-rw-r--r--tree.c73
-rw-r--r--vol.c36
-rw-r--r--vol.in35
109 files changed, 8314 insertions, 5582 deletions
diff --git a/INSTALL b/INSTALL
index da8eeab9dd4e..31ffaf00c008 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-$Id: INSTALL,v 1.2 2014/08/10 17:22:26 schwarze Exp $
+$Id: INSTALL,v 1.5 2014/08/18 13:27:47 kristaps Exp $
About mdocml, the portable mandoc distribution
----------------------------------------------
@@ -34,19 +34,52 @@ 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".
+You can find the version contained in this distribution tarball
+by running "./configure".
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. If you want to build the CGI program, man.cgi(8), too, run the
+command "echo BUILD_CGI=1 > configure.local". Then run "cp
+cgi.h.examples cgi.h" and edit cgi.h as desired.
-1.1. The SQLite database system, see <http://sqlite.org/>.
+2. Run "./configure".
+This script attempts autoconfiguration of mandoc for your system.
+Read both its standard output and the file "Makefile.local" it
+generates. If anything looks wrong or different from what you
+wish, read the file "configure.local.example", create and edit
+a file "configure.local", and re-run "./configure" until the
+result seems right to you.
+
+3. Run "make".
+Any POSIX-compatible make, in particular both BSD make and GNU make,
+should work. If the build fails, look at "configure.local.example"
+and go back to step 2.
+
+4. Run "make -n install" and check whether everything will be
+installed to the intended places. Otherwise, put some *DIR variables
+into "configure.local" and go back to step 2.
+
+5. Run "sudo make install". If you intend to build a binary
+package using some kind of fake root mechanism, you may need a
+command like "make DESTDIR=... install". Read the *-install targets
+in the "Makefile" to understand how DESTDIR is used.
+
+6. To set up a man.cgi(8) server, read its manual page.
+
+7. To use mandoc(1) as your man(1) formatter, read the "Deployment"
+section below.
+
+
+Understanding mandoc dependencies
+---------------------------------
+The mandoc(1), preconv(1), and demandoc(1) utilities have no external
+dependencies. However, makewhatis(8) and apropos(1) depend on the
+following software:
+
+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
@@ -57,47 +90,16 @@ 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
+If your system does not have them, the bundled compatibility version
+will be used, so you need not worry in that case. But 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>.
+If you run into that problem, set "HAVE_FTS=0" in configure.local.
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
----------------------------------
@@ -130,9 +132,9 @@ 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".
+1. Run "make distclean".
-2. Run "make config.h"
+2. Run "./configure"
3. Read the file "config.log". It shows the compiler commands used
to test the libraries installed on your system and the standard
@@ -140,8 +142,7 @@ 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".
+check that no "#define HAVE_*" differ from your expectations.
Deployment
diff --git a/LICENSE b/LICENSE
index 35072fb2d1ba..db26171c9de9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-$Id: LICENSE,v 1.2 2014/04/23 21:06:41 schwarze Exp $
+$Id: LICENSE,v 1.4 2014/08/21 00:42:38 schwarze Exp $
With the exceptions noted below, all code and documentation
contained in the mdocml toolkit is protected by the Copyright
@@ -37,8 +37,10 @@ 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_fts.c, compat_fts.h,
+compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c,
+man.1:
+Copyright (c) 1989,1990,1993,1994 The Regents of the University of California
compat_fgetln.c:
Copyright (c) 1998 The NetBSD Foundation, Inc.
diff --git a/Makefile b/Makefile
index 47f37a7dffc9..a8255fecc824 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.435 2014/08/10 02:45:04 schwarze Exp $
+# $Id: Makefile,v 1.448 2014/11/28 18:57:31 schwarze Exp $
#
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
# Copyright (c) 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,126 +15,31 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-VERSION = 1.13.1
-
-# === USER SETTINGS ====================================================
-
-# --- user settings relevant for all builds ----------------------------
-
-# Specify this if you want to hard-code the operating system to appear
-# in the lower-left hand corner of -mdoc manuals.
-#
-# CFLAGS += -DOSNAME="\"OpenBSD 5.5\""
-
-# IFF your system supports multi-byte functions (setlocale(), wcwidth(),
-# putwchar()) AND has __STDC_ISO_10646__ (that is, wchar_t is simply a
-# UCS-4 value) should you define USE_WCHAR. If you define it and your
-# system DOESN'T support this, -Tlocale will produce garbage.
-# If you don't define it, -Tlocale is a synonym for -Tacsii.
-#
-CFLAGS += -DUSE_WCHAR
-
-CFLAGS += -g -DHAVE_CONFIG_H
-CFLAGS += -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings
-PREFIX = /usr/local
-BINDIR = $(PREFIX)/bin
-INCLUDEDIR = $(PREFIX)/include/mandoc
-LIBDIR = $(PREFIX)/lib/mandoc
-MANDIR = $(PREFIX)/man
-EXAMPLEDIR = $(PREFIX)/share/examples/mandoc
-
-INSTALL = install
-INSTALL_PROGRAM = $(INSTALL) -m 0555
-INSTALL_DATA = $(INSTALL) -m 0444
-INSTALL_LIB = $(INSTALL) -m 0444
-INSTALL_SOURCE = $(INSTALL) -m 0644
-INSTALL_MAN = $(INSTALL_DATA)
-
-# --- user settings related to database support ------------------------
-
-# Building apropos(1) and makewhatis(8) requires both SQLite3 and fts(3).
-# To avoid those dependencies, comment the following line.
-# Be careful: the fts(3) implementation in glibc is broken on 32bit
-# machines, see: https://sourceware.org/bugzilla/show_bug.cgi?id=15838
-#
-BUILD_TARGETS += db-build
-
-# The remaining settings in this section
-# are only relevant if db-build is enabled.
-# Otherwise, they have no effect either way.
-
-# If your system has manpath(1), uncomment this. This is most any
-# system that's not OpenBSD or NetBSD. If uncommented, apropos(1)
-# and makewhatis(8) will use manpath(1) to get the MANPATH variable.
-#
-#CFLAGS += -DUSE_MANPATH
-
-# On some systems, SQLite3 may be installed below /usr/local.
-# In that case, uncomment the following two lines.
-#
-#CFLAGS += -I/usr/local/include
-#DBLIB += -L/usr/local/lib
-
-# OpenBSD has the ohash functions in libutil.
-# Comment the following line if your system doesn't.
-#
-DBLIB += -lutil
-
-SBINDIR = $(PREFIX)/sbin
-
-# --- user settings related to man.cgi ---------------------------------
-
-# To build man.cgi, copy cgi.h.example to cgi.h, edit it,
-# and enable the following line.
-# Obviously, this requires that db-build is enabled, too.
-#
-#BUILD_TARGETS += cgi-build
-
-# The remaining settings in this section
-# are only relevant if cgi-build is enabled.
-# Otherwise, they have no effect either way.
-
-# If your system does not support static binaries, comment this,
-# for example on Mac OS X.
-#
-STATIC = -static
-
-# Linux requires -pthread for statical linking.
-#
-#STATIC += -pthread
-
-WWWPREFIX = /var/www
-HTDOCDIR = $(WWWPREFIX)/htdocs
-CGIBINDIR = $(WWWPREFIX)/cgi-bin
-
-# === END OF USER SETTINGS =============================================
-
-INSTALL_TARGETS = $(BUILD_TARGETS:-build=-install)
-
-BASEBIN = mandoc preconv demandoc
-DBBIN = apropos makewhatis
+BASEBIN = mandoc demandoc
+DBBIN = makewhatis
CGIBIN = man.cgi
-DBLIB += -lsqlite3
-
-TESTSRCS = test-fgetln.c \
+TESTSRCS = test-dirent-namlen.c \
+ test-fgetln.c \
+ test-fts.c \
test-getsubopt.c \
test-mmap.c \
test-ohash.c \
test-reallocarray.c \
+ test-sqlite3.c \
test-sqlite3_errstr.c \
test-strcasestr.c \
test-strlcat.c \
test-strlcpy.c \
test-strptime.c \
- test-strsep.c
+ test-strsep.c \
+ test-wchar.c
-SRCS = apropos.c \
- arch.c \
- att.c \
+SRCS = att.c \
cgi.c \
chars.c \
compat_fgetln.c \
+ compat_fts.c \
compat_getsubopt.c \
compat_ohash.c \
compat_reallocarray.c \
@@ -187,7 +92,6 @@ SRCS = apropos.c \
term_ascii.c \
term_ps.c \
tree.c \
- vol.c \
$(TESTSRCS)
DISTFILES = INSTALL \
@@ -197,14 +101,12 @@ DISTFILES = INSTALL \
NEWS \
TODO \
apropos.1 \
- arch.in \
- att.in \
cgi.h.example \
chars.in \
+ compat_fts.h \
compat_ohash.h \
- config.h.post \
- config.h.pre \
configure \
+ configure.local.example \
demandoc.1 \
eqn.7 \
example.style.css \
@@ -218,6 +120,7 @@ DISTFILES = INSTALL \
main.h \
makewhatis.8 \
man-cgi.css \
+ man.1 \
man.7 \
man.cgi.8 \
man.h \
@@ -238,7 +141,6 @@ DISTFILES = INSTALL \
mdoc.h \
msec.in \
out.h \
- preconv.1 \
predefs.in \
roff.7 \
st.in \
@@ -246,7 +148,6 @@ DISTFILES = INSTALL \
tbl.3 \
tbl.7 \
term.h \
- vol.in \
$(SRCS)
LIBMAN_OBJS = man.o \
@@ -254,16 +155,14 @@ LIBMAN_OBJS = man.o \
man_macro.o \
man_validate.o
-LIBMDOC_OBJS = arch.o \
- att.o \
+LIBMDOC_OBJS = att.o \
lib.o \
mdoc.o \
mdoc_argv.o \
mdoc_hash.o \
mdoc_macro.o \
mdoc_validate.o \
- st.o \
- vol.o
+ st.o
LIBROFF_OBJS = eqn.o \
roff.o \
@@ -279,9 +178,11 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
mandoc.o \
mandoc_aux.o \
msec.o \
+ preconv.o \
read.o
COMPAT_OBJS = compat_fgetln.o \
+ compat_fts.o \
compat_getsubopt.o \
compat_ohash.o \
compat_reallocarray.o \
@@ -314,11 +215,11 @@ MANDOC_OBJS = $(MANDOC_HTML_OBJS) \
out.o \
tree.o
-MAKEWHATIS_OBJS = mandocdb.o mansearch_const.o manpath.o
+MAN_OBJS = $(MANDOC_OBJS)
-PRECONV_OBJS = preconv.o
+MAKEWHATIS_OBJS = mandocdb.o mansearch_const.o manpath.o
-APROPOS_OBJS = apropos.o mansearch.o mansearch_const.o manpath.o
+APROPOS_OBJS = mansearch.o mansearch_const.o manpath.o
CGI_OBJS = $(MANDOC_HTML_OBJS) \
cgi.o \
@@ -332,8 +233,8 @@ DEMANDOC_OBJS = demandoc.o
WWW_MANS = apropos.1.html \
demandoc.1.html \
+ man.1.html \
mandoc.1.html \
- preconv.1.html \
mandoc.3.html \
mandoc_escape.3.html \
mandoc_html.3.html \
@@ -360,9 +261,13 @@ WWW_MANS = apropos.1.html \
WWW_OBJS = mdocml.tar.gz \
mdocml.sha256
+include Makefile.local
+
+INSTALL_TARGETS = $(BUILD_TARGETS:-build=-install)
+
# === DEPENDENCY HANDLING ==============================================
-all: base-build $(BUILD_TARGETS)
+all: base-build $(BUILD_TARGETS) Makefile.local
base-build: $(BASEBIN)
@@ -374,20 +279,22 @@ install: base-install $(INSTALL_TARGETS)
www: $(WWW_OBJS) $(WWW_MANS)
+$(WWW_MANS): mandoc
+
include Makefile.depend
# === TARGETS CONTAINING SHELL COMMANDS ================================
+distclean: clean
+ rm -f Makefile.local config.h config.h.old config.log config.log.old
+
clean:
- rm -f libmandoc.a $(LIBMANDOC_OBJS)
- rm -f apropos $(APROPOS_OBJS)
+ rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS)
+ rm -f mandoc $(MANDOC_OBJS) $(APROPOS_OBJS)
rm -f makewhatis $(MAKEWHATIS_OBJS)
- rm -f preconv $(PRECONV_OBJS)
rm -f man.cgi $(CGI_OBJS)
rm -f manpage $(MANPAGE_OBJS)
rm -f demandoc $(DEMANDOC_OBJS)
- rm -f mandoc $(MANDOC_OBJS)
- rm -f config.h config.log $(COMPAT_OBJS)
rm -f $(WWW_MANS) $(WWW_OBJS)
rm -rf *.dSYM
@@ -403,7 +310,8 @@ base-install: base-build
$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h \
$(DESTDIR)$(INCLUDEDIR)
- $(INSTALL_MAN) mandoc.1 preconv.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
+ $(INSTALL_MAN) man.1 mandoc.1 demandoc.1 \
+ $(DESTDIR)$(MANDIR)/man1
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
$(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 \
@@ -417,8 +325,8 @@ db-install: db-build
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
+ ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/apropos
+ ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/whatis
$(INSTALL_PROGRAM) makewhatis $(DESTDIR)$(SBINDIR)
$(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1
ln -f $(DESTDIR)$(MANDIR)/man1/apropos.1 \
@@ -447,30 +355,29 @@ www-install: www
$(INSTALL_DATA) mdocml.sha256 \
$(DESTDIR)$(HTDOCDIR)/snapshots/mdocml-$(VERSION).sha256
+Makefile.local config.h: configure ${TESTSRCS}
+ @echo "$@ is out of date; please run ./configure"
+ @exit 1
+
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
+ s|\\\n||g; s| +| |g; s| $$||mg; print;' \
+ Makefile.depend > Makefile.tmp
mv Makefile.tmp Makefile.depend
libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
$(AR) rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
-mandoc: $(MANDOC_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) -o $@ $(MANDOC_OBJS) libmandoc.a
+mandoc: $(MAN_OBJS) libmandoc.a
+ $(CC) $(LDFLAGS) -o $@ $(MAN_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)
-
manpage: $(MANPAGE_OBJS) libmandoc.a
$(CC) $(LDFLAGS) -o $@ $(MANPAGE_OBJS) libmandoc.a $(DBLIB)
-apropos: $(APROPOS_OBJS) libmandoc.a
- $(CC) $(LDFLAGS) -o $@ $(APROPOS_OBJS) libmandoc.a $(DBLIB)
-
man.cgi: $(CGI_OBJS) libmandoc.a
$(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
@@ -482,18 +389,13 @@ mdocml.sha256: mdocml.tar.gz
mdocml.tar.gz: $(DISTFILES)
mkdir -p .dist/mdocml-$(VERSION)/
- $(INSTALL_SOURCE) $(DISTFILES) .dist/mdocml-$(VERSION)
+ $(INSTALL) -m 0644 $(DISTFILES) .dist/mdocml-$(VERSION)
chmod 755 .dist/mdocml-$(VERSION)/configure
( cd .dist/ && tar zcf ../$@ mdocml-$(VERSION) )
rm -rf .dist/
-config.h: configure config.h.pre config.h.post $(TESTSRCS)
- rm -f config.log
- CC="$(CC)" CFLAGS="$(CFLAGS)" DBLIB="$(DBLIB)" \
- VERSION="$(VERSION)" ./configure
-
.PHONY: base-install cgi-install db-install install www-install
-.PHONY: clean depend
+.PHONY: clean distclean depend
.SUFFIXES: .1 .3 .5 .7 .8 .h
.SUFFIXES: .1.html .3.html .5.html .7.html .8.html .h.html
diff --git a/Makefile.depend b/Makefile.depend
index dc49310e5222..d3c13e09cf5e 100644
--- a/Makefile.depend
+++ b/Makefile.depend
@@ -1,24 +1,23 @@
-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
+att.o: att.c config.h mdoc.h libmdoc.h
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
+compat_fgetln.o: compat_fgetln.c config.h
+compat_fts.o: compat_fts.c config.h compat_fts.h
+compat_getsubopt.o: compat_getsubopt.c config.h
+compat_ohash.o: compat_ohash.c config.h compat_ohash.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
+main.o: main.c config.h mandoc.h mandoc_aux.h main.h mdoc.h man.h manpath.h mansearch.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
@@ -27,10 +26,10 @@ 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
+mandocdb.o: mandocdb.c config.h compat_fts.h compat_ohash.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.o: mansearch.c config.h compat_ohash.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
@@ -42,9 +41,9 @@ mdoc_term.o: mdoc_term.c config.h mandoc.h mandoc_aux.h out.h term.h mdoc.h main
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
+preconv.o: preconv.c config.h mandoc.h libmandoc.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
+roff.o: roff.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.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
@@ -56,15 +55,18 @@ 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
+test-dirent-namlen.o: test-dirent-namlen.c
+test-fgetln.o: test-fgetln.c
+test-fts.o: test-fts.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.o: test-sqlite3.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
+test-wchar.o: test-wchar.c
diff --git a/NEWS b/NEWS
index 61006b5ee117..f47a807dadc5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-$Id: NEWS,v 1.5 2014/08/10 16:32:57 schwarze Exp $
+$Id: NEWS,v 1.6 2014/08/11 01:39:00 schwarze Exp $
This file lists the most important changes in the mdocml.bsd.lv distribution.
@@ -7,9 +7,6 @@ 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.
diff --git a/TODO b/TODO
index a41df2988270..98cb687eaa2b 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,37 @@
************************************************************************
* Official mandoc TODO.
-* $Id: TODO,v 1.176 2014/08/09 14:24:53 schwarze Exp $
+* $Id: TODO,v 1.189 2014/11/26 21:40:17 schwarze Exp $
************************************************************************
+Many issues are annotated for difficulty as follows:
+
+ - loc = locality of the issue
+ * single file issue, affects file only, or very few
+ ** single module issue, affects several files of one module
+ *** cross-module issue, significantly impacts multiple modules
+ and may require substantial changes to internal interfaces
+ - exist = difficulty of the existing code in this area
+ * affected code is straightforward and easy to read and change
+ ** affected code is somewhat complex, but once you understand
+ the design, not particularly difficult to understand
+ *** affected code uses a special, exceptionally tricky design
+ - algo = difficulty of the new algorithm to be written
+ * the required logic and code is straightforward
+ ** the required logic is somewhat complex and needs a careful design
+ *** the required logic is exceptionally tricky,
+ maybe an approach to solve that is not even known yet
+ - size = the amount of code to be written or changed
+ * a small number of lines (at most 100, usually much less)
+ ** a considerable amount of code (several dozen to a few hundred)
+ *** a large amount of code (many hundreds, maybe thousands)
+ - imp = importance of the issue
+ * mostly for completeness
+ ** would be nice to have
+ *** issue causes considerable inconvenience
+
+Obviously, as the issues have not been solved yet, these annotations
+are mere guesses, and some may be wrong.
+
************************************************************************
* crashes
************************************************************************
@@ -10,6 +39,7 @@
- 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.
+ loc ** exist * algo * size ** imp **
************************************************************************
* missing features
@@ -25,49 +55,62 @@
.na -- temporarily disable adjustment without changing the mode
.ad -- re-enable adjustment without changing the mode
Adjustment mode is ignored while in no-fill mode (.nf).
+ loc *** exist *** algo ** size ** imp ** (parser reorg would help)
- .fc (field control)
found by naddy@ in xloadimage(1)
+ loc ** exist *** algo * size * imp *
- .nr third argument (auto-increment step size, requires \n+)
found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
+ loc * exist * algo * size * imp **
- .ns (no-space mode) occurs in xine-config(1)
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
+ loc *** exist *** algo *** size ** imp *
- .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
+ loc ** exist *** algo ** size ** imp **
- .ti (temporary indent)
found by naddy@ in xloadimage(1)
found by bentley@ in nmh(1) Mon, 23 Apr 2012 13:38:28 -0600
+ loc ** exist ** algo ** size * imp ** (parser reorg helps a lot)
- .while and .shift
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
+ loc * exist ** algo ** size ** imp **
- \c (interrupted text) should prevent the line break
even inside .Bd literal; that occurs in chat(8)
also found in cclive(1) - DocBook output
+ loc ** exist *** algo ** size * imp *
- \h horizontal move
found in cclive(1) DocBook output
Anthony J. Bentley on discuss@ Sat, 21 Sep 2013 22:29:34 -0600
+ loc ** exist ** algo ** size * imp ** (parser reorg helps a lot)
- \n+ and \n- numerical register increment and decrement
found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
+ loc * exist * algo * size * imp **
-- \w'' width measurements
+- \w'' improve 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
+ loc ** exist *** algo *** size * imp ***
- using undefined strings or macros defines them to be empty
wl@ Mon, 14 Nov 2011 14:37:01 +0000
+ loc * exist * algo * size * imp *
--- missing mdoc features ----------------------------------------------
- fix bad block nesting involving multiple identical explicit blocks
see the OpenBSD mdoc_macro.c 1.47 commit message
+ loc * exist *** algo *** size * imp **
- .Bl -column .Xo support is missing
ultimate goal:
@@ -75,10 +118,12 @@
lib/libc/compat-43/sigvec.3
lib/libc/gen/signal.3
lib/libc/sys/sigaction.2
+ loc * exist *** algo *** size * imp **
- edge case: decide how to deal with blk_full bad nesting, e.g.
.Sh .Nm .Bk .Nm .Ek .Sh found by jmc@ in ssh-keygen(1)
from jmc@ Wed, 14 Jul 2010 18:10:32 +0100
+ loc * exist *** algo *** size ** imp **
- \\ is now implemented correctly
* when defining strings and macros using .ds and .de
@@ -92,18 +137,22 @@
we don't have either.
Besides, groff has bug causing text right *before* .Bd -centered
to be centered as well.
+ loc *** exist *** algo ** size ** imp ** (parser reorg would help)
- .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).
+ loc *** exist *** algo ** size ** imp ** (parser reorg would help)
- implement blank `Bl -column', such as
.Bl -column
.It foo Ta bar
.El
+ loc * exist *** algo *** size * imp *
- explicitly disallow nested `Bl -column', which would clobber internal
flags defined for struct mdoc_macro
+ loc * exist * algo * size * imp **
- In .Bl -column .It, the end of the line probably has to be regarded
as an implicit .Ta, if there could be one, see the following mildly
@@ -114,6 +163,7 @@
Default search path.
reported by Michal Mazurek <akfaew at jasminek dot net>
via jmc@ Thu, 7 Apr 2011 16:00:53 +0059
+ loc * exist *** algo ** size * imp **
- inside `.Bl -column' phrases, punctuation is handled like normal
text, e.g. `.Bl -column .It Fl x . Ta ...' should give "-x -."
@@ -123,11 +173,14 @@
but should give "ab ."
- set a meaningful default if no `Bl' list type is assigned
+ loc * exist * algo * size * imp ** (already done?)
- have a blank `It' head for `Bl -tag' not puke
+ loc * exist * algo * size * imp ** (already done?)
- check whether it is correct that `D1' uses INDENT+1;
does it need its own constant?
+ loc * exist ** algo ** size * imp **
- prohibit `Nm' from having non-text HEAD children
(e.g., NetBSD mDNSShared/dns-sd.1)
@@ -138,6 +191,7 @@
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
+ loc ** exist ** algo ** size * imp **
- 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
@@ -146,6 +200,7 @@
should be, needs investigation.
uqs@ Thu, 2 Jun 2011 11:03:51 +0200
uqs@ Thu, 2 Jun 2011 11:33:35 +0200
+ loc * exist ** algo *** size * imp **
--- missing man features -----------------------------------------------
@@ -155,18 +210,36 @@
- look at the POSIX manuals in the books/man-pages-posix port,
they use some unsupported tbl(7) features.
+ loc * exist ** algo ** size ** imp ***
-- investigate tbl(1) errors in sox(1)
- see also naddy@ Sat, 16 Oct 2010 23:51:57 +0200
+- use Unicode U+2500 to U+256C for table borders
+ in tbl(7) -Tutf-8 output
+ suggested by bentley@ Tue, 14 Oct 2014 04:10:55 -0600
+ loc * exist ** algo * size * imp **
- allow standalone `.' to be interpreted as an end-of-layout
delimiter instead of being thrown away as a no-op roff line
reported by Yuri Pankov, Wed 18 May 2011 11:34:59 CEST
+ loc ** exist ** algo ** size * imp **
+
+--- missing eqn features -----------------------------------------------
+
+- The "size" keyword is parsed, but ignored by the formatter.
+ loc * exist * algo * size * imp *
+
+- The spacing characters `~', `^', and tab are currently ignored,
+ see User's Guide (Second Edition) page 2 section 4.
+ loc * exist * algo ** size * imp **
+
+- Mark and lineup are parsed and ignored,
+ see User's Guide (Second Edition) page 5 section 15.
+ loc ** exist ** algo ** size ** imp **
--- missing misc features ----------------------------------------------
- italic correction (\/) in PostScript mode
Werner LEMBERG on groff at gnu dot org Sun, 10 Nov 2013 12:47:46
+ loc ** exist ** algo * size * imp *
- When makewhatis(8) encounters a FATAL parse error,
it silently treats the file as formatted, which makes no sense
@@ -174,13 +247,16 @@
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.
+ loc * exist * algo * size * imp **
- makewhatis(8) for preformatted pages:
parse the section number from the header line
and compare to the section number from the directory name
+ loc * exist * algo * size * imp **
- Does makewhatis(8) detect missing NAME sections, missing names,
and missing descriptions in all the file formats?
+ loc * exist * algo * size * imp ***
- clean up escape sequence handling, creating three classes:
(1) fully implemented, or parsed and ignored without loss of content
@@ -188,8 +264,10 @@
or serious mangling of formatting (e.g. \n) -> ERROR
see textproc/mgdiff(1) for nice examples
(3) undefined, just output the character -> perhaps WARNING
+ loc *** exist ** algo ** size ** imp *** (parser reorg helps)
- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET)
+ loc ** exist ** algo ** size *** imp *
--- compatibility checks -----------------------------------------------
@@ -199,6 +277,10 @@
- compare output to Heirloom roff, Solaris roff, and
http://repo.or.cz/w/neatroff.git http://litcave.rudi.ir/
+- look at AT&T DWB http://www2.research.att.com/sw/download
+ Carsten Kunze <carsten dot kunze at arcor dot de> has patches
+ Mon, 4 Aug 2014 17:01:28 +0200
+
- 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.
@@ -224,6 +306,11 @@
- check compatibility with the man(7) formatter
https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c
+- check compatibility with
+ http://ikiwiki.info/plugins/contrib/mandoc/
+ https://github.com/schmonz/ikiwiki/compare/mandoc
+ Amitai Schlair Mon, 19 May 2014 14:05:53 -0400
+
************************************************************************
* formatting issues: ugly output
************************************************************************
@@ -236,10 +323,12 @@
ought to render "Key Length" with emphasis, too,
see OpenBSD iked.conf(5).
reported again Nicolas Joly via wiz@ Wed, 12 Oct 2011 00:20:00 +0200
+ loc * exist *** algo *** size ** imp ***
- empty phrases in .Bl column produce too few blanks
try e.g. .Bl -column It Ta Ta
reported by millert Fri, 02 Apr 2010 16:13:46 -0400
+ loc * exist *** algo *** size * imp **
- .%T can have trailing punctuation. Currently, it puts the trailing
punctuation into a trailing MDOC_TEXT element inside its own scope.
@@ -249,11 +338,13 @@
slurp all arguments into one single text element - and one feature
of in_line() - put trailing punctuation out of scope.
Found in mount_nfs(8) and exports(5), search for "Appendix".
+ loc ** exist ** algo *** size * imp **
- Trailing punctuation after .%T triggers EOS spacing, at least
outside .Rs (eek!). Simply setting ARGSFL_DELIM for .%T is not
the right solution, it sends mandoc into an endless loop.
reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100
+ loc * exist ** algo ** size * imp **
- global variables in the SYNOPSIS of section 3 pages
.Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ...
@@ -261,6 +352,7 @@
- in enclosures, mandoc sometimes fancies a bogus end of sentence
reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059
+ loc * exist ** algo *** size * imp ***
- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc
reveals lots of bugs both in groff and mandoc...
@@ -273,6 +365,10 @@
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
+ instructions from juanfra@ Wed, 11 Jun 2014 02:21:01 +0200
+ add a new <</Type /Font>> block to the PDF files with /BaseFont /Courier
+ and change the /Name from /F0 to the new font (/F5 (?)).
+ loc * exist ** algo ** size * imp **
--- HTML issues --------------------------------------------------------
@@ -280,6 +376,20 @@
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
+ loc * exist * algo ** size * imp ***
+
+- jsg on icb, Nov 3, 2014:
+ try to guess Xr in man(7) for hyperlinking
+
+- The tables used to render the three-part page headers actually force
+ the width of the <body> to the max-width given for <html>.
+ Not yet sure how to fix that...
+ Observed by an Anonymous Coward on undeadly.org:
+ http://undeadly.org/cgi?action=article&sid=20140925064244&pid=1
+ loc * exist * algo ** size * imp ***
+
+- consider whether <var> can be used for Ar Dv Er Ev Fa Va.
+ from bentley@ Wed, 13 Aug 2014 09:17:55 -0600
- check https://github.com/trentm/mdocml
@@ -287,42 +397,57 @@
* formatting issues: gratuitous differences
************************************************************************
+- .Fn reopens a new scope after punctuation in mandoc,
+ but closes its scope for good in groff.
+ Do we want to change mandoc or groff?
+ Steffen Nurpmeso Sat, 08 Nov 2014 13:34:59 +0100
+ loc * exist ** algo ** size * imp **
+
- .Rv (and probably .Ex) print different text if an `Nm' has been named
or not (run a manual without `Nm blah' to see this). I'm not sure
that this exists in the wild, but it's still an error.
+ loc * exist * algo * size * imp * (already done?)
- In .Bl -bullet, the groff bullet is "+\b+\bo\bo", the mandoc bullet
- is just "o\bo".
+ is just "o\bo". The problem is to not break ps/pdf when fixing.
see for example OpenBSD ksh(1)
+ loc ** exist ** algo ** size * imp **
- 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
+ loc * exist ** algo ** size * imp **
- .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
reported again by sthen@ Wed, 18 Jan 2012 02:09:39 +0000 (UTC)
+ loc * exist *** algo ** size * imp **
- If the *first* line after .It is .Pp, break the line right after
the tag, do not pad with space characters before breaking.
See the description of the a, c, and i commands in sed(1).
+ loc * exist ** algo ** size * imp **
- If the first line after .It is .D1, do not assert a blank line
in between, see for example tmux(1).
reported by nicm@ 13 Jan 2011 00:18:57 +0000
+ loc * exist ** algo ** size * imp **
- Trailing punctuation after .It should trigger EOS spacing.
reported by Nicolas Joly Sat, 17 Nov 2012 11:49:54 +0100
Probably, this should be fixed somewhere in termp_it_pre(), not sure.
+ loc * exist ** algo ** size * imp **
- .Nx 1.0a
should be "NetBSD 1.0A", not "NetBSD 1.0a",
see OpenBSD ccdconfig(8).
+ loc * exist * algo * size * imp **
- In .Bl -tag, if a tag exceeds the right margin and must be continued
on the next line, it must be indented by -width, not width+1;
see "rule block|pass" in OpenBSD ifconfig(8).
+ loc * exist *** algo ** size * imp **
- When the -width string contains macros, the macros must be rendered
before measuring the width, for example
@@ -332,17 +457,21 @@
The same applies to .Bl -column column widths;
reported again by Nicolas Joly Thu, 1 Mar 2012 13:41:26 +0100 via wiz@ 5 Mar
reported again by Franco Fichtner Fri, 27 Sep 2013 21:02:28 +0200
+ loc *** exist *** algo *** size ** imp ***
An easy partial fix would be to just skip the first word if it starts
with a dot, including any following white space, when measuring.
+ loc * exist * algo * size * imp ***
- The \& zero-width character counts as output.
That is, when it is alone on a line between two .Pp,
we want three blank lines, not two as in mandoc.
+ loc ** exist ** algo ** size * imp **
- Header lines of excessive length:
Port OpenBSD man_term.c rev. 1.25 to mdoc_term.c
and document it in mdoc(7) and man(7) COMPATIBILITY
found while talking to Chris Bennett
+ loc * exist * algo * size * imp *
- trailing whitespace must be ignored even when followed by a font escape,
see for example
@@ -350,6 +479,7 @@
\fBdig \fR
operate in batch mode
in dig(1).
+ loc ** exist ** algo ** size * imp **
************************************************************************
* warning issues
@@ -361,17 +491,29 @@
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)
+ loc * exist ** algo ** size * imp **
+
+- warn about attempts to call non-callable macros
+ Steffen Nurpmeso Tue, 11 Nov 2014 22:55:16 +0100
+ Note that formatting is inconsistent in groff.
+ .Fn Po prints "Po()", .Ar Sh prints "file ..." and no "Sh".
+ Relatively hard because the relevant code is scattered
+ all over mdoc_macro.c and all subtly different.
+ loc ** exist ** algo ** size ** imp **
- warn about "new sentence, new line"
+ loc ** exist ** algo *** size * imp **
- mandoc_special does not really check the escape sequence,
but just the overall format
+ loc ** exist ** algo *** size ** imp **
- 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
+ (mostly done, check what remains)
- -Tlint parser errors and warnings to stdout
to tech@mdocml, naddy@ Wed, 28 Sep 2011 11:21:46 +0200
@@ -395,6 +537,9 @@
- mention /usr/share/misc/mdoc.template in mdoc(7)?
+- Is all the content from http://www.std.com/obi/BSD/doc/usd/28.tbl/tbl
+ covered in tbl(7)?
+
************************************************************************
* performance issues
************************************************************************
@@ -413,11 +558,15 @@ Several areas can be cleaned up to make mandoc even faster. These are
- instead of re-initialising the roff predefined-strings set before each
parse, create a read-only version the first time and copy it
+ loc * exist ** algo ** size * imp **
************************************************************************
* structural issues
************************************************************************
+- Use libz directly instead of forking gunzip(1).
+ Suggested by bapt at FreeBSD among others.
+
- We use the input line number at several places to distinguish
same-line from different-line input. That plainly doesn't work
with user-defined macros, leading to random breakage.
@@ -430,8 +579,25 @@ Several areas can be cleaned up to make mandoc even faster. These are
Update both mdoc(7) and man(7) documentation.
Triggered by Tim van der Molen Tue, 22 Feb 2011 20:30:45 +0100
+- struct mparse refactoring
+ Steffen Nurpmeso Thu, 04 Sep 2014 12:50:00 +0200
+
- 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
+************************************************************************
+* CGI issues
+************************************************************************
+
+ - Enable HTTP compression by detecting gzip encoding and filtering
+ output through libz.
+ - Sandbox (see OpenSSH).
+ - Enable caching support via HTTP 304 and If-Modified-Since.
+ - Allow for cgi.h to be overridden by CGI environment variables.
+ Otherwise, binary distributions will inherit the compile-time
+ behaviour, which is not optimal.
+ - Have Mac OSX systems automatically disable -static compilation of the
+ CGI: -static isn't supported.
+
diff --git a/apropos.1 b/apropos.1
index 14682420ff00..e2075349f553 100644
--- a/apropos.1
+++ b/apropos.1
@@ -1,4 +1,4 @@
-.\" $Id: apropos.1,v 1.29 2014/04/24 00:28:19 schwarze Exp $
+.\" $Id: apropos.1,v 1.36 2014/10/25 01:03:52 schwarze Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012, 2014 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: April 24 2014 $
+.Dd $Mdocdate: October 25 2014 $
.Dt APROPOS 1
.Os
.Sh NAME
@@ -24,6 +24,7 @@
.Nd search manual page databases
.Sh SYNOPSIS
.Nm
+.Op Fl acfhklVw
.Op Fl C Ar file
.Op Fl M Ar path
.Op Fl m Ar path
@@ -41,7 +42,7 @@ utilities query manual page databases generated by
evaluating
.Ar expression
for each file in each database.
-By default, it displays the names, section numbers, and description lines
+By default, they display the names, section numbers, and description lines
of all matching manuals.
.Pp
By default,
@@ -56,17 +57,82 @@ over manual names and descriptions
.Pq the Li \&Nm No and Li \&Nd No macro keys .
Multiple terms imply pairwise
.Fl o .
+.Pp
.Nm whatis
-maps terms only to case-sensitive manual names.
+is a synonym for
+.Nm
+.Fl f .
.Pp
-Its arguments are as follows:
+The options are as follows:
.Bl -tag -width Ds
+.It Fl a
+Instead of showing only the title lines, show the complete manual pages,
+just like
+.Xr man 1
+.Fl a
+would.
+If the standard output is a terminal device and
+.Fl c
+is not specified, use
+.Xr more 1
+to paginate them.
+In
+.Fl a
+mode, the options
+.Fl IKOTW
+described in the
+.Xr mandoc 1
+manual are also available.
.It Fl C Ar file
Specify an alternative configuration
.Ar file
in
.Xr man.conf 5
format.
+.It Fl c
+In
+.Fl a
+mode, copy the formatted manual pages to the standard output without using
+.Xr more 1
+to paginate them.
+.It Fl f
+Search for all words in
+.Ar expression
+in manual page names only.
+The search is case insensitive and matches whole words only.
+In this mode, macro keys, comparison operators, and logical operators
+are not available.
+This overrides any earlier
+.Fl k
+and
+.Fl l
+options.
+.It Fl h
+Instead of showing the title lines, show the SYNOPSIS sections, just like
+.Xr man 1
+.Fl h
+would.
+.It Fl k
+Support the full
+.Ar expression
+syntax.
+This overrides any earlier
+.Fl f
+and
+.Fl l
+options.
+It is the default for
+.Nm .
+.It Fl l
+An alias for
+.Xr mandoc 1
+.Fl a .
+This overrides any earlier
+.Fl f ,
+.Fl k ,
+and
+.Fl w
+options.
.It Fl M Ar path
Use the colon-separated path instead of the default list of paths
searched for
@@ -96,6 +162,14 @@ By default, pages from all sections are shown.
See
.Xr man 1
for a listing of sections.
+.It Fl V
+Print version and exit.
+.It Fl w
+Instead of showing title lines, show the pathnames of the matching
+manual pages, just like
+.Xr man 1
+.Fl w
+would.
.El
.Pp
An
@@ -165,11 +239,6 @@ is evaluated case-insensitively.
Has no effect on substring terms.
.El
.Pp
-.Nm whatis
-considers an
-.Ar expression
-to consist of an opaque keyword.
-.Pp
Results are sorted by manual sections and names, with output formatted as
.Pp
.D1 name[, name...](sec) \- description
@@ -270,7 +339,12 @@ Text production:
.It Li \&Dx Ta Dx No version reference
.El
.Sh ENVIRONMENT
-.Bl -tag -width MANPATH
+.Bl -tag -width MANPAGER
+.It Ev MANPAGER
+Any non-empty value of the environment variable
+.Ev MANPAGER
+will be used instead of the standard pagination program,
+.Xr more 1 .
.It Ev MANPATH
The standard search path used by
.Xr man 1
@@ -288,6 +362,13 @@ 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.
+.It Ev PAGER
+Specifies the pagination program to use when
+.Ev MANPAGER
+is not defined.
+If neither PAGER nor MANPAGER is defined,
+.Pa /usr/bin/more Fl s
+will be used.
.El
.Sh FILES
.Bl -tag -width "/etc/man.conf" -compact
@@ -349,11 +430,19 @@ The following two invocations are equivalent:
.Xr re_format 7 ,
.Xr makewhatis 8
.Sh HISTORY
-An
+Part of the functionality of
+.Nm whatis
+was already provided by the former
+.Nm manwhere
+utility in
+.Bx 1 .
+The
.Nm
-utility first appeared in
+and
+.Nm whatis
+utilities first appeared in
.Bx 2 .
-It was rewritten from scratch for
+They were rewritten from scratch for
.Ox 5.6 .
.Pp
The
@@ -373,13 +462,23 @@ and
and
.Fl s
in
-.Ox 4.5 .
+.Ox 4.5
+for
+.Nm
+and in
+.Ox 5.6
+for
+.Nm whatis .
.Sh AUTHORS
.An -nosplit
.An Bill Joy
-wrote the original
+wrote
+.Nm manwhere
+in 1977 and the original
.Bx
.Nm
+and
+.Nm whatis
in February 1979.
The current version was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
diff --git a/apropos.c b/apropos.c
deleted file mode 100644
index 80b6bc6d036e..000000000000
--- a/apropos.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* $Id: apropos.c,v 1.39 2014/04/20 16:46:04 schwarze Exp $ */
-/*
- * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <sys/param.h>
-
-#include <assert.h>
-#include <getopt.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "manpath.h"
-#include "mansearch.h"
-
-
-int
-main(int argc, char *argv[])
-{
- int ch, whatis;
- struct mansearch search;
- size_t i, sz;
- struct manpage *res;
- struct manpaths paths;
- char *defpaths, *auxpaths;
- char *conf_file;
- char *progname;
- const char *outkey;
- extern char *optarg;
- extern int optind;
-
- progname = strrchr(argv[0], '/');
- if (progname == NULL)
- progname = argv[0];
- else
- ++progname;
-
- whatis = (0 == strncmp(progname, "whatis", 6));
-
- memset(&paths, 0, sizeof(struct manpaths));
- memset(&search, 0, sizeof(struct mansearch));
-
- auxpaths = defpaths = NULL;
- conf_file = NULL;
- outkey = "Nd";
-
- while (-1 != (ch = getopt(argc, argv, "C:M:m:O:S:s:")))
- switch (ch) {
- case 'C':
- conf_file = optarg;
- break;
- case 'M':
- defpaths = optarg;
- break;
- case 'm':
- auxpaths = optarg;
- break;
- case 'O':
- outkey = optarg;
- break;
- case 'S':
- search.arch = optarg;
- break;
- case 's':
- search.sec = optarg;
- break;
- default:
- goto usage;
- }
-
- argc -= optind;
- argv += optind;
-
- if (0 == argc)
- goto usage;
-
- search.deftype = whatis ? TYPE_Nm : TYPE_Nm | TYPE_Nd;
- search.flags = whatis ? MANSEARCH_WHATIS : 0;
-
- manpath_parse(&paths, conf_file, defpaths, auxpaths);
- mansearch_setup(1);
- ch = mansearch(&search, &paths, argc, argv, outkey, &res, &sz);
- manpath_free(&paths);
-
- if (0 == ch)
- goto usage;
-
- for (i = 0; i < sz; i++) {
- printf("%s - %s\n", res[i].names,
- NULL == res[i].output ? "" : res[i].output);
- free(res[i].file);
- free(res[i].names);
- free(res[i].output);
- }
-
- free(res);
- mansearch_setup(0);
- return(sz ? EXIT_SUCCESS : EXIT_FAILURE);
-usage:
- fprintf(stderr, "usage: %s [-C file] [-M path] [-m path] "
- "[-O outkey] "
- "[-S arch] [-s section]%s ...\n", progname,
- whatis ? " name" : "\n expression");
- return(EXIT_FAILURE);
-}
diff --git a/arch.in b/arch.in
deleted file mode 100644
index a22ffd58ba7b..000000000000
--- a/arch.in
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $Id: arch.in,v 1.15 2014/04/27 22:42:15 schwarze Exp $ */
-/*
- * Copyright (c) 2009 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.
- */
-
-/*
- * This file defines the architecture token of the .Dt prologue macro.
- * All architectures that your system supports (or the manuals of your
- * system) should be included here. The right-hand-side is the
- * formatted output.
- *
- * Be sure to escape strings.
- *
- * REMEMBER TO ADD NEW ARCHITECTURES TO MDOC.7!
- */
-
-LINE("acorn26", "Acorn26")
-LINE("acorn32", "Acorn32")
-LINE("algor", "Algor")
-LINE("alpha", "Alpha")
-LINE("amd64", "AMD64")
-LINE("amiga", "Amiga")
-LINE("amigappc", "AmigaPPC")
-LINE("arc", "ARC")
-LINE("arm", "ARM")
-LINE("arm26", "ARM26")
-LINE("arm32", "ARM32")
-LINE("armish", "ARMISH")
-LINE("armv7", "ARMv7")
-LINE("aviion", "AViiON")
-LINE("atari", "ATARI")
-LINE("bebox", "BeBox")
-LINE("cats", "cats")
-LINE("cesfic", "CESFIC")
-LINE("cobalt", "Cobalt")
-LINE("dreamcast", "Dreamcast")
-LINE("emips", "EMIPS")
-LINE("evbarm", "evbARM")
-LINE("evbmips", "evbMIPS")
-LINE("evbppc", "evbPPC")
-LINE("evbsh3", "evbSH3")
-LINE("ews4800mips", "EWS4800MIPS")
-LINE("hp300", "HP300")
-LINE("hp700", "HP700")
-LINE("hpcarm", "HPCARM")
-LINE("hpcmips", "HPCMIPS")
-LINE("hpcsh", "HPCSH")
-LINE("hppa", "HPPA")
-LINE("hppa64", "HPPA64")
-LINE("ia64", "ia64")
-LINE("i386", "i386")
-LINE("ibmnws", "IBMNWS")
-LINE("iyonix", "Iyonix")
-LINE("landisk", "LANDISK")
-LINE("loongson", "Loongson")
-LINE("luna68k", "LUNA68K")
-LINE("luna88k", "LUNA88K")
-LINE("m68k", "m68k")
-LINE("mac68k", "Mac68k")
-LINE("macppc", "MacPPC")
-LINE("mips", "MIPS")
-LINE("mips64", "MIPS64")
-LINE("mipsco", "MIPSCo")
-LINE("mmeye", "mmEye")
-LINE("mvme68k", "MVME68k")
-LINE("mvme88k", "MVME88k")
-LINE("mvmeppc", "MVMEPPC")
-LINE("netwinder", "NetWinder")
-LINE("news68k", "NeWS68k")
-LINE("newsmips", "NeWSMIPS")
-LINE("next68k", "NeXT68k")
-LINE("octeon", "OCTEON")
-LINE("ofppc", "OFPPC")
-LINE("palm", "Palm")
-LINE("pc532", "PC532")
-LINE("playstation2", "PlayStation2")
-LINE("pmax", "PMAX")
-LINE("pmppc", "pmPPC")
-LINE("powerpc", "PowerPC")
-LINE("prep", "PReP")
-LINE("rs6000", "RS6000")
-LINE("sandpoint", "Sandpoint")
-LINE("sbmips", "SBMIPS")
-LINE("sgi", "SGI")
-LINE("sgimips", "SGIMIPS")
-LINE("sh3", "SH3")
-LINE("shark", "Shark")
-LINE("socppc", "SOCPPC")
-LINE("solbourne", "Solbourne")
-LINE("sparc", "SPARC")
-LINE("sparc64", "SPARC64")
-LINE("sun2", "Sun2")
-LINE("sun3", "Sun3")
-LINE("tahoe", "Tahoe")
-LINE("vax", "VAX")
-LINE("x68k", "X68k")
-LINE("x86", "x86")
-LINE("x86_64", "x86_64")
-LINE("xen", "Xen")
-LINE("zaurus", "Zaurus")
diff --git a/att.c b/att.c
index 059639af37aa..a1703ebcc662 100644
--- a/att.c
+++ b/att.c
@@ -1,4 +1,4 @@
-/* $Id: att.c,v 1.11 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: att.c,v 1.13 2014/11/28 18:57:31 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,24 +14,36 @@
* 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 <string.h>
#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
- if (0 == strcmp(p, x)) return(y);
+ if (0 == strcmp(p, x)) return(y)
const char *
mdoc_a2att(const char *p)
{
-#include "att.in"
+ LINE("v1", "Version\\~1 AT&T UNIX");
+ LINE("v2", "Version\\~2 AT&T UNIX");
+ LINE("v3", "Version\\~3 AT&T UNIX");
+ LINE("v4", "Version\\~4 AT&T UNIX");
+ LINE("v5", "Version\\~5 AT&T UNIX");
+ LINE("v6", "Version\\~6 AT&T UNIX");
+ LINE("v7", "Version\\~7 AT&T UNIX");
+ LINE("32v", "Version\\~32V AT&T UNIX");
+ LINE("III", "AT&T System\\~III UNIX");
+ LINE("V", "AT&T System\\~V UNIX");
+ LINE("V.1", "AT&T System\\~V Release\\~1 UNIX");
+ LINE("V.2", "AT&T System\\~V Release\\~2 UNIX");
+ LINE("V.3", "AT&T System\\~V Release\\~3 UNIX");
+ LINE("V.4", "AT&T System\\~V Release\\~4 UNIX");
return(NULL);
}
diff --git a/att.in b/att.in
deleted file mode 100644
index b4ef822158f8..000000000000
--- a/att.in
+++ /dev/null
@@ -1,40 +0,0 @@
-/* $Id: att.in,v 1.8 2011/07/31 17:30:33 schwarze Exp $ */
-/*
- * Copyright (c) 2009 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.
- */
-
-/*
- * This file defines the AT&T versions of the .At macro. This probably
- * isn't going to change. The right-hand side is the formatted string.
- *
- * Be sure to escape strings.
- * The non-breaking blanks prevent ending an output line right before
- * a number. Groff prevent line breaks at the same places.
- */
-
-LINE("v1", "Version\\~1 AT&T UNIX")
-LINE("v2", "Version\\~2 AT&T UNIX")
-LINE("v3", "Version\\~3 AT&T UNIX")
-LINE("v4", "Version\\~4 AT&T UNIX")
-LINE("v5", "Version\\~5 AT&T UNIX")
-LINE("v6", "Version\\~6 AT&T UNIX")
-LINE("v7", "Version\\~7 AT&T UNIX")
-LINE("32v", "Version\\~32V AT&T UNIX")
-LINE("III", "AT&T System\\~III UNIX")
-LINE("V", "AT&T System\\~V UNIX")
-LINE("V.1", "AT&T System\\~V Release\\~1 UNIX")
-LINE("V.2", "AT&T System\\~V Release\\~2 UNIX")
-LINE("V.3", "AT&T System\\~V Release\\~3 UNIX")
-LINE("V.4", "AT&T System\\~V Release\\~4 UNIX")
diff --git a/cgi.c b/cgi.c
index 1e38e3d872a5..65064ab2ad6c 100644
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-/* $Id: cgi.c,v 1.92 2014/08/05 15:29:30 schwarze Exp $ */
+/* $Id: cgi.c,v 1.102 2014/11/26 17:55:27 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@usta.de>
@@ -15,9 +15,10 @@
* 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 <sys/time.h>
#include <ctype.h>
#include <errno.h>
@@ -91,14 +92,14 @@ static const char *const sec_names[] = {
"All Sections",
"1 - General Commands",
"2 - System Calls",
- "3 - Subroutines",
- "3p - Perl Subroutines",
- "4 - Special Files",
+ "3 - Library Functions",
+ "3p - Perl Library",
+ "4 - Device Drivers",
"5 - File Formats",
"6 - Games",
- "7 - Macros and Conventions",
- "8 - Maintenance Commands",
- "9 - Kernel Interface"
+ "7 - Miscellaneous Information",
+ "8 - System Manager\'s Manual",
+ "9 - Kernel Developer\'s Manual"
};
static const int sec_MAX = sizeof(sec_names) / sizeof(char *);
@@ -162,8 +163,7 @@ http_printquery(const struct req *req, const char *sep)
printf("%sarch=", sep);
http_print(req->q.arch);
}
- if (NULL != req->q.manpath &&
- strcmp(req->q.manpath, req->p[0])) {
+ if (strcmp(req->q.manpath, req->p[0])) {
printf("%smanpath=", sep);
http_print(req->q.manpath);
}
@@ -297,11 +297,6 @@ next:
if (*qs != '\0')
qs++;
}
-
- /* Fall back to the default manpath. */
-
- if (req->q.manpath == NULL)
- req->q.manpath = mandoc_strdup(req->p[0]);
}
static void
@@ -375,13 +370,10 @@ resp_begin_html(int code, const char *msg)
resp_begin_http(code, msg);
- printf("<!DOCTYPE HTML PUBLIC "
- " \"-//W3C//DTD HTML 4.01//EN\""
- " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
+ printf("<!DOCTYPE html>\n"
"<HTML>\n"
"<HEAD>\n"
- "<META HTTP-EQUIV=\"Content-Type\""
- " CONTENT=\"text/html; charset=utf-8\">\n"
+ "<META CHARSET=\"UTF-8\" />\n"
"<LINK REL=\"stylesheet\" HREF=\"%s/man-cgi.css\""
" TYPE=\"text/css\" media=\"all\">\n"
"<LINK REL=\"stylesheet\" HREF=\"%s/man.css\""
@@ -471,8 +463,7 @@ resp_searchform(const struct req *req)
puts("<SELECT NAME=\"manpath\">");
for (i = 0; i < (int)req->psz; i++) {
printf("<OPTION ");
- if (NULL == req->q.manpath ? 0 == i :
- 0 == strcmp(req->q.manpath, req->p[i]))
+ if (strcmp(req->q.manpath, req->p[i]) == 0)
printf("SELECTED=\"selected\" ");
printf("VALUE=\"");
html_print(req->p[i]);
@@ -826,6 +817,7 @@ static void
format(const struct req *req, const char *file)
{
struct mparse *mp;
+ struct mchars *mchars;
struct mdoc *mdoc;
struct man *man;
void *vp;
@@ -839,8 +831,9 @@ format(const struct req *req, const char *file)
return;
}
+ mchars = mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL,
- req->q.manpath);
+ mchars, req->q.manpath);
rc = mparse_readfd(mp, fd, file);
close(fd);
@@ -866,10 +859,11 @@ format(const struct req *req, const char *file)
req->q.manpath, file);
pg_error_internal();
mparse_free(mp);
+ mchars_free(mchars);
return;
}
- vp = html_alloc(opts);
+ vp = html_alloc(mchars, opts);
if (NULL != mdoc)
html_mdoc(vp, mdoc);
@@ -878,6 +872,7 @@ format(const struct req *req, const char *file)
html_free(vp);
mparse_free(mp);
+ mchars_free(mchars);
free(opts);
}
@@ -953,10 +948,10 @@ pg_search(const struct req *req)
struct mansearch search;
struct manpaths paths;
struct manpage *res;
- char **cp;
- const char *ep, *start;
+ char **argv;
+ char *query, *rp, *wp;
size_t ressz;
- int i, sz;
+ int argc;
/*
* Begin by chdir()ing into the root of the manpath.
@@ -973,54 +968,54 @@ pg_search(const struct req *req)
search.arch = req->q.arch;
search.sec = req->q.sec;
- search.deftype = req->q.equal ? TYPE_Nm : (TYPE_Nm | TYPE_Nd);
- search.flags = req->q.equal ? MANSEARCH_MAN : 0;
+ search.outkey = "Nd";
+ search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR;
+ search.firstmatch = 1;
paths.sz = 1;
paths.paths = mandoc_malloc(sizeof(char *));
paths.paths[0] = mandoc_strdup(".");
/*
- * Poor man's tokenisation: just break apart by spaces.
- * Yes, this is half-ass. But it works for now.
+ * Break apart at spaces with backslash-escaping.
*/
- ep = req->q.query;
- while (ep && isspace((unsigned char)*ep))
- ep++;
-
- sz = 0;
- cp = NULL;
- while (ep && '\0' != *ep) {
- cp = mandoc_reallocarray(cp, sz + 1, sizeof(char *));
- start = ep;
- while ('\0' != *ep && ! isspace((unsigned char)*ep))
- ep++;
- cp[sz] = mandoc_malloc((ep - start) + 1);
- memcpy(cp[sz], start, ep - start);
- cp[sz++][ep - start] = '\0';
- while (isspace((unsigned char)*ep))
- ep++;
+ argc = 0;
+ argv = NULL;
+ rp = query = mandoc_strdup(req->q.query);
+ for (;;) {
+ while (isspace((unsigned char)*rp))
+ rp++;
+ if (*rp == '\0')
+ break;
+ argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *));
+ argv[argc++] = wp = rp;
+ for (;;) {
+ if (isspace((unsigned char)*rp)) {
+ *wp = '\0';
+ rp++;
+ break;
+ }
+ if (rp[0] == '\\' && rp[1] != '\0')
+ rp++;
+ if (wp != rp)
+ *wp = *rp;
+ if (*rp == '\0')
+ break;
+ wp++;
+ rp++;
+ }
}
- if (0 == mansearch(&search, &paths, sz, cp, "Nd", &res, &ressz))
+ if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz))
pg_noresult(req, "You entered an invalid query.");
else if (0 == ressz)
pg_noresult(req, "No results found.");
else
pg_searchres(req, res, ressz);
- for (i = 0; i < sz; i++)
- free(cp[i]);
- free(cp);
-
- for (i = 0; i < (int)ressz; i++) {
- free(res[i].file);
- free(res[i].names);
- free(res[i].output);
- }
- free(res);
-
+ free(query);
+ mansearch_free(res, ressz);
free(paths.paths[0]);
free(paths.paths);
}
@@ -1029,10 +1024,23 @@ int
main(void)
{
struct req req;
+ struct itimerval itimer;
const char *path;
const char *querystring;
int i;
+ /* Poor man's ReDoS mitigation. */
+
+ itimer.it_value.tv_sec = 2;
+ itimer.it_value.tv_usec = 0;
+ itimer.it_interval.tv_sec = 2;
+ itimer.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) {
+ fprintf(stderr, "setitimer: %s\n", strerror(errno));
+ pg_error_internal();
+ return(EXIT_FAILURE);
+ }
+
/* Scan our run-time environment. */
if (NULL == (scriptname = getenv("SCRIPT_NAME")))
@@ -1066,8 +1074,9 @@ main(void)
if (NULL != (querystring = getenv("QUERY_STRING")))
http_parse(&req, querystring);
- if ( ! (NULL == req.q.manpath ||
- validate_manpath(&req, req.q.manpath))) {
+ if (req.q.manpath == NULL)
+ req.q.manpath = mandoc_strdup(req.p[0]);
+ else if ( ! validate_manpath(&req, req.q.manpath)) {
pg_error_badrequest(
"You specified an invalid manpath.");
return(EXIT_FAILURE);
diff --git a/chars.c b/chars.c
index d758d0ccbd1b..fe0b17dea823 100644
--- a/chars.c
+++ b/chars.c
@@ -1,7 +1,7 @@
-/* $Id: chars.c,v 1.58 2014/07/23 15:00:08 schwarze Exp $ */
+/* $Id: chars.c,v 1.65 2014/10/29 00:17:43 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 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,9 +15,9 @@
* 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 <assert.h>
#include <ctype.h>
@@ -104,20 +104,16 @@ mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
const struct ln *ln;
ln = find(arg, p, sz);
- if (NULL == ln)
- return(-1);
- return(ln->unicode);
+ return(ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1);
}
-char
+int
mchars_num2char(const char *p, size_t sz)
{
int i;
- if ((i = mandoc_strntoi(p, sz, 10)) < 0)
- return('\0');
-
- return(i > 0 && i < 256 && isprint(i) ? i : '\0');
+ i = mandoc_strntoi(p, sz, 10);
+ return(i >= 0 && i < 256 ? i : -1);
}
int
@@ -125,21 +121,9 @@ mchars_num2uc(const char *p, size_t sz)
{
int i;
- if ((i = mandoc_strntoi(p, sz, 16)) < 0)
- return('\0');
-
- /*
- * 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');
+ i = mandoc_strntoi(p, sz, 16);
+ assert(i >= 0 && i <= 0x10FFFF);
+ return(i);
}
const char *
@@ -149,15 +133,26 @@ mchars_spec2str(const struct mchars *arg,
const struct ln *ln;
ln = find(arg, p, sz);
- if (NULL == ln) {
+ if (ln == NULL) {
*rsz = 1;
- return(NULL);
+ return(sz == 1 ? p : NULL);
}
*rsz = strlen(ln->ascii);
return(ln->ascii);
}
+const char *
+mchars_uc2str(int uc)
+{
+ int i;
+
+ for (i = 0; i < LINES_MAX; i++)
+ if (uc == lines[i].unicode)
+ return(lines[i].ascii);
+ return("<?>");
+}
+
static const struct ln *
find(const struct mchars *tab, const char *p, size_t sz)
{
diff --git a/chars.in b/chars.in
index 098504fa1648..752015c1b6d4 100644
--- a/chars.in
+++ b/chars.in
@@ -1,4 +1,4 @@
-/* $Id: chars.in,v 1.46 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: chars.in,v 1.49 2014/11/06 22:28:36 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -57,7 +57,7 @@ CHAR("\'", "\'", 180)
CHAR("aa", "\'", 180)
CHAR("ga", "`", 96)
CHAR("`", "`", 96)
-CHAR("ab", "`", 728)
+CHAR("ab", "'\b`", 728)
CHAR("ac", ",", 184)
CHAR("ad", "\"", 168)
CHAR("ah", "v", 711)
@@ -86,8 +86,8 @@ CHAR("lB", "[", 91)
CHAR("rB", "]", 93)
CHAR("lC", "{", 123)
CHAR("rC", "}", 125)
-CHAR("la", "<", 60)
-CHAR("ra", ">", 62)
+CHAR("la", "<", 10216)
+CHAR("ra", ">", 10217)
CHAR("bv", "|", 9130)
CHAR("braceex", "|", 9130)
CHAR("bracketlefttp", "|", 9121)
@@ -100,7 +100,7 @@ CHAR("lt", ",-", 9127)
CHAR("bracelefttp", ",-", 9127)
CHAR("lk", "{", 9128)
CHAR("braceleftmid", "{", 9128)
-CHAR("lb", ",-", 9129)
+CHAR("lb", "`-", 9129)
CHAR("braceleftbp", "`-", 9129)
CHAR("braceleftex", "|", 9130)
CHAR("rt", "-.", 9131)
@@ -120,127 +120,127 @@ CHAR("parenrightex", "|", 9119)
/* Greek characters. */
CHAR("*A", "A", 913)
CHAR("*B", "B", 914)
-CHAR("*G", "|", 915)
-CHAR("*D", "/\\", 916)
+CHAR("*G", "G", 915)
+CHAR("*D", "_\b/_\b\\", 916)
CHAR("*E", "E", 917)
CHAR("*Z", "Z", 918)
CHAR("*Y", "H", 919)
-CHAR("*H", "O", 920)
+CHAR("*H", "-\bO", 920)
CHAR("*I", "I", 921)
CHAR("*K", "K", 922)
CHAR("*L", "/\\", 923)
CHAR("*M", "M", 924)
CHAR("*N", "N", 925)
-CHAR("*C", "H", 926)
+CHAR("*C", "_\bH", 926)
CHAR("*O", "O", 927)
CHAR("*P", "TT", 928)
CHAR("*R", "P", 929)
-CHAR("*S", ">", 931)
+CHAR("*S", "S", 931)
CHAR("*T", "T", 932)
CHAR("*U", "Y", 933)
-CHAR("*F", "O_", 934)
+CHAR("*F", "I\bO", 934)
CHAR("*X", "X", 935)
-CHAR("*Q", "Y", 936)
-CHAR("*W", "O", 937)
+CHAR("*Q", "I\bY", 936)
+CHAR("*W", "_\bO", 937)
CHAR("*a", "a", 945)
CHAR("*b", "B", 946)
CHAR("*g", "y", 947)
CHAR("*d", "d", 948)
CHAR("*e", "e", 949)
-CHAR("*z", "C", 950)
+CHAR("*z", ",\bC", 950)
CHAR("*y", "n", 951)
-CHAR("*h", "0", 952)
+CHAR("*h", "-\b0", 952)
CHAR("*i", "i", 953)
CHAR("*k", "k", 954)
-CHAR("*l", "\\", 955)
-CHAR("*m", "u", 956)
+CHAR("*l", ">\b\\", 955)
+CHAR("*m", ",\bu", 956)
CHAR("*n", "v", 957)
-CHAR("*c", "E", 958)
+CHAR("*c", ",\bE", 958)
CHAR("*o", "o", 959)
-CHAR("*p", "n", 960)
+CHAR("*p", "-\bn", 960)
CHAR("*r", "p", 961)
-CHAR("*s", "o", 963)
-CHAR("*t", "t", 964)
+CHAR("*s", "-\bo", 963)
+CHAR("*t", "~\bt", 964)
CHAR("*u", "u", 965)
-CHAR("*f", "o", 981)
+CHAR("*f", "|\bo", 981)
CHAR("*x", "x", 967)
-CHAR("*q", "u", 968)
+CHAR("*q", "|\bu", 968)
CHAR("*w", "w", 969)
-CHAR("+h", "0", 977)
-CHAR("+f", "o", 966)
-CHAR("+p", "w", 982)
+CHAR("+h", "-\b0", 977)
+CHAR("+f", "|\bo", 966)
+CHAR("+p", "-\bw", 982)
CHAR("+e", "e", 1013)
CHAR("ts", "s", 962)
/* Accented letters. */
-CHAR(",C", "C", 199)
-CHAR(",c", "c", 231)
-CHAR("/L", "L", 321)
-CHAR("/O", "O", 216)
-CHAR("/l", "l", 322)
-CHAR("/o", "o", 248)
-CHAR("oA", "A", 197)
-CHAR("oa", "a", 229)
-CHAR(":A", "A", 196)
-CHAR(":E", "E", 203)
-CHAR(":I", "I", 207)
-CHAR(":O", "O", 214)
-CHAR(":U", "U", 220)
-CHAR(":a", "a", 228)
-CHAR(":e", "e", 235)
-CHAR(":i", "i", 239)
-CHAR(":o", "o", 246)
-CHAR(":u", "u", 252)
-CHAR(":y", "y", 255)
-CHAR("\'A", "A", 193)
-CHAR("\'E", "E", 201)
-CHAR("\'I", "I", 205)
-CHAR("\'O", "O", 211)
-CHAR("\'U", "U", 218)
-CHAR("\'a", "a", 225)
-CHAR("\'e", "e", 233)
-CHAR("\'i", "i", 237)
-CHAR("\'o", "o", 243)
-CHAR("\'u", "u", 250)
-CHAR("^A", "A", 194)
-CHAR("^E", "E", 202)
-CHAR("^I", "I", 206)
-CHAR("^O", "O", 212)
-CHAR("^U", "U", 219)
-CHAR("^a", "a", 226)
-CHAR("^e", "e", 234)
-CHAR("^i", "i", 238)
-CHAR("^o", "o", 244)
-CHAR("^u", "u", 251)
-CHAR("`A", "A", 192)
-CHAR("`E", "E", 200)
-CHAR("`I", "I", 204)
-CHAR("`O", "O", 210)
-CHAR("`U", "U", 217)
-CHAR("`a", "a", 224)
-CHAR("`e", "e", 232)
-CHAR("`i", "i", 236)
-CHAR("`o", "o", 242)
-CHAR("`u", "u", 249)
-CHAR("~A", "A", 195)
-CHAR("~N", "N", 209)
-CHAR("~O", "O", 213)
-CHAR("~a", "a", 227)
-CHAR("~n", "n", 241)
-CHAR("~o", "o", 245)
+CHAR(",C", ",\bC", 199)
+CHAR(",c", ",\bc", 231)
+CHAR("/L", "/\bL", 321)
+CHAR("/O", "/\bO", 216)
+CHAR("/l", "/\bl", 322)
+CHAR("/o", "/\bo", 248)
+CHAR("oA", "o\bA", 197)
+CHAR("oa", "o\ba", 229)
+CHAR(":A", "\"\bA", 196)
+CHAR(":E", "\"\bE", 203)
+CHAR(":I", "\"\bI", 207)
+CHAR(":O", "\"\bO", 214)
+CHAR(":U", "\"\bU", 220)
+CHAR(":a", "\"\ba", 228)
+CHAR(":e", "\"\be", 235)
+CHAR(":i", "\"\bi", 239)
+CHAR(":o", "\"\bo", 246)
+CHAR(":u", "\"\bu", 252)
+CHAR(":y", "\"\by", 255)
+CHAR("'A", "'\bA", 193)
+CHAR("'E", "'\bE", 201)
+CHAR("'I", "'\bI", 205)
+CHAR("'O", "'\bO", 211)
+CHAR("'U", "'\bU", 218)
+CHAR("'a", "'\ba", 225)
+CHAR("'e", "'\be", 233)
+CHAR("'i", "'\bi", 237)
+CHAR("'o", "'\bo", 243)
+CHAR("'u", "'\bu", 250)
+CHAR("^A", "^\bA", 194)
+CHAR("^E", "^\bE", 202)
+CHAR("^I", "^\bI", 206)
+CHAR("^O", "^\bO", 212)
+CHAR("^U", "^\bU", 219)
+CHAR("^a", "^\ba", 226)
+CHAR("^e", "^\be", 234)
+CHAR("^i", "^\bi", 238)
+CHAR("^o", "^\bo", 244)
+CHAR("^u", "^\bu", 251)
+CHAR("`A", "`\bA", 192)
+CHAR("`E", "`\bE", 200)
+CHAR("`I", "`\bI", 204)
+CHAR("`O", "`\bO", 210)
+CHAR("`U", "`\bU", 217)
+CHAR("`a", "`\ba", 224)
+CHAR("`e", "`\be", 232)
+CHAR("`i", "`\bi", 236)
+CHAR("`o", "`\bo", 242)
+CHAR("`u", "`\bu", 249)
+CHAR("~A", "~\bA", 195)
+CHAR("~N", "~\bN", 209)
+CHAR("~O", "~\bO", 213)
+CHAR("~a", "~\ba", 227)
+CHAR("~n", "~\bn", 241)
+CHAR("~o", "~\bo", 245)
/* Arrows and lines. */
CHAR("<-", "<-", 8592)
CHAR("->", "->", 8594)
-CHAR("<>", "<>", 8596)
-CHAR("da", "v", 8595)
-CHAR("ua", "^", 8593)
+CHAR("<>", "<->", 8596)
+CHAR("da", "|\bv", 8595)
+CHAR("ua", "|\b^", 8593)
CHAR("va", "^v", 8597)
CHAR("lA", "<=", 8656)
CHAR("rA", "=>", 8658)
CHAR("hA", "<=>", 8660)
-CHAR("dA", "v", 8659)
-CHAR("uA", "^", 8657)
+CHAR("dA", "=\bv", 8659)
+CHAR("uA", "=\b^", 8657)
CHAR("vA", "^=v", 8661)
/* Logic. */
@@ -249,7 +249,7 @@ CHAR("OR", "v", 8744)
CHAR("no", "~", 172)
CHAR("tno", "~", 172)
CHAR("te", "3", 8707)
-CHAR("fa", "V", 8704)
+CHAR("fa", "-\bV", 8704)
CHAR("st", "-)", 8715)
CHAR("tf", ".:.", 8756)
CHAR("3d", ".:.", 8756)
@@ -266,8 +266,8 @@ CHAR("pc", ".", 183)
CHAR("md", ".", 8901)
CHAR("mu", "x", 215)
CHAR("tmu", "x", 215)
-CHAR("c*", "x", 8855)
-CHAR("c+", "+", 8853)
+CHAR("c*", "O\bx", 8855)
+CHAR("c+", "O\b+", 8853)
CHAR("di", "-:-", 247)
CHAR("tdi", "-:-", 247)
CHAR("f/", "/", 8260)
@@ -293,14 +293,14 @@ CHAR("sb", "(=", 8834)
CHAR("nb", "(!=", 8836)
CHAR("sp", "=)", 8835)
CHAR("nc", "!=)", 8837)
-CHAR("ib", "(=", 8838)
-CHAR("ip", "=)", 8839)
+CHAR("ib", "(=\b_", 8838)
+CHAR("ip", "=\b_)", 8839)
CHAR("ca", "(^)", 8745)
CHAR("cu", "U", 8746)
-CHAR("/_", "/_", 8736)
-CHAR("pp", "_|_", 8869)
-CHAR("is", "I", 8747)
-CHAR("integral", "I", 8747)
+CHAR("/_", "_\b/", 8736)
+CHAR("pp", "_\b|", 8869)
+CHAR("is", "'\b,\bI", 8747)
+CHAR("integral", "'\b,\bI", 8747)
CHAR("sum", "E", 8721)
CHAR("product", "TT", 8719)
CHAR("coproduct", "U", 8720)
@@ -336,22 +336,22 @@ CHAR("IJ", "IJ", 306)
CHAR("ij", "ij", 307)
/* Special letters. */
-CHAR("-D", "D", 208)
-CHAR("Sd", "o", 240)
-CHAR("TP", "b", 222)
-CHAR("Tp", "b", 254)
+CHAR("-D", "-\bD", 208)
+CHAR("Sd", "d", 240)
+CHAR("TP", "Th", 222)
+CHAR("Tp", "th", 254)
CHAR(".i", "i", 305)
CHAR(".j", "j", 567)
/* Currency. */
CHAR("Do", "$", 36)
-CHAR("ct", "c", 162)
+CHAR("ct", "/\bc", 162)
CHAR("Eu", "EUR", 8364)
CHAR("eu", "EUR", 8364)
-CHAR("Ye", "Y", 165)
-CHAR("Po", "L", 163)
-CHAR("Cs", "x", 164)
-CHAR("Fn", "f", 402)
+CHAR("Ye", "=\bY", 165)
+CHAR("Po", "GBP", 163)
+CHAR("Cs", "o\bx", 164)
+CHAR("Fn", ",\bf", 402)
/* Lines. */
CHAR("ba", "|", 124)
@@ -363,14 +363,14 @@ CHAR("sl", "/", 47)
CHAR("rs", "\\", 92)
/* Text markers. */
-CHAR("ci", "o", 9675)
-CHAR("bu", "o", 8226)
-CHAR("dd", "=", 8225)
-CHAR("dg", "-", 8224)
+CHAR("ci", "O", 9675)
+CHAR("bu", "+\bo", 8226)
+CHAR("dd", "|\b=", 8225)
+CHAR("dg", "|\b-", 8224)
CHAR("lz", "<>", 9674)
CHAR("sq", "[]", 9633)
-CHAR("ps", "9|", 182)
-CHAR("sc", "S", 167)
+CHAR("ps", "<par>", 182)
+CHAR("sc", "<sec>", 167)
CHAR("lh", "<=", 9756)
CHAR("rh", "=>", 9758)
CHAR("at", "@", 64)
@@ -385,18 +385,18 @@ CHAR("tm", "tm", 8482)
/* Punctuation. */
CHAR(".", ".", 46)
-CHAR("r!", "i", 161)
-CHAR("r?", "c", 191)
+CHAR("r!", "!", 161)
+CHAR("r?", "?", 191)
CHAR("em", "--", 8212)
CHAR("en", "-", 8211)
CHAR("hy", "-", 8208)
CHAR("e", "\\", 92)
/* Units. */
-CHAR("de", "o", 176)
+CHAR("de", "<deg>", 176)
CHAR("%0", "%o", 8240)
CHAR("fm", "\'", 8242)
-CHAR("sd", "\"", 8243)
-CHAR("mc", "mu", 181)
+CHAR("sd", "''", 8243)
+CHAR("mc", ",\bu", 181)
CHAR_TBL_END
diff --git a/compat_fgetln.c b/compat_fgetln.c
index 49c9985b6e00..3760ab994d11 100644
--- a/compat_fgetln.c
+++ b/compat_fgetln.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_FGETLN
+#if HAVE_FGETLN
int dummy;
@@ -41,6 +39,9 @@ int dummy;
* 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/compat_fts.c b/compat_fts.c
new file mode 100644
index 000000000000..4caf74c13800
--- /dev/null
+++ b/compat_fts.c
@@ -0,0 +1,826 @@
+#include "config.h"
+
+#if HAVE_FTS
+
+int dummy;
+
+#else
+
+/* $Id: compat_fts.c,v 1.4 2014/08/17 20:45:59 schwarze Exp $ */
+/* $OpenBSD: fts.c,v 1.46 2014/05/25 17:47:04 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "compat_fts.h"
+
+static FTSENT *fts_alloc(FTS *, const char *, size_t);
+static FTSENT *fts_build(FTS *);
+static void fts_lfree(FTSENT *);
+static void fts_load(FTS *, FTSENT *);
+static size_t fts_maxarglen(char * const *);
+static void fts_padjust(FTS *, FTSENT *);
+static int fts_palloc(FTS *, size_t);
+static unsigned short fts_stat(FTS *, FTSENT *);
+static int fts_safe_changedir(FTS *, FTSENT *, int, const char *);
+
+#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define CLR(opt) (sp->fts_options &= ~(opt))
+#define ISSET(opt) (sp->fts_options & (opt))
+#define SET(opt) (sp->fts_options |= (opt))
+
+#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
+
+FTS *
+fts_open(char * const *argv, int options, void *dummy)
+{
+ FTS *sp;
+ FTSENT *p, *root;
+ int nitems;
+ FTSENT *parent, *tmp;
+ size_t len;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream */
+ if ((sp = calloc(1, sizeof(FTS))) == NULL)
+ return (NULL);
+ sp->fts_options = options;
+
+ /*
+ * Start out with 1K of path space, and enough, in any case,
+ * to hold the user's paths.
+ */
+ if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX)))
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+ if ((parent = fts_alloc(sp, "", 0)) == NULL)
+ goto mem2;
+ parent->fts_level = FTS_ROOTPARENTLEVEL;
+
+ /* Allocate/initialize root(s). */
+ for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
+ /* Don't allow zero-length paths. */
+ if ((len = strlen(*argv)) == 0) {
+ errno = ENOENT;
+ goto mem3;
+ }
+
+ if ((p = fts_alloc(sp, *argv, len)) == NULL)
+ goto mem3;
+ p->fts_level = FTS_ROOTLEVEL;
+ p->fts_parent = parent;
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p);
+
+ /* Command-line "." and ".." are real directories. */
+ if (p->fts_info == FTS_DOT)
+ p->fts_info = FTS_D;
+
+ p->fts_link = NULL;
+ if (root == NULL)
+ tmp = root = p;
+ else {
+ tmp->fts_link = p;
+ tmp = p;
+ }
+ }
+
+ /*
+ * Allocate a dummy pointer and make fts_read think that we've just
+ * finished the node before the root(s); set p->fts_info to FTS_INIT
+ * so that everything about the "current" node is ignored.
+ */
+ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+ goto mem3;
+ sp->fts_cur->fts_link = root;
+ sp->fts_cur->fts_info = FTS_INIT;
+
+ /*
+ * If using chdir(2), grab a file descriptor pointing to dot to ensure
+ * that we can get back here; this could be avoided for some paths,
+ * but almost certainly not worth the effort. Slashes, symbolic links,
+ * and ".." are all fairly nasty problems. Note, if we can't get the
+ * descriptor we run anyway, just more slowly.
+ */
+ if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
+ SET(FTS_NOCHDIR);
+
+ if (nitems == 0)
+ free(parent);
+
+ return (sp);
+
+mem3: fts_lfree(root);
+ free(parent);
+mem2: free(sp->fts_path);
+mem1: free(sp);
+ return (NULL);
+}
+
+static void
+fts_load(FTS *sp, FTSENT *p)
+{
+ size_t len;
+ char *cp;
+
+ /*
+ * Load the stream structure for the next traversal. Since we don't
+ * actually enter the directory until after the preorder visit, set
+ * the fts_accpath field specially so the chdir gets done to the right
+ * place and the user can access the first node. From fts_open it's
+ * known that the path will fit.
+ */
+ len = p->fts_pathlen = p->fts_namelen;
+ memmove(sp->fts_path, p->fts_name, len + 1);
+ if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+ len = strlen(++cp);
+ memmove(p->fts_name, cp, len + 1);
+ p->fts_namelen = len;
+ }
+ p->fts_accpath = p->fts_path = sp->fts_path;
+ sp->fts_dev = p->fts_dev;
+}
+
+int
+fts_close(FTS *sp)
+{
+ FTSENT *freep, *p;
+ int rfd, error = 0;
+
+ /*
+ * This still works if we haven't read anything -- the dummy structure
+ * points to the root list, so we step through to the end of the root
+ * list which has a valid parent pointer.
+ */
+ if (sp->fts_cur) {
+ for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+ freep = p;
+ p = p->fts_link ? p->fts_link : p->fts_parent;
+ free(freep);
+ }
+ free(p);
+ }
+
+ /* Stash the original directory fd if needed. */
+ rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd;
+
+ /* Free up child linked list, sort array, path buffer, stream ptr.*/
+ if (sp->fts_child)
+ fts_lfree(sp->fts_child);
+ free(sp->fts_path);
+ free(sp);
+
+ /* Return to original directory, checking for error. */
+ if (rfd != -1) {
+ int saved_errno;
+ error = fchdir(rfd);
+ saved_errno = errno;
+ (void)close(rfd);
+ errno = saved_errno;
+ }
+
+ return (error);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define NAPPEND(p) \
+ (p->fts_path[p->fts_pathlen - 1] == '/' \
+ ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT *
+fts_read(FTS *sp)
+{
+ FTSENT *p, *tmp;
+ int instr;
+ char *t;
+
+ /* If finished or unrecoverable error, return NULL. */
+ if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /* Save and zero out user instructions. */
+ instr = p->fts_instr;
+ p->fts_instr = FTS_NOINSTR;
+
+ /* Directory in pre-order. */
+ if (p->fts_info == FTS_D) {
+ /* If skipped or crossed mount point, do post-order visit. */
+ if (instr == FTS_SKIP ||
+ (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+ if (sp->fts_child) {
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+ p->fts_info = FTS_DP;
+ return (p);
+ }
+
+ /*
+ * Cd to the subdirectory.
+ *
+ * If have already read and now fail to chdir, whack the list
+ * to make the names come out right, and set the parent errno
+ * so the application will eventually get an error condition.
+ * Set the FTS_DONTCHDIR flag so that when we logically change
+ * directories back to the parent we don't do a chdir.
+ *
+ * If haven't read do so. If the read fails, fts_build sets
+ * FTS_STOP or the fts_info field of the node.
+ */
+ if (sp->fts_child) {
+ if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+ p->fts_errno = errno;
+ p->fts_flags |= FTS_DONTCHDIR;
+ for (p = sp->fts_child; p; p = p->fts_link)
+ p->fts_accpath =
+ p->fts_parent->fts_accpath;
+ }
+ } else if ((sp->fts_child = fts_build(sp)) == NULL) {
+ if (ISSET(FTS_STOP))
+ return (NULL);
+ return (p);
+ }
+ p = sp->fts_child;
+ sp->fts_child = NULL;
+ goto name;
+ }
+
+ /* Move to the next node on this level. */
+next: tmp = p;
+ if ((p = p->fts_link)) {
+ free(tmp);
+
+ /*
+ * If reached the top, return to the original directory (or
+ * the root of the tree), and load the paths for the next root.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ fts_load(sp, p);
+ return (sp->fts_cur = p);
+ }
+
+ /*
+ * User may have called fts_set on the node. If skipped,
+ * ignore. If followed, get a file descriptor so we can
+ * get back if necessary.
+ */
+ if (p->fts_instr == FTS_SKIP)
+ goto next;
+
+name: t = sp->fts_path + NAPPEND(p->fts_parent);
+ *t++ = '/';
+ memmove(t, p->fts_name, p->fts_namelen + 1);
+ return (sp->fts_cur = p);
+ }
+
+ /* Move up to the parent node. */
+ p = tmp->fts_parent;
+ free(tmp);
+
+ if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+ /*
+ * Done; free everything up and set errno to 0 so the user
+ * can distinguish between error and EOF.
+ */
+ free(p);
+ errno = 0;
+ return (sp->fts_cur = NULL);
+ }
+
+ /* NUL terminate the pathname. */
+ sp->fts_path[p->fts_pathlen] = '\0';
+
+ /*
+ * Return to the parent directory. If at a root node or came through
+ * a symlink, go back through the file descriptor. Otherwise, cd up
+ * one directory.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ sp->fts_cur = p;
+ return (NULL);
+ }
+ } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+ fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+ SET(FTS_STOP);
+ sp->fts_cur = p;
+ return (NULL);
+ }
+ p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+ return (sp->fts_cur = p);
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set. An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+fts_set(FTS *sp, FTSENT *p, int instr)
+{
+ if (instr && instr != FTS_NOINSTR && instr != FTS_SKIP) {
+ errno = EINVAL;
+ return (1);
+ }
+ p->fts_instr = instr;
+ return (0);
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here. The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read. There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly. First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry. Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls. The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT *
+fts_build(FTS *sp)
+{
+ struct dirent *dp;
+ FTSENT *p, *head;
+ FTSENT *cur, *tail;
+ DIR *dirp;
+ void *oldaddr;
+ size_t dlen, len, maxlen;
+ int nitems, cderrno, descend, level, nlinks, nostat, doadjust;
+ int saved_errno;
+ char *cp;
+
+ /* Set current node pointer. */
+ cur = sp->fts_cur;
+
+ /*
+ * Open the directory for reading. If this fails, we're done.
+ * If being called from fts_read, set the fts_info field.
+ */
+ if ((dirp = opendir(cur->fts_accpath)) == NULL) {
+ cur->fts_info = FTS_DNR;
+ cur->fts_errno = errno;
+ return (NULL);
+ }
+
+ /*
+ * Nlinks is the number of possible entries of type directory in the
+ * directory if we're cheating on stat calls, 0 if we're not doing
+ * any stat calls at all, -1 if we're doing stats on everything.
+ */
+ nlinks = -1;
+ nostat = 0;
+
+ /*
+ * If we're going to need to stat anything or we want to descend
+ * and stay in the directory, chdir. If this fails we keep going,
+ * but set a flag so we don't chdir after the post-order visit.
+ * We won't be able to stat anything, but we can still return the
+ * names themselves. Note, that since fts_read won't be able to
+ * chdir into the directory, it will have to return different path
+ * names than before, i.e. "a/b" instead of "b". Since the node
+ * has already been visited in pre-order, have to wait until the
+ * post-order visit to return the error. There is a special case
+ * here, if there was nothing to stat then it's not an error to
+ * not be able to stat. This is all fairly nasty. If a program
+ * needed sorted entries or stat information, they had better be
+ * checking FTS_NS on the returned nodes.
+ */
+ cderrno = 0;
+ if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
+ if (nlinks)
+ cur->fts_errno = errno;
+ cur->fts_flags |= FTS_DONTCHDIR;
+ descend = 0;
+ cderrno = errno;
+ (void)closedir(dirp);
+ dirp = NULL;
+ } else
+ descend = 1;
+
+ /*
+ * Figure out the max file name length that can be stored in the
+ * current path -- the inner loop allocates more path as necessary.
+ * We really wouldn't have to do the maxlen calculations here, we
+ * could do them in fts_read before returning the path, but it's a
+ * lot easier here since the length is part of the dirent structure.
+ *
+ * If not changing directories set a pointer so that can just append
+ * each new name into the path.
+ */
+ len = NAPPEND(cur);
+ if (ISSET(FTS_NOCHDIR)) {
+ cp = sp->fts_path + len;
+ *cp++ = '/';
+ }
+ len++;
+ maxlen = sp->fts_pathlen - len;
+
+ /*
+ * fts_level is signed so we must prevent it from wrapping
+ * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL.
+ */
+ level = cur->fts_level;
+ if (level < FTS_MAXLEVEL)
+ level++;
+
+ /* Read the directory, attaching each entry to the `link' pointer. */
+ doadjust = 0;
+ for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+ if (ISDOT(dp->d_name))
+ continue;
+
+#if HAVE_DIRENT_NAMLEN
+ dlen = dp->d_namlen;
+#else
+ dlen = strlen(dp->d_name);
+#endif
+
+ if (!(p = fts_alloc(sp, dp->d_name, dlen)))
+ goto mem1;
+ if (dlen >= maxlen) { /* include space for NUL */
+ oldaddr = sp->fts_path;
+ if (fts_palloc(sp, dlen + len + 1)) {
+ /*
+ * No more memory for path or structures. Save
+ * errno, free up the current structure and the
+ * structures already allocated.
+ */
+mem1: saved_errno = errno;
+ if (p)
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ errno = saved_errno;
+ return (NULL);
+ }
+ /* Did realloc() change the pointer? */
+ if (oldaddr != sp->fts_path) {
+ doadjust = 1;
+ if (ISSET(FTS_NOCHDIR))
+ cp = sp->fts_path + len;
+ }
+ maxlen = sp->fts_pathlen - len;
+ }
+
+ p->fts_level = level;
+ p->fts_parent = sp->fts_cur;
+ p->fts_pathlen = len + dlen;
+ if (p->fts_pathlen < len) {
+ /*
+ * If we wrap, free up the current structure and
+ * the structures already allocated, then error
+ * out with ENAMETOOLONG.
+ */
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+
+ if (cderrno) {
+ if (nlinks) {
+ p->fts_info = FTS_NS;
+ p->fts_errno = cderrno;
+ } else
+ p->fts_info = FTS_NSOK;
+ p->fts_accpath = cur->fts_accpath;
+ } else if (nlinks == 0
+#ifdef DT_DIR
+ || (nostat &&
+ dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
+#endif
+ ) {
+ p->fts_accpath =
+ ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
+ p->fts_info = FTS_NSOK;
+ } else {
+ /* Build a file name for fts_stat to stat. */
+ if (ISSET(FTS_NOCHDIR)) {
+ p->fts_accpath = p->fts_path;
+ memmove(cp, p->fts_name, p->fts_namelen + 1);
+ } else
+ p->fts_accpath = p->fts_name;
+ /* Stat it. */
+ p->fts_info = fts_stat(sp, p);
+
+ /* Decrement link count if applicable. */
+ if (nlinks > 0 && (p->fts_info == FTS_D ||
+ p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
+ --nlinks;
+ }
+
+ /* We walk in directory order so "ls -f" doesn't get upset. */
+ p->fts_link = NULL;
+ if (head == NULL)
+ head = tail = p;
+ else {
+ tail->fts_link = p;
+ tail = p;
+ }
+ ++nitems;
+ }
+ if (dirp)
+ (void)closedir(dirp);
+
+ /*
+ * If realloc() changed the address of the path, adjust the
+ * addresses for the rest of the tree and the dir list.
+ */
+ if (doadjust)
+ fts_padjust(sp, head);
+
+ /*
+ * If not changing directories, reset the path back to original
+ * state.
+ */
+ if (ISSET(FTS_NOCHDIR)) {
+ if (len == sp->fts_pathlen || nitems == 0)
+ --cp;
+ *cp = '\0';
+ }
+
+ /*
+ * If descended after called from fts_children or after called from
+ * fts_read and nothing found, get back. At the root level we use
+ * the saved fd; if one of fts_open()'s arguments is a relative path
+ * to an empty directory, we wind up here with no other way back. If
+ * can't get back, we're done.
+ */
+ if (descend && !nitems &&
+ (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) :
+ fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+
+ /* If didn't find anything, return NULL. */
+ if (!nitems) {
+ cur->fts_info = FTS_DP;
+ return (NULL);
+ }
+ return (head);
+}
+
+static unsigned short
+fts_stat(FTS *sp, FTSENT *p)
+{
+ FTSENT *t;
+ dev_t dev;
+ ino_t ino;
+ struct stat *sbp;
+
+ /* If user needs stat info, stat buffer already allocated. */
+ sbp = p->fts_statp;
+
+ if (lstat(p->fts_accpath, sbp)) {
+ p->fts_errno = errno;
+ memset(sbp, 0, sizeof(struct stat));
+ return (FTS_NS);
+ }
+
+ if (S_ISDIR(sbp->st_mode)) {
+ /*
+ * Set the device/inode. Used to find cycles and check for
+ * crossing mount points. Also remember the link count, used
+ * in fts_build to limit the number of stat calls. It is
+ * understood that these fields are only referenced if fts_info
+ * is set to FTS_D.
+ */
+ dev = p->fts_dev = sbp->st_dev;
+ ino = p->fts_ino = sbp->st_ino;
+ p->fts_nlink = sbp->st_nlink;
+
+ if (ISDOT(p->fts_name))
+ return (FTS_DOT);
+
+ /*
+ * Cycle detection is done by brute force when the directory
+ * is first encountered. If the tree gets deep enough or the
+ * number of symbolic links to directories is high enough,
+ * something faster might be worthwhile.
+ */
+ for (t = p->fts_parent;
+ t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+ if (ino == t->fts_ino && dev == t->fts_dev) {
+ p->fts_cycle = t;
+ return (FTS_DC);
+ }
+ return (FTS_D);
+ }
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SL);
+ if (S_ISREG(sbp->st_mode))
+ return (FTS_F);
+ return (FTS_DEFAULT);
+}
+
+static FTSENT *
+fts_alloc(FTS *sp, const char *name, size_t namelen)
+{
+ FTSENT *p;
+ size_t len;
+
+ len = sizeof(FTSENT) + namelen;
+ if ((p = calloc(1, len)) == NULL)
+ return (NULL);
+
+ p->fts_path = sp->fts_path;
+ p->fts_namelen = namelen;
+ p->fts_instr = FTS_NOINSTR;
+ p->fts_statp = malloc(sizeof(struct stat));
+ if (p->fts_statp == NULL) {
+ free(p);
+ return (NULL);
+ }
+ memcpy(p->fts_name, name, namelen);
+
+ return (p);
+}
+
+static void
+fts_lfree(FTSENT *head)
+{
+ FTSENT *p;
+
+ /* Free a linked list of structures. */
+ while ((p = head)) {
+ head = head->fts_link;
+ free(p);
+ }
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than PATH_MAX, even
+ * though the kernel won't resolve them. Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+fts_palloc(FTS *sp, size_t more)
+{
+ char *p;
+
+ /*
+ * Check for possible wraparound.
+ */
+ more += 256;
+ if (sp->fts_pathlen + more < sp->fts_pathlen) {
+ if (sp->fts_path)
+ free(sp->fts_path);
+ sp->fts_path = NULL;
+ errno = ENAMETOOLONG;
+ return (1);
+ }
+ sp->fts_pathlen += more;
+ p = realloc(sp->fts_path, sp->fts_pathlen);
+ if (p == NULL) {
+ if (sp->fts_path)
+ free(sp->fts_path);
+ sp->fts_path = NULL;
+ return (1);
+ }
+ sp->fts_path = p;
+ return (0);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(FTS *sp, FTSENT *head)
+{
+ FTSENT *p;
+ char *addr = sp->fts_path;
+
+#define ADJUST(p) { \
+ if ((p)->fts_accpath != (p)->fts_name) { \
+ (p)->fts_accpath = \
+ (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
+ } \
+ (p)->fts_path = addr; \
+}
+ /* Adjust the current set of children. */
+ for (p = sp->fts_child; p; p = p->fts_link)
+ ADJUST(p);
+
+ /* Adjust the rest of the tree, including the current level. */
+ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+ ADJUST(p);
+ p = p->fts_link ? p->fts_link : p->fts_parent;
+ }
+}
+
+static size_t
+fts_maxarglen(char * const *argv)
+{
+ size_t len, max;
+
+ for (max = 0; *argv; ++argv)
+ if ((len = strlen(*argv)) > max)
+ max = len;
+ return (max + 1);
+}
+
+/*
+ * Change to dir specified by fd or p->fts_accpath without getting
+ * tricked by someone changing the world out from underneath us.
+ * Assumes p->fts_dev and p->fts_ino are filled in.
+ */
+static int
+fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
+{
+ int ret, oerrno, newfd;
+ struct stat sb;
+
+ newfd = fd;
+ if (ISSET(FTS_NOCHDIR))
+ return (0);
+ if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
+ return (-1);
+ if (fstat(newfd, &sb)) {
+ ret = -1;
+ goto bail;
+ }
+ if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
+ errno = ENOENT; /* disinformation */
+ ret = -1;
+ goto bail;
+ }
+ ret = fchdir(newfd);
+bail:
+ oerrno = errno;
+ if (fd < 0)
+ (void)close(newfd);
+ errno = oerrno;
+ return (ret);
+}
+
+#endif
diff --git a/compat_fts.h b/compat_fts.h
new file mode 100644
index 000000000000..ce7ee6287055
--- /dev/null
+++ b/compat_fts.h
@@ -0,0 +1,106 @@
+/* $OpenBSD: fts.h,v 1.14 2012/12/05 23:19:57 deraadt Exp $ */
+/* $NetBSD: fts.h,v 1.7 2012/03/01 16:18:51 hans Exp $ */
+
+/*
+ * Copyright (c) 1989, 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.
+ *
+ * @(#)fts.h 8.3 (Berkeley) 8/14/94
+ */
+
+#ifndef _FTS_H_
+#define _FTS_H_
+
+typedef struct {
+ struct _ftsent *fts_cur; /* current node */
+ struct _ftsent *fts_child; /* linked list of children */
+ dev_t fts_dev; /* starting device # */
+ char *fts_path; /* path for this descent */
+ int fts_rfd; /* fd for root */
+ size_t fts_pathlen; /* sizeof(path) */
+
+#define FTS_NOCHDIR 0x0004 /* don't change directories */
+#define FTS_PHYSICAL 0x0010 /* physical walk */
+#define FTS_XDEV 0x0040 /* don't cross devices */
+#define FTS_OPTIONMASK 0x00ff /* valid user option mask */
+
+#define FTS_STOP 0x2000 /* (private) unrecoverable error */
+ int fts_options; /* fts_open options, global flags */
+} FTS;
+
+typedef struct _ftsent {
+ struct _ftsent *fts_cycle; /* cycle node */
+ struct _ftsent *fts_parent; /* parent directory */
+ struct _ftsent *fts_link; /* next file in directory */
+ char *fts_accpath; /* access path */
+ char *fts_path; /* root path */
+ int fts_errno; /* errno for this node */
+ size_t fts_pathlen; /* strlen(fts_path) */
+ size_t fts_namelen; /* strlen(fts_name) */
+
+ ino_t fts_ino; /* inode */
+ dev_t fts_dev; /* device */
+ nlink_t fts_nlink; /* link count */
+
+#define FTS_ROOTPARENTLEVEL -1
+#define FTS_ROOTLEVEL 0
+#define FTS_MAXLEVEL 0x7fffffff
+ int fts_level; /* depth (-1 to N) */
+
+#define FTS_D 1 /* preorder directory */
+#define FTS_DC 2 /* directory that causes cycles */
+#define FTS_DEFAULT 3 /* none of the above */
+#define FTS_DNR 4 /* unreadable directory */
+#define FTS_DOT 5 /* dot or dot-dot */
+#define FTS_DP 6 /* postorder directory */
+#define FTS_ERR 7 /* error; errno is set */
+#define FTS_F 8 /* regular file */
+#define FTS_INIT 9 /* initialized only */
+#define FTS_NS 10 /* stat(2) failed */
+#define FTS_NSOK 11 /* no stat(2) requested */
+#define FTS_SL 12 /* symbolic link */
+ unsigned short fts_info; /* user flags for FTSENT structure */
+
+#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
+ unsigned short fts_flags; /* private flags for FTSENT structure */
+
+#define FTS_NOINSTR 3 /* no instructions */
+#define FTS_SKIP 4 /* discard node */
+ unsigned short fts_instr; /* fts_set() instructions */
+
+ struct stat *fts_statp; /* stat(2) information */
+ char fts_name[1]; /* file name */
+} FTSENT;
+
+__BEGIN_DECLS
+int fts_close(FTS *);
+FTS *fts_open(char * const *, int, void *);
+FTSENT *fts_read(FTS *);
+int fts_set(FTS *, FTSENT *, int);
+__END_DECLS
+
+#endif /* !_FTS_H_ */
diff --git a/compat_getsubopt.c b/compat_getsubopt.c
index 9cd415367dad..880f2f789d4a 100644
--- a/compat_getsubopt.c
+++ b/compat_getsubopt.c
@@ -1,13 +1,12 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_GETSUBOPT
+#if HAVE_GETSUBOPT
int dummy;
#else
+/* $Id: compat_getsubopt.c,v 1.5 2014/08/17 20:53:50 schwarze Exp $ */
/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */
/*-
@@ -43,18 +42,11 @@ int dummy;
#include <stdlib.h>
#include <string.h>
-/*
- * The SVID interface to getsubopt provides no way of figuring out which
- * part of the suboptions list wasn't matched. This makes error messages
- * tricky... The extern variable suboptarg is a pointer to the token
- * which didn't match.
- */
-char *suboptarg;
-
int
getsubopt(char **optionp, char * const *tokens, char **valuep)
{
int cnt;
+ char *suboptarg;
char *p;
suboptarg = *valuep = NULL;
diff --git a/compat_ohash.c b/compat_ohash.c
index 0992b3657dde..cbd6052182f2 100644
--- a/compat_ohash.c
+++ b/compat_ohash.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_OHASH
+#if HAVE_OHASH
int dummy;
@@ -25,6 +23,8 @@ int dummy;
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <sys/types.h>
+
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/compat_reallocarray.c b/compat_reallocarray.c
index e25d8374bd53..6e96a6ab7d7e 100644
--- a/compat_reallocarray.c
+++ b/compat_reallocarray.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_REALLOCARRAY
+#if HAVE_REALLOCARRAY
int dummy;
diff --git a/compat_sqlite3_errstr.c b/compat_sqlite3_errstr.c
index b8d6eb58f1cc..c62384887a68 100644
--- a/compat_sqlite3_errstr.c
+++ b/compat_sqlite3_errstr.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_SQLITE3_ERRSTR
+#if HAVE_SQLITE3_ERRSTR
int dummy;
diff --git a/compat_strcasestr.c b/compat_strcasestr.c
index 5216d0215753..0706ee00e50b 100644
--- a/compat_strcasestr.c
+++ b/compat_strcasestr.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_STRCASESTR
+#if HAVE_STRCASESTR
int dummy;
diff --git a/compat_strlcat.c b/compat_strlcat.c
index 543d40b38b05..acaae4fb1506 100644
--- a/compat_strlcat.c
+++ b/compat_strlcat.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_STRLCAT
+#if HAVE_STRLCAT
int dummy;
diff --git a/compat_strlcpy.c b/compat_strlcpy.c
index a7c64ff9997c..a00d511817a3 100644
--- a/compat_strlcpy.c
+++ b/compat_strlcpy.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_STRLCPY
+#if HAVE_STRLCPY
int dummy;
diff --git a/compat_strsep.c b/compat_strsep.c
index a5c58c625326..348f7ebf67f9 100644
--- a/compat_strsep.c
+++ b/compat_strsep.c
@@ -1,8 +1,6 @@
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_STRSEP
+#if HAVE_STRSEP
int dummy;
diff --git a/config.h.post b/config.h.post
deleted file mode 100644
index e95f5f5311d4..000000000000
--- a/config.h.post
+++ /dev/null
@@ -1,42 +0,0 @@
-#if !defined(__BEGIN_DECLS)
-# ifdef __cplusplus
-# define __BEGIN_DECLS extern "C" {
-# else
-# define __BEGIN_DECLS
-# endif
-#endif
-#if !defined(__END_DECLS)
-# ifdef __cplusplus
-# define __END_DECLS }
-# else
-# define __END_DECLS
-# endif
-#endif
-
-#ifndef HAVE_FGETLN
-extern char *fgetln(FILE *, size_t *);
-#endif
-#ifndef HAVE_GETSUBOPT
-extern int getsubopt(char **, char * const *, char **);
-extern char *suboptarg;
-#endif
-#ifndef HAVE_REALLOCARRAY
-extern void *reallocarray(void *, size_t, size_t);
-#endif
-#ifndef HAVE_SQLITE3_ERRSTR
-extern const char *sqlite3_errstr(int);
-#endif
-#ifndef HAVE_STRCASESTR
-extern char *strcasestr(const char *, const char *);
-#endif
-#ifndef HAVE_STRLCAT
-extern size_t strlcat(char *, const char *, size_t);
-#endif
-#ifndef HAVE_STRLCPY
-extern size_t strlcpy(char *, const char *, size_t);
-#endif
-#ifndef HAVE_STRSEP
-extern char *strsep(char **, const char *);
-#endif
-
-#endif /* MANDOC_CONFIG_H */
diff --git a/config.h.pre b/config.h.pre
deleted file mode 100644
index 1c3940de5cc0..000000000000
--- a/config.h.pre
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MANDOC_CONFIG_H
-#define MANDOC_CONFIG_H
-
-#if defined(__linux__) || defined(__MINT__)
-# define _GNU_SOURCE /* getsubopt(), strcasestr(), strptime() */
-#endif
-
-#include <sys/types.h>
-#include <stdio.h>
diff --git a/configure b/configure
index 5b987ebef60d..0fb841cfcf20 100755
--- a/configure
+++ b/configure
@@ -14,36 +14,380 @@
# 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"
+[ -e config.log ] && mv config.log config.log.old
+[ -e config.h ] && mv config.h config.h.old
+
+# Output file descriptor usage:
+# 1 (stdout): config.h, Makefile.local
+# 2 (stderr): original stderr, usually to the console
+# 3: config.log
+
+exec 3> config.log
+echo "config.log: writing..."
+
+# --- default settings -------------------------------------------------
+# Initialize all variables here,
+# such that nothing can leak in from the environment.
+
+VERSION="1.13.1"
+echo "VERSION=\"${VERSION}\"" 1>&2
+echo "VERSION=\"${VERSION}\"" 1>&3
+
+OSNAME=
+
+CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make -f -`
+CFLAGS="-g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings"
+DBLIB=
+STATIC="-static"
+
+BUILD_DB=1
+BUILD_CGI=0
+
+HAVE_DIRENT_NAMLEN=
+HAVE_FGETLN=
+HAVE_FTS=
+HAVE_GETSUBOPT=
+HAVE_MMAP=
+HAVE_REALLOCARRAY=
+HAVE_STRCASESTR=
+HAVE_STRLCAT=
+HAVE_STRLCPY=
+HAVE_STRPTIME=
+HAVE_STRSEP=
+HAVE_WCHAR=
+
+HAVE_SQLITE3=
+HAVE_SQLITE3_ERRSTR=
+HAVE_OHASH=
+HAVE_MANPATH=
+
+PREFIX="/usr/local"
+BINDIR=
+SBINDIR=
+INCLUDEDIR=
+LIBDIR=
+MANDIR=
+EXAMPLEDIR=
+
+WWWPREFIX="/var/www"
+HTDOCDIR=
+CGIBINDIR=
+
+INSTALL="install"
+INSTALL_PROGRAM=
+INSTALL_LIB=
+INSTALL_MAN=
+INSTALL_DATA=
+
+# --- manual settings from configure.local -----------------------------
+
+if [ -e ./configure.local ]; then
+ echo "configure.local: reading..." 1>&2
+ echo "configure.local: reading..." 1>&3
+ cat ./configure.local 1>&3
+ . ./configure.local
+else
+ echo "configure.local: no (fully automatic configuration)" 1>&2
+ echo "configure.local: no (fully automatic configuration)" 1>&3
+fi
+echo 1>&3
+# --- tests for config.h ----------------------------------------------
+
+COMP="${CC} ${CFLAGS} -Wno-unused -Werror"
+
+# Check whether this HAVE_ setting is manually overridden.
+# If yes, use the override, if no, do not decide anything yet.
+# Arguments: lower-case test name, manual value
+ismanual() {
+ [ -z "${2}" ] && return 1
+ echo "${1}: manual (${2})" 1>&2
+ echo "${1}: manual (${2})" 1>&3
+ echo 1>&3
+ return 0
+}
+
+# Run a single autoconfiguration test.
+# In case of success, enable the feature.
+# In case of failure, do not decide anything yet.
+# Arguments: lower-case test name, upper-case test name, additional CFLAGS
+singletest() {
+ cat 1>&3 << __HEREDOC__
+${1}: testing...
+${COMP} ${3} -o test-${1} test-${1}.c
+__HEREDOC__
+
+ if ${COMP} ${3} -o "test-${1}" "test-${1}.c" 1>&3 2>&3; then
+ echo "${1}: ${CC} succeeded" 1>&3
+ else
+ echo "${1}: ${CC} failed with $?" 1>&3
+ echo 1>&3
+ return 1
+ fi
+
+ if ./test-${1} 1>&3 2>&3; then
+ echo "${1}: yes" 1>&2
+ echo "${1}: yes" 1>&3
+ echo 1>&3
+ eval HAVE_${2}=1
+ rm "test-${1}"
+ return 0
+ else
+ echo "${1}: execution failed with $?" 1>&3
+ echo 1>&3
+ rm "test-${1}"
+ return 1
+ fi
+}
+
+# Run a complete autoconfiguration test, including the check for
+# a manual override and disabling the feature on failure.
+# Arguments: lower case name, upper case name, additional CFLAGS
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}"
+ eval _manual=\${HAVE_${2}}
+ ismanual "${1}" "${_manual}" && return 0
+ singletest "${1}" "${2}" "${3}" && return 0
+ echo "${1}: no" 1>&2
+ eval HAVE_${2}=0
+ return 1
}
-cat config.h.pre
+# --- library functions ---
+runtest dirent-namlen DIRENT_NAMLEN || true
+runtest fgetln FGETLN || true
+runtest fts FTS || true
+runtest getsubopt GETSUBOPT || true
+runtest mmap MMAP || true
+runtest reallocarray REALLOCARRAY || true
+runtest strcasestr STRCASESTR || true
+runtest strlcat STRLCAT || true
+runtest strlcpy STRLCPY || true
+runtest strptime STRPTIME || true
+runtest strsep STRSEP || true
+runtest wchar WCHAR || true
+
+# --- sqlite3 ---
+DETECTLIB=
+if [ ${BUILD_DB} -eq 0 ]; then
+ echo "BUILD_DB=0 (manual)" 1>&2
+ echo "BUILD_DB=0 (manual)" 1>&3
+ echo 1>&3
+ HAVE_SQLITE3=0
+elif ismanual sqlite3 "${HAVE_SQLITE3}"; then
+ DETECTLIB="-lsqlite3"
+elif [ -n "${DBLIB}" ]; then
+ runtest sqlite3 SQLITE3 "${DBLIB}" || true
+elif singletest sqlite3 SQLITE3 "-lsqlite3"; then
+ DETECTLIB="-lsqlite3"
+elif runtest sqlite3 SQLITE3 \
+ "-I/usr/local/include -L/usr/local/lib -lsqlite3"; then
+ DETECTLIB="-L/usr/local/lib -lsqlite3"
+ CFLAGS="${CFLAGS} -I/usr/local/include"
+fi
+if [ ${BUILD_DB} -gt 0 -a ${HAVE_SQLITE3} -eq 0 ]; then
+ echo "BUILD_DB=0 (no sqlite3)" 1>&2
+ echo "BUILD_DB=0 (no sqlite3)" 1>&3
+ echo 1>&3
+ BUILD_DB=0
+fi
+
+# --- sqlite3_errstr ---
+if [ ${BUILD_DB} -eq 0 ]; then
+ HAVE_SQLITE3_ERRSTR=1
+elif ismanual sqlite3_errstr "${HAVE_SQLITE3_ERRSTR}"; then
+ :
+elif [ -n "${DBLIB}" ]; then
+ runtest sqlite3_errstr SQLITE3_ERRSTR "${DBLIB}" || true
+else
+ runtest sqlite3_errstr SQLITE3_ERRSTR "${DETECTLIB}" || true
+fi
+
+# --- ohash ---
+if [ ${BUILD_DB} -eq 0 ]; then
+ HAVE_OHASH=1
+elif ismanual ohash "${HAVE_OHASH}"; then
+ :
+elif [ -n "${DBLIB}" ]; then
+ runtest ohash OHASH "${DBLIB}" || true
+elif singletest ohash OHASH; then
+ :
+elif runtest ohash OHASH "-lutil"; then
+ DETECTLIB="${DETECTLIB} -lutil"
+fi
+
+# --- DBLIB ---
+if [ ${BUILD_DB} -eq 0 ]; then
+ DBLIB=
+elif [ -z "${DBLIB}" ]; then
+ DBLIB="${DETECTLIB}"
+ echo "DBLIB=\"${DBLIB}\"" 1>&2
+ echo "DBLIB=\"${DBLIB}\"" 1>&3
+ echo 1>&3
+fi
+
+# --- manpath ---
+if [ ${BUILD_DB} -eq 0 ]; then
+ HAVE_MANPATH=0
+elif ismanual manpath "${HAVE_MANPATH}"; then
+ :
+elif manpath 1>&3 2>&3; then
+ echo "manpath: yes" 1>&2
+ echo "manpath: yes" 1>&3
+ echo 1>&3
+ HAVE_MANPATH=1
+else
+ echo "manpath: no" 1>&2
+ echo "manpath: no" 1>&3
+ echo 1>&3
+ HAVE_MANPATH=0
+fi
+
+# --- write config.h ---
+
+exec > config.h
+
+cat << __HEREDOC__
+#ifndef MANDOC_CONFIG_H
+#define MANDOC_CONFIG_H
+
+#if defined(__linux__) || defined(__MINT__)
+#define _GNU_SOURCE /* See test-*.c what needs this. */
+#endif
+
+__HEREDOC__
+
+[ ${HAVE_FGETLN} -eq 0 -o ${HAVE_REALLOCARRAY} -eq 0 -o \
+ ${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 ] \
+ && echo "#include <sys/types.h>"
+[ ${HAVE_FGETLN} -eq 0 ] && echo "#include <stdio.h>"
+
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
+[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\""
+
+cat << __HEREDOC__
+#define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN}
+#define HAVE_FGETLN ${HAVE_FGETLN}
+#define HAVE_FTS ${HAVE_FTS}
+#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT}
+#define HAVE_MMAP ${HAVE_MMAP}
+#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY}
+#define HAVE_STRCASESTR ${HAVE_STRCASESTR}
+#define HAVE_STRLCAT ${HAVE_STRLCAT}
+#define HAVE_STRLCPY ${HAVE_STRLCPY}
+#define HAVE_STRPTIME ${HAVE_STRPTIME}
+#define HAVE_STRSEP ${HAVE_STRSEP}
+#define HAVE_WCHAR ${HAVE_WCHAR}
+#define HAVE_SQLITE3 ${HAVE_SQLITE3}
+#define HAVE_SQLITE3_ERRSTR ${HAVE_SQLITE3_ERRSTR}
+#define HAVE_OHASH ${HAVE_OHASH}
+#define HAVE_MANPATH ${HAVE_MANPATH}
+
+#if !defined(__BEGIN_DECLS)
+# ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# else
+# define __BEGIN_DECLS
+# endif
+#endif
+#if !defined(__END_DECLS)
+# ifdef __cplusplus
+# define __END_DECLS }
+# else
+# define __END_DECLS
+# endif
+#endif
+
+__HEREDOC__
+
+[ ${HAVE_FGETLN} -eq 0 ] && \
+ echo "extern char *fgetln(FILE *, size_t *);"
+
+[ ${HAVE_GETSUBOPT} -eq 0 ] && \
+ echo "extern int getsubopt(char **, char * const *, char **);"
+
+[ ${HAVE_REALLOCARRAY} -eq 0 ] && \
+ echo "extern void *reallocarray(void *, size_t, size_t);"
+
+[ ${BUILD_DB} -gt 0 -a ${HAVE_SQLITE3_ERRSTR} -eq 0 ] &&
+ echo "extern const char *sqlite3_errstr(int);"
+
+[ ${HAVE_STRCASESTR} -eq 0 ] && \
+ echo "extern char *strcasestr(const char *, const char *);"
+
+[ ${HAVE_STRLCAT} -eq 0 ] && \
+ echo "extern size_t strlcat(char *, const char *, size_t);"
+
+[ ${HAVE_STRLCPY} -eq 0 ] && \
+ echo "extern size_t strlcpy(char *, const char *, size_t);"
+
+[ ${HAVE_STRSEP} -eq 0 ] && \
+ echo "extern char *strsep(char **, const char *);"
+
echo
-cat config.h.post
+echo "#endif /* MANDOC_CONFIG_H */"
+
+echo "config.h: written" 1>&2
+echo "config.h: written" 1>&3
+
+# --- tests for Makefile.local -----------------------------------------
+
+exec > Makefile.local
+
+[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin"
+[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin"
+[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc"
+[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc"
+[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man"
+[ -z "${EXAMPLEDIR}" ] && EXAMPLEDIR="${PREFIX}/share/examples/mandoc"
+
+[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs"
+[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin"
+
+[ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555"
+[ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444"
+[ -z "${INSTALL_MAN}" ] && INSTALL_MAN="${INSTALL} -m 0444"
+[ -z "${INSTALL_DATA}" ] && INSTALL_DATA="${INSTALL} -m 0444"
+
+if [ ${BUILD_DB} -eq 0 -a ${BUILD_CGI} -gt 0 ]; then
+ echo "BUILD_CGI=0 (no BUILD_DB)" 1>&2
+ echo "BUILD_CGI=0 (no BUILD_DB)" 1>&3
+ BUILD_CGI=0
+fi
+
+BUILD_TARGETS="base-build"
+[ ${BUILD_DB} -gt 0 ] && BUILD_TARGETS="${BUILD_TARGETS} db-build"
+[ ${BUILD_CGI} -gt 0 ] && BUILD_TARGETS="${BUILD_TARGETS} cgi-build"
+
+cat << __HEREDOC__
+VERSION = ${VERSION}
+BUILD_TARGETS = ${BUILD_TARGETS}
+CFLAGS = ${CFLAGS}
+DBLIB = ${DBLIB}
+STATIC = ${STATIC}
+PREFIX = ${PREFIX}
+BINDIR = ${BINDIR}
+SBINDIR = ${SBINDIR}
+INCLUDEDIR = ${INCLUDEDIR}
+LIBDIR = ${LIBDIR}
+MANDIR = ${MANDIR}
+EXAMPLEDIR = ${EXAMPLEDIR}
+WWWPREFIX = ${WWWPREFIX}
+HTDOCDIR = ${HTDOCDIR}
+CGIBINDIR = ${CGIBINDIR}
+INSTALL = ${INSTALL}
+INSTALL_PROGRAM = ${INSTALL_PROGRAM}
+INSTALL_LIB = ${INSTALL_LIB}
+INSTALL_MAN = ${INSTALL_MAN}
+INSTALL_DATA = ${INSTALL_DATA}
+__HEREDOC__
+
+[ ${BUILD_DB} -gt 0 ] && \
+ echo "MAN_OBJS = \$(MANDOC_OBJS) \$(APROPOS_OBJS)"
+
+echo "Makefile.local: written" 1>&2
+echo "Makefile.local: written" 1>&3
exit 0
diff --git a/configure.local.example b/configure.local.example
new file mode 100644
index 000000000000..76dcc6297626
--- /dev/null
+++ b/configure.local.example
@@ -0,0 +1,189 @@
+# $Id: configure.local.example,v 1.1 2014/08/16 19:00:01 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.
+
+# For all settings documented in this file, there are reasonable
+# defaults and/or the ./configure script attempts autodetection.
+# Consequently, you only need to create a file ./configure.local
+# and put any of these settings into it if ./configure autodetection
+# fails or if you want to make different choices for other reasons.
+
+# If autodetection fails, please tell <tech@mdocml.bsd.lv>.
+
+# We recommend that you write ./configure.local from scratch and
+# only put the lines there you need. This file contains examples.
+# It is not intended as a template to be copied as a whole.
+
+# --- user settings relevant for all builds ----------------------------
+
+# For -Tutf8 and -Tlocale operation, mandoc(1) requires <locale.h>
+# providing setlocale(3) and <wchar.h> providing wcwidth(3) and
+# putwchar(3) with a wchar_t storing UCS-4 values. Theoretically,
+# the latter should be tested with the __STDC_ISO_10646__ feature
+# macro. In practice, many <wchar.h> headers do not provide that
+# macro even though they treat wchar_t as UCS-4. So the automatic
+# test only checks that wchar_t is wide enough, that is, at least
+# four bytes.
+
+# The following line forces multi-byte support.
+# If your C library does not treat wchar_t as UCS-4, the UTF-8 output
+# mode will print garbage.
+
+HAVE_WCHAR=1
+
+# The following line disables multi-byte support.
+# The output modes -Tutf8 and -Tlocale will be the same as -Tascii.
+
+HAVE_WCHAR=0
+
+# In manual pages written in the mdoc(7) language, the operating system
+# version is displayed in the page footer line. If an operating system
+# is specified as an argument to the .Os macro, that is always used.
+# If the .Os macro has no argument and an operation system is specified
+# with the mandoc(1) -Ios= command line option, that is used.
+# Otherwise, the uname(3) library function is called at runtime to find
+# the name of the operating system.
+# If you do not want uname(3) to be called but instead want a fixed
+# string to be used, use the following line:
+
+OSNAME="OpenBSD 5.5"
+
+# The following installation directories are used.
+# It is possible to set only one or a few of these variables,
+# there is no need to copy the whole block.
+# Even if you set PREFIX to something else, the other variables
+# pick it up without copying them all over.
+
+PREFIX="/usr/local"
+BINDIR="${PREFIX}/bin"
+SBINDIR="${PREFIX}/sbin"
+INCLUDEDIR="${PREFIX}/include/mandoc"
+LIBDIR="${PREFIX}/lib/mandoc"
+MANDIR="${PREFIX}/man"
+EXAMPLEDIR="${PREFIX}/share/examples/mandoc"
+
+# It is possible to change the utility program used for installation
+# and the modes files are installed with. The defaults are:
+
+INSTALL="install"
+INSTALL_PROGRAM="${INSTALL} -m 0555"
+INSTALL_LIB="${INSTALL} -m 0444"
+INSTALL_MAN="${INSTALL} -m 0444"
+INSTALL_DATA="${INSTALL} -m 0444"
+
+# --- user settings related to database support ------------------------
+
+# By default, building makewhatis(8) and apropos(1) is enabled.
+# To disable it, for example to avoid the dependency on SQLite3,
+# use the following line. It that case, the remaining settings
+# in this section are irrelevant.
+
+BUILD_DB=0
+
+# Two libraries are needed: SQLite3 and ohash(3).
+# Autoconfiguration tries the following linker flags to find them.
+# If none of these work, add a working DBLIB line to configure.local,
+# disabling autodetection for library directories.
+
+DBLIB="-lsqlite3"
+DBLIB="-lsqlite3 -lutil"
+DBLIB="-L/usr/local/lib -lsqlite3"
+
+# When library autodetection decides to use -L/usr/local/lib,
+# -I/usr/local/include is automatically added to CFLAGS.
+# If you manually set DBLIB to something including -L/usr/local/lib,
+# chances are you will also need the following line:
+
+CFLAGS="${CFLAGS} -I/usr/local/include"
+
+# The man(1) utility needs to know where the manuals reside.
+# We know of two ways to tell it: via manpath(1) or man.conf(5).
+# The latter is used by OpenBSD and NetBSD, the former by most
+# other systems.
+
+# Force usage of manpath(1).
+# If it is not installed or not operational,
+# makewhatis(8) and apropos(1) will not work properly.
+
+HAVE_MANPATH=1
+
+# Force usage of man.conf(5).
+# If it does not exist or contains no valid configuration,
+# makewhatis(8) and apropos(1) will not work properly.
+
+HAVE_MANPATH=0
+
+# --- user settings related man.cgi ------------------------------------
+
+# By default, building man.cgi(8) is disabled. To enable it, copy
+# cgi.h.example to cgi.h, edit it, and use the following line.
+# Obviously, this requires that BUILD_DB is enabled, too.
+
+BUILD_CGI=1
+
+# The remaining settings in this section are only relevant if BUILD_CGI
+# is enabled. Otherwise, they have no effect either way.
+
+# By default, man.cgi(8) is linked statically.
+# Some systems do not support static linking, for example Mac OS X.
+# In that case, use the following line:
+
+STATIC=
+
+# Some systems, for example Linux, require -pthread for static linking:
+
+STATIC="-static -pthread"
+
+# Some directories.
+# This works just like PREFIX, see above.
+
+WWWPREFIX="/var/www"
+HTDOCDIR="${WWWPREFIX}/htdocs"
+CGIBINDIR="${WWWPREFIX}/cgi-bin"
+
+# --- settings that rarely need to be touched --------------------------
+
+# Do not set these variables unless you really need to.
+
+# You can manually override the compiler to be used.
+# But that's rarely useful because ./configure asks your make(1)
+# which compiler to use, and that answer will hardly be wrong.
+
+CC=cc
+
+# The default compiler flags are:
+
+CFLAGS="-g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings"
+
+# In rare cases, it may be required to skip individual automatic tests.
+# Each of the following variables can be set to 0 (test will not be run
+# and will be regarded as failed) or 1 (test will not be run and will
+# be regarded as successful).
+
+HAVE_DIRENT_NAMLEN=0
+HAVE_FGETLN=0
+HAVE_FTS=0
+HAVE_GETSUBOPT=0
+HAVE_MMAP=0
+HAVE_REALLOCARRAY=0
+HAVE_STRCASESTR=0
+HAVE_STRLCAT=0
+HAVE_STRLCPY=0
+HAVE_STRPTIME=0
+HAVE_STRSEP=0
+
+HAVE_SQLITE3=0
+HAVE_SQLITE3_ERRSTR=0
+HAVE_OHASH=0
diff --git a/demandoc.1 b/demandoc.1
index 84571baf30aa..bca69eff1b5b 100644
--- a/demandoc.1
+++ b/demandoc.1
@@ -1,4 +1,4 @@
-.\" $Id: demandoc.1,v 1.7 2013/07/13 19:41:16 schwarze Exp $
+.\" $Id: demandoc.1,v 1.8 2014/09/12 00:10:26 schwarze Exp $
.\"
.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 13 2013 $
+.Dd $Mdocdate: September 12 2014 $
.Dt DEMANDOC 1
.Os
.Sh NAME
@@ -92,7 +92,7 @@ This is accomplished as follows (assuming British spelling):
.Dl $ demandoc -w file.1 | spell -b
.Sh SEE ALSO
.Xr mandoc 1 ,
-.Xr man 7
+.Xr man 7 ,
.Xr mdoc 7
.Sh HISTORY
.Nm
diff --git a/demandoc.c b/demandoc.c
index 4a7b979e9225..e9aa62afb2ba 100644
--- a/demandoc.c
+++ b/demandoc.c
@@ -1,4 +1,4 @@
-/* $Id: demandoc.c,v 1.10 2014/03/19 22:20:43 schwarze Exp $ */
+/* $Id: demandoc.c,v 1.12 2014/10/28 17:36:19 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,9 @@
* 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 <assert.h>
#include <ctype.h>
@@ -43,6 +43,7 @@ int
main(int argc, char *argv[])
{
struct mparse *mp;
+ struct mchars *mchars;
int ch, i, list;
extern int optind;
@@ -76,7 +77,8 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, NULL);
+ mchars = mchars_alloc();
+ mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, mchars, NULL);
assert(mp);
if (0 == argc)
@@ -88,6 +90,7 @@ main(int argc, char *argv[])
}
mparse_free(mp);
+ mchars_free(mchars);
return((int)MANDOCLEVEL_OK);
}
diff --git a/eqn.7 b/eqn.7
index dcbad41cc15b..c1e9c7634d4a 100644
--- a/eqn.7
+++ b/eqn.7
@@ -1,6 +1,7 @@
-.\" $Id: eqn.7,v 1.29 2013/07/13 19:41:16 schwarze Exp $
+.\" $Id: eqn.7,v 1.31 2014/10/12 11:57:38 schwarze Exp $
.\"
.\" Copyright (c) 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
@@ -14,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: October 12 2014 $
.Dt EQN 7
.Os
.Sh NAME
@@ -37,7 +38,9 @@ This manual describes the
.Nm
language accepted by the
.Xr mandoc 1
-utility, which corresponds to the Second Edition eqn specification (see
+utility, which corresponds to the Second Edition
+.Nm
+specification (see
.Sx SEE ALSO
for references).
.Pp
@@ -77,6 +80,7 @@ box : text
| \*qgsize\*q text
| \*qset\*q text text
| \*qundef\*q text
+ | \*qsqrt\*q box
| box pos box
| box mark
| \*qmatrix\*q \*q{\*q [col \*q{\*q list \*q}\*q ]*
@@ -98,8 +102,19 @@ space : [\e^~ \et]
.Pp
White-space consists of the space, tab, circumflex, and tilde
characters.
+It is required to delimit tokens consisting of alphabetic characters
+and it is ignored at other places.
+Braces and quotes also delimit tokens.
If within a quoted string, these space characters are retained.
-Quoted strings are also not scanned for replacement definitions.
+Quoted strings are also not scanned for keywords, glyph names,
+and expansion of definitions.
+To print a literal quote character, it can be prepended with a
+backslash or expressed with the \e(dq escape sequence.
+.Pp
+Subequations can be enclosed in braces to pass them as arguments
+to operation keywords, overriding standard operation precedence.
+Braces can be nested.
+To set a brace verbatim, it needs to be enclosed in quotes.
.Pp
The following text terms are translated into a rendered glyph, if
available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa,
@@ -110,9 +125,12 @@ int (integral), sum (summation), grad (gradient), del (vector
differential), times (multiply), cdot (centre-dot), nothing (zero-width
space), approx (approximately equals), prime (prime), half (one-half),
partial (partial differential), inf (infinity), >> (much greater), <<
-(much less), \-> (left arrow), <\- (right arrow), += (plus-minus), !=
+(much less), \-> (left arrow), <\- (right arrow), +\- (plus-minus), !=
(not equal), == (equivalence), <= (less-than-equal), and >=
(more-than-equal).
+The character escape sequences documented in
+.Xr mandoc_char 7
+can be used, too.
.Pp
The following control statements are available:
.Bl -tag -width Ds
@@ -120,7 +138,7 @@ The following control statements are available:
Replace all occurrences of a key with a value.
Its syntax is as follows:
.Pp
-.D1 define Ar key cvalc
+.D1 Cm define Ar key cvalc
.Pp
The first character of the value string,
.Ar c ,
@@ -128,8 +146,8 @@ is used as the delimiter for the value
.Ar val .
This allows for arbitrary enclosure of terms (not just quotes), such as
.Pp
-.D1 define Ar foo 'bar baz'
-.D1 define Ar foo cbar bazc
+.D1 Cm define Ar foo 'bar baz'
+.D1 Cm define Ar foo cbar bazc
.Pp
It is an error to have an empty
.Ar key
@@ -164,24 +182,26 @@ is discarded.
Set the default font of subsequent output.
Its syntax is as follows:
.Pp
-.D1 gfont Ar font
+.D1 Cm gfont Ar font
.Pp
In mandoc, this value is discarded.
.It Cm gsize
Set the default size of subsequent output.
Its syntax is as follows:
.Pp
-.D1 gsize Ar size
+.D1 Cm gsize Oo +|\- Oc Ns Ar size
.Pp
The
.Ar size
value should be an integer.
+If prepended by a sign,
+the font size is changed relative to the current size.
.It Cm set
Set an equation mode.
In mandoc, both arguments are thrown away.
Its syntax is as follows:
.Pp
-.D1 set Ar key val
+.D1 Cm set Ar key val
.Pp
The
.Ar key
@@ -193,7 +213,7 @@ This statement is a GNU extension.
Unset a previously-defined key.
Its syntax is as follows:
.Pp
-.D1 define Ar key
+.D1 Cm define Ar key
.Pp
Once invoked, the definition for
.Ar key
@@ -203,6 +223,207 @@ The
is not expanded for replacements.
This statement is a GNU extension.
.El
+.Pp
+Operation keywords have the following semantics:
+.Bl -tag -width Ds
+.It Cm above
+See
+.Cm pile .
+.It Cm bar
+Draw a line over the preceding box.
+.It Cm bold
+Set the following box using bold font.
+.It Cm ccol
+Like
+.Cm cpile ,
+but for use in
+.Cm matrix .
+.It Cm cpile
+Like
+.Cm pile ,
+but with slightly increased vertical spacing.
+.It Cm dot
+Set a single dot over the preceding box.
+.It Cm dotdot
+Set two dots (dieresis) over the preceding box.
+.It Cm dyad
+Set a dyad symbol (left-right arrow) over the preceding box.
+.It Cm fat
+A synonym for
+.Cm bold .
+.It Cm font
+Set the second argument using the font specified by the first argument;
+currently not recognized by the
+.Xr mandoc 1
+.Nm
+parser.
+.It Cm from
+Set the following box below the preceding box,
+using a slightly smaller font.
+Used for sums, integrals, limits, and the like.
+.It Cm hat
+Set a hat (circumflex) over the preceding box.
+.It Cm italic
+Set the following box using italic font.
+.It Cm lcol
+Like
+.Cm lpile ,
+but for use in
+.Cm matrix .
+.It Cm left
+Set the first argument as a big left delimiter before the second argument.
+As an optional third argument,
+.Cm right
+can follow.
+In that case, the fourth argument is set as a big right delimiter after
+the second argument.
+.It Cm lpile
+Like
+.Cm cpile ,
+but subequations are left-justified.
+.It Cm matrix
+Followed by a list of columns enclosed in braces.
+All columns need to have the same number of subequations.
+The columns are set as a matrix.
+The difference compared to multiple subsequent
+.Cm pile
+operators is that in a
+.Cm matrix ,
+corresponding subequations in all columns line up horizontally,
+while each
+.Cm pile
+does vertical spacing independently.
+.It Cm over
+Set a fraction.
+The preceding box is the numerator, the following box is the denominator.
+.It Cm pile
+Followed by a list of subequations enclosed in braces,
+the subequations being separated by
+.Cm above
+keywords.
+Sets the subequations one above the other, each of them centered.
+Typically used to represent vectors in coordinate representation.
+.It Cm rcol
+Like
+.Cm rpile ,
+but for use in
+.Cm matrix .
+.It Cm right
+See
+.Cm left ;
+.Cm right
+cannot be used without
+.Cm left .
+To set a big right delimiter without a big left delimiter, the following
+construction can be used:
+.Pp
+.D1 Cm left No \(dq\(dq Ar box Cm right Ar delimiter
+.It Cm roman
+Set the following box using the default font.
+.It Cm rpile
+Like
+.Cm cpile ,
+but subequations are right-justified.
+.It Cm size
+Set the second argument with the font size specified by the first
+argument; currently ignored by
+.Xr mandoc 1 .
+By prepending a plus or minus sign to the first argument,
+the font size can be selected relative to the current size.
+.It Cm sqrt
+Set the square root of the following box.
+.It Cm sub
+Set the following box as a subscript to the preceding box.
+.It Cm sup
+Set the following box as a superscript to the preceding box.
+As a special case, if a
+.Cm sup
+clause immediately follows a
+.Cm sub
+clause as in
+.Pp
+.D1 Ar mainbox Cm sub Ar subbox Cm sup Ar supbox
+.Pp
+both are set with respect to the same
+.Ar mainbox ,
+that is,
+.Ar supbox
+is set above
+.Ar subbox .
+.It Cm tilde
+Set a tilde over the preceding box.
+.It Cm to
+Set the following box above the preceding box,
+using a slightly smaller font.
+Used for sums and integrals and the like.
+As a special case, if a
+.Cm to
+clause immediately follows a
+.Cm from
+clause as in
+.Pp
+.D1 Ar mainbox Cm from Ar frombox Cm to Ar tobox
+.Pp
+both are set below and above the same
+.Ar mainbox .
+.It Cm under
+Underline the preceding box.
+.It Cm vec
+Set a vector symbol (right arrow) over the preceding box.
+.El
+.Pp
+The binary operations
+.Cm from ,
+.Cm to ,
+.Cm sub ,
+and
+.Cm sup
+group to the right, that is,
+.Pp
+.D1 Ar mainbox Cm sup Ar supbox Cm sub Ar subbox
+.Pp
+is the same as
+.Pp
+.D1 Ar mainbox Cm sup Brq Ar supbox Cm sub Ar subbox
+.Pp
+and different from
+.Pp
+.D1 Bro Ar mainbox Cm sup Ar supbox Brc Cm sub Ar subbox .
+.Pp
+By contrast,
+.Cm over
+groups to the left.
+.Pp
+In the following list, earlier operations bind more tightly than
+later operations:
+.Pp
+.Bl -enum -compact
+.It
+.Cm dyad ,
+.Cm vec ,
+.Cm under ,
+.Cm bar ,
+.Cm tilde ,
+.Cm hat ,
+.Cm dot ,
+.Cm dotdot
+.It
+.Cm fat ,
+.Cm roman ,
+.Cm italic ,
+.Cm bold ,
+.Cm size
+.It
+.Cm sub ,
+.Cm sup
+.It
+.Cm sqrt
+.It
+.Cm over
+.It
+.Cm from ,
+.Cm to
+.El
.Sh COMPATIBILITY
This section documents the compatibility of mandoc
.Nm
@@ -236,6 +457,11 @@ The
and
.Cm down Ar n
commands are also ignored.
+.It
+Inline equations and the
+.Cm delim
+control statement are not yet implemented in
+.Xr mandoc 1 .
.El
.Sh SEE ALSO
.Xr mandoc 1 ,
diff --git a/eqn.c b/eqn.c
index cda0db5d26e4..a64031b29b9c 100644
--- a/eqn.c
+++ b/eqn.c
@@ -1,6 +1,7 @@
-/* $Id: eqn.c,v 1.44 2014/07/06 19:09:00 schwarze Exp $ */
+/* $Id: eqn.c,v 1.56 2014/10/25 15:06:30 schwarze Exp $ */
/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2014 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
@@ -14,9 +15,9 @@
* 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 <assert.h>
#include <limits.h>
@@ -30,14 +31,109 @@
#include "libmandoc.h"
#include "libroff.h"
+#define EQN_MSG(t, x) \
+ mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
-#define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
+#define STRNEQ(p1, sz1, p2, sz2) \
+ ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
-enum eqn_rest {
- EQN_DESCOPE,
- EQN_ERR,
- EQN_OK,
- EQN_EOF
+enum eqn_tok {
+ EQN_TOK_DYAD = 0,
+ EQN_TOK_VEC,
+ EQN_TOK_UNDER,
+ EQN_TOK_BAR,
+ EQN_TOK_TILDE,
+ EQN_TOK_HAT,
+ EQN_TOK_DOT,
+ EQN_TOK_DOTDOT,
+ EQN_TOK_FWD,
+ EQN_TOK_BACK,
+ EQN_TOK_DOWN,
+ EQN_TOK_UP,
+ EQN_TOK_FAT,
+ EQN_TOK_ROMAN,
+ EQN_TOK_ITALIC,
+ EQN_TOK_BOLD,
+ EQN_TOK_SIZE,
+ EQN_TOK_SUB,
+ EQN_TOK_SUP,
+ EQN_TOK_SQRT,
+ EQN_TOK_OVER,
+ EQN_TOK_FROM,
+ EQN_TOK_TO,
+ EQN_TOK_BRACE_OPEN,
+ EQN_TOK_BRACE_CLOSE,
+ EQN_TOK_GSIZE,
+ EQN_TOK_GFONT,
+ EQN_TOK_MARK,
+ EQN_TOK_LINEUP,
+ EQN_TOK_LEFT,
+ EQN_TOK_RIGHT,
+ EQN_TOK_PILE,
+ EQN_TOK_LPILE,
+ EQN_TOK_RPILE,
+ EQN_TOK_CPILE,
+ EQN_TOK_MATRIX,
+ EQN_TOK_CCOL,
+ EQN_TOK_LCOL,
+ EQN_TOK_RCOL,
+ EQN_TOK_DELIM,
+ EQN_TOK_DEFINE,
+ EQN_TOK_TDEFINE,
+ EQN_TOK_NDEFINE,
+ EQN_TOK_UNDEF,
+ EQN_TOK_EOF,
+ EQN_TOK_ABOVE,
+ EQN_TOK__MAX
+};
+
+static const char *eqn_toks[EQN_TOK__MAX] = {
+ "dyad", /* EQN_TOK_DYAD */
+ "vec", /* EQN_TOK_VEC */
+ "under", /* EQN_TOK_UNDER */
+ "bar", /* EQN_TOK_BAR */
+ "tilde", /* EQN_TOK_TILDE */
+ "hat", /* EQN_TOK_HAT */
+ "dot", /* EQN_TOK_DOT */
+ "dotdot", /* EQN_TOK_DOTDOT */
+ "fwd", /* EQN_TOK_FWD * */
+ "back", /* EQN_TOK_BACK */
+ "down", /* EQN_TOK_DOWN */
+ "up", /* EQN_TOK_UP */
+ "fat", /* EQN_TOK_FAT */
+ "roman", /* EQN_TOK_ROMAN */
+ "italic", /* EQN_TOK_ITALIC */
+ "bold", /* EQN_TOK_BOLD */
+ "size", /* EQN_TOK_SIZE */
+ "sub", /* EQN_TOK_SUB */
+ "sup", /* EQN_TOK_SUP */
+ "sqrt", /* EQN_TOK_SQRT */
+ "over", /* EQN_TOK_OVER */
+ "from", /* EQN_TOK_FROM */
+ "to", /* EQN_TOK_TO */
+ "{", /* EQN_TOK_BRACE_OPEN */
+ "}", /* EQN_TOK_BRACE_CLOSE */
+ "gsize", /* EQN_TOK_GSIZE */
+ "gfont", /* EQN_TOK_GFONT */
+ "mark", /* EQN_TOK_MARK */
+ "lineup", /* EQN_TOK_LINEUP */
+ "left", /* EQN_TOK_LEFT */
+ "right", /* EQN_TOK_RIGHT */
+ "pile", /* EQN_TOK_PILE */
+ "lpile", /* EQN_TOK_LPILE */
+ "rpile", /* EQN_TOK_RPILE */
+ "cpile", /* EQN_TOK_CPILE */
+ "matrix", /* EQN_TOK_MATRIX */
+ "ccol", /* EQN_TOK_CCOL */
+ "lcol", /* EQN_TOK_LCOL */
+ "rcol", /* EQN_TOK_RCOL */
+ "delim", /* EQN_TOK_DELIM */
+ "define", /* EQN_TOK_DEFINE */
+ "tdefine", /* EQN_TOK_TDEFINE */
+ "ndefine", /* EQN_TOK_NDEFINE */
+ "undef", /* EQN_TOK_UNDEF */
+ NULL, /* EQN_TOK_EOF */
+ "above", /* EQN_TOK_ABOVE */
};
enum eqn_symt {
@@ -103,181 +199,73 @@ enum eqn_symt {
EQNSYM__MAX
};
-enum eqnpartt {
- EQN_DEFINE = 0,
- EQN_NDEFINE,
- EQN_TDEFINE,
- EQN_SET,
- EQN_UNDEF,
- EQN_GFONT,
- EQN_GSIZE,
- EQN_BACK,
- EQN_FWD,
- EQN_UP,
- EQN_DOWN,
- EQN__MAX
-};
-
-struct eqnstr {
- const char *name;
- size_t sz;
-};
-
-#define STRNEQ(p1, sz1, p2, sz2) \
- ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
-#define EQNSTREQ(x, p, sz) \
- STRNEQ((x)->name, (x)->sz, (p), (sz))
-
-struct eqnpart {
- struct eqnstr str;
- int (*fp)(struct eqn_node *);
-};
-
struct eqnsym {
- struct eqnstr str;
+ const char *str;
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 *,
- struct eqn_box *);
-static void eqn_box_free(struct eqn_box *);
-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 *);
-static int eqn_do_define(struct eqn_node *);
-static int eqn_do_ign1(struct eqn_node *);
-static int eqn_do_ign2(struct eqn_node *);
-static int eqn_do_tdefine(struct eqn_node *);
-static int eqn_do_undef(struct eqn_node *);
-static enum eqn_rest eqn_eqn(struct eqn_node *, struct eqn_box *);
-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 *,
- char, size_t *, int);
-static void eqn_rewind(struct eqn_node *);
-
-static const struct eqnpart eqnparts[EQN__MAX] = {
- { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
- { { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */
- { { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */
- { { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */
- { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
- { { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */
- { { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */
- { { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */
- { { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */
- { { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */
- { { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */
-};
-
-static const struct eqnstr eqnmarks[EQNMARK__MAX] = {
- { "", 0 }, /* EQNMARK_NONE */
- { "dot", 3 }, /* EQNMARK_DOT */
- { "dotdot", 6 }, /* EQNMARK_DOTDOT */
- { "hat", 3 }, /* EQNMARK_HAT */
- { "tilde", 5 }, /* EQNMARK_TILDE */
- { "vec", 3 }, /* EQNMARK_VEC */
- { "dyad", 4 }, /* EQNMARK_DYAD */
- { "bar", 3 }, /* EQNMARK_BAR */
- { "under", 5 }, /* EQNMARK_UNDER */
-};
-
-static const struct eqnstr eqnfonts[EQNFONT__MAX] = {
- { "", 0 }, /* EQNFONT_NONE */
- { "roman", 5 }, /* EQNFONT_ROMAN */
- { "bold", 4 }, /* EQNFONT_BOLD */
- { "fat", 3 }, /* EQNFONT_FAT */
- { "italic", 6 }, /* EQNFONT_ITALIC */
-};
-
-static const struct eqnstr eqnposs[EQNPOS__MAX] = {
- { "", 0 }, /* EQNPOS_NONE */
- { "over", 4 }, /* EQNPOS_OVER */
- { "sup", 3 }, /* EQNPOS_SUP */
- { "sub", 3 }, /* EQNPOS_SUB */
- { "to", 2 }, /* EQNPOS_TO */
- { "from", 4 }, /* EQNPOS_FROM */
-};
-
-static const struct eqnstr eqnpiles[EQNPILE__MAX] = {
- { "", 0 }, /* EQNPILE_NONE */
- { "pile", 4 }, /* EQNPILE_PILE */
- { "cpile", 5 }, /* EQNPILE_CPILE */
- { "rpile", 5 }, /* EQNPILE_RPILE */
- { "lpile", 5 }, /* EQNPILE_LPILE */
- { "col", 3 }, /* EQNPILE_COL */
- { "ccol", 4 }, /* EQNPILE_CCOL */
- { "rcol", 4 }, /* EQNPILE_RCOL */
- { "lcol", 4 }, /* EQNPILE_LCOL */
-};
-
static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
- { { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
- { { "beta", 4 }, "*b" }, /* EQNSYM_beta */
- { { "chi", 3 }, "*x" }, /* EQNSYM_chi */
- { { "delta", 5 }, "*d" }, /* EQNSYM_delta */
- { { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
- { { "eta", 3 }, "*y" }, /* EQNSYM_eta */
- { { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
- { { "iota", 4 }, "*i" }, /* EQNSYM_iota */
- { { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
- { { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
- { { "mu", 2 }, "*m" }, /* EQNSYM_mu */
- { { "nu", 2 }, "*n" }, /* EQNSYM_nu */
- { { "omega", 5 }, "*w" }, /* EQNSYM_omega */
- { { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
- { { "phi", 3 }, "*f" }, /* EQNSYM_phi */
- { { "pi", 2 }, "*p" }, /* EQNSYM_pi */
- { { "psi", 2 }, "*q" }, /* EQNSYM_psi */
- { { "rho", 3 }, "*r" }, /* EQNSYM_rho */
- { { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
- { { "tau", 3 }, "*t" }, /* EQNSYM_tau */
- { { "theta", 5 }, "*h" }, /* EQNSYM_theta */
- { { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
- { { "xi", 2 }, "*c" }, /* EQNSYM_xi */
- { { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
- { { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
- { { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
- { { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
- { { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
- { { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
- { { "PI", 2 }, "*P" }, /* EQNSYM_PI */
- { { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
- { { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
- { { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
- { { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
- { { "XI", 2 }, "*C" }, /* EQNSYM_XI */
- { { "inter", 5 }, "ca" }, /* EQNSYM_inter */
- { { "union", 5 }, "cu" }, /* EQNSYM_union */
- { { "prod", 4 }, "product" }, /* EQNSYM_prod */
- { { "int", 3 }, "integral" }, /* EQNSYM_int */
- { { "sum", 3 }, "sum" }, /* EQNSYM_sum */
- { { "grad", 4 }, "gr" }, /* EQNSYM_grad */
- { { "del", 3 }, "gr" }, /* EQNSYM_del */
- { { "times", 5 }, "mu" }, /* EQNSYM_times */
- { { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
- { { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
- { { "approx", 6 }, "~~" }, /* EQNSYM_approx */
- { { "prime", 5 }, "aq" }, /* EQNSYM_prime */
- { { "half", 4 }, "12" }, /* EQNSYM_half */
- { { "partial", 7 }, "pd" }, /* EQNSYM_partial */
- { { "inf", 3 }, "if" }, /* EQNSYM_inf */
- { { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
- { { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
- { { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
- { { "->", 2 }, "->" }, /* EQNSYM_rarrow */
- { { "+-", 2 }, "+-" }, /* EQNSYM_pm */
- { { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
- { { "==", 2 }, "==" }, /* EQNSYM_equiv */
- { { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
- { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
+ { "alpha", "*a" }, /* EQNSYM_alpha */
+ { "beta", "*b" }, /* EQNSYM_beta */
+ { "chi", "*x" }, /* EQNSYM_chi */
+ { "delta", "*d" }, /* EQNSYM_delta */
+ { "epsilon", "*e" }, /* EQNSYM_epsilon */
+ { "eta", "*y" }, /* EQNSYM_eta */
+ { "gamma", "*g" }, /* EQNSYM_gamma */
+ { "iota", "*i" }, /* EQNSYM_iota */
+ { "kappa", "*k" }, /* EQNSYM_kappa */
+ { "lambda", "*l" }, /* EQNSYM_lambda */
+ { "mu", "*m" }, /* EQNSYM_mu */
+ { "nu", "*n" }, /* EQNSYM_nu */
+ { "omega", "*w" }, /* EQNSYM_omega */
+ { "omicron", "*o" }, /* EQNSYM_omicron */
+ { "phi", "*f" }, /* EQNSYM_phi */
+ { "pi", "*p" }, /* EQNSYM_pi */
+ { "psi", "*q" }, /* EQNSYM_psi */
+ { "rho", "*r" }, /* EQNSYM_rho */
+ { "sigma", "*s" }, /* EQNSYM_sigma */
+ { "tau", "*t" }, /* EQNSYM_tau */
+ { "theta", "*h" }, /* EQNSYM_theta */
+ { "upsilon", "*u" }, /* EQNSYM_upsilon */
+ { "xi", "*c" }, /* EQNSYM_xi */
+ { "zeta", "*z" }, /* EQNSYM_zeta */
+ { "DELTA", "*D" }, /* EQNSYM_DELTA */
+ { "GAMMA", "*G" }, /* EQNSYM_GAMMA */
+ { "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */
+ { "OMEGA", "*W" }, /* EQNSYM_OMEGA */
+ { "PHI", "*F" }, /* EQNSYM_PHI */
+ { "PI", "*P" }, /* EQNSYM_PI */
+ { "PSI", "*Q" }, /* EQNSYM_PSI */
+ { "SIGMA", "*S" }, /* EQNSYM_SIGMA */
+ { "THETA", "*H" }, /* EQNSYM_THETA */
+ { "UPSILON", "*U" }, /* EQNSYM_UPSILON */
+ { "XI", "*C" }, /* EQNSYM_XI */
+ { "inter", "ca" }, /* EQNSYM_inter */
+ { "union", "cu" }, /* EQNSYM_union */
+ { "prod", "product" }, /* EQNSYM_prod */
+ { "int", "integral" }, /* EQNSYM_int */
+ { "sum", "sum" }, /* EQNSYM_sum */
+ { "grad", "gr" }, /* EQNSYM_grad */
+ { "del", "gr" }, /* EQNSYM_del */
+ { "times", "mu" }, /* EQNSYM_times */
+ { "cdot", "pc" }, /* EQNSYM_cdot */
+ { "nothing", "&" }, /* EQNSYM_nothing */
+ { "approx", "~~" }, /* EQNSYM_approx */
+ { "prime", "aq" }, /* EQNSYM_prime */
+ { "half", "12" }, /* EQNSYM_half */
+ { "partial", "pd" }, /* EQNSYM_partial */
+ { "inf", "if" }, /* EQNSYM_inf */
+ { ">>", ">>" }, /* EQNSYM_muchgreat */
+ { "<<", "<<" }, /* EQNSYM_muchless */
+ { "<-", "<-" }, /* EQNSYM_larrow */
+ { "->", "->" }, /* EQNSYM_rarrow */
+ { "+-", "+-" }, /* EQNSYM_pm */
+ { "!=", "!=" }, /* EQNSYM_nequal */
+ { "==", "==" }, /* EQNSYM_equiv */
+ { "<=", "<=" }, /* EQNSYM_lessequal */
+ { ">=", ">=" }, /* EQNSYM_moreequal */
};
-
enum rofferr
eqn_read(struct eqn_node **epp, int ln,
const char *p, int pos, int *offs)
@@ -325,24 +313,12 @@ eqn_read(struct eqn_node **epp, int ln,
}
struct eqn_node *
-eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
+eqn_alloc(int pos, int line, struct mparse *parse)
{
struct eqn_node *p;
- size_t sz;
- const char *end;
p = mandoc_calloc(1, sizeof(struct eqn_node));
- if (name && '\0' != *name) {
- sz = strlen(name);
- assert(sz);
- do {
- sz--;
- end = name + (int)sz;
- } while (' ' == *end || '\t' == *end);
- p->eqn.name = mandoc_strndup(name, sz + 1);
- }
-
p->parse = parse;
p->eqn.ln = line;
p->eqn.pos = pos;
@@ -351,365 +327,27 @@ eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
return(p);
}
-enum rofferr
-eqn_end(struct eqn_node **epp)
-{
- struct eqn_node *ep;
- struct eqn_box *root;
- enum eqn_rest c;
-
- ep = *epp;
- *epp = NULL;
-
- ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
-
- root = ep->eqn.root;
- root->type = EQN_ROOT;
-
- if (0 == ep->sz)
- return(ROFF_IGN);
-
- if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
- EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
- c = EQN_ERR;
- }
-
- return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
-}
-
-static enum eqn_rest
-eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
-{
- struct eqn_box *bp;
- enum eqn_rest c;
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_SUBEXPR;
-
- while (EQN_OK == (c = eqn_box(ep, bp)))
- /* Spin! */ ;
-
- return(c);
-}
-
-static enum eqn_rest
-eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
-{
- struct eqn_box *bp;
- const char *start;
- size_t sz;
- enum eqn_rest c;
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_MATRIX;
-
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- if ( ! STRNEQ(start, sz, "{", 1)) {
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- }
-
- while (EQN_OK == (c = eqn_box(ep, bp)))
- switch (bp->last->pile) {
- case EQNPILE_LCOL:
- /* FALLTHROUGH */
- case EQNPILE_CCOL:
- /* FALLTHROUGH */
- case EQNPILE_RCOL:
- continue;
- default:
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- };
-
- if (EQN_DESCOPE != c) {
- if (EQN_EOF == c)
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
-
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_OK);
-
- EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
- return(EQN_ERR);
-}
-
-static enum eqn_rest
-eqn_list(struct eqn_node *ep, struct eqn_box *last)
-{
- struct eqn_box *bp;
- const char *start;
- size_t sz;
- enum eqn_rest c;
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_LIST;
-
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- if ( ! STRNEQ(start, sz, "{", 1)) {
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- }
-
- while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if ( ! STRNEQ(start, sz, "above", 5))
- break;
- }
-
- if (EQN_DESCOPE != c) {
- if (EQN_ERR != c)
- EQN_MSG(MANDOCERR_EQNSCOPE, ep);
- return(EQN_ERR);
- }
-
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_OK);
-
- EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
- return(EQN_ERR);
-}
-
-static enum eqn_rest
-eqn_box(struct eqn_node *ep, struct eqn_box *last)
-{
- size_t sz;
- const char *start;
- char *left;
- char sym[64];
- enum eqn_rest c;
- int i, size;
- struct eqn_box *bp;
-
- if (NULL == (start = eqn_nexttok(ep, &sz)))
- return(EQN_EOF);
-
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_DESCOPE);
- else if (STRNEQ(start, sz, "right", 5))
- return(EQN_DESCOPE);
- else if (STRNEQ(start, sz, "above", 5))
- return(EQN_DESCOPE);
- else if (STRNEQ(start, sz, "mark", 4))
- return(EQN_OK);
- else if (STRNEQ(start, sz, "lineup", 6))
- return(EQN_OK);
-
- 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);
- }
-
- if (STRNEQ(start, sz, "{", 1)) {
- if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
- if (EQN_ERR != c)
- EQN_MSG(MANDOCERR_EQNSCOPE, ep);
- return(EQN_ERR);
- }
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if (STRNEQ(start, sz, "}", 1))
- 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))
- continue;
- if (EQN_OK == (c = eqn_list(ep, last)))
- last->last->pile = (enum eqn_pilet)i;
- return(c);
- }
-
- if (STRNEQ(start, sz, "matrix", 6))
- return(eqn_matrix(ep, last));
-
- if (STRNEQ(start, sz, "left", 4)) {
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- left = mandoc_strndup(start, sz);
- c = eqn_eqn(ep, last);
- if (last->last)
- last->last->left = left;
- else
- free(left);
- if (EQN_DESCOPE != c)
- return(c);
- assert(last->last);
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if ( ! STRNEQ(start, sz, "right", 5))
- return(EQN_DESCOPE);
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- last->last->right = mandoc_strndup(start, sz);
- return(EQN_OK);
- }
-
- for (i = 0; i < (int)EQNPOS__MAX; i++) {
- if ( ! EQNSTREQ(&eqnposs[i], start, sz))
- continue;
- 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);
- return(EQN_ERR);
- }
- return(c);
- }
-
- for (i = 0; i < (int)EQNMARK__MAX; i++) {
- if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
- continue;
- 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);
- return(EQN_ERR);
- }
- return(c);
- }
-
- for (i = 0; i < (int)EQNFONT__MAX; i++) {
- if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
- continue;
- if (EQN_EOF == (c = eqn_box(ep, last))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- } else if (EQN_OK == c)
- last->last->font = (enum eqn_fontt)i;
- return(c);
- }
-
- if (STRNEQ(start, sz, "size", 4)) {
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- size = mandoc_strntoi(start, sz, 10);
- if (EQN_EOF == (c = eqn_box(ep, last))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- } else if (EQN_OK != c)
- return(c);
- last->last->size = size;
- }
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_TEXT;
- for (i = 0; i < (int)EQNSYM__MAX; i++)
- if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
- sym[63] = '\0';
- (void)snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
- bp->text = mandoc_strdup(sym);
- return(EQN_OK);
- }
-
- bp->text = mandoc_strndup(start, sz);
- return(EQN_OK);
-}
-
-void
-eqn_free(struct eqn_node *p)
+/*
+ * Find the key "key" of the give size within our eqn-defined values.
+ */
+static struct eqn_def *
+eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
{
int i;
- eqn_box_free(p->eqn.root);
-
- for (i = 0; i < (int)p->defsz; i++) {
- free(p->defs[i].key);
- free(p->defs[i].val);
- }
-
- free(p->eqn.name);
- free(p->data);
- free(p->defs);
- free(p);
-}
-
-static struct eqn_box *
-eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
-{
- struct eqn_box *bp;
-
- bp = mandoc_calloc(1, sizeof(struct eqn_box));
- bp->parent = parent;
- bp->size = ep->gsize;
-
- if (NULL == parent->first)
- parent->first = bp;
- else
- parent->last->next = bp;
-
- parent->last = bp;
- return(bp);
-}
-
-static void
-eqn_box_free(struct eqn_box *bp)
-{
-
- if (bp->first)
- eqn_box_free(bp->first);
- if (bp->next)
- eqn_box_free(bp->next);
-
- free(bp->text);
- free(bp->left);
- free(bp->right);
- free(bp);
-}
-
-static const char *
-eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
-{
-
- return(eqn_next(ep, '"', sz, 0));
-}
-
-static const char *
-eqn_nexttok(struct eqn_node *ep, size_t *sz)
-{
-
- return(eqn_next(ep, '"', sz, 1));
-}
-
-static void
-eqn_rewind(struct eqn_node *ep)
-{
+ 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]);
- ep->cur = ep->rew;
+ return(NULL);
}
+/*
+ * Get the next token from the input stream using the given quote
+ * character.
+ * Optionally make any replacements.
+ */
static const char *
eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
{
@@ -799,48 +437,187 @@ again:
return(start);
}
-static int
-eqn_do_ign1(struct eqn_node *ep)
+/*
+ * Get the next delimited token using the default current quote
+ * character.
+ */
+static const char *
+eqn_nexttok(struct eqn_node *ep, size_t *sz)
{
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else
- return(1);
+ return(eqn_next(ep, '"', sz, 1));
+}
- return(0);
+/*
+ * Get next token without replacement.
+ */
+static const char *
+eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
+{
+
+ return(eqn_next(ep, '"', sz, 0));
}
-static int
-eqn_do_ign2(struct eqn_node *ep)
+/*
+ * Parse a token from the stream of text.
+ * A token consists of one of the recognised eqn(7) strings.
+ * Strings are separated by delimiting marks.
+ * This returns EQN_TOK_EOF when there are no more tokens.
+ * If the token is an unrecognised string literal, then it returns
+ * EQN_TOK__MAX and sets the "p" pointer to an allocated, nil-terminated
+ * string.
+ * This must be later freed with free(3).
+ */
+static enum eqn_tok
+eqn_tok_parse(struct eqn_node *ep, char **p)
+{
+ const char *start;
+ size_t i, sz;
+ int quoted;
+
+ if (NULL != p)
+ *p = NULL;
+
+ quoted = ep->data[ep->cur] == '"';
+
+ if (NULL == (start = eqn_nexttok(ep, &sz)))
+ return(EQN_TOK_EOF);
+
+ if (quoted) {
+ if (p != NULL)
+ *p = mandoc_strndup(start, sz);
+ return(EQN_TOK__MAX);
+ }
+
+ for (i = 0; i < EQN_TOK__MAX; i++) {
+ if (NULL == eqn_toks[i])
+ continue;
+ if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i])))
+ break;
+ }
+
+ if (i == EQN_TOK__MAX && NULL != p)
+ *p = mandoc_strndup(start, sz);
+
+ return(i);
+}
+
+static void
+eqn_box_free(struct eqn_box *bp)
{
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else
- return(1);
+ if (bp->first)
+ eqn_box_free(bp->first);
+ if (bp->next)
+ eqn_box_free(bp->next);
+
+ free(bp->text);
+ free(bp->left);
+ free(bp->right);
+ free(bp->top);
+ free(bp->bottom);
+ free(bp);
+}
+
+/*
+ * Allocate a box as the last child of the parent node.
+ */
+static struct eqn_box *
+eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
+{
+ struct eqn_box *bp;
+
+ bp = mandoc_calloc(1, sizeof(struct eqn_box));
+ bp->parent = parent;
+ bp->parent->args++;
+ bp->expectargs = UINT_MAX;
+ bp->size = ep->gsize;
+
+ if (NULL != parent->first) {
+ parent->last->next = bp;
+ bp->prev = parent->last;
+ } else
+ parent->first = bp;
+
+ parent->last = bp;
+ return(bp);
+}
+
+/*
+ * Reparent the current last node (of the current parent) under a new
+ * EQN_SUBEXPR as the first element.
+ * Then return the new parent.
+ * The new EQN_SUBEXPR will have a two-child limit.
+ */
+static struct eqn_box *
+eqn_box_makebinary(struct eqn_node *ep,
+ enum eqn_post pos, struct eqn_box *parent)
+{
+ struct eqn_box *b, *newb;
+
+ assert(NULL != parent->last);
+ b = parent->last;
+ if (parent->last == parent->first)
+ parent->first = NULL;
+ parent->args--;
+ parent->last = b->prev;
+ b->prev = NULL;
+ newb = eqn_box_alloc(ep, parent);
+ newb->pos = pos;
+ newb->type = EQN_SUBEXPR;
+ newb->expectargs = 2;
+ newb->args = 1;
+ newb->first = newb->last = b;
+ newb->first->next = NULL;
+ b->parent = newb;
+ return(newb);
+}
- return(0);
+/*
+ * Parse the "delim" control statement.
+ */
+static void
+eqn_delim(struct eqn_node *ep)
+{
+ const char *start;
+ size_t sz;
+
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "delim");
+ else if (strncmp(start, "off", 3) == 0)
+ ep->delim = 0;
+ else if (strncmp(start, "on", 2) == 0) {
+ if (ep->odelim && ep->cdelim)
+ ep->delim = 1;
+ } else if (start[1] != '\0') {
+ ep->odelim = start[0];
+ ep->cdelim = start[1];
+ ep->delim = 1;
+ }
}
+/*
+ * Undefine a previously-defined string.
+ */
static int
-eqn_do_tdefine(struct eqn_node *ep)
+eqn_undef(struct eqn_node *ep)
{
+ const char *start;
+ struct eqn_def *def;
+ size_t sz;
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
+ if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
EQN_MSG(MANDOCERR_EQNEOF, ep);
- else
- return(1);
+ return(0);
+ } else if (NULL != (def = eqn_def_find(ep, start, sz)))
+ def->keysz = 0;
- return(0);
+ return(1);
}
static int
-eqn_do_define(struct eqn_node *ep)
+eqn_def(struct eqn_node *ep)
{
const char *start;
size_t sz;
@@ -856,7 +633,6 @@ eqn_do_define(struct eqn_node *ep)
* Search for a key that already exists.
* Create a new key if none is found.
*/
-
if (NULL == (def = eqn_def_find(ep, start, sz))) {
/* Find holes in string array. */
for (i = 0; i < (int)ep->defsz; i++)
@@ -883,7 +659,7 @@ eqn_do_define(struct eqn_node *ep)
if (NULL == start) {
EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
+ return(-1);
}
def->valsz = sz;
@@ -893,56 +669,434 @@ eqn_do_define(struct eqn_node *ep)
return(1);
}
+/*
+ * Recursively parse an eqn(7) expression.
+ */
static int
-eqn_do_gfont(struct eqn_node *ep)
-{
-
- if (NULL == eqn_nextrawtok(ep, NULL)) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
- }
- return(1);
-}
-
-static int
-eqn_do_gsize(struct eqn_node *ep)
+eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
{
+ char *p;
+ enum eqn_tok tok, subtok;
+ enum eqn_post pos;
+ struct eqn_box *cur;
+ int rc, size;
+ size_t i, sz;
+ char sym[64];
const char *start;
- size_t sz;
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
+ assert(parent != NULL);
+ if (ep->data == NULL)
+ return(-1);
+
+next_tok:
+ tok = eqn_tok_parse(ep, &p);
+
+this_tok:
+ switch (tok) {
+ case (EQN_TOK_UNDEF):
+ if ((rc = eqn_undef(ep)) <= 0)
+ return(rc);
+ break;
+ case (EQN_TOK_NDEFINE):
+ case (EQN_TOK_DEFINE):
+ if ((rc = eqn_def(ep)) <= 0)
+ return(rc);
+ break;
+ case (EQN_TOK_TDEFINE):
+ if (NULL == eqn_nextrawtok(ep, NULL))
+ EQN_MSG(MANDOCERR_EQNEOF, ep);
+ else if (NULL == eqn_next(ep,
+ ep->data[(int)ep->cur], NULL, 0))
+ EQN_MSG(MANDOCERR_EQNEOF, ep);
+ break;
+ case (EQN_TOK_DELIM):
+ eqn_delim(ep);
+ break;
+ case (EQN_TOK_GFONT):
+ if (eqn_nextrawtok(ep, NULL) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ case (EQN_TOK_MARK):
+ case (EQN_TOK_LINEUP):
+ /* Ignore these. */
+ break;
+ case (EQN_TOK_DYAD):
+ case (EQN_TOK_VEC):
+ case (EQN_TOK_UNDER):
+ case (EQN_TOK_BAR):
+ case (EQN_TOK_TILDE):
+ case (EQN_TOK_HAT):
+ case (EQN_TOK_DOT):
+ case (EQN_TOK_DOTDOT):
+ if (parent->last == NULL) {
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ cur->text = mandoc_strdup("");
+ }
+ parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
+ parent->type = EQN_LISTONE;
+ parent->expectargs = 1;
+ switch (tok) {
+ case (EQN_TOK_DOTDOT):
+ strlcpy(sym, "\\[ad]", sizeof(sym));
+ break;
+ case (EQN_TOK_VEC):
+ strlcpy(sym, "\\[->]", sizeof(sym));
+ break;
+ case (EQN_TOK_DYAD):
+ strlcpy(sym, "\\[<>]", sizeof(sym));
+ break;
+ case (EQN_TOK_TILDE):
+ strlcpy(sym, "\\[a~]", sizeof(sym));
+ break;
+ case (EQN_TOK_UNDER):
+ strlcpy(sym, "\\[ul]", sizeof(sym));
+ break;
+ case (EQN_TOK_BAR):
+ strlcpy(sym, "\\[rl]", sizeof(sym));
+ break;
+ case (EQN_TOK_DOT):
+ strlcpy(sym, "\\[a.]", sizeof(sym));
+ break;
+ case (EQN_TOK_HAT):
+ strlcpy(sym, "\\[ha]", sizeof(sym));
+ break;
+ default:
+ abort();
+ }
+
+ switch (tok) {
+ case (EQN_TOK_DOTDOT):
+ case (EQN_TOK_VEC):
+ case (EQN_TOK_DYAD):
+ case (EQN_TOK_TILDE):
+ case (EQN_TOK_BAR):
+ case (EQN_TOK_DOT):
+ case (EQN_TOK_HAT):
+ parent->top = mandoc_strdup(sym);
+ break;
+ case (EQN_TOK_UNDER):
+ parent->bottom = mandoc_strdup(sym);
+ break;
+ default:
+ abort();
+ }
+ parent = parent->parent;
+ break;
+ case (EQN_TOK_FWD):
+ case (EQN_TOK_BACK):
+ case (EQN_TOK_DOWN):
+ case (EQN_TOK_UP):
+ subtok = eqn_tok_parse(ep, NULL);
+ if (subtok != EQN_TOK__MAX) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ tok = subtok;
+ goto this_tok;
+ }
+ break;
+ case (EQN_TOK_FAT):
+ case (EQN_TOK_ROMAN):
+ case (EQN_TOK_ITALIC):
+ case (EQN_TOK_BOLD):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ /*
+ * These values apply to the next word or sequence of
+ * words; thus, we mark that we'll have a child with
+ * exactly one of those.
+ */
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_LISTONE;
+ parent->expectargs = 1;
+ switch (tok) {
+ case (EQN_TOK_FAT):
+ parent->font = EQNFONT_FAT;
+ break;
+ case (EQN_TOK_ROMAN):
+ parent->font = EQNFONT_ROMAN;
+ break;
+ case (EQN_TOK_ITALIC):
+ parent->font = EQNFONT_ITALIC;
+ break;
+ case (EQN_TOK_BOLD):
+ parent->font = EQNFONT_BOLD;
+ break;
+ default:
+ abort();
+ }
+ break;
+ case (EQN_TOK_SIZE):
+ case (EQN_TOK_GSIZE):
+ /* Accept two values: integral size and a single. */
+ if (NULL == (start = eqn_nexttok(ep, &sz))) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ size = mandoc_strntoi(start, sz, 10);
+ if (-1 == size) {
+ mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ if (EQN_TOK_GSIZE == tok) {
+ ep->gsize = size;
+ break;
+ }
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_LISTONE;
+ parent->expectargs = 1;
+ parent->size = size;
+ break;
+ case (EQN_TOK_FROM):
+ case (EQN_TOK_TO):
+ case (EQN_TOK_SUB):
+ case (EQN_TOK_SUP):
+ /*
+ * We have a left-right-associative expression.
+ * Repivot under a positional node, open a child scope
+ * and keep on reading.
+ */
+ if (parent->last == NULL) {
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ cur->text = mandoc_strdup("");
+ }
+ /* Handle the "subsup" and "fromto" positions. */
+ if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
+ parent->expectargs = 3;
+ parent->pos = EQNPOS_SUBSUP;
+ break;
+ }
+ if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {
+ parent->expectargs = 3;
+ parent->pos = EQNPOS_FROMTO;
+ break;
+ }
+ switch (tok) {
+ case (EQN_TOK_FROM):
+ pos = EQNPOS_FROM;
+ break;
+ case (EQN_TOK_TO):
+ pos = EQNPOS_TO;
+ break;
+ case (EQN_TOK_SUP):
+ pos = EQNPOS_SUP;
+ break;
+ case (EQN_TOK_SUB):
+ pos = EQNPOS_SUB;
+ break;
+ default:
+ abort();
+ }
+ parent = eqn_box_makebinary(ep, pos, parent);
+ break;
+ case (EQN_TOK_SQRT):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ /*
+ * Accept a left-right-associative set of arguments just
+ * like sub and sup and friends but without rebalancing
+ * under a pivot.
+ */
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_SUBEXPR;
+ parent->pos = EQNPOS_SQRT;
+ parent->expectargs = 1;
+ break;
+ case (EQN_TOK_OVER):
+ /*
+ * We have a right-left-associative fraction.
+ * Close out anything that's currently open, then
+ * rebalance and continue reading.
+ */
+ if (parent->last == NULL) {
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ cur->text = mandoc_strdup("");
+ }
+ while (EQN_SUBEXPR == parent->type)
+ parent = parent->parent;
+ parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
+ break;
+ case (EQN_TOK_RIGHT):
+ case (EQN_TOK_BRACE_CLOSE):
+ /*
+ * Close out the existing brace.
+ * FIXME: this is a shitty sentinel: we should really
+ * have a native EQN_BRACE type or whatnot.
+ */
+ for (cur = parent; cur != NULL; cur = cur->parent)
+ if (cur->type == EQN_LIST &&
+ (tok == EQN_TOK_BRACE_CLOSE ||
+ cur->left != NULL))
+ break;
+ if (cur == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ parent = cur;
+ if (EQN_TOK_RIGHT == tok) {
+ if (NULL == (start = eqn_nexttok(ep, &sz))) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
+ ep->parse, ep->eqn.ln,
+ ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ /* Handling depends on right/left. */
+ if (STRNEQ(start, sz, "ceiling", 7)) {
+ strlcpy(sym, "\\[rc]", sizeof(sym));
+ parent->right = mandoc_strdup(sym);
+ } else if (STRNEQ(start, sz, "floor", 5)) {
+ strlcpy(sym, "\\[rf]", sizeof(sym));
+ parent->right = mandoc_strdup(sym);
+ } else
+ parent->right = mandoc_strndup(start, sz);
+ }
+ parent = parent->parent;
+ if (EQN_TOK_BRACE_CLOSE == tok && parent &&
+ (parent->type == EQN_PILE ||
+ parent->type == EQN_MATRIX))
+ parent = parent->parent;
+ /* Close out any "singleton" lists. */
+ while (parent->type == EQN_LISTONE &&
+ parent->args == parent->expectargs)
+ parent = parent->parent;
+ break;
+ case (EQN_TOK_BRACE_OPEN):
+ case (EQN_TOK_LEFT):
+ /*
+ * If we already have something in the stack and we're
+ * in an expression, then rewind til we're not any more
+ * (just like with the text node).
+ */
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ if (EQN_TOK_LEFT == tok &&
+ (start = eqn_nexttok(ep, &sz)) == NULL) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_LIST;
+ if (EQN_TOK_LEFT == tok) {
+ if (STRNEQ(start, sz, "ceiling", 7)) {
+ strlcpy(sym, "\\[lc]", sizeof(sym));
+ parent->left = mandoc_strdup(sym);
+ } else if (STRNEQ(start, sz, "floor", 5)) {
+ strlcpy(sym, "\\[lf]", sizeof(sym));
+ parent->left = mandoc_strdup(sym);
+ } else
+ parent->left = mandoc_strndup(start, sz);
+ }
+ break;
+ case (EQN_TOK_PILE):
+ case (EQN_TOK_LPILE):
+ case (EQN_TOK_RPILE):
+ case (EQN_TOK_CPILE):
+ case (EQN_TOK_CCOL):
+ case (EQN_TOK_LCOL):
+ case (EQN_TOK_RCOL):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_PILE;
+ parent->expectargs = 1;
+ break;
+ case (EQN_TOK_ABOVE):
+ for (cur = parent; cur != NULL; cur = cur->parent)
+ if (cur->type == EQN_PILE)
+ break;
+ if (cur == NULL) {
+ mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ parent = eqn_box_alloc(ep, cur);
+ parent->type = EQN_LIST;
+ break;
+ case (EQN_TOK_MATRIX):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_MATRIX;
+ parent->expectargs = 1;
+ break;
+ case (EQN_TOK_EOF):
+ /*
+ * End of file!
+ * TODO: make sure we're not in an open subexpression.
+ */
return(0);
+ default:
+ assert(tok == EQN_TOK__MAX);
+ assert(NULL != p);
+ /*
+ * If we already have something in the stack and we're
+ * in an expression, then rewind til we're not any more.
+ */
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ for (i = 0; i < EQNSYM__MAX; i++)
+ if (0 == strcmp(eqnsyms[i].str, p)) {
+ (void)snprintf(sym, sizeof(sym),
+ "\\[%s]", eqnsyms[i].sym);
+ cur->text = mandoc_strdup(sym);
+ free(p);
+ break;
+ }
+
+ if (i == EQNSYM__MAX)
+ cur->text = p;
+ /*
+ * Post-process list status.
+ */
+ while (parent->type == EQN_LISTONE &&
+ parent->args == parent->expectargs)
+ parent = parent->parent;
+ break;
}
- ep->gsize = mandoc_strntoi(start, sz, 10);
- return(1);
+ goto next_tok;
}
-static int
-eqn_do_undef(struct eqn_node *ep)
+enum rofferr
+eqn_end(struct eqn_node **epp)
{
- const char *start;
- struct eqn_def *def;
- size_t sz;
+ struct eqn_node *ep;
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
- } else if (NULL != (def = eqn_def_find(ep, start, sz)))
- def->keysz = 0;
+ ep = *epp;
+ *epp = NULL;
- return(1);
+ ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
+ ep->eqn.root->expectargs = UINT_MAX;
+ return(0 == eqn_parse(ep, ep->eqn.root) ? ROFF_EQN : ROFF_IGN);
}
-static struct eqn_def *
-eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
+void
+eqn_free(struct eqn_node *p)
{
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))
- return(&ep->defs[i]);
+ eqn_box_free(p->eqn.root);
- return(NULL);
+ for (i = 0; i < (int)p->defsz; i++) {
+ free(p->defs[i].key);
+ free(p->defs[i].val);
+ }
+
+ free(p->data);
+ free(p->defs);
+ free(p);
}
diff --git a/eqn_html.c b/eqn_html.c
index 3e58ab5880b5..f29733613bb9 100644
--- a/eqn_html.c
+++ b/eqn_html.c
@@ -1,6 +1,6 @@
-/* $Id: eqn_html.c,v 1.3 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: eqn_html.c,v 1.10 2014/10/12 19:31:41 schwarze Exp $ */
/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2014 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
@@ -14,9 +14,9 @@
* 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 <assert.h>
#include <stdio.h>
@@ -27,16 +27,153 @@
#include "out.h"
#include "html.h"
-static const enum htmltag fontmap[EQNFONT__MAX] = {
- TAG_SPAN, /* EQNFONT_NONE */
- TAG_SPAN, /* EQNFONT_ROMAN */
- TAG_B, /* EQNFONT_BOLD */
- TAG_B, /* EQNFONT_FAT */
- TAG_I /* EQNFONT_ITALIC */
-};
+static void
+eqn_box(struct html *p, const struct eqn_box *bp)
+{
+ struct tag *post, *row, *cell, *t;
+ struct htmlpair tag[2];
+ const struct eqn_box *child, *parent;
+ size_t i, j, rows;
+
+ if (NULL == bp)
+ return;
+
+ post = NULL;
+
+ /*
+ * Special handling for a matrix, which is presented to us in
+ * column order, but must be printed in row-order.
+ */
+ if (EQN_MATRIX == bp->type) {
+ if (NULL == bp->first)
+ goto out;
+ if (EQN_LIST != bp->first->type) {
+ eqn_box(p, bp->first);
+ goto out;
+ }
+ if (NULL == (parent = bp->first->first))
+ goto out;
+ /* Estimate the number of rows, first. */
+ if (NULL == (child = parent->first))
+ goto out;
+ for (rows = 0; NULL != child; rows++)
+ child = child->next;
+ /* Print row-by-row. */
+ post = print_otag(p, TAG_MTABLE, 0, NULL);
+ for (i = 0; i < rows; i++) {
+ parent = bp->first->first;
+ row = print_otag(p, TAG_MTR, 0, NULL);
+ while (NULL != parent) {
+ child = parent->first;
+ for (j = 0; j < i; j++) {
+ if (NULL == child)
+ break;
+ child = child->next;
+ }
+ cell = print_otag
+ (p, TAG_MTD, 0, NULL);
+ /*
+ * If we have no data for this
+ * particular cell, then print a
+ * placeholder and continue--don't puke.
+ */
+ if (NULL != child)
+ eqn_box(p, child->first);
+ print_tagq(p, cell);
+ parent = parent->next;
+ }
+ print_tagq(p, row);
+ }
+ goto out;
+ }
+
+ switch (bp->pos) {
+ case (EQNPOS_TO):
+ post = print_otag(p, TAG_MOVER, 0, NULL);
+ break;
+ case (EQNPOS_SUP):
+ post = print_otag(p, TAG_MSUP, 0, NULL);
+ break;
+ case (EQNPOS_FROM):
+ post = print_otag(p, TAG_MUNDER, 0, NULL);
+ break;
+ case (EQNPOS_SUB):
+ post = print_otag(p, TAG_MSUB, 0, NULL);
+ break;
+ case (EQNPOS_OVER):
+ post = print_otag(p, TAG_MFRAC, 0, NULL);
+ break;
+ case (EQNPOS_FROMTO):
+ post = print_otag(p, TAG_MUNDEROVER, 0, NULL);
+ break;
+ case (EQNPOS_SUBSUP):
+ post = print_otag(p, TAG_MSUBSUP, 0, NULL);
+ break;
+ case (EQNPOS_SQRT):
+ post = print_otag(p, TAG_MSQRT, 0, NULL);
+ break;
+ default:
+ break;
+ }
+
+ if (bp->top || bp->bottom) {
+ assert(NULL == post);
+ if (bp->top && NULL == bp->bottom)
+ post = print_otag(p, TAG_MOVER, 0, NULL);
+ else if (bp->top && bp->bottom)
+ post = print_otag(p, TAG_MUNDEROVER, 0, NULL);
+ else if (bp->bottom)
+ post = print_otag(p, TAG_MUNDER, 0, NULL);
+ }
+
+ if (EQN_PILE == bp->type) {
+ assert(NULL == post);
+ if (bp->first != NULL && bp->first->type == EQN_LIST)
+ post = print_otag(p, TAG_MTABLE, 0, NULL);
+ } else if (bp->type == EQN_LIST &&
+ bp->parent && bp->parent->type == EQN_PILE) {
+ assert(NULL == post);
+ post = print_otag(p, TAG_MTR, 0, NULL);
+ print_otag(p, TAG_MTD, 0, NULL);
+ }
+
+ if (NULL != bp->text) {
+ assert(NULL == post);
+ post = print_otag(p, TAG_MI, 0, NULL);
+ print_text(p, bp->text);
+ } else if (NULL == post) {
+ if (NULL != bp->left || NULL != bp->right) {
+ PAIR_INIT(&tag[0], ATTR_OPEN,
+ NULL == bp->left ? "" : bp->left);
+ PAIR_INIT(&tag[1], ATTR_CLOSE,
+ NULL == bp->right ? "" : bp->right);
+ post = print_otag(p, TAG_MFENCED, 2, tag);
+ }
+ if (NULL == post)
+ post = print_otag(p, TAG_MROW, 0, NULL);
+ else
+ print_otag(p, TAG_MROW, 0, NULL);
+ }
+
+ eqn_box(p, bp->first);
+
+out:
+ if (NULL != bp->bottom) {
+ t = print_otag(p, TAG_MO, 0, NULL);
+ print_text(p, bp->bottom);
+ print_tagq(p, t);
+ }
+ if (NULL != bp->top) {
+ t = print_otag(p, TAG_MO, 0, NULL);
+ print_text(p, bp->top);
+ print_tagq(p, t);
+ }
-static void eqn_box(struct html *, const struct eqn_box *);
+ if (NULL != post)
+ print_tagq(p, post);
+ eqn_box(p, bp->next);
+}
void
print_eqn(struct html *p, const struct eqn *ep)
@@ -45,7 +182,7 @@ print_eqn(struct html *p, const struct eqn *ep)
struct tag *t;
PAIR_CLASS_INIT(&tag, "eqn");
- t = print_otag(p, TAG_SPAN, 1, &tag);
+ t = print_otag(p, TAG_MATH, 1, &tag);
p->flags |= HTML_NONOSPACE;
eqn_box(p, ep->root);
@@ -53,29 +190,3 @@ print_eqn(struct html *p, const struct eqn *ep)
print_tagq(p, t);
}
-
-static void
-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);
-
- if (bp->left)
- print_text(p, bp->left);
-
- if (bp->text)
- print_text(p, bp->text);
-
- if (bp->first)
- eqn_box(p, bp->first);
-
- if (NULL != t)
- print_tagq(p, t);
- if (bp->right)
- print_text(p, bp->right);
-
- if (bp->next)
- eqn_box(p, bp->next);
-}
diff --git a/eqn_term.c b/eqn_term.c
index 889c5c6586f0..010a152e2567 100644
--- a/eqn_term.c
+++ b/eqn_term.c
@@ -1,6 +1,7 @@
-/* $Id: eqn_term.c,v 1.5 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: eqn_term.c,v 1.7 2014/10/12 14:49:39 schwarze Exp $ */
/*
* Copyright (c) 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
@@ -14,9 +15,9 @@
* 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 <assert.h>
#include <stdio.h>
@@ -42,36 +43,82 @@ void
term_eqn(struct termp *p, const struct eqn *ep)
{
- p->flags |= TERMP_NONOSPACE;
eqn_box(p, ep->root);
- term_word(p, " ");
- p->flags &= ~TERMP_NONOSPACE;
+ p->flags &= ~TERMP_NOSPACE;
}
static void
eqn_box(struct termp *p, const struct eqn_box *bp)
{
+ const struct eqn_box *child;
- if (EQNFONT_NONE != bp->font)
+ if (bp->type == EQN_LIST ||
+ (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
+ (bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
+ if (bp->parent->type == EQN_SUBEXPR && bp->prev != NULL)
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->left != NULL ? bp->left : "(");
+ p->flags |= TERMP_NOSPACE;
+ }
+ if (bp->font != EQNFONT_NONE)
term_fontpush(p, fontmap[(int)bp->font]);
- if (bp->left)
- term_word(p, bp->left);
- if (EQN_SUBEXPR == bp->type)
- term_word(p, "(");
- if (bp->text)
+ if (bp->text != NULL)
term_word(p, bp->text);
- if (bp->first)
+ if (bp->pos == EQNPOS_SQRT) {
+ term_word(p, "sqrt");
+ p->flags |= TERMP_NOSPACE;
eqn_box(p, bp->first);
+ } else if (bp->type == EQN_SUBEXPR) {
+ child = bp->first;
+ eqn_box(p, child);
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->pos == EQNPOS_OVER ? "/" :
+ (bp->pos == EQNPOS_SUP ||
+ bp->pos == EQNPOS_TO) ? "^" : "_");
+ p->flags |= TERMP_NOSPACE;
+ child = child->next;
+ eqn_box(p, child);
+ if (bp->pos == EQNPOS_FROMTO ||
+ bp->pos == EQNPOS_SUBSUP) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, "^");
+ p->flags |= TERMP_NOSPACE;
+ child = child->next;
+ eqn_box(p, child);
+ }
+ } else {
+ child = bp->first;
+ if (bp->type == EQN_MATRIX && child->type == EQN_LIST)
+ child = child->first;
+ while (child != NULL) {
+ eqn_box(p,
+ bp->type == EQN_PILE &&
+ child->type == EQN_LIST &&
+ child->args == 1 ?
+ child->first : child);
+ child = child->next;
+ }
+ }
- if (EQN_SUBEXPR == bp->type)
- term_word(p, ")");
- if (bp->right)
- term_word(p, bp->right);
- if (EQNFONT_NONE != bp->font)
+ if (bp->font != EQNFONT_NONE)
term_fontpop(p);
+ if (bp->type == EQN_LIST ||
+ (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
+ (bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->right != NULL ? bp->right : ")");
+ if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
+ p->flags |= TERMP_NOSPACE;
+ }
- if (bp->next)
- eqn_box(p, bp->next);
+ if (bp->top != NULL) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->top);
+ }
+ if (bp->bottom != NULL) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, "_");
+ }
}
diff --git a/example.style.css b/example.style.css
index 660f4d132000..d7d7e8571389 100644
--- a/example.style.css
+++ b/example.style.css
@@ -1,4 +1,4 @@
-/* $Id: example.style.css,v 1.49 2011/12/15 12:18:57 kristaps Exp $ */
+/* $Id: example.style.css,v 1.53 2014/09/27 11:16:24 kristaps Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
* or -Txhtml output mode.
@@ -20,11 +20,11 @@ div.mandoc div.subsection { } /* Sub-sections (Ss, SS). */
div.mandoc table.synopsis { } /* SYNOPSIS section table. */
div.mandoc table.foot { } /* Document footer. */
div.mandoc td.foot-date { width: 50%; } /* Document footer: date. */
-div.mandoc td.foot-os { width: 50%; text-align: right; } /* Document footer: OS/source. */
+div.mandoc td.foot-os { width: 50%; } /* Document footer: OS/source. */
div.mandoc table.head { } /* Document header. */
div.mandoc td.head-ltitle { width: 10%; } /* Document header: left-title. */
-div.mandoc td.head-vol { width: 80%; text-align: center; } /* Document header: volume. */
-div.mandoc td.head-rtitle { width: 10%; text-align: right; } /* Document header: right-title. */
+div.mandoc td.head-vol { width: 80%; } /* Document header: volume. */
+div.mandoc td.head-rtitle { width: 10%; } /* Document header: right-title. */
div.mandoc .display { } /* All Bd, D1, Dl. */
div.mandoc .list { } /* All Bl. */
div.mandoc i { } /* Italic: BI, IB, I, (implicit). */
@@ -108,3 +108,4 @@ div.mandoc ol.list-enum { padding-left: 2em; }
div.mandoc li.list-enum { }
div.mandoc span.eqn { } /* Equation modes. See eqn(7). */
div.mandoc table.tbl { } /* Table modes. See tbl(7). */
+div.mandoc div.spacer { margin: 1em 0; }
diff --git a/html.c b/html.c
index d4783ee06fdc..050fefe698ae 100644
--- a/html.c
+++ b/html.c
@@ -1,6 +1,6 @@
-/* $Id: html.c,v 1.159 2014/07/23 15:00:08 schwarze Exp $ */
+/* $Id: html.c,v 1.181 2014/10/29 00:17:43 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,9 +15,7 @@
* 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>
@@ -70,17 +68,31 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"dt", HTML_CLRLINE}, /* TAG_DT */
{"dd", HTML_CLRLINE}, /* TAG_DD */
{"blockquote", HTML_CLRLINE}, /* TAG_BLOCKQUOTE */
- {"p", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_P */
{"pre", HTML_CLRLINE }, /* TAG_PRE */
{"b", 0 }, /* TAG_B */
{"i", 0 }, /* TAG_I */
{"code", 0 }, /* TAG_CODE */
{"small", 0 }, /* TAG_SMALL */
+ {"style", HTML_CLRLINE}, /* TAG_STYLE */
+ {"math", HTML_CLRLINE}, /* TAG_MATH */
+ {"mrow", 0}, /* TAG_MROW */
+ {"mi", 0}, /* TAG_MI */
+ {"mo", 0}, /* TAG_MO */
+ {"msup", 0}, /* TAG_MSUP */
+ {"msub", 0}, /* TAG_MSUB */
+ {"msubsup", 0}, /* TAG_MSUBSUP */
+ {"mfrac", 0}, /* TAG_MFRAC */
+ {"msqrt", 0}, /* TAG_MSQRT */
+ {"mfenced", 0}, /* TAG_MFENCED */
+ {"mtable", 0}, /* TAG_MTABLE */
+ {"mtr", 0}, /* TAG_MTR */
+ {"mtd", 0}, /* TAG_MTD */
+ {"munderover", 0}, /* TAG_MUNDEROVER */
+ {"munder", 0}, /* TAG_MUNDER*/
+ {"mover", 0}, /* TAG_MOVER*/
};
static const char *const htmlattrs[ATTR_MAX] = {
- "http-equiv", /* ATTR_HTTPEQUIV */
- "content", /* ATTR_CONTENT */
"name", /* ATTR_NAME */
"rel", /* ATTR_REL */
"href", /* ATTR_HREF */
@@ -88,11 +100,12 @@ static const char *const htmlattrs[ATTR_MAX] = {
"media", /* ATTR_MEDIA */
"class", /* ATTR_CLASS */
"style", /* ATTR_STYLE */
- "width", /* ATTR_WIDTH */
"id", /* ATTR_ID */
- "summary", /* ATTR_SUMMARY */
- "align", /* ATTR_ALIGN */
"colspan", /* ATTR_COLSPAN */
+ "charset", /* ATTR_CHARSET */
+ "open", /* ATTR_OPEN */
+ "close", /* ATTR_CLOSE */
+ "mathvariant", /* ATTR_MATHVARIANT */
};
static const char *const roffscales[SCALE_MAX] = {
@@ -114,11 +127,10 @@ 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)
+void *
+html_alloc(const struct mchars *mchars, char *outopts)
{
struct html *h;
const char *toks[5];
@@ -132,9 +144,8 @@ ml_alloc(char *outopts, enum htmltype type)
h = mandoc_calloc(1, sizeof(struct html));
- h->type = type;
h->tags.head = NULL;
- h->symtab = mchars_alloc();
+ h->symtab = mchars;
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
@@ -157,20 +168,6 @@ ml_alloc(char *outopts, enum htmltype type)
return(h);
}
-void *
-html_alloc(char *outopts)
-{
-
- return(ml_alloc(outopts, HTML_HTML_4_01_STRICT));
-}
-
-void *
-xhtml_alloc(char *outopts)
-{
-
- return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT));
-}
-
void
html_free(void *p)
{
@@ -184,9 +181,6 @@ html_free(void *p)
free(tag);
}
- if (h->symtab)
- mchars_free(h->symtab);
-
free(h);
}
@@ -194,18 +188,23 @@ void
print_gen_head(struct html *h)
{
struct htmlpair tag[4];
+ struct tag *t;
- tag[0].key = ATTR_HTTPEQUIV;
- tag[0].val = "Content-Type";
- tag[1].key = ATTR_CONTENT;
- tag[1].val = "text/html; charset=utf-8";
- print_otag(h, TAG_META, 2, tag);
+ tag[0].key = ATTR_CHARSET;
+ tag[0].val = "utf-8";
+ print_otag(h, TAG_META, 1, tag);
- tag[0].key = ATTR_NAME;
- tag[0].val = "resource-type";
- tag[1].key = ATTR_CONTENT;
- tag[1].val = "document";
- print_otag(h, TAG_META, 2, tag);
+ /*
+ * Print a default style-sheet.
+ */
+ t = print_otag(h, TAG_STYLE, 0, NULL);
+ print_text(h, "table.head, table.foot { width: 100%; }\n"
+ "td.head-rtitle, td.foot-os { text-align: right; }\n"
+ "td.head-vol { text-align: center; }\n"
+ "table.foot td { width: 50%; }\n"
+ "table.head td { width: 33%; }\n"
+ "div.spacer { margin: 1em 0; }\n");
+ print_tagq(h, t);
if (h->style) {
tag[0].key = ATTR_REL;
@@ -420,29 +419,31 @@ print_encode(struct html *h, const char *p, int norecurse)
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:
c = mchars_num2char(seq, len);
- if ( ! ('\0' == c || print_escape(c)))
- putchar(c);
+ if (c < 0)
+ continue;
break;
case ESCAPE_SPECIAL:
c = mchars_spec2cp(h->symtab, seq, len);
- if (c > 0)
- printf("&#%d;", c);
- else if (-1 == c && 1 == len &&
- !print_escape(*seq))
- putchar((int)*seq);
+ if (c <= 0)
+ continue;
break;
case ESCAPE_NOSPACE:
if ('\0' == *p)
nospace = 1;
- break;
+ continue;
default:
- break;
+ continue;
}
+ if ((c < 0x20 && c != 0x09) ||
+ (c > 0x7E && c < 0xA0))
+ c = 0xFFFD;
+ if (c > 0x7E)
+ printf("&#%d;", c);
+ else if ( ! print_escape(c))
+ putchar(c);
}
return(nospace);
@@ -495,24 +496,10 @@ print_otag(struct html *h, enum htmltag tag,
for (i = 0; i < sz; i++)
print_attr(h, htmlattrs[p[i].key], p[i].val);
- /* Add non-overridable attributes. */
-
- if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) {
- print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml");
- print_attr(h, "xml:lang", "en");
- print_attr(h, "lang", "en");
- }
-
- /* Accommodate for XML "well-formed" singleton escaping. */
+ /* Accommodate for "well-formed" singleton escaping. */
if (HTML_AUTOCLOSE & htmltags[tag].flags)
- switch (h->type) {
- case HTML_XHTML_1_0_STRICT:
- putchar('/');
- break;
- default:
- break;
- }
+ putchar('/');
putchar('>');
@@ -538,26 +525,8 @@ print_ctag(struct html *h, enum htmltag tag)
void
print_gen_decls(struct html *h)
{
- const char *doctype;
- const char *dtd;
- const char *name;
-
- switch (h->type) {
- case HTML_HTML_4_01_STRICT:
- name = "HTML";
- doctype = "-//W3C//DTD HTML 4.01//EN";
- dtd = "http://www.w3.org/TR/html4/strict.dtd";
- break;
- default:
- puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- name = "html";
- doctype = "-//W3C//DTD XHTML 1.0 Strict//EN";
- dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
- break;
- }
- printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
- name, doctype, dtd);
+ puts("<!DOCTYPE html>");
}
void
@@ -650,6 +619,18 @@ print_stagq(struct html *h, const struct tag *suntil)
}
void
+print_paragraph(struct html *h)
+{
+ struct tag *t;
+ struct htmlpair tag;
+
+ PAIR_CLASS_INIT(&tag, "spacer");
+ t = print_otag(h, TAG_DIV, 1, &tag);
+ print_tagq(h, t);
+}
+
+
+void
bufinit(struct html *h)
{
@@ -761,6 +742,8 @@ bufcat_su(struct html *h, const char *p, const struct roffsu *su)
v = su->scale;
if (SCALE_MM == su->unit && 0.0 == (v /= 100.0))
v = 1.0;
+ else if (SCALE_BU == su->unit)
+ v /= 24.0;
bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]);
}
diff --git a/html.h b/html.h
index ca15f0f32164..521635f96fd9 100644
--- a/html.h
+++ b/html.h
@@ -1,6 +1,6 @@
-/* $Id: html.h,v 1.51 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: html.h,v 1.67 2014/10/28 17:36:19 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2011, 2014 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
@@ -44,18 +44,32 @@ enum htmltag {
TAG_DT,
TAG_DD,
TAG_BLOCKQUOTE,
- TAG_P,
TAG_PRE,
TAG_B,
TAG_I,
TAG_CODE,
TAG_SMALL,
+ TAG_STYLE,
+ TAG_MATH,
+ TAG_MROW,
+ TAG_MI,
+ TAG_MO,
+ TAG_MSUP,
+ TAG_MSUB,
+ TAG_MSUBSUP,
+ TAG_MFRAC,
+ TAG_MSQRT,
+ TAG_MFENCED,
+ TAG_MTABLE,
+ TAG_MTR,
+ TAG_MTD,
+ TAG_MUNDEROVER,
+ TAG_MUNDER,
+ TAG_MOVER,
TAG_MAX
};
enum htmlattr {
- ATTR_HTTPEQUIV,
- ATTR_CONTENT,
ATTR_NAME,
ATTR_REL,
ATTR_HREF,
@@ -63,11 +77,12 @@ enum htmlattr {
ATTR_MEDIA,
ATTR_CLASS,
ATTR_STYLE,
- ATTR_WIDTH,
ATTR_ID,
- ATTR_SUMMARY,
- ATTR_ALIGN,
ATTR_COLSPAN,
+ ATTR_CHARSET,
+ ATTR_OPEN,
+ ATTR_CLOSE,
+ ATTR_MATHVARIANT,
ATTR_MAX
};
@@ -103,12 +118,6 @@ struct htmlpair {
#define PAIR_CLASS_INIT(p, v) PAIR_INIT(p, ATTR_CLASS, v)
#define PAIR_HREF_INIT(p, v) PAIR_INIT(p, ATTR_HREF, v)
#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 {
- HTML_HTML_4_01_STRICT,
- HTML_XHTML_1_0_STRICT
-};
struct html {
int flags;
@@ -119,10 +128,12 @@ struct html {
#define HTML_NONOSPACE (1 << 4) /* never add spaces */
#define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */
#define HTML_SKIPCHAR (1 << 6) /* skip the next character */
+#define HTML_NOSPLIT (1 << 7) /* do not break line before .An */
+#define HTML_SPLIT (1 << 8) /* break line before .An */
struct tagq tags; /* stack of open tags */
struct rofftbl tbl; /* current table */
struct tag *tblt; /* current open table scope */
- struct mchars *symtab; /* character-escapes */
+ const struct mchars *symtab; /* character table */
char *base_man; /* base for manpage href */
char *base_includes; /* base for include href */
char *style; /* style-sheet URI */
@@ -131,7 +142,6 @@ struct html {
struct tag *metaf; /* current open font scope */
enum htmlfont metal; /* last used font */
enum htmlfont metac; /* current font mode */
- enum htmltype type; /* output media type */
int oflags; /* output options */
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
};
@@ -146,6 +156,7 @@ void print_text(struct html *, const char *);
void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
void print_eqn(struct html *, const struct eqn *);
+void print_paragraph(struct html *);
#if __GNUC__ - 0 >= 4
__attribute__((__format__ (__printf__, 2, 3)))
diff --git a/lib.c b/lib.c
index 8cc8a778a690..17ce5296dea4 100644
--- a/lib.c
+++ b/lib.c
@@ -1,4 +1,4 @@
-/* $Id: lib.c,v 1.10 2014/03/23 11:25:26 schwarze Exp $ */
+/* $Id: lib.c,v 1.11 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,9 @@
* 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 <string.h>
diff --git a/libman.h b/libman.h
index e852927cd2cd..8f66013ab24e 100644
--- a/libman.h
+++ b/libman.h
@@ -1,6 +1,7 @@
-/* $Id: libman.h,v 1.63 2014/08/01 21:24:17 schwarze Exp $ */
+/* $Id: libman.h,v 1.65 2014/11/28 05:51:32 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
@@ -45,7 +46,7 @@ struct man {
char *buf
struct man_macro {
- int (*fp)(MACRO_PROT_ARGS);
+ void (*fp)(MACRO_PROT_ARGS);
int flags;
#define MAN_SCOPED (1 << 0)
#define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */
@@ -53,24 +54,25 @@ struct man_macro {
#define MAN_NSCOPED (1 << 3) /* See in_line_eoln(). */
#define MAN_NOCLOSE (1 << 4) /* See blk_exp(). */
#define MAN_BSCOPE (1 << 5) /* Break BLINE scope. */
+#define MAN_JOIN (1 << 6) /* Join arguments together. */
};
extern const struct man_macro *const man_macros;
__BEGIN_DECLS
-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);
-int man_tail_alloc(struct man *, int, int, enum mant);
-int man_body_alloc(struct man *, int, int, enum mant);
-int man_elem_alloc(struct man *, int, int, enum mant);
+void man_word_alloc(struct man *, int, int, const char *);
+void man_word_append(struct man *, const char *);
+void man_block_alloc(struct man *, int, int, enum mant);
+void man_head_alloc(struct man *, int, int, enum mant);
+void man_body_alloc(struct man *, int, int, enum mant);
+void man_elem_alloc(struct man *, int, int, enum mant);
void man_node_delete(struct man *, struct man_node *);
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_unscope(struct man *, const struct man_node *);
+void man_macroend(struct man *);
+void man_valid_post(struct man *);
+void man_unscope(struct man *, const struct man_node *);
__END_DECLS
diff --git a/libmandoc.h b/libmandoc.h
index 1011cc502147..c5a8d5cd73e1 100644
--- a/libmandoc.h
+++ b/libmandoc.h
@@ -1,4 +1,4 @@
-/* $Id: libmandoc.h,v 1.42 2014/07/09 11:31:43 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.49 2014/11/28 06:27:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -30,6 +30,11 @@ enum rofferr {
ROFF_ERR /* badness: puke and stop */
};
+struct buf {
+ char *buf;
+ size_t sz;
+};
+
__BEGIN_DECLS
struct roff;
@@ -55,34 +60,32 @@ struct mdoc *mdoc_alloc(struct roff *, struct mparse *,
void mdoc_reset(struct mdoc *);
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 mdoc_addspan(struct mdoc *, const struct tbl_span *);
+void mdoc_addeqn(struct mdoc *, const struct eqn *);
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_endparse(struct man *);
-int man_addspan(struct man *, const struct tbl_span *);
-int man_addeqn(struct man *, const struct eqn *);
+void man_addspan(struct man *, const struct tbl_span *);
+void man_addeqn(struct man *, const struct eqn *);
+
+int preconv_cue(const struct buf *, size_t);
+int preconv_encode(struct buf *, size_t *,
+ struct buf *, size_t *, int *);
void roff_free(struct roff *);
-struct roff *roff_alloc(struct mparse *, int);
+struct roff *roff_alloc(struct mparse *, const struct mchars *, int);
void roff_reset(struct roff *);
-enum rofferr roff_parseln(struct roff *, int,
- char **, size_t *, int, int *);
+enum rofferr roff_parseln(struct roff *, int, struct buf *, 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 *,
const char *, int *);
-#if 0
-char roff_eqndelim(const struct roff *);
-void roff_openeqn(struct roff *, const char *,
- int, int, const char *);
-int roff_closeeqn(struct roff *);
-#endif
+int roff_getformat(const struct roff *);
const struct tbl_span *roff_span(const struct roff *);
const struct eqn *roff_eqn(const struct roff *);
diff --git a/libmdoc.h b/libmdoc.h
index 1507a8c26fbb..056e9c9b0522 100644
--- a/libmdoc.h
+++ b/libmdoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmdoc.h,v 1.88 2014/08/01 17:40:34 schwarze Exp $ */
+/* $Id: libmdoc.h,v 1.95 2014/11/29 03:37:44 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -37,6 +37,7 @@ struct mdoc {
#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting */
#define MDOC_KEEP (1 << 8) /* in a word keep */
#define MDOC_SMOFF (1 << 9) /* spacing is off */
+#define MDOC_NODELIMC (1 << 10) /* disable closing delimiter handling */
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 */
@@ -55,7 +56,7 @@ struct mdoc {
char *buf
struct mdoc_macro {
- int (*fp)(MACRO_PROT_ARGS);
+ void (*fp)(MACRO_PROT_ARGS);
int flags;
#define MDOC_CALLABLE (1 << 0)
#define MDOC_PARSED (1 << 1)
@@ -76,13 +77,6 @@ enum margserr {
ARGS_PEND /* last phrase (-column) */
};
-enum margverr {
- ARGV_ERROR,
- ARGV_EOLN, /* end of line */
- ARGV_ARG, /* valid argument */
- ARGV_WORD /* normal word (or bad argument---same thing) */
-};
-
/*
* A punctuation delimiter is opening, closing, or "middle mark"
* punctuation. These govern spacing.
@@ -104,38 +98,34 @@ extern const struct mdoc_macro *const mdoc_macros;
__BEGIN_DECLS
-int mdoc_macro(MACRO_PROT_ARGS);
-int mdoc_word_alloc(struct mdoc *,
- int, int, const char *);
+void mdoc_macro(MACRO_PROT_ARGS);
+void 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,
+void mdoc_elem_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
-int mdoc_block_alloc(struct mdoc *, int, int,
+struct mdoc_node *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);
-int mdoc_body_alloc(struct mdoc *, int, int, enum mdoct);
-int mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
+struct mdoc_node *mdoc_head_alloc(struct mdoc *, int, int, enum mdoct);
+void mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct);
+struct mdoc_node *mdoc_body_alloc(struct mdoc *, int, int, enum mdoct);
+void mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
struct mdoc_node *, enum mdoc_endbody);
void mdoc_node_delete(struct mdoc *, struct mdoc_node *);
-int mdoc_node_relink(struct mdoc *, struct mdoc_node *);
+void mdoc_node_relink(struct mdoc *, struct mdoc_node *);
void mdoc_hash_init(void);
enum mdoct mdoc_hash_find(const char *);
const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *);
const char *mdoc_a2st(const char *);
const char *mdoc_a2arch(const char *);
-const char *mdoc_a2vol(const char *);
-int mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
-int mdoc_valid_post(struct mdoc *);
-enum margverr mdoc_argv(struct mdoc *, int, enum mdoct,
+void mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
+void mdoc_valid_post(struct mdoc *);
+void mdoc_argv(struct mdoc *, int, enum mdoct,
struct mdoc_arg **, int *, char *);
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,
- int *, char *, char **);
-int mdoc_macroend(struct mdoc *);
+void mdoc_macroend(struct mdoc *);
enum mdelim mdoc_isdelim(const char *);
__END_DECLS
diff --git a/libroff.h b/libroff.h
index f917b14926f9..bd9bcd220e40 100644
--- a/libroff.h
+++ b/libroff.h
@@ -1,6 +1,7 @@
-/* $Id: libroff.h,v 1.29 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: libroff.h,v 1.31 2014/10/25 14:35:37 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
@@ -43,16 +44,19 @@ struct tbl_node {
};
struct eqn_node {
- struct eqn_def *defs;
- size_t defsz;
- char *data;
- size_t rew;
- size_t cur;
- size_t sz;
- int gsize;
- struct eqn eqn;
- struct mparse *parse;
- struct eqn_node *next;
+ struct eqn eqn; /* syntax tree of this equation */
+ struct mparse *parse; /* main parser, for error reporting */
+ struct eqn_node *next; /* singly linked list of equations */
+ struct eqn_def *defs; /* array of definitions */
+ char *data; /* source code of this equation */
+ size_t defsz; /* number of definitions */
+ size_t sz; /* length of the source code */
+ size_t cur; /* parse point in the source code */
+ size_t rew; /* beginning of the current token */
+ int gsize; /* default point size */
+ int delim; /* in-line delimiters enabled */
+ char odelim; /* in-line opening delimiter */
+ char cdelim; /* in-line closing delimiter */
};
struct eqn_def {
@@ -73,7 +77,7 @@ int tbl_data(struct tbl_node *, int, const char *);
int tbl_cdata(struct tbl_node *, int, const char *);
const struct tbl_span *tbl_span(struct tbl_node *);
void tbl_end(struct tbl_node **);
-struct eqn_node *eqn_alloc(const char *, int, int, struct mparse *);
+struct eqn_node *eqn_alloc(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,
diff --git a/main.c b/main.c
index d97c8e2393b0..34784994ced0 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,6 @@
-/* $Id: main.c,v 1.177 2014/06/21 22:24:01 schwarze Exp $ */
+/* $Id: main.c,v 1.200 2014/11/26 21:40:17 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
@@ -16,11 +16,14 @@
* 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 <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -32,6 +35,8 @@
#include "main.h"
#include "mdoc.h"
#include "man.h"
+#include "manpath.h"
+#include "mansearch.h"
#if !defined(__GNUC__) || (__GNUC__ < 2)
# if !defined(lint)
@@ -39,6 +44,15 @@
# endif
#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
+enum outmode {
+ OUTMODE_DEF = 0,
+ OUTMODE_FLN,
+ OUTMODE_LST,
+ OUTMODE_ALL,
+ OUTMODE_INT,
+ OUTMODE_ONE
+};
+
typedef void (*out_mdoc)(void *, const struct mdoc *);
typedef void (*out_man)(void *, const struct man *);
typedef void (*out_free)(void *);
@@ -50,7 +64,6 @@ enum outt {
OUTT_TREE, /* -Ttree */
OUTT_MAN, /* -Tman */
OUTT_HTML, /* -Thtml */
- OUTT_XHTML, /* -Txhtml */
OUTT_LINT, /* -Tlint */
OUTT_PS, /* -Tps */
OUTT_PDF /* -Tpdf */
@@ -58,6 +71,7 @@ enum outt {
struct curparse {
struct mparse *mp;
+ struct mchars *mchars; /* character table */
enum mandoclevel wlevel; /* ignore messages below this */
int wstop; /* stop after a file with a warning */
enum outt outtype; /* which output to use */
@@ -68,27 +82,45 @@ struct curparse {
char outopts[BUFSIZ]; /* buf of output opts */
};
+static int koptions(int *, 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,
const char *, enum mandoclevel *);
+static enum mandoclevel passthrough(const char *, int, int);
+static void spawn_pager(void);
static int toptions(struct curparse *, char *);
-static void usage(void) __attribute__((noreturn));
+static void usage(enum argmode) __attribute__((noreturn));
static void version(void) __attribute__((noreturn));
static int woptions(struct curparse *, char *);
+static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static const char *progname;
int
main(int argc, char *argv[])
{
- int c;
struct curparse curp;
- int options;
- enum mandoclevel rc;
+ struct mansearch search;
+ struct manpaths paths;
+ char *conf_file, *defpaths, *auxpaths;
char *defos;
+#if HAVE_SQLITE3
+ struct manpage *res, *resp;
+ size_t isec, i, sz;
+ int prio, best_prio;
+ char sec;
+#endif
+ enum mandoclevel rc;
+ enum outmode outmode;
+ int fd;
+ int show_usage;
+ int use_pager;
+ int synopsis_only;
+ int options;
+ int c;
progname = strrchr(argv[0], '/');
if (progname == NULL)
@@ -96,15 +128,57 @@ main(int argc, char *argv[])
else
++progname;
- memset(&curp, 0, sizeof(struct curparse));
+ /* Search options. */
+
+ memset(&paths, 0, sizeof(struct manpaths));
+ conf_file = defpaths = auxpaths = NULL;
+
+ memset(&search, 0, sizeof(struct mansearch));
+ search.outkey = "Nd";
+
+ if (strcmp(progname, "man") == 0)
+ search.argmode = ARG_NAME;
+ else if (strncmp(progname, "apropos", 7) == 0)
+ search.argmode = ARG_EXPR;
+ else if (strncmp(progname, "whatis", 6) == 0)
+ search.argmode = ARG_WORD;
+ else
+ search.argmode = ARG_FILE;
+
+ /* Parser and formatter options. */
- options = MPARSE_SO;
+ memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_ASCII;
curp.wlevel = MANDOCLEVEL_FATAL;
+ options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
defos = NULL;
- while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
+ use_pager = 1;
+ show_usage = 0;
+ synopsis_only = 0;
+ outmode = OUTMODE_DEF;
+
+ while (-1 != (c = getopt(argc, argv,
+ "aC:cfhI:iK:klM:m:O:S:s:T:VW:w"))) {
switch (c) {
+ case 'a':
+ outmode = OUTMODE_ALL;
+ break;
+ case 'C':
+ conf_file = optarg;
+ break;
+ case 'c':
+ use_pager = 0;
+ break;
+ case 'f':
+ search.argmode = ARG_WORD;
+ break;
+ case 'h':
+ (void)strlcat(curp.outopts, "synopsis,", BUFSIZ);
+ synopsis_only = 1;
+ use_pager = 0;
+ outmode = OUTMODE_ALL;
+ break;
case 'I':
if (strncmp(optarg, "os=", 3)) {
fprintf(stderr,
@@ -120,14 +194,37 @@ main(int argc, char *argv[])
}
defos = mandoc_strdup(optarg + 3);
break;
- case 'm':
- if ( ! moptions(&options, optarg))
+ case 'i':
+ outmode = OUTMODE_INT;
+ break;
+ case 'K':
+ if ( ! koptions(&options, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
+ case 'k':
+ search.argmode = ARG_EXPR;
+ break;
+ case 'l':
+ search.argmode = ARG_FILE;
+ outmode = OUTMODE_ALL;
+ break;
+ case 'M':
+ defpaths = optarg;
+ break;
+ case 'm':
+ auxpaths = optarg;
+ break;
case 'O':
+ search.outkey = optarg;
(void)strlcat(curp.outopts, optarg, BUFSIZ);
(void)strlcat(curp.outopts, ",", BUFSIZ);
break;
+ case 'S':
+ search.arch = optarg;
+ break;
+ case 's':
+ search.sec = optarg;
+ break;
case 'T':
if ( ! toptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
@@ -136,15 +233,147 @@ main(int argc, char *argv[])
if ( ! woptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
+ case 'w':
+ outmode = OUTMODE_FLN;
+ break;
case 'V':
version();
/* NOTREACHED */
default:
- usage();
- /* NOTREACHED */
+ show_usage = 1;
+ break;
+ }
+ }
+
+ if (show_usage)
+ usage(search.argmode);
+
+ /* Postprocess options. */
+
+ if (outmode == OUTMODE_DEF) {
+ switch (search.argmode) {
+ case ARG_FILE:
+ outmode = OUTMODE_ALL;
+ use_pager = 0;
+ break;
+ case ARG_NAME:
+ outmode = OUTMODE_ONE;
+ break;
+ default:
+ outmode = OUTMODE_LST;
+ break;
+ }
+ }
+
+ /* Parse arguments. */
+
+ argc -= optind;
+ argv += optind;
+#if HAVE_SQLITE3
+ resp = NULL;
+#endif
+
+ /* Quirk for a man(1) section argument without -s. */
+
+ if (search.argmode == ARG_NAME &&
+ argv[0] != NULL &&
+ isdigit((unsigned char)argv[0][0]) &&
+ (argv[0][1] == '\0' || !strcmp(argv[0], "3p"))) {
+ search.sec = argv[0];
+ argv++;
+ argc--;
+ }
+
+ rc = MANDOCLEVEL_OK;
+
+ /* man(1), whatis(1), apropos(1) */
+
+ if (search.argmode != ARG_FILE) {
+#if HAVE_SQLITE3
+ if (argc == 0)
+ usage(search.argmode);
+
+ if (search.argmode == ARG_NAME &&
+ outmode == OUTMODE_ONE)
+ search.firstmatch = 1;
+
+ /* Access the mandoc database. */
+
+ manpath_parse(&paths, conf_file, defpaths, auxpaths);
+ mansearch_setup(1);
+ if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
+ usage(search.argmode);
+ resp = res;
+
+ if (sz == 0) {
+ if (search.argmode == ARG_NAME)
+ fprintf(stderr, "%s: No entry for %s "
+ "in the manual.\n", progname, argv[0]);
+ rc = MANDOCLEVEL_BADARG;
+ goto out;
+ }
+
+ /*
+ * For standard man(1) and -a output mode,
+ * prepare for copying filename pointers
+ * into the program parameter array.
+ */
+
+ if (outmode == OUTMODE_ONE) {
+ argc = 1;
+ best_prio = 10;
+ } else if (outmode == OUTMODE_ALL)
+ argc = (int)sz;
+
+ /* Iterate all matching manuals. */
+
+ for (i = 0; i < sz; i++) {
+ if (outmode == OUTMODE_FLN)
+ puts(res[i].file);
+ else if (outmode == OUTMODE_LST)
+ printf("%s - %s\n", res[i].names,
+ res[i].output == NULL ? "" :
+ res[i].output);
+ else if (outmode == OUTMODE_ONE) {
+ /* Search for the best section. */
+ isec = strcspn(res[i].file, "123456789");
+ sec = res[i].file[isec];
+ if ('\0' == sec)
+ continue;
+ prio = sec_prios[sec - '1'];
+ if (prio >= best_prio)
+ continue;
+ best_prio = prio;
+ resp = res + i;
+ }
}
- curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
+ /*
+ * For man(1), -a and -i output mode, fall through
+ * to the main mandoc(1) code iterating files
+ * and running the parsers on each of them.
+ */
+
+ if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
+ goto out;
+#else
+ fputs("mandoc: database support not compiled in\n",
+ stderr);
+ return((int)MANDOCLEVEL_BADARG);
+#endif
+ }
+
+ /* mandoc(1) */
+
+ if ( ! moptions(&options, auxpaths))
+ return((int)MANDOCLEVEL_BADARG);
+
+ if (use_pager && isatty(STDOUT_FILENO))
+ spawn_pager();
+
+ curp.mchars = mchars_alloc();
+ curp.mp = mparse_alloc(options, curp.wlevel, mmsg,
+ curp.mchars, defos);
/*
* Conditionally start up the lookaside buffer before parsing.
@@ -152,25 +381,53 @@ main(int argc, char *argv[])
if (OUTT_MAN == curp.outtype)
mparse_keep(curp.mp);
- argc -= optind;
- argv += optind;
+ if (argc == 0)
+ parse(&curp, STDIN_FILENO, "<stdin>", &rc);
- rc = MANDOCLEVEL_OK;
+ while (argc) {
+#if HAVE_SQLITE3
+ if (resp != NULL) {
+ rc = mparse_open(curp.mp, &fd, resp->file);
+ if (fd == -1)
+ /* nothing */;
+ else if (resp->form & FORM_SRC) {
+ /* For .so only; ignore failure. */
+ chdir(paths.paths[resp->ipath]);
+ parse(&curp, fd, resp->file, &rc);
+ } else
+ rc = passthrough(resp->file, fd,
+ synopsis_only);
+ resp++;
+ } else
+#endif
+ {
+ rc = mparse_open(curp.mp, &fd, *argv++);
+ if (fd != -1)
+ parse(&curp, fd, argv[-1], &rc);
+ }
- if (NULL == *argv)
- parse(&curp, STDIN_FILENO, "<stdin>", &rc);
+ if (mparse_wait(curp.mp) != MANDOCLEVEL_OK)
+ rc = MANDOCLEVEL_SYSERR;
- while (*argv) {
- parse(&curp, -1, *argv, &rc);
if (MANDOCLEVEL_OK != rc && curp.wstop)
break;
- ++argv;
+ argc--;
}
if (curp.outfree)
(*curp.outfree)(curp.outdata);
- if (curp.mp)
- mparse_free(curp.mp);
+ mparse_free(curp.mp);
+ mchars_free(curp.mchars);
+
+#if HAVE_SQLITE3
+out:
+ if (search.argmode != ARG_FILE) {
+ manpath_free(&paths);
+ mansearch_free(res, sz);
+ mansearch_setup(0);
+ }
+#endif
+
free(defos);
return((int)rc);
@@ -180,24 +437,36 @@ static void
version(void)
{
- printf("%s %s\n", progname, VERSION);
+ printf("mandoc %s\n", VERSION);
exit((int)MANDOCLEVEL_OK);
}
static void
-usage(void)
+usage(enum argmode argmode)
{
- fprintf(stderr, "usage: %s "
- "[-V] "
- "[-Ios=name] "
- "[-mformat] "
- "[-Ooption] "
- "[-Toutput] "
- "[-Wlevel]\n"
- "\t [file ...]\n",
- progname);
-
+ switch (argmode) {
+ case ARG_FILE:
+ fputs("usage: mandoc [-acfhklV] [-Ios=name] "
+ "[-Kencoding] [-mformat] [-Ooption]\n"
+ "\t [-Toutput] [-Wlevel] [file ...]\n", stderr);
+ break;
+ case ARG_NAME:
+ fputs("usage: man [-acfhklVw] [-C file] "
+ "[-M path] [-m path] [-S arch] [-s section]\n"
+ "\t [section] name ...\n", stderr);
+ break;
+ case ARG_WORD:
+ fputs("usage: whatis [-acfhklVw] [-C file] "
+ "[-M path] [-m path] [-O outkey] [-S arch]\n"
+ "\t [-s section] name ...\n", stderr);
+ break;
+ case ARG_EXPR:
+ fputs("usage: apropos [-acfhklVw] [-C file] "
+ "[-M path] [-m path] [-O outkey] [-S arch]\n"
+ "\t [-s section] expression ...\n", stderr);
+ break;
+ }
exit((int)MANDOCLEVEL_BADARG);
}
@@ -233,32 +502,34 @@ parse(struct curparse *curp, int fd, const char *file,
if ( ! (curp->outman && curp->outmdoc)) {
switch (curp->outtype) {
- case OUTT_XHTML:
- curp->outdata = xhtml_alloc(curp->outopts);
- curp->outfree = html_free;
- break;
case OUTT_HTML:
- curp->outdata = html_alloc(curp->outopts);
+ curp->outdata = html_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = html_free;
break;
case OUTT_UTF8:
- curp->outdata = utf8_alloc(curp->outopts);
+ curp->outdata = utf8_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = ascii_free;
break;
case OUTT_LOCALE:
- curp->outdata = locale_alloc(curp->outopts);
+ curp->outdata = locale_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = ascii_free;
break;
case OUTT_ASCII:
- curp->outdata = ascii_alloc(curp->outopts);
+ curp->outdata = ascii_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = ascii_free;
break;
case OUTT_PDF:
- curp->outdata = pdf_alloc(curp->outopts);
+ curp->outdata = pdf_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = pspdf_free;
break;
case OUTT_PS:
- curp->outdata = ps_alloc(curp->outopts);
+ curp->outdata = ps_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = pspdf_free;
break;
default:
@@ -267,8 +538,6 @@ parse(struct curparse *curp, int fd, const char *file,
switch (curp->outtype) {
case OUTT_HTML:
- /* FALLTHROUGH */
- case OUTT_XHTML:
curp->outman = html_man;
curp->outmdoc = html_mdoc;
break;
@@ -314,11 +583,97 @@ parse(struct curparse *curp, int fd, const char *file,
*level = rc;
}
+static enum mandoclevel
+passthrough(const char *file, int fd, int synopsis_only)
+{
+ const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS";
+ const char synr[] = "SYNOPSIS";
+
+ FILE *stream;
+ const char *syscall;
+ char *line;
+ size_t len, off;
+ ssize_t nw;
+ int print;
+
+ if ((stream = fdopen(fd, "r")) == NULL) {
+ close(fd);
+ syscall = "fdopen";
+ goto fail;
+ }
+
+ print = 0;
+ while ((line = fgetln(stream, &len)) != NULL) {
+ if (synopsis_only) {
+ if (print) {
+ if ( ! isspace((unsigned char)*line))
+ goto done;
+ while (len &&
+ isspace((unsigned char)*line)) {
+ line++;
+ len--;
+ }
+ } else {
+ if ((len == sizeof(synb) &&
+ ! strncmp(line, synb, len - 1)) ||
+ (len == sizeof(synr) &&
+ ! strncmp(line, synr, len - 1)))
+ print = 1;
+ continue;
+ }
+ }
+ for (off = 0; off < len; off += nw)
+ if ((nw = write(STDOUT_FILENO, line + off,
+ len - off)) == -1 || nw == 0) {
+ fclose(stream);
+ syscall = "write";
+ goto fail;
+ }
+ }
+
+ if (ferror(stream)) {
+ fclose(stream);
+ syscall = "fgetln";
+ goto fail;
+ }
+
+done:
+ fclose(stream);
+ return(MANDOCLEVEL_OK);
+
+fail:
+ fprintf(stderr, "%s: %s: SYSERR: %s: %s",
+ progname, file, syscall, strerror(errno));
+ return(MANDOCLEVEL_SYSERR);
+}
+
+static int
+koptions(int *options, char *arg)
+{
+
+ if ( ! strcmp(arg, "utf-8")) {
+ *options |= MPARSE_UTF8;
+ *options &= ~MPARSE_LATIN1;
+ } else if ( ! strcmp(arg, "iso-8859-1")) {
+ *options |= MPARSE_LATIN1;
+ *options &= ~MPARSE_UTF8;
+ } else if ( ! strcmp(arg, "us-ascii")) {
+ *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
+ } else {
+ fprintf(stderr, "%s: -K%s: Bad argument\n",
+ progname, arg);
+ return(0);
+ }
+ return(1);
+}
+
static int
moptions(int *options, char *arg)
{
- if (0 == strcmp(arg, "doc"))
+ if (arg == NULL)
+ /* nothing to do */;
+ else if (0 == strcmp(arg, "doc"))
*options |= MPARSE_MDOC;
else if (0 == strcmp(arg, "andoc"))
/* nothing to do */;
@@ -353,7 +708,7 @@ toptions(struct curparse *curp, char *arg)
else if (0 == strcmp(arg, "locale"))
curp->outtype = OUTT_LOCALE;
else if (0 == strcmp(arg, "xhtml"))
- curp->outtype = OUTT_XHTML;
+ curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "ps"))
curp->outtype = OUTT_PS;
else if (0 == strcmp(arg, "pdf"))
@@ -428,3 +783,79 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
fputc('\n', stderr);
}
+
+static void
+spawn_pager(void)
+{
+#define MAX_PAGER_ARGS 16
+ char *argv[MAX_PAGER_ARGS];
+ const char *pager;
+ char *cp;
+ int fildes[2];
+ int argc;
+
+ if (pipe(fildes) == -1) {
+ fprintf(stderr, "%s: pipe: %s\n",
+ progname, strerror(errno));
+ return;
+ }
+
+ switch (fork()) {
+ case -1:
+ fprintf(stderr, "%s: fork: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+ case 0:
+ close(fildes[0]);
+ if (dup2(fildes[1], STDOUT_FILENO) == -1) {
+ fprintf(stderr, "%s: dup output: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return;
+ default:
+ break;
+ }
+
+ /* The original process becomes the pager. */
+
+ close(fildes[1]);
+ if (dup2(fildes[0], STDIN_FILENO) == -1) {
+ fprintf(stderr, "%s: dup input: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+
+ pager = getenv("MANPAGER");
+ if (pager == NULL || *pager == '\0')
+ pager = getenv("PAGER");
+ if (pager == NULL || *pager == '\0')
+ pager = "/usr/bin/more -s";
+ cp = mandoc_strdup(pager);
+
+ /*
+ * Parse the pager command into words.
+ * Intentionally do not do anything fancy here.
+ */
+
+ argc = 0;
+ while (argc + 1 < MAX_PAGER_ARGS) {
+ argv[argc++] = cp;
+ cp = strchr(cp, ' ');
+ if (cp == NULL)
+ break;
+ *cp++ = '\0';
+ while (*cp == ' ')
+ cp++;
+ if (*cp == '\0')
+ break;
+ }
+ argv[argc] = NULL;
+
+ /* Hand over to the pager. */
+
+ execvp(argv[0], argv);
+ fprintf(stderr, "%s: exec: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+}
diff --git a/main.h b/main.h
index beb0481cab83..c7768e3bb168 100644
--- a/main.h
+++ b/main.h
@@ -1,4 +1,4 @@
-/* $Id: main.h,v 1.16 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: main.h,v 1.17 2014/10/28 17:36:19 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -32,8 +32,7 @@ struct man;
* terminal output routines with different character settings.
*/
-void *html_alloc(char *);
-void *xhtml_alloc(char *);
+void *html_alloc(const struct mchars *, char *);
void html_mdoc(void *, const struct mdoc *);
void html_man(void *, const struct man *);
void html_free(void *);
@@ -44,13 +43,13 @@ void tree_man(void *, const struct man *);
void man_mdoc(void *, const struct mdoc *);
void man_man(void *, const struct man *);
-void *locale_alloc(char *);
-void *utf8_alloc(char *);
-void *ascii_alloc(char *);
+void *locale_alloc(const struct mchars *, char *);
+void *utf8_alloc(const struct mchars *, char *);
+void *ascii_alloc(const struct mchars *, char *);
void ascii_free(void *);
-void *pdf_alloc(char *);
-void *ps_alloc(char *);
+void *pdf_alloc(const struct mchars *, char *);
+void *ps_alloc(const struct mchars *, char *);
void pspdf_free(void *);
void terminal_mdoc(void *, const struct mdoc *);
diff --git a/makewhatis.8 b/makewhatis.8
index 02c4cc354bd6..8a5de938fd73 100644
--- a/makewhatis.8
+++ b/makewhatis.8
@@ -1,4 +1,4 @@
-.\" $Id: makewhatis.8,v 1.2 2014/04/25 12:13:15 schwarze Exp $
+.\" $Id: makewhatis.8,v 1.3 2014/08/17 21:03:06 schwarze Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012 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: April 25 2014 $
+.Dd $Mdocdate: August 17 2014 $
.Dt MAKEWHATIS 8
.Os
.Sh NAME
@@ -98,7 +98,7 @@ format.
Display all files added or removed to the index.
With a second
.Fl D ,
-also show all keyswords added for each file.
+also show all keywords added for each file.
.It Fl d Ar dir
Merge (remove and re-add)
.Ar
diff --git a/man.1 b/man.1
new file mode 100644
index 000000000000..0d26fd281e79
--- /dev/null
+++ b/man.1
@@ -0,0 +1,402 @@
+.\" $Id: man.1,v 1.7 2014/11/11 02:43:41 schwarze Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
+.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+.\"
+.\" 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.
+.\"
+.\" @(#)man.1 8.2 (Berkeley) 1/2/94
+.\"
+.Dd $Mdocdate: November 11 2014 $
+.Dt MAN 1
+.Os
+.Sh NAME
+.Nm man
+.Nd display manual pages
+.Sh SYNOPSIS
+.Nm man
+.Op Fl acfhklVw
+.Op Fl C Ar file
+.Op Fl M Ar path
+.Op Fl m Ar path
+.Op Fl S Ar subsection
+.Op Fl s Ar section
+.Op Ar section
+.Ar name ...
+.Sh DESCRIPTION
+The
+.Nm
+utility
+displays the
+manual pages entitled
+.Ar name .
+Pages may be selected according to
+a specific category
+.Pq Ar section
+or
+machine architecture
+.Pq Ar subsection .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Display all of the manual pages for a specified
+.Ar section
+and
+.Ar name
+combination.
+Normally, only the first manual page found is displayed.
+.It Fl C Ar file
+Use the specified
+.Ar file
+instead of the default configuration file.
+This permits users to configure their own manual environment.
+See
+.Xr man.conf 5
+for a description of the contents of this file.
+.It Fl c
+Copy the manual page to the standard output instead of using
+.Xr more 1
+to paginate it.
+This is done by default if the standard output is not a terminal device.
+.It Fl f
+A synonym for
+.Xr whatis 1 .
+It searches for
+.Ar name
+in manual page names and displays the header lines from all matching pages.
+The search is case insensitive and matches whole words only.
+This overrides any earlier
+.Fl k
+and
+.Fl l
+options.
+.It Fl h
+Display only the SYNOPSIS lines of the requested manual pages.
+Implies
+.Fl a
+and
+.Fl c .
+.It Fl k
+A synonym for
+.Xr apropos 1 .
+Instead of
+.Ar name ,
+an expression can be provided using the syntax described in the
+.Xr apropos 1
+manual.
+By default, it displays the header lines of all matching pages.
+This overrides any earlier
+.Fl f
+and
+.Fl l
+options.
+.It Fl l
+A synonym for
+.Xr mandoc 1
+.Fl a .
+The
+.Ar name
+arguments are interpreted as filenames.
+No search is done and
+.Ar file ,
+.Ar path ,
+.Ar section ,
+and
+.Ar subsection
+are ignored.
+This overrides any earlier
+.Fl f ,
+.Fl k ,
+and
+.Fl w
+options.
+.It Fl M Ar path
+Override the list of standard directories which
+.Nm
+searches for manual pages.
+The supplied
+.Ar path
+must be a colon
+.Pq Ql \&:
+separated list of directories.
+This search path may also be set using the environment variable
+.Ev MANPATH .
+The subdirectories to be searched, and their search order,
+are specified by the
+.Dq _subdir
+line in the
+.Nm
+configuration file.
+.It Fl m Ar path
+Augment the list of standard directories which
+.Nm
+searches for manual pages.
+The supplied
+.Ar path
+must be a colon
+.Pq Ql \&:
+separated list of directories.
+These directories will be searched before the standard directories or
+the directories specified using the
+.Fl M
+option or the
+.Ev MANPATH
+environment variable.
+The subdirectories to be searched, and their search order,
+are specified by the
+.Dq _subdir
+line in the
+.Nm
+configuration file.
+.It Fl S Ar subsection
+Restricts the directories that
+.Nm
+will search to those of a specific
+.Xr machine 1
+architecture.
+.Ar subsection
+is case insensitive.
+.Pp
+By default manual pages for all architectures are installed.
+Therefore this option can be used to view pages for one
+architecture whilst using another.
+.Pp
+This option overrides the
+.Ev MACHINE
+environment variable.
+.It Xo
+.Op Fl s
+.Ar section
+.Xc
+Restricts the directories that
+.Nm
+will search to a specific section.
+The currently available sections are:
+.Pp
+.Bl -tag -width "localXXX" -offset indent -compact
+.It 1
+General commands
+.Pq tools and utilities .
+.It 2
+System calls and error numbers.
+.It 3
+Libraries.
+.It 3f
+Fortran programmer's reference guide.
+.It 3p
+.Xr perl 1
+programmer's reference guide.
+.It 4
+Device drivers.
+.It 5
+File formats.
+.It 6
+Games.
+.It 7
+Miscellaneous.
+.It 8
+System maintenance and operation commands.
+.It 9
+Kernel internals.
+.It X11
+An alias for X11R6.
+.It X11R6
+X Window System.
+.It local
+Pages located in
+.Pa /usr/local .
+.It n
+Tcl/Tk commands.
+.El
+.Pp
+The
+.Nm
+configuration file,
+.Xr man.conf 5 ,
+specifies the possible
+.Ar section
+values, and their search order.
+Additional sections may be specified.
+.It Fl V
+Print version and exit.
+.It Fl w
+List the pathnames of the manual pages which
+.Nm
+would display for the specified
+.Ar section
+and
+.Ar name
+combination.
+.El
+.Pp
+The
+.Nm
+utility also supports the options
+.Fl IKOTW
+described in the
+.Xr mandoc 1
+manual.
+.Pp
+Guidelines for writing
+man pages can be found in
+.Xr mdoc 7 .
+.Pp
+If both a formatted and an unformatted version of the same manual page,
+for example
+.Pa cat1/foo.0
+and
+.Pa man1/foo.1 ,
+exist in the same directory, and at least one of them is selected,
+only the newer one is used.
+However, if both the
+.Fl a
+and the
+.Fl w
+options are specified, both file names are printed.
+.Sh ENVIRONMENT
+.Bl -tag -width MANPATHX
+.It Ev MACHINE
+As some manual pages are intended only for specific architectures,
+.Nm
+searches any subdirectories,
+with the same name as the current architecture,
+in every directory which it searches.
+Machine specific areas are checked before general areas.
+The current machine type may be overridden by setting the environment
+variable
+.Ev MACHINE
+to the name of a specific architecture,
+or with the
+.Fl S
+option.
+.Ev MACHINE
+is case insensitive.
+.It Ev MANPAGER
+Any non-empty value of the environment variable
+.Ev MANPAGER
+will be used instead of the standard pagination program,
+.Xr more 1 .
+.It Ev MANPATH
+The standard search path used by
+.Nm
+may be overridden by specifying a path in the
+.Ev MANPATH
+environment
+variable.
+The format of the path is a colon
+.Pq Ql \&:
+separated list of directories.
+The subdirectories to be searched, as well as their search order,
+are specified by the
+.Dq _subdir
+line in the
+.Nm
+configuration file.
+.It Ev PAGER
+Specifies the pagination program to use when
+.Ev MANPAGER
+is not defined.
+If neither PAGER nor MANPAGER is defined,
+.Pa /usr/bin/more Fl s
+will be used.
+.El
+.Sh FILES
+.Bl -tag -width /etc/man.conf -compact
+.It Pa /etc/man.conf
+default man configuration file
+.El
+.Sh EXIT STATUS
+.Ex -std man
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr intro 1 ,
+.Xr whatis 1 ,
+.Xr whereis 1 ,
+.Xr intro 2 ,
+.Xr intro 3 ,
+.Xr intro 4 ,
+.Xr intro 5 ,
+.Xr man.conf 5 ,
+.Xr intro 6 ,
+.Xr intro 7 ,
+.Xr mdoc 7 ,
+.Xr intro 8 ,
+.Xr intro 9
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2008
+specification.
+.Pp
+The flags
+.Op Fl aCcfhMmSsw ,
+as well as the environment variables
+.Ev MACHINE ,
+.Ev MANPAGER ,
+and
+.Ev MANPATH ,
+are extensions to that specification.
+.Sh HISTORY
+A
+.Nm
+command first appeared in
+.At v3 .
+.Pp
+The
+.Fl w
+option first appeared in
+.At v7 ;
+.Fl f
+and
+.Fl k
+in
+.Bx 4 ;
+.Fl M
+in
+.Bx 4.3 ;
+.Fl a
+in
+.Bx 4.3 Tahoe ;
+.Fl c
+and
+.Fl m
+in
+.Bx 4.3 Reno ;
+.Fl h
+in
+.Bx 4.3 Net/2 ;
+.Fl C
+in
+.Nx 1.0 ;
+and
+.Fl s
+and
+.Fl S
+in
+.Ox 2.3 .
diff --git a/man.c b/man.c
index 75a6350577ba..048db26f9a2b 100644
--- a/man.c
+++ b/man.c
@@ -1,4 +1,4 @@
-/* $Id: man.c,v 1.137 2014/08/01 21:24:17 schwarze Exp $ */
+/* $Id: man.c,v 1.145 2014/11/28 06:27:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -16,9 +16,7 @@
* 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>
@@ -52,8 +50,7 @@ const char * const *man_macronames = __man_macronames;
static struct man_node *man_node_alloc(struct man *, int, int,
enum man_type, enum mant);
-static int man_node_append(struct man *,
- struct man_node *);
+static void man_node_append(struct man *, struct man_node *);
static void man_node_free(struct man_node *);
static void man_node_unlink(struct man *,
struct man_node *);
@@ -61,7 +58,7 @@ static int man_ptext(struct man *, int, char *, int);
static int man_pmacro(struct man *, int, char *, int);
static void man_free1(struct man *);
static void man_alloc1(struct man *);
-static int man_descope(struct man *, int, int);
+static void man_descope(struct man *, int, int);
const struct man_node *
@@ -114,14 +111,16 @@ int
man_endparse(struct man *man)
{
- return(man_macroend(man));
+ man_macroend(man);
+ return(1);
}
int
man_parseln(struct man *man, int ln, char *buf, int offs)
{
- man->flags |= MAN_NEWLINE;
+ if (man->last->type != MAN_EQN || ln > man->last->line)
+ man->flags |= MAN_NEWLINE;
return (roff_getcontrol(man->roff, buf, &offs) ?
man_pmacro(man, ln, buf, offs) :
@@ -134,16 +133,11 @@ man_free1(struct man *man)
if (man->first)
man_node_delete(man, man->first);
- if (man->meta.title)
- free(man->meta.title);
- if (man->meta.source)
- free(man->meta.source);
- if (man->meta.date)
- free(man->meta.date);
- if (man->meta.vol)
- free(man->meta.vol);
- if (man->meta.msec)
- free(man->meta.msec);
+ free(man->meta.title);
+ free(man->meta.source);
+ free(man->meta.date);
+ free(man->meta.vol);
+ free(man->meta.msec);
}
static void
@@ -160,13 +154,13 @@ man_alloc1(struct man *man)
}
-static int
+static void
man_node_append(struct man *man, struct man_node *p)
{
assert(man->last);
assert(man->first);
- assert(MAN_ROOT != p->type);
+ assert(p->type != MAN_ROOT);
switch (man->next) {
case MAN_NEXT_SIBLING:
@@ -192,15 +186,11 @@ man_node_append(struct man *man, struct man_node *p)
man->flags &= ~MAN_LITERAL;
break;
case MAN_HEAD:
- assert(MAN_BLOCK == p->parent->type);
+ assert(p->parent->type == MAN_BLOCK);
p->parent->head = p;
break;
- case MAN_TAIL:
- assert(MAN_BLOCK == p->parent->type);
- p->parent->tail = p;
- break;
case MAN_BODY:
- assert(MAN_BLOCK == p->parent->type);
+ assert(p->parent->type == MAN_BLOCK);
p->parent->body = p;
break;
default:
@@ -213,14 +203,11 @@ man_node_append(struct man *man, struct man_node *p)
case MAN_TBL:
/* FALLTHROUGH */
case MAN_TEXT:
- if ( ! man_valid_post(man))
- return(0);
+ man_valid_post(man);
break;
default:
break;
}
-
- return(1);
}
static struct man_node *
@@ -235,85 +222,76 @@ man_node_alloc(struct man *man, int line, int pos,
p->type = type;
p->tok = tok;
- if (MAN_NEWLINE & man->flags)
+ if (man->flags & MAN_NEWLINE)
p->flags |= MAN_LINE;
man->flags &= ~MAN_NEWLINE;
return(p);
}
-int
+void
man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_ELEM, tok);
- if ( ! man_node_append(man, p))
- return(0);
- man->next = MAN_NEXT_CHILD;
- return(1);
-}
-
-int
-man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
-{
- struct man_node *p;
-
- p = man_node_alloc(man, line, pos, MAN_TAIL, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-int
+void
man_head_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_HEAD, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-int
+void
man_body_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_BODY, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-int
+void
man_block_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_BLOCK, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-int
+void
man_word_alloc(struct man *man, int line, int pos, const char *word)
{
struct man_node *n;
n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
n->string = roff_strdup(man->roff, word);
+ man_node_append(man, n);
+ man->next = MAN_NEXT_SIBLING;
+}
- if ( ! man_node_append(man, n))
- return(0);
-
+void
+man_word_append(struct man *man, const char *word)
+{
+ struct man_node *n;
+ char *addstr, *newstr;
+
+ n = man->last;
+ addstr = roff_strdup(man->roff, word);
+ mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
+ free(addstr);
+ free(n->string);
+ n->string = newstr;
man->next = MAN_NEXT_SIBLING;
- return(1);
}
/*
@@ -324,8 +302,7 @@ static void
man_node_free(struct man_node *p)
{
- if (p->string)
- free(p->string);
+ free(p->string);
free(p);
}
@@ -340,37 +317,33 @@ man_node_delete(struct man *man, struct man_node *p)
man_node_free(p);
}
-int
+void
man_addeqn(struct man *man, const struct eqn *ep)
{
struct man_node *n;
n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
n->eqn = ep;
-
- if ( ! man_node_append(man, n))
- return(0);
-
+ if (ep->ln > man->last->line)
+ n->flags |= MAN_LINE;
+ man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
- return(man_descope(man, ep->ln, ep->pos));
+ man_descope(man, ep->ln, ep->pos);
}
-int
+void
man_addspan(struct man *man, const struct tbl_span *sp)
{
struct man_node *n;
n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
n->span = sp;
-
- if ( ! man_node_append(man, n))
- return(0);
-
+ man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
- return(man_descope(man, sp->line, 0));
+ man_descope(man, sp->line, 0);
}
-static int
+static void
man_descope(struct man *man, int line, int offs)
{
/*
@@ -379,19 +352,15 @@ man_descope(struct man *man, int line, int offs)
* out the block scope (also if applicable).
*/
- if (MAN_ELINE & man->flags) {
+ if (man->flags & MAN_ELINE) {
man->flags &= ~MAN_ELINE;
- if ( ! man_unscope(man, man->last->parent))
- return(0);
+ man_unscope(man, man->last->parent);
}
-
- if ( ! (MAN_BLINE & man->flags))
- return(1);
+ if ( ! (man->flags & MAN_BLINE))
+ return;
man->flags &= ~MAN_BLINE;
-
- if ( ! man_unscope(man, man->last->parent))
- return(0);
- return(man_body_alloc(man, line, offs, man->last->tok));
+ man_unscope(man, man->last->parent);
+ man_body_alloc(man, line, offs, man->last->tok);
}
static int
@@ -401,13 +370,13 @@ man_ptext(struct man *man, int line, char *buf, int offs)
/* Literal free-form text whitespace is preserved. */
- if (MAN_LITERAL & man->flags) {
- if ( ! man_word_alloc(man, line, offs, buf + offs))
- return(0);
- return(man_descope(man, line, offs));
+ if (man->flags & MAN_LITERAL) {
+ man_word_alloc(man, line, offs, buf + offs);
+ man_descope(man, line, offs);
+ return(1);
}
- for (i = offs; ' ' == buf[i]; i++)
+ for (i = offs; buf[i] == ' '; i++)
/* Skip leading whitespace. */ ;
/*
@@ -415,12 +384,11 @@ man_ptext(struct man *man, int line, char *buf, int offs)
* but add a single vertical space elsewhere.
*/
- if ('\0' == buf[i]) {
+ if (buf[i] == '\0') {
/* Allocate a blank entry. */
- if (MAN_SH != man->last->tok &&
- MAN_SS != man->last->tok) {
- if ( ! man_elem_alloc(man, line, offs, MAN_sp))
- return(0);
+ if (man->last->tok != MAN_SH &&
+ man->last->tok != MAN_SS) {
+ man_elem_alloc(man, line, offs, MAN_sp);
man->next = MAN_NEXT_SIBLING;
}
return(1);
@@ -447,9 +415,7 @@ man_ptext(struct man *man, int line, char *buf, int offs)
buf[i] = '\0';
}
-
- if ( ! man_word_alloc(man, line, offs, buf + offs))
- return(0);
+ man_word_alloc(man, line, offs, buf + offs);
/*
* End-of-sentence check. If the last character is an unescaped
@@ -461,50 +427,59 @@ man_ptext(struct man *man, int line, char *buf, int offs)
if (mandoc_eos(buf, (size_t)i))
man->last->flags |= MAN_EOS;
- return(man_descope(man, line, offs));
+ man_descope(man, line, offs);
+ return(1);
}
static int
man_pmacro(struct man *man, int ln, char *buf, int offs)
{
- char mac[5];
struct man_node *n;
+ const char *cp;
enum mant tok;
int i, ppos;
int bline;
-
- if ('"' == buf[offs]) {
- mandoc_msg(MANDOCERR_COMMENT_BAD, man->parse,
- ln, offs, NULL);
- return(1);
- } else if ('\0' == buf[offs])
- return(1);
+ char mac[5];
ppos = offs;
/*
* Copy the first word into a nil-terminated buffer.
- * Stop copying when a tab, space, or eoln is encountered.
+ * Stop when a space, tab, escape, or eoln is encountered.
*/
i = 0;
- while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] &&
- '\t' != buf[offs])
+ while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
mac[i++] = buf[offs++];
mac[i] = '\0';
tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
- if (MAN_MAX == tok) {
+ if (tok == MAN_MAX) {
mandoc_msg(MANDOCERR_MACRO, man->parse,
ln, ppos, buf + ppos - 1);
return(1);
}
- /* The macro is sane. Jump to the next word. */
+ /* Skip a leading escape sequence or tab. */
+
+ switch (buf[offs]) {
+ case '\\':
+ cp = buf + offs + 1;
+ mandoc_escape(&cp, NULL, NULL);
+ offs = cp - buf;
+ break;
+ case '\t':
+ offs++;
+ break;
+ default:
+ break;
+ }
+
+ /* Jump to the next non-whitespace word. */
- while (buf[offs] && ' ' == buf[offs])
+ while (buf[offs] && buf[offs] == ' ')
offs++;
/*
@@ -512,7 +487,7 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
* into the parser as "text", so we only warn about spaces here.
*/
- if ('\0' == buf[offs] && ' ' == buf[offs - 1])
+ if (buf[offs] == '\0' && buf[offs - 1] == ' ')
mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
ln, offs - 1, NULL);
@@ -522,14 +497,14 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
* macros---they don't print text---so we let those slip by.
*/
- if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
+ if ( ! (man_macros[tok].flags & MAN_NSCOPED) &&
man->flags & MAN_ELINE) {
n = man->last;
assert(MAN_TEXT != n->type);
/* Remove repeated NSCOPED macros causing ELINE. */
- if (MAN_NSCOPED & man_macros[n->tok].flags)
+ if (man_macros[n->tok].flags & MAN_NSCOPED)
n = n->parent;
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line,
@@ -544,24 +519,24 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
* Remove prior BLINE macro that is being clobbered.
*/
if ((man->flags & MAN_BLINE) &&
- (MAN_BSCOPE & man_macros[tok].flags)) {
+ (man_macros[tok].flags & MAN_BSCOPE)) {
n = man->last;
/* Might be a text node like 8 in
* .TP 8
* .SH foo
*/
- if (MAN_TEXT == n->type)
+ if (n->type == MAN_TEXT)
n = n->parent;
/* Remove element that didn't end BLINE, if any. */
- if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
+ if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
n = n->parent;
- assert(MAN_HEAD == n->type);
+ assert(n->type == MAN_HEAD);
n = n->parent;
- assert(MAN_BLOCK == n->type);
- assert(MAN_SCOPED & man_macros[n->tok].flags);
+ assert(n->type == MAN_BLOCK);
+ assert(man_macros[n->tok].flags & MAN_SCOPED);
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line,
n->pos, "%s breaks %s", man_macronames[tok],
@@ -578,14 +553,13 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
/* Call to handler... */
assert(man_macros[tok].fp);
- if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf))
- return(0);
+ (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
- if (man->quick && MAN_SH == tok) {
+ if (man->quick && tok == MAN_SH) {
n = man->last;
- if (MAN_BODY == n->type &&
+ if (n->type == MAN_BODY &&
strcmp(n->prev->child->string, "NAME"))
return(2);
}
@@ -600,12 +574,12 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
man_macros[tok].flags & MAN_NSCOPED)
return(1);
- assert(MAN_BLINE & man->flags);
+ assert(man->flags & MAN_BLINE);
man->flags &= ~MAN_BLINE;
- if ( ! man_unscope(man, man->last->parent))
- return(0);
- return(man_body_alloc(man, ln, ppos, man->last->tok));
+ man_unscope(man, man->last->parent);
+ man_body_alloc(man, ln, ppos, man->last->tok);
+ return(1);
}
/*
@@ -663,7 +637,7 @@ man_deroff(char **dest, const struct man_node *n)
char *cp;
size_t sz;
- if (MAN_TEXT != n->type) {
+ if (n->type != MAN_TEXT) {
for (n = n->child; n; n = n->next)
man_deroff(dest, n);
return;
diff --git a/man.cgi.8 b/man.cgi.8
index 69335e632ec9..4d3588b01607 100644
--- a/man.cgi.8
+++ b/man.cgi.8
@@ -1,4 +1,4 @@
-.\" $Id: man.cgi.8,v 1.9 2014/07/22 18:14:13 schwarze Exp $
+.\" $Id: man.cgi.8,v 1.11 2014/09/14 19:44:28 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 22 2014 $
+.Dd $Mdocdate: September 14 2014 $
.Dt MAN.CGI 8
.Os
.Sh NAME
@@ -43,6 +43,12 @@ either a name of a manual page or an
using the syntax described in the
.Xr apropos 1
manual; filling this in is required for each search.
+.Pp
+The expression is broken into words at whitespace.
+Whitespace characters and backslashes can be escaped
+by prepending a backslash.
+The effect of prepending a backslash to another character is undefined;
+in the current implementation, it has no effect.
.It
A
.Dq Submit
@@ -307,7 +313,7 @@ and ending before the
.Ev QUERY_STRING .
It is used by the
.Cm show
-page to aquire the manpath and filename it needs.
+page to acquire 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.
diff --git a/man.h b/man.h
index aa80b6732eae..22827c53769b 100644
--- a/man.h
+++ b/man.h
@@ -1,4 +1,4 @@
-/* $Id: man.h,v 1.65 2014/06/20 23:02:31 schwarze Exp $ */
+/* $Id: man.h,v 1.66 2014/11/28 05:51:32 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -68,7 +68,6 @@ enum man_type {
MAN_BLOCK,
MAN_HEAD,
MAN_BODY,
- MAN_TAIL,
MAN_TBL,
MAN_EQN
};
diff --git a/man_hash.c b/man_hash.c
index ab887226b5de..c52add28efab 100644
--- a/man_hash.c
+++ b/man_hash.c
@@ -1,4 +1,4 @@
-/* $Id: man_hash.c,v 1.27 2014/04/20 16:46:04 schwarze Exp $ */
+/* $Id: man_hash.c,v 1.28 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,7 @@
* 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>
diff --git a/man_html.c b/man_html.c
index 9689cc261e5f..6fe40a974b0b 100644
--- a/man_html.c
+++ b/man_html.c
@@ -1,6 +1,6 @@
-/* $Id: man_html.c,v 1.96 2014/08/01 19:25:52 schwarze Exp $ */
+/* $Id: man_html.c,v 1.104 2014/09/27 11:17:19 kristaps Exp $ */
/*
- * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2012, 2014 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
@@ -15,9 +15,7 @@
* 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>
@@ -144,7 +142,7 @@ print_bvspace(struct html *h, const struct man_node *n)
if (NULL == n->prev)
return;
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
}
void
@@ -221,7 +219,7 @@ print_man_node(MAN_ARGS)
* before printing the line's data.
*/
if ('\0' == *n->string) {
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
return;
}
@@ -301,7 +299,7 @@ a2width(const struct man_node *n, struct roffsu *su)
static void
man_root_pre(MAN_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
char *title;
@@ -309,34 +307,26 @@ man_root_pre(MAN_ARGS)
assert(man->msec);
mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
- PAIR_SUMMARY_INIT(&tag[0], "Document Header");
- PAIR_CLASS_INIT(&tag[1], "head");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
print_otag(h, TAG_TBODY, 0, NULL);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "head-ltitle");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head-ltitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-vol");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "head-vol");
+ print_otag(h, TAG_TD, 1, &tag);
if (NULL != man->vol)
print_text(h, man->vol);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-rtitle");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "head-rtitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_tagq(h, t);
free(title);
@@ -345,29 +335,23 @@ man_root_pre(MAN_ARGS)
static void
man_root_post(MAN_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
- PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
- PAIR_CLASS_INIT(&tag[1], "foot");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "foot-date");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot-date");
+ print_otag(h, TAG_TD, 1, &tag);
assert(man->date);
print_text(h, man->date);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "foot-os");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "foot-os");
+ print_otag(h, TAG_TD, 1, &tag);
if (man->source)
print_text(h, man->source);
@@ -554,7 +538,7 @@ man_IP_pre(MAN_ARGS)
static int
man_HP_pre(MAN_ARGS)
{
- struct htmlpair tag;
+ struct htmlpair tag[2];
struct roffsu su;
const struct man_node *np;
@@ -574,8 +558,9 @@ man_HP_pre(MAN_ARGS)
bufcat_su(h, "margin-left", &su);
su.scale = -su.scale;
bufcat_su(h, "text-indent", &su);
- PAIR_STYLE_INIT(&tag, h);
- print_otag(h, TAG_P, 1, &tag);
+ PAIR_STYLE_INIT(&tag[0], h);
+ PAIR_CLASS_INIT(&tag[1], "spacer");
+ print_otag(h, TAG_DIV, 2, tag);
return(1);
}
diff --git a/man_macro.c b/man_macro.c
index ea45a504db4c..1b8965899edc 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -1,7 +1,7 @@
-/* $Id: man_macro.c,v 1.87 2014/07/30 23:01:39 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.91 2014/11/28 05:51:32 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -16,9 +16,9 @@
* 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 <assert.h>
#include <ctype.h>
@@ -36,14 +36,14 @@ enum rew {
REW_HALT
};
-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 void blk_close(MACRO_PROT_ARGS);
+static void blk_exp(MACRO_PROT_ARGS);
+static void blk_imp(MACRO_PROT_ARGS);
+static void in_line_eoln(MACRO_PROT_ARGS);
static int man_args(struct man *, int,
int *, char *, char **);
-static int rew_scope(enum man_type,
+static void rew_scope(enum man_type,
struct man *, enum mant);
static enum rew rew_dohalt(enum mant, enum man_type,
const struct man_node *);
@@ -61,15 +61,15 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ blk_imp, MAN_BSCOPE }, /* P */
{ blk_imp, MAN_BSCOPE }, /* IP */
{ blk_imp, MAN_BSCOPE }, /* HP */
- { in_line_eoln, MAN_SCOPED }, /* SM */
- { in_line_eoln, MAN_SCOPED }, /* SB */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */
{ in_line_eoln, 0 }, /* BI */
{ in_line_eoln, 0 }, /* IB */
{ in_line_eoln, 0 }, /* BR */
{ in_line_eoln, 0 }, /* RB */
- { in_line_eoln, MAN_SCOPED }, /* R */
- { in_line_eoln, MAN_SCOPED }, /* B */
- { in_line_eoln, MAN_SCOPED }, /* I */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
{ in_line_eoln, MAN_NSCOPED }, /* na */
@@ -95,12 +95,11 @@ const struct man_macro __man_macros[MAN_MAX] = {
const struct man_macro * const man_macros = __man_macros;
-int
+void
man_unscope(struct man *man, const struct man_node *to)
{
struct man_node *n;
- man->next = MAN_NEXT_SIBLING;
to = to->parent;
n = man->last;
while (n != to) {
@@ -139,20 +138,29 @@ man_unscope(struct man *man, const struct man_node *to)
* Save a pointer to the parent such that
* we know where to continue the iteration.
*/
+
man->last = n;
n = n->parent;
- if ( ! man_valid_post(man))
- return(0);
+ man_valid_post(man);
}
- return(1);
+
+ /*
+ * If we ended up at the parent of the node we were
+ * supposed to rewind to, that means the target node
+ * got deleted, so add the next node we parse as a child
+ * of the parent instead of as a sibling of the target.
+ */
+
+ man->next = (man->last == to) ?
+ MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
}
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 (type == MAN_BLOCK && ntok == n->parent->tok &&
+ n->parent->type == MAN_BODY)
return(REW_REWIND);
return(ntok == n->tok ? REW_HALT : REW_NOHALT);
}
@@ -235,7 +243,7 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
* for example, the `SH' macro will close out any intervening `SS'
* scopes. When a scope is closed, it must be validated and actioned.
*/
-static int
+static void
rew_scope(enum man_type type, struct man *man, enum mant tok)
{
struct man_node *n;
@@ -249,7 +257,7 @@ rew_scope(enum man_type type, struct man *man, enum mant tok)
*/
c = rew_dohalt(tok, type, n);
if (REW_HALT == c)
- return(1);
+ return;
if (REW_REWIND == c)
break;
}
@@ -258,16 +266,15 @@ rew_scope(enum man_type type, struct man *man, enum mant tok)
* 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));
+ man_unscope(man, n);
}
/*
* Close out a generic explicit macro.
*/
-int
+void
blk_close(MACRO_PROT_ARGS)
{
enum mant ntok;
@@ -286,57 +293,46 @@ blk_close(MACRO_PROT_ARGS)
}
for (nn = man->last->parent; nn; nn = nn->parent)
- if (ntok == nn->tok && MAN_BLOCK == nn->type)
+ if (nn->tok == ntok && nn->type == MAN_BLOCK)
break;
- if (NULL == nn) {
+ if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, man_macronames[tok]);
- if ( ! rew_scope(MAN_BLOCK, man, MAN_PP))
- return(0);
+ rew_scope(MAN_BLOCK, man, MAN_PP);
} else
man_unscope(man, nn);
-
- return(1);
}
-int
+void
blk_exp(MACRO_PROT_ARGS)
{
struct man_node *n;
int la;
char *p;
- /* Close out prior implicit scopes. */
-
- if ( ! rew_scope(MAN_BLOCK, man, tok))
- return(0);
-
- if ( ! man_block_alloc(man, line, ppos, tok))
- return(0);
- if ( ! man_head_alloc(man, line, ppos, tok))
- return(0);
+ rew_scope(MAN_BLOCK, man, tok);
+ man_block_alloc(man, line, ppos, tok);
+ man_head_alloc(man, line, ppos, tok);
for (;;) {
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
- if ( ! man_word_alloc(man, line, la, p))
- return(0);
+ man_word_alloc(man, line, la, p);
}
assert(man);
assert(tok != MAN_MAX);
- for (n = man->last; n; n = n->parent) {
- if (n->tok != tok)
- continue;
- assert(MAN_HEAD == n->type);
- man_unscope(man, n);
- break;
- }
+ for (n = man->last; n; n = n->parent)
+ if (n->tok == tok) {
+ assert(n->type == MAN_HEAD);
+ man_unscope(man, n);
+ break;
+ }
- return(man_body_alloc(man, line, ppos, tok));
+ man_body_alloc(man, line, ppos, tok);
}
/*
@@ -345,27 +341,17 @@ blk_exp(MACRO_PROT_ARGS)
* scopes, such as `SH' closing out an `SS', are defined in the rew
* routines.
*/
-int
+void
blk_imp(MACRO_PROT_ARGS)
{
int la;
char *p;
struct man_node *n;
- /* Close out prior scopes. */
-
- if ( ! rew_scope(MAN_BODY, man, tok))
- return(0);
- if ( ! rew_scope(MAN_BLOCK, man, tok))
- return(0);
-
- /* Allocate new block & head scope. */
-
- if ( ! man_block_alloc(man, line, ppos, tok))
- return(0);
- if ( ! man_head_alloc(man, line, ppos, tok))
- return(0);
-
+ rew_scope(MAN_BODY, man, tok);
+ rew_scope(MAN_BLOCK, man, tok);
+ man_block_alloc(man, line, ppos, tok);
+ man_head_alloc(man, line, ppos, tok);
n = man->last;
/* Add line arguments. */
@@ -374,46 +360,44 @@ blk_imp(MACRO_PROT_ARGS)
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
- if ( ! man_word_alloc(man, line, la, p))
- return(0);
+ man_word_alloc(man, line, la, p);
}
/* Close out head and open body (unless MAN_SCOPE). */
- if (MAN_SCOPED & man_macros[tok].flags) {
+ if (man_macros[tok].flags & MAN_SCOPED) {
/* If we're forcing scope (`TP'), keep it open. */
- if (MAN_FSCOPED & man_macros[tok].flags) {
+ if (man_macros[tok].flags & MAN_FSCOPED) {
man->flags |= MAN_BLINE;
- return(1);
+ return;
} else if (n == man->last) {
man->flags |= MAN_BLINE;
- return(1);
+ return;
}
}
-
- if ( ! rew_scope(MAN_HEAD, man, tok))
- return(0);
- return(man_body_alloc(man, line, ppos, tok));
+ rew_scope(MAN_HEAD, man, tok);
+ man_body_alloc(man, line, ppos, tok);
}
-int
+void
in_line_eoln(MACRO_PROT_ARGS)
{
int la;
char *p;
struct man_node *n;
- if ( ! man_elem_alloc(man, line, ppos, tok))
- return(0);
-
+ man_elem_alloc(man, line, ppos, tok);
n = man->last;
for (;;) {
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
- if ( ! man_word_alloc(man, line, la, p))
- return(0);
+ if (man_macros[tok].flags & MAN_JOIN &&
+ man->last->type == MAN_TEXT)
+ man_word_append(man, p);
+ else
+ man_word_alloc(man, line, la, p);
}
/*
@@ -431,13 +415,13 @@ in_line_eoln(MACRO_PROT_ARGS)
* waiting for terms to load into our context.
*/
- if (n == man->last && MAN_SCOPED & man_macros[tok].flags) {
- assert( ! (MAN_NSCOPED & man_macros[tok].flags));
+ if (n == man->last && man_macros[tok].flags & MAN_SCOPED) {
+ assert( ! (man_macros[tok].flags & MAN_NSCOPED));
man->flags |= MAN_ELINE;
- return(1);
+ return;
}
- assert(MAN_ROOT != man->last->type);
+ assert(man->last->type != MAN_ROOT);
man->next = MAN_NEXT_SIBLING;
/*
@@ -451,8 +435,7 @@ in_line_eoln(MACRO_PROT_ARGS)
break;
if (man->last->type == MAN_ROOT)
break;
- if ( ! man_valid_post(man))
- return(0);
+ man_valid_post(man);
}
assert(man->last);
@@ -461,18 +444,16 @@ in_line_eoln(MACRO_PROT_ARGS)
* Same here regarding whether we're back at the root.
*/
- if (man->last->type != MAN_ROOT && ! man_valid_post(man))
- return(0);
-
- return(1);
+ if (man->last->type != MAN_ROOT)
+ man_valid_post(man);
}
-int
+void
man_macroend(struct man *man)
{
- return(man_unscope(man, man->first));
+ man_unscope(man, man->first);
}
static int
diff --git a/man_term.c b/man_term.c
index c91c0746201a..2531f816f76d 100644
--- a/man_term.c
+++ b/man_term.c
@@ -1,4 +1,4 @@
-/* $Id: man_term.c,v 1.149 2014/06/20 23:02:31 schwarze Exp $ */
+/* $Id: man_term.c,v 1.156 2014/11/21 01:52:53 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,7 @@
* 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>
@@ -143,38 +141,47 @@ void
terminal_man(void *arg, const struct man *man)
{
struct termp *p;
- const struct man_node *n;
const struct man_meta *meta;
+ struct man_node *n;
struct mtermp mt;
p = (struct termp *)arg;
- if (0 == p->defindent)
- p->defindent = 7;
-
p->overstep = 0;
- p->maxrmargin = p->defrmargin;
+ p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
- if (NULL == p->symtab)
- p->symtab = mchars_alloc();
-
- n = man_node(man);
+ n = man_node(man)->child;
meta = man_meta(man);
- term_begin(p, print_man_head, print_man_foot, meta);
- p->flags |= TERMP_NOSPACE;
-
memset(&mt, 0, sizeof(struct mtermp));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
- if (n->child)
- print_man_nodelist(p, &mt, n->child, meta);
-
- term_end(p);
+ if (p->synopsisonly) {
+ while (n != NULL) {
+ if (n->tok == MAN_SH &&
+ n->child->child->type == MAN_TEXT &&
+ !strcmp(n->child->child->string, "SYNOPSIS")) {
+ if (n->child->next->child != NULL)
+ print_man_nodelist(p, &mt,
+ n->child->next->child, meta);
+ term_newln(p);
+ break;
+ }
+ n = n->next;
+ }
+ } else {
+ if (p->defindent == 0)
+ p->defindent = 7;
+ term_begin(p, print_man_head, print_man_foot, meta);
+ p->flags |= TERMP_NOSPACE;
+ if (n != NULL)
+ print_man_nodelist(p, &mt, n, meta);
+ term_end(p);
+ }
}
@@ -449,11 +456,6 @@ pre_in(DECL_ARGS)
else
p->offset = v;
- /* Don't let this creep beyond the right margin. */
-
- if (p->offset > p->rmargin)
- p->offset = p->rmargin;
-
return(0);
}
@@ -647,8 +649,7 @@ pre_IP(DECL_ARGS)
return(0);
case MAN_BODY:
p->offset = mt->offset + len;
- p->rmargin = p->maxrmargin > p->offset ?
- p->maxrmargin : p->offset;
+ p->rmargin = p->maxrmargin;
break;
default:
break;
@@ -739,8 +740,7 @@ pre_TP(DECL_ARGS)
return(0);
case MAN_BODY:
p->offset = mt->offset + len;
- p->rmargin = p->maxrmargin > p->offset ?
- p->maxrmargin : p->offset;
+ p->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
break;
@@ -891,8 +891,7 @@ pre_RS(DECL_ARGS)
mt->offset += sz;
p->offset = mt->offset;
- p->rmargin = p->maxrmargin > p->offset ?
- p->maxrmargin : p->offset;
+ p->rmargin = p->maxrmargin;
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
@@ -977,7 +976,11 @@ print_man_node(DECL_ARGS)
goto out;
case MAN_EQN:
+ if ( ! (n->flags & MAN_LINE))
+ p->flags |= TERMP_NOSPACE;
term_eqn(p, n->eqn);
+ if (n->next != NULL && ! (n->next->flags & MAN_LINE))
+ p->flags |= TERMP_NOSPACE;
return;
case MAN_TBL:
/*
@@ -1052,7 +1055,7 @@ print_man_foot(struct termp *p, const void *arg)
{
const struct man_meta *meta;
char *title;
- size_t datelen;
+ size_t datelen, titlen;
meta = (const struct man_meta *)arg;
assert(meta->title);
@@ -1089,7 +1092,8 @@ print_man_foot(struct termp *p, const void *arg)
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
p->offset = 0;
- p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
+ p->rmargin = p->maxrmargin > datelen ?
+ (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
if (meta->source)
term_word(p, meta->source);
@@ -1097,11 +1101,10 @@ print_man_foot(struct termp *p, const void *arg)
/* At the bottom in the middle: manual date. */
- p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
- p->rmargin = p->maxrmargin - term_strlen(p, title);
- if (p->offset + datelen >= p->rmargin)
- p->rmargin = p->offset + datelen;
+ titlen = term_strlen(p, title);
+ p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0;
+ p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
term_flushln(p);
@@ -1144,7 +1147,7 @@ print_man_head(struct termp *p, const void *arg)
p->offset = 0;
p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
- p->maxrmargin - vollen;
+ vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
term_word(p, title);
term_flushln(p);
diff --git a/man_validate.c b/man_validate.c
index c17eb9ecdac6..5688bb548aaf 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -1,4 +1,4 @@
-/* $Id: man_validate.c,v 1.105 2014/08/06 15:09:05 schwarze Exp $ */
+/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,7 @@
* 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>
@@ -38,26 +36,26 @@
#define CHKARGS struct man *man, struct man_node *n
-typedef int (*v_check)(CHKARGS);
-
-static int check_eq0(CHKARGS);
-static int check_eq2(CHKARGS);
-static int check_le1(CHKARGS);
-static int check_le5(CHKARGS);
-static int check_par(CHKARGS);
-static int check_part(CHKARGS);
-static int check_root(CHKARGS);
-static int check_text(CHKARGS);
-
-static int post_AT(CHKARGS);
-static int post_IP(CHKARGS);
-static int post_vs(CHKARGS);
-static int post_fi(CHKARGS);
-static int post_ft(CHKARGS);
-static int post_nf(CHKARGS);
-static int post_TH(CHKARGS);
-static int post_UC(CHKARGS);
-static int post_UR(CHKARGS);
+typedef void (*v_check)(CHKARGS);
+
+static void check_eq0(CHKARGS);
+static void check_eq2(CHKARGS);
+static void check_le1(CHKARGS);
+static void check_le5(CHKARGS);
+static void check_par(CHKARGS);
+static void check_part(CHKARGS);
+static void check_root(CHKARGS);
+static void check_text(CHKARGS);
+
+static void post_AT(CHKARGS);
+static void post_IP(CHKARGS);
+static void post_vs(CHKARGS);
+static void post_fi(CHKARGS);
+static void post_ft(CHKARGS);
+static void post_nf(CHKARGS);
+static void post_TH(CHKARGS);
+static void post_UC(CHKARGS);
+static void post_UR(CHKARGS);
static v_check man_valids[MAN_MAX] = {
post_vs, /* br */
@@ -102,7 +100,7 @@ static v_check man_valids[MAN_MAX] = {
};
-int
+void
man_valid_post(struct man *man)
{
struct man_node *n;
@@ -110,25 +108,29 @@ man_valid_post(struct man *man)
n = man->last;
if (n->flags & MAN_VALID)
- return(1);
+ return;
n->flags |= MAN_VALID;
switch (n->type) {
case MAN_TEXT:
- return(check_text(man, n));
+ check_text(man, n);
+ break;
case MAN_ROOT:
- return(check_root(man, n));
+ check_root(man, n);
+ break;
case MAN_EQN:
/* FALLTHROUGH */
case MAN_TBL:
- return(1);
+ break;
default:
cp = man_valids + n->tok;
- return(*cp ? (*cp)(man, n) : 1);
+ if (*cp)
+ (*cp)(man, n);
+ break;
}
}
-static int
+static void
check_root(CHKARGS)
{
@@ -154,35 +156,31 @@ check_root(CHKARGS)
man->meta.date = man->quick ? mandoc_strdup("") :
mandoc_normdate(man->parse, NULL, n->line, n->pos);
}
-
- return(1);
}
-static int
+static void
check_text(CHKARGS)
{
char *cp, *p;
if (MAN_LITERAL & man->flags)
- return(1);
+ return;
cp = n->string;
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
mandoc_msg(MANDOCERR_FI_TAB, man->parse,
n->line, n->pos + (p - cp), NULL);
- return(1);
}
#define INEQ_DEFINE(x, ineq, name) \
-static int \
+static void \
check_##name(CHKARGS) \
{ \
if (n->nchild ineq (x)) \
- return(1); \
+ return; \
mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
"line arguments %s %d (have %d)", \
#ineq, (x), n->nchild); \
- return(1); \
}
INEQ_DEFINE(0, ==, eq0)
@@ -190,25 +188,24 @@ INEQ_DEFINE(2, ==, eq2)
INEQ_DEFINE(1, <=, le1)
INEQ_DEFINE(5, <=, le5)
-static int
+static void
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(check_part(man, n));
+ check_part(man, n);
}
-static int
+static void
post_ft(CHKARGS)
{
char *cp;
int ok;
if (0 == n->nchild)
- return(1);
+ return;
ok = 0;
cp = n->child->string;
@@ -250,22 +247,18 @@ post_ft(CHKARGS)
if (1 < n->nchild)
mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
n->pos, "want one child (have %d)", n->nchild);
-
- return(1);
}
-static int
+static void
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)");
-
- return(1);
}
-static int
+static void
check_par(CHKARGS)
{
@@ -291,11 +284,9 @@ check_par(CHKARGS)
default:
break;
}
-
- return(1);
}
-static int
+static void
post_IP(CHKARGS)
{
@@ -313,10 +304,9 @@ post_IP(CHKARGS)
default:
break;
}
- return(1);
}
-static int
+static void
post_TH(CHKARGS)
{
struct man_node *nb;
@@ -404,10 +394,9 @@ post_TH(CHKARGS)
* meta-data.
*/
man_node_delete(man, man->last);
- return(1);
}
-static int
+static void
post_nf(CHKARGS)
{
@@ -418,10 +407,9 @@ post_nf(CHKARGS)
n->line, n->pos, "nf");
man->flags |= MAN_LITERAL;
- return(1);
}
-static int
+static void
post_fi(CHKARGS)
{
@@ -432,10 +420,9 @@ post_fi(CHKARGS)
n->line, n->pos, "fi");
man->flags &= ~MAN_LITERAL;
- return(1);
}
-static int
+static void
post_UC(CHKARGS)
{
static const char * const bsd_versions[] = {
@@ -470,10 +457,9 @@ post_UC(CHKARGS)
free(man->meta.source);
man->meta.source = mandoc_strdup(p);
- return(1);
}
-static int
+static void
post_AT(CHKARGS)
{
static const char * const unix_versions[] = {
@@ -508,10 +494,9 @@ post_AT(CHKARGS)
free(man->meta.source);
man->meta.source = mandoc_strdup(p);
- return(1);
}
-static int
+static void
post_vs(CHKARGS)
{
@@ -521,7 +506,7 @@ post_vs(CHKARGS)
check_le1(man, n);
if (NULL != n->prev)
- return(1);
+ return;
switch (n->parent->tok) {
case MAN_SH:
@@ -541,6 +526,4 @@ post_vs(CHKARGS)
default:
break;
}
-
- return(1);
}
diff --git a/mandoc.1 b/mandoc.1
index e9f7375777bc..9f2d6ba71f31 100644
--- a/mandoc.1
+++ b/mandoc.1
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.1,v 1.106 2014/08/08 01:50:59 schwarze Exp $
+.\" $Id: mandoc.1,v 1.125 2014/11/28 18:09:01 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2012, 2014 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: August 8 2014 $
+.Dd $Mdocdate: November 28 2014 $
.Dt MANDOC 1
.Os
.Sh NAME
@@ -23,10 +23,11 @@
.Nd format and display UNIX manuals
.Sh SYNOPSIS
.Nm mandoc
-.Op Fl V
+.Op Fl acfhklV
.Sm off
.Op Fl I Cm os Li = Ar name
.Sm on
+.Op Fl K Ns Ar encoding
.Op Fl m Ns Ar format
.Op Fl O Ns Ar option
.Op Fl T Ns Ar output
@@ -51,8 +52,31 @@ and produces
.Fl T Ns Cm ascii
output.
.Pp
-The arguments are as follows:
+The options are as follows:
.Bl -tag -width Ds
+.It Fl a
+If the standard output is a terminal device and
+.Fl c
+is not specified, use
+.Xr more 1
+to paginate the output, just like
+.Xr man 1
+would.
+.It Fl c
+Copy the formatted manual pages to the standard output without using
+.Xr more 1
+to paginate them.
+This is the default.
+It can be specified to override
+.Fl a .
+.It Fl f
+A synonym for
+.Xr whatis 1 .
+This overrides any earlier
+.Fl k
+and
+.Fl l
+options.
.Sm off
.It Fl I Cm os Li = Ar name
.Sm on
@@ -62,6 +86,51 @@ for the
.Xr mdoc 7
.Sq \&Os
macro.
+.It Fl h
+Display only the SYNOPSIS lines.
+Implies
+.Fl c .
+.It Fl K Ns Ar encoding
+Specify the input encoding.
+The supported
+.Ar encoding
+arguments are
+.Cm us-ascii ,
+.Cm iso-8859-1 ,
+and
+.Cm utf-8 .
+If not specified, autodetection uses the first match:
+.Bl -tag -width iso-8859-1
+.It Cm utf-8
+if the first three bytes of the input file
+are the UTF-8 byte order mark (BOM, 0xefbbbf)
+.It Ar encoding
+if the first or second line of the input file matches the
+.Sy emacs
+mode line format
+.Pp
+.D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*-
+.It Cm utf-8
+if the first non-ASCII byte in the file introduces a valid UTF-8 sequence
+.It Cm iso-8859-1
+otherwise
+.El
+.It Fl k
+A synonym for
+.Xr apropos 1 .
+This overrides any earlier
+.Fl f
+and
+.Fl l
+options.
+.It Fl l
+A synonym for
+.Fl a .
+Also reverts any earlier
+.Fl f
+and
+.Fl k
+options.
.It Fl m Ns Ar format
Input format.
See
@@ -122,6 +191,18 @@ If multiple files are specified,
.Nm
will halt with the first failed parse.
.El
+.Pp
+In
+.Fl f
+and
+.Fl k
+mode,
+.Nm
+also supports the options
+.Fl CMmOSsw
+described in the
+.Xr apropos 1
+manual.
.Ss Input Formats
The
.Nm
@@ -178,7 +259,7 @@ This is the default.
See
.Sx ASCII Output .
.It Fl T Ns Cm html
-Produce strict CSS1/HTML-4.01 output.
+Produce HTML5, CSS1, and MathML output.
See
.Sx HTML Output .
.It Fl T Ns Cm lint
@@ -210,9 +291,8 @@ Encode output in the UTF\-8 multi-byte format.
See
.Sx UTF\-8 Output .
.It Fl T Ns Cm xhtml
-Produce strict CSS1/XHTML-1.0 output.
-See
-.Sx XHTML Output .
+This is a synonym for
+.Fl T Ns Cm html .
.El
.Pp
If multiple input files are specified, these will be processed by the
@@ -265,7 +345,11 @@ which will normalise to \(>=60.
.Ss HTML Output
Output produced by
.Fl T Ns Cm html
-conforms to HTML-4.01 strict.
+conforms to HTML5 using optional self-closing tags.
+Default styles use only CSS1.
+Equations rendered from
+.Xr eqn 7
+blocks use MathML.
.Pp
The
.Pa example.style.css
@@ -273,7 +357,8 @@ file documents style-sheet classes available for customising output.
If a style-sheet is not specified with
.Fl O Ns Ar style ,
.Fl T Ns Cm html
-defaults to simple output readable in any graphical or text-based web
+defaults to simple output (via an embedded style-sheet)
+readable in any graphical or text-based web
browser.
.Pp
Special characters are rendered in decimal-encoded UTF\-8.
@@ -283,16 +368,8 @@ The following
arguments are accepted:
.Bl -tag -width Ds
.It Cm fragment
-Omit the
-.Aq !DOCTYPE
-declaration and the
-.Aq html ,
-.Aq head ,
-and
-.Aq body
-elements and only emit the subtree below the
-.Aq body
-element.
+Omit the <!DOCTYPE> declaration and the <html>, <head>, and <body>
+elements and only emit the subtree below the <body> element.
The
.Cm style
argument will be ignored.
@@ -416,15 +493,21 @@ to force a UTF\-8 locale.
See
.Sx Locale Output
for details and options.
-.Ss XHTML Output
-Output produced by
-.Fl T Ns Cm xhtml
-conforms to XHTML-1.0 strict.
-.Pp
-See
-.Sx HTML Output
-for details; beyond generating XHTML tags instead of HTML tags, these
-output modes are identical.
+.Sh ENVIRONMENT
+.Bl -tag -width MANPAGER
+.It Ev MANPAGER
+Any non-empty value of the environment variable
+.Ev MANPAGER
+will be used instead of the standard pagination program,
+.Xr more 1 .
+.It Ev PAGER
+Specifies the pagination program to use when
+.Ev MANPAGER
+is not defined.
+If neither PAGER nor MANPAGER is defined,
+.Pa /usr/bin/more Fl s
+will be used.
+.El
.Sh EXIT STATUS
The
.Nm
@@ -582,12 +665,6 @@ macro lacks the mandatory section argument.
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
@@ -696,6 +773,28 @@ The same standard section title occurs more than once.
.Pq mdoc
A standard section header occurs in a section of the manual
where it normally isn't useful.
+.It Sy "unusual Xr order"
+.Pq mdoc
+In the SEE ALSO section, an
+.Ic \&Xr
+macro with a lower section number follows one with a higher number,
+or two
+.Ic \&Xr
+macros refering to the same section are out of alphabetical order.
+.It Sy "unusual Xr punctuation"
+.Pq mdoc
+In the SEE ALSO section, punctuation between two
+.Ic \&Xr
+macros differs from a single comma, or there is trailing punctuation
+after the last
+.Ic \&Xr
+macro.
+.It Sy "AUTHORS section without An macro"
+.Pq mdoc
+An AUTHORS sections contains no
+.Ic \&An
+macros, or only empty ones.
+Probably, there are author names lacking markup.
.El
.Ss "Warnings related to macros and nesting"
.Bl -ohang
@@ -824,8 +923,11 @@ The previous, interrupted macro is deleted from the parse tree.
.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.
+.Pq roff , eqn
+The macro name is missing from a macro definition request,
+or an
+.Xr eqn 7
+control statement or operation keyword lacks its required argument.
.It Sy "conditional request controls empty scope"
.Pq roff
A conditional request is only useful if any of the following
@@ -959,6 +1061,11 @@ The
utility assumes
.Fl std
even when it is not specified, but other implementations may not.
+.It Sy "missing eqn box, using \(dq\(dq"
+.Pq eqn
+A diacritic mark or a binary operator is found,
+but there is nothing to the left of it.
+An empty box is inserted.
.El
.Ss "Warnings related to bad macro arguments"
.Bl -ohang
@@ -1026,6 +1133,21 @@ macro has an invalid argument.
It is used verbatim, with
.Qq "AT&T UNIX "
prefixed to it.
+.It Sy "comma in function argument"
+.Pq mdoc
+An argument of an
+.Ic \&Fa
+or
+.Ic \&Fn
+macro contains a comma; it should probably be split into two arguments.
+.It Sy "parenthesis in function name"
+.Pq mdoc
+The first argument of an
+.Ic \&Fc
+or
+.Ic \&Fn
+macro contains an opening or closing parenthesis; that's probably wrong,
+parentheses are added automatically.
.It Sy "invalid content in Rs block"
.Pq mdoc
An
@@ -1044,11 +1166,16 @@ or
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
+.Pq man , tbl
A
.Xr roff 7
.Ic \&ft
-request has an invalid argument.
+request or a
+.Xr tbl 7
+.Ic \&f
+layout modifier has an unknown
+.Ar font
+argument.
.El
.Ss "Warnings related to plain text"
.Bl -ohang
@@ -1111,7 +1238,6 @@ keeps the code more readable.
.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
@@ -1165,12 +1291,15 @@ macro.
It may be mistyped or unsupported.
The request or macro is discarded including its arguments.
.It Sy "skipping item outside list"
-.Pq mdoc
+.Pq mdoc , eqn
An
.Ic \&It
macro occurs outside any
.Ic \&Bl
-list.
+list, or an
+.Xr eqn 7
+.Ic above
+delimiter occurs outside any pile.
It is discarded including its arguments.
.It Sy "skipping column outside column list"
.Pq mdoc
@@ -1191,7 +1320,9 @@ block closing macro, a
.Ic \&RE
or
.Ic \&UE
-macro, or the end of an equation, table, or
+macro, an
+.Xr eqn 7
+right delimiter or closing brace, 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.
@@ -1259,6 +1390,17 @@ 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 "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 argument is ignored including the file name following it.
.It Sy "missing list type, using -item"
.Pq mdoc
A
@@ -1288,11 +1430,16 @@ An
.Ic \&St
macro has an unknown argument and is discarded.
.It Sy "skipping request without numeric argument"
-.Pq roff
+.Pq roff , eqn
An
.Ic \&it
-request has a non-numeric or negative argument or no argument at all.
-The invalid request is ignored.
+request or an
+.Xr eqn 7
+.Ic \&size
+or
+.Ic \&gsize
+statement has a non-numeric or negative argument or no argument at all.
+The invalid request or statement is ignored.
.It Sy "skipping all arguments"
.Pq mdoc , man , eqn , roff
An
@@ -1315,6 +1462,8 @@ or
.Ic \&PP
macro, an
.Xr eqn 7
+.Ic \&EQ
+or
.Ic \&EN
macro, or a
.Xr roff 7
@@ -1340,17 +1489,6 @@ 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,
@@ -1430,7 +1568,7 @@ has no effect.
.It
Words aren't hyphenated.
.El
-.Ss HTML/XHTML Compatibility
+.Ss HTML Compatibility
.Bl -bullet -compact
.It
The
diff --git a/mandoc.3 b/mandoc.3
index 8f76ad21fff4..f05fdac997bf 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.3,v 1.25 2014/08/05 05:48:56 schwarze Exp $
+.\" $Id: mandoc.3,v 1.29 2014/11/26 23:42:14 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010 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: August 5 2014 $
+.Dd $Mdocdate: November 26 2014 $
.Dt MANDOC 3
.Os
.Sh NAME
@@ -31,11 +31,13 @@
.Nm mparse_free ,
.Nm mparse_getkeep ,
.Nm mparse_keep ,
+.Nm mparse_open ,
.Nm mparse_readfd ,
.Nm mparse_reset ,
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel
+.Nm mparse_wait ,
.Nd mandoc macro compiler library
.Sh LIBRARY
.Lb libmandoc
@@ -50,6 +52,7 @@
.Fa "int options"
.Fa "enum mandoclevel wlevel"
.Fa "mandocmsg mmsg"
+.Fa "const struct mchars *mchars"
.Fa "char *defos"
.Fc
.Ft void
@@ -74,6 +77,12 @@
.Fa "struct mparse *parse"
.Fc
.Ft "enum mandoclevel"
+.Fo mparse_open
+.Fa "struct mparse *parse"
+.Fa "int *fd"
+.Fa "const char *fname"
+.Fc
+.Ft "enum mandoclevel"
.Fo mparse_readfd
.Fa "struct mparse *parse"
.Fa "int fd"
@@ -98,6 +107,10 @@
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
+.Ft "enum mandoclevel"
+.Fo mparse_wait
+.Fa "struct mparse *parse"
+.Fc
.In sys/types.h
.In mandoc.h
.In mdoc.h
@@ -159,6 +172,8 @@ The following describes a general parse sequence:
.Bl -enum
.It
initiate a parsing sequence with
+.Xr mchars_alloc 3
+and
.Fn mparse_alloc ;
.It
parse files or file descriptors with
@@ -173,7 +188,9 @@ or
.Fn man_node ;
.It
free all allocated memory with
-.Fn mparse_free ,
+.Fn mparse_free
+and
+.Xr mchars_free 3 ,
or invoke
.Fn mparse_reset
and parse new files.
@@ -194,6 +211,12 @@ A fatal error, error, or warning message during parsing.
A classification of an
.Vt "enum mandocerr"
as regards system operation.
+.It Vt "struct mchars"
+An opaque pointer to a a character table.
+Created with
+.Xr mchars_alloc 3
+and freed with
+.Xr mchars_free 3 .
.It Vt "struct mparse"
An opaque pointer to a running parse sequence.
Created with
@@ -318,6 +341,9 @@ A callback function to handle errors and warnings.
See
.Pa main.c
for an example.
+.It Ar mchars
+An opaque pointer to a a character table obtained from
+.Xr mchars_alloc 3 .
.It Ar defos
A default string for the
.Xr mdoc 7
@@ -361,18 +387,47 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
+.It Fn mparse_open
+If the
+.Fa fname
+ends in
+.Pa .gz ,
+open with
+.Xr gunzip 1 ;
+otherwise, with
+.Xr open 2 .
+If
+.Xr open 2
+fails, append
+.Pa .gz
+and try with
+.Xr gunzip 1 .
+Return a file descriptor open for reading in
+.Fa fd ,
+or -1 on failure.
+It can be passed to
+.Fn mparse_readfd
+or used directly.
+Declared in
+.In mandoc.h ,
+implemented in
+.Pa read.c .
.It Fn mparse_readfd
Parse a file or file descriptor.
If
.Va fd
-is -1,
+is -1, open
.Va fname
-is opened for reading.
+with
+.Fn mparse_open .
Otherwise,
.Va fname
is assumed to be the name associated with
.Va fd .
-This may be called multiple times with different parameters; however,
+Calls
+.Fn mparse_wait
+before returning.
+This function may be called multiple times with different parameters; however,
.Fn mparse_reset
should be invoked between parses.
Declared in
@@ -413,6 +468,28 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
+.It Fn mparse_wait
+Bury a
+.Xr gunzip 1
+child process that was spawned with
+.Fn mparse_open .
+To be called after the parse sequence is complete.
+Not needed after
+.Fn mparse_readfd ,
+but does no harm in that case, either.
+Returns
+.Dv MANDOCLEVEL_OK
+on success and
+.Dv MANDOCLEVEL_SYSERR
+on failure, that is, when
+.Xr wait 2
+fails, or when
+.Xr gunzip 1
+died from a signal or exited with non-zero status.
+Declared in
+.In mandoc.h ,
+implemented in
+.Pa read.c .
.El
.Ss Variables
.Bl -ohang
diff --git a/mandoc.c b/mandoc.c
index dd2227299931..2ec179ea2302 100644
--- a/mandoc.c
+++ b/mandoc.c
@@ -1,4 +1,4 @@
-/* $Id: mandoc.c,v 1.83 2014/07/06 19:09:00 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.88 2014/10/28 13:24:44 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,7 @@
* 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>
@@ -81,24 +79,13 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
case '[':
gly = ESCAPE_SPECIAL;
- /*
- * Unicode escapes are defined in groff as \[uXXXX] to
- * \[u10FFFF], where the contained value must be a valid
- * Unicode codepoint. Here, however, only check whether
- * it's not a zero-width escape.
- */
- if ('u' == (*start)[0] && ']' != (*start)[1])
- gly = ESCAPE_UNICODE;
term = ']';
break;
case 'C':
if ('\'' != **start)
return(ESCAPE_ERROR);
*start = ++*end;
- if ('u' == (*start)[0] && '\'' != (*start)[1])
- gly = ESCAPE_UNICODE;
- else
- gly = ESCAPE_SPECIAL;
+ gly = ESCAPE_SPECIAL;
term = '\'';
break;
@@ -201,7 +188,8 @@ mandoc_escape(const char **end, const char **start, int *sz)
/* FALLTHROUGH */
case 'x':
if (strchr(" %&()*+-./0123456789:<=>", **start)) {
- ++*end;
+ if ('\0' != **start)
+ ++*end;
return(ESCAPE_ERROR);
}
gly = ESCAPE_IGNORE;
@@ -345,6 +333,21 @@ mandoc_escape(const char **end, const char **start, int *sz)
case ESCAPE_SPECIAL:
if (1 == *sz && 'c' == **start)
gly = ESCAPE_NOSPACE;
+ /*
+ * Unicode escapes are defined in groff as \[u0000]
+ * to \[u10FFFF], where the contained value must be
+ * a valid Unicode codepoint. Here, however, only
+ * check the length and range.
+ */
+ if (**start != 'u' || *sz < 5 || *sz > 7)
+ break;
+ if (*sz == 7 && ((*start)[1] != '1' || (*start)[2] != '0'))
+ break;
+ if (*sz == 6 && (*start)[1] == '0')
+ break;
+ if ((int)strspn(*start + 1, "0123456789ABCDEFabcdef")
+ + 1 == *sz)
+ gly = ESCAPE_UNICODE;
break;
default:
break;
@@ -457,7 +460,7 @@ a2time(time_t *t, const char *fmt, const char *p)
memset(&tm, 0, sizeof(struct tm));
pp = NULL;
-#ifdef HAVE_STRPTIME
+#if HAVE_STRPTIME
pp = strptime(p, fmt, &tm);
#endif
if (NULL != pp && '\0' == *pp) {
diff --git a/mandoc.db.5 b/mandoc.db.5
index 8d5649578f54..e3452ffe89db 100644
--- a/mandoc.db.5
+++ b/mandoc.db.5
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.db.5,v 1.1 2014/04/15 20:18:26 schwarze Exp $
+.\" $Id: mandoc.db.5,v 1.2 2014/09/03 18:09:14 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: April 15 2014 $
+.Dd $Mdocdate: September 3 2014 $
.Dt MANDOC.DB 5
.Os
.Sh NAME
@@ -67,13 +67,26 @@ The description line
.Pq Sq \&Nd
of the page.
.It Sy mpages.form
-The
+An
.Vt INTEGER
-1 if the page is unformatted, i.e. in
+bit field.
+If bit
+.Dv FORM_GZ
+is set, the page is compressed and requires
+.Xr gunzip 1
+for display.
+If bit
+.Dv FORM_SRC
+is set, the page is unformatted, that is in
.Xr mdoc 7
or
.Xr man 7
-format, and 2 if it is formatted, i.e. a
+format, and requires
+.Xr mandoc 1
+for display.
+If bit
+.Dv FORM_SRC
+is not set, the page is formatted, i.e. a
.Sq cat
page.
.It Sy mlinks.sec
diff --git a/mandoc.h b/mandoc.h
index fd91314d76e8..98578ed45451 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -1,6 +1,6 @@
-/* $Id: mandoc.h,v 1.152 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.171 2014/11/28 18:09:01 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -54,7 +54,6 @@ enum mandocerr {
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 "" */
@@ -72,6 +71,9 @@ enum mandocerr {
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 */
+ MANDOCERR_XR_ORDER, /* unusual Xr order: ... after ... */
+ MANDOCERR_XR_PUNCT, /* unusual Xr punctuation: ... after ... */
+ MANDOCERR_AN_MISSING, /* AUTHORS section without An macro */
/* related to macros and nesting */
MANDOCERR_MACRO_OBS, /* obsolete macro: macro */
@@ -101,6 +103,7 @@ enum mandocerr {
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 */
+ MANDOCERR_EQN_NOBOX, /* missing eqn box, using "": op */
/* related to bad arguments */
MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
@@ -110,6 +113,8 @@ enum mandocerr {
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_FA_COMMA, /* comma in function argument: arg */
+ MANDOCERR_FN_PAREN, /* parenthesis in function name: arg */
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 */
@@ -129,7 +134,6 @@ enum mandocerr {
MANDOCERR_EQNSCOPE, /* equation scope open on exit */
MANDOCERR_EQNBADSCOPE, /* overlapping equation scopes */
MANDOCERR_EQNEOF, /* unexpected end of equation */
- MANDOCERR_EQNSYNT, /* equation syntax error */
/* related to tables */
MANDOCERR_TBL, /* bad table syntax */
@@ -154,6 +158,7 @@ enum mandocerr {
/* related to request and macro arguments */
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
MANDOCERR_ARGCOUNT, /* argument count wrong */
+ MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
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 */
@@ -161,19 +166,26 @@ enum mandocerr {
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_DIVZERO, /* divide by zero */
MANDOCERR_FATAL, /* ===== start of fatal errors ===== */
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_SYSDUP, /* cannot dup file descriptor */
+ MANDOCERR_SYSEXEC, /* cannot exec */
+ MANDOCERR_SYSEXIT, /* gunzip failed with code */
+ MANDOCERR_SYSFORK, /* cannot fork */
MANDOCERR_SYSOPEN, /* cannot open file */
- MANDOCERR_SYSSTAT, /* cannot stat file */
+ MANDOCERR_SYSPIPE, /* cannot open pipe */
MANDOCERR_SYSREAD, /* cannot read file */
+ MANDOCERR_SYSSIG, /* gunzip died from signal */
+ MANDOCERR_SYSSTAT, /* cannot stat file */
+ MANDOCERR_SYSWAIT, /* wait failed */
MANDOCERR_MAX
};
@@ -234,6 +246,7 @@ struct tbl_cell {
#define TBL_CELL_EQUAL (1 << 4) /* e, E */
#define TBL_CELL_UP (1 << 5) /* u, U */
#define TBL_CELL_WIGN (1 << 6) /* z, Z */
+#define TBL_CELL_WMAX (1 << 7) /* x, X */
struct tbl_head *head;
};
@@ -295,21 +308,10 @@ enum eqn_boxt {
EQN_ROOT, /* root of parse tree */
EQN_TEXT, /* text (number, variable, whatever) */
EQN_SUBEXPR, /* nested `eqn' subexpression */
- EQN_LIST, /* subexpressions list */
- EQN_MATRIX /* matrix subexpression */
-};
-
-enum eqn_markt {
- EQNMARK_NONE = 0,
- EQNMARK_DOT,
- EQNMARK_DOTDOT,
- EQNMARK_HAT,
- EQNMARK_TILDE,
- EQNMARK_VEC,
- EQNMARK_DYAD,
- EQNMARK_BAR,
- EQNMARK_UNDER,
- EQNMARK__MAX
+ EQN_LIST, /* list (braces, etc.) */
+ EQN_LISTONE, /* singleton list */
+ EQN_PILE, /* vertical pile */
+ EQN_MATRIX /* pile of piles */
};
enum eqn_fontt {
@@ -323,11 +325,14 @@ enum eqn_fontt {
enum eqn_post {
EQNPOS_NONE = 0,
- EQNPOS_OVER,
EQNPOS_SUP,
+ EQNPOS_SUBSUP,
EQNPOS_SUB,
EQNPOS_TO,
EQNPOS_FROM,
+ EQNPOS_FROMTO,
+ EQNPOS_OVER,
+ EQNPOS_SQRT,
EQNPOS__MAX
};
@@ -355,12 +360,16 @@ struct eqn_box {
struct eqn_box *first; /* first child node */
struct eqn_box *last; /* last child node */
struct eqn_box *next; /* node sibling */
+ struct eqn_box *prev; /* node sibling */
struct eqn_box *parent; /* node sibling */
char *text; /* text (or NULL) */
- char *left;
- char *right;
+ char *left; /* fence left-hand */
+ char *right; /* fence right-hand */
+ char *top; /* expression over-symbol */
+ char *bottom; /* expression under-symbol */
+ size_t args; /* arguments in parent */
+ size_t expectargs; /* max arguments in parent */
enum eqn_post pos; /* position of next box */
- enum eqn_markt mark; /* a mark about the box */
enum eqn_fontt font; /* font of box */
enum eqn_pilet pile; /* equation piling */
};
@@ -383,6 +392,8 @@ struct eqn {
#define MPARSE_MAN 2 /* assume -man */
#define MPARSE_SO 4 /* honour .so requests */
#define MPARSE_QUICK 8 /* abort the parse early */
+#define MPARSE_UTF8 16 /* accept UTF-8 input */
+#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
@@ -413,16 +424,18 @@ __BEGIN_DECLS
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
struct mchars *mchars_alloc(void);
void mchars_free(struct mchars *);
-char mchars_num2char(const char *, size_t);
+int mchars_num2char(const char *, size_t);
+const char *mchars_uc2str(int);
int mchars_num2uc(const char *, size_t);
int mchars_spec2cp(const struct mchars *,
const char *, size_t);
const char *mchars_spec2str(const struct mchars *,
const char *, size_t, size_t *);
struct mparse *mparse_alloc(int, enum mandoclevel, mandocmsg,
- const char *);
+ const struct mchars *, const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
+enum mandoclevel mparse_open(struct mparse *, int *, const char *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t,
const char *);
@@ -432,6 +445,7 @@ void mparse_result(struct mparse *,
const char *mparse_getkeep(const struct mparse *);
const char *mparse_strerror(enum mandocerr);
const char *mparse_strlevel(enum mandoclevel);
+enum mandoclevel mparse_wait(struct mparse *);
__END_DECLS
diff --git a/mandoc_aux.c b/mandoc_aux.c
index b5376735ceea..2275bbcf36b9 100644
--- a/mandoc_aux.c
+++ b/mandoc_aux.c
@@ -1,4 +1,4 @@
-/* $Id: mandoc_aux.c,v 1.3 2014/07/09 08:20:34 schwarze Exp $ */
+/* $Id: mandoc_aux.c,v 1.4 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,7 @@
* 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>
diff --git a/mandoc_escape.3 b/mandoc_escape.3
index 84243fdeb6eb..f381b6297fd0 100644
--- a/mandoc_escape.3
+++ b/mandoc_escape.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc_escape.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $
+.\" $Id: mandoc_escape.3,v 1.2 2014/10/28 14:06:31 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 5 2014 $
+.Dd $Mdocdate: October 28 2014 $
.Dt MANDOC_ESCAPE 3
.Os
.Sh NAME
@@ -197,15 +197,9 @@ form, directly follows the initial backslash:
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.
+If the argument matches one of the forms described below under
+.Dv ESCAPE_UNICODE ,
+that value is returned instead.
.Pp
The
.Dv ESCAPE_SPECIAL
@@ -219,17 +213,27 @@ 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 :
+but with an argument of the forms
+.Ic u Ns Ar XXXX ,
+.Ic u Ns Ar YXXXX ,
+or
+.Ic u10 Ns Ar XXXX
+where
+.Ar X
+and
+.Ar Y
+are hexadecimal digits and
+.Ar Y
+is not zero:
.Ic \eC'u , \e[u .
As a special exception,
.Fa start
is set to the character after the
-.Sq u ,
+.Ic u ,
and the
.Fa sz
return value does not include the
-.Sq u
+.Ic u
either.
.Pp
Such Unicode character escape sequences can be rendered using the function
diff --git a/mandocdb.c b/mandocdb.c
index a604b468ff74..4f6a062fe622 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -1,4 +1,4 @@
-/* $Id: mandocdb.c,v 1.155 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mandocdb.c,v 1.171 2014/11/27 01:58:21 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,10 +15,9 @@
* 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 <sys/stat.h>
#include <sys/wait.h>
@@ -26,7 +25,11 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#if HAVE_FTS
#include <fts.h>
+#else
+#include "compat_fts.h"
+#endif
#include <getopt.h>
#include <limits.h>
#include <stddef.h>
@@ -36,7 +39,7 @@
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_OHASH
+#if HAVE_OHASH
#include <ohash.h>
#else
#include "compat_ohash.h"
@@ -80,12 +83,6 @@ enum op {
OP_TEST /* change no databases, report potential problems */
};
-enum form {
- FORM_NONE, /* format is unknown */
- FORM_SRC, /* format is -man or -mdoc */
- FORM_CAT /* format is cat */
-};
-
struct str {
char *rendered; /* key in UTF-8 or ASCII form */
const struct mpage *mpage; /* if set, the owning parse */
@@ -101,24 +98,24 @@ struct inodev {
struct mpage {
struct inodev inodev; /* used for hashing routine */
int64_t pageid; /* pageid in mpages SQL table */
- enum form form; /* format from file content */
char *sec; /* section from file content */
char *arch; /* architecture from file content */
char *title; /* title from file content */
char *desc; /* description from file content */
struct mlink *mlinks; /* singly linked list */
+ int form; /* format from file content */
};
struct mlink {
char file[PATH_MAX]; /* filename rel. to manpath */
- enum form dform; /* format from directory */
- enum form fform; /* format from file name suffix */
char *dsec; /* section from directory */
char *arch; /* architecture from directory */
char *name; /* name from file name (not empty) */
char *fsec; /* section from file name suffix */
struct mlink *next; /* singly linked list */
struct mpage *mpage; /* parent */
+ int dform; /* format from directory */
+ int fform; /* format from file name suffix */
int gzip; /* filename has a .gz suffix */
};
@@ -141,6 +138,7 @@ struct mdoc_handler {
static void dbclose(int);
static void dbadd(struct mpage *, struct mchars *);
static void dbadd_mlink(const struct mlink *mlink);
+static void dbadd_mlink_name(const struct mlink *mlink);
static int dbopen(int);
static void dbprune(void);
static void filescan(const char *);
@@ -172,7 +170,7 @@ static void putmdockey(const struct mpage *,
const struct mdoc_node *, uint64_t);
static void render_key(struct mchars *, struct str *);
static void say(const char *, const char *, ...);
-static int set_basedir(const char *);
+static int set_basedir(const char *, int);
static int treescan(void);
static size_t utf8(unsigned int, char [7]);
@@ -318,6 +316,7 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = {
{ NULL, 0 }, /* sp */
{ NULL, 0 }, /* %U */
{ NULL, 0 }, /* Ta */
+ { NULL, 0 }, /* ll */
};
@@ -427,9 +426,9 @@ main(int argc, char *argv[])
}
exitcode = (int)MANDOCLEVEL_OK;
- mp = mparse_alloc(mparse_options, MANDOCLEVEL_FATAL, NULL, NULL);
mc = mchars_alloc();
-
+ mp = mparse_alloc(mparse_options, MANDOCLEVEL_FATAL, NULL,
+ mc, NULL);
ohash_init(&mpages, 6, &mpages_info);
ohash_init(&mlinks, 6, &mlinks_info);
@@ -439,7 +438,7 @@ main(int argc, char *argv[])
* Most of these deal with a specific directory.
* Jump into that directory first.
*/
- if (OP_TEST != op && 0 == set_basedir(path_arg))
+ if (OP_TEST != op && 0 == set_basedir(path_arg, 1))
goto out;
if (dbopen(1)) {
@@ -505,12 +504,12 @@ main(int argc, char *argv[])
ohash_init(&mlinks, 6, &mlinks_info);
}
- if (0 == set_basedir(dirs.paths[j]))
- goto out;
+ if (0 == set_basedir(dirs.paths[j], argc > 0))
+ continue;
if (0 == treescan())
- goto out;
+ continue;
if (0 == dbopen(0))
- goto out;
+ continue;
mpages_merge(mc, mp);
if (warnings && !nodb &&
@@ -527,8 +526,8 @@ main(int argc, char *argv[])
}
out:
manpath_free(&dirs);
- mchars_free(mc);
mparse_free(mp);
+ mchars_free(mc);
mpages_free();
ohash_delete(&mpages);
ohash_delete(&mlinks);
@@ -835,6 +834,7 @@ filescan(const char *file)
}
mlink = mandoc_calloc(1, sizeof(struct mlink));
+ mlink->dform = FORM_NONE;
if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
sizeof(mlink->file)) {
say(start, "Filename too long");
@@ -1078,15 +1078,13 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
{
char any[] = "any";
struct ohash_info str_info;
- int fd[2];
struct mpage *mpage, *mpage_dest;
struct mlink *mlink, *mlink_dest;
struct mdoc *mdoc;
struct man *man;
char *sodest;
char *cp;
- pid_t child_pid;
- int status;
+ int fd;
unsigned int pslot;
enum mandoclevel lvl;
@@ -1095,13 +1093,13 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
str_info.free = hash_free;
str_info.key_offset = offsetof(struct str, key);
- if (0 == nodb)
+ if ( ! nodb)
SQL_EXEC("BEGIN TRANSACTION");
mpage = ohash_first(&mpages, &pslot);
- while (NULL != mpage) {
+ while (mpage != NULL) {
mlinks_undupe(mpage);
- if (NULL == mpage->mlinks) {
+ if (mpage->mlinks == NULL) {
mpage = ohash_next(&mpages, &pslot);
continue;
}
@@ -1113,39 +1111,11 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
mdoc = NULL;
man = NULL;
sodest = NULL;
- child_pid = 0;
- fd[0] = -1;
- fd[1] = -1;
-
- if (mpage->mlinks->gzip) {
- if (-1 == pipe(fd)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&pipe gunzip");
- goto nextpage;
- }
- switch (child_pid = fork()) {
- case -1:
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&fork gunzip");
- child_pid = 0;
- close(fd[1]);
- close(fd[0]);
- goto nextpage;
- case 0:
- close(fd[0]);
- if (-1 == dup2(fd[1], STDOUT_FILENO)) {
- say(mpage->mlinks->file,
- "&dup gunzip");
- exit(1);
- }
- execlp("gunzip", "gunzip", "-c",
- mpage->mlinks->file, NULL);
- say(mpage->mlinks->file, "&exec gunzip");
- exit(1);
- default:
- close(fd[1]);
- break;
- }
+
+ mparse_open(mp, &fd, mpage->mlinks->file);
+ if (fd == -1) {
+ say(mpage->mlinks->file, "&open");
+ goto nextpage;
}
/*
@@ -1153,17 +1123,23 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
* source code, unless it is already known to be
* formatted. Fall back to formatted mode.
*/
- if (FORM_CAT != mpage->mlinks->dform ||
- FORM_CAT != mpage->mlinks->fform) {
- lvl = mparse_readfd(mp, fd[0], mpage->mlinks->file);
+ if (mpage->mlinks->dform != FORM_CAT ||
+ mpage->mlinks->fform != FORM_CAT) {
+ lvl = mparse_readfd(mp, fd, mpage->mlinks->file);
if (lvl < MANDOCLEVEL_FATAL)
mparse_result(mp, &mdoc, &man, &sodest);
}
- if (NULL != sodest) {
+ if (sodest != NULL) {
mlink_dest = ohash_find(&mlinks,
ohash_qlookup(&mlinks, sodest));
- if (NULL != mlink_dest) {
+ if (mlink_dest == NULL) {
+ mandoc_asprintf(&cp, "%s.gz", sodest);
+ mlink_dest = ohash_find(&mlinks,
+ ohash_qlookup(&mlinks, cp));
+ free(cp);
+ }
+ if (mlink_dest != NULL) {
/* The .so target exists. */
@@ -1182,9 +1158,9 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
*/
if (mpage_dest->pageid)
- dbadd_mlink(mlink);
+ dbadd_mlink_name(mlink);
- if (NULL == mlink->next)
+ if (mlink->next == NULL)
break;
mlink = mlink->next;
}
@@ -1196,17 +1172,17 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
mpage->mlinks = NULL;
}
goto nextpage;
- } else if (NULL != mdoc) {
+ } else if (mdoc != NULL) {
mpage->form = FORM_SRC;
mpage->sec = mdoc_meta(mdoc)->msec;
mpage->sec = mandoc_strdup(
- NULL == mpage->sec ? "" : mpage->sec);
+ mpage->sec == NULL ? "" : mpage->sec);
mpage->arch = mdoc_meta(mdoc)->arch;
mpage->arch = mandoc_strdup(
- NULL == mpage->arch ? "" : mpage->arch);
+ mpage->arch == NULL ? "" : mpage->arch);
mpage->title =
mandoc_strdup(mdoc_meta(mdoc)->title);
- } else if (NULL != man) {
+ } else if (man != NULL) {
mpage->form = FORM_SRC;
mpage->sec =
mandoc_strdup(man_meta(man)->msec);
@@ -1224,8 +1200,8 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
mandoc_strdup(mpage->mlinks->name);
}
putkey(mpage, mpage->sec, TYPE_sec);
- putkey(mpage, '\0' == *mpage->arch ?
- any : mpage->arch, TYPE_arch);
+ if (*mpage->arch != '\0')
+ putkey(mpage, mpage->arch, TYPE_arch);
for (mlink = mpage->mlinks; mlink; mlink = mlink->next) {
if ('\0' != *mlink->dsec)
@@ -1245,7 +1221,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
} else if (NULL != man)
parse_man(mpage, man_node(man));
else
- parse_cat(mpage, fd[0]);
+ parse_cat(mpage, fd);
if (NULL == mpage->desc)
mpage->desc = mandoc_strdup(mpage->mlinks->name);
@@ -1257,21 +1233,9 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
dbadd(mpage, mc);
nextpage:
- if (child_pid) {
- if (-1 == waitpid(child_pid, &status, 0)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&wait gunzip");
- } else if (WIFSIGNALED(status)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file,
- "gunzip died from signal %d",
- WTERMSIG(status));
- } else if (WEXITSTATUS(status)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file,
- "gunzip failed with code %d",
- WEXITSTATUS(status));
- }
+ if (mparse_wait(mp) != MANDOCLEVEL_OK) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file, "&wait gunzip");
}
ohash_delete(&strings);
ohash_delete(&names);
@@ -1329,6 +1293,8 @@ parse_cat(struct mpage *mpage, int fd)
fopen(mpage->mlinks->file, "r") :
fdopen(fd, "r");
if (NULL == stream) {
+ if (-1 != fd)
+ close(fd);
if (warnings)
say(mpage->mlinks->file, "&fopen");
return;
@@ -1764,7 +1730,8 @@ putkeys(const struct mpage *mpage,
if (TYPE_Nm & v) {
htab = &names;
v &= name_mask;
- name_mask &= ~NAME_FIRST;
+ if (v & NAME_FIRST)
+ name_mask &= ~NAME_FIRST;
if (debug > 1)
say(mpage->mlinks->file,
"Adding name %*s", sz, cp);
@@ -1772,7 +1739,7 @@ putkeys(const struct mpage *mpage,
htab = &strings;
if (debug > 1)
for (i = 0; i < mansearch_keymax; i++)
- if (1 << i & v)
+ if ((uint64_t)1 << i & v)
say(mpage->mlinks->file,
"Adding key %s=%*s",
mansearch_keynames[i], sz, cp);
@@ -1939,7 +1906,7 @@ render_key(struct mchars *mc, struct str *key)
*/
if (write_utf8) {
- if (0 == (u = mchars_spec2cp(mc, seq, len)))
+ if ((u = mchars_spec2cp(mc, seq, len)) <= 0)
continue;
cpp = utfbuf;
if (0 == (sz = utf8(u, utfbuf)))
@@ -1981,6 +1948,21 @@ dbadd_mlink(const struct mlink *mlink)
sqlite3_reset(stmts[STMT_INSERT_LINK]);
}
+static void
+dbadd_mlink_name(const struct mlink *mlink)
+{
+ size_t i;
+
+ dbadd_mlink(mlink);
+
+ i = 1;
+ SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, NAME_FILE & NAME_MASK);
+ SQL_BIND_TEXT(stmts[STMT_INSERT_NAME], i, mlink->name);
+ SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, mlink->mpage->pageid);
+ SQL_STEP(stmts[STMT_INSERT_NAME]);
+ sqlite3_reset(stmts[STMT_INSERT_NAME]);
+}
+
/*
* Flush the current page's terms (and their bits) into the database.
* Wrap the entire set of additions in a transaction to make sqlite be a
@@ -2045,7 +2027,7 @@ dbadd(struct mpage *mpage, struct mchars *mc)
i = 1;
SQL_BIND_TEXT(stmts[STMT_INSERT_PAGE], i, key->rendered);
- SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, FORM_SRC == mpage->form);
+ SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, mpage->form);
SQL_STEP(stmts[STMT_INSERT_PAGE]);
mpage->pageid = sqlite3_last_insert_rowid(db);
sqlite3_reset(stmts[STMT_INSERT_PAGE]);
@@ -2342,7 +2324,7 @@ prepare_statements:
"PRAGMA synchronous = OFF", NULL, NULL, NULL)) {
exitcode = (int)MANDOCLEVEL_SYSERR;
say(MANDOC_DB, "PRAGMA synchronous: %s",
- sqlite3_errmsg(db));
+ sqlite3_errmsg(db));
sqlite3_close(db);
return(0);
}
@@ -2373,7 +2355,7 @@ hash_free(void *p, void *arg)
}
static int
-set_basedir(const char *targetdir)
+set_basedir(const char *targetdir, int report_baddir)
{
static char startdir[PATH_MAX];
static int getcwd_status; /* 1 = ok, 2 = failure */
@@ -2426,12 +2408,16 @@ set_basedir(const char *targetdir)
* we can reliably check whether files are inside.
*/
if (NULL == realpath(targetdir, basedir)) {
- exitcode = (int)MANDOCLEVEL_BADARG;
- say("", "&%s: realpath", targetdir);
+ if (report_baddir || errno != ENOENT) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say("", "&%s: realpath", targetdir);
+ }
return(0);
} else if (-1 == chdir(basedir)) {
- exitcode = (int)MANDOCLEVEL_BADARG;
- say("", "&chdir");
+ if (report_baddir || errno != ENOENT) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say("", "&chdir");
+ }
return(0);
}
chdir_status = 1;
diff --git a/manpage.c b/manpage.c
index 00793ccce48d..70eb06b69ceb 100644
--- a/manpage.c
+++ b/manpage.c
@@ -1,4 +1,4 @@
-/* $Id: manpage.c,v 1.7 2014/01/06 03:02:46 schwarze Exp $ */
+/* $Id: manpage.c,v 1.9 2014/08/17 03:24:47 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,9 @@
* 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 <assert.h>
#include <getopt.h>
@@ -87,10 +87,11 @@ main(int argc, char *argv[])
if (0 == argc)
goto usage;
- search.deftype = TYPE_Nm | TYPE_Nd;
+ search.outkey = "Nd";
+ search.argmode = ARG_EXPR;
manpath_parse(&paths, conf_file, defpaths, auxpaths);
- ch = mansearch(&search, &paths, argc, argv, "Nd", &res, &sz);
+ ch = mansearch(&search, &paths, argc, argv, &res, &sz);
manpath_free(&paths);
if (0 == ch)
diff --git a/manpath.c b/manpath.c
index 61b2c7e05077..e85175e945e8 100644
--- a/manpath.c
+++ b/manpath.c
@@ -1,6 +1,6 @@
-/* $Id: manpath.c,v 1.15 2014/04/23 21:06:41 schwarze Exp $ */
+/* $Id: manpath.c,v 1.19 2014/11/27 00:30:40 schwarze Exp $ */
/*
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,9 +15,10 @@
* 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 <sys/stat.h>
#include <assert.h>
#include <ctype.h>
@@ -32,14 +33,14 @@
#define MAN_CONF_FILE "/etc/man.conf"
#define MAN_CONF_KEY "_whatdb"
-static void manpath_add(struct manpaths *, const char *);
-static void manpath_parseline(struct manpaths *, char *);
+static void manpath_add(struct manpaths *, const char *, int);
+static void manpath_parseline(struct manpaths *, char *, int);
void
manpath_parse(struct manpaths *dirs, const char *file,
char *defp, char *auxp)
{
-#ifdef USE_MANPATH
+#if HAVE_MANPATH
char cmd[(PATH_MAX * 3) + 20];
FILE *stream;
char *buf;
@@ -79,7 +80,7 @@ manpath_parse(struct manpaths *dirs, const char *file,
if ( ! ferror(stream) && feof(stream) &&
bsz && '\n' == buf[bsz - 1]) {
buf[bsz - 1] = '\0';
- manpath_parseline(dirs, buf);
+ manpath_parseline(dirs, buf, 1);
}
free(buf);
@@ -88,11 +89,11 @@ manpath_parse(struct manpaths *dirs, const char *file,
char *insert;
/* Always prepend -m. */
- manpath_parseline(dirs, auxp);
+ manpath_parseline(dirs, auxp, 1);
/* If -M is given, it overrides everything else. */
if (NULL != defp) {
- manpath_parseline(dirs, defp);
+ manpath_parseline(dirs, defp, 1);
return;
}
@@ -110,13 +111,13 @@ manpath_parse(struct manpaths *dirs, const char *file,
/* Prepend man.conf(5) to MANPATH. */
if (':' == defp[0]) {
manpath_manconf(dirs, file);
- manpath_parseline(dirs, defp);
+ manpath_parseline(dirs, defp, 0);
return;
}
/* Append man.conf(5) to MANPATH. */
if (':' == defp[strlen(defp) - 1]) {
- manpath_parseline(dirs, defp);
+ manpath_parseline(dirs, defp, 0);
manpath_manconf(dirs, file);
return;
}
@@ -125,14 +126,14 @@ manpath_parse(struct manpaths *dirs, const char *file,
insert = strstr(defp, "::");
if (NULL != insert) {
*insert++ = '\0';
- manpath_parseline(dirs, defp);
+ manpath_parseline(dirs, defp, 0);
manpath_manconf(dirs, file);
- manpath_parseline(dirs, insert + 1);
+ manpath_parseline(dirs, insert + 1, 0);
return;
}
/* MANPATH overrides man.conf(5) completely. */
- manpath_parseline(dirs, defp);
+ manpath_parseline(dirs, defp, 0);
#endif
}
@@ -140,7 +141,7 @@ manpath_parse(struct manpaths *dirs, const char *file,
* Parse a FULL pathname from a colon-separated list of arrays.
*/
static void
-manpath_parseline(struct manpaths *dirs, char *path)
+manpath_parseline(struct manpaths *dirs, char *path, int complain)
{
char *dir;
@@ -148,7 +149,7 @@ manpath_parseline(struct manpaths *dirs, char *path)
return;
for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
- manpath_add(dirs, dir);
+ manpath_add(dirs, dir, complain);
}
/*
@@ -156,19 +157,33 @@ manpath_parseline(struct manpaths *dirs, char *path)
* Grow the array one-by-one for simplicity's sake.
*/
static void
-manpath_add(struct manpaths *dirs, const char *dir)
+manpath_add(struct manpaths *dirs, const char *dir, int complain)
{
char buf[PATH_MAX];
+ struct stat sb;
char *cp;
size_t i;
- if (NULL == (cp = realpath(dir, buf)))
+ if (NULL == (cp = realpath(dir, buf))) {
+ if (complain) {
+ fputs("manpath: ", stderr);
+ perror(dir);
+ }
return;
+ }
for (i = 0; i < dirs->sz; i++)
if (0 == strcmp(dirs->paths[i], dir))
return;
+ if (stat(cp, &sb) == -1) {
+ if (complain) {
+ fputs("manpath: ", stderr);
+ perror(dir);
+ }
+ return;
+ }
+
dirs->paths = mandoc_reallocarray(dirs->paths,
dirs->sz + 1, sizeof(char *));
@@ -215,7 +230,7 @@ manpath_manconf(struct manpaths *dirs, const char *file)
if (NULL == (q = strrchr(p, '/')))
continue;
*q = '\0';
- manpath_add(dirs, p);
+ manpath_add(dirs, p, 0);
}
fclose(stream);
diff --git a/mansearch.c b/mansearch.c
index e1226b1ce173..77d4c074c060 100644
--- a/mansearch.c
+++ b/mansearch.c
@@ -1,4 +1,4 @@
-/* $Id: mansearch.c,v 1.42 2014/08/09 14:24:53 schwarze Exp $ */
+/* $Id: mansearch.c,v 1.51 2014/11/27 01:58:21 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,11 +15,11 @@
* 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 <sys/types.h>
+
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
@@ -32,7 +32,7 @@
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_OHASH
+#if HAVE_OHASH
#include <ohash.h>
#else
#include "compat_ohash.h"
@@ -79,8 +79,9 @@ struct expr {
struct match {
uint64_t pageid; /* identifier in database */
+ uint64_t bits; /* name type mask */
char *desc; /* manual page description */
- int form; /* 0 == catpage */
+ int form; /* bit field: formatted, zipped? */
};
static void buildnames(struct manpage *, sqlite3 *,
@@ -159,7 +160,6 @@ 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;
@@ -195,11 +195,11 @@ mansearch(const struct mansearch *search,
goto out;
outbit = 0;
- if (NULL != outkey) {
+ if (NULL != search->outkey) {
for (indexbit = 0, iterbit = 1;
indexbit < mansearch_keymax;
indexbit++, iterbit <<= 1) {
- if (0 == strcasecmp(outkey,
+ if (0 == strcasecmp(search->outkey,
mansearch_keynames[indexbit])) {
outbit = iterbit;
break;
@@ -302,6 +302,7 @@ mansearch(const struct mansearch *search,
mp = mandoc_calloc(1, sizeof(struct match));
mp->pageid = pageid;
mp->form = sqlite3_column_int(s, 1);
+ mp->bits = sqlite3_column_int64(s, 3);
if (TYPE_Nd == outbit)
mp->desc = mandoc_strdup((const char *)
sqlite3_column_text(s, 0));
@@ -336,6 +337,8 @@ mansearch(const struct mansearch *search,
maxres, sizeof(struct manpage));
}
mpage = *res + cur;
+ mpage->ipath = i;
+ mpage->bits = mp->bits;
mpage->sec = 10;
mpage->form = mp->form;
buildnames(mpage, db, s, mp->pageid,
@@ -352,6 +355,14 @@ mansearch(const struct mansearch *search,
sqlite3_finalize(s2);
sqlite3_close(db);
ohash_delete(&htab);
+
+ /*
+ * In man(1) mode, prefer matches in earlier trees
+ * over matches in later trees.
+ */
+
+ if (cur && search->firstmatch)
+ break;
}
qsort(*res, cur, sizeof(struct manpage), manpage_compare);
rc = 1;
@@ -367,6 +378,19 @@ out:
return(rc);
}
+void
+mansearch_free(struct manpage *res, size_t sz)
+{
+ size_t i;
+
+ for (i = 0; i < sz; i++) {
+ free(res[i].file);
+ free(res[i].names);
+ free(res[i].output);
+ }
+ free(res);
+}
+
static int
manpage_compare(const void *vp1, const void *vp2)
{
@@ -375,8 +399,9 @@ manpage_compare(const void *vp1, const void *vp2)
mp1 = vp1;
mp2 = vp2;
- diff = mp1->sec - mp2->sec;
- return(diff ? diff : strcasecmp(mp1->names, mp2->names));
+ return( (diff = mp2->bits - mp1->bits) ? diff :
+ (diff = mp1->sec - mp2->sec) ? diff :
+ strcasecmp(mp1->names, mp2->names));
}
static void
@@ -447,28 +472,28 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
/* Also save the first file name encountered. */
- if (NULL != mpage->file)
+ if (mpage->file != NULL)
continue;
- if (form) {
+ if (form & FORM_SRC) {
sep1 = "man";
fsec = sec;
} else {
sep1 = "cat";
fsec = "0";
}
- sep2 = '\0' == *arch ? "" : "/";
+ sep2 = *arch == '\0' ? "" : "/";
mandoc_asprintf(&mpage->file, "%s/%s%s%s%s/%s.%s",
path, sep1, sec, sep2, arch, name, fsec);
}
- if (SQLITE_DONE != c)
+ if (c != SQLITE_DONE)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
sqlite3_reset(s);
/* Append one final section to the names. */
- if (NULL != prevsec) {
- sep2 = '\0' == *prevarch ? "" : "/";
+ if (prevsec != NULL) {
+ sep2 = *prevarch == '\0' ? "" : "/";
mandoc_asprintf(&newnames, "%s(%s%s%s)",
mpage->names, prevsec, sep2, prevarch);
free(mpage->names);
@@ -566,8 +591,10 @@ sql_statement(const struct expr *e)
size_t sz;
int needop;
- sql = mandoc_strdup(
- "SELECT desc, form, pageid FROM mpages WHERE ");
+ sql = mandoc_strdup(e->equal ?
+ "SELECT desc, form, pageid, bits "
+ "FROM mpages NATURAL JOIN names WHERE " :
+ "SELECT desc, form, pageid, 0 FROM mpages WHERE ");
sz = strlen(sql);
for (needop = 0; NULL != e; e = e->next) {
@@ -587,8 +614,7 @@ sql_statement(const struct expr *e)
? "pageid IN (SELECT pageid FROM names "
"WHERE name REGEXP ?)"
: e->equal
- ? "pageid IN (SELECT pageid FROM names "
- "WHERE name = ?)"
+ ? "name = ? "
: "pageid IN (SELECT pageid FROM names "
"WHERE name MATCH ?)")
: (NULL == e->substr
@@ -739,35 +765,30 @@ exprterm(const struct mansearch *search, char *buf, int cs)
e = mandoc_calloc(1, sizeof(struct expr));
- if (MANSEARCH_MAN & search->flags) {
- e->bits = search->deftype;
+ if (search->argmode == ARG_NAME) {
+ e->bits = TYPE_Nm;
e->substr = buf;
e->equal = 1;
return(e);
}
/*
- * Look for an '=' or '~' operator,
- * unless forced to some fixed macro keys.
+ * Separate macro keys from search string.
+ * If needed, request regular expression handling
+ * by setting e->substr to NULL.
*/
- if (MANSEARCH_WHATIS & search->flags)
- val = NULL;
- else
- val = strpbrk(buf, "=~");
-
- if (NULL == val) {
- e->bits = search->deftype;
+ if (search->argmode == ARG_WORD) {
+ e->bits = TYPE_Nm;
+ e->substr = NULL;
+ mandoc_asprintf(&val, "[[:<:]]%s[[:>:]]", buf);
+ cs = 0;
+ } else if ((val = strpbrk(buf, "=~")) == NULL) {
+ e->bits = TYPE_Nm | TYPE_Nd;
e->substr = buf;
-
- /*
- * Found an operator.
- * Regexp search is requested by !e->substr.
- */
-
} else {
if (val == buf)
- e->bits = search->deftype;
+ e->bits = TYPE_Nm | TYPE_Nd;
if ('=' == *val)
e->substr = val + 1;
*val++ = '\0';
@@ -777,15 +798,10 @@ exprterm(const struct mansearch *search, char *buf, int cs)
/* 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)
+ if (search->argmode == ARG_WORD)
free(val);
if (irc) {
regerror(irc, &e->regexp, errbuf, sizeof(errbuf));
diff --git a/mansearch.h b/mansearch.h
index eff5e371c2f0..4f92ef260838 100644
--- a/mansearch.h
+++ b/mansearch.h
@@ -1,4 +1,4 @@
-/* $Id: mansearch.h,v 1.15 2014/07/24 20:30:45 schwarze Exp $ */
+/* $Id: mansearch.h,v 1.21 2014/11/27 01:58:21 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -62,18 +62,29 @@
#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_FIRST 0x0000004000000004ULL
+#define NAME_TITLE 0x0000004000000006ULL
+#define NAME_HEAD 0x0000004000000008ULL
+#define NAME_FILE 0x0000004000000010ULL
#define NAME_MASK 0x000000000000001fULL
-__BEGIN_DECLS
+#define FORM_CAT 0 /* manual page is preformatted */
+#define FORM_SRC 1 /* format is mdoc(7) or man(7) */
+#define FORM_NONE 4 /* format is unknown */
+
+enum argmode {
+ ARG_FILE = 0,
+ ARG_NAME,
+ ARG_WORD,
+ ARG_EXPR
+};
struct manpage {
char *file; /* to be prefixed by manpath */
char *names; /* a list of names with sections */
char *output; /* user-defined additional output */
+ size_t ipath; /* number of the manpath */
+ uint64_t bits; /* name type mask */
int sec; /* section number, 10 means invalid */
int form; /* 0 == catpage */
};
@@ -81,21 +92,22 @@ struct manpage {
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 */
+ const char *outkey; /* show content of this macro */
+ enum argmode argmode; /* interpretation of arguments */
+ int firstmatch; /* first matching database only */
};
+__BEGIN_DECLS
+
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 */
+void mansearch_free(struct manpage *, size_t);
__END_DECLS
-#endif /*!MANSEARCH_H*/
+#endif /* MANSEARCH_H */
diff --git a/mansearch_const.c b/mansearch_const.c
index 1533f927d6e5..9ba8bc250ab3 100644
--- a/mansearch_const.c
+++ b/mansearch_const.c
@@ -1,4 +1,4 @@
-/* $Id: mansearch_const.c,v 1.5 2014/08/09 14:05:21 schwarze Exp $ */
+/* $Id: mansearch_const.c,v 1.6 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -14,11 +14,10 @@
* 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"
diff --git a/mchars_alloc.3 b/mchars_alloc.3
index 8c3f853492f2..eba81b5224ec 100644
--- a/mchars_alloc.3
+++ b/mchars_alloc.3
@@ -1,4 +1,4 @@
-.\" $Id: mchars_alloc.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $
+.\" $Id: mchars_alloc.3,v 1.2 2014/10/26 18:07:28 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 5 2014 $
+.Dd $Mdocdate: October 26 2014 $
.Dt MCHARS_ALLOC 3
.Os
.Sh NAME
@@ -59,6 +59,8 @@
.Fa "size_t sz"
.Fa "size_t *rsz"
.Fc
+.Ft "const char *"
+.Fn mchars_uc2str "int codepoint"
.Sh DESCRIPTION
These functions translate Unicode character numbers and
.Xr roff 7
@@ -199,6 +201,14 @@ output module use this function to render
and
.Ic \eC\(aq Ns Ar name Ns Ic \(aq
escape sequences.
+.Pp
+The function
+.Fn mchars_uc2str
+performs a reverse lookup of the Unicode
+.Fa codepoint
+and returns an ASCII string representation, or the string
+.Qq <?>
+if none is available.
.Sh FILES
These funtions are implemented in the file
.Pa chars.c .
@@ -218,6 +228,7 @@ following mandoc versions:
.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
+.It Fn mchars_uc2str Ta 1.13.2 Ta \(em Ta \(em
.El
.Sh AUTHORS
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
diff --git a/mdoc.7 b/mdoc.7
index a8c60d5e984d..a13d613bbf89 100644
--- a/mdoc.7
+++ b/mdoc.7
@@ -1,4 +1,4 @@
-.\" $Id: mdoc.7,v 1.234 2014/08/08 16:38:06 schwarze Exp $
+.\" $Id: mdoc.7,v 1.244 2014/11/28 18:36:35 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: August 8 2014 $
+.Dd $Mdocdate: November 28 2014 $
.Dt MDOC 7
.Os
.Sh NAME
@@ -388,7 +388,7 @@ See
References other manuals with related topics.
This section should exist for most manuals.
Cross-references should conventionally be ordered first by section, then
-alphabetically.
+alphabetically (ignoring case).
.Pp
References to other documentation concerning the topic of the manual page,
for example authoritative books or journal articles, may also be
@@ -433,7 +433,7 @@ in the alphabetical
.Ss Document preamble and NAME section macros
.Bl -column "Brq, Bro, Brc" description
.It Sx \&Dd Ta document date: Cm $\&Mdocdate$ | Ar month day , year
-.It Sx \&Dt Ta document title: Ar TITLE section Op Ar volume | arch
+.It Sx \&Dt Ta document title: Ar TITLE section Op Ar arch
.It Sx \&Os Ta operating system version: Op Ar system Op Ar version
.It Sx \&Nm Ta document name (one argument)
.It Sx \&Nd Ta document description (one line)
@@ -937,8 +937,11 @@ The
.Fl width
and
.Fl offset
-arguments accept scaling widths as described in
-.Xr roff 7
+arguments accept macro names as described for
+.Sx \&Bd
+.Fl offset ,
+scaling widths as described in
+.Xr roff 7 ,
or use the length of the given string.
The
.Fl offset
@@ -1182,13 +1185,12 @@ See also
and
.Sx \&Dl .
.Ss \&Db
-Switch debugging mode.
-Its syntax is as follows:
-.Pp
-.D1 Pf \. Sx \&Db Cm on | off
-.Pp
-This macro is ignored by
-.Xr mandoc 1 .
+This macro is obsolete.
+No replacement is needed.
+It is ignored by
+.Xr mandoc 1
+and groff including its arguments.
+It was formerly used to toggle a debugging mode.
.Ss \&Dc
Close a
.Sx \&Do
@@ -1245,7 +1247,7 @@ See also
and
.Sx \&Os .
.Ss \&Dl
-One-line intended display.
+One-line indented display.
This is formatted as literal text and is useful for commands and
invocations.
It is followed by a newline.
@@ -1297,7 +1299,7 @@ Its syntax is as follows:
.Pf \. Sx \&Dt
.Ar TITLE
.Ar section
-.Op Ar volume | arch
+.Op Ar arch
.Ed
.Pp
Its arguments are as follows:
@@ -1346,35 +1348,6 @@ or
.Pq paper .
It should correspond to the manual's filename suffix and defaults to
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
-.Cm USD
-.Pq users' supplementary documents ,
-.Cm PS1
-.Pq programmers' supplementary documents ,
-.Cm AMD
-.Pq administrators' supplementary documents ,
-.Cm SMM
-.Pq system managers' manuals ,
-.Cm URM
-.Pq users' reference manuals ,
-.Cm PRM
-.Pq programmers' reference manuals ,
-.Cm KM
-.Pq kernel manuals ,
-.Cm IND
-.Pq master index ,
-.Cm MMI
-.Pq master index ,
-.Cm LOCAL
-.Pq local manuals ,
-.Cm LOC
-.Pq local manuals ,
-or
-.Cm CON
-.Pq contributed manuals .
.It Ar arch
This specifies the machine architecture a manual page applies to,
where relevant, for example
@@ -1383,17 +1356,11 @@ where relevant, for example
.Cm i386 ,
or
.Cm sparc64 .
-The list of supported architectures varies by operating system.
-For the full list of all architectures recognized by
-.Xr mandoc 1 ,
-see the file
-.Pa arch.in
-in the source distribution.
+The list of valid architectures varies by operating system.
.El
.Pp
Examples:
.Dl \&.Dt FOO 1
-.Dl \&.Dt FOO 4 KM
.Dl \&.Dt FOO 9 i386
.Pp
See also
@@ -1467,16 +1434,29 @@ See also
and
.Sx \&It .
.Ss \&Em
-Denotes text that should be
-.Em emphasised .
-Note that this is a presentation term and should not be used for
-stylistically decorating technical terms.
-Depending on the output device, this is usually represented
-using an italic font or underlined characters.
+Request an italic font.
+If the output device does not provide that, underline.
+.Pp
+This is most often used for stress emphasis (not to be confused with
+importance, see
+.Sx \&Sy ) .
+In the rare cases where none of the semantic markup macros fit,
+it can also be used for technical terms and placeholders, except
+that for syntax elements,
+.Sx \&Sy
+and
+.Sx \&Ar
+are preferred, respectively.
.Pp
Examples:
-.Dl \&.Em Warnings!
-.Dl \&.Em Remarks :
+.Bd -literal -compact -offset indent
+Selected lines are those
+\&.Em not
+matching any of the specified patterns.
+Some of the functions use a
+\&.Em hold space
+to save the pattern space for subsequent retrieval.
+.Ed
.Pp
See also
.Sx \&Bf ,
@@ -1557,7 +1537,7 @@ arguments are treated as separate utilities.
See also
.Sx \&Rv .
.Ss \&Fa
-Function argument.
+Function argument or parameter.
Its syntax is as follows:
.Bd -ragged -offset indent
.Pf \. Sx \&Fa
@@ -2497,10 +2477,12 @@ Based on POSIX.1 and POSIX.2, published in 1992.
.It Single UNIX Specification version 1 and related standards
.Pp
.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-susv1
+.St -susv1
.It \-xpg4.2
.St -xpg4.2
.br
-This standard was published in 1994 and is also called SUSv1.
+This standard was published in 1994.
It was used as the basis for UNIX 95 certification.
The following three refer to parts of it.
.Pp
@@ -2544,17 +2526,8 @@ The following refer to parts of it.
.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
@@ -2564,16 +2537,6 @@ POSIX software administration.
.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
@@ -2593,8 +2556,10 @@ The second and last Technical Corrigendum.
.Bl -tag -width "-p1003.1g-2000" -compact
.It \-p1003.1-2008
.St -p1003.1-2008
+.It \-susv4
+.St -susv4
.br
-This standard is also called SUSv4 and
+This standard is also called
X/Open Portability Guide version 7.
.Pp
.It \-p1003.1-2013
@@ -2637,10 +2602,24 @@ See also
and
.Sx \&Ss .
.Ss \&Sy
-Format enclosed arguments in symbolic
-.Pq Dq boldface .
-Note that this is a presentation term and should not be used for
-stylistically decorating technical terms.
+Request a boldface font.
+.Pp
+This is most often used to indicate importance or seriousness (not to be
+confused with stress emphasis, see
+.Sx \&Em ) .
+When none of the semantic macros fit, it is also adequate for syntax
+elements that have to be given or that appear verbatim.
+.Pp
+Examples:
+.Bd -literal -compact -offset indent
+\&.Sy Warning :
+If
+\&.Sy s
+appears in the owner permissions, set-user-ID mode is set.
+This utility replaces the former
+\&.Sy dumpdir
+program.
+.Ed
.Pp
See also
.Sx \&Bf ,
@@ -2673,8 +2652,17 @@ A variable name.
Examples:
.Dl \&.Va foo
.Dl \&.Va const char *bar ;
+.Pp
+For function arguments and parameters, use
+.Sx \&Fa
+instead.
+For declarations of global variables in the
+.Em SYNOPSIS
+section, use
+.Sx \&Vt .
.Ss \&Vt
A variable type.
+.Pp
This is also used for indicating global variables in the
.Em SYNOPSIS
section, in which case a variable name is also specified.
@@ -2689,18 +2677,21 @@ In the former case, this macro starts a new output line,
and a blank line is inserted in front if there is a preceding
function definition or include directive.
.Pp
-Note that this should not be confused with
-.Sx \&Ft ,
-which is used for function return types.
-.Pp
Examples:
.Dl \&.Vt unsigned char
.Dl \&.Vt extern const char * const sys_signame[] \&;
.Pp
+For parameters in function prototypes, use
+.Sx \&Fa
+instead, for function return types
+.Sx \&Ft ,
+and for variable names outside the
+.Em SYNOPSIS
+section
+.Sx \&Va ,
+even when including a type with the name.
See also
-.Sx MANUAL STRUCTURE
-and
-.Sx \&Va .
+.Sx MANUAL STRUCTURE .
.Ss \&Xc
Close a scope opened by
.Sx \&Xo .
diff --git a/mdoc.c b/mdoc.c
index e8143bf08841..3e80bc7786a5 100644
--- a/mdoc.c
+++ b/mdoc.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc.c,v 1.223 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.233 2014/11/28 06:27:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,7 @@
* 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>
@@ -91,11 +89,7 @@ static void mdoc_free1(struct mdoc *);
static void mdoc_alloc1(struct mdoc *);
static struct mdoc_node *node_alloc(struct mdoc *, int, int,
enum mdoct, enum mdoc_type);
-static int node_append(struct mdoc *,
- struct mdoc_node *);
-#if 0
-static int mdoc_preptext(struct mdoc *, int, char *, int);
-#endif
+static void node_append(struct mdoc *, struct mdoc_node *);
static int mdoc_ptext(struct mdoc *, int, char *, int);
static int mdoc_pmacro(struct mdoc *, int, char *, int);
@@ -200,37 +194,32 @@ int
mdoc_endparse(struct mdoc *mdoc)
{
- return(mdoc_macroend(mdoc));
+ mdoc_macroend(mdoc);
+ return(1);
}
-int
+void
mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep)
{
struct mdoc_node *n;
n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
n->eqn = ep;
-
- if ( ! node_append(mdoc, n))
- return(0);
-
+ if (ep->ln > mdoc->last->line)
+ n->flags |= MDOC_LINE;
+ node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
-int
+void
mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
{
struct mdoc_node *n;
n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL);
n->span = sp;
-
- if ( ! node_append(mdoc, n))
- return(0);
-
+ node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
/*
@@ -241,7 +230,8 @@ int
mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
{
- mdoc->flags |= MDOC_NEWLINE;
+ if (mdoc->last->type != MDOC_EQN || ln > mdoc->last->line)
+ mdoc->flags |= MDOC_NEWLINE;
/*
* Let the roff nS register switch SYNOPSIS mode early,
@@ -259,7 +249,7 @@ mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
mdoc_ptext(mdoc, ln, buf, offs));
}
-int
+void
mdoc_macro(MACRO_PROT_ARGS)
{
assert(tok < MDOC_MAX);
@@ -269,7 +259,7 @@ mdoc_macro(MACRO_PROT_ARGS)
mandoc_vmsg(MANDOCERR_DT_LATE,
mdoc->parse, line, ppos,
"Dt %s", buf + *pos);
- return(1);
+ return;
}
} else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) {
if (mdoc->meta.title == NULL) {
@@ -282,12 +272,11 @@ mdoc_macro(MACRO_PROT_ARGS)
mdoc->meta.vol = mandoc_strdup("LOCAL");
mdoc->flags |= MDOC_PBODY;
}
-
- return((*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf));
+ (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
}
-static int
+static void
node_append(struct mdoc *mdoc, struct mdoc_node *p)
{
@@ -331,8 +320,7 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
break;
}
- if ( ! mdoc_valid_pre(mdoc, p))
- return(0);
+ mdoc_valid_pre(mdoc, p);
switch (p->type) {
case MDOC_HEAD:
@@ -359,14 +347,11 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
case MDOC_TBL:
/* FALLTHROUGH */
case MDOC_TEXT:
- if ( ! mdoc_valid_post(mdoc))
- return(0);
+ mdoc_valid_post(mdoc);
break;
default:
break;
}
-
- return(1);
}
static struct mdoc_node *
@@ -396,46 +381,41 @@ node_alloc(struct mdoc *mdoc, int line, int pos,
return(p);
}
-int
+void
mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
struct mdoc_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
}
-int
+struct mdoc_node *
mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
struct mdoc_node *p;
assert(mdoc->first);
assert(mdoc->last);
-
p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
+ return(p);
}
-int
+struct mdoc_node *
mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
struct mdoc_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
+ return(p);
}
-int
+void
mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
struct mdoc_node *body, enum mdoc_endbody end)
{
@@ -445,13 +425,11 @@ mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
p->pending = body;
p->norm = body->norm;
p->end = end;
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
-int
+struct mdoc_node *
mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
{
@@ -477,14 +455,12 @@ mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
default:
break;
}
-
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
+ return(p);
}
-int
+void
mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
{
@@ -502,26 +478,19 @@ mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
default:
break;
}
-
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
}
-int
+void
mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p)
{
struct mdoc_node *n;
n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT);
n->string = roff_strdup(mdoc->roff, p);
-
- if ( ! node_append(mdoc, n))
- return(0);
-
+ node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
void
@@ -603,68 +572,14 @@ mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
mdoc_node_free(p);
}
-int
+void
mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
{
mdoc_node_unlink(mdoc, p);
- return(node_append(mdoc, p));
+ node_append(mdoc, p);
}
-#if 0
-/*
- * Pre-treat a text line.
- * Text lines can consist of equations, which must be handled apart from
- * the regular text.
- * Thus, use this function to step through a line checking if it has any
- * equations embedded in it.
- * This must handle multiple equations AND equations that do not end at
- * the end-of-line, i.e., will re-enter in the next roff parse.
- */
-static int
-mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs)
-{
- char *start, *end;
- char delim;
-
- while ('\0' != buf[offs]) {
- /* Mark starting position if eqn is set. */
- start = NULL;
- if ('\0' != (delim = roff_eqndelim(mdoc->roff)))
- if (NULL != (start = strchr(buf + offs, delim)))
- *start++ = '\0';
-
- /* Parse text as normal. */
- if ( ! mdoc_ptext(mdoc, line, buf, offs))
- return(0);
-
- /* Continue only if an equation exists. */
- if (NULL == start)
- break;
-
- /* Read past the end of the equation. */
- offs += start - (buf + offs);
- assert(start == &buf[offs]);
- if (NULL != (end = strchr(buf + offs, delim))) {
- *end++ = '\0';
- while (' ' == *end)
- end++;
- }
-
- /* Parse the equation itself. */
- roff_openeqn(mdoc->roff, NULL, line, offs, buf);
-
- /* Process a finished equation? */
- if (roff_closeeqn(mdoc->roff))
- if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff)))
- return(0);
- offs += (end - (buf + offs));
- }
-
- return(1);
-}
-#endif
-
/*
* Parse free-form text, that is, a line that does not begin with the
* control character.
@@ -689,7 +604,8 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
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));
+ mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
+ return(1);
}
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
@@ -698,7 +614,8 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
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));
+ mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
+ return(1);
}
/*
@@ -746,7 +663,7 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, (int)(ws-buf), NULL);
- if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) {
+ if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
line, (int)(c - buf), NULL);
@@ -755,18 +672,15 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
* blank lines aren't allowed, but enough manuals assume this
* behaviour that we want to work around it.
*/
- if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL))
- return(0);
-
+ mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL);
mdoc->next = MDOC_NEXT_SIBLING;
-
- return(mdoc_valid_post(mdoc));
+ mdoc_valid_post(mdoc);
+ return(1);
}
- if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs))
- return(0);
+ mdoc_word_alloc(mdoc, line, offs, buf+offs);
- if (MDOC_LITERAL & mdoc->flags)
+ if (mdoc->flags & MDOC_LITERAL)
return(1);
/*
@@ -779,7 +693,6 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
mdoc->last->flags |= MDOC_EOS;
-
return(1);
}
@@ -790,46 +703,47 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
static int
mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
{
+ struct mdoc_node *n;
+ const char *cp;
enum mdoct tok;
int i, sv;
char mac[5];
- struct mdoc_node *n;
-
- /* Empty post-control lines are ignored. */
-
- if ('"' == buf[offs]) {
- 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.
+ * Stop when a space, tab, escape, or eoln is encountered.
*/
i = 0;
- while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] &&
- '\t' != buf[offs])
+ while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
mac[i++] = buf[offs++];
mac[i] = '\0';
tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
- if (MDOC_MAX == tok) {
+ if (tok == MDOC_MAX) {
mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
ln, sv, buf + sv - 1);
return(1);
}
- /* Disregard the first trailing tab, if applicable. */
+ /* Skip a leading escape sequence or tab. */
- if ('\t' == buf[offs])
+ switch (buf[offs]) {
+ case '\\':
+ cp = buf + offs + 1;
+ mandoc_escape(&cp, NULL, NULL);
+ offs = cp - buf;
+ break;
+ case '\t':
offs++;
+ break;
+ default:
+ break;
+ }
/* Jump to the next non-whitespace word. */
@@ -850,8 +764,10 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
* into macro processing.
*/
- if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok)
- return(mdoc_macro(mdoc, tok, ln, sv, &offs, buf));
+ if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
+ mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
+ return(1);
+ }
n = mdoc->last;
assert(mdoc->last);
@@ -864,7 +780,8 @@ 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) {
mdoc->flags |= MDOC_FREECOL;
- return(mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf));
+ mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
+ return(1);
}
/*
@@ -878,13 +795,13 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
MDOC_Bl == n->parent->tok &&
LIST_column == n->parent->norm->Bl.type) {
mdoc->flags |= MDOC_FREECOL;
- return(mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf));
+ mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
+ return(1);
}
/* Normal processing of a macro. */
- if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
- return(0);
+ mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
diff --git a/mdoc_argv.c b/mdoc_argv.c
index e48516cd5f09..3e7fabd2ae1c 100644
--- a/mdoc_argv.c
+++ b/mdoc_argv.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_argv.c,v 1.95 2014/07/06 19:09:00 schwarze Exp $ */
+/* $OpenBSD$ */
/*
* Copyright (c) 2008, 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,9 +15,7 @@
* 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>
@@ -56,9 +54,9 @@ static void argn_free(struct mdoc_arg *, 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 void argv_multi(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
-static int argv_single(struct mdoc *, int,
+static void argv_single(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
static const enum argvflag argvflags[MDOC_ARG_MAX] = {
@@ -272,100 +270,105 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
/*
- * Parse an argument from line text. This comes in the form of -key
- * [value0...], which may either have a single mandatory value, at least
- * one mandatory value, an optional single value, or no value.
+ * Parse flags and their arguments from the input line.
+ * These come in the form -flag [argument ...].
+ * Some flags take no argument, some one, some multiple.
*/
-enum margverr
+void
mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
- struct mdoc_arg **v, int *pos, char *buf)
+ struct mdoc_arg **reta, int *pos, char *buf)
{
- char *p, sv;
- struct mdoc_argv tmp;
- struct mdoc_arg *arg;
- const enum mdocargt *ap;
+ struct mdoc_argv tmpv;
+ struct mdoc_argv **retv;
+ const enum mdocargt *argtable;
+ char *argname;
+ int ipos, retc;
+ char savechar;
- if ('\0' == buf[*pos])
- return(ARGV_EOLN);
- else if (NULL == (ap = mdocargs[tok].argvs))
- return(ARGV_WORD);
- else if ('-' != buf[*pos])
- return(ARGV_WORD);
+ *reta = NULL;
- /* Seek to the first unescaped space. */
+ /* Which flags does this macro support? */
- p = &buf[++(*pos)];
+ argtable = mdocargs[tok].argvs;
+ if (argtable == NULL)
+ return;
- assert(*pos > 0);
+ /* Loop over the flags on the input line. */
- for ( ; buf[*pos] ; (*pos)++)
- if (' ' == buf[*pos] && '\\' != buf[*pos - 1])
- break;
+ ipos = *pos;
+ while (buf[ipos] == '-') {
- /*
- * 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).
- */
+ /* Seek to the first unescaped space. */
- if ('\0' != (sv = buf[*pos]))
- buf[(*pos)++] = '\0';
+ for (argname = buf + ++ipos; buf[ipos] != '\0'; ipos++)
+ if (buf[ipos] == ' ' && buf[ipos - 1] != '\\')
+ break;
- /*
- * Now look up the word as a flag. Use temporary storage that
- * we'll copy into the node's flags, if necessary.
- */
+ /*
+ * We want to nil-terminate the word to look it up.
+ * 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 ((savechar = buf[ipos]) != '\0')
+ buf[ipos++] = '\0';
- memset(&tmp, 0, sizeof(struct mdoc_argv));
+ /*
+ * Now look up the word as a flag. Use temporary
+ * storage that we'll copy into the node's flags.
+ */
+
+ while ((tmpv.arg = *argtable++) != MDOC_ARG_MAX)
+ if ( ! strcmp(argname, mdoc_argnames[tmpv.arg]))
+ break;
- tmp.line = line;
- tmp.pos = *pos;
- tmp.arg = MDOC_ARG_MAX;
+ /* If it isn't a flag, restore the saved byte. */
- while (MDOC_ARG_MAX != (tmp.arg = *ap++))
- if (0 == strcmp(p, mdoc_argnames[tmp.arg]))
+ if (tmpv.arg == MDOC_ARG_MAX) {
+ if (savechar != '\0')
+ buf[ipos - 1] = savechar;
break;
+ }
- if (MDOC_ARG_MAX == tmp.arg) {
- /*
- * The flag was not found.
- * Restore saved zeroed byte and return as a word.
- */
- if (sv)
- buf[*pos - 1] = sv;
- return(ARGV_WORD);
- }
+ /* Read to the next word (the first argument). */
- /* Read to the next word (the argument). */
-
- while (buf[*pos] && ' ' == buf[*pos])
- (*pos)++;
-
- switch (argvflags[tmp.arg]) {
- case ARGV_SINGLE:
- if ( ! argv_single(mdoc, line, &tmp, pos, buf))
- return(ARGV_ERROR);
- break;
- case ARGV_MULTI:
- if ( ! argv_multi(mdoc, line, &tmp, pos, buf))
- return(ARGV_ERROR);
- break;
- case ARGV_NONE:
- break;
- }
+ while (buf[ipos] == ' ')
+ ipos++;
- if (NULL == (arg = *v))
- arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
+ /* Parse the arguments of the flag. */
- arg->argc++;
- arg->argv = mandoc_reallocarray(arg->argv,
- arg->argc, sizeof(struct mdoc_argv));
+ tmpv.line = line;
+ tmpv.pos = ipos;
+ tmpv.sz = 0;
+ tmpv.value = NULL;
- memcpy(&arg->argv[(int)arg->argc - 1], &tmp,
- sizeof(struct mdoc_argv));
+ switch (argvflags[tmpv.arg]) {
+ case ARGV_SINGLE:
+ argv_single(mdoc, line, &tmpv, &ipos, buf);
+ break;
+ case ARGV_MULTI:
+ argv_multi(mdoc, line, &tmpv, &ipos, buf);
+ break;
+ case ARGV_NONE:
+ break;
+ }
+
+ /* Append to the return values. */
+
+ if (*reta == NULL)
+ *reta = mandoc_calloc(1, sizeof(**reta));
- return(ARGV_ARG);
+ retc = ++(*reta)->argc;
+ retv = &(*reta)->argv;
+ *retv = mandoc_reallocarray(*retv, retc, sizeof(**retv));
+ memcpy(*retv + retc - 1, &tmpv, sizeof(**retv));
+
+ /* Prepare for parsing the next flag. */
+
+ *pos = ipos;
+ argtable = mdocargs[tok].argvs;
+ }
}
void
@@ -409,22 +412,17 @@ argn_free(struct mdoc_arg *p, int iarg)
}
enum margserr
-mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v)
-{
-
- return(args(mdoc, line, pos, buf, ARGSFL_NONE, v));
-}
-
-enum margserr
mdoc_args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum mdoct tok, char **v)
{
- enum argsflag fl;
struct mdoc_node *n;
+ char *v_local;
+ enum argsflag fl;
- fl = mdocargs[tok].flags;
-
- if (MDOC_It != tok)
+ if (v == NULL)
+ v = &v_local;
+ fl = tok == MDOC_MAX ? ARGSFL_NONE : mdocargs[tok].flags;
+ if (tok != MDOC_It)
return(args(mdoc, line, pos, buf, fl, v));
/*
@@ -654,7 +652,7 @@ args_checkpunct(const char *buf, int i)
return('\0' == buf[i]);
}
-static int
+static void
argv_multi(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
@@ -662,25 +660,21 @@ argv_multi(struct mdoc *mdoc, int line,
char *p;
for (v->sz = 0; ; v->sz++) {
- if ('-' == buf[*pos])
+ if (buf[*pos] == '-')
break;
ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
- if (ARGS_ERROR == ac)
- return(0);
- else if (ARGS_EOLN == ac)
+ if (ac == ARGS_EOLN)
break;
- if (0 == v->sz % MULTI_STEP)
+ if (v->sz % MULTI_STEP == 0)
v->value = mandoc_reallocarray(v->value,
v->sz + MULTI_STEP, sizeof(char *));
v->value[(int)v->sz] = mandoc_strdup(p);
}
-
- return(1);
}
-static int
+static void
argv_single(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
@@ -688,14 +682,10 @@ argv_single(struct mdoc *mdoc, int line,
char *p;
ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- return(1);
+ if (ac == ARGS_EOLN)
+ return;
v->sz = 1;
v->value = mandoc_malloc(sizeof(char *));
v->value[0] = mandoc_strdup(p);
-
- return(1);
}
diff --git a/mdoc_hash.c b/mdoc_hash.c
index db30ee602a8b..5e34fe8f58be 100644
--- a/mdoc_hash.c
+++ b/mdoc_hash.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_hash.c,v 1.20 2014/04/20 16:46:05 schwarze Exp $ */
+/* $Id: mdoc_hash.c,v 1.21 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,7 @@
* 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>
diff --git a/mdoc_html.c b/mdoc_html.c
index 9fe241e739d6..0cd3cf01744d 100644
--- a/mdoc_html.c
+++ b/mdoc_html.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_html.c,v 1.195 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.213 2014/11/27 22:27:56 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,9 +15,7 @@
* 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>
@@ -58,7 +56,6 @@ static void synopsis_pre(struct html *,
const struct mdoc_node *);
static void a2width(const char *, struct roffsu *);
-static void a2offs(const char *, struct roffsu *);
static void mdoc_root_post(MDOC_ARGS);
static int mdoc_root_pre(MDOC_ARGS);
@@ -101,6 +98,7 @@ static int mdoc_mt_pre(MDOC_ARGS);
static int mdoc_ms_pre(MDOC_ARGS);
static int mdoc_nd_pre(MDOC_ARGS);
static int mdoc_nm_pre(MDOC_ARGS);
+static int mdoc_no_pre(MDOC_ARGS);
static int mdoc_ns_pre(MDOC_ARGS);
static int mdoc_pa_pre(MDOC_ARGS);
static void mdoc_pf_post(MDOC_ARGS);
@@ -185,7 +183,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
{mdoc_xx_pre, NULL}, /* Bsx */
{mdoc_bx_pre, NULL}, /* Bx */
- {NULL, NULL}, /* Db */
+ {mdoc_skip_pre, NULL}, /* Db */
{NULL, NULL}, /* Dc */
{mdoc_quote_pre, mdoc_quote_post}, /* Do */
{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
@@ -195,7 +193,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* Eo */
{mdoc_xx_pre, NULL}, /* Fx */
{mdoc_ms_pre, NULL}, /* Ms */
- {mdoc_igndelim_pre, NULL}, /* No */
+ {mdoc_no_pre, NULL}, /* No */
{mdoc_ns_pre, NULL}, /* Ns */
{mdoc_xx_pre, NULL}, /* Nx */
{mdoc_xx_pre, NULL}, /* Ox */
@@ -283,7 +281,7 @@ a2width(const char *p, struct roffsu *su)
{
if ( ! a2roffsu(p, su, SCALE_MAX)) {
- su->unit = SCALE_BU;
+ su->unit = SCALE_EN;
su->scale = html_strlen(p);
}
}
@@ -316,11 +314,11 @@ synopsis_pre(struct html *h, const struct mdoc_node *n)
case MDOC_In:
/* FALLTHROUGH */
case MDOC_Vt:
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
break;
case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
break;
}
/* FALLTHROUGH */
@@ -330,27 +328,6 @@ synopsis_pre(struct html *h, const struct mdoc_node *n)
}
}
-/*
- * Calculate the scaling unit passed in an `-offset' argument. This
- * uses either a native scaling unit (e.g., 1i, 2m), one of a set of
- * predefined strings (indent, etc.), or the string length of the value.
- */
-static void
-a2offs(const char *p, struct roffsu *su)
-{
-
- /* FIXME: "right"? */
-
- if (0 == strcmp(p, "left"))
- SCALE_HS_INIT(su, 0);
- else if (0 == strcmp(p, "indent"))
- SCALE_HS_INIT(su, INDENT);
- else if (0 == strcmp(p, "indent-two"))
- SCALE_HS_INIT(su, INDENT * 2);
- else if ( ! a2roffsu(p, su, SCALE_MAX))
- SCALE_HS_INIT(su, html_strlen(p));
-}
-
static void
print_mdoc(MDOC_ARGS)
{
@@ -446,13 +423,12 @@ print_mdoc_node(MDOC_ARGS)
* the "meta" table state. This will be reopened on the
* next table element.
*/
- if (h->tblt) {
+ if (h->tblt != NULL) {
print_tblclose(h);
t = h->tags.head;
}
-
- assert(NULL == h->tblt);
- if (mdocs[n->tok].pre && ENDBODY_NOT == n->end)
+ assert(h->tblt == NULL);
+ if (mdocs[n->tok].pre && (n->end == ENDBODY_NOT || n->child))
child = (*mdocs[n->tok].pre)(meta, n, h);
break;
}
@@ -477,8 +453,13 @@ print_mdoc_node(MDOC_ARGS)
case MDOC_EQN:
break;
default:
- if (mdocs[n->tok].post && ENDBODY_NOT == n->end)
- (*mdocs[n->tok].post)(meta, n, h);
+ if ( ! mdocs[n->tok].post || n->flags & MDOC_ENDED)
+ break;
+ (*mdocs[n->tok].post)(meta, n, h);
+ if (n->end != ENDBODY_NOT)
+ n->pending->flags |= MDOC_ENDED;
+ if (n->end == ENDBODY_NOSPACE)
+ h->flags |= HTML_NOSPACE;
break;
}
}
@@ -486,29 +467,23 @@ print_mdoc_node(MDOC_ARGS)
static void
mdoc_root_post(MDOC_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
- PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
- PAIR_CLASS_INIT(&tag[1], "foot");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
print_otag(h, TAG_TBODY, 0, NULL);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "foot-date");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot-date");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, meta->date);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "foot-os");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "foot-os");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, meta->os);
print_tagq(h, t);
}
@@ -516,7 +491,7 @@ mdoc_root_post(MDOC_ARGS)
static int
mdoc_root_pre(MDOC_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
char *volume, *title;
@@ -532,33 +507,25 @@ mdoc_root_pre(MDOC_ARGS)
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
- PAIR_SUMMARY_INIT(&tag[0], "Document Header");
- PAIR_CLASS_INIT(&tag[1], "head");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
print_otag(h, TAG_TBODY, 0, NULL);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "head-ltitle");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head-ltitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-vol");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "head-vol");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, volume);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-rtitle");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "head-rtitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_tagq(h, t);
@@ -572,12 +539,18 @@ mdoc_sh_pre(MDOC_ARGS)
{
struct htmlpair tag;
- if (MDOC_BLOCK == n->type) {
+ switch (n->type) {
+ case MDOC_BLOCK:
PAIR_CLASS_INIT(&tag, "section");
print_otag(h, TAG_DIV, 1, &tag);
return(1);
- } else if (MDOC_BODY == n->type)
+ case MDOC_BODY:
+ if (n->sec == SEC_AUTHORS)
+ h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
return(1);
+ default:
+ break;
+ }
bufinit(h);
bufcat(h, "x");
@@ -642,9 +615,10 @@ mdoc_fl_pre(MDOC_ARGS)
print_text(h, "\\-");
- if (n->child)
- h->flags |= HTML_NOSPACE;
- else if (n->next && n->next->line == n->line)
+ if ( ! (n->nchild == 0 &&
+ (n->next == NULL ||
+ n->next->type == MDOC_TEXT ||
+ n->next->flags & MDOC_LINE)))
h->flags |= HTML_NOSPACE;
return(1);
@@ -1003,7 +977,7 @@ mdoc_bl_pre(MDOC_ARGS)
/* Set the block's left-hand margin. */
if (n->norm->Bl.offs) {
- a2offs(n->norm->Bl.offs, &su);
+ a2width(n->norm->Bl.offs, &su);
bufcat_su(h, "margin-left", &su);
}
@@ -1165,13 +1139,21 @@ mdoc_bd_pre(MDOC_ARGS)
break;
}
if ( ! comp)
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
return(1);
}
- SCALE_HS_INIT(&su, 0);
- if (n->norm->Bd.offs)
- a2offs(n->norm->Bd.offs, &su);
+ /* Handle the -offset argument. */
+
+ if (n->norm->Bd.offs == NULL ||
+ ! strcmp(n->norm->Bd.offs, "left"))
+ SCALE_HS_INIT(&su, 0);
+ else if ( ! strcmp(n->norm->Bd.offs, "indent"))
+ SCALE_HS_INIT(&su, INDENT);
+ else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
+ SCALE_HS_INIT(&su, INDENT * 2);
+ else
+ a2width(n->norm->Bd.offs, &su);
bufinit(h);
bufcat_su(h, "margin-left", &su);
@@ -1259,7 +1241,25 @@ mdoc_an_pre(MDOC_ARGS)
{
struct htmlpair tag;
- /* TODO: -split and -nosplit (see termp_an_pre()). */
+ if (n->norm->An.auth == AUTH_split) {
+ h->flags &= ~HTML_NOSPLIT;
+ h->flags |= HTML_SPLIT;
+ return(0);
+ }
+ if (n->norm->An.auth == AUTH_nosplit) {
+ h->flags &= ~HTML_SPLIT;
+ h->flags |= HTML_NOSPLIT;
+ return(0);
+ }
+
+ if (n->child == NULL)
+ return(0);
+
+ if (h->flags & HTML_SPLIT)
+ print_otag(h, TAG_BR, 0, NULL);
+
+ if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
+ h->flags |= HTML_SPLIT;
PAIR_CLASS_INIT(&tag, "author");
print_otag(h, TAG_SPAN, 1, &tag);
@@ -1553,7 +1553,7 @@ static int
mdoc_pp_pre(MDOC_ARGS)
{
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
return(0);
}
@@ -1881,7 +1881,7 @@ mdoc_rs_pre(MDOC_ARGS)
return(1);
if (n->prev && SEC_SEE_ALSO == n->sec)
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
PAIR_CLASS_INIT(&tag, "ref");
print_otag(h, TAG_SPAN, 1, &tag);
@@ -1889,6 +1889,16 @@ mdoc_rs_pre(MDOC_ARGS)
}
static int
+mdoc_no_pre(MDOC_ARGS)
+{
+ struct htmlpair tag;
+
+ PAIR_CLASS_INIT(&tag, "none");
+ print_otag(h, TAG_CODE, 1, &tag);
+ return(1);
+}
+
+static int
mdoc_li_pre(MDOC_ARGS)
{
struct htmlpair tag;
@@ -2069,7 +2079,8 @@ mdoc_quote_pre(MDOC_ARGS)
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- print_text(h, "\\(la");
+ print_text(h, n->parent->prev != NULL &&
+ n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
break;
case MDOC_Bro:
/* FALLTHROUGH */
@@ -2135,17 +2146,19 @@ static void
mdoc_quote_post(MDOC_ARGS)
{
- if (MDOC_BODY != n->type)
+ if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
- if (MDOC_En != n->tok)
+ if ( ! (n->tok == MDOC_En ||
+ (n->tok == MDOC_Eo && n->end == ENDBODY_SPACE)))
h->flags |= HTML_NOSPACE;
switch (n->tok) {
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- print_text(h, "\\(ra");
+ print_text(h, n->parent->prev != NULL &&
+ n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
break;
case MDOC_Bro:
/* FALLTHROUGH */
diff --git a/mdoc_macro.c b/mdoc_macro.c
index 0f5b557f4e78..b501d4d62946 100644
--- a/mdoc_macro.c
+++ b/mdoc_macro.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_macro.c,v 1.139 2014/08/01 17:27:44 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.154 2014/11/29 04:31:35 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 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
@@ -15,9 +15,9 @@
* 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 <assert.h>
#include <ctype.h>
@@ -40,32 +40,31 @@ 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 phrase_ta(MACRO_PROT_ARGS);
-
-static int dword(struct mdoc *, int, int, const char *,
+static void blk_full(MACRO_PROT_ARGS);
+static void blk_exp_close(MACRO_PROT_ARGS);
+static void blk_part_exp(MACRO_PROT_ARGS);
+static void blk_part_imp(MACRO_PROT_ARGS);
+static void ctx_synopsis(MACRO_PROT_ARGS);
+static void in_line_eoln(MACRO_PROT_ARGS);
+static void in_line_argn(MACRO_PROT_ARGS);
+static void in_line(MACRO_PROT_ARGS);
+static void phrase_ta(MACRO_PROT_ARGS);
+
+static void dword(struct mdoc *, int, int, const char *,
enum mdelim, int);
-static int append_delims(struct mdoc *,
- int, int *, char *);
+static void append_delims(struct mdoc *, int, int *, char *);
static enum mdoct lookup(enum mdoct, const char *);
-static enum mdoct lookup_raw(const char *);
+static int macro_or_word(MACRO_PROT_ARGS, int);
static int make_pending(struct mdoc_node *, enum mdoct,
struct mdoc *, int, int);
-static int phrase(struct mdoc *, int, int, char *);
+static int parse_rest(struct mdoc *, enum mdoct,
+ 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 *,
- const struct mdoc_node *);
-static int rew_sub(enum mdoc_type, struct mdoc *,
+static void rew_elem(struct mdoc *, enum mdoct);
+static void rew_last(struct mdoc *, const struct mdoc_node *);
+static void rew_sub(enum mdoc_type, struct mdoc *,
enum mdoct, int, int);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
@@ -147,8 +146,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
- { in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
- MDOC_IGNDELIM | MDOC_JOIN }, /* No */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
@@ -172,7 +170,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
MDOC_EXPLICIT | MDOC_JOIN }, /* So */
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */
- { in_line_eoln, 0 }, /* Sm */
+ { in_line_argn, 0 }, /* Sm */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
@@ -210,7 +208,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line_eoln, 0 }, /* sp */
{ in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
- { in_line_eoln, 0 }, /* ll */
+ { in_line_eoln, MDOC_PROLOGUE }, /* ll */
};
const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
@@ -221,63 +219,51 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
* closing out open [implicit] scopes. Obviously, open explicit scopes
* are errors.
*/
-int
+void
mdoc_macroend(struct mdoc *mdoc)
{
struct mdoc_node *n;
/* Scan for open explicit scopes. */
- n = MDOC_VALID & mdoc->last->flags ?
+ n = mdoc->last->flags & MDOC_VALID ?
mdoc->last->parent : mdoc->last;
for ( ; n; n = n->parent)
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags)
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
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));
+ rew_last(mdoc, mdoc->first);
}
/*
- * Look up a macro from within a subsequent context.
+ * Look up the macro at *p called by "from",
+ * or as a line macro if from == MDOC_MAX.
*/
static enum mdoct
lookup(enum mdoct from, const char *p)
{
-
- if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
- return(MDOC_MAX);
- return(lookup_raw(p));
-}
-
-/*
- * Lookup a macro following the initial line macro.
- */
-static enum mdoct
-lookup_raw(const char *p)
-{
enum mdoct res;
- if (MDOC_MAX == (res = mdoc_hash_find(p)))
- return(MDOC_MAX);
- if (MDOC_CALLABLE & mdoc_macros[res].flags)
- return(res);
+ if (from == MDOC_MAX || mdoc_macros[from].flags & MDOC_PARSED) {
+ res = mdoc_hash_find(p);
+ if (res != MDOC_MAX && mdoc_macros[res].flags & MDOC_CALLABLE)
+ return(res);
+ }
return(MDOC_MAX);
}
-static int
+static void
rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
{
struct mdoc_node *n, *np;
assert(to);
mdoc->next = MDOC_NEXT_SIBLING;
-
-
while (mdoc->last != to) {
/*
* Save the parent here, because we may delete the
@@ -286,15 +272,13 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
* out to be lost.
*/
np = mdoc->last->parent;
- if ( ! mdoc_valid_post(mdoc))
- return(0);
+ mdoc_valid_post(mdoc);
n = mdoc->last;
mdoc->last = np;
assert(mdoc->last);
mdoc->last->last = n;
}
-
- return(mdoc_valid_post(mdoc));
+ mdoc_valid_post(mdoc);
}
/*
@@ -438,9 +422,11 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
* Default block rewinding rules.
* In particular, always skip block end markers,
* and let all blocks rewind Nm children.
+ * Do not warn again when closing a block,
+ * since closing the body already warned.
*/
if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok ||
- (MDOC_BLOCK == p->type &&
+ MDOC_BLOCK == type || (MDOC_BLOCK == p->type &&
! (MDOC_EXPLICIT & mdoc_macros[tok].flags)))
return(REWIND_MORE);
@@ -454,7 +440,7 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
REWIND_FORCE : REWIND_LATER);
}
-static int
+static void
rew_elem(struct mdoc *mdoc, enum mdoct tok)
{
struct mdoc_node *n;
@@ -464,8 +450,7 @@ rew_elem(struct mdoc *mdoc, enum mdoct tok)
n = n->parent;
assert(MDOC_ELEM == n->type);
assert(tok == n->tok);
-
- return(rew_last(mdoc, n));
+ rew_last(mdoc, n);
}
/*
@@ -544,7 +529,7 @@ make_pending(struct mdoc_node *broken, enum mdoct tok,
return(0);
}
-static int
+static void
rew_sub(enum mdoc_type t, struct mdoc *mdoc,
enum mdoct tok, int line, int ppos)
{
@@ -554,11 +539,11 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc,
while (n) {
switch (rew_dohalt(tok, t, n)) {
case REWIND_NONE:
- return(1);
+ return;
case REWIND_THIS:
n->lastline = line -
- (MDOC_NEWLINE & mdoc->flags &&
- ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
+ (mdoc->flags & MDOC_NEWLINE &&
+ ! (mdoc_macros[tok].flags & MDOC_EXPLICIT));
break;
case REWIND_FORCE:
mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse,
@@ -568,105 +553,87 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc,
/* FALLTHROUGH */
case REWIND_MORE:
n->lastline = line -
- (MDOC_NEWLINE & mdoc->flags ? 1 : 0);
+ (mdoc->flags & MDOC_NEWLINE ? 1 : 0);
n = n->parent;
continue;
case REWIND_LATER:
if (make_pending(n, tok, mdoc, line, ppos) ||
- MDOC_BLOCK != t)
- return(1);
+ t != MDOC_BLOCK)
+ return;
/* FALLTHROUGH */
case REWIND_ERROR:
mandoc_msg(MANDOCERR_BLK_NOTOPEN,
mdoc->parse, line, ppos,
mdoc_macronames[tok]);
- return(1);
+ return;
}
break;
}
-
assert(n);
- if ( ! rew_last(mdoc, n))
- return(0);
+ rew_last(mdoc, n);
/*
* The current block extends an enclosing block.
* Now that the current block ends, close the enclosing block, too.
*/
- while (NULL != (n = n->pending)) {
- if ( ! rew_last(mdoc, n))
- return(0);
- if (MDOC_HEAD == n->type &&
- ! mdoc_body_alloc(mdoc, n->line, n->pos, n->tok))
- return(0);
+ while ((n = n->pending) != NULL) {
+ rew_last(mdoc, n);
+ if (n->type == MDOC_HEAD)
+ mdoc_body_alloc(mdoc, n->line, n->pos, n->tok);
}
-
- return(1);
}
/*
* Allocate a word and check whether it's punctuation or not.
* Punctuation consists of those tokens found in mdoc_isdelim().
*/
-static int
+static void
dword(struct mdoc *mdoc, int line, int col, const char *p,
enum mdelim d, int may_append)
{
- if (DELIM_MAX == d)
+ if (d == DELIM_MAX)
d = mdoc_isdelim(p);
if (may_append &&
- ! ((MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF) & mdoc->flags) &&
- DELIM_NONE == d && MDOC_TEXT == mdoc->last->type &&
- DELIM_NONE == mdoc_isdelim(mdoc->last->string)) {
+ ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) &&
+ d == DELIM_NONE && mdoc->last->type == MDOC_TEXT &&
+ mdoc_isdelim(mdoc->last->string) == DELIM_NONE) {
mdoc_word_append(mdoc, p);
- return(1);
+ return;
}
- if ( ! mdoc_word_alloc(mdoc, line, col, p))
- return(0);
-
- if (DELIM_OPEN == d)
- mdoc->last->flags |= MDOC_DELIMO;
+ mdoc_word_alloc(mdoc, line, col, p);
/*
- * Closing delimiters only suppress the preceding space
- * when they follow something, not when they start a new
- * block or element, and not when they follow `No'.
- *
- * XXX Explicitly special-casing MDOC_No here feels
- * like a layering violation. Find a better way
- * and solve this in the code related to `No'!
+ * If the word consists of a bare delimiter,
+ * flag the new node accordingly,
+ * unless doing so was vetoed by the invoking macro.
+ * Always clear the veto, it is only valid for one word.
*/
- else if (DELIM_CLOSE == d && mdoc->last->prev &&
- mdoc->last->prev->tok != MDOC_No &&
+ if (d == DELIM_OPEN)
+ mdoc->last->flags |= MDOC_DELIMO;
+ else if (d == DELIM_CLOSE &&
+ ! (mdoc->flags & MDOC_NODELIMC) &&
mdoc->last->parent->tok != MDOC_Fd)
mdoc->last->flags |= MDOC_DELIMC;
-
- return(1);
+ mdoc->flags &= ~MDOC_NODELIMC;
}
-static int
+static void
append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
{
- int la;
- enum margserr ac;
char *p;
+ int la;
- if ('\0' == buf[*pos])
- return(1);
+ if (buf[*pos] == '\0')
+ return;
for (;;) {
la = *pos;
- ac = mdoc_zargs(mdoc, line, pos, buf, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- else if (ARGS_EOLN == ac)
+ if (mdoc_args(mdoc, line, pos, buf, MDOC_MAX, &p) == ARGS_EOLN)
break;
-
dword(mdoc, line, la, p, DELIM_MAX, 1);
/*
@@ -680,20 +647,54 @@ 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)))
mdoc->last->flags |= MDOC_EOS;
}
+}
- return(1);
+/*
+ * Parse one word.
+ * If it is a macro, call it and return 1.
+ * Otherwise, allocate it and return 0.
+ */
+static int
+macro_or_word(MACRO_PROT_ARGS, int parsed)
+{
+ char *p;
+ enum mdoct ntok;
+
+ p = buf + ppos;
+ ntok = MDOC_MAX;
+ if (mdoc->flags & MDOC_PHRASELIT)
+ /* nothing */;
+ else if (*p == '"')
+ p++;
+ else if (parsed)
+ ntok = lookup(tok, p);
+
+ if (ntok == MDOC_MAX) {
+ dword(mdoc, line, ppos, p, DELIM_MAX, tok == MDOC_MAX ||
+ mdoc_macros[tok].flags & MDOC_JOIN);
+ return(0);
+ } else {
+ if (mdoc_macros[tok].fp == in_line_eoln)
+ rew_elem(mdoc, tok);
+ mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
+ if (tok == MDOC_MAX)
+ append_delims(mdoc, line, pos, buf);
+ return(1);
+ }
}
/*
* Close out block partial/full explicit.
*/
-static int
+static void
blk_exp_close(MACRO_PROT_ARGS)
{
struct mdoc_node *body; /* Our own body. */
+ struct mdoc_node *endbody; /* Our own end marker. */
struct mdoc_node *later; /* A sub-block starting later. */
struct mdoc_node *n; /* For searching backwards. */
@@ -710,6 +711,7 @@ blk_exp_close(MACRO_PROT_ARGS)
break;
case MDOC_Ek:
mdoc->flags &= ~MDOC_KEEP;
+ /* FALLTHROUGH */
default:
maxargs = 0;
break;
@@ -719,20 +721,22 @@ blk_exp_close(MACRO_PROT_ARGS)
* Search backwards for beginnings of blocks,
* both of our own and of pending sub-blocks.
*/
+
atok = rew_alt(tok);
- body = later = NULL;
+ body = endbody = later = NULL;
for (n = mdoc->last; n; n = n->parent) {
- if (MDOC_VALID & n->flags)
+ if (n->flags & MDOC_VALID)
continue;
/* Remember the start of our own body. */
- if (MDOC_BODY == n->type && atok == n->tok) {
- if (ENDBODY_NOT == n->end)
+
+ if (n->type == MDOC_BODY && atok == n->tok) {
+ if (n->end == ENDBODY_NOT)
body = n;
continue;
}
- if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok)
+ if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm)
continue;
if (atok == n->tok) {
assert(body);
@@ -742,7 +746,8 @@ blk_exp_close(MACRO_PROT_ARGS)
* When there is no pending sub block,
* just proceed to closing out.
*/
- if (NULL == later)
+
+ if (later == NULL)
break;
/*
@@ -750,15 +755,28 @@ blk_exp_close(MACRO_PROT_ARGS)
* postpone closing out the current block
* until the rew_sub() closing out the sub-block.
*/
+
make_pending(later, tok, mdoc, line, ppos);
/*
* Mark the place where the formatting - but not
* the scope - of the current block ends.
*/
- if ( ! mdoc_endbody_alloc(mdoc, line, ppos,
- atok, body, ENDBODY_SPACE))
- return(0);
+
+ mdoc_endbody_alloc(mdoc, line, ppos,
+ atok, body, ENDBODY_SPACE);
+
+ /*
+ * If a block closing macro taking arguments
+ * breaks another block, put the arguments
+ * into the end marker and remeber the
+ * end marker in order to close it out.
+ */
+
+ if (maxargs) {
+ endbody = mdoc->last;
+ mdoc->next = MDOC_NEXT_CHILD;
+ }
break;
}
@@ -767,84 +785,87 @@ blk_exp_close(MACRO_PROT_ARGS)
* open explicit block, or, in case there are only
* implicit ones, the first open implicit block.
*/
+
if (later &&
- MDOC_EXPLICIT & mdoc_macros[later->tok].flags)
+ mdoc_macros[later->tok].flags & MDOC_EXPLICIT)
continue;
- if (MDOC_It != n->tok)
+ if (n->tok != MDOC_It)
later = n;
}
+ rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
- if ( ! (MDOC_PARSED & mdoc_macros[tok].flags)) {
- if ('\0' != buf[*pos])
+ if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
+ if (buf[*pos] != '\0')
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));
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ return;
}
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
-
- if (NULL == later && maxargs > 0)
- if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok)))
- return(0);
+ if (maxargs && endbody == NULL) {
+ if (n == NULL) {
+ /*
+ * Stray .Ec without previous .Eo:
+ * Break the output line, ignore any arguments.
+ */
+ mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
+ rew_elem(mdoc, MDOC_br);
+ } else
+ mdoc_tail_alloc(mdoc, line, ppos, atok);
+ }
- for (flushed = j = 0; ; j++) {
+ flushed = n == NULL;
+ for (j = 0; ; j++) {
lastarg = *pos;
if (j == maxargs && ! flushed) {
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
+ if (endbody == NULL)
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ else
+ rew_last(mdoc, endbody);
flushed = 1;
}
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_PUNCT == ac)
- break;
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
+ if (ntok == MDOC_MAX) {
+ dword(mdoc, line, lastarg, p, DELIM_MAX,
+ MDOC_JOIN & mdoc_macros[tok].flags);
continue;
}
if ( ! flushed) {
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
+ if (endbody == NULL)
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ else
+ rew_last(mdoc, endbody);
flushed = 1;
}
-
mdoc->flags &= ~MDOC_NEWLINE;
-
- if ( ! mdoc_macro(mdoc, ntok, line, lastarg, pos, buf))
- return(0);
+ mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
break;
}
- if ( ! flushed && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
-
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if ( ! flushed) {
+ if (endbody == NULL)
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ else
+ rew_last(mdoc, endbody);
+ }
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-static int
+static void
in_line(MACRO_PROT_ARGS)
{
- int la, scope, cnt, nc, nl;
- enum margverr av;
+ int la, scope, cnt, firstarg, mayopen, nc, nl;
enum mdoct ntok;
enum margserr ac;
enum mdelim d;
@@ -877,35 +898,42 @@ in_line(MACRO_PROT_ARGS)
break;
}
- for (arg = NULL;; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ d = DELIM_NONE;
+ firstarg = 1;
+ mayopen = 1;
for (cnt = scope = 0;; ) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
+ /*
+ * At the end of a macro line,
+ * opening delimiters do not suppress spacing.
+ */
+
+ if (ac == ARGS_EOLN) {
+ if (d == DELIM_OPEN)
+ mdoc->last->flags &= ~MDOC_DELIMO;
break;
- if (ARGS_PUNCT == ac)
+ }
+
+ /*
+ * The rest of the macro line is only punctuation,
+ * to be handled by append_delims().
+ * If there were no other arguments,
+ * do not allow the first one to suppress spacing,
+ * even if it turns out to be a closing one.
+ */
+
+ if (ac == ARGS_PUNCT) {
+ if (cnt == 0 && nc == 0)
+ mdoc->flags |= MDOC_NODELIMC;
break;
+ }
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
+ MDOC_MAX : lookup(tok, p);
/*
* In this case, we've located a submacro and must
@@ -914,27 +942,22 @@ in_line(MACRO_PROT_ARGS)
* or raise a warning.
*/
- if (MDOC_MAX != ntok) {
- if (scope && ! rew_elem(mdoc, tok))
- return(0);
- if (nc && 0 == cnt) {
- if ( ! mdoc_elem_alloc(mdoc,
- line, ppos, tok, arg))
- return(0);
- if ( ! rew_last(mdoc, mdoc->last))
- return(0);
- } else if ( ! nc && 0 == cnt) {
+ if (ntok != MDOC_MAX) {
+ if (scope)
+ rew_elem(mdoc, tok);
+ if (nc && ! cnt) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ rew_last(mdoc, mdoc->last);
+ } else if ( ! nc && ! cnt) {
mdoc_argv_free(arg);
mandoc_msg(MANDOCERR_MACRO_EMPTY,
mdoc->parse, line, ppos,
mdoc_macronames[tok]);
}
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ mdoc_macro(mdoc, ntok, line, la, pos, buf);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
+ return;
}
/*
@@ -943,61 +966,64 @@ in_line(MACRO_PROT_ARGS)
* the word.
*/
- d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
+ d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p);
if (DELIM_NONE != d) {
/*
* If we encounter closing punctuation, no word
- * has been omitted, no scope is open, and we're
+ * has been emitted, no scope is open, and we're
* allowed to have an empty element, then start
- * a new scope. `Ar', `Fl', and `Li', only do
- * this once per invocation. There may be more
- * of these (all of them?).
+ * a new scope.
*/
- 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)
- cnt++;
+ if ((d == DELIM_CLOSE ||
+ (d == DELIM_MIDDLE && tok == MDOC_Fl)) &&
+ !cnt && !scope && nc && mayopen) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
scope = 1;
+ cnt++;
+ if (tok == MDOC_Nm)
+ mayopen = 0;
}
/*
* Close out our scope, if one is open, before
* any punctuation.
*/
- if (scope && ! rew_elem(mdoc, tok))
- return(0);
+ if (scope)
+ rew_elem(mdoc, tok);
scope = 0;
- } else if ( ! scope) {
- if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
+ if (tok == MDOC_Fn)
+ mayopen = 0;
+ } else if (mayopen && !scope) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
scope = 1;
+ cnt++;
}
- if (DELIM_NONE == d)
- cnt++;
+ dword(mdoc, line, la, p, d,
+ MDOC_JOIN & mdoc_macros[tok].flags);
- if ( ! dword(mdoc, line, la, p, d,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
+ /*
+ * If the first argument is a closing delimiter,
+ * do not suppress spacing before it.
+ */
+
+ if (firstarg && d == DELIM_CLOSE && !nc)
+ mdoc->last->flags &= ~MDOC_DELIMC;
+ firstarg = 0;
/*
* `Fl' macros have their scope re-opened with each new
* word so that the `-' can be added to each one without
* having to parse out spaces.
*/
- if (scope && MDOC_Fl == tok) {
- if ( ! rew_elem(mdoc, tok))
- return(0);
+ if (scope && tok == MDOC_Fl) {
+ rew_elem(mdoc, tok);
scope = 0;
}
}
- if (scope && ! rew_elem(mdoc, tok))
- return(0);
+ if (scope)
+ rew_elem(mdoc, tok);
/*
* If no elements have been collected and we're allowed to have
@@ -1005,34 +1031,29 @@ in_line(MACRO_PROT_ARGS)
* raise a warning.
*/
- if (nc && 0 == cnt) {
- 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);
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
- line, ppos, mdoc_macronames[tok]);
+ if ( ! cnt) {
+ if (nc) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ rew_last(mdoc, mdoc->last);
+ } else {
+ mdoc_argv_free(arg);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ }
}
-
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-static int
+static void
blk_full(MACRO_PROT_ARGS)
{
- int la, nl, nparsed;
+ int la, nl, parsed;
struct mdoc_arg *arg;
struct mdoc_node *head; /* save of head macro */
struct mdoc_node *body; /* save of body macro */
struct mdoc_node *n;
- enum mdoc_type mtt;
- enum mdoct ntok;
enum margserr ac, lac;
- enum margverr av;
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
@@ -1041,25 +1062,23 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_It) {
for (n = mdoc->last; n; n = n->parent)
- if (n->tok == MDOC_Bl)
+ if (n->tok == MDOC_Bl &&
+ ! (n->flags & MDOC_VALID))
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));
+ mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
+ rew_elem(mdoc, MDOC_br);
+ return;
}
}
/* Close out prior implicit scope. */
- if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
+ if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
+ rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
}
/*
@@ -1071,72 +1090,42 @@ blk_full(MACRO_PROT_ARGS)
* regular child nodes.
*/
- for (arg = NULL;; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
-
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
-
- if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
- return(0);
-
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ mdoc_block_alloc(mdoc, line, ppos, tok, arg);
head = body = NULL;
/*
* Exception: Heads of `It' macros in `-diag' lists are not
* 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;
+
+ parsed = tok != MDOC_It ||
+ mdoc->last->parent->tok != MDOC_Bl ||
+ mdoc->last->parent->norm->Bl.type != LIST_diag;
/*
* The `Nd' macro has all arguments in its body: it's a hybrid
* of block partial-explicit and full-implicit. Stupid.
*/
- if (MDOC_Nd == tok) {
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
+ if (tok == MDOC_Nd) {
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+ rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
}
- if (MDOC_Bk == tok)
+ if (tok == MDOC_Bk)
mdoc->flags |= MDOC_KEEP;
- ac = ARGS_ERROR;
-
- for ( ; ; ) {
+ ac = ARGS_PEND;
+ for (;;) {
la = *pos;
- /* Initialise last-phrase-type with ARGS_PEND. */
- lac = ARGS_ERROR == ac ? ARGS_PEND : ac;
+ lac = ac;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_PUNCT == ac)
+ if (ac == ARGS_PUNCT)
break;
-
- if (ARGS_ERROR == ac)
- return(0);
-
- if (ARGS_EOLN == ac) {
- if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac)
+ if (ac == ARGS_EOLN) {
+ if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE)
break;
/*
* This is necessary: if the last token on a
@@ -1145,11 +1134,8 @@ blk_full(MACRO_PROT_ARGS)
* reopen our scope if the last parse was a
* phrase or partial phrase.
*/
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
+ rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
break;
}
@@ -1158,42 +1144,33 @@ blk_full(MACRO_PROT_ARGS)
* 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 ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
+ if (head == NULL &&
+ ac != ARGS_PEND &&
+ ac != ARGS_PHRASE &&
+ ac != ARGS_PPHRASE &&
+ ac != ARGS_QWORD &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
/* Open a head if one hasn't been opened. */
- if (NULL == head) {
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
- }
+ if (head == NULL)
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+
+ if (ac == ARGS_PHRASE ||
+ ac == ARGS_PEND ||
+ ac == ARGS_PPHRASE) {
- 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.
*/
- 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))
- return(0);
- body = mdoc->last;
+ rew_sub(body ? MDOC_BODY : MDOC_HEAD,
+ mdoc, tok, line, ppos);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
/*
* Process phrases: set whether we're in a
@@ -1201,45 +1178,24 @@ blk_full(MACRO_PROT_ARGS)
* then call down into the phrase parser.
*/
- if (ARGS_PPHRASE == ac)
+ if (ac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
- if (ARGS_PEND == ac && ARGS_PPHRASE == lac)
+ if (ac == ARGS_PEND && lac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
-
- if ( ! phrase(mdoc, line, la, buf))
- return(0);
-
+ parse_rest(mdoc, MDOC_MAX, line, &la, buf);
mdoc->flags &= ~MDOC_PPHRASE;
continue;
}
- ntok = nparsed || ARGS_QWORD == ac ?
- MDOC_MAX : lookup(tok, p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
- }
-
- if (NULL == head) {
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
+ break;
}
- if (nl && ! append_delims(mdoc, line, pos, buf))
- return(0);
-
- /* If we've already opened our body, exit now. */
-
- if (NULL != body)
+ if (head == NULL)
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
+ if (body != NULL)
goto out;
/*
@@ -1249,39 +1205,30 @@ 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 (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT &&
+ ! (n->flags & MDOC_VALID)) {
n->pending = head;
- return(1);
+ return;
}
}
/* Close out scopes to remain in a consistent state. */
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
-
+ rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ mdoc_body_alloc(mdoc, line, ppos, tok);
out:
- if ( ! (MDOC_FREECOL & mdoc->flags))
- return(1);
-
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
-
- mdoc->flags &= ~MDOC_FREECOL;
- return(1);
+ if (mdoc->flags & MDOC_FREECOL) {
+ rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ mdoc->flags &= ~MDOC_FREECOL;
+ }
}
-static int
+static void
blk_part_imp(MACRO_PROT_ARGS)
{
int la, nl;
- enum mdoct ntok;
enum margserr ac;
char *p;
struct mdoc_node *blk; /* saved block context */
@@ -1299,15 +1246,9 @@ blk_part_imp(MACRO_PROT_ARGS)
* or more closing punctuation nodes.
*/
- if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
- return(0);
-
- blk = mdoc->last;
-
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
+ blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
+ mdoc_head_alloc(mdoc, line, ppos, tok);
+ rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
/*
* Open the body scope "on-demand", that is, after we've
@@ -1318,92 +1259,56 @@ blk_part_imp(MACRO_PROT_ARGS)
for (body = NULL; ; ) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
break;
- if (ARGS_PUNCT == ac)
- break;
-
- if (NULL == body && ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
- if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
- continue;
- }
-
- if (NULL == body) {
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
- }
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
+ if (body == NULL && ac != ARGS_QWORD &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
- }
-
- /* Clean-ups to leave in a consistent state. */
+ if (body == NULL)
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
- if (NULL == body) {
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ break;
}
+ if (body == NULL)
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
/*
* 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) {
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
- ! (MDOC_VALID & n->flags)) {
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT &&
+ ! (n->flags & MDOC_VALID)) {
make_pending(n, tok, mdoc, line, ppos);
- if ( ! mdoc_endbody_alloc(mdoc, line, ppos,
- tok, body, ENDBODY_NOSPACE))
- return(0);
- return(1);
+ mdoc_endbody_alloc(mdoc, line, ppos,
+ tok, body, ENDBODY_NOSPACE);
+ return;
}
}
assert(n == body);
-
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
-
- /* Standard appending of delimiters. */
-
- if (nl && ! append_delims(mdoc, line, pos, buf))
- return(0);
-
- /* Rewind scope, if applicable. */
-
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
+ rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
+ rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
/* Move trailing .Ns out of scope. */
for (n = body->child; n && n->next; n = n->next)
/* Do nothing. */ ;
- if (n && MDOC_Ns == n->tok)
+ if (n && n->tok == MDOC_Ns)
mdoc_node_relink(mdoc, n);
-
- return(1);
}
-static int
+static void
blk_part_exp(MACRO_PROT_ARGS)
{
int la, nl;
@@ -1411,7 +1316,6 @@ blk_part_exp(MACRO_PROT_ARGS)
struct mdoc_node *head; /* keep track of head */
struct mdoc_node *body; /* keep track of body */
char *p;
- enum mdoct ntok;
nl = MDOC_NEWLINE & mdoc->flags;
@@ -1421,35 +1325,25 @@ blk_part_exp(MACRO_PROT_ARGS)
* case of `Eo'); and a body that may be empty.
*/
- if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
- return(0);
-
+ mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
for (head = body = NULL; ; ) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_PUNCT == ac)
- break;
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
/* Flush out leading punctuation. */
- if (NULL == head && ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
+ if (head == NULL && ac != ARGS_QWORD &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
assert(NULL == body);
- if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
- if (NULL == head) {
- assert(NULL == body);
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
+ if (head == NULL) {
+ assert(body == NULL);
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
}
/*
@@ -1457,65 +1351,40 @@ blk_part_exp(MACRO_PROT_ARGS)
* macros just immediately close out and begin the body.
*/
- if (NULL == body) {
+ if (body == NULL) {
assert(head);
/* No check whether it's a macro! */
- if (MDOC_Eo == tok)
- if ( ! dword(mdoc, line, la, p, DELIM_MAX, 0))
- return(0);
-
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
-
- if (MDOC_Eo == tok)
+ if (tok == MDOC_Eo)
+ dword(mdoc, line, la, p, DELIM_MAX, 0);
+ rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
+ if (tok == MDOC_Eo)
continue;
}
+ assert(head != NULL && body != NULL);
- assert(NULL != head && NULL != body);
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ break;
}
/* Clean-up to leave in a consistent state. */
- if (NULL == head)
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
+ if (head == NULL)
+ mdoc_head_alloc(mdoc, line, ppos, tok);
- if (NULL == body) {
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
+ if (body == NULL) {
+ rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ mdoc_body_alloc(mdoc, line, ppos, tok);
}
-
- /* Standard appending of delimiters. */
-
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-static int
+static void
in_line_argn(MACRO_PROT_ARGS)
{
int la, flushed, j, maxargs, nl;
enum margserr ac;
- enum margverr av;
struct mdoc_arg *arg;
char *p;
enum mdoct ntok;
@@ -1533,8 +1402,6 @@ in_line_argn(MACRO_PROT_ARGS)
switch (tok) {
case MDOC_Ap:
/* FALLTHROUGH */
- case MDOC_No:
- /* FALLTHROUGH */
case MDOC_Ns:
/* FALLTHROUGH */
case MDOC_Ux:
@@ -1552,183 +1419,104 @@ in_line_argn(MACRO_PROT_ARGS)
break;
}
- for (arg = NULL; ; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
-
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
for (flushed = j = 0; ; ) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_PUNCT == ac)
- break;
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
- 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);
+ if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
+ ac != ARGS_QWORD && j == 0 &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
- } else if (0 == j)
- if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
+ } else if (j == 0)
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
if (j == maxargs && ! flushed) {
- if ( ! rew_elem(mdoc, tok))
- return(0);
+ rew_elem(mdoc, tok);
flushed = 1;
}
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ ntok = ac == ARGS_QWORD ? MDOC_MAX : lookup(tok, p);
- if (MDOC_MAX != ntok) {
- if ( ! flushed && ! rew_elem(mdoc, tok))
- return(0);
+ if (ntok != MDOC_MAX) {
+ if ( ! flushed)
+ rew_elem(mdoc, tok);
flushed = 1;
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
+ mdoc_macro(mdoc, ntok, line, la, pos, buf);
j++;
break;
}
- if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
- ARGS_QWORD != ac &&
- ! flushed &&
- DELIM_NONE != mdoc_isdelim(p)) {
- if ( ! rew_elem(mdoc, tok))
- return(0);
+ if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
+ ac != ARGS_QWORD && ! flushed &&
+ mdoc_isdelim(p) != DELIM_NONE) {
+ rew_elem(mdoc, tok);
flushed = 1;
}
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
+ dword(mdoc, line, la, p, DELIM_MAX,
+ MDOC_JOIN & mdoc_macros[tok].flags);
j++;
}
- if (0 == j && ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
-
- /* Close out in a consistent state. */
-
- if ( ! flushed && ! rew_elem(mdoc, tok))
- return(0);
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (j == 0)
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ if ( ! flushed)
+ rew_elem(mdoc, tok);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-static int
+static void
in_line_eoln(MACRO_PROT_ARGS)
{
- int la;
- enum margserr ac;
- enum margverr av;
struct mdoc_arg *arg;
- char *p;
- enum mdoct ntok;
-
- assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
if (tok == MDOC_Pp)
rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos);
- /* Parse macro arguments. */
-
- for (arg = NULL; ; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
-
- /* Open element scope. */
-
- if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ if (parse_rest(mdoc, tok, line, pos, buf))
+ return;
+ rew_elem(mdoc, tok);
+}
- /* Parse argument terms. */
+/*
+ * The simplest argument parser available: Parse the remaining
+ * words until the end of the phrase or line and return 0
+ * or until the next macro, call that macro, and return 1.
+ */
+static int
+parse_rest(struct mdoc *mdoc, enum mdoct tok, int line, int *pos, char *buf)
+{
+ int la;
for (;;) {
la = *pos;
- ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
+ if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
return(0);
- if (ARGS_EOLN == ac)
- break;
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! rew_elem(mdoc, tok))
- return(0);
- return(mdoc_macro(mdoc, ntok, line, la, pos, buf));
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ return(1);
}
-
- /* Close out (no delimiters). */
-
- return(rew_elem(mdoc, tok));
}
-static int
+static void
ctx_synopsis(MACRO_PROT_ARGS)
{
- int nl;
- nl = MDOC_NEWLINE & mdoc->flags;
-
- /* If we're not in the SYNOPSIS, go straight to in-line. */
- if ( ! (MDOC_SYNOPSIS & mdoc->flags))
- return(in_line(mdoc, tok, line, ppos, pos, buf));
-
- /* If we're a nested call, same place. */
- if ( ! nl)
- return(in_line(mdoc, tok, line, ppos, pos, buf));
-
- /*
- * XXX: this will open a block scope; however, if later we end
- * up formatting the block scope, then child nodes will inherit
- * the formatting. Be careful.
- */
- if (MDOC_Nm == tok)
- return(blk_full(mdoc, tok, line, ppos, pos, buf));
- assert(MDOC_Vt == tok);
- return(blk_part_imp(mdoc, tok, line, ppos, pos, buf));
+ if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE))
+ in_line(mdoc, tok, line, ppos, pos, buf);
+ else if (tok == MDOC_Nm)
+ blk_full(mdoc, tok, line, ppos, pos, buf);
+ else {
+ assert(tok == MDOC_Vt);
+ blk_part_imp(mdoc, tok, line, ppos, pos, buf);
+ }
}
/*
@@ -1736,87 +1524,25 @@ ctx_synopsis(MACRO_PROT_ARGS)
* They're unusual because they're basically free-form text until a
* macro is encountered.
*/
-static int
-phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
-{
- int la, pos;
- enum margserr ac;
- enum mdoct ntok;
- char *p;
-
- for (pos = ppos; ; ) {
- la = pos;
-
- ac = mdoc_zargs(mdoc, line, &pos, buf, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- break;
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, &pos, buf))
- return(0);
- return(append_delims(mdoc, line, &pos, buf));
- }
-
- return(1);
-}
-
-static int
+static void
phrase_ta(MACRO_PROT_ARGS)
{
struct mdoc_node *n;
- int la;
- enum mdoct ntok;
- enum margserr ac;
- char *p;
/* Make sure we are in a column list or ignore this macro. */
+
n = mdoc->last;
- while (NULL != n && MDOC_Bl != n->tok)
+ while (n != NULL && n->tok != MDOC_Bl)
n = n->parent;
- if (NULL == n || LIST_column != n->norm->Bl.type) {
+ if (n == NULL || n->norm->Bl.type != LIST_column) {
mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
line, ppos, "Ta");
- return(1);
+ return;
}
/* Advance to the next column. */
- if ( ! rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, MDOC_It))
- return(0);
-
- for (;;) {
- la = *pos;
- ac = mdoc_zargs(mdoc, line, pos, buf, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- break;
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- return(append_delims(mdoc, line, pos, buf));
- }
- return(1);
+ rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos);
+ mdoc_body_alloc(mdoc, line, ppos, MDOC_It);
+ parse_rest(mdoc, MDOC_MAX, line, pos, buf);
}
diff --git a/mdoc_man.c b/mdoc_man.c
index 8ef6908a15dc..41cc65b5765e 100644
--- a/mdoc_man.c
+++ b/mdoc_man.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_man.c,v 1.68 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.76 2014/11/27 22:27:56 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -14,9 +14,9 @@
* 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 <assert.h>
#include <stdio.h>
@@ -46,6 +46,7 @@ static void font_push(char);
static void font_pop(void);
static void mid_it(void);
static void post__t(DECL_ARGS);
+static void post_aq(DECL_ARGS);
static void post_bd(DECL_ARGS);
static void post_bf(DECL_ARGS);
static void post_bk(DECL_ARGS);
@@ -72,6 +73,7 @@ static void post_vt(DECL_ARGS);
static int pre__t(DECL_ARGS);
static int pre_an(DECL_ARGS);
static int pre_ap(DECL_ARGS);
+static int pre_aq(DECL_ARGS);
static int pre_bd(DECL_ARGS);
static int pre_bf(DECL_ARGS);
static int pre_bk(DECL_ARGS);
@@ -82,7 +84,8 @@ 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_skip(DECL_ARGS);
+static int pre_eo(DECL_ARGS);
static int pre_ex(DECL_ARGS);
static int pre_fa(DECL_ARGS);
static int pre_fd(DECL_ARGS);
@@ -112,7 +115,7 @@ static int pre_xr(DECL_ARGS);
static void print_word(const char *);
static void print_line(const char *, int);
static void print_block(const char *, int);
-static void print_offs(const char *);
+static void print_offs(const char *, int);
static void print_width(const char *,
const struct mdoc_node *, size_t);
static void print_count(int *);
@@ -172,8 +175,8 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre__t, post__t, NULL, NULL }, /* %T */
{ NULL, NULL, post_percent, NULL, NULL }, /* %V */
{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
- { cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */
- { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
+ { cond_body, pre_aq, post_aq, NULL, NULL }, /* Ao */
+ { cond_body, pre_aq, post_aq, NULL, NULL }, /* Aq */
{ NULL, NULL, NULL, NULL, NULL }, /* At */
{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
@@ -181,14 +184,14 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
{ NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */
{ NULL, pre_bx, NULL, NULL, NULL }, /* Bx */
- { NULL, NULL, NULL, NULL, NULL }, /* Db */
+ { NULL, pre_skip, NULL, NULL, NULL }, /* Db */
{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
{ cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Do */
{ cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Dq */
{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
- { NULL, NULL, post_eo, NULL, NULL }, /* Eo */
+ { cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
{ NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
{ NULL, pre_no, NULL, NULL, NULL }, /* No */
@@ -233,7 +236,7 @@ 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, pre_es, NULL, NULL, NULL }, /* Es */
+ { NULL, pre_skip, 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 */
@@ -416,7 +419,7 @@ print_block(const char *s, int newflags)
}
static void
-print_offs(const char *v)
+print_offs(const char *v, int keywords)
{
char buf[24];
struct roffsu su;
@@ -425,11 +428,11 @@ print_offs(const char *v)
print_line(".RS", MMAN_Bk_susp);
/* Convert v into a number (of characters). */
- if (NULL == v || '\0' == *v || 0 == strcmp(v, "left"))
+ if (NULL == v || '\0' == *v || (keywords && !strcmp(v, "left")))
sz = 0;
- else if (0 == strcmp(v, "indent"))
+ else if (keywords && !strcmp(v, "indent"))
sz = 6;
- else if (0 == strcmp(v, "indent-two"))
+ else if (keywords && !strcmp(v, "indent-two"))
sz = 12;
else if (a2roffsu(v, &su, SCALE_MAX)) {
if (SCALE_EN == su.unit)
@@ -594,15 +597,19 @@ print_node(DECL_ARGS)
printf("\\&");
outflags &= ~MMAN_spc;
}
+ if (outflags & MMAN_Sm && ! (n->flags & MDOC_DELIMC))
+ outflags |= MMAN_spc_force;
print_word(n->string);
+ if (outflags & MMAN_Sm && ! (n->flags & MDOC_DELIMO))
+ outflags |= MMAN_spc;
} else {
/*
* Conditionally run the pre-node action handler for a
* node.
*/
act = manacts + n->tok;
- cond = NULL == act->cond || (*act->cond)(meta, n);
- if (cond && act->pre && ENDBODY_NOT == n->end)
+ cond = act->cond == NULL || (*act->cond)(meta, n);
+ if (cond && act->pre && (n->end == ENDBODY_NOT || n->nchild))
do_sub = (*act->pre)(meta, n);
}
@@ -866,6 +873,25 @@ pre_ap(DECL_ARGS)
}
static int
+pre_aq(DECL_ARGS)
+{
+
+ print_word(n->parent->prev != NULL &&
+ n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
+ outflags &= ~MMAN_spc;
+ return(1);
+}
+
+static void
+post_aq(DECL_ARGS)
+{
+
+ outflags &= ~(MMAN_spc | MMAN_nl);
+ print_word(n->parent->prev != NULL &&
+ n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
+}
+
+static int
pre_bd(DECL_ARGS)
{
@@ -876,7 +902,7 @@ pre_bd(DECL_ARGS)
print_line(".nf", 0);
if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
outflags |= MMAN_sp;
- print_offs(n->norm->Bd.offs);
+ print_offs(n->norm->Bd.offs, 1);
return(1);
}
@@ -963,7 +989,7 @@ pre_bl(DECL_ARGS)
* just nest and do not add up their indentation.
*/
if (n->norm->Bl.offs) {
- print_offs(n->norm->Bl.offs);
+ print_offs(n->norm->Bl.offs, 0);
Bl_stack[Bl_stack_len++] = 0;
}
@@ -1048,7 +1074,7 @@ static int
pre_dl(DECL_ARGS)
{
- print_offs("6n");
+ print_offs("6n", 0);
return(1);
}
@@ -1098,19 +1124,20 @@ post_en(DECL_ARGS)
return;
}
-static void
-post_eo(DECL_ARGS)
+static int
+pre_eo(DECL_ARGS)
{
- if (MDOC_HEAD == n->type || MDOC_BODY == n->type)
- outflags &= ~MMAN_spc;
+ outflags &= ~(MMAN_spc | MMAN_nl);
+ return(1);
}
-static int
-pre_es(DECL_ARGS)
+static void
+post_eo(DECL_ARGS)
{
- return(0);
+ if (n->end != ENDBODY_SPACE)
+ outflags &= ~MMAN_spc;
}
static int
@@ -1166,7 +1193,8 @@ pre_fl(DECL_ARGS)
font_push('B');
print_word("\\-");
- outflags &= ~MMAN_spc;
+ if (n->nchild)
+ outflags &= ~MMAN_spc;
return(1);
}
@@ -1175,8 +1203,10 @@ post_fl(DECL_ARGS)
{
font_pop();
- if (0 == n->nchild && NULL != n->next &&
- n->next->line == n->line)
+ if ( ! (n->nchild ||
+ n->next == NULL ||
+ n->next->type == MDOC_TEXT ||
+ n->next->flags & MDOC_LINE))
outflags &= ~MMAN_spc;
}
@@ -1337,7 +1367,7 @@ pre_it(DECL_ARGS)
outflags |= MMAN_nl;
font_push('B');
if (LIST_bullet == bln->norm->Bl.type)
- print_word("o");
+ print_word("\\(bu");
else
print_word("-");
font_pop();
@@ -1650,6 +1680,13 @@ pre_rv(DECL_ARGS)
}
static int
+pre_skip(DECL_ARGS)
+{
+
+ return(0);
+}
+
+static int
pre_sm(DECL_ARGS)
{
diff --git a/mdoc_term.c b/mdoc_term.c
index eda36221ae8b..dcc2682f4e8e 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_term.c,v 1.275 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.297 2014/11/28 16:54:23 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -16,9 +16,7 @@
* 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>
@@ -53,7 +51,6 @@ struct termact {
static size_t a2width(const struct termp *, const char *);
static size_t a2height(const struct termp *, const char *);
-static size_t a2offs(const struct termp *, const char *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
@@ -67,7 +64,6 @@ static void synopsis_pre(struct termp *,
static void termp____post(DECL_ARGS);
static void termp__t_post(DECL_ARGS);
-static void termp_an_post(DECL_ARGS);
static void termp_bd_post(DECL_ARGS);
static void termp_bk_post(DECL_ARGS);
static void termp_bl_post(DECL_ARGS);
@@ -95,7 +91,6 @@ static int termp_bt_pre(DECL_ARGS);
static int termp_bx_pre(DECL_ARGS);
static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
-static int termp_es_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
@@ -115,6 +110,7 @@ static int termp_quote_pre(DECL_ARGS);
static int termp_rs_pre(DECL_ARGS);
static int termp_rv_pre(DECL_ARGS);
static int termp_sh_pre(DECL_ARGS);
+static int termp_skip_pre(DECL_ARGS);
static int termp_sm_pre(DECL_ARGS);
static int termp_sp_pre(DECL_ARGS);
static int termp_ss_pre(DECL_ARGS);
@@ -140,7 +136,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* El */
{ termp_it_pre, termp_it_post }, /* It */
{ termp_under_pre, NULL }, /* Ad */
- { termp_an_pre, termp_an_post }, /* An */
+ { termp_an_pre, NULL }, /* An */
{ termp_under_pre, NULL }, /* Ar */
{ termp_cd_pre, NULL }, /* Cd */
{ termp_bold_pre, NULL }, /* Cm */
@@ -187,7 +183,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Bq */
{ termp_xx_pre, NULL }, /* Bsx */
{ termp_bx_pre, NULL }, /* Bx */
- { NULL, NULL }, /* Db */
+ { termp_skip_pre, NULL }, /* Db */
{ NULL, NULL }, /* Dc */
{ termp_quote_pre, termp_quote_post }, /* Do */
{ termp_quote_pre, termp_quote_post }, /* Dq */
@@ -197,7 +193,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
- { NULL, NULL }, /* No */
+ { termp_li_pre, NULL }, /* No */
{ termp_ns_pre, NULL }, /* Ns */
{ termp_xx_pre, NULL }, /* Nx */
{ termp_xx_pre, NULL }, /* Ox */
@@ -239,7 +235,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Bro */
{ NULL, NULL }, /* Brc */
{ NULL, termp____post }, /* %C */
- { termp_es_pre, NULL }, /* Es */
+ { termp_skip_pre, NULL }, /* Es */
{ termp_quote_pre, termp_quote_post }, /* En */
{ termp_xx_pre, NULL }, /* Dx */
{ NULL, termp____post }, /* %Q */
@@ -254,34 +250,41 @@ static const struct termact termacts[MDOC_MAX] = {
void
terminal_mdoc(void *arg, const struct mdoc *mdoc)
{
- const struct mdoc_node *n;
const struct mdoc_meta *meta;
+ struct mdoc_node *n;
struct termp *p;
p = (struct termp *)arg;
- if (0 == p->defindent)
- p->defindent = 5;
-
p->overstep = 0;
- p->maxrmargin = p->defrmargin;
+ p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
- if (NULL == p->symtab)
- p->symtab = mchars_alloc();
-
- n = mdoc_node(mdoc);
+ n = mdoc_node(mdoc)->child;
meta = mdoc_meta(mdoc);
- term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
-
- if (n->child) {
- if (MDOC_Sh != n->child->tok)
- term_vspace(p);
- print_mdoc_nodelist(p, NULL, meta, n->child);
+ if (p->synopsisonly) {
+ while (n != NULL) {
+ if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
+ if (n->child->next->child != NULL)
+ print_mdoc_nodelist(p, NULL,
+ meta, n->child->next->child);
+ term_newln(p);
+ break;
+ }
+ n = n->next;
+ }
+ } else {
+ if (p->defindent == 0)
+ p->defindent = 5;
+ term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
+ if (n != NULL) {
+ if (n->tok != MDOC_Sh)
+ term_vspace(p);
+ print_mdoc_nodelist(p, NULL, meta, n);
+ }
+ term_end(p);
}
-
- term_end(p);
}
static void
@@ -337,13 +340,18 @@ print_mdoc_node(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
break;
case MDOC_EQN:
+ if ( ! (n->flags & MDOC_LINE))
+ p->flags |= TERMP_NOSPACE;
term_eqn(p, n->eqn);
+ if (n->next != NULL && ! (n->next->flags & MDOC_LINE))
+ p->flags |= TERMP_NOSPACE;
break;
case MDOC_TBL:
term_tbl(p, n->span);
break;
default:
- if (termacts[n->tok].pre && ENDBODY_NOT == n->end)
+ if (termacts[n->tok].pre &&
+ (n->end == ENDBODY_NOT || n->nchild))
chld = (*termacts[n->tok].pre)
(p, &npair, meta, n);
break;
@@ -398,6 +406,7 @@ static void
print_mdoc_foot(struct termp *p, const void *arg)
{
const struct mdoc_meta *meta;
+ size_t sz;
meta = (const struct mdoc_meta *)arg;
@@ -414,8 +423,9 @@ print_mdoc_foot(struct termp *p, const void *arg)
term_vspace(p);
p->offset = 0;
- p->rmargin = (p->maxrmargin -
- term_strlen(p, meta->date) + term_len(p, 1)) / 2;
+ sz = term_strlen(p, meta->date);
+ p->rmargin = p->maxrmargin > sz ?
+ (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
@@ -423,7 +433,8 @@ print_mdoc_foot(struct termp *p, const void *arg)
term_flushln(p);
p->offset = p->rmargin;
- p->rmargin = p->maxrmargin - term_strlen(p, meta->os);
+ sz = term_strlen(p, meta->os);
+ p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
@@ -465,9 +476,6 @@ print_mdoc_head(struct termp *p, const void *arg)
* switches on the manual section.
*/
- p->offset = 0;
- p->rmargin = p->maxrmargin;
-
assert(meta->vol);
if (NULL == meta->arch)
volume = mandoc_strdup(meta->vol);
@@ -488,7 +496,7 @@ print_mdoc_head(struct termp *p, const void *arg)
p->offset = 0;
p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
- p->maxrmargin - vollen;
+ vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
term_word(p, title);
term_flushln(p);
@@ -537,27 +545,10 @@ a2width(const struct termp *p, const char *v)
struct roffsu su;
assert(v);
- if ( ! a2roffsu(v, &su, SCALE_MAX))
- SCALE_HS_INIT(&su, term_strlen(p, v));
-
- return(term_hspan(p, &su));
-}
-
-static size_t
-a2offs(const struct termp *p, const char *v)
-{
- struct roffsu su;
-
- if ('\0' == *v)
- return(0);
- else if (0 == strcmp(v, "left"))
- return(0);
- else if (0 == strcmp(v, "indent"))
- return(term_len(p, p->defindent + 1));
- else if (0 == strcmp(v, "indent-two"))
- return(term_len(p, (p->defindent + 1) * 2));
- else if ( ! a2roffsu(v, &su, SCALE_MAX))
+ if ( ! a2roffsu(v, &su, SCALE_MAX)) {
SCALE_HS_INIT(&su, term_strlen(p, v));
+ su.scale /= term_strlen(p, "0");
+ }
return(term_hspan(p, &su));
}
@@ -585,16 +576,18 @@ print_bvspace(struct termp *p,
/* Do not vspace directly after Ss/Sh. */
- for (nn = n; nn; nn = nn->parent) {
- if (MDOC_BLOCK != nn->type)
- continue;
- if (MDOC_Ss == nn->tok)
- return;
- if (MDOC_Sh == nn->tok)
+ nn = n;
+ while (nn->prev == NULL) {
+ do {
+ nn = nn->parent;
+ if (nn->type == MDOC_ROOT)
+ return;
+ } while (nn->type != MDOC_BLOCK);
+ if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
return;
- if (NULL == nn->prev)
- continue;
- break;
+ if (nn->tok == MDOC_It &&
+ nn->parent->parent->norm->Bl.type != LIST_item)
+ break;
}
/* A `-column' does not assert vspace within the list. */
@@ -650,7 +643,7 @@ termp_it_pre(DECL_ARGS)
width = offset = 0;
if (bl->norm->Bl.offs)
- offset = a2offs(p, bl->norm->Bl.offs);
+ offset = a2width(p, bl->norm->Bl.offs);
switch (type) {
case LIST_column:
@@ -808,7 +801,8 @@ termp_it_pre(DECL_ARGS)
* the "overstep" effect in term_flushln() and treat
* this as a `-ohang' list instead.
*/
- if (n->next->child &&
+ if (NULL != n->next &&
+ NULL != n->next->child &&
(MDOC_Bl == n->next->child->tok ||
MDOC_Bd == n->next->child->tok))
break;
@@ -864,7 +858,9 @@ termp_it_pre(DECL_ARGS)
* don't want to recalculate rmargin and offsets when
* using `Bd' or `Bl' within `-hang' overstep lists.
*/
- if (MDOC_HEAD == n->type && n->next->child &&
+ if (MDOC_HEAD == n->type &&
+ NULL != n->next &&
+ NULL != n->next->child &&
(MDOC_Bl == n->next->child->tok ||
MDOC_Bd == n->next->child->tok))
break;
@@ -881,11 +877,8 @@ termp_it_pre(DECL_ARGS)
assert(width);
if (MDOC_HEAD == n->type)
p->rmargin = p->offset + width;
- else {
+ else
p->offset += width;
- if (p->rmargin < p->offset)
- p->rmargin = p->offset;
- }
break;
case LIST_column:
assert(width);
@@ -1002,6 +995,7 @@ termp_it_post(DECL_ARGS)
static int
termp_nm_pre(DECL_ARGS)
{
+ const char *cp;
if (MDOC_BLOCK == n->type) {
p->flags |= TERMP_PREKEEP;
@@ -1012,14 +1006,15 @@ termp_nm_pre(DECL_ARGS)
if (NULL == n->child)
return(0);
p->flags |= TERMP_NOSPACE;
- p->offset += term_len(p, 1) +
- (NULL == n->prev->child ?
- term_strlen(p, meta->name) :
- MDOC_TEXT == n->prev->child->type ?
- term_strlen(p, n->prev->child->string) :
- term_len(p, 5));
- if (p->rmargin < p->offset)
- p->rmargin = p->offset;
+ cp = NULL;
+ if (n->prev->child != NULL)
+ cp = n->prev->child->string;
+ if (cp == NULL)
+ cp = meta->name;
+ if (cp == NULL)
+ p->offset += term_len(p, 6);
+ else
+ p->offset += term_len(p, 1) + term_strlen(p, cp);
return(1);
}
@@ -1029,7 +1024,8 @@ termp_nm_pre(DECL_ARGS)
if (MDOC_HEAD == n->type)
synopsis_pre(p, n->parent);
- if (MDOC_HEAD == n->type && n->next->child) {
+ if (MDOC_HEAD == n->type &&
+ NULL != n->next && NULL != n->next->child) {
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 1;
p->rmargin = p->offset + term_len(p, 1);
@@ -1057,7 +1053,8 @@ termp_nm_post(DECL_ARGS)
if (MDOC_BLOCK == n->type) {
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
- } else if (MDOC_HEAD == n->type && n->next->child) {
+ } else if (MDOC_HEAD == n->type &&
+ NULL != n->next && NULL != n->next->child) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->trailspace = 0;
@@ -1072,9 +1069,10 @@ termp_fl_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\-");
- if (n->child)
- p->flags |= TERMP_NOSPACE;
- else if (n->next && n->next->line == n->line)
+ if ( ! (n->nchild == 0 &&
+ (n->next == NULL ||
+ n->next->type == MDOC_TEXT ||
+ n->next->flags & MDOC_LINE)))
p->flags |= TERMP_NOSPACE;
return(1);
@@ -1095,54 +1093,27 @@ static int
termp_an_pre(DECL_ARGS)
{
- if (NULL == n->child)
- return(1);
-
- /*
- * If not in the AUTHORS section, `An -split' will cause
- * newlines to occur before the author name. If in the AUTHORS
- * section, by default, the first `An' invocation is nosplit,
- * then all subsequent ones, regardless of whether interspersed
- * with other macros/text, are split. -split, in this case,
- * will override the condition of the implied first -nosplit.
- */
-
- if (n->sec == SEC_AUTHORS) {
- if ( ! (TERMP_ANPREC & p->flags)) {
- if (TERMP_SPLIT & p->flags)
- term_newln(p);
- return(1);
- }
- if (TERMP_NOSPLIT & p->flags)
- return(1);
- term_newln(p);
- return(1);
- }
-
- if (TERMP_SPLIT & p->flags)
- term_newln(p);
-
- return(1);
-}
-
-static void
-termp_an_post(DECL_ARGS)
-{
-
- if (n->child) {
- if (SEC_AUTHORS == n->sec)
- p->flags |= TERMP_ANPREC;
- return;
- }
-
- if (AUTH_split == n->norm->An.auth) {
+ if (n->norm->An.auth == AUTH_split) {
p->flags &= ~TERMP_NOSPLIT;
p->flags |= TERMP_SPLIT;
- } else if (AUTH_nosplit == n->norm->An.auth) {
+ return(0);
+ }
+ if (n->norm->An.auth == AUTH_nosplit) {
p->flags &= ~TERMP_SPLIT;
p->flags |= TERMP_NOSPLIT;
+ return(0);
}
+ if (n->child == NULL)
+ return(0);
+
+ if (p->flags & TERMP_SPLIT)
+ term_newln(p);
+
+ if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
+ p->flags |= TERMP_SPLIT;
+
+ return(1);
}
static int
@@ -1256,14 +1227,8 @@ static int
termp_nd_pre(DECL_ARGS)
{
- if (MDOC_BODY != n->type)
- return(1);
-
-#if defined(__OpenBSD__) || defined(__linux__)
- term_word(p, "\\(en");
-#else
- term_word(p, "\\(em");
-#endif
+ if (n->type == MDOC_BODY)
+ term_word(p, "\\(en");
return(1);
}
@@ -1408,14 +1373,17 @@ static int
termp_sh_pre(DECL_ARGS)
{
- /* No vspace between consecutive `Sh' calls. */
-
switch (n->type) {
case MDOC_BLOCK:
- if (n->prev && MDOC_Sh == n->prev->tok)
- if (NULL == n->prev->body->child)
- break;
- term_vspace(p);
+ /*
+ * Vertical space before sections, except
+ * when the previous section was empty.
+ */
+ if (n->prev == NULL ||
+ MDOC_Sh != n->prev->tok ||
+ (n->prev->body != NULL &&
+ n->prev->body->child != NULL))
+ term_vspace(p);
break;
case MDOC_HEAD:
term_fontpush(p, TERMFONT_BOLD);
@@ -1593,8 +1561,17 @@ termp_bd_pre(DECL_ARGS)
} else if (MDOC_HEAD == n->type)
return(0);
- if (n->norm->Bd.offs)
- p->offset += a2offs(p, n->norm->Bd.offs);
+ /* Handle the -offset argument. */
+
+ if (n->norm->Bd.offs == NULL ||
+ ! strcmp(n->norm->Bd.offs, "left"))
+ /* nothing */;
+ else if ( ! strcmp(n->norm->Bd.offs, "indent"))
+ p->offset += term_len(p, p->defindent + 1);
+ else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
+ p->offset += term_len(p, (p->defindent + 1) * 2);
+ else
+ p->offset += a2width(p, n->norm->Bd.offs);
/*
* If -ragged or -filled are specified, the block does nothing
@@ -1860,7 +1837,7 @@ termp_sp_pre(DECL_ARGS)
}
static int
-termp_es_pre(DECL_ARGS)
+termp_skip_pre(DECL_ARGS)
{
return(0);
@@ -1877,7 +1854,8 @@ termp_quote_pre(DECL_ARGS)
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- term_word(p, "<");
+ term_word(p, n->parent->prev != NULL &&
+ n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
break;
case MDOC_Bro:
/* FALLTHROUGH */
@@ -1938,17 +1916,19 @@ static void
termp_quote_post(DECL_ARGS)
{
- if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
+ if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
- if (MDOC_En != n->tok)
+ if ( ! (n->tok == MDOC_En ||
+ (n->tok == MDOC_Eo && n->end == ENDBODY_SPACE)))
p->flags |= TERMP_NOSPACE;
switch (n->tok) {
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- term_word(p, ">");
+ term_word(p, n->parent->prev != NULL &&
+ n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
break;
case MDOC_Bro:
/* FALLTHROUGH */
diff --git a/mdoc_validate.c b/mdoc_validate.c
index 78b64cf0a5bd..5a07af3e2e67 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_validate.c,v 1.243 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.262 2014/11/28 18:36:35 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -16,16 +16,13 @@
* 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>
#ifndef OSNAME
#include <sys/utsname.h>
#endif
-#include <sys/types.h>
-
#include <assert.h>
#include <ctype.h>
#include <limits.h>
@@ -56,82 +53,84 @@ enum check_lvl {
CHECK_ERROR,
};
-typedef int (*v_pre)(PRE_ARGS);
-typedef int (*v_post)(POST_ARGS);
+typedef void (*v_pre)(PRE_ARGS);
+typedef void (*v_post)(POST_ARGS);
struct valids {
v_pre pre;
v_post post;
};
-static int check_count(struct mdoc *, enum mdoc_type,
+static void check_count(struct mdoc *, enum mdoc_type,
enum check_lvl, enum check_ineq, int);
static void check_text(struct mdoc *, int, int, char *);
static void check_argv(struct mdoc *,
struct mdoc_node *, struct mdoc_argv *);
static void check_args(struct mdoc *, struct mdoc_node *);
+static int child_an(const struct mdoc_node *);
static enum mdoc_sec a2sec(const char *);
static size_t macro2len(enum mdoct);
-
-static int ebool(POST_ARGS);
-static int berr_ge1(POST_ARGS);
-static int bwarn_ge1(POST_ARGS);
-static int ewarn_eq0(POST_ARGS);
-static int ewarn_eq1(POST_ARGS);
-static int ewarn_ge1(POST_ARGS);
-static int ewarn_le1(POST_ARGS);
-static int hwarn_eq0(POST_ARGS);
-static int hwarn_eq1(POST_ARGS);
-static int hwarn_ge1(POST_ARGS);
-
-static int post_an(POST_ARGS);
-static int post_at(POST_ARGS);
-static int post_bf(POST_ARGS);
-static int post_bk(POST_ARGS);
-static int post_bl(POST_ARGS);
-static int post_bl_block(POST_ARGS);
-static int post_bl_block_width(POST_ARGS);
-static int post_bl_block_tag(POST_ARGS);
-static int post_bl_head(POST_ARGS);
-static int post_bx(POST_ARGS);
-static int post_d1(POST_ARGS);
-static int post_defaults(POST_ARGS);
-static int post_dd(POST_ARGS);
-static int post_dt(POST_ARGS);
-static int post_en(POST_ARGS);
-static int post_es(POST_ARGS);
-static int post_eoln(POST_ARGS);
-static int post_ex(POST_ARGS);
-static int post_fo(POST_ARGS);
-static int post_hyph(POST_ARGS);
-static int post_hyphtext(POST_ARGS);
-static int post_ignpar(POST_ARGS);
-static int post_it(POST_ARGS);
-static int post_lb(POST_ARGS);
-static int post_literal(POST_ARGS);
-static int post_nd(POST_ARGS);
-static int post_nm(POST_ARGS);
-static int post_ns(POST_ARGS);
-static int post_os(POST_ARGS);
-static int post_par(POST_ARGS);
-static int post_root(POST_ARGS);
-static int post_rs(POST_ARGS);
-static int post_sh(POST_ARGS);
-static int post_sh_body(POST_ARGS);
-static int post_sh_head(POST_ARGS);
-static int post_st(POST_ARGS);
-static int post_vt(POST_ARGS);
-static int pre_an(PRE_ARGS);
-static int pre_bd(PRE_ARGS);
-static int pre_bl(PRE_ARGS);
-static int pre_dd(PRE_ARGS);
-static int pre_display(PRE_ARGS);
-static int pre_dt(PRE_ARGS);
-static int pre_literal(PRE_ARGS);
-static int pre_obsolete(PRE_ARGS);
-static int pre_os(PRE_ARGS);
-static int pre_par(PRE_ARGS);
-static int pre_std(PRE_ARGS);
+static void rewrite_macro2len(char **);
+
+static void bwarn_ge1(POST_ARGS);
+static void ewarn_eq1(POST_ARGS);
+static void ewarn_ge1(POST_ARGS);
+static void hwarn_eq0(POST_ARGS);
+
+static void post_an(POST_ARGS);
+static void post_at(POST_ARGS);
+static void post_bf(POST_ARGS);
+static void post_bk(POST_ARGS);
+static void post_bl(POST_ARGS);
+static void post_bl_block(POST_ARGS);
+static void post_bl_block_tag(POST_ARGS);
+static void post_bl_head(POST_ARGS);
+static void post_bx(POST_ARGS);
+static void post_d1(POST_ARGS);
+static void post_defaults(POST_ARGS);
+static void post_dd(POST_ARGS);
+static void post_dt(POST_ARGS);
+static void post_en(POST_ARGS);
+static void post_es(POST_ARGS);
+static void post_eoln(POST_ARGS);
+static void post_ex(POST_ARGS);
+static void post_fa(POST_ARGS);
+static void post_fn(POST_ARGS);
+static void post_fname(POST_ARGS);
+static void post_fo(POST_ARGS);
+static void post_hyph(POST_ARGS);
+static void post_hyphtext(POST_ARGS);
+static void post_ignpar(POST_ARGS);
+static void post_it(POST_ARGS);
+static void post_lb(POST_ARGS);
+static void post_literal(POST_ARGS);
+static void post_nd(POST_ARGS);
+static void post_nm(POST_ARGS);
+static void post_ns(POST_ARGS);
+static void post_os(POST_ARGS);
+static void post_par(POST_ARGS);
+static void post_root(POST_ARGS);
+static void post_rs(POST_ARGS);
+static void post_sh(POST_ARGS);
+static void post_sh_head(POST_ARGS);
+static void post_sh_name(POST_ARGS);
+static void post_sh_see_also(POST_ARGS);
+static void post_sh_authors(POST_ARGS);
+static void post_sm(POST_ARGS);
+static void post_st(POST_ARGS);
+static void post_vt(POST_ARGS);
+
+static void pre_an(PRE_ARGS);
+static void pre_bd(PRE_ARGS);
+static void pre_bl(PRE_ARGS);
+static void pre_dd(PRE_ARGS);
+static void pre_display(PRE_ARGS);
+static void pre_dt(PRE_ARGS);
+static void pre_literal(PRE_ARGS);
+static void pre_obsolete(PRE_ARGS);
+static void pre_os(PRE_ARGS);
+static void pre_par(PRE_ARGS);
+static void pre_std(PRE_ARGS);
static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Ap */
@@ -157,10 +156,10 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Er */
{ NULL, NULL }, /* Ev */
{ pre_std, post_ex }, /* Ex */
- { NULL, NULL }, /* Fa */
+ { NULL, post_fa }, /* Fa */
{ NULL, ewarn_ge1 }, /* Fd */
{ NULL, NULL }, /* Fl */
- { NULL, NULL }, /* Fn */
+ { NULL, post_fn }, /* Fn */
{ NULL, NULL }, /* Ft */
{ NULL, NULL }, /* Ic */
{ NULL, ewarn_eq1 }, /* In */
@@ -196,7 +195,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Bq */
{ NULL, NULL }, /* Bsx */
{ NULL, post_bx }, /* Bx */
- { NULL, ebool }, /* Db */
+ { pre_obsolete, NULL }, /* Db */
{ NULL, NULL }, /* Dc */
{ NULL, NULL }, /* Do */
{ NULL, NULL }, /* Dq */
@@ -206,7 +205,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Eo */
{ NULL, NULL }, /* Fx */
{ NULL, NULL }, /* Ms */
- { NULL, ewarn_eq0 }, /* No */
+ { NULL, NULL }, /* No */
{ NULL, post_ns }, /* Ns */
{ NULL, NULL }, /* Nx */
{ NULL, NULL }, /* Ox */
@@ -223,7 +222,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Sc */
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
- { NULL, ebool }, /* Sm */
+ { NULL, post_sm }, /* Sm */
{ NULL, post_hyph }, /* Sx */
{ NULL, NULL }, /* Sy */
{ NULL, NULL }, /* Tn */
@@ -305,7 +304,7 @@ static const char * const secnames[SEC__MAX] = {
};
-int
+void
mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
{
v_pre p;
@@ -319,17 +318,18 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
case MDOC_EQN:
/* FALLTHROUGH */
case MDOC_ROOT:
- return(1);
+ return;
default:
break;
}
check_args(mdoc, n);
p = mdoc_valids[n->tok].pre;
- return(*p ? (*p)(mdoc, n) : 1);
+ if (*p)
+ (*p)(mdoc, n);
}
-int
+void
mdoc_valid_post(struct mdoc *mdoc)
{
struct mdoc_node *n;
@@ -337,7 +337,7 @@ mdoc_valid_post(struct mdoc *mdoc)
n = mdoc->last;
if (n->flags & MDOC_VALID)
- return(1);
+ return;
n->flags |= MDOC_VALID;
switch (n->type) {
@@ -346,16 +346,33 @@ mdoc_valid_post(struct mdoc *mdoc)
case MDOC_EQN:
/* FALLTHROUGH */
case MDOC_TBL:
- return(1);
+ break;
case MDOC_ROOT:
- return(post_root(mdoc));
+ post_root(mdoc);
+ break;
default:
+
+ /*
+ * Closing delimiters are not special at the
+ * beginning of a block, opening delimiters
+ * are not special at the end.
+ */
+
+ if (n->child != NULL)
+ n->child->flags &= ~MDOC_DELIMC;
+ if (n->last != NULL)
+ n->last->flags &= ~MDOC_DELIMO;
+
+ /* Call the macro's postprocessor. */
+
p = mdoc_valids[n->tok].post;
- return(*p ? (*p)(mdoc) : 1);
+ if (*p)
+ (*p)(mdoc);
+ break;
}
}
-static int
+static void
check_count(struct mdoc *mdoc, enum mdoc_type type,
enum check_lvl lvl, enum check_ineq ineq, int val)
{
@@ -363,23 +380,23 @@ check_count(struct mdoc *mdoc, enum mdoc_type type,
enum mandocerr t;
if (mdoc->last->type != type)
- return(1);
+ return;
switch (ineq) {
case CHECK_LT:
p = "less than ";
if (mdoc->last->nchild < val)
- return(1);
+ return;
break;
case CHECK_GT:
p = "more than ";
if (mdoc->last->nchild > val)
- return(1);
+ return;
break;
case CHECK_EQ:
p = "";
if (val == mdoc->last->nchild)
- return(1);
+ return;
break;
default:
abort();
@@ -390,62 +407,30 @@ check_count(struct mdoc *mdoc, enum mdoc_type type,
mandoc_vmsg(t, mdoc->parse, mdoc->last->line,
mdoc->last->pos, "want %s%d children (have %d)",
p, val, mdoc->last->nchild);
- return(1);
-}
-
-static int
-berr_ge1(POST_ARGS)
-{
-
- return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
}
-static int
+static void
bwarn_ge1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
+ check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
}
-static int
-ewarn_eq0(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
-}
-
-static int
+static void
ewarn_eq1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
}
-static int
+static void
ewarn_ge1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
-}
-
-static int
-ewarn_le1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
}
-static int
+static void
hwarn_eq0(POST_ARGS)
{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
-}
-
-static int
-hwarn_eq1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
-}
-
-static int
-hwarn_ge1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
+ check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
}
static void
@@ -483,13 +468,13 @@ check_text(struct mdoc *mdoc, int ln, int pos, char *p)
ln, pos + (int)(p - cp), NULL);
}
-static int
+static void
pre_display(PRE_ARGS)
{
struct mdoc_node *node;
if (MDOC_BLOCK != n->type)
- return(1);
+ return;
for (node = mdoc->last->parent; node; node = node->parent)
if (MDOC_BLOCK == node->type)
@@ -500,11 +485,9 @@ pre_display(PRE_ARGS)
mandoc_vmsg(MANDOCERR_BD_NEST,
mdoc->parse, n->line, n->pos,
"%s in Bd", mdoc_macronames[n->tok]);
-
- return(1);
}
-static int
+static void
pre_bl(PRE_ARGS)
{
struct mdoc_node *np;
@@ -523,7 +506,7 @@ pre_bl(PRE_ARGS)
assert(np);
assert(MDOC_BLOCK == np->type);
assert(MDOC_Bl == np->tok);
- return(1);
+ return;
}
/*
@@ -532,7 +515,7 @@ pre_bl(PRE_ARGS)
* ones. If we find no list type, we default to LIST_item.
*/
- wa = n->args->argv;
+ wa = (n->args == NULL) ? NULL : n->args->argv;
mdoclt = MDOC_ARG_MAX;
for (i = 0; n->args && i < (int)n->args->argc; i++) {
argv = n->args->argv + i;
@@ -594,6 +577,7 @@ pre_bl(PRE_ARGS)
mdoc->parse, argv->line,
argv->pos, "Bl -width %s",
argv->value[0]);
+ rewrite_macro2len(argv->value);
n->norm->Bl.width = argv->value[0];
break;
case MDOC_Offset:
@@ -608,6 +592,7 @@ pre_bl(PRE_ARGS)
mdoc->parse, argv->line,
argv->pos, "Bl -offset %s",
argv->value[0]);
+ rewrite_macro2len(argv->value);
n->norm->Bl.offs = argv->value[0];
break;
default:
@@ -692,11 +677,10 @@ pre_bl(PRE_ARGS)
default:
break;
}
-
- return(pre_par(mdoc, n));
+ pre_par(mdoc, n);
}
-static int
+static void
pre_bd(PRE_ARGS)
{
struct mdoc_node *np;
@@ -716,7 +700,7 @@ pre_bd(PRE_ARGS)
assert(np);
assert(MDOC_BLOCK == np->type);
assert(MDOC_Bd == np->tok);
- return(1);
+ return;
}
for (i = 0; n->args && i < (int)n->args->argc; i++) {
@@ -742,7 +726,7 @@ pre_bd(PRE_ARGS)
case MDOC_File:
mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
n->line, n->pos, NULL);
- return(0);
+ break;
case MDOC_Offset:
if (0 == argv->sz) {
mandoc_msg(MANDOCERR_ARG_EMPTY,
@@ -755,6 +739,7 @@ pre_bd(PRE_ARGS)
mdoc->parse, argv->line,
argv->pos, "Bd -offset %s",
argv->value[0]);
+ rewrite_macro2len(argv->value);
n->norm->Bd.offs = argv->value[0];
break;
case MDOC_Compact:
@@ -784,18 +769,17 @@ pre_bd(PRE_ARGS)
n->line, n->pos, "Bd");
n->norm->Bd.type = DISP_ragged;
}
-
- return(pre_par(mdoc, n));
+ pre_par(mdoc, n);
}
-static int
+static void
pre_an(PRE_ARGS)
{
struct mdoc_argv *argv;
size_t i;
if (n->args == NULL)
- return(1);
+ return;
for (i = 1; i < n->args->argc; i++) {
argv = n->args->argv + i;
@@ -811,34 +795,30 @@ pre_an(PRE_ARGS)
n->norm->An.auth = AUTH_nosplit;
else
abort();
-
- return(1);
}
-static int
+static void
pre_std(PRE_ARGS)
{
if (n->args && 1 == n->args->argc)
if (MDOC_Std == n->args->argv[0].arg)
- return(1);
+ return;
mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
- return(1);
}
-static int
+static void
pre_obsolete(PRE_ARGS)
{
if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type)
mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
- return(1);
}
-static int
+static void
pre_dt(PRE_ARGS)
{
@@ -848,10 +828,9 @@ pre_dt(PRE_ARGS)
else if (mdoc->meta.os != NULL)
mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
n->line, n->pos, "Dt after Os");
- return(1);
}
-static int
+static void
pre_os(PRE_ARGS)
{
@@ -861,10 +840,9 @@ pre_os(PRE_ARGS)
else if (mdoc->flags & MDOC_PBODY)
mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
n->line, n->pos, "Os");
- return(1);
}
-static int
+static void
pre_dd(PRE_ARGS)
{
@@ -880,10 +858,9 @@ pre_dd(PRE_ARGS)
else if (mdoc->meta.os != NULL)
mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
n->line, n->pos, "Dd after Os");
- return(1);
}
-static int
+static void
post_bf(POST_ARGS)
{
struct mdoc_node *np, *nch;
@@ -906,7 +883,7 @@ post_bf(POST_ARGS)
assert(np);
assert(MDOC_HEAD == np->type);
assert(MDOC_Bf == np->tok);
- return(1);
+ return;
}
np = mdoc->last;
@@ -920,7 +897,7 @@ post_bf(POST_ARGS)
if (NULL == nch) {
mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
np->line, np->pos, "Bf");
- return(1);
+ return;
}
nch = nch->next;
}
@@ -940,7 +917,7 @@ post_bf(POST_ARGS)
np->norm->Bf.font = FONT_Sy;
else
abort();
- return(1);
+ return;
}
/* Extract parameter into data. */
@@ -955,11 +932,9 @@ post_bf(POST_ARGS)
mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
np->child->line, np->child->pos,
"Bf %s", np->child->string);
-
- return(1);
}
-static int
+static void
post_lb(POST_ARGS)
{
struct mdoc_node *n;
@@ -967,10 +942,7 @@ post_lb(POST_ARGS)
char *libname;
check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
-
n = mdoc->last->child;
-
- assert(n);
assert(MDOC_TEXT == n->type);
if (NULL == (stdlibname = mdoc_a2lib(n->string)))
@@ -981,10 +953,9 @@ post_lb(POST_ARGS)
free(n->string);
n->string = libname;
- return(1);
}
-static int
+static void
post_eoln(POST_ARGS)
{
const struct mdoc_node *n;
@@ -995,19 +966,63 @@ post_eoln(POST_ARGS)
mdoc->parse, n->line, n->pos,
"%s %s", mdoc_macronames[n->tok],
n->child->string);
- return(1);
}
-static int
+static void
+post_fname(POST_ARGS)
+{
+ const struct mdoc_node *n;
+ const char *cp;
+ size_t pos;
+
+ n = mdoc->last->child;
+ pos = strcspn(n->string, "()");
+ cp = n->string + pos;
+ if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
+ mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
+ n->line, n->pos + pos, n->string);
+}
+
+static void
+post_fn(POST_ARGS)
+{
+
+ post_fname(mdoc);
+ post_fa(mdoc);
+}
+
+static void
post_fo(POST_ARGS)
{
- hwarn_eq1(mdoc);
+ check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1);
bwarn_ge1(mdoc);
- return(1);
+ if (mdoc->last->type == MDOC_HEAD && mdoc->last->nchild)
+ post_fname(mdoc);
}
-static int
+static void
+post_fa(POST_ARGS)
+{
+ const struct mdoc_node *n;
+ const char *cp;
+
+ for (n = mdoc->last->child; n != NULL; n = n->next) {
+ for (cp = n->string; *cp != '\0'; cp++) {
+ /* Ignore callbacks and alterations. */
+ if (*cp == '(' || *cp == '{')
+ break;
+ if (*cp != ',')
+ continue;
+ mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
+ n->line, n->pos + (cp - n->string),
+ n->string);
+ break;
+ }
+ }
+}
+
+static void
post_vt(POST_ARGS)
{
const struct mdoc_node *n;
@@ -1021,48 +1036,45 @@ post_vt(POST_ARGS)
*/
if (MDOC_BODY != mdoc->last->type)
- return(1);
+ return;
for (n = mdoc->last->child; n; n = n->next)
if (MDOC_TEXT != n->type)
mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
-
- return(1);
}
-static int
+static void
post_nm(POST_ARGS)
{
if (NULL != mdoc->meta.name)
- return(1);
+ return;
mdoc_deroff(&mdoc->meta.name, mdoc->last);
if (NULL == mdoc->meta.name)
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
mdoc->last->line, mdoc->last->pos, "Nm");
- return(1);
}
-static int
+static void
post_nd(POST_ARGS)
{
- berr_ge1(mdoc);
- return(post_hyph(mdoc));
+ check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0);
+ post_hyph(mdoc);
}
-static int
+static void
post_d1(POST_ARGS)
{
bwarn_ge1(mdoc);
- return(post_hyph(mdoc));
+ post_hyph(mdoc);
}
-static int
+static void
post_literal(POST_ARGS)
{
@@ -1079,11 +1091,9 @@ post_literal(POST_ARGS)
if (MDOC_BODY == mdoc->last->type)
mdoc->flags &= ~MDOC_LITERAL;
-
- return(1);
}
-static int
+static void
post_defaults(POST_ARGS)
{
struct mdoc_node *nn;
@@ -1095,38 +1105,29 @@ post_defaults(POST_ARGS)
*/
if (mdoc->last->child)
- return(1);
+ return;
nn = mdoc->last;
mdoc->next = MDOC_NEXT_CHILD;
switch (nn->tok) {
case MDOC_Ar:
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
- return(0);
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
- return(0);
- break;
- case MDOC_Li:
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
- return(0);
+ mdoc_word_alloc(mdoc, nn->line, nn->pos, "file");
+ mdoc_word_alloc(mdoc, nn->line, nn->pos, "...");
break;
case MDOC_Pa:
/* FALLTHROUGH */
case MDOC_Mt:
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
- return(0);
+ mdoc_word_alloc(mdoc, nn->line, nn->pos, "~");
break;
default:
abort();
/* NOTREACHED */
}
-
mdoc->last = nn;
- return(1);
}
-static int
+static void
post_at(POST_ARGS)
{
struct mdoc_node *n;
@@ -1136,10 +1137,9 @@ post_at(POST_ARGS)
n = mdoc->last;
if (n->child == NULL) {
mdoc->next = MDOC_NEXT_CHILD;
- if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"))
- return(0);
+ mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
mdoc->last = n;
- return(1);
+ return;
}
/*
@@ -1159,10 +1159,9 @@ post_at(POST_ARGS)
free(n->string);
n->string = att;
- return(1);
}
-static int
+static void
post_an(POST_ARGS)
{
struct mdoc_node *np;
@@ -1173,28 +1172,24 @@ post_an(POST_ARGS)
check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
} else if (np->child)
check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
-
- return(1);
}
-static int
+static void
post_en(POST_ARGS)
{
if (MDOC_BLOCK == mdoc->last->type)
mdoc->last->norm->Es = mdoc->last_es;
- return(1);
}
-static int
+static void
post_es(POST_ARGS)
{
mdoc->last_es = mdoc->last;
- return(1);
}
-static int
+static void
post_it(POST_ARGS)
{
int i, cols;
@@ -1203,7 +1198,7 @@ post_it(POST_ARGS)
nit = mdoc->last;
if (MDOC_BLOCK != nit->type)
- return(1);
+ return;
nbl = nit->parent->parent;
lt = nbl->norm->Bl.type;
@@ -1260,11 +1255,9 @@ post_it(POST_ARGS)
default:
abort();
}
-
- return(1);
}
-static int
+static void
post_bl_block(POST_ARGS)
{
struct mdoc_node *n, *ni, *nc;
@@ -1281,12 +1274,7 @@ post_bl_block(POST_ARGS)
if (LIST_tag == n->norm->Bl.type &&
NULL == n->norm->Bl.width) {
- if ( ! post_bl_block_tag(mdoc))
- return(0);
- assert(n->norm->Bl.width);
- } else if (NULL != n->norm->Bl.width) {
- if ( ! post_bl_block_width(mdoc))
- return(0);
+ post_bl_block_tag(mdoc);
assert(n->norm->Bl.width);
}
@@ -1310,8 +1298,7 @@ post_bl_block(POST_ARGS)
mandoc_msg(MANDOCERR_PAR_MOVE,
mdoc->parse, nc->line, nc->pos,
mdoc_macronames[nc->tok]);
- if ( ! mdoc_node_relink(mdoc, nc))
- return(0);
+ mdoc_node_relink(mdoc, nc);
} else if (0 == n->norm->Bl.comp &&
LIST_column != n->norm->Bl.type) {
mandoc_vmsg(MANDOCERR_PAR_SKIP,
@@ -1324,56 +1311,32 @@ post_bl_block(POST_ARGS)
nc = ni->body->last;
}
}
- return(1);
}
-static int
-post_bl_block_width(POST_ARGS)
+/*
+ * If the argument of -offset or -width is a macro,
+ * replace it with the associated default width.
+ */
+void
+rewrite_macro2len(char **arg)
{
size_t width;
- int i;
enum mdoct tok;
- struct mdoc_node *n;
- char buf[24];
-
- n = mdoc->last;
- /*
- * Calculate the real width of a list from the -width string,
- * which may contain a macro (with a known default width), a
- * literal string, or a scaling width.
- *
- * If the value to -width is a macro, then we re-write it to be
- * the macro's width as set in share/tmac/mdoc/doc-common.
- */
-
- if (0 == strcmp(n->norm->Bl.width, "Ds"))
+ if (*arg == NULL)
+ return;
+ else if ( ! strcmp(*arg, "Ds"))
width = 6;
- else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
- return(1);
+ else if ((tok = mdoc_hash_find(*arg)) == MDOC_MAX)
+ return;
else
width = macro2len(tok);
- /* The value already exists: free and reallocate it. */
-
- assert(n->args);
-
- for (i = 0; i < (int)n->args->argc; i++)
- if (MDOC_Width == n->args->argv[i].arg)
- break;
-
- assert(i < (int)n->args->argc);
-
- (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width);
- free(n->args->argv[i].value[0]);
- n->args->argv[i].value[0] = mandoc_strdup(buf);
-
- /* Set our width! */
- n->norm->Bl.width = n->args->argv[i].value[0];
- return(1);
+ free(*arg);
+ mandoc_asprintf(arg, "%zun", width);
}
-static int
+static void
post_bl_block_tag(POST_ARGS)
{
struct mdoc_node *n, *nn;
@@ -1385,7 +1348,7 @@ post_bl_block_tag(POST_ARGS)
* Calculate the -width for a `Bl -tag' list if it hasn't been
* provided. Uses the first head macro. NOTE AGAIN: this is
* ONLY if the -width argument has NOT been provided. See
- * post_bl_block_width() for converting the -width string.
+ * rewrite_macro2len() for converting the -width string.
*/
sz = 10;
@@ -1436,19 +1399,20 @@ post_bl_block_tag(POST_ARGS)
/* Set our width! */
n->norm->Bl.width = n->args->argv[i].value[0];
- return(1);
}
-static int
+static void
post_bl_head(POST_ARGS)
{
struct mdoc_node *np, *nn, *nnp;
struct mdoc_argv *argv;
int i, j;
- if (LIST_column != mdoc->last->norm->Bl.type)
+ if (LIST_column != mdoc->last->norm->Bl.type) {
/* FIXME: this should be ERROR class... */
- return(hwarn_eq0(mdoc));
+ hwarn_eq0(mdoc);
+ return;
+ }
/*
* Append old-style lists, where the column width specifiers
@@ -1457,7 +1421,7 @@ post_bl_head(POST_ARGS)
*/
if (mdoc->last->child == NULL)
- return(1);
+ return;
np = mdoc->last->parent;
assert(np->args);
@@ -1493,11 +1457,9 @@ post_bl_head(POST_ARGS)
mdoc->last->nchild = 0;
mdoc->last->child = NULL;
-
- return(1);
}
-static int
+static void
post_bl(POST_ARGS)
{
struct mdoc_node *nparent, *nprev; /* of the Bl block */
@@ -1507,13 +1469,15 @@ post_bl(POST_ARGS)
nbody = mdoc->last;
switch (nbody->type) {
case MDOC_BLOCK:
- return(post_bl_block(mdoc));
+ post_bl_block(mdoc);
+ return;
case MDOC_HEAD:
- return(post_bl_head(mdoc));
+ post_bl_head(mdoc);
+ return;
case MDOC_BODY:
break;
default:
- return(1);
+ return;
}
bwarn_ge1(mdoc);
@@ -1570,56 +1534,47 @@ post_bl(POST_ARGS)
nchild = nnext;
}
-
- return(1);
}
-static int
+static void
post_bk(POST_ARGS)
{
hwarn_eq0(mdoc);
bwarn_ge1(mdoc);
- return(1);
}
-static int
-ebool(struct mdoc *mdoc)
+static void
+post_sm(struct mdoc *mdoc)
{
struct mdoc_node *nch;
- enum mdoct tok;
- tok = mdoc->last->tok;
nch = mdoc->last->child;
- if (NULL == nch) {
- if (MDOC_Sm == tok)
- mdoc->flags ^= MDOC_SMOFF;
- return(1);
+ if (nch == NULL) {
+ mdoc->flags ^= MDOC_SMOFF;
+ return;
}
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
-
- assert(MDOC_TEXT == nch->type);
+ assert(nch->type == MDOC_TEXT);
- if (0 == strcmp(nch->string, "on")) {
- if (MDOC_Sm == tok)
- mdoc->flags &= ~MDOC_SMOFF;
- return(1);
+ if ( ! strcmp(nch->string, "on")) {
+ mdoc->flags &= ~MDOC_SMOFF;
+ return;
}
- if (0 == strcmp(nch->string, "off")) {
- if (MDOC_Sm == tok)
- mdoc->flags |= MDOC_SMOFF;
- return(1);
+ if ( ! strcmp(nch->string, "off")) {
+ mdoc->flags |= MDOC_SMOFF;
+ return;
}
mandoc_vmsg(MANDOCERR_SM_BAD,
mdoc->parse, nch->line, nch->pos,
- "%s %s", mdoc_macronames[tok], nch->string);
- return(mdoc_node_relink(mdoc, nch));
+ "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
+ mdoc_node_relink(mdoc, nch);
+ return;
}
-static int
+static void
post_root(POST_ARGS)
{
struct mdoc_node *n;
@@ -1646,23 +1601,20 @@ post_root(POST_ARGS)
mdoc->meta.os = mandoc_strdup("");
}
- n = mdoc->first;
- assert(n);
-
/* Check that we begin with a proper `Sh'. */
- if (NULL == n->child)
- mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse,
- n->line, n->pos, NULL);
- else if (MDOC_Sh != n->child->tok)
- mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
- n->child->line, n->child->pos,
- mdoc_macronames[n->child->tok]);
+ n = mdoc->first->child;
+ while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
+ n = n->next;
- return(1);
+ if (n == NULL)
+ mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
+ else if (n->tok != MDOC_Sh)
+ mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
}
-static int
+static void
post_st(POST_ARGS)
{
struct mdoc_node *n, *nch;
@@ -1675,7 +1627,7 @@ post_st(POST_ARGS)
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
mdoc_node_delete(mdoc, n);
- return(1);
+ return;
}
assert(MDOC_TEXT == nch->type);
@@ -1688,11 +1640,9 @@ post_st(POST_ARGS)
free(nch->string);
nch->string = mandoc_strdup(p);
}
-
- return(1);
}
-static int
+static void
post_rs(POST_ARGS)
{
struct mdoc_node *nn, *next, *prev;
@@ -1701,14 +1651,14 @@ post_rs(POST_ARGS)
switch (mdoc->last->type) {
case MDOC_HEAD:
check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
- return(1);
+ return;
case MDOC_BODY:
if (mdoc->last->child)
break;
check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
- return(1);
+ return;
default:
- return(1);
+ return;
}
/*
@@ -1782,15 +1732,13 @@ post_rs(POST_ARGS)
mdoc->last->child = nn;
}
}
-
- return(1);
}
/*
* For some arguments of some macros,
* convert all breakable hyphens into ASCII_HYPH.
*/
-static int
+static void
post_hyph(POST_ARGS)
{
struct mdoc_node *n, *nch;
@@ -1801,15 +1749,15 @@ post_hyph(POST_ARGS)
case MDOC_HEAD:
if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
break;
- return(1);
+ return;
case MDOC_BODY:
if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
break;
- return(1);
+ return;
case MDOC_ELEM:
break;
default:
- return(1);
+ return;
}
for (nch = n->child; nch; nch = nch->next) {
@@ -1824,49 +1772,60 @@ post_hyph(POST_ARGS)
isalpha((unsigned char)cp[1]))
*cp = ASCII_HYPH;
}
- return(1);
}
-static int
+static void
post_hyphtext(POST_ARGS)
{
ewarn_ge1(mdoc);
- return(post_hyph(mdoc));
+ post_hyph(mdoc);
}
-static int
+static void
post_ns(POST_ARGS)
{
if (MDOC_LINE & mdoc->last->flags)
mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
mdoc->last->line, mdoc->last->pos, NULL);
- return(1);
}
-static int
+static void
post_sh(POST_ARGS)
{
post_ignpar(mdoc);
- if (MDOC_HEAD == mdoc->last->type)
- return(post_sh_head(mdoc));
- if (MDOC_BODY == mdoc->last->type)
- return(post_sh_body(mdoc));
-
- return(1);
+ switch (mdoc->last->type) {
+ case MDOC_HEAD:
+ post_sh_head(mdoc);
+ break;
+ case MDOC_BODY:
+ switch (mdoc->lastsec) {
+ case SEC_NAME:
+ post_sh_name(mdoc);
+ break;
+ case SEC_SEE_ALSO:
+ post_sh_see_also(mdoc);
+ break;
+ case SEC_AUTHORS:
+ post_sh_authors(mdoc);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
}
-static int
-post_sh_body(POST_ARGS)
+static void
+post_sh_name(POST_ARGS)
{
struct mdoc_node *n;
- if (SEC_NAME != mdoc->lastsec)
- return(1);
-
/*
* Warn if the NAME section doesn't contain the `Nm' and `Nd'
* macros (can have multiple `Nm' and one `Nd'). Note that the
@@ -1876,7 +1835,7 @@ post_sh_body(POST_ARGS)
if (NULL == (n = mdoc->last->child)) {
mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
mdoc->last->line, mdoc->last->pos, "empty");
- return(1);
+ return;
}
for ( ; n && n->next; n = n->next) {
@@ -1890,14 +1849,94 @@ post_sh_body(POST_ARGS)
assert(n);
if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
- return(1);
+ return;
mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
- return(1);
+}
+
+static void
+post_sh_see_also(POST_ARGS)
+{
+ const struct mdoc_node *n;
+ const char *name, *sec;
+ const char *lastname, *lastsec, *lastpunct;
+ int cmp;
+
+ n = mdoc->last->child;
+ lastname = lastsec = lastpunct = NULL;
+ while (n != NULL) {
+ if (n->tok != MDOC_Xr || n->nchild < 2)
+ break;
+
+ /* Process one .Xr node. */
+
+ name = n->child->string;
+ sec = n->child->next->string;
+ if (lastsec != NULL) {
+ if (lastpunct[0] != ',' || lastpunct[1] != '\0')
+ mandoc_vmsg(MANDOCERR_XR_PUNCT,
+ mdoc->parse, n->line, n->pos,
+ "%s before %s(%s)", lastpunct,
+ name, sec);
+ cmp = strcmp(lastsec, sec);
+ if (cmp > 0)
+ mandoc_vmsg(MANDOCERR_XR_ORDER,
+ mdoc->parse, n->line, n->pos,
+ "%s(%s) after %s(%s)", name,
+ sec, lastname, lastsec);
+ else if (cmp == 0 &&
+ strcasecmp(lastname, name) > 0)
+ mandoc_vmsg(MANDOCERR_XR_ORDER,
+ mdoc->parse, n->line, n->pos,
+ "%s after %s", name, lastname);
+ }
+ lastname = name;
+ lastsec = sec;
+
+ /* Process the following node. */
+
+ n = n->next;
+ if (n == NULL)
+ break;
+ if (n->tok == MDOC_Xr) {
+ lastpunct = "none";
+ continue;
+ }
+ if (n->type != MDOC_TEXT)
+ break;
+ for (name = n->string; *name != '\0'; name++)
+ if (isalpha((const unsigned char)*name))
+ return;
+ lastpunct = n->string;
+ if (n->next == NULL)
+ mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
+ n->line, n->pos, "%s after %s(%s)",
+ lastpunct, lastname, lastsec);
+ n = n->next;
+ }
}
static int
+child_an(const struct mdoc_node *n)
+{
+
+ for (n = n->child; n != NULL; n = n->next)
+ if ((n->tok == MDOC_An && n->nchild) || child_an(n))
+ return(1);
+ return(0);
+}
+
+static void
+post_sh_authors(POST_ARGS)
+{
+
+ if ( ! child_an(mdoc->last))
+ mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
+}
+
+static void
post_sh_head(POST_ARGS)
{
struct mdoc_node *n;
@@ -1956,7 +1995,7 @@ post_sh_head(POST_ARGS)
if (SEC_CUSTOM == sec) {
free(secname);
- return(1);
+ return;
}
/*
@@ -1982,7 +2021,7 @@ post_sh_head(POST_ARGS)
if (mdoc->meta.msec == NULL) {
free(secname);
- return(1);
+ return;
}
goodsec = NULL;
@@ -2014,21 +2053,19 @@ post_sh_head(POST_ARGS)
default:
break;
}
-
free(secname);
- return(1);
}
-static int
+static void
post_ignpar(POST_ARGS)
{
struct mdoc_node *np;
- hwarn_ge1(mdoc);
+ check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0);
post_hyph(mdoc);
if (MDOC_BODY != mdoc->last->type)
- return(1);
+ return;
if (NULL != (np = mdoc->last->child))
if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
@@ -2047,18 +2084,16 @@ post_ignpar(POST_ARGS)
mdoc_macronames[mdoc->last->tok]);
mdoc_node_delete(mdoc, np);
}
-
- return(1);
}
-static int
+static void
pre_par(PRE_ARGS)
{
if (NULL == mdoc->last)
- return(1);
+ return;
if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
- return(1);
+ return;
/*
* Don't allow prior `Lp' or `Pp' prior to a paragraph-type
@@ -2068,63 +2103,59 @@ pre_par(PRE_ARGS)
if (MDOC_Pp != mdoc->last->tok &&
MDOC_Lp != mdoc->last->tok &&
MDOC_br != mdoc->last->tok)
- return(1);
+ return;
if (MDOC_Bl == n->tok && n->norm->Bl.comp)
- return(1);
+ return;
if (MDOC_Bd == n->tok && n->norm->Bd.comp)
- return(1);
+ return;
if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
- return(1);
+ return;
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
mdoc->last->line, mdoc->last->pos,
"%s before %s", mdoc_macronames[mdoc->last->tok],
mdoc_macronames[n->tok]);
mdoc_node_delete(mdoc, mdoc->last);
- return(1);
}
-static int
+static void
post_par(POST_ARGS)
{
struct mdoc_node *np;
if (mdoc->last->tok == MDOC_sp)
- ewarn_le1(mdoc);
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
else
- ewarn_eq0(mdoc);
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
if (MDOC_ELEM != mdoc->last->type &&
MDOC_BLOCK != mdoc->last->type)
- return(1);
+ return;
if (NULL == (np = mdoc->last->prev)) {
np = mdoc->last->parent;
if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
- return(1);
- } else {
- if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
- (MDOC_br != mdoc->last->tok ||
- (MDOC_sp != np->tok && MDOC_br != np->tok)))
- return(1);
- }
+ return;
+ } else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
+ (MDOC_br != mdoc->last->tok ||
+ (MDOC_sp != np->tok && MDOC_br != np->tok)))
+ return;
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
mdoc->last->line, mdoc->last->pos,
"%s after %s", mdoc_macronames[mdoc->last->tok],
mdoc_macronames[np->tok]);
mdoc_node_delete(mdoc, mdoc->last);
- return(1);
}
-static int
+static void
pre_literal(PRE_ARGS)
{
pre_display(mdoc, n);
if (MDOC_BODY != n->type)
- return(1);
+ return;
/*
* The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
@@ -2145,11 +2176,9 @@ pre_literal(PRE_ARGS)
abort();
/* NOTREACHED */
}
-
- return(1);
}
-static int
+static void
post_dd(POST_ARGS)
{
struct mdoc_node *n;
@@ -2176,10 +2205,9 @@ post_dd(POST_ARGS)
}
out:
mdoc_node_delete(mdoc, n);
- return(1);
}
-static int
+static void
post_dt(POST_ARGS)
{
struct mdoc_node *nn, *n;
@@ -2252,39 +2280,21 @@ post_dt(POST_ARGS)
mdoc->meta.msec = mandoc_strdup(nn->string);
}
- if (NULL == (nn = nn->next))
- goto out;
-
- /* Handles: `.Dt TITLE SEC VOL'
- * title = TITLE,
- * volume = VOL is vol ? format(VOL) :
- * VOL is arch ? format(arch) :
- * VOL
- */
+ /* Handle an optional architecture */
- cp = mdoc_a2vol(nn->string);
- if (cp) {
- free(mdoc->meta.vol);
- mdoc->meta.vol = mandoc_strdup(cp);
- } else {
- cp = mdoc_a2arch(nn->string);
- if (NULL == cp) {
- mandoc_vmsg(MANDOCERR_ARCH_BAD, mdoc->parse,
- nn->line, nn->pos, "Dt ... %s", nn->string);
- free(mdoc->meta.vol);
- mdoc->meta.vol = mandoc_strdup(nn->string);
- } else
- mdoc->meta.arch = mandoc_strdup(cp);
+ if ((nn = nn->next) != NULL) {
+ for (p = nn->string; *p; p++)
+ *p = tolower((unsigned char)*p);
+ mdoc->meta.arch = mandoc_strdup(nn->string);
}
/* Ignore any subsequent parameters... */
/* FIXME: warn about subsequent parameters. */
out:
mdoc_node_delete(mdoc, n);
- return(1);
}
-static int
+static void
post_bx(POST_ARGS)
{
struct mdoc_node *n;
@@ -2298,11 +2308,9 @@ post_bx(POST_ARGS)
n = mdoc->last->child;
if (n && NULL != (n = n->next))
*n->string = (char)toupper((unsigned char)*n->string);
-
- return(1);
}
-static int
+static void
post_os(POST_ARGS)
{
#ifndef OSNAME
@@ -2350,14 +2358,13 @@ post_os(POST_ARGS)
out:
mdoc_node_delete(mdoc, n);
- return(1);
}
/*
* If no argument is provided,
* fill in the name of the current manual page.
*/
-static int
+static void
post_ex(POST_ARGS)
{
struct mdoc_node *n;
@@ -2365,21 +2372,17 @@ post_ex(POST_ARGS)
n = mdoc->last;
if (n->child)
- return(1);
+ return;
if (mdoc->meta.name == NULL) {
mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
n->line, n->pos, "Ex");
- return(1);
+ return;
}
mdoc->next = MDOC_NEXT_CHILD;
-
- if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
- return(0);
-
+ mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
mdoc->last = n;
- return(1);
}
static enum mdoc_sec
diff --git a/msec.c b/msec.c
index 3db04d66635d..2d0d85bbe69b 100644
--- a/msec.c
+++ b/msec.c
@@ -1,4 +1,4 @@
-/* $Id: msec.c,v 1.11 2014/03/23 11:25:26 schwarze Exp $ */
+/* $Id: msec.c,v 1.12 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,9 @@
* 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 <string.h>
diff --git a/msec.in b/msec.in
index f3aebb46a109..4fab2f653b6b 100644
--- a/msec.in
+++ b/msec.in
@@ -1,4 +1,4 @@
-/* $Id: msec.in,v 1.6 2010/06/19 20:46:28 kristaps Exp $ */
+/* $Id: msec.in,v 1.7 2014/08/26 11:21:40 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -25,8 +25,8 @@
LINE("1", "General Commands Manual")
LINE("2", "System Calls Manual")
LINE("3", "Library Functions Manual")
-LINE("3p", "Perl Library Functions Manual")
-LINE("4", "Kernel Interfaces Manual")
+LINE("3p", "Perl Library Manual")
+LINE("4", "Device Drivers Manual")
LINE("5", "File Formats Manual")
LINE("6", "Games Manual")
LINE("7", "Miscellaneous Information Manual")
diff --git a/out.c b/out.c
index 0e5a63c02398..5b08a09abd42 100644
--- a/out.c
+++ b/out.c
@@ -1,7 +1,7 @@
-/* $Id: out.c,v 1.49 2014/08/01 19:25:52 schwarze Exp $ */
+/* $Id: out.c,v 1.53 2014/10/14 18:18:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 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,9 +15,7 @@
* 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>
@@ -112,7 +110,7 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
case '\0':
if (SCALE_MAX == def)
return(0);
- unit = SCALE_BU;
+ unit = SCALE_EN;
break;
case 'u':
unit = SCALE_BU;
@@ -141,11 +139,14 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
* used for the actual width calculations.
*/
void
-tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
+tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
+ size_t totalwidth)
{
const struct tbl_dat *dp;
struct roffcol *col;
+ size_t ewidth, xwidth;
int spans;
+ int icol, maxcol, necol, nxcol;
/*
* Allocate the master column specifiers. These will hold the
@@ -157,7 +158,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
sizeof(struct roffcol));
- for ( ; sp; sp = sp->next) {
+ for (maxcol = -1; sp; sp = sp->next) {
if (TBL_SPAN_DATA != sp->pos)
continue;
spans = 1;
@@ -172,11 +173,72 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
spans = dp->spans;
if (1 < spans)
continue;
- assert(dp->layout);
- col = &tbl->cols[dp->layout->head->ident];
+ icol = dp->layout->head->ident;
+ if (maxcol < icol)
+ maxcol = icol;
+ col = tbl->cols + icol;
+ col->flags |= dp->layout->flags;
+ if (dp->layout->flags & TBL_CELL_WIGN)
+ continue;
tblcalc_data(tbl, col, sp->opts, dp);
}
}
+
+ /*
+ * Count columns to equalize and columns to maximize.
+ * Find maximum width of the columns to equalize.
+ * Find total width of the columns *not* to maximize.
+ */
+
+ necol = nxcol = 0;
+ ewidth = xwidth = 0;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if (col->flags & TBL_CELL_EQUAL) {
+ necol++;
+ if (ewidth < col->width)
+ ewidth = col->width;
+ }
+ if (col->flags & TBL_CELL_WMAX)
+ nxcol++;
+ else
+ xwidth += col->width;
+ }
+
+ /*
+ * Equalize columns, if requested for any of them.
+ * Update total width of the columns not to maximize.
+ */
+
+ if (necol) {
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if ( ! (col->flags & TBL_CELL_EQUAL))
+ continue;
+ if (col->width == ewidth)
+ continue;
+ if (nxcol && totalwidth)
+ xwidth += ewidth - col->width;
+ col->width = ewidth;
+ }
+ }
+
+ /*
+ * If there are any columns to maximize, find the total
+ * available width, deducting 3n margins between columns.
+ * Distribute the available width evenly.
+ */
+
+ if (nxcol && totalwidth) {
+ xwidth = totalwidth - 3*maxcol - xwidth;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if ( ! (col->flags & TBL_CELL_WMAX))
+ continue;
+ col->width = xwidth / nxcol--;
+ xwidth -= col->width;
+ }
+ }
}
static void
diff --git a/out.h b/out.h
index 514db3fe279c..de38ec1754af 100644
--- a/out.h
+++ b/out.h
@@ -1,4 +1,4 @@
-/* $Id: out.h,v 1.22 2014/04/20 16:46:05 schwarze Exp $ */
+/* $Id: out.h,v 1.24 2014/10/14 02:16:06 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -34,6 +34,7 @@ enum roffscale {
struct roffcol {
size_t width; /* width of cell */
size_t decimal; /* decimal position in cell */
+ int flags; /* layout flags, see tbl_cell */
};
struct roffsu {
@@ -59,12 +60,13 @@ __BEGIN_DECLS
while (/* CONSTCOND */ 0)
#define SCALE_HS_INIT(p, v) \
- do { (p)->unit = SCALE_BU; \
+ do { (p)->unit = SCALE_EN; \
(p)->scale = (v); } \
while (/* CONSTCOND */ 0)
int a2roffsu(const char *, struct roffsu *, enum roffscale);
-void tblcalc(struct rofftbl *tbl, const struct tbl_span *);
+void tblcalc(struct rofftbl *tbl,
+ const struct tbl_span *, size_t);
__END_DECLS
diff --git a/preconv.1 b/preconv.1
deleted file mode 100644
index 8daee30854d9..000000000000
--- a/preconv.1
+++ /dev/null
@@ -1,157 +0,0 @@
-.\" $Id: preconv.1,v 1.7 2013/07/13 19:41:16 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: July 13 2013 $
-.Dt PRECONV 1
-.Os
-.Sh NAME
-.Nm preconv
-.Nd recode multibyte UNIX manuals
-.Sh SYNOPSIS
-.Nm preconv
-.Op Fl D Ar enc
-.Op Fl e Ar enc
-.Op Ar file
-.Sh DESCRIPTION
-The
-.Nm
-utility recodes multibyte
-.Ux
-manual files into
-.Xr mandoc 1
-.Po
-or other troff system supporting the
-.Sq \e[uNNNN]
-escape sequence
-.Pc
-input.
-.Pp
-By default, it parses from standard output, determining encoding as
-described in
-.Sx Algorithm .
-.Pp
-Its arguments are as follows:
-.Bl -tag -width Ds
-.It Fl D Ar enc
-The default encoding.
-.It Fl e Ar enc
-The document's encoding.
-.It Ar file
-The input file.
-.El
-.Pp
-The recoded input is written to standard output: Unicode characters in
-the ASCII range are printed as regular ASCII characters, while those
-above this range are printed using the
-.Sq \e[uNNNN]
-format documented in
-.Xr mandoc_char 7 .
-.Pp
-If input bytes are improperly formed in the current encoding, they're
-passed unmodified to standard output.
-For some encodings, such as UTF-8, unrecoverable input sequences will
-cause
-.Nm
-to stop processing and exit.
-.Ss Algorithm
-An encoding is chosen according to the following steps:
-.Bl -enum
-.It
-From the argument passed to
-.Fl e Ar enc .
-.It
-If a BOM exists, UTF\-8 encoding is selected.
-.It
-From the coding tags parsed from
-.Qq File Variables
-on the first two lines of input.
-A file variable is an input line of the form
-.Pp
-.Dl \%.\e\(dq -*- key: val [; key: val ]* -*-
-.Pp
-A coding tag variable is where
-.Cm key
-is
-.Qq coding
-and
-.Cm val
-is the name of the encoding.
-A typical file variable with a coding tag is
-.Pp
-.Dl \%.\e\(dq -*- mode: troff; coding: utf-8 -*-
-.It
-From the argument passed to
-.Fl D Ar enc .
-.It
-If all else fails, Latin\-1 is used.
-.El
-.Pp
-The
-.Nm
-utility recognises the UTF\-8, us\-ascii, and latin\-1 encodings as
-passed to the
-.Fl e
-and
-.Fl D
-arguments, or as coding tags.
-Encodings are matched case-insensitively.
-.\" .Sh IMPLEMENTATION NOTES
-.\" Not used in OpenBSD.
-.\" .Sh RETURN VALUES
-.\" For sections 2, 3, & 9 only.
-.\" .Sh ENVIRONMENT
-.\" For sections 1, 6, 7, & 8 only.
-.\" .Sh FILES
-.Sh EXIT STATUS
-.Ex -std
-.Sh EXAMPLES
-Explicitly page a UTF\-8 manual
-.Pa foo.1
-in the current locale:
-.Pp
-.Dl $ preconv \-e utf\-8 foo.1 | mandoc -Tlocale | less
-.\" .Sh DIAGNOSTICS
-.\" For sections 1, 4, 6, 7, & 8 only.
-.\" .Sh ERRORS
-.\" For sections 2, 3, & 9 only.
-.Sh SEE ALSO
-.Xr mandoc 1 ,
-.Xr mandoc_char 7
-.Sh STANDARDS
-The
-.Nm
-utility references the US-ASCII character set standard, ANSI_X3.4\-1968;
-the Latin\-1 character set standard, ISO/IEC 8859\-1:1998; the UTF\-8
-character set standard; and UCS (Unicode), ISO/IEC 10646.
-.Sh HISTORY
-The
-.Nm
-utility first appeared in the GNU troff
-.Pq Dq groff
-system in December 2005, authored by Tomohiro Kubota and Werner
-Lemberg.
-The implementation that is part of the
-.Xr mandoc 1
-utility appeared in May 2011.
-.Sh AUTHORS
-The
-.Nm
-utility was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
-.\" .Sh CAVEATS
-.\" .Sh BUGS
-.\" .Sh SECURITY CONSIDERATIONS
-.\" Not used in OpenBSD.
diff --git a/preconv.c b/preconv.c
index 7595887dd26f..0c6076ecb425 100644
--- a/preconv.c
+++ b/preconv.c
@@ -1,6 +1,7 @@
-/* $Id: preconv.c,v 1.6 2013/06/02 03:52:21 schwarze Exp $ */
+/* $Id: preconv.c,v 1.12 2014/11/14 04:24:04 schwarze Exp $ */
/*
* Copyright (c) 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
@@ -14,325 +15,132 @@
* 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
-#ifdef HAVE_MMAP
-#include <sys/stat.h>
-#include <sys/mman.h>
-#endif
+#include <sys/types.h>
-#include <assert.h>
-#include <fcntl.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+#include "mandoc.h"
+#include "libmandoc.h"
-/*
- * The read_whole_file() and resize_buf() functions are copied from
- * read.c, including all dependency code.
- */
-
-enum enc {
- ENC_UTF_8, /* UTF-8 */
- ENC_US_ASCII, /* US-ASCII */
- ENC_LATIN_1, /* Latin-1 */
- ENC__MAX
-};
-
-struct buf {
- char *buf; /* binary input buffer */
- size_t sz; /* size of binary buffer */
- size_t offs; /* starting buffer offset */
-};
-
-struct encode {
- const char *name;
- int (*conv)(const struct buf *);
-};
-
-static int cue_enc(const struct buf *, size_t *, enum enc *);
-static int conv_latin_1(const struct buf *);
-static int conv_us_ascii(const struct buf *);
-static int conv_utf_8(const struct buf *);
-static int read_whole_file(const char *, int,
- struct buf *, int *);
-static void resize_buf(struct buf *, size_t);
-static void usage(void);
-
-static const struct encode encs[ENC__MAX] = {
- { "utf-8", conv_utf_8 }, /* ENC_UTF_8 */
- { "us-ascii", conv_us_ascii }, /* ENC_US_ASCII */
- { "latin-1", conv_latin_1 }, /* ENC_LATIN_1 */
-};
-
-static const char *progname;
-
-static void
-usage(void)
-{
-
- fprintf(stderr, "usage: %s "
- "[-D enc] "
- "[-e ENC] "
- "[file]\n", progname);
-}
-
-static int
-conv_latin_1(const struct buf *b)
+int
+preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
+ int *filenc)
{
size_t i;
- unsigned char cu;
- const char *cp;
-
- cp = b->buf + (int)b->offs;
-
- /*
- * Latin-1 falls into the first 256 code-points of Unicode, so
- * there's no need for any sort of translation. Just make the
- * 8-bit characters use the Unicode escape.
- * Note that binary values 128 < v < 160 are passed through
- * unmodified to mandoc.
- */
-
- for (i = b->offs; i < b->sz; i++) {
- cu = (unsigned char)*cp++;
- cu < 160U ? putchar(cu) : printf("\\[u%.4X]", cu);
- }
-
- return(1);
-}
-
-static int
-conv_us_ascii(const struct buf *b)
-{
-
- /*
- * US-ASCII has no conversion since it falls into the first 128
- * bytes of Unicode.
- */
-
- fwrite(b->buf, 1, b->sz, stdout);
- return(1);
-}
-
-static int
-conv_utf_8(const struct buf *b)
-{
- int state, be;
+ int state;
unsigned int accum;
- size_t i;
unsigned char cu;
- const char *cp;
- const long one = 1L;
- cp = b->buf + (int)b->offs;
+ if ( ! (*filenc & MPARSE_UTF8))
+ goto latin;
+
state = 0;
accum = 0U;
- be = 0;
-
- /* Quick test for big-endian value. */
- if ( ! (*((const char *)(&one))))
- be = 1;
-
- for (i = b->offs; i < b->sz; i++) {
- cu = (unsigned char)*cp++;
+ for (i = *ii; i < ib->sz; i++) {
+ cu = ib->buf[i];
if (state) {
if ( ! (cu & 128) || (cu & 64)) {
/* Bad sequence header. */
- return(0);
+ break;
}
/* Accept only legitimate bit patterns. */
if (cu > 191 || cu < 128) {
/* Bad in-sequence bits. */
- return(0);
+ break;
}
accum |= (cu & 63) << --state * 6;
- /*
- * Accum is held in little-endian order as
- * stipulated by the UTF-8 sequence coding. We
- * need to convert to a native big-endian if our
- * architecture requires it.
- */
-
- if (0 == state && be)
- accum = (accum >> 24) |
- ((accum << 8) & 0x00FF0000) |
- ((accum >> 8) & 0x0000FF00) |
- (accum << 24);
+ if (state)
+ continue;
- if (0 == state) {
- accum < 128U ? putchar(accum) :
- printf("\\[u%.4X]", accum);
- accum = 0U;
- }
- } else if (cu & (1 << 7)) {
+ if (accum < 0x80)
+ ob->buf[(*oi)++] = accum;
+ else
+ *oi += snprintf(ob->buf + *oi,
+ 11, "\\[u%.4X]", accum);
+ *ii = i + 1;
+ *filenc &= ~MPARSE_LATIN1;
+ return(1);
+ } else {
/*
* Entering a UTF-8 state: if we encounter a
* UTF-8 bitmask, calculate the expected UTF-8
* state from it.
*/
- for (state = 0; state < 7; state++)
+ for (state = 0; state < 7; state++)
if ( ! (cu & (1 << (7 - state))))
break;
/* Accept only legitimate bit patterns. */
- switch (state) {
+ switch (state--) {
case (4):
if (cu <= 244 && cu >= 240) {
accum = (cu & 7) << 18;
- break;
+ continue;
}
/* Bad 4-sequence start bits. */
- return(0);
+ break;
case (3):
if (cu <= 239 && cu >= 224) {
accum = (cu & 15) << 12;
- break;
+ continue;
}
/* Bad 3-sequence start bits. */
- return(0);
+ break;
case (2):
if (cu <= 223 && cu >= 194) {
accum = (cu & 31) << 6;
- break;
+ continue;
}
/* Bad 2-sequence start bits. */
- return(0);
+ break;
default:
/* Bad sequence bit mask. */
- return(0);
+ break;
}
- state--;
- } else
- putchar(cu);
- }
-
- if (0 != state) {
- /* Bad trailing bits. */
- return(0);
- }
-
- return(1);
-}
-
-static void
-resize_buf(struct buf *buf, size_t initial)
-{
-
- buf->sz = buf->sz > initial / 2 ?
- 2 * buf->sz : initial;
-
- buf->buf = realloc(buf->buf, buf->sz);
- if (NULL == buf->buf) {
- perror(NULL);
- exit(EXIT_FAILURE);
+ break;
+ }
}
-}
-static int
-read_whole_file(const char *f, int fd,
- struct buf *fb, int *with_mmap)
-{
- size_t off;
- ssize_t ssz;
+ /* FALLTHROUGH: Invalid or incomplete UTF-8 sequence. */
-#ifdef HAVE_MMAP
- struct stat st;
- if (-1 == fstat(fd, &st)) {
- perror(f);
+latin:
+ if ( ! (*filenc & MPARSE_LATIN1))
return(0);
- }
- /*
- * If we're a regular file, try just reading in the whole entry
- * via mmap(). This is faster than reading it into blocks, and
- * since each file is only a few bytes to begin with, I'm not
- * concerned that this is going to tank any machines.
- */
+ *oi += snprintf(ob->buf + *oi, 11,
+ "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
- if (S_ISREG(st.st_mode) && st.st_size >= (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", f);
- return(0);
- }
-
- if (S_ISREG(st.st_mode)) {
- *with_mmap = 1;
- fb->sz = (size_t)st.st_size;
- fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
- if (fb->buf != MAP_FAILED)
- return(1);
- }
-#endif
-
- /*
- * If this isn't a regular file (like, say, stdin), then we must
- * go the old way and just read things in bit by bit.
- */
-
- *with_mmap = 0;
- off = 0;
- fb->sz = 0;
- fb->buf = NULL;
- for (;;) {
- if (off == fb->sz && fb->sz == (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", f);
- break;
- }
-
- if (off == fb->sz)
- resize_buf(fb, 65536);
-
- ssz = read(fd, fb->buf + (int)off, fb->sz - off);
- if (ssz == 0) {
- fb->sz = off;
- return(1);
- }
- if (ssz == -1) {
- perror(f);
- break;
- }
- off += (size_t)ssz;
- }
-
- free(fb->buf);
- fb->buf = NULL;
- return(0);
+ *filenc &= ~MPARSE_UTF8;
+ return(1);
}
-static int
-cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
+int
+preconv_cue(const struct buf *b, size_t offset)
{
const char *ln, *eoln, *eoph;
- size_t sz, phsz, nsz;
- int i;
+ size_t sz, phsz;
- ln = b->buf + (int)*offs;
- sz = b->sz - *offs;
+ ln = b->buf + offset;
+ sz = b->sz - offset;
/* Look for the end-of-line. */
if (NULL == (eoln = memchr(ln, '\n', sz)))
- return(-1);
-
- /* Set next-line marker. */
-
- *offs = (size_t)((eoln + 1) - b->buf);
+ eoln = ln + sz;
/* Check if we have the correct header/trailer. */
- if ((sz = (size_t)(eoln - ln)) < 10 ||
- memcmp(ln, ".\\\" -*-", 7) ||
- memcmp(eoln - 3, "-*-", 3))
- return(0);
+ if ((sz = (size_t)(eoln - ln)) < 10 ||
+ memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
+ return(MPARSE_UTF8 | MPARSE_LATIN1);
/* Move after the header and adjust for the trailer. */
@@ -356,12 +164,12 @@ cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
/* Only account for the "coding" phrase. */
- if ((phsz = (size_t)(eoph - ln)) < 7 ||
- strncasecmp(ln, "coding:", 7)) {
+ if ((phsz = eoph - ln) < 7 ||
+ strncasecmp(ln, "coding:", 7)) {
sz -= phsz;
ln += phsz;
continue;
- }
+ }
sz -= 7;
ln += 7;
@@ -371,153 +179,15 @@ cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
sz--;
}
if (0 == sz)
- break;
+ return(0);
/* Check us against known encodings. */
- for (i = 0; i < (int)ENC__MAX; i++) {
- nsz = strlen(encs[i].name);
- if (phsz < nsz)
- continue;
- if (strncasecmp(ln, encs[i].name, nsz))
- continue;
-
- *enc = (enum enc)i;
- return(1);
- }
-
- /* Unknown encoding. */
-
- *enc = ENC__MAX;
- return(1);
- }
-
- return(0);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, ch, map, fd, rc;
- struct buf b;
- const char *fn;
- enum enc enc, def;
- unsigned char bom[3] = { 0xEF, 0xBB, 0xBF };
- size_t offs;
- extern int optind;
- extern char *optarg;
-
- progname = strrchr(argv[0], '/');
- if (progname == NULL)
- progname = argv[0];
- else
- ++progname;
-
- fn = "<stdin>";
- fd = STDIN_FILENO;
- rc = EXIT_FAILURE;
- enc = def = ENC__MAX;
- map = 0;
-
- memset(&b, 0, sizeof(struct buf));
-
- while (-1 != (ch = getopt(argc, argv, "D:e:rdvh")))
- switch (ch) {
- case ('D'):
- /* FALLTHROUGH */
- case ('e'):
- for (i = 0; i < (int)ENC__MAX; i++) {
- if (strcasecmp(optarg, encs[i].name))
- continue;
- break;
- }
- if (i < (int)ENC__MAX) {
- if ('D' == ch)
- def = (enum enc)i;
- else
- enc = (enum enc)i;
- break;
- }
-
- fprintf(stderr, "%s: Bad encoding\n", optarg);
- return(EXIT_FAILURE);
- case ('r'):
- /* FALLTHROUGH */
- case ('d'):
- /* FALLTHROUGH */
- case ('v'):
- /* Compatibility with GNU preconv. */
- break;
- case ('h'):
- /* Compatibility with GNU preconv. */
- /* FALLTHROUGH */
- default:
- usage();
- return(EXIT_FAILURE);
- }
-
- argc -= optind;
- argv += optind;
-
- /*
- * Open and read the first argument on the command-line.
- * If we don't have one, we default to stdin.
- */
-
- if (argc > 0) {
- fn = *argv;
- fd = open(fn, O_RDONLY, 0);
- if (-1 == fd) {
- perror(fn);
- return(EXIT_FAILURE);
- }
- }
-
- if ( ! read_whole_file(fn, fd, &b, &map))
- goto out;
-
- /* Try to read the UTF-8 BOM. */
-
- if (ENC__MAX == enc)
- if (b.sz > 3 && 0 == memcmp(b.buf, bom, 3)) {
- b.offs = 3;
- enc = ENC_UTF_8;
- }
-
- /* Try reading from the "-*-" cue. */
-
- if (ENC__MAX == enc) {
- offs = b.offs;
- ch = cue_enc(&b, &offs, &enc);
- if (0 == ch)
- ch = cue_enc(&b, &offs, &enc);
- }
-
- /*
- * No encoding has been detected.
- * Thus, we either fall into our default encoder, if specified,
- * or use Latin-1 if all else fails.
- */
-
- if (ENC__MAX == enc)
- enc = ENC__MAX == def ? ENC_LATIN_1 : def;
-
- if ( ! (*encs[(int)enc].conv)(&b)) {
- fprintf(stderr, "%s: Bad encoding\n", fn);
- goto out;
+ if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
+ return(MPARSE_UTF8);
+ if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
+ return(MPARSE_LATIN1);
+ return(0);
}
-
- rc = EXIT_SUCCESS;
-out:
-#ifdef HAVE_MMAP
- if (map)
- munmap(b.buf, b.sz);
- else
-#endif
- free(b.buf);
-
- if (fd > STDIN_FILENO)
- close(fd);
-
- return(rc);
+ return(MPARSE_UTF8 | MPARSE_LATIN1);
}
diff --git a/read.c b/read.c
index 94668389b182..96444f59ffa2 100644
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/* $Id: read.c,v 1.79 2014/08/06 15:09:05 schwarze Exp $ */
+/* $Id: read.c,v 1.101 2014/11/28 18:09:01 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -16,14 +16,14 @@
* 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
-#ifdef HAVE_MMAP
-# include <sys/stat.h>
-# include <sys/mman.h>
+#include <sys/types.h>
+#if HAVE_MMAP
+#include <sys/mman.h>
+#include <sys/stat.h>
#endif
+#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
@@ -45,32 +45,31 @@
#define REPARSE_LIMIT 1000
-struct buf {
- char *buf; /* binary input buffer */
- size_t sz; /* size of binary buffer */
-};
-
struct mparse {
- enum mandoclevel file_status; /* status of current parse */
- enum mandoclevel wlevel; /* ignore messages below this */
- int line; /* line number in the file */
- 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) */
+ const struct mchars *mchars; /* character table */
char *sodest; /* filename pointed to by .so */
- int reparse_count; /* finite interp. stack */
- mandocmsg mmsg; /* warning/error message handler */
- const char *file;
- struct buf *secondary;
+ const char *file; /* filename of current input file */
+ struct buf *primary; /* buffer currently being parsed */
+ struct buf *secondary; /* preprocessed copy of input */
const char *defos; /* default operating system */
+ mandocmsg mmsg; /* warning/error message handler */
+ enum mandoclevel file_status; /* status of current parse */
+ enum mandoclevel wlevel; /* ignore messages below this */
+ int options; /* parser options */
+ int filenc; /* encoding of the current file */
+ int reparse_count; /* finite interp. stack */
+ int line; /* line number in the file */
+ pid_t child; /* the gunzip(1) process */
};
+static void choose_parser(struct mparse *);
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 void mparse_buf_r(struct mparse *, struct buf, size_t, int);
static int read_whole_file(struct mparse *, const char *, int,
struct buf *, int *);
static void mparse_end(struct mparse *);
@@ -98,7 +97,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"lower case character in document title",
"missing manual section, using \"\"",
"unknown manual section",
- "unknown manual volume or arch",
"missing date, using today's date",
"cannot parse date, using it verbatim",
"missing Os macro, using \"\"",
@@ -116,6 +114,9 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"sections out of conventional order",
"duplicate section title",
"unexpected section",
+ "unusual Xr order",
+ "unusual Xr punctuation",
+ "AUTHORS section without An macro",
/* related to macros and nesting */
"obsolete macro",
@@ -145,6 +146,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"missing font type, using \\fR",
"unknown font type, using \\fR",
"missing -std argument, adding it",
+ "missing eqn box, using \"\"",
/* related to bad macro arguments */
"unterminated quoted argument",
@@ -154,6 +156,8 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"skipping duplicate list type",
"skipping -width argument",
"unknown AT&T UNIX version",
+ "comma in function argument",
+ "parenthesis in function name",
"invalid content in Rs block",
"invalid Boolean argument",
"unknown font, skipping request",
@@ -173,7 +177,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"equation scope open on exit",
"overlapping equation scopes",
"unexpected end of equation",
- "equation syntax error",
/* related to tables */
"bad table syntax",
@@ -198,6 +201,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
/* related to request and macro arguments */
"escaped character not allowed in a name",
"argument count wrong",
+ "NOT IMPLEMENTED: Bd -file",
"missing list type, using -item",
"missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN",
@@ -205,18 +209,25 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"skipping request without numeric argument",
"skipping all arguments",
"skipping excess arguments",
+ "divide by zero",
"generic fatal error",
"input too large",
- "NOT IMPLEMENTED: Bd -file",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
".so request failed",
/* system errors */
+ "cannot dup file descriptor",
+ "cannot exec",
+ "gunzip failed with code",
+ "cannot fork",
NULL,
- "cannot stat file",
+ "cannot open pipe",
"cannot read file",
+ "gunzip died from signal",
+ "cannot stat file",
+ "wait failed",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
@@ -239,38 +250,40 @@ resize_buf(struct buf *buf, size_t initial)
}
static void
-pset(const char *buf, int pos, struct mparse *curp)
+choose_parser(struct mparse *curp)
{
- int i;
+ char *cp, *ep;
+ int format;
/*
- * Try to intuit which kind of manual parser should be used. If
- * passed in by command-line (-man, -mdoc), then use that
- * explicitly. If passed as -mandoc, then try to guess from the
- * line: either skip dot-lines, use -mdoc when finding `.Dt', or
- * default to -man, which is more lenient.
- *
- * Separate out pmdoc/pman from mdoc/man: the first persists
- * through all parsers, while the latter is used per-parse.
+ * If neither command line arguments -mdoc or -man select
+ * a parser nor the roff parser found a .Dd or .TH macro
+ * yet, look ahead in the main input buffer.
*/
- if ('.' == buf[0] || '\'' == buf[0]) {
- for (i = 1; buf[i]; i++)
- if (' ' != buf[i] && '\t' != buf[i])
+ if ((format = roff_getformat(curp->roff)) == 0) {
+ cp = curp->primary->buf;
+ ep = cp + curp->primary->sz;
+ while (cp < ep) {
+ if (*cp == '.' || *cp == '\'') {
+ cp++;
+ if (cp[0] == 'D' && cp[1] == 'd') {
+ format = MPARSE_MDOC;
+ break;
+ }
+ if (cp[0] == 'T' && cp[1] == 'H') {
+ format = MPARSE_MAN;
+ break;
+ }
+ }
+ cp = memchr(cp, '\n', ep - cp);
+ if (cp == NULL)
break;
- if ('\0' == buf[i])
- return;
- }
-
- if (MPARSE_MDOC & curp->options) {
- curp->mdoc = curp->pmdoc;
- return;
- } else if (MPARSE_MAN & curp->options) {
- curp->man = curp->pman;
- return;
+ cp++;
+ }
}
- if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
+ if (format == MPARSE_MDOC) {
if (NULL == curp->pmdoc)
curp->pmdoc = mdoc_alloc(
curp->roff, curp, curp->defos,
@@ -280,6 +293,8 @@ pset(const char *buf, int pos, struct mparse *curp)
return;
}
+ /* Fall back to man(7) as a last resort. */
+
if (NULL == curp->pman)
curp->pman = man_alloc(curp->roff, curp,
MPARSE_QUICK & curp->options ? 1 : 0);
@@ -288,36 +303,43 @@ pset(const char *buf, int pos, struct mparse *curp)
}
/*
- * Main parse routine for an opened file. This is called for each
- * opened file and simply loops around the full input file, possibly
- * nesting (i.e., with `so').
+ * Main parse routine for a buffer.
+ * It assumes encoding and line numbering are already set up.
+ * It can recurse directly (for invocations of user-defined
+ * macros, inline equations, and input line traps)
+ * and indirectly (for .so file inclusion).
*/
static void
-mparse_buf_r(struct mparse *curp, struct buf blk, int start)
+mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
const struct tbl_span *span;
struct buf ln;
+ size_t pos; /* byte number in the ln buffer */
enum rofferr rr;
- int i, of, rc;
- int pos; /* byte number in the ln buffer */
+ int of;
int lnn; /* line number in the real file */
unsigned char c;
- memset(&ln, 0, sizeof(struct buf));
+ memset(&ln, 0, sizeof(ln));
lnn = curp->line;
pos = 0;
- for (i = 0; i < (int)blk.sz; ) {
+ while (i < blk.sz) {
if (0 == pos && '\0' == blk.buf[i])
break;
if (start) {
curp->line = lnn;
curp->reparse_count = 0;
+
+ if (lnn < 3 &&
+ curp->filenc & MPARSE_UTF8 &&
+ curp->filenc & MPARSE_LATIN1)
+ curp->filenc = preconv_cue(&blk, i);
}
- while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
+ while (i < blk.sz && (start || blk.buf[i] != '\0')) {
/*
* When finding an unescaped newline character,
@@ -325,7 +347,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
* Skip a preceding carriage return, if any.
*/
- if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
+ if ('\r' == blk.buf[i] && i + 1 < blk.sz &&
'\n' == blk.buf[i + 1])
++i;
if ('\n' == blk.buf[i]) {
@@ -335,27 +357,35 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
}
/*
- * Make sure we have space for at least
- * one backslash and one other character
- * and the trailing NUL byte.
+ * Make sure we have space for the worst
+ * case of 11 bytes: "\\[u10ffff]\0"
*/
- if (pos + 2 >= (int)ln.sz)
+ if (pos + 11 > 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,
- * I'll be helpful and replace these characters
- * with "?", so we don't display gibberish.
- * Note to manual writers: use special characters.
+ * Encode 8-bit input.
*/
- c = (unsigned char) blk.buf[i];
+ c = blk.buf[i];
+ if (c & 0x80) {
+ if ( ! (curp->filenc && preconv_encode(
+ &blk, &i, &ln, &pos, &curp->filenc))) {
+ mandoc_vmsg(MANDOCERR_BADCHAR,
+ curp, curp->line, pos,
+ "0x%x", c);
+ ln.buf[pos++] = '?';
+ i++;
+ }
+ continue;
+ }
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
+ /*
+ * Exclude control characters.
+ */
+
+ if (c == 0x7f || (c < 0x20 && c != 0x09)) {
mandoc_vmsg(MANDOCERR_BADCHAR, curp,
curp->line, pos, "0x%x", c);
i++;
@@ -365,7 +395,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
/* Trailing backslash = a plain char. */
- if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
+ if (blk.buf[i] != '\\' || i + 1 == blk.sz) {
ln.buf[pos++] = blk.buf[i++];
continue;
}
@@ -377,7 +407,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
* skip that one as well.
*/
- if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
+ if ('\r' == blk.buf[i + 1] && i + 2 < blk.sz &&
'\n' == blk.buf[i + 2])
++i;
if ('\n' == blk.buf[i + 1]) {
@@ -389,7 +419,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
i += 2;
/* Comment, skip to end of line */
- for (; i < (int)blk.sz; ++i) {
+ for (; i < blk.sz; ++i) {
if ('\n' == blk.buf[i]) {
++i;
++lnn;
@@ -426,7 +456,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 >= ln.sz)
resize_buf(&ln, 256);
ln.buf[pos] = '\0';
@@ -463,20 +493,19 @@ 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, &of);
switch (rr) {
case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count)
- mparse_buf_r(curp, ln, 0);
+ mparse_buf_r(curp, ln, of, 0);
else
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
curp->line, pos, NULL);
pos = 0;
continue;
case ROFF_APPEND:
- pos = (int)strlen(ln.buf);
+ pos = strlen(ln.buf);
continue;
case ROFF_RERUN:
goto rerun;
@@ -487,8 +516,8 @@ rerun:
assert(MANDOCLEVEL_FATAL <= curp->file_status);
break;
case ROFF_SO:
- if (0 == (MPARSE_SO & curp->options) &&
- (i >= (int)blk.sz || '\0' == blk.buf[i])) {
+ if ( ! (curp->options & MPARSE_SO) &&
+ (i >= blk.sz || blk.buf[i] == '\0')) {
curp->sodest = mandoc_strdup(ln.buf + of);
free(ln.buf);
return;
@@ -529,12 +558,10 @@ rerun:
*/
if ( ! (curp->man || curp->mdoc))
- pset(ln.buf + of, pos - of, curp);
+ choose_parser(curp);
/*
- * Lastly, push down into the parsers themselves. One
- * of these will have already been set in the pset()
- * routine.
+ * Lastly, push down into the parsers themselves.
* If libroff returns ROFF_TBL, then add it to the
* currently open parse. Since we only get here if
* there does exist data (see tbl_data.c), we're
@@ -542,34 +569,21 @@ rerun:
* Do the same for ROFF_EQN.
*/
- rc = -1;
-
- if (ROFF_TBL == rr)
- while (NULL != (span = roff_span(curp->roff))) {
- rc = curp->man ?
- 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));
- else if (curp->man || curp->mdoc)
- rc = curp->man ?
- man_parseln(curp->man,
- curp->line, ln.bu