Import CVS version of mandoc as of 20141201

This commit is contained in:
Baptiste Daroussin 2014-12-02 07:34:06 +00:00
parent 52c0e9552d
commit 81bffeeaab
109 changed files with 8344 additions and 5612 deletions

93
INSTALL
View File

@ -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

View File

@ -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.

194
Makefile
View File

@ -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
MAN_OBJS = $(MANDOC_OBJS)
MAKEWHATIS_OBJS = mandocdb.o mansearch_const.o manpath.o
PRECONV_OBJS = preconv.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

View File

@ -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

5
NEWS
View File

@ -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.

176
TODO
View File

@ -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.

133
apropos.1
View File

@ -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 .
.Nm whatis
maps terms only to case-sensitive manual names.
.Pp
Its arguments are as follows:
.Nm whatis
is a synonym for
.Nm
.Fl f .
.Pp
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

123
apropos.c
View File

@ -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);
}

112
arch.in
View File

@ -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")

22
att.c
View File

@ -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);
}

40
att.in
View File

@ -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")

133
cgi.c
View File

@ -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 @@ http_parse(struct req *req, const char *qs)
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);

53
chars.c
View File

@ -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)
{

230
chars.in
View File

@ -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

View File

@ -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>

826
compat_fts.c Normal file
View File

@ -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

106
compat_fts.h Normal file
View File

@ -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_ */

View File

@ -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;

View File

@ -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>

View File

@ -1,8 +1,6 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_REALLOCARRAY
#if HAVE_REALLOCARRAY
int dummy;

View File

@ -1,8 +1,6 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SQLITE3_ERRSTR
#if HAVE_SQLITE3_ERRSTR
int dummy;

View File

@ -1,8 +1,6 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRCASESTR
#if HAVE_STRCASESTR
int dummy;

View File

@ -1,8 +1,6 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRLCAT
#if HAVE_STRLCAT
int dummy;

View File

@ -1,8 +1,6 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRLCPY
#if HAVE_STRLCPY
int dummy;

View File

@ -1,8 +1,6 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRSEP
#if HAVE_STRSEP
int dummy;

View File

@ -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 */

View File

@ -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>

390
configure vendored
View File

@ -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
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}"
# 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
}
cat config.h.pre
# 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() {
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
}
# --- 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

189
configure.local.example Normal file
View File

@ -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

View File

@ -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

View File

@ -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);
}

250
eqn.7
View File

@ -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 ,

1388
eqn.c

File diff suppressed because it is too large Load Diff

View File

@ -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;
static void eqn_box(struct html *, const struct eqn_box *);
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);
}
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);
}

View File

@ -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, "_");
}
}

View File

@ -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; }

159
html.c
View File

@ -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
@ -649,6 +618,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]);
}

43
html.h
View File

@ -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)))

6
lib.c
View File

@ -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>

View File

@ -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

View File

@ -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 *);

View File

@ -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

View File

@ -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,

539
main.c
View File

@ -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. */
options = MPARSE_SO;
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. */
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;
}
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
/*
* 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;
}
}
/*
* 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;
rc = MANDOCLEVEL_OK;
if (NULL == *argv)
if (argc == 0)
parse(&curp, STDIN_FILENO, "<stdin>", &rc);
while (*argv) {
parse(&curp, -1, *argv, &rc);
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 (mparse_wait(curp.mp) != MANDOCLEVEL_OK)
rc = MANDOCLEVEL_SYSERR;
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);
}

15
main.h
View File

@ -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 *);

View File

@ -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

402
man.1 Normal file
View File

@ -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 .

246
man.c
View File

@ -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_node_append(man, p);
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->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);
if ( ! man_node_append(man, n))
return(0);
man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
}
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. */
while (buf[offs] && ' ' == 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. */
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;

View File

@ -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.

3
man.h
View File

@ -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
};

View File

@ -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>

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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);
typedef void (*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 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 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);
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);
}

254
mandoc.1
View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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 @@ dbopen(int real)
"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;

View File

@ -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)

View File

@ -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);

View File

@ -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 @@ mansearch(const struct mansearch *search,
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));

View File

@ -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 */

View File

@ -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"

View File

@ -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

175
mdoc.7
View File

@ -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 .

229
mdoc.c
View File

@ -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. */

View File

@ -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.
*/
memset(&tmp, 0, sizeof(struct mdoc_argv));
tmp.line = line;
tmp.pos = *pos;
tmp.arg = MDOC_ARG_MAX;
while (MDOC_ARG_MAX != (tmp.arg = *ap++))
if (0 == strcmp(p, mdoc_argnames[tmp.arg]))
break;
if (MDOC_ARG_MAX == tmp.arg) {
/*
* The flag was not found.
* Restore saved zeroed byte and return as a word.
* 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 (sv)
buf[*pos - 1] = sv;
return(ARGV_WORD);
if ((savechar = buf[ipos]) != '\0')
buf[ipos++] = '\0';
/*
* 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;
/* If it isn't a flag, restore the saved byte. */
if (tmpv.arg == MDOC_ARG_MAX) {
if (savechar != '\0')
buf[ipos - 1] = savechar;
break;
}
/* Read to the next word (the first argument). */
while (buf[ipos] == ' ')
ipos++;
/* Parse the arguments of the flag. */
tmpv.line = line;
tmpv.pos = ipos;
tmpv.sz = 0;
tmpv.value = NULL;
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));
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;
}
/* 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;
}
if (NULL == (arg = *v))
arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
arg->argc++;
arg->argv = mandoc_reallocarray(arg->argv,
arg->argc, sizeof(struct mdoc_argv));
memcpy(&arg->argv[(int)arg->argc - 1], &tmp,
sizeof(struct mdoc_argv));
return(ARGV_ARG);
}
void
@ -408,23 +411,18 @@ argn_free(struct mdoc_arg *p, int iarg)
p->argv[iarg] = p->argv[iarg+1];
}
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);
}

View File

@ -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>

View File

@ -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,13 +1881,23 @@ 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);
return(1);
}
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)
{
@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
@ -865,6 +872,25 @@ pre_ap(DECL_ARGS)
return(0);
}
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,21 +1124,22 @@ post_en(DECL_ARGS)
return;
}
static int
pre_eo(DECL_ARGS)
{
outflags &= ~(MMAN_spc | MMAN_nl);
return(1);
}
static void
post_eo(DECL_ARGS)
{
if (MDOC_HEAD == n->type || MDOC_BODY == n->type)
if (n->end != ENDBODY_SPACE)
outflags &= ~MMAN_spc;
}
static int
pre_es(DECL_ARGS)
{
return(0);
}
static int
pre_fa(DECL_ARGS)
{
@ -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();
@ -1649,6 +1679,13 @@ pre_rv(DECL_ARGS)
return(0);
}
static int
pre_skip(DECL_ARGS)
{
return(0);
}
static int
pre_sm(DECL_ARGS)
{

View File

@ -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)
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 (MDOC_Sh == nn->tok)
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 */

File diff suppressed because it is too large Load Diff

6
msec.c
View File

@ -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>

View File

@ -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")

80
out.c
View File

@ -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

8
out.h
View File

@ -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

157
preconv.1
View File

@ -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.

460
preconv.c
View File

@ -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 (state)
continue;
if (0 == state && be)
accum = (accum >> 24) |
((accum << 8) & 0x00FF0000) |
((accum >> 8) & 0x0000FF00) |
(accum << 24);
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);
break;
}
}
if (0 != state) {
/* Bad trailing bits. */
/* FALLTHROUGH: Invalid or incomplete UTF-8 sequence. */
latin:
if ( ! (*filenc & MPARSE_LATIN1))
return(0);
}
*oi += snprintf(ob->buf + *oi, 11,
"\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
*filenc &= ~MPARSE_UTF8;
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);
}
}
static int
read_whole_file(const char *f, int fd,
struct buf *fb, int *with_mmap)
{
size_t off;
ssize_t ssz;
#ifdef HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
perror(f);
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.
*/
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);
}
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);
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);
}
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;
}
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);
}

430
read.c
View File

@ -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;
cp++;
}
}
if (MPARSE_MDOC & curp->options) {
curp->mdoc = curp->pmdoc;
return;
} else if (MPARSE_MAN & curp->options) {
curp->man = curp->pman;
return;
}
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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
*/
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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
* 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.buf, of) :
mdoc_parseln(curp->mdoc,
curp->line, ln.buf, of);
if (0 == rc) {
assert(MANDOCLEVEL_FATAL <= curp->file_status);
break;
} else if (2 == rc)
break;
if (rr == ROFF_TBL) {
while ((span = roff_span(curp->roff)) != NULL)
if (curp->man == NULL)
mdoc_addspan(curp->mdoc, span);
else
man_addspan(curp->man, span);
} else if (rr == ROFF_EQN) {
if (curp->man == NULL)
mdoc_addeqn(curp->mdoc, roff_eqn(curp->roff));
else
man_addeqn(curp->man, roff_eqn(curp->roff));
} else if ((curp->man == NULL ?
mdoc_parseln(curp->mdoc, curp->line, ln.buf, of) :
man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
break;
/* Temporary buffers typically are not full. */
@ -591,7 +605,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
size_t off;
ssize_t ssz;
#ifdef HAVE_MMAP
#if HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
curp->file_status = MANDOCLEVEL_SYSERR;
@ -702,7 +716,9 @@ mparse_end(struct mparse *curp)
static void
mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
{
struct buf *svprimary;
const char *svfile;
size_t offset;
static int recursion_depth;
if (64 < recursion_depth) {
@ -713,14 +729,27 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
/* Line number is per-file. */
svfile = curp->file;
curp->file = file;
svprimary = curp->primary;
curp->primary = &blk;
curp->line = 1;
recursion_depth++;
mparse_buf_r(curp, blk, 1);
/* Skip an UTF-8 byte order mark. */
if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
(unsigned char)blk.buf[0] == 0xef &&
(unsigned char)blk.buf[1] == 0xbb &&
(unsigned char)blk.buf[2] == 0xbf) {
offset = 3;
curp->filenc &= ~MPARSE_LATIN1;
} else
offset = 0;
mparse_buf_r(curp, blk, offset, 1);
if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
mparse_end(curp);
curp->primary = svprimary;
curp->file = svfile;
}
@ -737,49 +766,159 @@ mparse_readmem(struct mparse *curp, const void *buf, size_t len,
return(curp->file_status);
}
/*
* If a file descriptor is given, use it and assume it points
* to the named file. Otherwise, open the named file.
* Read the whole file into memory and call the parsers.
* Called recursively when an .so request is encountered.
*/
enum mandoclevel
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
struct buf blk;
int with_mmap;
int save_filenc;
pid_t save_child;
if (-1 == fd && -1 == (fd = open(file, O_RDONLY, 0))) {
curp->file_status = MANDOCLEVEL_SYSERR;
if (curp->mmsg)
(*curp->mmsg)(MANDOCERR_SYSOPEN,
curp->file_status,
file, 0, 0, strerror(errno));
save_child = curp->child;
if (fd != -1)
curp->child = 0;
else if (mparse_open(curp, &fd, file) >= MANDOCLEVEL_SYSERR)
goto out;
if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
save_filenc = curp->filenc;
curp->filenc = curp->options &
(MPARSE_UTF8 | MPARSE_LATIN1);
mparse_parse_buffer(curp, blk, file);
curp->filenc = save_filenc;
#if HAVE_MMAP
if (with_mmap)
munmap(blk.buf, blk.sz);
else
#endif
free(blk.buf);
}
/*
* Run for each opened file; may be called more than once for
* each full parse sequence if the opened file is nested (i.e.,
* from `so'). Simply sucks in the whole file and moves into
* the parse phase for the file.
*/
if ( ! read_whole_file(curp, file, fd, &blk, &with_mmap))
goto out;
mparse_parse_buffer(curp, blk, file);
#ifdef HAVE_MMAP
if (with_mmap)
munmap(blk.buf, blk.sz);
else
#endif
free(blk.buf);
if (STDIN_FILENO != fd && -1 == close(fd))
if (fd != STDIN_FILENO && close(fd) == -1)
perror(file);
mparse_wait(curp);
out:
curp->child = save_child;
return(curp->file_status);
}
enum mandoclevel
mparse_open(struct mparse *curp, int *fd, const char *file)
{
int pfd[2];
int save_errno;
char *cp;
enum mandocerr err;
pfd[1] = -1;
curp->file = file;
/* Unless zipped, try to just open the file. */
if ((cp = strrchr(file, '.')) == NULL ||
strcmp(cp + 1, "gz")) {
curp->child = 0;
if ((*fd = open(file, O_RDONLY)) != -1)
return(MANDOCLEVEL_OK);
/* Open failed; try to append ".gz". */
mandoc_asprintf(&cp, "%s.gz", file);
file = cp;
} else
cp = NULL;
/* Before forking, make sure the file can be read. */
save_errno = errno;
if (access(file, R_OK) == -1) {
if (cp != NULL)
errno = save_errno;
err = MANDOCERR_SYSOPEN;
goto out;
}
/* Run gunzip(1). */
if (pipe(pfd) == -1) {
err = MANDOCERR_SYSPIPE;
goto out;
}
switch (curp->child = fork()) {
case -1:
err = MANDOCERR_SYSFORK;
close(pfd[0]);
close(pfd[1]);
pfd[1] = -1;
break;
case 0:
close(pfd[0]);
if (dup2(pfd[1], STDOUT_FILENO) == -1) {
err = MANDOCERR_SYSDUP;
break;
}
execlp("gunzip", "gunzip", "-c", file, NULL);
err = MANDOCERR_SYSEXEC;
break;
default:
close(pfd[1]);
*fd = pfd[0];
return(MANDOCLEVEL_OK);
}
out:
free(cp);
*fd = -1;
curp->child = 0;
curp->file_status = MANDOCLEVEL_SYSERR;
if (curp->mmsg)
(*curp->mmsg)(err, curp->file_status, curp->file,
0, 0, strerror(errno));
if (pfd[1] != -1)
exit(1);
return(curp->file_status);
}
enum mandoclevel
mparse_wait(struct mparse *curp)
{
int status;
if (curp->child == 0)
return(MANDOCLEVEL_OK);
if (waitpid(curp->child, &status, 0) == -1) {
mandoc_msg(MANDOCERR_SYSWAIT, curp, 0, 0,
strerror(errno));
curp->file_status = MANDOCLEVEL_SYSERR;
return(curp->file_status);
}
if (WIFSIGNALED(status)) {
mandoc_vmsg(MANDOCERR_SYSSIG, curp, 0, 0,
"%d", WTERMSIG(status));
curp->file_status = MANDOCLEVEL_SYSERR;
return(curp->file_status);
}
if (WEXITSTATUS(status)) {
mandoc_vmsg(MANDOCERR_SYSEXIT, curp, 0, 0,
"%d", WEXITSTATUS(status));
curp->file_status = MANDOCLEVEL_SYSERR;
return(curp->file_status);
}
return(MANDOCLEVEL_OK);
}
struct mparse *
mparse_alloc(int options, enum mandoclevel wlevel,
mandocmsg mmsg, const char *defos)
mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
const struct mchars *mchars, const char *defos)
{
struct mparse *curp;
@ -792,7 +931,8 @@ mparse_alloc(int options, enum mandoclevel wlevel,
curp->mmsg = mmsg;
curp->defos = defos;
curp->roff = roff_alloc(curp, options);
curp->mchars = mchars;
curp->roff = roff_alloc(curp, curp->mchars, options);
if (curp->options & MPARSE_MDOC)
curp->pmdoc = mdoc_alloc(
curp->roff, curp, curp->defos,

27
roff.7
View File

@ -1,4 +1,4 @@
.\" $Id: roff.7,v 1.55 2014/07/07 11:35:06 schwarze Exp $
.\" $Id: roff.7,v 1.59 2014/11/19 01:20:25 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013, 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: July 7 2014 $
.Dd $Mdocdate: November 19 2014 $
.Dt ROFF 7
.Os
.Sh NAME
@ -239,8 +239,9 @@ pica (~1/6 inch)
.It p
point (~1/72 inch)
.It f
synonym for
scale
.Sq u
by 65536
.It v
default vertical span
.It m
@ -254,7 +255,7 @@ width of rendered
.Pq en
character
.It u
default horizontal span
default horizontal span for the terminal
.It M
mini-em (~1/100 em)
.El
@ -262,7 +263,6 @@ mini-em (~1/100 em)
Using anything other than
.Sq m ,
.Sq n ,
.Sq u ,
or
.Sq v
is necessarily non-portable across output media.
@ -747,16 +747,18 @@ If the first character of COND is
.Pq even page ,
.Sq r
.Pq register accessed ,
or
.Sq t
.Pq troff mode ,
or
.Sq v
.Pq vroff mode ,
COND evaluates to false.
.It
If COND starts with a parenthesis or with an optionally signed
integer number, it is evaluated according to the rules of
.Sx Numerical expressions
explained below.
It evaluates to true if the the result is positive,
It evaluates to true if the result is positive,
or to false if the result is zero or negative.
.It
Otherwise, the first character of COND is regarded as a delimiter
@ -935,6 +937,11 @@ Turn on no-space mode.
This line-scoped request is intended to take no arguments.
Currently, it is ignored including its arguments,
and the number of arguments is not checked.
.Ss \&pl
Change page length.
This line-scoped request is intended to take one height argument.
Currently, it is ignored including its arguments,
and the number of arguments is not checked.
.Ss \&ps
Change point size.
This line-scoped request is intended to take one numerical argument.
@ -1348,6 +1355,12 @@ refers to groff version 1.15.
.Pp
.Bl -dash -compact
.It
The
.Sq u
scaling unit is the default terminal unit.
In traditional troff systems, this unit would change depending on the
output media.
.It
In mandoc, the
.Sx \&EQ ,
.Sx \&TE ,

509
roff.c

File diff suppressed because it is too large Load Diff

6
st.c
View File

@ -1,4 +1,4 @@
/* $Id: st.c,v 1.10 2014/03/23 11:25:26 schwarze Exp $ */
/* $Id: st.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>

9
st.in
View File

@ -1,4 +1,4 @@
/* $Id: st.in,v 1.24 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: st.in,v 1.26 2014/11/16 20:46:21 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -42,13 +42,9 @@ LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
LINE("-p1003.1d-99", "IEEE Std 1003.1d-1999 (\\(lqPOSIX.1d\\(rq)")
LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
LINE("-p1003.1j-2000", "IEEE Std 1003.1j-2000 (\\(lqPOSIX.1j\\(rq)")
LINE("-p1003.1q-2000", "IEEE Std 1003.1q-2000 (\\(lqPOSIX.1q\\(rq)")
LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)")
LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)")
LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
@ -76,8 +72,9 @@ LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\
LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
LINE("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)")
LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
LINE("-susv1", "Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
LINE("-susv4", "Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")

View File

@ -1,4 +1,4 @@
/* $Id: style.css,v 1.25 2011/08/26 09:03:17 kristaps Exp $ */
/* $Id: style.css,v 1.30 2014/09/27 11:16:24 kristaps Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
@ -20,16 +20,17 @@ blockquote { margin-left: 5ex; margin-top: 0ex; margin-bottom: 0ex; } /* D1. */
div.section { margin-bottom: 2ex; margin-left: 5ex; } /* Sections (Sh, SH). */
div.subsection { } /* Sub-sections (Ss, SS). */
table.synopsis { } /* SYNOPSIS section table. */
div.spacer { margin: 1em 0; }
/* Preamble structure. */
table.foot { font-size: smaller; margin-top: 1em; border-top: 1px dotted #dddddd; } /* Document footer. */
td.foot-date { width: 50%; } /* Document footer: date. */
td.foot-os { width: 50%; text-align: right; } /* Document footer: OS/source. */
td.foot-os { width: 50%; } /* Document footer: OS/source. */
table.head { font-size: smaller; margin-bottom: 1em; border-bottom: 1px dotted #dddddd; } /* Document header. */
td.head-ltitle { width: 10%; } /* Document header: left-title. */
td.head-vol { width: 80%; text-align: center; } /* Document header: volume. */
td.head-rtitle { width: 10%; text-align: right; } /* Document header: right-title. */
td.head-vol { width: 80%; } /* Document header: volume. */
td.head-rtitle { width: 10%; } /* Document header: right-title. */
/* General font modes. */

62
tbl.7
View File

@ -1,6 +1,7 @@
.\" $Id: tbl.7,v 1.18 2013/09/16 22:39:19 schwarze Exp $
.\" $Id: tbl.7,v 1.21 2014/11/26 17:51:55 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -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: September 16 2013 $
.Dd $Mdocdate: November 26 2014 $
.Dt TBL 7
.Os
.Sh NAME
@ -134,6 +135,7 @@ in the case of
.Ss Options
The first line of a table consists of space-separated option keys and
modifiers terminated by a semicolon.
For GNU compatibility, option keys can also be separated by commas.
If the first line does not have a terminating semicolon, it is assumed
that no options are specified and instead a
.Sx Layout
@ -195,7 +197,7 @@ Each layout line corresponds to a line of data; the last layout line
applies to all remaining data lines.
Layout lines may also be separated by a comma.
Each layout cell consists of one of the following case-insensitive keys:
.Bl -tag -width Ds
.Bl -tag -width 2n
.It Cm c
Centre a literal string within its column.
.It Cm r
@ -244,35 +246,45 @@ Keys may be followed by a set of modifiers.
A modifier is either a modifier key or a natural number for specifying
the minimum width of a column.
The following case-insensitive modifier keys are available:
.Cm z ,
.Cm u ,
.Cm e ,
.Cm t ,
.Bl -tag -width 2n
.It Cm b
Use a bold font for the contents of this column.
.It Cm e
Make this column wider to match the maximum width
of any other column also having the
.Cm e
modifier.
.It Cm f
The next character selects the font to use for this column.
See the
.Xr roff 7
manual for supported one-character font names.
.It Cm i
Use an italic font for the contents of this column.
.It Cm x
After determining the width of all other columns, distribute the
rest of the line length among all columns having the
.Cm x
modifier.
.It Cm z
Do not use this cell for determining the width of this column.
.El
.Pp
The modifiers
.Cm d ,
.Cm b ,
.Cm i ,
.Cm r ,
.Cm t ,
.Cm u ,
and
.Cm f
.Po
followed by
.Cm b ,
.Cm i ,
.Cm r ,
.Cm 3 ,
.Cm 2 ,
or
.Cm 1
.Pc .
All of these are ignored by
.Cm w
are ignored by
.Xr mandoc 1 .
.Pp
For example, the following layout specifies a centre-justified column of
minimum width 10, followed by vertical bar, followed by a left-justified
column of minimum width 10, another vertical bar, then a column
justified about the decimal point in numbers:
column of minimum width 10, another vertical bar, then a column using
bold font justified about the decimal point in numbers:
.Pp
.Dl c10 | l10 | n
.Dl c10 | l10 | nfB
.Ss Data
The data section follows the last layout row.
By default, cells in a data section are delimited by a tab.

6
tbl.c
View File

@ -1,4 +1,4 @@
/* $Id: tbl.c,v 1.29 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: tbl.c,v 1.30 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 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 <stdio.h>

View File

@ -1,4 +1,4 @@
/* $Id: tbl_data.c,v 1.31 2014/04/23 16:08:33 schwarze Exp $ */
/* $Id: tbl_data.c,v 1.32 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 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 <ctype.h>

View File

@ -1,4 +1,4 @@
/* $Id: tbl_html.c,v 1.11 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: tbl_html.c,v 1.13 2014/10/14 02:16:06 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 <stdio.h>
@ -57,7 +57,7 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
if (TBL_SPAN_FIRST & sp->flags) {
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
tblcalc(&h->tbl, sp);
tblcalc(&h->tbl, sp, 0);
}
assert(NULL == h->tblt);

View File

@ -1,4 +1,4 @@
/* $Id: tbl_layout.c,v 1.26 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: tbl_layout.c,v 1.30 2014/11/25 21:41:47 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014 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 <ctype.h>
#include <stdlib.h>
@ -59,7 +59,6 @@ static int mods(struct tbl_node *, struct tbl_cell *,
int, const char *, int *);
static int cell(struct tbl_node *, struct tbl_row *,
int, const char *, int *);
static void row(struct tbl_node *, int, const char *, int *);
static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
enum tbl_cellt, int vert);
@ -168,6 +167,9 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
goto mod;
case 'w': /* XXX for now, ignore minimal column width */
goto mod;
case 'x':
cp->flags |= TBL_CELL_WMAX;
goto mod;
case 'f':
break;
case 'r':
@ -201,6 +203,11 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
default:
break;
}
if (isalnum((unsigned char)p[*pos - 1])) {
mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
ln, *pos - 1, "TS f%c", p[*pos - 1]);
goto mod;
}
mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
ln, *pos - 1, NULL);
@ -292,68 +299,54 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos));
}
static void
row(struct tbl_node *tbl, int ln, const char *p, int *pos)
{
struct tbl_row *rp;
row: /*
* EBNF describing this section:
*
* row ::= row_list [:space:]* [.]?[\n]
* row_list ::= [:space:]* row_elem row_tail
* row_tail ::= [:space:]*[,] row_list |
* epsilon
* row_elem ::= [\t\ ]*[:alpha:]+
*/
rp = mandoc_calloc(1, sizeof(struct tbl_row));
if (tbl->last_row)
tbl->last_row->next = rp;
else
tbl->first_row = rp;
tbl->last_row = rp;
cell:
while (isspace((unsigned char)p[*pos]))
(*pos)++;
/* Safely exit layout context. */
if ('.' == p[*pos]) {
tbl->part = TBL_PART_DATA;
if (NULL == tbl->first_row)
mandoc_msg(MANDOCERR_TBLNOLAYOUT,
tbl->parse, ln, *pos, NULL);
(*pos)++;
return;
}
/* End (and possibly restart) a row. */
if (',' == p[*pos]) {
(*pos)++;
goto row;
} else if ('\0' == p[*pos])
return;
if ( ! cell(tbl, rp, ln, p, pos))
return;
goto cell;
/* NOTREACHED */
}
int
tbl_layout(struct tbl_node *tbl, int ln, const char *p)
{
struct tbl_row *rp;
int pos;
pos = 0;
row(tbl, ln, p, &pos);
rp = NULL;
/* Always succeed. */
return(1);
for (;;) {
/* Skip whitespace before and after each cell. */
while (isspace((unsigned char)p[pos]))
pos++;
switch (p[pos]) {
case ',': /* Next row on this input line. */
pos++;
rp = NULL;
continue;
case '\0': /* Next row on next input line. */
return(1);
case '.': /* End of layout. */
pos++;
tbl->part = TBL_PART_DATA;
if (tbl->first_row != NULL)
return(1);
mandoc_msg(MANDOCERR_TBLNOLAYOUT,
tbl->parse, ln, pos, NULL);
rp = mandoc_calloc(1, sizeof(*rp));
cell_alloc(tbl, rp, TBL_CELL_LEFT, 0);
tbl->first_row = tbl->last_row = rp;
return(1);
default: /* Cell. */
break;
}
if (rp == NULL) { /* First cell on this line. */
rp = mandoc_calloc(1, sizeof(*rp));
if (tbl->last_row)
tbl->last_row->next = rp;
else
tbl->first_row = rp;
tbl->last_row = rp;
}
if ( ! cell(tbl, rp, ln, p, &pos))
return(1);
}
}
static struct tbl_cell *

View File

@ -1,4 +1,4 @@
/* $Id: tbl_opts.c,v 1.13 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: tbl_opts.c,v 1.15 2014/11/26 17:51:55 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 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 <ctype.h>
#include <stdio.h>
@ -182,7 +182,7 @@ opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
*
* options ::= option_list [:space:]* [;][\n]
* option_list ::= option option_tail
* option_tail ::= [:space:]+ option_list |
* option_tail ::= [,:space:]+ option_list |
* ::= epsilon
* option ::= [:alpha:]+ args
* args ::= [:space:]* [(] [:alpha:]+ [)]
@ -213,7 +213,7 @@ opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
buf[i] = '\0';
while (isspace((unsigned char)p[*pos]))
while (isspace((unsigned char)p[*pos]) || p[*pos] == ',')
(*pos)++;
/*

View File

@ -1,4 +1,4 @@
/* $Id: tbl_term.c,v 1.27 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: tbl_term.c,v 1.31 2014/10/14 18:18:05 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2014 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 <stdio.h>
@ -43,6 +43,7 @@ static void tbl_number(struct termp *, const struct tbl_opts *,
const struct roffcol *);
static void tbl_hrule(struct termp *, const struct tbl_span *);
static void tbl_vrule(struct termp *, const struct tbl_head *);
static void tbl_word(struct termp *, const struct tbl_dat *);
static size_t
@ -90,7 +91,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tbl.slen = term_tbl_strlen;
tp->tbl.arg = tp;
tblcalc(&tp->tbl, sp);
tblcalc(&tp->tbl, sp, rmargin - tp->offset);
}
/* Horizontal frame at the start of boxed tables. */
@ -106,7 +107,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Vertical frame at the start of each row. */
if ((TBL_OPT_BOX | TBL_OPT_DBOX) & sp->opts->opts ||
sp->head->vert)
(sp->head != NULL && sp->head->vert))
term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
@ -378,7 +379,7 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
}
tbl_char(tp, ASCII_NBRSP, padl);
term_word(tp, dp->string);
tbl_word(tp, dp);
tbl_char(tp, ASCII_NBRSP, padr);
}
@ -419,8 +420,23 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
padl = col->decimal - d;
tbl_char(tp, ASCII_NBRSP, padl);
term_word(tp, dp->string);
tbl_word(tp, dp);
if (col->width > sz + padl)
tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
}
static void
tbl_word(struct termp *tp, const struct tbl_dat *dp)
{
const void *prev_font;
prev_font = term_fontq(tp);
if (dp->layout->flags & TBL_CELL_BOLD)
term_fontpush(tp, TERMFONT_BOLD);
else if (dp->layout->flags & TBL_CELL_ITALIC)
term_fontpush(tp, TERMFONT_UNDER);
term_word(tp, dp->string);
term_fontpopq(tp, prev_font);
}

190
term.c
View File

@ -1,4 +1,4 @@
/* $Id: term.c,v 1.226 2014/08/01 19:38:29 schwarze Exp $ */
/* $Id: term.c,v 1.236 2014/11/21 01:52:53 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 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>
@ -44,11 +42,7 @@ void
term_free(struct termp *p)
{
if (p->buf)
free(p->buf);
if (p->symtab)
mchars_free(p->symtab);
free(p->buf);
free(p);
}
@ -106,7 +100,7 @@ term_flushln(struct termp *p)
size_t j; /* temporary loop index for p->buf */
size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */
size_t mmax; /* used in calculating bp */
size_t rmargin; /* the rightmost of the two margins */
/*
* First, establish the maximum columns of "visible" content.
@ -119,13 +113,17 @@ term_flushln(struct termp *p)
* is negative, it gets sign extended. Subtracting that
* very large size_t effectively adds a small number to dv.
*/
assert (p->rmargin >= p->offset);
dv = p->rmargin - p->offset;
rmargin = p->rmargin > p->offset ? p->rmargin : p->offset;
dv = p->rmargin - p->offset;
maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
dv = p->maxrmargin - p->offset;
mmax = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
if (p->flags & TERMP_NOBREAK) {
dv = p->maxrmargin > p->offset ?
p->maxrmargin - p->offset : 0;
bp = (int)dv > p->overstep ?
dv - (size_t)p->overstep : 0;
} else
bp = maxvis;
/*
* Calculate the required amount of padding.
@ -194,8 +192,8 @@ term_flushln(struct termp *p)
(*p->endline)(p);
p->viscol = 0;
if (TERMP_BRIND & p->flags) {
vbl = p->rmargin;
vend += p->rmargin - p->offset;
vbl = rmargin;
vend += rmargin - p->offset;
} else
vbl = p->offset;
@ -222,7 +220,7 @@ term_flushln(struct termp *p)
break;
if (' ' == p->buf[i]) {
j = i;
while (' ' == p->buf[i])
while (i < p->col && ' ' == p->buf[i])
i++;
dv = (i - j) * (*p->width)(p, ' ');
vbl += dv;
@ -260,8 +258,10 @@ term_flushln(struct termp *p)
* If there was trailing white space, it was not printed;
* so reset the cursor position accordingly.
*/
if (vis)
if (vis > vbl)
vis -= vbl;
else
vis = 0;
p->col = 0;
p->overstep = 0;
@ -397,7 +397,6 @@ term_word(struct termp *p, const char *word)
{
const char nbrsp[2] = { ASCII_NBRSP, 0 };
const char *seq, *cp;
char c;
int sz, uc;
size_t ssz;
enum mandoc_esc esc;
@ -446,68 +445,70 @@ term_word(struct termp *p, const char *word)
if (ESCAPE_ERROR == esc)
continue;
if (TERMENC_ASCII != p->enc)
switch (esc) {
case ESCAPE_UNICODE:
uc = mchars_num2uc(seq + 1, sz - 1);
if ('\0' == uc)
break;
encode1(p, uc);
continue;
case ESCAPE_SPECIAL:
uc = mchars_spec2cp(p->symtab, seq, sz);
if (uc <= 0)
break;
encode1(p, uc);
continue;
default:
break;
}
switch (esc) {
case ESCAPE_UNICODE:
encode1(p, '?');
uc = mchars_num2uc(seq + 1, sz - 1);
break;
case ESCAPE_NUMBERED:
c = mchars_num2char(seq, sz);
if ('\0' != c)
encode(p, &c, 1);
uc = mchars_num2char(seq, sz);
if (uc < 0)
continue;
break;
case ESCAPE_SPECIAL:
cp = mchars_spec2str(p->symtab, seq, sz, &ssz);
if (NULL != cp)
encode(p, cp, ssz);
else if (1 == ssz)
encode(p, seq, sz);
break;
if (p->enc == TERMENC_ASCII) {
cp = mchars_spec2str(p->symtab,
seq, sz, &ssz);
if (cp != NULL)
encode(p, cp, ssz);
} else {
uc = mchars_spec2cp(p->symtab, seq, sz);
if (uc > 0)
encode1(p, uc);
}
continue;
case ESCAPE_FONTBOLD:
term_fontrepl(p, TERMFONT_BOLD);
break;
continue;
case ESCAPE_FONTITALIC:
term_fontrepl(p, TERMFONT_UNDER);
break;
continue;
case ESCAPE_FONTBI:
term_fontrepl(p, TERMFONT_BI);
break;
continue;
case ESCAPE_FONT:
/* FALLTHROUGH */
case ESCAPE_FONTROMAN:
term_fontrepl(p, TERMFONT_NONE);
break;
continue;
case ESCAPE_FONTPREV:
term_fontlast(p);
break;
continue;
case ESCAPE_NOSPACE:
if (TERMP_SKIPCHAR & p->flags)
p->flags &= ~TERMP_SKIPCHAR;
else if ('\0' == *word)
p->flags |= TERMP_NOSPACE;
break;
continue;
case ESCAPE_SKIPCHAR:
p->flags |= TERMP_SKIPCHAR;
break;
continue;
default:
break;
continue;
}
/*
* Common handling for Unicode and numbered
* character escape sequences.
*/
if (p->enc == TERMENC_ASCII) {
cp = ascii_uc2str(uc);
encode(p, cp, strlen(cp));
} else {
if ((uc < 0x20 && uc != 0x09) ||
(uc > 0x7E && uc < 0xA0))
uc = 0xFFFD;
encode1(p, uc);
}
}
p->flags &= ~TERMP_NBRWORD;
@ -659,7 +660,7 @@ size_t
term_strlen(const struct termp *p, const char *cp)
{
size_t sz, rsz, i;
int ssz, skip, c;
int ssz, skip, uc;
const char *seq, *rhs;
enum mandoc_esc esc;
static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH,
@ -685,62 +686,65 @@ term_strlen(const struct termp *p, const char *cp)
if (ESCAPE_ERROR == esc)
continue;
if (TERMENC_ASCII != p->enc)
switch (esc) {
case ESCAPE_UNICODE:
c = mchars_num2uc(seq + 1,
ssz - 1);
if ('\0' == c)
break;
sz += cond_width(p, c, &skip);
continue;
case ESCAPE_SPECIAL:
c = mchars_spec2cp(p->symtab,
seq, ssz);
if (c <= 0)
break;
sz += cond_width(p, c, &skip);
continue;
default:
break;
}
rhs = NULL;
switch (esc) {
case ESCAPE_UNICODE:
sz += cond_width(p, '?', &skip);
uc = mchars_num2uc(seq + 1, ssz - 1);
break;
case ESCAPE_NUMBERED:
c = mchars_num2char(seq, ssz);
if ('\0' != c)
sz += cond_width(p, c, &skip);
uc = mchars_num2char(seq, ssz);
if (uc < 0)
continue;
break;
case ESCAPE_SPECIAL:
rhs = mchars_spec2str(p->symtab,
seq, ssz, &rsz);
if (ssz != 1 || rhs)
break;
rhs = seq;
rsz = ssz;
break;
if (p->enc == TERMENC_ASCII) {
rhs = mchars_spec2str(p->symtab,
seq, ssz, &rsz);
if (rhs != NULL)
break;
} else {
uc = mchars_spec2cp(p->symtab,
seq, ssz);
if (uc > 0)
sz += cond_width(p, uc, &skip);
}
continue;
case ESCAPE_SKIPCHAR:
skip = 1;
break;
continue;
default:
break;
continue;
}
if (NULL == rhs)
break;
/*
* Common handling for Unicode and numbered
* character escape sequences.
*/
if (rhs == NULL) {
if (p->enc == TERMENC_ASCII) {
rhs = ascii_uc2str(uc);
rsz = strlen(rhs);
} else {
if ((uc < 0x20 && uc != 0x09) ||
(uc > 0x7E && uc < 0xA0))
uc = 0xFFFD;
sz += cond_width(p, uc, &skip);
continue;
}
}
if (skip) {
skip = 0;
break;
}
/*
* Common handling for all escape sequences
* printing more than one character.
*/
for (i = 0; i < rsz; i++)
sz += (*p->width)(p, *rhs++);
break;

12
term.h
View File

@ -1,4 +1,4 @@
/* $Id: term.h,v 1.101 2014/04/20 16:46:05 schwarze Exp $ */
/* $Id: term.h,v 1.105 2014/10/28 17:36:19 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@ -54,6 +54,7 @@ struct termp_tbl {
struct termp {
enum termtype type;
struct rofftbl tbl; /* table configuration */
int synopsisonly; /* print the synopsis only */
int mdocstyle; /* imitate mdoc(7) output */
size_t defindent; /* Default indent for text. */
size_t defrmargin; /* Right margin of the device. */
@ -80,12 +81,11 @@ struct termp {
#define TERMP_BRIND (1 << 9) /* See term_flushln(). */
#define TERMP_DANGLE (1 << 10) /* See term_flushln(). */
#define TERMP_HANG (1 << 11) /* See term_flushln(). */
#define TERMP_NOSPLIT (1 << 12) /* See termp_an_pre/post(). */
#define TERMP_SPLIT (1 << 13) /* See termp_an_pre/post(). */
#define TERMP_ANPREC (1 << 14) /* See termp_an_pre(). */
#define TERMP_NOSPLIT (1 << 12) /* Do not break line before .An. */
#define TERMP_SPLIT (1 << 13) /* Break line before .An. */
int *buf; /* Output buffer. */
enum termenc enc; /* Type of encoding. */
struct mchars *symtab; /* Encoded-symbol table. */
const struct mchars *symtab; /* Character table. */
enum termfont fontl; /* Last font set. */
enum termfont fontq[10]; /* Symmetric fonts. */
int fonti; /* Index of font stack. */
@ -104,6 +104,8 @@ struct termp {
struct termp_ps *ps;
};
const char *ascii_uc2str(int);
void term_eqn(struct termp *, const struct eqn *);
void term_tbl(struct termp *, const struct tbl_span *);
void term_free(struct termp *);

View File

@ -1,4 +1,4 @@
/* $Id: term_ascii.c,v 1.27 2014/08/01 19:25:52 schwarze Exp $ */
/* $Id: term_ascii.c,v 1.40 2014/11/20 13:56:20 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@ -15,21 +15,20 @@
* 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>
#ifdef USE_WCHAR
# include <locale.h>
#include <assert.h>
#if HAVE_WCHAR
#include <locale.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef USE_WCHAR
# include <wchar.h>
#if HAVE_WCHAR
#include <wchar.h>
#endif
#include "mandoc.h"
@ -38,18 +37,8 @@
#include "term.h"
#include "main.h"
/*
* Sadly, this doesn't seem to be defined on systems even when they
* support it. For the time being, remove it and let those compiling
* the software decide for themselves what to use.
*/
#if 0
#if ! defined(__STDC_ISO_10646__)
# undef USE_WCHAR
#endif
#endif
static struct termp *ascii_init(enum termenc, char *);
static struct termp *ascii_init(enum termenc,
const struct mchars *, char *);
static double ascii_hspan(const struct termp *,
const struct roffsu *);
static size_t ascii_width(const struct termp *, int);
@ -60,7 +49,7 @@ static void ascii_endline(struct termp *);
static void ascii_letter(struct termp *, int);
static void ascii_setwidth(struct termp *, int, size_t);
#ifdef USE_WCHAR
#if HAVE_WCHAR
static void locale_advance(struct termp *, size_t);
static void locale_endline(struct termp *);
static void locale_letter(struct termp *, int);
@ -69,14 +58,15 @@ static size_t locale_width(const struct termp *, int);
static struct termp *
ascii_init(enum termenc enc, char *outopts)
ascii_init(enum termenc enc, const struct mchars *mchars, char *outopts)
{
const char *toks[4];
const char *toks[5];
char *v;
struct termp *p;
p = mandoc_calloc(1, sizeof(struct termp));
p->symtab = mchars;
p->tabwidth = 5;
p->defrmargin = p->lastrmargin = 78;
@ -92,7 +82,7 @@ ascii_init(enum termenc enc, char *outopts)
p->setwidth = ascii_setwidth;
p->width = ascii_width;
#ifdef USE_WCHAR
#if HAVE_WCHAR
if (TERMENC_ASCII != enc) {
v = TERMENC_LOCALE == enc ?
setlocale(LC_ALL, "") :
@ -110,7 +100,8 @@ ascii_init(enum termenc enc, char *outopts)
toks[0] = "indent";
toks[1] = "width";
toks[2] = "mdoc";
toks[3] = NULL;
toks[3] = "synopsis";
toks[4] = NULL;
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
@ -128,6 +119,9 @@ ascii_init(enum termenc enc, char *outopts)
p->mdocstyle = 1;
p->defindent = 5;
break;
case 3:
p->synopsisonly = 1;
break;
default:
break;
}
@ -140,24 +134,24 @@ ascii_init(enum termenc enc, char *outopts)
}
void *
ascii_alloc(char *outopts)
ascii_alloc(const struct mchars *mchars, char *outopts)
{
return(ascii_init(TERMENC_ASCII, outopts));
return(ascii_init(TERMENC_ASCII, mchars, outopts));
}
void *
utf8_alloc(char *outopts)
utf8_alloc(const struct mchars *mchars, char *outopts)
{
return(ascii_init(TERMENC_UTF8, outopts));
return(ascii_init(TERMENC_UTF8, mchars, outopts));
}
void *
locale_alloc(char *outopts)
locale_alloc(const struct mchars *mchars, char *outopts)
{
return(ascii_init(TERMENC_LOCALE, outopts));
return(ascii_init(TERMENC_LOCALE, mchars, outopts));
}
static void
@ -165,12 +159,14 @@ ascii_setwidth(struct termp *p, int iop, size_t width)
{
p->rmargin = p->defrmargin;
if (0 < iop)
if (iop > 0)
p->defrmargin += width;
else if (0 > iop)
else if (iop == 0)
p->defrmargin = width ? width : p->lastrmargin;
else if (p->defrmargin > width)
p->defrmargin -= width;
else
p->defrmargin = width ? width : p->lastrmargin;
p->defrmargin = 0;
p->lastrmargin = p->rmargin;
p->rmargin = p->maxrmargin = p->defrmargin;
}
@ -232,38 +228,125 @@ ascii_hspan(const struct termp *p, const struct roffsu *su)
double r;
/*
* Approximate based on character width. These are generated
* entirely by eyeballing the screen, but appear to be correct.
* Approximate based on character width.
* None of these will be actually correct given that an inch on
* the screen depends on character size, terminal, etc., etc.
*/
switch (su->unit) {
case SCALE_BU:
r = su->scale * 10.0 / 240.0;
break;
case SCALE_CM:
r = su->scale * 4.0;
r = su->scale * 10.0 / 2.54;
break;
case SCALE_FS:
r = su->scale * 2730.666;
break;
case SCALE_IN:
r = su->scale * 10.0;
break;
case SCALE_MM:
r = su->scale / 100.0;
break;
case SCALE_PC:
r = (su->scale * 10.0) / 6.0;
r = su->scale * 10.0 / 6.0;
break;
case SCALE_PT:
r = (su->scale * 10.0) / 72.0;
break;
case SCALE_MM:
r = su->scale / 1000.0;
r = su->scale * 10.0 / 72.0;
break;
case SCALE_VS:
r = su->scale * 2.0 - 1.0;
break;
default:
case SCALE_EN:
/* FALLTHROUGH */
case SCALE_EM:
r = su->scale;
break;
default:
abort();
/* NOTREACHED */
}
return(r);
}
#ifdef USE_WCHAR
const char *
ascii_uc2str(int uc)
{
static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
static const char *tab[] = {
"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
"<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>",
"<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
"<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>",
" ", "!", "\"", "#", "$", "%", "&", "'",
"(", ")", "*", "+", ",", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", ":", ";", "<", "=", ">", "?",
"@", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "[", "\\", "]", "^", "_",
"`", "a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w",
"x", "y", "z", "{", "|", "}", "~", "<DEL>",
"<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
"<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
"<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
"<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>",
"\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
"<deg>","+-", "2", "3", "'", ",\bu", "<par>",".",
",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
"`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC",
"`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI",
"-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x",
"/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss",
"`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc",
"`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi",
"d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-",
"/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by",
"A", "a", "A", "a", "A", "a", "'\bC", "'\bc",
"^\bC", "^\bc", "C", "c", "C", "c", "D", "d",
"/\bD", "/\bd", "E", "e", "E", "e", "E", "e",
"E", "e", "E", "e", "^\bG", "^\bg", "G", "g",
"G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh",
"~\bI", "~\bi", "I", "i", "I", "i", "I", "i",
"I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk",
"q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L",
"l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N",
"n", "'n", "Ng", "ng", "O", "o", "O", "o",
"O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br",
"R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs",
"S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt",
"~\bU", "~\bu", "U", "u", "U", "u", "U", "u",
"U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by",
"\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s",
"b", "B", "B", "b", "6", "6", "O", "C",
"c", "D", "D", "D", "d", "d", "3", "@",
"E", "F", ",\bf", "G", "G", "hv", "I", "/\bI",
"K", "k", "/\bl", "l", "W", "N", "n", "~\bO",
"O", "o", "OI", "oi", "P", "p", "YR", "2",
"2", "SH", "sh", "t", "T", "t", "T", "U",
"u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH",
"ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w",
"|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ",
"Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I",
"i", "O", "o", "U", "u", "U", "u", "U",
"u", "U", "u", "U", "u", "@", "A", "a",
"A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g",
"K", "k", "O", "o", "O", "o", "ZH", "zh",
"j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W",
"`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"};
assert(uc >= 0);
if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
return(tab[uc]);
return(mchars_uc2str(uc));
}
#if HAVE_WCHAR
static size_t
locale_width(const struct termp *p, int c)
{

Some files were not shown because too many files have changed in this diff Show More