Import mdocml CVS snapshot 20160116

This commit is contained in:
bapt 2016-01-15 23:08:59 +00:00
parent 3481e0a06e
commit 877b18fd0c
134 changed files with 7855 additions and 6921 deletions

16
INSTALL
View File

@ -1,4 +1,4 @@
$Id: INSTALL,v 1.10 2015/03/09 21:00:14 schwarze Exp $
$Id: INSTALL,v 1.13 2015/11/07 14:01:16 schwarze Exp $
About mdocml, the portable mandoc distribution
----------------------------------------------
@ -42,6 +42,8 @@ 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.
On Solaris 10 and earlier, you may have to run "ksh ./configure"
because the native /bin/sh lacks some POSIX features.
3. Run "make".
Any POSIX-compatible make, in particular both BSD make and GNU make,
@ -82,9 +84,10 @@ manual page source.
Understanding mandoc dependencies
---------------------------------
The mandoc(1), man(1), and demandoc(1) utilities have no external
dependencies, but makewhatis(8) and apropos(1) depend on the
following software:
The mandoc(1), man(1), and demandoc(1) utilities only depend
on the zlib library for decompressing gzipped manual pages,
but makewhatis(8) and apropos(1) depend on the following
additional software:
1. The SQLite database system, see <http://sqlite.org/>.
The recommended version of SQLite is 3.8.4.3 or newer. The mandoc
@ -107,6 +110,11 @@ If you run into that problem, set "HAVE_FTS=0" in configure.local.
If your system does not have it, the bundled compatibility version
will be used, so you probably need not worry about it.
One of the chief design goals of the mandoc toolbox is to make
sure that nothing related to documentation requires C++.
Consequently, linking mandoc against any kind of C++ program
would defeat the purpose and is not supported.
Checking autoconfiguration quality
----------------------------------

17
LICENSE
View File

@ -1,4 +1,4 @@
$Id: LICENSE,v 1.7 2015/02/16 14:56:22 schwarze Exp $
$Id: LICENSE,v 1.11 2015/11/07 17:58:55 schwarze Exp $
With the exceptions noted below, all code and documentation
contained in the mdocml toolkit is protected by the Copyright
@ -8,10 +8,12 @@ Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
See the individual source files for information about who contributed
@ -35,13 +37,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
The following files included from outside sources are protected by
other people's Copyright and are distributed under a 3-clause BSD
license; see these individual files for details.
other people's Copyright and are distributed under various 2-clause
and 3-clause BSD licenses; see these individual files for details.
compat_fts.c, compat_fts.h,
soelim.c, soelim.1:
Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
compat_err.c, 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.
compat_stringlist.c, compat_stringlist.h:
Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.457 2015/03/13 12:35:32 schwarze Exp $
# $Id: Makefile,v 1.480 2015/11/07 21:53:14 schwarze Exp $
#
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
# Copyright (c) 2011, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -20,36 +20,49 @@ VERSION = 1.13.3
# === LIST OF FILES ====================================================
TESTSRCS = test-dirent-namlen.c \
test-fgetln.c \
test-err.c \
test-fts.c \
test-getline.c \
test-getsubopt.c \
test-isblank.c \
test-mkdtemp.c \
test-mmap.c \
test-ohash.c \
test-pledge.c \
test-progname.c \
test-reallocarray.c \
test-sqlite3.c \
test-sqlite3_errstr.c \
test-strcasestr.c \
test-stringlist.c \
test-strlcat.c \
test-strlcpy.c \
test-strptime.c \
test-strsep.c \
test-strtonum.c \
test-vasprintf.c \
test-wchar.c
SRCS = att.c \
cgi.c \
chars.c \
compat_fgetln.c \
compat_err.c \
compat_fts.c \
compat_getline.c \
compat_getsubopt.c \
compat_isblank.c \
compat_mkdtemp.c \
compat_ohash.c \
compat_progname.c \
compat_reallocarray.c \
compat_sqlite3_errstr.c \
compat_strcasestr.c \
compat_stringlist.c \
compat_strlcat.c \
compat_strlcpy.c \
compat_strsep.c \
compat_strtonum.c \
compat_vasprintf.c \
demandoc.c \
eqn.c \
eqn_html.c \
@ -65,6 +78,7 @@ SRCS = att.c \
man_validate.c \
mandoc.c \
mandoc_aux.c \
mandoc_ohash.c \
mandocdb.c \
manpage.c \
manpath.c \
@ -76,6 +90,7 @@ SRCS = att.c \
mdoc_html.c \
mdoc_macro.c \
mdoc_man.c \
mdoc_state.c \
mdoc_term.c \
mdoc_validate.c \
msec.c \
@ -83,7 +98,9 @@ SRCS = att.c \
preconv.c \
read.c \
roff.c \
soelim.c \
st.c \
tag.c \
tbl.c \
tbl_data.c \
tbl_html.c \
@ -93,8 +110,7 @@ SRCS = att.c \
term.c \
term_ascii.c \
term_ps.c \
tree.c \
$(TESTSRCS)
tree.c
DISTFILES = INSTALL \
LICENSE \
@ -104,14 +120,13 @@ DISTFILES = INSTALL \
TODO \
apropos.1 \
cgi.h.example \
chars.in \
compat_fts.h \
compat_ohash.h \
compat_stringlist.h \
configure \
configure.local.example \
demandoc.1 \
eqn.7 \
example.style.css \
gmdiff \
html.h \
lib.in \
@ -121,13 +136,15 @@ DISTFILES = INSTALL \
libroff.h \
main.h \
makewhatis.8 \
man-cgi.css \
man.1 \
man.7 \
man.cgi.8 \
man.conf.5 \
man.h \
manconf.h \
mandoc.1 \
mandoc.3 \
mandoc.css \
mandoc.db.5 \
mandoc.h \
mandoc_aux.h \
@ -136,7 +153,7 @@ DISTFILES = INSTALL \
mandoc_headers.3 \
mandoc_html.3 \
mandoc_malloc.3 \
manpath.h \
mandoc_ohash.h \
mansearch.3 \
mansearch.h \
mchars_alloc.3 \
@ -146,12 +163,15 @@ DISTFILES = INSTALL \
out.h \
predefs.in \
roff.7 \
roff.h \
soelim.1 \
st.in \
style.css \
tag.h \
tbl.3 \
tbl.7 \
term.h \
$(SRCS)
$(SRCS) \
$(TESTSRCS)
LIBMAN_OBJS = man.o \
man_hash.o \
@ -164,6 +184,7 @@ LIBMDOC_OBJS = att.o \
mdoc_argv.o \
mdoc_hash.o \
mdoc_macro.o \
mdoc_state.o \
mdoc_validate.o \
st.o
@ -180,21 +201,27 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
chars.o \
mandoc.o \
mandoc_aux.o \
mandoc_ohash.o \
msec.o \
preconv.o \
read.o
COMPAT_OBJS = compat_fgetln.o \
COMPAT_OBJS = compat_err.o \
compat_fts.o \
compat_getline.o \
compat_getsubopt.o \
compat_isblank.o \
compat_mkdtemp.o \
compat_ohash.o \
compat_progname.o \
compat_reallocarray.o \
compat_sqlite3_errstr.o \
compat_strcasestr.o \
compat_strlcat.o \
compat_strlcpy.o \
compat_strsep.o \
compat_strtonum.o
compat_strtonum.o \
compat_vasprintf.o
MANDOC_HTML_OBJS = eqn_html.o \
html.o \
@ -218,6 +245,7 @@ BASE_OBJS = $(MANDOC_HTML_OBJS) \
main.o \
manpath.o \
out.o \
tag.o \
tree.o
MAIN_OBJS = $(BASE_OBJS)
@ -236,10 +264,18 @@ MANPAGE_OBJS = manpage.o mansearch.o mansearch_const.o manpath.o
DEMANDOC_OBJS = demandoc.o
SOELIM_OBJS = soelim.o \
compat_err.o \
compat_getline.o \
compat_progname.o \
compat_reallocarray.o \
compat_stringlist.o
WWW_MANS = apropos.1.html \
demandoc.1.html \
man.1.html \
mandoc.1.html \
soelim.1.html \
mandoc.3.html \
mandoc_escape.3.html \
mandoc_headers.3.html \
@ -248,6 +284,7 @@ WWW_MANS = apropos.1.html \
mansearch.3.html \
mchars_alloc.3.html \
tbl.3.html \
man.conf.5.html \
mandoc.db.5.html \
eqn.7.html \
man.7.html \
@ -258,11 +295,12 @@ WWW_MANS = apropos.1.html \
makewhatis.8.html \
man.cgi.8.html \
man.h.html \
manconf.h.html \
mandoc.h.html \
mandoc_aux.h.html \
manpath.h.html \
mansearch.h.html \
mdoc.h.html
mdoc.h.html \
roff.h.html
WWW_OBJS = mdocml.tar.gz \
mdocml.sha256
@ -275,7 +313,7 @@ include Makefile.local
all: base-build $(BUILD_TARGETS) Makefile.local
base-build: mandoc demandoc
base-build: mandoc demandoc soelim
cgi-build: man.cgi
@ -301,33 +339,36 @@ clean:
rm -f man.cgi $(CGI_OBJS)
rm -f manpage $(MANPAGE_OBJS)
rm -f demandoc $(DEMANDOC_OBJS)
rm -f soelim $(SOELIM_OBJS)
rm -f $(WWW_MANS) $(WWW_OBJS)
rm -rf *.dSYM
base-install: base-build
mkdir -p $(DESTDIR)$(BINDIR)
mkdir -p $(DESTDIR)$(EXAMPLEDIR)
mkdir -p $(DESTDIR)$(LIBDIR)
mkdir -p $(DESTDIR)$(INCLUDEDIR)
mkdir -p $(DESTDIR)$(MANDIR)/man1
mkdir -p $(DESTDIR)$(MANDIR)/man3
mkdir -p $(DESTDIR)$(MANDIR)/man5
mkdir -p $(DESTDIR)$(MANDIR)/man7
$(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR)
$(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM)
ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_MAN)
$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h \
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h roff.h \
$(DESTDIR)$(INCLUDEDIR)
$(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
$(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1
$(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
$(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/${MANM_MANCONF}.5
$(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/${MANM_MAN}.7
$(INSTALL_MAN) mdoc.7 $(DESTDIR)$(MANDIR)/man7/${MANM_MDOC}.7
$(INSTALL_MAN) roff.7 $(DESTDIR)$(MANDIR)/man7/${MANM_ROFF}.7
$(INSTALL_MAN) eqn.7 $(DESTDIR)$(MANDIR)/man7/${MANM_EQN}.7
$(INSTALL_MAN) tbl.7 $(DESTDIR)$(MANDIR)/man7/${MANM_TBL}.7
$(INSTALL_MAN) mandoc_char.7 $(DESTDIR)$(MANDIR)/man7
$(INSTALL_DATA) example.style.css $(DESTDIR)$(EXAMPLEDIR)
db-install: base-build
mkdir -p $(DESTDIR)$(BINDIR)
@ -354,8 +395,7 @@ cgi-install: cgi-build
mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1
mkdir -p $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8
$(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR)
$(INSTALL_DATA) example.style.css $(DESTDIR)$(HTDOCDIR)/man.css
$(INSTALL_DATA) man-cgi.css $(DESTDIR)$(HTDOCDIR)
$(INSTALL_DATA) mandoc.css $(DESTDIR)$(HTDOCDIR)
$(INSTALL_MAN) apropos.1 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man1/
$(INSTALL_MAN) man.cgi.8 $(DESTDIR)$(WWWPREFIX)/man/mandoc/man8/
@ -376,13 +416,16 @@ man.cgi: $(CGI_OBJS) libmandoc.a
$(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB)
demandoc: $(DEMANDOC_OBJS) libmandoc.a
$(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a
$(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a $(DBLIB)
soelim: $(SOELIM_OBJS)
$(CC) $(LDFLAGS) -o $@ $(SOELIM_OBJS)
# --- maintainer targets ---
www-install: www
mkdir -p $(HTDOCDIR)/snapshots
$(INSTALL_DATA) $(WWW_MANS) style.css $(HTDOCDIR)
$(INSTALL_DATA) $(WWW_MANS) mandoc.css $(HTDOCDIR)
$(INSTALL_DATA) $(WWW_OBJS) $(HTDOCDIR)/snapshots
$(INSTALL_DATA) mdocml.tar.gz \
$(HTDOCDIR)/snapshots/mdocml-$(VERSION).tar.gz
@ -416,4 +459,4 @@ mdocml.tar.gz: $(DISTFILES)
.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
./mandoc -Thtml -Wall,stop \
-Ostyle=style.css,man=%N.%S.html,includes=%I.html $< > $@
-Ostyle=mandoc.css,man=%N.%S.html,includes=%I.html $< > $@

View File

@ -1,51 +1,61 @@
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
att.o: att.c config.h roff.h mdoc.h libmdoc.h
cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h
chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h
compat_err.o: compat_err.c config.h
compat_fts.o: compat_fts.c config.h compat_fts.h
compat_getline.o: compat_getline.c config.h
compat_getsubopt.o: compat_getsubopt.c config.h
compat_isblank.o: compat_isblank.c config.h
compat_mkdtemp.o: compat_mkdtemp.c config.h
compat_ohash.o: compat_ohash.c config.h compat_ohash.h
compat_progname.o: compat_progname.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_stringlist.o: compat_stringlist.c config.h compat_stringlist.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_strtonum.o: compat_strtonum.c config.h
demandoc.o: demandoc.c config.h man.h mdoc.h mandoc.h
compat_vasprintf.o: compat_vasprintf.c config.h
demandoc.o: demandoc.c config.h roff.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 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 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 libman.h
man_html.o: man_html.c config.h mandoc_aux.h man.h out.h html.h main.h
man_macro.o: man_macro.c config.h man.h mandoc.h libmandoc.h libman.h
man_term.o: man_term.c config.h mandoc.h mandoc_aux.h out.h man.h term.h main.h
man_validate.o: man_validate.c config.h man.h mandoc.h mandoc_aux.h libman.h libmandoc.h
html.o: html.c config.h mandoc.h mandoc_aux.h out.h html.h manconf.h main.h
lib.o: lib.c config.h roff.h mdoc.h libmdoc.h lib.in
main.o: main.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h
man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_hash.o: man_hash.c config.h roff.h man.h libman.h
man_html.o: man_html.c config.h mandoc_aux.h roff.h man.h out.h html.h main.h
man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h main.h
man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.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 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 compat_ohash.h mandoc.h mandoc_aux.h manpath.h mansearch.h
mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h
manpage.o: manpage.c config.h manconf.h mansearch.h
manpath.o: manpath.c config.h mandoc_aux.h manconf.h
mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h
mansearch_const.o: mansearch_const.c config.h mansearch.h
mdoc.o: mdoc.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
mdoc_argv.o: mdoc_argv.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
mdoc_hash.o: mdoc_hash.c config.h mdoc.h libmdoc.h
mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mdoc.h out.h html.h main.h
mdoc_macro.o: mdoc_macro.c config.h mdoc.h mandoc.h libmdoc.h libmandoc.h
mdoc_man.o: mdoc_man.c config.h mandoc.h mandoc_aux.h out.h man.h mdoc.h main.h
mdoc_term.o: mdoc_term.c config.h mandoc.h mandoc_aux.h out.h term.h mdoc.h main.h
mdoc_validate.o: mdoc_validate.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h
mdoc_hash.o: mdoc_hash.c config.h roff.h mdoc.h libmdoc.h
mdoc_html.o: mdoc_html.c config.h mandoc_aux.h roff.h mdoc.h out.h html.h main.h
mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h
mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h
mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.h main.h
mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.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 mandoc.h libmandoc.h
read.o: read.c config.h mandoc.h mandoc_aux.h libmandoc.h mdoc.h man.h
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
read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h roff_int.h
roff.o: roff.c config.h mandoc.h mandoc_aux.h roff.h libmandoc.h roff_int.h libroff.h predefs.in
soelim.o: soelim.c config.h compat_stringlist.h
st.o: st.c config.h roff.h mdoc.h libmdoc.h st.in
tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h
tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h
@ -53,22 +63,6 @@ tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h
tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h
term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h main.h
tree.o: tree.c config.h mandoc.h mdoc.h man.h main.h
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-strtonum.o: test-strtonum.c
test-wchar.o: test-wchar.c
term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h
term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h
tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h main.h

4
NEWS
View File

@ -1,4 +1,4 @@
$Id: NEWS,v 1.9 2015/03/13 12:35:32 schwarze Exp $
$Id: NEWS,v 1.10 2015/11/05 16:58:20 schwarze Exp $
This file lists the most important changes in the mdocml.bsd.lv distribution.
@ -93,7 +93,7 @@ Changes in version 1.13.3, released on March 13, 2015
* roff(7): Three minor fixes with respect to evaluation of conditionals.
* roff(7): Let .it accept numerical expressions, not just constants.
* mandoc_char(7): Correct some character names and renderings.
* If earlier files set a non-zero exit status, never reset it to zero.
* If earlier files set a non-zero exit status, never reset it to zero.
--- THANKS TO ---
* Jonathan Gray (OpenBSD) for yet more testing with afl (the American
Fuzzy Lop security fuzzer), again resulting in many bug reports.

110
TODO
View File

@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
* $Id: TODO,v 1.202 2015/03/11 13:11:22 schwarze Exp $
* $Id: TODO,v 1.216 2016/01/08 01:37:32 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@ -66,6 +66,7 @@ are mere guesses, and some may be wrong.
loc * exist * algo * size * imp **
- .ns (no-space mode) occurs in xine-config(1)
when implementing this, also let .TH set it
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
loc *** exist *** algo *** size ** imp *
@ -105,6 +106,19 @@ are mere guesses, and some may be wrong.
needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
loc ** exist *** algo *** size * imp ***
- \\ in high-level macro arguments
Currently, \\ is expanded in two situations:
1) macro and string definition (roff.c setstrn())
2) macro argument parsing (mandoc.c mandoc_getarg())
For user defined macros, the second happens in time because of ROFF_REPARSE.
But for standard high-level macros, it only happens after entering the
high level parsers, which is too late because the code doesn't get
back to roff.c roff_res() from that point. Because this requires
distinguishing requests, user-defined macros and standard macros
on the roff_res() level, it is hard to solve without the parser reorg.
Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +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 *
@ -194,6 +208,26 @@ are mere guesses, and some may be wrong.
--- missing tbl features -----------------------------------------------
- horizontal lines in the layout still consume data cells
and can be mixed with actual data on the same table line
synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400
loc ** exist ** algo ** size ** imp ***
- the "w" layout option is ignored
synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400
loc * exist * algo * size * imp **
- the "s" layout column specifier is used for placement of data
into columns, but ignored during column width calculations
synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400
loc * exist ** algo *** size * imp **
- support mdoc(7) and man(7) macros inside tbl(7) code;
probably requires the parser reorg and letting tbl(7)
use roff_node such that macro sets can mix;
informed by bapt@ that FreeBSD needs this.
loc *** exist ** algo *** size ** imp ***
- look at the POSIX manuals in the books/man-pages-posix port,
they use some unsupported tbl(7) features.
loc * exist ** algo ** size ** imp ***
@ -203,13 +237,13 @@ are mere guesses, and some may be wrong.
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 -----------------------------------------------
- In a matrix, break the output line after each matrix line.
Found in the discussion at CDBUG 2015.
Suggested by Avi Weinstock.
loc * exist * algo * size * imp **
- The "size" keyword is parsed, but ignored by the formatter.
loc * exist * algo * size * imp *
@ -227,13 +261,9 @@ are mere guesses, and some may be wrong.
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
at all for paths like man1/foo.1 - and which also contradicts
what the manual says at the end of the description.
The end result will be ENOENT for file names returned
by mansearch() in manpage.file.
loc * exist * algo * size * imp **
- change the default PAGER to more -Es and use the pager
even for apropos title line output; req by bapt@
loc * exist * algo * size * imp ***
- makewhatis(8) for preformatted pages:
parse the section number from the header line
@ -255,11 +285,13 @@ are mere guesses, and some may be wrong.
- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET)
loc ** exist ** algo ** size *** imp *
--- compatibility checks -----------------------------------------------
- Vsevolod Stakhov (FreeBSD) needs either a markdown output formatter
for mandoc -mdoc or a markdown to mdoc converter because they
have to maintain manuals needed both in markdown and mdoc format.
Look at the libsoldout (markdown -> whatever)
loc * exist * algo * size ** imp **
- write a configure check for [[:<:]] support and provide some
fallback for whatis(1) when it doesn't work;
Svyatoslav Mishyn Wed, 17 Dec 2014 11:07:10 +0200
--- compatibility checks -----------------------------------------------
- is .Bk implemented correctly in modern groff?
sobrado@ Tue, 19 Apr 2011 22:12:55 +0200
@ -293,6 +325,9 @@ are mere guesses, and some may be wrong.
http://swtch.com/plan9port/man/man7/man.html
"Anthony J. Bentley" <anthonyjbentley@gmail.com> 28 Dec 2010 21:58:40 -0700
- check compatibility with COHERENT troff:
http://www.nesssoftware.com/home/mwc/source.php
- check compatibility with the man(7) formatter
https://raw.githubusercontent.com/rofl0r/hardcore-utils/master/man.c
@ -381,6 +416,12 @@ are mere guesses, and some may be wrong.
see also matthew@ Fri, 18 Jul 2014 19:25:12 -0700
loc * exist * algo ** size * imp ***
- .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal
space, see for example random(3). Introduced in
http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92
reported by deraadt@ Mon, 28 Sep 2015 20:14:13 -0600 (MDT)
loc ** exist ** algo ** size * imp *
- jsg on icb, Nov 3, 2014:
try to guess Xr in man(7) for hyperlinking
@ -394,6 +435,10 @@ are mere guesses, and some may be wrong.
- consider whether <var> can be used for Ar Dv Er Ev Fa Va.
from bentley@ Wed, 13 Aug 2014 09:17:55 -0600
- generate <img> tags in HTML
idea from florian@ Tue, 7 Apr 2015 00:26:28 +0000
may be possible to implement with .Lk img://something.png alt_text
- check https://github.com/trentm/mdocml
************************************************************************
@ -466,6 +511,10 @@ are mere guesses, and some may be wrong.
found while talking to Chris Bennett
loc * exist * algo * size * imp *
- Sequences of multiple man(7) paragraphs (.PP, .IP) interspersed
with .ps and .nf/.fi produce execessive blank lines, see libJudy
and graphics/dcmtk. The parser reorg may help with this.
- trailing whitespace must be ignored even when followed by a font escape,
see for example
makes
@ -474,10 +523,32 @@ are mere guesses, and some may be wrong.
in dig(1).
loc ** exist ** algo ** size * imp **
************************************************************************
* portability
************************************************************************
- systems having UTF-8 but not en_US.UTF-8
call locale(1) from ./configure, select a UTF-8-locale,
and use that for test-wchar.c and term_ascii.c
to Markus Waldeck Sat, 18 Jul 2015 01:55:37 +0200
loc * exist * algo * size * imp *
************************************************************************
* warning issues
************************************************************************
- provide a way in mandoc(1) to warn about broken .Xr links;
probably cannot be on by default in -Tlint because it needs
to access the manpath and mandoc.db(3) after parsing.
asked for by jmc@ Fri, 4 Dec 2015 22:39:40 +0000
- Report errors in -O suboption parsing.
loc * exist * algo * size * imp **
- warn when .Sh or .Ss contain other macros
Steffen Nurpmeso, savannah.gnu.org/bugs/index.php?45034
loc * exist * algo * size * imp **
- check that MANDOCERR_BADTAB is thrown in the right cases,
i.e. when finding a literal tab character in fill mode,
and possibly change the wording of the warning message
@ -557,11 +628,6 @@ Several areas can be cleaned up to make mandoc even faster. These are
* structural issues
************************************************************************
- Improve -O suboption parsing. Do it in the main program such that
errors can be reported. Pay attention to distinguishing the
mandoc(1) and apropos(1) styles of both options.
loc ** exist * algo ** size ** imp ***
- Use libz directly instead of forking gunzip(1).
Suggested by bapt at FreeBSD among others.

View File

@ -1,4 +1,4 @@
.\" $Id: apropos.1,v 1.37 2015/02/16 16:23:54 schwarze Exp $
.\" $Id: apropos.1,v 1.39 2015/04/03 08:46:17 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: February 16 2015 $
.Dd $Mdocdate: April 3 2015 $
.Dt APROPOS 1
.Os
.Sh NAME
@ -210,7 +210,7 @@ This has syntax
.Sm off
.Oo
.Op Ar key Op , Ar key ...
.Pq Cm = | ~
.Pq Cm = | \(ti
.Oc
.Ar val ,
.Sm on
@ -227,7 +227,7 @@ for a list of available keys.
Operator
.Cm =
evaluates a substring, while
.Cm ~
.Cm \(ti
evaluates a regular expression.
.It Fl i Ar term
If
@ -365,7 +365,8 @@ 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
.Xr more 1
.Fl s
will be used.
.El
.Sh FILES
@ -398,7 +399,7 @@ as well:
.Pp
Search in names and descriptions using a regular expression:
.Pp
.Dl $ apropos '~set.?[ug]id'
.Dl $ apropos \(aq\(tiset.?[ug]id\(aq
.Pp
Search for manuals in the library section mentioning both the
.Qq optind
@ -413,15 +414,15 @@ Do exactly the same as calling
with the argument
.Qq ssh :
.Pp
.Dl $ apropos \-\- \-i 'Nm~[[:<:]]ssh[[:>:]]'
.Dl $ apropos \-\- \-i \(aqNm\(ti[[:<:]]ssh[[:>:]]\(aq
.Pp
The following two invocations are equivalent:
.Pp
.D1 Li $ apropos -S Ar arch Li -s Ar section expression
.Bd -ragged -offset indent
.Li $ apropos \e( Ar expression Li \e)
.Li -a arch~^( Ns Ar arch Ns Li |any)$
.Li -a sec~^ Ns Ar section Ns Li $
.Li -a arch\(ti^( Ns Ar arch Ns Li |any)$
.Li -a sec\(ti^ Ns Ar section Ns Li $
.Ed
.Sh SEE ALSO
.Xr man 1 ,

5
att.c
View File

@ -1,4 +1,4 @@
/* $Id: att.c,v 1.13 2014/11/28 18:57:31 schwarze Exp $ */
/* $Id: att.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -19,6 +19,7 @@
#include <sys/types.h>
#include <string.h>
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
@ -45,5 +46,5 @@ mdoc_a2att(const char *p)
LINE("V.3", "AT&T System\\~V Release\\~3 UNIX");
LINE("V.4", "AT&T System\\~V Release\\~4 UNIX");
return(NULL);
return NULL;
}

204
cgi.c
View File

@ -1,15 +1,15 @@
/* $Id: cgi.c,v 1.104 2015/02/10 08:05:30 schwarze Exp $ */
/* $Id: cgi.c,v 1.116 2016/01/04 12:36:26 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@usta.de>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@usta.de>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -30,10 +30,13 @@
#include <string.h>
#include <unistd.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "main.h"
#include "manpath.h"
#include "manconf.h"
#include "mansearch.h"
#include "cgi.h"
@ -60,9 +63,6 @@ static void html_print(const char *);
static void html_putchar(char);
static int http_decode(char *);
static void http_parse(struct req *, const char *);
static void http_print(const char *);
static void http_putchar(char);
static void http_printquery(const struct req *, const char *);
static void pathgen(struct req *);
static void pg_error_badrequest(const char *);
static void pg_error_internal(void);
@ -74,6 +74,7 @@ static void pg_searchres(const struct req *,
static void pg_show(struct req *, const char *);
static void resp_begin_html(int, const char *);
static void resp_begin_http(int, const char *);
static void resp_copy(const char *);
static void resp_end_html(void);
static void resp_searchform(const struct req *);
static void resp_show(const struct req *, const char *);
@ -145,40 +146,6 @@ html_putchar(char c)
}
}
static void
http_printquery(const struct req *req, const char *sep)
{
if (NULL != req->q.query) {
printf("query=");
http_print(req->q.query);
}
if (0 == req->q.equal)
printf("%sapropos=1", sep);
if (NULL != req->q.sec) {
printf("%ssec=", sep);
http_print(req->q.sec);
}
if (NULL != req->q.arch) {
printf("%sarch=", sep);
http_print(req->q.arch);
}
if (strcmp(req->q.manpath, req->p[0])) {
printf("%smanpath=", sep);
http_print(req->q.manpath);
}
}
static void
http_print(const char *p)
{
if (NULL == p)
return;
while ('\0' != *p)
http_putchar(*p++);
}
/*
* Call through to html_putchar().
* Accepts NULL strings.
@ -299,20 +266,6 @@ http_parse(struct req *req, const char *qs)
}
}
static void
http_putchar(char c)
{
if (isalnum((unsigned char)c)) {
putchar((unsigned char)c);
return;
} else if (' ' == c) {
putchar('+');
return;
}
printf("%%%.2x", c);
}
/*
* HTTP-decode a string. The standard explanation is that this turns
* "%4e+foo" into "n foo" in the regular way. This is done in-place
@ -331,13 +284,13 @@ http_decode(char *p)
for ( ; '\0' != *p; p++, q++) {
if ('%' == *p) {
if ('\0' == (hex[0] = *(p + 1)))
return(0);
return 0;
if ('\0' == (hex[1] = *(p + 2)))
return(0);
return 0;
if (1 != sscanf(hex, "%x", &c))
return(0);
return 0;
if ('\0' == c)
return(0);
return 0;
*q = (char)c;
p += 2;
@ -346,7 +299,7 @@ http_decode(char *p)
}
*q = '\0';
return(1);
return 1;
}
static void
@ -364,6 +317,20 @@ resp_begin_http(int code, const char *msg)
fflush(stdout);
}
static void
resp_copy(const char *filename)
{
char buf[4096];
ssize_t sz;
int fd;
if ((fd = open(filename, O_RDONLY)) != -1) {
fflush(stdout);
while ((sz = read(fd, buf, sizeof(buf))) > 0)
write(STDOUT_FILENO, buf, sz);
}
}
static void
resp_begin_html(int code, const char *msg)
{
@ -374,21 +341,23 @@ resp_begin_html(int code, const char *msg)
"<HTML>\n"
"<HEAD>\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\""
"<LINK REL=\"stylesheet\" HREF=\"%s/mandoc.css\""
" TYPE=\"text/css\" media=\"all\">\n"
"<TITLE>%s</TITLE>\n"
"</HEAD>\n"
"<BODY>\n"
"<!-- Begin page content. //-->\n",
CSS_DIR, CSS_DIR, CUSTOMIZE_TITLE);
CSS_DIR, CUSTOMIZE_TITLE);
resp_copy(MAN_DIR "/header.html");
}
static void
resp_end_html(void)
{
resp_copy(MAN_DIR "/footer.html");
puts("</BODY>\n"
"</HTML>");
}
@ -398,7 +367,6 @@ resp_searchform(const struct req *req)
{
int i;
puts(CUSTOMIZE_BEGIN);
puts("<!-- Begin search form. //-->");
printf("<DIV ID=\"mancgi\">\n"
"<FORM ACTION=\"%s\" METHOD=\"get\">\n"
@ -498,10 +466,10 @@ validate_urifrag(const char *frag)
if ( ! (isalnum((unsigned char)*frag) ||
'-' == *frag || '.' == *frag ||
'/' == *frag || '_' == *frag))
return(0);
return 0;
frag++;
}
return(1);
return 1;
}
static int
@ -510,13 +478,13 @@ validate_manpath(const struct req *req, const char* manpath)
size_t i;
if ( ! strcmp(manpath, "mandoc"))
return(1);
return 1;
for (i = 0; i < req->psz; i++)
if ( ! strcmp(manpath, req->p[i]))
return(1);
return 1;
return(0);
return 0;
}
static int
@ -526,8 +494,8 @@ validate_filename(const char *file)
if ('.' == file[0] && '/' == file[1])
file += 2;
return ( ! (strstr(file, "../") || strstr(file, "/..") ||
(strncmp(file, "man", 3) && strncmp(file, "cat", 3))));
return ! (strstr(file, "../") || strstr(file, "/..") ||
(strncmp(file, "man", 3) && strncmp(file, "cat", 3)));
}
static void
@ -604,9 +572,8 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
* without any delay.
*/
printf("Status: 303 See Other\r\n");
printf("Location: http://%s%s/%s/%s?",
printf("Location: http://%s%s/%s/%s",
HTTP_HOST, scriptname, req->q.manpath, r[0].file);
http_printquery(req, "&");
printf("\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"\r\n");
@ -621,9 +588,8 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
for (i = 0; i < sz; i++) {
printf("<TR>\n"
"<TD CLASS=\"title\">\n"
"<A HREF=\"%s/%s/%s?",
"<A HREF=\"%s/%s/%s",
scriptname, req->q.manpath, r[i].file);
http_printquery(req, "&amp;");
printf("\">");
html_print(r[i].names);
printf("</A>\n"
@ -685,12 +651,13 @@ static void
catman(const struct req *req, const char *file)
{
FILE *f;
size_t len;
int i;
char *p;
size_t sz;
ssize_t len;
int i;
int italic, bold;
if (NULL == (f = fopen(file, "r"))) {
if ((f = fopen(file, "r")) == NULL) {
puts("<P>You specified an invalid manual file.</P>");
return;
}
@ -698,9 +665,12 @@ catman(const struct req *req, const char *file)
puts("<DIV CLASS=\"catman\">\n"
"<PRE>");
while (NULL != (p = fgetln(f, &len))) {
p = NULL;
sz = 0;
while ((len = getline(&p, &sz, f)) != -1) {
bold = italic = 0;
for (i = 0; i < (int)len - 1; i++) {
for (i = 0; i < len - 1; i++) {
/*
* This means that the catpage is out of state.
* Ignore it and keep going (although the
@ -725,7 +695,7 @@ catman(const struct req *req, const char *file)
italic = bold = 0;
html_putchar(p[i]);
continue;
} else if (i + 2 >= (int)len)
} else if (i + 2 >= len)
continue;
/* Italic mode. */
@ -801,11 +771,12 @@ catman(const struct req *req, const char *file)
if (bold)
printf("</B>");
if (i == (int)len - 1 && '\n' != p[i])
if (i == len - 1 && p[i] != '\n')
html_putchar(p[i]);
putchar('\n');
}
free(p);
puts("</PRE>\n"
"</DIV>");
@ -816,12 +787,10 @@ catman(const struct req *req, const char *file)
static void
format(const struct req *req, const char *file)
{
struct manoutput conf;
struct mparse *mp;
struct mchars *mchars;
struct mdoc *mdoc;
struct man *man;
struct roff_man *man;
void *vp;
char *opts;
int fd;
int usepath;
@ -830,42 +799,45 @@ format(const struct req *req, const char *file)
return;
}
mchars = mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL,
mchars, req->q.manpath);
mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, req->q.manpath);
mparse_readfd(mp, fd, file);
close(fd);
memset(&conf, 0, sizeof(conf));
conf.fragment = 1;
usepath = strcmp(req->q.manpath, req->p[0]);
mandoc_asprintf(&opts,
"fragment,man=%s?query=%%N&sec=%%S%s%s%s%s",
mandoc_asprintf(&conf.man, "%s?query=%%N&sec=%%S%s%s%s%s",
scriptname,
req->q.arch ? "&arch=" : "",
req->q.arch ? req->q.arch : "",
usepath ? "&manpath=" : "",
usepath ? req->q.manpath : "");
mparse_result(mp, &mdoc, &man, NULL);
if (NULL == man && NULL == mdoc) {
mparse_result(mp, &man, NULL);
if (man == NULL) {
fprintf(stderr, "fatal mandoc error: %s/%s\n",
req->q.manpath, file);
pg_error_internal();
mparse_free(mp);
mchars_free(mchars);
mchars_free();
return;
}
vp = html_alloc(mchars, opts);
vp = html_alloc(&conf);
if (NULL != mdoc)
html_mdoc(vp, mdoc);
else
if (man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
html_mdoc(vp, man);
} else {
man_validate(man);
html_man(vp, man);
}
html_free(vp);
mparse_free(mp);
mchars_free(mchars);
free(opts);
mchars_free();
free(conf.man);
}
static void
@ -1030,7 +1002,7 @@ main(void)
if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) {
fprintf(stderr, "setitimer: %s\n", strerror(errno));
pg_error_internal();
return(EXIT_FAILURE);
return EXIT_FAILURE;
}
/* Scan our run-time environment. */
@ -1042,7 +1014,7 @@ main(void)
fprintf(stderr, "unsafe SCRIPT_NAME \"%s\"\n",
scriptname);
pg_error_internal();
return(EXIT_FAILURE);
return EXIT_FAILURE;
}
/*
@ -1055,7 +1027,7 @@ main(void)
fprintf(stderr, "MAN_DIR: %s: %s\n",
MAN_DIR, strerror(errno));
pg_error_internal();
return(EXIT_FAILURE);
return EXIT_FAILURE;
}
memset(&req, 0, sizeof(struct req));
@ -1071,13 +1043,13 @@ main(void)
else if ( ! validate_manpath(&req, req.q.manpath)) {
pg_error_badrequest(
"You specified an invalid manpath.");
return(EXIT_FAILURE);
return EXIT_FAILURE;
}
if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
pg_error_badrequest(
"You specified an invalid architecture.");
return(EXIT_FAILURE);
return EXIT_FAILURE;
}
/* Dispatch to the three different pages. */
@ -1102,7 +1074,7 @@ main(void)
for (i = 0; i < (int)req.psz; i++)
free(req.p[i]);
free(req.p);
return(EXIT_SUCCESS);
return EXIT_SUCCESS;
}
/*
@ -1114,6 +1086,7 @@ pathgen(struct req *req)
FILE *fp;
char *dp;
size_t dpsz;
ssize_t len;
if (NULL == (fp = fopen("manpath.conf", "r"))) {
fprintf(stderr, "%s/manpath.conf: %s\n",
@ -1122,12 +1095,14 @@ pathgen(struct req *req)
exit(EXIT_FAILURE);
}
while (NULL != (dp = fgetln(fp, &dpsz))) {
if ('\n' == dp[dpsz - 1])
dpsz--;
dp = NULL;
dpsz = 0;
while ((len = getline(&dp, &dpsz, fp)) != -1) {
if (dp[len - 1] == '\n')
dp[--len] = '\0';
req->p = mandoc_realloc(req->p,
(req->psz + 1) * sizeof(char *));
dp = mandoc_strndup(dp, dpsz);
if ( ! validate_urifrag(dp)) {
fprintf(stderr, "%s/manpath.conf contains "
"unsafe path \"%s\"\n", MAN_DIR, dp);
@ -1141,7 +1116,10 @@ pathgen(struct req *req)
exit(EXIT_FAILURE);
}
req->p[req->psz++] = dp;
dp = NULL;
dpsz = 0;
}
free(dp);
if ( req->p == NULL ) {
fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR);

View File

@ -4,6 +4,4 @@
#define MAN_DIR "/var/www/man"
#define CSS_DIR ""
#define CUSTOMIZE_TITLE "Manual pages with mandoc"
#define CUSTOMIZE_BEGIN "<H2>\nManual pages with " \
"<A HREF=\"http://mdocml.bsd.lv/\">mandoc</A>\n</H2>"
#define COMPAT_OLDURI Yes

485
chars.c
View File

@ -1,7 +1,7 @@
/* $Id: chars.c,v 1.66 2015/02/17 20:37:16 schwarze Exp $ */
/* $Id: chars.c,v 1.68 2015/10/13 22:59:54 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011, 2014, 2015 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
@ -21,90 +21,429 @@
#include <assert.h>
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
#include "libmandoc.h"
#define PRINT_HI 126
#define PRINT_LO 32
struct ln {
struct ln *next;
const char *code;
const char roffcode[16];
const char *ascii;
int unicode;
};
#define LINES_MAX 332
/* Special break control characters. */
static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
static const char ascii_break[2] = { ASCII_BREAK, '\0' };
#define CHAR(in, ch, code) \
{ NULL, (in), (ch), (code) },
static struct ln lines[] = {
#define CHAR_TBL_START static struct ln lines[LINES_MAX] = {
#define CHAR_TBL_END };
/* Spacing. */
{ " ", ascii_nbrsp, 0x00a0 },
{ "~", ascii_nbrsp, 0x00a0 },
{ "0", " ", 0x2002 },
{ "|", "", 0 },
{ "^", "", 0 },
{ "&", "", 0 },
{ "%", "", 0 },
{ ":", ascii_break, 0 },
/* XXX The following three do not really belong here. */
{ "t", "", 0 },
{ "c", "", 0 },
{ "}", "", 0 },
#include "chars.in"
/* Lines. */
{ "ba", "|", 0x007c },
{ "br", "|", 0x2502 },
{ "ul", "_", 0x005f },
{ "rn", "-", 0x203e },
{ "bb", "|", 0x00a6 },
{ "sl", "/", 0x002f },
{ "rs", "\\", 0x005c },
struct mchars {
struct ln **htab;
/* Text markers. */
{ "ci", "O", 0x25cb },
{ "bu", "+\bo", 0x2022 },
{ "dd", "|\b=", 0x2021 },
{ "dg", "|\b-", 0x2020 },
{ "lz", "<>", 0x25ca },
{ "sq", "[]", 0x25a1 },
{ "ps", "<par>", 0x00b6 },
{ "sc", "<sec>", 0x00a7 },
{ "lh", "<=", 0x261c },
{ "rh", "=>", 0x261e },
{ "at", "@", 0x0040 },
{ "sh", "#", 0x0023 },
{ "CR", "_|", 0x21b5 },
{ "OK", "\\/", 0x2713 },
/* Legal symbols. */
{ "co", "(C)", 0x00a9 },
{ "rg", "(R)", 0x00ae },
{ "tm", "tm", 0x2122 },
/* Punctuation. */
{ "em", "--", 0x2014 },
{ "en", "-", 0x2013 },
{ "hy", "-", 0x2010 },
{ "e", "\\", 0x005c },
{ ".", ".", 0x002e },
{ "r!", "!", 0x00a1 },
{ "r?", "?", 0x00bf },
/* Quotes. */
{ "Bq", ",,", 0x201e },
{ "bq", ",", 0x201a },
{ "lq", "\"", 0x201c },
{ "rq", "\"", 0x201d },
{ "Lq", "``", 0x201c },
{ "Rq", "''", 0x201d },
{ "oq", "`", 0x2018 },
{ "cq", "\'", 0x2019 },
{ "aq", "\'", 0x0027 },
{ "dq", "\"", 0x0022 },
{ "Fo", "<<", 0x00ab },
{ "Fc", ">>", 0x00bb },
{ "fo", "<", 0x2039 },
{ "fc", ">", 0x203a },
/* Brackets. */
{ "lB", "[", 0x005b },
{ "rB", "]", 0x005d },
{ "lC", "{", 0x007b },
{ "rC", "}", 0x007d },
{ "la", "<", 0x27e8 },
{ "ra", ">", 0x27e9 },
{ "bv", "|", 0x23aa },
{ "braceex", "|", 0x23aa },
{ "bracketlefttp", "|", 0x23a1 },
{ "bracketleftbt", "|", 0x23a3 },
{ "bracketleftex", "|", 0x23a2 },
{ "bracketrighttp", "|", 0x23a4 },
{ "bracketrightbt", "|", 0x23a6 },
{ "bracketrightex", "|", 0x23a5 },
{ "lt", ",-", 0x23a7 },
{ "bracelefttp", ",-", 0x23a7 },
{ "lk", "{", 0x23a8 },
{ "braceleftmid", "{", 0x23a8 },
{ "lb", "`-", 0x23a9 },
{ "braceleftbt", "`-", 0x23a9 },
{ "braceleftex", "|", 0x23aa },
{ "rt", "-.", 0x23ab },
{ "bracerighttp", "-.", 0x23ab },
{ "rk", "}", 0x23ac },
{ "bracerightmid", "}", 0x23ac },
{ "rb", "-\'", 0x23ad },
{ "bracerightbt", "-\'", 0x23ad },
{ "bracerightex", "|", 0x23aa },
{ "parenlefttp", "/", 0x239b },
{ "parenleftbt", "\\", 0x239d },
{ "parenleftex", "|", 0x239c },
{ "parenrighttp", "\\", 0x239e },
{ "parenrightbt", "/", 0x23a0 },
{ "parenrightex", "|", 0x239f },
/* Arrows and lines. */
{ "<-", "<-", 0x2190 },
{ "->", "->", 0x2192 },
{ "<>", "<->", 0x2194 },
{ "da", "|\bv", 0x2193 },
{ "ua", "|\b^", 0x2191 },
{ "va", "^v", 0x2195 },
{ "lA", "<=", 0x21d0 },
{ "rA", "=>", 0x21d2 },
{ "hA", "<=>", 0x21d4 },
{ "uA", "=\b^", 0x21d1 },
{ "dA", "=\bv", 0x21d3 },
{ "vA", "^=v", 0x21d5 },
/* Logic. */
{ "AN", "^", 0x2227 },
{ "OR", "v", 0x2228 },
{ "no", "~", 0x00ac },
{ "tno", "~", 0x00ac },
{ "te", "3", 0x2203 },
{ "fa", "-\bV", 0x2200 },
{ "st", "-)", 0x220b },
{ "tf", ".:.", 0x2234 },
{ "3d", ".:.", 0x2234 },
{ "or", "|", 0x007c },
/* Mathematicals. */
{ "pl", "+", 0x002b },
{ "mi", "-", 0x2212 },
{ "-", "-", 0x002d },
{ "-+", "-+", 0x2213 },
{ "+-", "+-", 0x00b1 },
{ "t+-", "+-", 0x00b1 },
{ "pc", ".", 0x00b7 },
{ "md", ".", 0x22c5 },
{ "mu", "x", 0x00d7 },
{ "tmu", "x", 0x00d7 },
{ "c*", "O\bx", 0x2297 },
{ "c+", "O\b+", 0x2295 },
{ "di", "-:-", 0x00f7 },
{ "tdi", "-:-", 0x00f7 },
{ "f/", "/", 0x2044 },
{ "**", "*", 0x2217 },
{ "<=", "<=", 0x2264 },
{ ">=", ">=", 0x2265 },
{ "<<", "<<", 0x226a },
{ ">>", ">>", 0x226b },
{ "eq", "=", 0x003d },
{ "!=", "!=", 0x2260 },
{ "==", "==", 0x2261 },
{ "ne", "!==", 0x2262 },
{ "ap", "~", 0x223c },
{ "|=", "-~", 0x2243 },
{ "=~", "=~", 0x2245 },
{ "~~", "~~", 0x2248 },
{ "~=", "~=", 0x2248 },
{ "pt", "oc", 0x221d },
{ "es", "{}", 0x2205 },
{ "mo", "E", 0x2208 },
{ "nm", "!E", 0x2209 },
{ "sb", "(=", 0x2282 },
{ "nb", "(!=", 0x2284 },
{ "sp", "=)", 0x2283 },
{ "nc", "!=)", 0x2285 },
{ "ib", "(=\b_", 0x2286 },
{ "ip", "=\b_)", 0x2287 },
{ "ca", "(^)", 0x2229 },
{ "cu", "U", 0x222a },
{ "/_", "_\b/", 0x2220 },
{ "pp", "_\b|", 0x22a5 },
{ "is", "'\b,\bI", 0x222b },
{ "integral", "'\b,\bI", 0x222b },
{ "sum", "E", 0x2211 },
{ "product", "TT", 0x220f },
{ "coproduct", "U", 0x2210 },
{ "gr", "V", 0x2207 },
{ "sr", "\\/", 0x221a },
{ "sqrt", "\\/", 0x221a },
{ "lc", "|~", 0x2308 },
{ "rc", "~|", 0x2309 },
{ "lf", "|_", 0x230a },
{ "rf", "_|", 0x230b },
{ "if", "oo", 0x221e },
{ "Ah", "N", 0x2135 },
{ "Im", "I", 0x2111 },
{ "Re", "R", 0x211c },
{ "pd", "a", 0x2202 },
{ "-h", "/h", 0x210f },
{ "12", "1/2", 0x00bd },
{ "14", "1/4", 0x00bc },
{ "34", "3/4", 0x00be },
/* Ligatures. */
{ "ff", "ff", 0xfb00 },
{ "fi", "fi", 0xfb01 },
{ "fl", "fl", 0xfb02 },
{ "Fi", "ffi", 0xfb03 },
{ "Fl", "ffl", 0xfb04 },
{ "AE", "AE", 0x00c6 },
{ "ae", "ae", 0x00e6 },
{ "OE", "OE", 0x0152 },
{ "oe", "oe", 0x0153 },
{ "ss", "ss", 0x00df },
{ "IJ", "IJ", 0x0132 },
{ "ij", "ij", 0x0133 },
/* Accents. */
{ "a\"", "\"", 0x02dd },
{ "a-", "-", 0x00af },
{ "a.", ".", 0x02d9 },
{ "a^", "^", 0x005e },
{ "aa", "\'", 0x00b4 },
{ "\'", "\'", 0x00b4 },
{ "ga", "`", 0x0060 },
{ "`", "`", 0x0060 },
{ "ab", "'\b`", 0x02d8 },
{ "ac", ",", 0x00b8 },
{ "ad", "\"", 0x00a8 },
{ "ah", "v", 0x02c7 },
{ "ao", "o", 0x02da },
{ "a~", "~", 0x007e },
{ "ho", ",", 0x02db },
{ "ha", "^", 0x005e },
{ "ti", "~", 0x007e },
/* Accented letters. */
{ "'A", "'\bA", 0x00c1 },
{ "'E", "'\bE", 0x00c9 },
{ "'I", "'\bI", 0x00cd },
{ "'O", "'\bO", 0x00d3 },
{ "'U", "'\bU", 0x00da },
{ "'a", "'\ba", 0x00e1 },
{ "'e", "'\be", 0x00e9 },
{ "'i", "'\bi", 0x00ed },
{ "'o", "'\bo", 0x00f3 },
{ "'u", "'\bu", 0x00fa },
{ "`A", "`\bA", 0x00c0 },
{ "`E", "`\bE", 0x00c8 },
{ "`I", "`\bI", 0x00cc },
{ "`O", "`\bO", 0x00d2 },
{ "`U", "`\bU", 0x00d9 },
{ "`a", "`\ba", 0x00e0 },
{ "`e", "`\be", 0x00e8 },
{ "`i", "`\bi", 0x00ec },
{ "`o", "`\bo", 0x00f2 },
{ "`u", "`\bu", 0x00f9 },
{ "~A", "~\bA", 0x00c3 },
{ "~N", "~\bN", 0x00d1 },
{ "~O", "~\bO", 0x00d5 },
{ "~a", "~\ba", 0x00e3 },
{ "~n", "~\bn", 0x00f1 },
{ "~o", "~\bo", 0x00f5 },
{ ":A", "\"\bA", 0x00c4 },
{ ":E", "\"\bE", 0x00cb },
{ ":I", "\"\bI", 0x00cf },
{ ":O", "\"\bO", 0x00d6 },
{ ":U", "\"\bU", 0x00dc },
{ ":a", "\"\ba", 0x00e4 },
{ ":e", "\"\be", 0x00eb },
{ ":i", "\"\bi", 0x00ef },
{ ":o", "\"\bo", 0x00f6 },
{ ":u", "\"\bu", 0x00fc },
{ ":y", "\"\by", 0x00ff },
{ "^A", "^\bA", 0x00c2 },
{ "^E", "^\bE", 0x00ca },
{ "^I", "^\bI", 0x00ce },
{ "^O", "^\bO", 0x00d4 },
{ "^U", "^\bU", 0x00db },
{ "^a", "^\ba", 0x00e2 },
{ "^e", "^\be", 0x00ea },
{ "^i", "^\bi", 0x00ee },
{ "^o", "^\bo", 0x00f4 },
{ "^u", "^\bu", 0x00fb },
{ ",C", ",\bC", 0x00c7 },
{ ",c", ",\bc", 0x00e7 },
{ "/L", "/\bL", 0x0141 },
{ "/l", "/\bl", 0x0142 },
{ "/O", "/\bO", 0x00d8 },
{ "/o", "/\bo", 0x00f8 },
{ "oA", "o\bA", 0x00c5 },
{ "oa", "o\ba", 0x00e5 },
/* Special letters. */
{ "-D", "-\bD", 0x00d0 },
{ "Sd", "d", 0x00f0 },
{ "TP", "Th", 0x00de },
{ "Tp", "th", 0x00fe },
{ ".i", "i", 0x0131 },
{ ".j", "j", 0x0237 },
/* Currency. */
{ "Do", "$", 0x0024 },
{ "ct", "/\bc", 0x00a2 },
{ "Eu", "EUR", 0x20ac },
{ "eu", "EUR", 0x20ac },
{ "Ye", "=\bY", 0x00a5 },
{ "Po", "GBP", 0x00a3 },
{ "Cs", "o\bx", 0x00a4 },
{ "Fn", ",\bf", 0x0192 },
/* Units. */
{ "de", "<deg>", 0x00b0 },
{ "%0", "%o", 0x2030 },
{ "fm", "\'", 0x2032 },
{ "sd", "''", 0x2033 },
{ "mc", ",\bu", 0x00b5 },
/* Greek characters. */
{ "*A", "A", 0x0391 },
{ "*B", "B", 0x0392 },
{ "*G", "G", 0x0393 },
{ "*D", "_\b/_\b\\", 0x0394 },
{ "*E", "E", 0x0395 },
{ "*Z", "Z", 0x0396 },
{ "*Y", "H", 0x0397 },
{ "*H", "-\bO", 0x0398 },
{ "*I", "I", 0x0399 },
{ "*K", "K", 0x039a },
{ "*L", "/\\", 0x039b },
{ "*M", "M", 0x039c },
{ "*N", "N", 0x039d },
{ "*C", "_\bH", 0x039e },
{ "*O", "O", 0x039f },
{ "*P", "TT", 0x03a0 },
{ "*R", "P", 0x03a1 },
{ "*S", "S", 0x03a3 },
{ "*T", "T", 0x03a4 },
{ "*U", "Y", 0x03a5 },
{ "*F", "I\bO", 0x03a6 },
{ "*X", "X", 0x03a7 },
{ "*Q", "I\bY", 0x03a8 },
{ "*W", "_\bO", 0x03a9 },
{ "*a", "a", 0x03b1 },
{ "*b", "B", 0x03b2 },
{ "*g", "y", 0x03b3 },
{ "*d", "d", 0x03b4 },
{ "*e", "e", 0x03b5 },
{ "*z", ",\bC", 0x03b6 },
{ "*y", "n", 0x03b7 },
{ "*h", "-\b0", 0x03b8 },
{ "*i", "i", 0x03b9 },
{ "*k", "k", 0x03ba },
{ "*l", ">\b\\", 0x03bb },
{ "*m", ",\bu", 0x03bc },
{ "*n", "v", 0x03bd },
{ "*c", ",\bE", 0x03be },
{ "*o", "o", 0x03bf },
{ "*p", "-\bn", 0x03c0 },
{ "*r", "p", 0x03c1 },
{ "*s", "-\bo", 0x03c3 },
{ "*t", "~\bt", 0x03c4 },
{ "*u", "u", 0x03c5 },
{ "*f", "|\bo", 0x03d5 },
{ "*x", "x", 0x03c7 },
{ "*q", "|\bu", 0x03c8 },
{ "*w", "w", 0x03c9 },
{ "+h", "-\b0", 0x03d1 },
{ "+f", "|\bo", 0x03c6 },
{ "+p", "-\bw", 0x03d6 },
{ "+e", "e", 0x03f5 },
{ "ts", "s", 0x03c2 },
};
static const struct ln *find(const struct mchars *,
const char *, size_t);
static struct ohash mchars;
void
mchars_free(struct mchars *arg)
mchars_free(void)
{
free(arg->htab);
free(arg);
ohash_delete(&mchars);
}
struct mchars *
void
mchars_alloc(void)
{
struct mchars *tab;
struct ln **htab;
struct ln *pp;
int i, hash;
size_t i;
unsigned int slot;
/*
* Constructs a very basic chaining hashtable. The hash routine
* is simply the integral value of the first character.
* Subsequent entries are chained in the order they're processed.
*/
tab = mandoc_malloc(sizeof(struct mchars));
htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln *));
for (i = 0; i < LINES_MAX; i++) {
hash = (int)lines[i].code[0] - PRINT_LO;
if (NULL == (pp = htab[hash])) {
htab[hash] = &lines[i];
continue;
}
for ( ; pp->next; pp = pp->next)
/* Scan ahead. */ ;
pp->next = &lines[i];
mandoc_ohash_init(&mchars, 9, offsetof(struct ln, roffcode));
for (i = 0; i < sizeof(lines)/sizeof(lines[0]); i++) {
slot = ohash_qlookup(&mchars, lines[i].roffcode);
assert(ohash_find(&mchars, slot) == NULL);
ohash_insert(&mchars, slot, lines + i);
}
tab->htab = htab;
return(tab);
}
int
mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
mchars_spec2cp(const char *p, size_t sz)
{
const struct ln *ln;
const char *end;
ln = find(arg, p, sz);
return(ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1);
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1;
}
int
@ -113,7 +452,7 @@ mchars_num2char(const char *p, size_t sz)
int i;
i = mandoc_strntoi(p, sz, 10);
return(i >= 0 && i < 256 ? i : -1);
return i >= 0 && i < 256 ? i : -1;
}
int
@ -123,53 +462,33 @@ mchars_num2uc(const char *p, size_t sz)
i = mandoc_strntoi(p, sz, 16);
assert(i >= 0 && i <= 0x10FFFF);
return(i);
return i;
}
const char *
mchars_spec2str(const struct mchars *arg,
const char *p, size_t sz, size_t *rsz)
mchars_spec2str(const char *p, size_t sz, size_t *rsz)
{
const struct ln *ln;
const char *end;
ln = find(arg, p, sz);
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
if (ln == NULL) {
*rsz = 1;
return(sz == 1 ? p : NULL);
return sz == 1 ? p : NULL;
}
*rsz = strlen(ln->ascii);
return(ln->ascii);
return ln->ascii;
}
const char *
mchars_uc2str(int uc)
{
int i;
size_t i;
for (i = 0; i < LINES_MAX; i++)
for (i = 0; i < sizeof(lines)/sizeof(lines[0]); 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)
{
const struct ln *pp;
int hash;
assert(p);
if (0 == sz || p[0] < PRINT_LO || p[0] > PRINT_HI)
return(NULL);
hash = (int)p[0] - PRINT_LO;
for (pp = tab->htab[hash]; pp; pp = pp->next)
if (0 == strncmp(pp->code, p, sz) &&
'\0' == pp->code[(int)sz])
return(pp);
return(NULL);
return lines[i].ascii;
return "<?>";
}

404
chars.in
View File

@ -1,404 +0,0 @@
/* $Id: chars.in,v 1.52 2015/02/17 20:37:16 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* The ASCII translation tables.
*
* The left-hand side corresponds to the input sequence (\x, \(xx, \*(xx
* and so on) whose length is listed second element. The right-hand
* side is what's produced by the front-end, with the fourth element
* being its length.
*
* XXX - C-escape strings!
* XXX - update LINES_MAX if adding more!
*/
/* Special break control characters. */
static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
static const char ascii_break[2] = { ASCII_BREAK, '\0' };
CHAR_TBL_START
/* Spacing. */
CHAR(" ", ascii_nbrsp, 160)
CHAR("~", ascii_nbrsp, 160)
CHAR("0", " ", 8194)
CHAR("|", "", 0)
CHAR("^", "", 0)
CHAR("&", "", 0)
CHAR("%", "", 0)
CHAR(":", ascii_break, 0)
/* XXX The following three do not really belong into this file. */
CHAR("t", "", 0)
CHAR("c", "", 0)
CHAR("}", "", 0)
/* Accents. */
CHAR("a\"", "\"", 733)
CHAR("a-", "-", 175)
CHAR("a.", ".", 729)
CHAR("a^", "^", 94)
CHAR("\'", "\'", 180)
CHAR("aa", "\'", 180)
CHAR("ga", "`", 96)
CHAR("`", "`", 96)
CHAR("ab", "'\b`", 728)
CHAR("ac", ",", 184)
CHAR("ad", "\"", 168)
CHAR("ah", "v", 711)
CHAR("ao", "o", 730)
CHAR("a~", "~", 126)
CHAR("ho", ",", 731)
CHAR("ha", "^", 94)
CHAR("ti", "~", 126)
/* Quotes. */
CHAR("Bq", ",,", 8222)
CHAR("bq", ",", 8218)
CHAR("lq", "\"", 8220)
CHAR("rq", "\"", 8221)
CHAR("Lq", "``", 8220)
CHAR("Rq", "''", 8221)
CHAR("oq", "`", 8216)
CHAR("cq", "\'", 8217)
CHAR("aq", "\'", 39)
CHAR("dq", "\"", 34)
CHAR("Fo", "<<", 171)
CHAR("Fc", ">>", 187)
CHAR("fo", "<", 8249)
CHAR("fc", ">", 8250)
/* Brackets. */
CHAR("lB", "[", 91)
CHAR("rB", "]", 93)
CHAR("lC", "{", 123)
CHAR("rC", "}", 125)
CHAR("la", "<", 10216)
CHAR("ra", ">", 10217)
CHAR("bv", "|", 9130)
CHAR("braceex", "|", 9130)
CHAR("bracketlefttp", "|", 9121)
CHAR("bracketleftbt", "|", 9123)
CHAR("bracketleftex", "|", 9122)
CHAR("bracketrighttp", "|", 9124)
CHAR("bracketrightbt", "|", 9126)
CHAR("bracketrightex", "|", 9125)
CHAR("lt", ",-", 9127)
CHAR("bracelefttp", ",-", 9127)
CHAR("lk", "{", 9128)
CHAR("braceleftmid", "{", 9128)
CHAR("lb", "`-", 9129)
CHAR("braceleftbt", "`-", 9129)
CHAR("braceleftex", "|", 9130)
CHAR("rt", "-.", 9131)
CHAR("bracerighttp", "-.", 9131)
CHAR("rk", "}", 9132)
CHAR("bracerightmid", "}", 9132)
CHAR("rb", "-\'", 9133)
CHAR("bracerightbt", "-\'", 9133)
CHAR("bracerightex", "|", 9130)
CHAR("parenlefttp", "/", 9115)
CHAR("parenleftbt", "\\", 9117)
CHAR("parenleftex", "|", 9116)
CHAR("parenrighttp", "\\", 9118)
CHAR("parenrightbt", "/", 9120)
CHAR("parenrightex", "|", 9119)
/* Greek characters. */
CHAR("*A", "A", 913)
CHAR("*B", "B", 914)
CHAR("*G", "G", 915)
CHAR("*D", "_\b/_\b\\", 916)
CHAR("*E", "E", 917)
CHAR("*Z", "Z", 918)
CHAR("*Y", "H", 919)
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", "_\bH", 926)
CHAR("*O", "O", 927)
CHAR("*P", "TT", 928)
CHAR("*R", "P", 929)
CHAR("*S", "S", 931)
CHAR("*T", "T", 932)
CHAR("*U", "Y", 933)
CHAR("*F", "I\bO", 934)
CHAR("*X", "X", 935)
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", ",\bC", 950)
CHAR("*y", "n", 951)
CHAR("*h", "-\b0", 952)
CHAR("*i", "i", 953)
CHAR("*k", "k", 954)
CHAR("*l", ">\b\\", 955)
CHAR("*m", ",\bu", 956)
CHAR("*n", "v", 957)
CHAR("*c", ",\bE", 958)
CHAR("*o", "o", 959)
CHAR("*p", "-\bn", 960)
CHAR("*r", "p", 961)
CHAR("*s", "-\bo", 963)
CHAR("*t", "~\bt", 964)
CHAR("*u", "u", 965)
CHAR("*f", "|\bo", 981)
CHAR("*x", "x", 967)
CHAR("*q", "|\bu", 968)
CHAR("*w", "w", 969)
CHAR("+h", "-\b0", 977)
CHAR("+f", "|\bo", 966)
CHAR("+p", "-\bw", 982)
CHAR("+e", "e", 1013)
CHAR("ts", "s", 962)
/* Accented letters. */
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", "|\bv", 8595)
CHAR("ua", "|\b^", 8593)
CHAR("va", "^v", 8597)
CHAR("lA", "<=", 8656)
CHAR("rA", "=>", 8658)
CHAR("hA", "<=>", 8660)
CHAR("dA", "=\bv", 8659)
CHAR("uA", "=\b^", 8657)
CHAR("vA", "^=v", 8661)
/* Logic. */
CHAR("AN", "^", 8743)
CHAR("OR", "v", 8744)
CHAR("no", "~", 172)
CHAR("tno", "~", 172)
CHAR("te", "3", 8707)
CHAR("fa", "-\bV", 8704)
CHAR("st", "-)", 8715)
CHAR("tf", ".:.", 8756)
CHAR("3d", ".:.", 8756)
CHAR("or", "|", 124)
/* Mathematicals. */
CHAR("pl", "+", 43)
CHAR("mi", "-", 8722)
CHAR("-", "-", 45)
CHAR("-+", "-+", 8723)
CHAR("+-", "+-", 177)
CHAR("t+-", "+-", 177)
CHAR("pc", ".", 183)
CHAR("md", ".", 8901)
CHAR("mu", "x", 215)
CHAR("tmu", "x", 215)
CHAR("c*", "O\bx", 8855)
CHAR("c+", "O\b+", 8853)
CHAR("di", "-:-", 247)
CHAR("tdi", "-:-", 247)
CHAR("f/", "/", 8260)
CHAR("**", "*", 8727)
CHAR("<=", "<=", 8804)
CHAR(">=", ">=", 8805)
CHAR("<<", "<<", 8810)
CHAR(">>", ">>", 8811)
CHAR("eq", "=", 61)
CHAR("!=", "!=", 8800)
CHAR("==", "==", 8801)
CHAR("ne", "!==", 8802)
CHAR("=~", "=~", 8773)
CHAR("|=", "-~", 8771)
CHAR("ap", "~", 8764)
CHAR("~~", "~~", 8776)
CHAR("~=", "~=", 8776)
CHAR("pt", "oc", 8733)
CHAR("es", "{}", 8709)
CHAR("mo", "E", 8712)
CHAR("nm", "!E", 8713)
CHAR("sb", "(=", 8834)
CHAR("nb", "(!=", 8836)
CHAR("sp", "=)", 8835)
CHAR("nc", "!=)", 8837)
CHAR("ib", "(=\b_", 8838)
CHAR("ip", "=\b_)", 8839)
CHAR("ca", "(^)", 8745)
CHAR("cu", "U", 8746)
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)
CHAR("gr", "V", 8711)
CHAR("sr", "\\/", 8730)
CHAR("sqrt", "\\/", 8730)
CHAR("lc", "|~", 8968)
CHAR("rc", "~|", 8969)
CHAR("lf", "|_", 8970)
CHAR("rf", "_|", 8971)
CHAR("if", "oo", 8734)
CHAR("Ah", "N", 8501)
CHAR("Im", "I", 8465)
CHAR("Re", "R", 8476)
CHAR("pd", "a", 8706)
CHAR("-h", "/h", 8463)
CHAR("12", "1/2", 189)
CHAR("14", "1/4", 188)
CHAR("34", "3/4", 190)
/* Ligatures. */
CHAR("ff", "ff", 64256)
CHAR("fi", "fi", 64257)
CHAR("fl", "fl", 64258)
CHAR("Fi", "ffi", 64259)
CHAR("Fl", "ffl", 64260)
CHAR("AE", "AE", 198)
CHAR("ae", "ae", 230)
CHAR("OE", "OE", 338)
CHAR("oe", "oe", 339)
CHAR("ss", "ss", 223)
CHAR("IJ", "IJ", 306)
CHAR("ij", "ij", 307)
/* Special letters. */
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", "/\bc", 162)
CHAR("Eu", "EUR", 8364)
CHAR("eu", "EUR", 8364)
CHAR("Ye", "=\bY", 165)
CHAR("Po", "GBP", 163)
CHAR("Cs", "o\bx", 164)
CHAR("Fn", ",\bf", 402)
/* Lines. */
CHAR("ba", "|", 124)
CHAR("br", "|", 9474)
CHAR("ul", "_", 95)
CHAR("rn", "-", 8254)
CHAR("bb", "|", 166)
CHAR("sl", "/", 47)
CHAR("rs", "\\", 92)
/* Text markers. */
CHAR("ci", "O", 9675)
CHAR("bu", "+\bo", 8226)
CHAR("dd", "|\b=", 8225)
CHAR("dg", "|\b-", 8224)
CHAR("lz", "<>", 9674)
CHAR("sq", "[]", 9633)
CHAR("ps", "<par>", 182)
CHAR("sc", "<sec>", 167)
CHAR("lh", "<=", 9756)
CHAR("rh", "=>", 9758)
CHAR("at", "@", 64)
CHAR("sh", "#", 35)
CHAR("CR", "_|", 8629)
CHAR("OK", "\\/", 10003)
/* Legal symbols. */
CHAR("co", "(C)", 169)
CHAR("rg", "(R)", 174)
CHAR("tm", "tm", 8482)
/* Punctuation. */
CHAR(".", ".", 46)
CHAR("r!", "!", 161)
CHAR("r?", "?", 191)
CHAR("em", "--", 8212)
CHAR("en", "-", 8211)
CHAR("hy", "-", 8208)
CHAR("e", "\\", 92)
/* Units. */
CHAR("de", "<deg>", 176)
CHAR("%0", "%o", 8240)
CHAR("fm", "\'", 8242)
CHAR("sd", "''", 8243)
CHAR("mc", ",\bu", 181)
CHAR_TBL_END

112
compat_err.c Normal file
View File

@ -0,0 +1,112 @@
#include "config.h"
#if HAVE_ERR
int dummy;
#else
/* $Id: compat_err.c,v 1.4 2015/11/26 07:42:11 schwarze Exp $ */
/*
* Copyright (c) 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.
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void vwarni(const char *, va_list);
static void vwarnxi(const char *, va_list);
static void
vwarnxi(const char *fmt, va_list ap)
{
fprintf(stderr, "%s: ", getprogname());
if (fmt != NULL)
vfprintf(stderr, fmt, ap);
}
static void
vwarni(const char *fmt, va_list ap)
{
int sverrno;
sverrno = errno;
vwarnxi(fmt, ap);
if (fmt != NULL)
fputs(": ", stderr);
fprintf(stderr, "%s\n", strerror(sverrno));
}
void
err(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarni(fmt, ap);
va_end(ap);
exit(eval);
}
void
errx(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnxi(fmt, ap);
va_end(ap);
fputc('\n', stderr);
exit(eval);
}
void
warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarni(fmt, ap);
va_end(ap);
}
void
warnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnxi(fmt, ap);
va_end(ap);
fputc('\n', stderr);
}
#endif

View File

@ -1,94 +0,0 @@
#include "config.h"
#if HAVE_FGETLN
int dummy;
#else
/* $NetBSD: fgetln.c,v 1.3 2006/09/25 07:18:17 lukem Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *
fgetln(fp, len)
FILE *fp;
size_t *len;
{
static char *buf = NULL;
static size_t bufsiz = 0;
char *ptr;
if (buf == NULL) {
bufsiz = BUFSIZ;
if ((buf = malloc(bufsiz)) == NULL)
return NULL;
}
if (fgets(buf, bufsiz, fp) == NULL)
return NULL;
*len = 0;
while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
size_t nbufsiz = bufsiz + BUFSIZ;
char *nbuf = realloc(buf, nbufsiz);
if (nbuf == NULL) {
int oerrno = errno;
free(buf);
errno = oerrno;
buf = NULL;
return NULL;
} else
buf = nbuf;
*len = bufsiz;
if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL)
return buf;
bufsiz = nbufsiz;
}
*len = (ptr - buf) + 1;
return buf;
}
#endif

View File

@ -6,7 +6,7 @@ int dummy;
#else
/* $Id: compat_fts.c,v 1.8 2015/02/07 07:53:01 schwarze Exp $ */
/* $Id: compat_fts.c,v 1.9 2015/03/18 19:29:48 schwarze Exp $ */
/* $OpenBSD: fts.c,v 1.50 2015/01/16 16:48:51 deraadt Exp $ */
/*-
@ -60,7 +60,6 @@ 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])))
#ifndef O_DIRECTORY
@ -74,8 +73,6 @@ static int fts_safe_changedir(FTS *, FTSENT *, int, const char *);
#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)
{
@ -146,17 +143,6 @@ fts_open(char * const *argv, int options, void *dummy)
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 | O_CLOEXEC)) < 0)
SET(FTS_NOCHDIR);
if (nitems == 0)
free(parent);
@ -197,7 +183,6 @@ int
fts_close(FTS *sp)
{
FTSENT *freep, *p;
int rfd, error = 0;
/*
* This still works if we haven't read anything -- the dummy structure
@ -213,25 +198,13 @@ fts_close(FTS *sp)
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);
return (0);
}
/*
@ -274,25 +247,11 @@ fts_read(FTS *sp)
}
/*
* 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;
}
/* nothing */
} else if ((sp->fts_child = fts_build(sp)) == NULL) {
if (ISSET(FTS_STOP))
return (NULL);
@ -313,10 +272,6 @@ next: tmp = p;
* 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);
}
@ -352,23 +307,6 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent);
/* 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);
}
@ -414,7 +352,7 @@ fts_build(FTS *sp)
DIR *dirp;
void *oldaddr;
size_t dlen, len, maxlen;
int nitems, cderrno, descend, level, doadjust;
int nitems, level, doadjust;
int saved_errno;
char *cp;
@ -431,32 +369,6 @@ fts_build(FTS *sp)
return (NULL);
}
/*
* 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)) {
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.
@ -468,10 +380,8 @@ fts_build(FTS *sp)
* each new name into the path.
*/
len = NAPPEND(cur);
if (ISSET(FTS_NOCHDIR)) {
cp = sp->fts_path + len;
*cp++ = '/';
}
cp = sp->fts_path + len;
*cp++ = '/';
len++;
maxlen = sp->fts_pathlen - len;
@ -518,8 +428,7 @@ mem1: saved_errno = errno;
/* Did realloc() change the pointer? */
if (oldaddr != sp->fts_path) {
doadjust = 1;
if (ISSET(FTS_NOCHDIR))
cp = sp->fts_path + len;
cp = sp->fts_path + len;
}
maxlen = sp->fts_pathlen - len;
}
@ -542,20 +451,11 @@ mem1: saved_errno = errno;
return (NULL);
}
if (cderrno) {
p->fts_info = FTS_NS;
p->fts_errno = cderrno;
p->fts_accpath = cur->fts_accpath;
} 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);
}
/* Build a file name for fts_stat to stat. */
p->fts_accpath = p->fts_path;
memmove(cp, p->fts_name, p->fts_namelen + 1);
/* Stat it. */
p->fts_info = fts_stat(sp, p);
/* We walk in directory order so "ls -f" doesn't get upset. */
p->fts_link = NULL;
@ -581,26 +481,9 @@ mem1: saved_errno = errno;
* 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 (len == sp->fts_pathlen || nitems == 0)
--cp;
*cp = '\0';
/* If didn't find anything, return NULL. */
if (!nitems) {
@ -771,38 +654,4 @@ fts_maxarglen(char * const *argv)
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|O_DIRECTORY|O_CLOEXEC)) < 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

View File

@ -40,13 +40,12 @@ typedef struct {
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_OPTIONMASK 0x0054 /* valid user option mask */
#define FTS_STOP 0x2000 /* (private) unrecoverable error */
int fts_options; /* fts_open options, global flags */
@ -85,9 +84,6 @@ typedef struct _ftsent {
#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 */
@ -96,11 +92,10 @@ typedef struct _ftsent {
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_ */

68
compat_getline.c Normal file
View File

@ -0,0 +1,68 @@
#include "config.h"
#if HAVE_GETLINE
int dummy;
#else
/* $Id: compat_getline.c,v 1.1 2015/11/07 20:52:52 schwarze Exp $ */
/*
* Copyright (c) 2015 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.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
ssize_t
getline(char **buf, size_t *bufsz, FILE *fp)
{
char *nbuf;
size_t nbufsz, pos;
int c;
if (buf == NULL || bufsz == NULL) {
errno = EINVAL;
return -1;
}
if (*buf == NULL)
*bufsz = 0;
else
**buf = '\0';
pos = 0;
for (;;) {
if (pos + 1 >= *bufsz) {
nbufsz = *bufsz ? *bufsz * 2 : BUFSIZ;
if ((nbuf = realloc(*buf, nbufsz)) == NULL)
return -1;
*buf = nbuf;
*bufsz = nbufsz;
}
if ((c = fgetc(fp)) == EOF) {
(*buf)[pos] = '\0';
return pos > 0 && feof(fp) ? (ssize_t)pos : -1;
}
(*buf)[pos++] = c;
(*buf)[pos] = '\0';
if (c == '\n')
return pos;
}
}
#endif

33
compat_isblank.c Normal file
View File

@ -0,0 +1,33 @@
#include "config.h"
#if HAVE_ISBLANK
int dummy;
#else
/* $Id: compat_isblank.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2015 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.
*/
int
isblank(int c)
{
return c == ' ' || c == '\t';
}
#endif

61
compat_mkdtemp.c Normal file
View File

@ -0,0 +1,61 @@
#include "config.h"
#if HAVE_MKDTEMP
int dummy;
#else
/* $Id: compat_mkdtemp.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2015 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.
*
* The algorithm of this function is inspired by OpenBSD mkdtemp(3)
* by Theo de Raadt and Todd Miller, but the code differs.
*/
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
char *
mkdtemp(char *path)
{
char *start, *cp;
unsigned int tries;
start = strchr(path, '\0');
while (start > path && start[-1] == 'X')
start--;
for (tries = INT_MAX; tries; tries--) {
if (mktemp(path) == NULL) {
errno = EEXIST;
return NULL;
}
if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0)
return path;
if (errno != EEXIST)
return NULL;
for (cp = start; *cp != '\0'; cp++)
*cp = 'X';
}
errno = EEXIST;
return NULL;
}
#endif

View File

@ -49,7 +49,6 @@ struct ohash {
* a hashing table index (opaque) to be used in find/insert/remove.
* The keys are stored at a known position in the client data.
*/
__BEGIN_DECLS
void ohash_init(struct ohash *, unsigned, struct ohash_info *);
void ohash_delete(struct ohash *);
@ -69,5 +68,5 @@ uint32_t ohash_interval(const char *, const char **);
unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
unsigned int ohash_qlookup(struct ohash *, const char *);
__END_DECLS
#endif

42
compat_progname.c Normal file
View File

@ -0,0 +1,42 @@
#include "config.h"
#if HAVE_PROGNAME
int dummy;
#else
/* $Id: compat_progname.c,v 1.1 2015/11/06 16:30:33 schwarze Exp $ */
/*
* Copyright (c) 2015 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.
*/
static const char *progname;
void
setprogname(const char *name)
{
progname = name;
}
const char *
getprogname(void)
{
return progname;
}
#endif

View File

@ -10,7 +10,7 @@ const char *
sqlite3_errstr(int rc)
{
return(rc ? "unknown error" : "not an error");
return rc ? "unknown error" : "not an error";
}
#endif

119
compat_stringlist.c Normal file
View File

@ -0,0 +1,119 @@
#include "config.h"
#if HAVE_STRINGLIST
int dummy;
#else
/* $Id: compat_stringlist.c,v 1.6 2015/11/07 14:22:29 schwarze Exp $ */
/*
* Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#if HAVE_ERR
#include <err.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "compat_stringlist.h"
#define _SL_CHUNKSIZE 20
/*
* sl_init(): Initialize a string list
*/
StringList *
sl_init(void)
{
StringList *sl;
sl = malloc(sizeof(StringList));
if (sl == NULL)
err(1, "stringlist");
sl->sl_cur = 0;
sl->sl_max = _SL_CHUNKSIZE;
sl->sl_str = reallocarray(NULL, sl->sl_max, sizeof(char *));
if (sl->sl_str == NULL)
err(1, "stringlist");
return sl;
}
/*
* sl_add(): Add an item to the string list
*/
int
sl_add(StringList *sl, char *name)
{
if (sl->sl_cur == sl->sl_max - 1) {
sl->sl_max += _SL_CHUNKSIZE;
sl->sl_str = reallocarray(sl->sl_str,
sl->sl_max, sizeof(char *));
if (sl->sl_str == NULL)
return (-1);
}
sl->sl_str[sl->sl_cur++] = name;
return (0);
}
/*
* sl_free(): Free a stringlist
*/
void
sl_free(StringList *sl, int all)
{
size_t i;
if (sl == NULL)
return;
if (sl->sl_str) {
if (all)
for (i = 0; i < sl->sl_cur; i++)
free(sl->sl_str[i]);
free(sl->sl_str);
}
free(sl);
}
/*
* sl_find(): Find a name in the string list
*/
char *
sl_find(StringList *sl, const char *name)
{
size_t i;
for (i = 0; i < sl->sl_cur; i++)
if (strcmp(sl->sl_str[i], name) == 0)
return sl->sl_str[i];
return NULL;
}
#endif

45
compat_stringlist.h Normal file
View File

@ -0,0 +1,45 @@
/* $Id: compat_stringlist.h,v 1.4 2015/11/07 14:01:16 schwarze Exp $ */
/* $NetBSD: stringlist.h,v 1.2 1997/01/17 06:11:36 lukem Exp $ */
/*
* Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
/*
* Simple string list
*/
typedef struct _stringlist {
char **sl_str;
size_t sl_max;
size_t sl_cur;
} StringList;
StringList *sl_init(void);
int sl_add(StringList *, char *);
void sl_free(StringList *, int);
char *sl_find(StringList *, const char *);

56
compat_vasprintf.c Normal file
View File

@ -0,0 +1,56 @@
#include "config.h"
#if HAVE_VASPRINTF
int dummy;
#else
/* $Id: compat_vasprintf.c,v 1.3 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2015 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.
*
* This fallback implementation is not efficient:
* It does the formatting twice.
* Short of fiddling with the unknown internals of the system's
* printf(3) or completely reimplementing printf(3), i can't think
* of another portable solution.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
int
vasprintf(char **ret, const char *format, va_list ap)
{
char buf[2];
va_list ap2;
int sz;
va_copy(ap2, ap);
sz = vsnprintf(buf, sizeof(buf), format, ap2);
va_end(ap2);
if (sz != -1 && (*ret = malloc(sz + 1)) != NULL) {
if (vsnprintf(*ret, sz + 1, format, ap) == sz)
return sz;
free(*ret);
}
*ret = NULL;
return -1;
}
#endif

53
config.h Normal file
View File

@ -0,0 +1,53 @@
#ifdef __cplusplus
#error "Do not use C++. See the INSTALL file."
#endif
#ifndef MANDOC_CONFIG_H
#define MANDOC_CONFIG_H
#if defined(__linux__) || defined(__MINT__)
#define _GNU_SOURCE /* See test-*.c what needs this. */
#endif
#include <sys/types.h>
#include <stdio.h>
#define MAN_CONF_FILE "/etc/man.conf"
#define MANPATH_DEFAULT "/usr/share/man:/usr/X11R6/man:/usr/local/man"
#define HAVE_DIRENT_NAMLEN 1
#define HAVE_ERR 1
#define HAVE_FTS 1
#define HAVE_GETLINE 0
#define HAVE_GETSUBOPT 1
#define HAVE_ISBLANK 1
#define HAVE_MKDTEMP 1
#define HAVE_MMAP 1
#define HAVE_PLEDGE 0
#define HAVE_PROGNAME 1
#define HAVE_REALLOCARRAY 1
#define HAVE_REWB_BSD 0
#define HAVE_REWB_SYSV 0
#define HAVE_STRCASESTR 1
#define HAVE_STRINGLIST 0
#define HAVE_STRLCAT 1
#define HAVE_STRLCPY 1
#define HAVE_STRPTIME 1
#define HAVE_STRSEP 1
#define HAVE_STRTONUM 1
#define HAVE_VASPRINTF 1
#define HAVE_WCHAR 1
#define HAVE_SQLITE3 1
#define HAVE_SQLITE3_ERRSTR 0
#define HAVE_OHASH 0
#define HAVE_MANPATH 1
#define BINM_APROPOS "apropos"
#define BINM_MAKEWHATIS "makewhatis"
#define BINM_MAN "man"
#define BINM_SOELIM "soelim"
#define BINM_WHATIS "whatis"
extern ssize_t getline(char **, size_t *, FILE *);
extern const char *sqlite3_errstr(int);
#endif /* MANDOC_CONFIG_H */

210
config.log Normal file
View File

@ -0,0 +1,210 @@
configure.local: no (fully automatic configuration)
dirent-namlen: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-dirent-namlen test-dirent-namlen.c
dirent-namlen: cc succeeded
dirent-namlen: yes
err: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-err test-err.c
err: cc succeeded
test-err: 1. warnx
test-err: 2. warn: No error: 0
test-err: 3. err: No error: 0
err: yes
fts: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-fts test-fts.c
fts: cc succeeded
fts: yes
getline: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-getline test-getline.c
test-getline.c:12:9: error: implicit declaration of function 'getline' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return getline(&line, &linesz, stdin) != -1;
^
1 error generated.
getline: cc failed with 1
getsubopt: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-getsubopt test-getsubopt.c
getsubopt: cc succeeded
getsubopt: yes
isblank: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-isblank test-isblank.c
isblank: cc succeeded
isblank: yes
mkdtemp: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-mkdtemp test-mkdtemp.c
mkdtemp: cc succeeded
mkdtemp: yes
mmap: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-mmap test-mmap.c
mmap: cc succeeded
mmap: yes
pledge: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-pledge test-pledge.c
test-pledge.c:6:11: error: implicit declaration of function 'pledge' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return !!pledge("stdio", NULL);
^
1 error generated.
pledge: cc failed with 1
progname: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-progname test-progname.c
progname: cc succeeded
progname: yes
reallocarray: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-reallocarray test-reallocarray.c
reallocarray: cc succeeded
reallocarray: yes
rewb-bsd: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-rewb-bsd test-rewb-bsd.c
test-rewb-bsd.c:11:42: error: use of undeclared identifier 'NULL'
if (regexec(&re, "the word is here", 0, NULL, 0))
^
test-rewb-bsd.c:13:35: error: use of undeclared identifier 'NULL'
if (regexec(&re, "same word", 0, NULL, 0))
^
test-rewb-bsd.c:15:36: error: use of undeclared identifier 'NULL'
if (regexec(&re, "word again", 0, NULL, 0))
^
test-rewb-bsd.c:17:30: error: use of undeclared identifier 'NULL'
if (regexec(&re, "word", 0, NULL, 0))
^
test-rewb-bsd.c:19:31: error: use of undeclared identifier 'NULL'
if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH)
^
test-rewb-bsd.c:21:31: error: use of undeclared identifier 'NULL'
if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH)
^
test-rewb-bsd.c:23:34: error: use of undeclared identifier 'NULL'
if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH)
^
7 errors generated.
rewb-bsd: cc failed with 1
rewb-sysv: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-rewb-sysv test-rewb-sysv.c
test-rewb-sysv.c:11:42: error: use of undeclared identifier 'NULL'
if (regexec(&re, "the word is here", 0, NULL, 0))
^
test-rewb-sysv.c:13:35: error: use of undeclared identifier 'NULL'
if (regexec(&re, "same word", 0, NULL, 0))
^
test-rewb-sysv.c:15:36: error: use of undeclared identifier 'NULL'
if (regexec(&re, "word again", 0, NULL, 0))
^
test-rewb-sysv.c:17:30: error: use of undeclared identifier 'NULL'
if (regexec(&re, "word", 0, NULL, 0))
^
test-rewb-sysv.c:19:31: error: use of undeclared identifier 'NULL'
if (regexec(&re, "wordy", 0, NULL, 0) != REG_NOMATCH)
^
test-rewb-sysv.c:21:31: error: use of undeclared identifier 'NULL'
if (regexec(&re, "sword", 0, NULL, 0) != REG_NOMATCH)
^
test-rewb-sysv.c:23:34: error: use of undeclared identifier 'NULL'
if (regexec(&re, "reworded", 0, NULL, 0) != REG_NOMATCH)
^
7 errors generated.
rewb-sysv: cc failed with 1
strcasestr: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-strcasestr test-strcasestr.c
strcasestr: cc succeeded
strcasestr: yes
stringlist: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-stringlist test-stringlist.c
test-stringlist.c:26:26: error: use of undeclared identifier 'NULL'
if ((sl = sl_init()) == NULL)
^
1 error generated.
stringlist: cc failed with 1
strlcat: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-strlcat test-strlcat.c
strlcat: cc succeeded
strlcat: yes
strlcpy: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-strlcpy test-strlcpy.c
strlcpy: cc succeeded
strlcpy: yes
strptime: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-strptime test-strptime.c
strptime: cc succeeded
strptime: yes
strsep: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-strsep test-strsep.c
strsep: cc succeeded
strsep: yes
strtonum: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-strtonum test-strtonum.c
strtonum: cc succeeded
strtonum: yes
vasprintf: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-vasprintf test-vasprintf.c
vasprintf: cc succeeded
vasprintf: yes
wchar: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-wchar test-wchar.c
wchar: cc succeeded
*wchar: yes
sqlite3: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -lsqlite3 -o test-sqlite3 test-sqlite3.c
test-sqlite3.c:20:10: fatal error: 'sqlite3.h' file not found
#include <sqlite3.h>
^
1 error generated.
sqlite3: cc failed with 1
sqlite3: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -I/usr/local/include -L/usr/local/lib -lsqlite3 -o test-sqlite3 test-sqlite3.c
sqlite3: cc succeeded
sqlite3: yes
sqlite3_errstr: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -L/usr/local/lib -lsqlite3 -o test-sqlite3_errstr test-sqlite3_errstr.c
test-sqlite3_errstr.c:2:10: fatal error: 'sqlite3.h' file not found
#include <sqlite3.h>
^
1 error generated.
sqlite3_errstr: cc failed with 1
ohash: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -o test-ohash test-ohash.c
test-ohash.c:4:10: fatal error: 'ohash.h' file not found
#include <ohash.h>
^
1 error generated.
ohash: cc failed with 1
ohash: testing...
cc -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -Wno-unused -Werror -lutil -o test-ohash test-ohash.c
test-ohash.c:4:10: fatal error: 'ohash.h' file not found
#include <ohash.h>
^
1 error generated.
ohash: cc failed with 1
DBLIB="-L/usr/local/lib -lsqlite3 -lz"
/usr/share/man:/usr/local/man:/usr/share/openssl/man:/usr/local/lib/perl5/site_perl/man:/usr/local/lib/perl5/5.20/perl/man:/usr/local/share/xpdf/man
manpath: yes
config.h: written
Makefile.local: written

116
configure vendored
View File

@ -16,8 +16,8 @@
set -e
[ -e config.log ] && mv config.log config.log.old
[ -e config.h ] && mv config.h config.h.old
[ -w config.log ] && mv config.log config.log.old
[ -w config.h ] && mv config.h config.h.old
# Output file descriptor usage:
# 1 (stdout): config.h, Makefile.local
@ -31,6 +31,7 @@ echo "config.log: writing..."
# Initialize all variables here,
# such that nothing can leak in from the environment.
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
OSNAME=
CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make -f -`
@ -42,17 +43,26 @@ BUILD_DB=1
BUILD_CGI=0
HAVE_DIRENT_NAMLEN=
HAVE_FGETLN=
HAVE_ERR=
HAVE_FTS=
HAVE_GETLINE=
HAVE_GETSUBOPT=
HAVE_ISBLANK=
HAVE_MKDTEMP=
HAVE_MMAP=
HAVE_PLEDGE=
HAVE_PROGNAME=
HAVE_REALLOCARRAY=
HAVE_REWB_BSD=
HAVE_REWB_SYSV=
HAVE_STRCASESTR=
HAVE_STRINGLIST=
HAVE_STRLCAT=
HAVE_STRLCPY=
HAVE_STRPTIME=
HAVE_STRSEP=
HAVE_STRTONUM=
HAVE_VASPRINTF=
HAVE_WCHAR=
HAVE_SQLITE3=
@ -66,7 +76,6 @@ SBINDIR=
INCLUDEDIR=
LIBDIR=
MANDIR=
EXAMPLEDIR=
HOMEBREWDIR=
WWWPREFIX="/var/www"
@ -74,10 +83,12 @@ HTDOCDIR=
CGIBINDIR=
BINM_APROPOS="apropos"
BINM_MAN="man"
BINM_WHATIS="whatis"
BINM_MAKEWHATIS="makewhatis"
BINM_MAN="man"
BINM_SOELIM="soelim"
BINM_WHATIS="whatis"
MANM_MAN="man"
MANM_MANCONF="man.conf"
MANM_MDOC="mdoc"
MANM_ROFF="roff"
MANM_EQN="eqn"
@ -91,7 +102,7 @@ INSTALL_DATA=
# --- manual settings from configure.local -----------------------------
if [ -e ./configure.local ]; then
if [ -r ./configure.local ]; then
echo "configure.local: reading..." 1>&2
echo "configure.local: reading..." 1>&3
cat ./configure.local 1>&3
@ -164,17 +175,26 @@ runtest() {
# --- library functions ---
runtest dirent-namlen DIRENT_NAMLEN || true
runtest fgetln FGETLN || true
runtest err ERR || true
runtest fts FTS || true
runtest getline GETLINE || true
runtest getsubopt GETSUBOPT || true
runtest isblank ISBLANK || true
runtest mkdtemp MKDTEMP || true
runtest mmap MMAP || true
runtest pledge PLEDGE || true
runtest progname PROGNAME || true
runtest reallocarray REALLOCARRAY || true
runtest rewb-bsd REWB_BSD || true
runtest rewb-sysv REWB_SYSV || true
runtest strcasestr STRCASESTR || true
runtest stringlist STRINGLIST || true
runtest strlcat STRLCAT || true
runtest strlcpy STRLCPY || true
runtest strptime STRPTIME || true
runtest strsep STRSEP || true
runtest strtonum STRTONUM || true
runtest vasprintf VASPRINTF || true
runtest wchar WCHAR || true
# --- sqlite3 ---
@ -228,9 +248,9 @@ fi
# --- DBLIB ---
if [ ${BUILD_DB} -eq 0 ]; then
DBLIB=
DBLIB="-lz"
elif [ -z "${DBLIB}" ]; then
DBLIB="${DETECTLIB}"
DBLIB="${DETECTLIB} -lz"
echo "DBLIB=\"${DBLIB}\"" 1>&2
echo "DBLIB=\"${DBLIB}\"" 1>&3
echo 1>&3
@ -256,6 +276,10 @@ fi
exec > config.h
cat << __HEREDOC__
#ifdef __cplusplus
#error "Do not use C++. See the INSTALL file."
#endif
#ifndef MANDOC_CONFIG_H
#define MANDOC_CONFIG_H
@ -265,28 +289,40 @@ cat << __HEREDOC__
__HEREDOC__
[ ${HAVE_FGETLN} -eq 0 -o ${HAVE_REALLOCARRAY} -eq 0 -o \
[ ${HAVE_GETLINE} -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>"
[ ${HAVE_VASPRINTF} -eq 0 ] && echo "#include <stdarg.h>"
[ ${HAVE_GETLINE} -eq 0 ] && echo "#include <stdio.h>"
echo
echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\""
echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\""
[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\""
[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\""
cat << __HEREDOC__
#define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN}
#define HAVE_FGETLN ${HAVE_FGETLN}
#define HAVE_ERR ${HAVE_ERR}
#define HAVE_FTS ${HAVE_FTS}
#define HAVE_GETLINE ${HAVE_GETLINE}
#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT}
#define HAVE_ISBLANK ${HAVE_ISBLANK}
#define HAVE_MKDTEMP ${HAVE_MKDTEMP}
#define HAVE_MMAP ${HAVE_MMAP}
#define HAVE_PLEDGE ${HAVE_PLEDGE}
#define HAVE_PROGNAME ${HAVE_PROGNAME}
#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY}
#define HAVE_REWB_BSD ${HAVE_REWB_BSD}
#define HAVE_REWB_SYSV ${HAVE_REWB_SYSV}
#define HAVE_STRCASESTR ${HAVE_STRCASESTR}
#define HAVE_STRINGLIST ${HAVE_STRINGLIST}
#define HAVE_STRLCAT ${HAVE_STRLCAT}
#define HAVE_STRLCPY ${HAVE_STRLCPY}
#define HAVE_STRPTIME ${HAVE_STRPTIME}
#define HAVE_STRSEP ${HAVE_STRSEP}
#define HAVE_STRTONUM ${HAVE_STRTONUM}
#define HAVE_VASPRINTF ${HAVE_VASPRINTF}
#define HAVE_WCHAR ${HAVE_WCHAR}
#define HAVE_SQLITE3 ${HAVE_SQLITE3}
#define HAVE_SQLITE3_ERRSTR ${HAVE_SQLITE3_ERRSTR}
@ -294,33 +330,37 @@ cat << __HEREDOC__
#define HAVE_MANPATH ${HAVE_MANPATH}
#define BINM_APROPOS "${BINM_APROPOS}"
#define BINM_MAN "${BINM_MAN}"
#define BINM_WHATIS "${BINM_WHATIS}"
#define BINM_MAKEWHATIS "${BINM_MAKEWHATIS}"
#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
#define BINM_MAN "${BINM_MAN}"
#define BINM_SOELIM "${BINM_SOELIM}"
#define BINM_WHATIS "${BINM_WHATIS}"
__HEREDOC__
[ ${HAVE_FGETLN} -eq 0 ] && \
echo "extern char *fgetln(FILE *, size_t *);"
if [ ${HAVE_ERR} -eq 0 ]; then
echo "extern void err(int, const char *, ...);"
echo "extern void errx(int, const char *, ...);"
echo "extern void warn(const char *, ...);"
echo "extern void warnx(const char *, ...);"
fi
[ ${HAVE_GETLINE} -eq 0 ] && \
echo "extern ssize_t getline(char **, size_t *, FILE *);"
[ ${HAVE_GETSUBOPT} -eq 0 ] && \
echo "extern int getsubopt(char **, char * const *, char **);"
[ ${HAVE_ISBLANK} -eq 0 ] && \
echo "extern int isblank(int);"
[ ${HAVE_MKDTEMP} -eq 0 ] && \
echo "extern char *mkdtemp(char *);"
if [ ${HAVE_PROGNAME} -eq 0 ]; then
echo "extern const char *getprogname(void);"
echo "extern void setprogname(const char *);"
fi
[ ${HAVE_REALLOCARRAY} -eq 0 ] && \
echo "extern void *reallocarray(void *, size_t, size_t);"
@ -342,6 +382,9 @@ __HEREDOC__
[ ${HAVE_STRTONUM} -eq 0 ] && \
echo "extern long long strtonum(const char *, long long, long long, const char **);"
[ ${HAVE_VASPRINTF} -eq 0 ] && \
echo "extern int vasprintf(char **, const char *, va_list);"
echo
echo "#endif /* MANDOC_CONFIG_H */"
@ -357,7 +400,6 @@ exec > Makefile.local
[ -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"
@ -382,6 +424,7 @@ INSTALL_TARGETS="base-install"
cat << __HEREDOC__
BUILD_TARGETS = ${BUILD_TARGETS}
INSTALL_TARGETS = ${INSTALL_TARGETS}
CC = ${CC}
CFLAGS = ${CFLAGS}
DBLIB = ${DBLIB}
STATIC = ${STATIC}
@ -391,15 +434,16 @@ SBINDIR = ${SBINDIR}
INCLUDEDIR = ${INCLUDEDIR}
LIBDIR = ${LIBDIR}
MANDIR = ${MANDIR}
EXAMPLEDIR = ${EXAMPLEDIR}
WWWPREFIX = ${WWWPREFIX}
HTDOCDIR = ${HTDOCDIR}
CGIBINDIR = ${CGIBINDIR}
BINM_APROPOS = ${BINM_APROPOS}
BINM_MAN = ${BINM_MAN}
BINM_WHATIS = ${BINM_WHATIS}
BINM_MAKEWHATIS = ${BINM_MAKEWHATIS}
BINM_MAN = ${BINM_MAN}
BINM_SOELIM = ${BINM_SOELIM}
BINM_WHATIS = ${BINM_WHATIS}
MANM_MAN = ${MANM_MAN}
MANM_MANCONF = ${MANM_MANCONF}
MANM_MDOC = ${MANM_MDOC}
MANM_ROFF = ${MANM_ROFF}
MANM_EQN = ${MANM_EQN}

View File

@ -1,4 +1,4 @@
# $Id: configure.local.example,v 1.6 2015/02/16 14:56:22 schwarze Exp $
# $Id: configure.local.example,v 1.10 2015/11/07 13:14:21 schwarze Exp $
#
# Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
#
@ -48,6 +48,13 @@ HAVE_WCHAR=1
HAVE_WCHAR=0
# When man(1) or apropos(1) is called without -m and -M options,
# MANPATH is not set in the environment, man.conf(5) is not available
# and manpath(1) not used, manuals are searched for in the following
# directory trees by default.
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
# 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.
@ -72,7 +79,6 @@ SBINDIR="${PREFIX}/sbin"
INCLUDEDIR="${PREFIX}/include/mandoc"
LIBDIR="${PREFIX}/lib/mandoc"
MANDIR="${PREFIX}/man"
EXAMPLEDIR="${PREFIX}/share/examples/mandoc"
# 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).
@ -89,6 +95,11 @@ HAVE_MANPATH=1
# man(1), makewhatis(8), and apropos(1) will not work properly.
HAVE_MANPATH=0
# Some distributions may want to avoid naming conflicts
# with the configuration files of other man(1) implementations.
# This changes the name of the installed section 5 manual page as well.
MANM_MANCONF="mandoc.conf" # default is "man.conf"
# Some distributions may want to avoid naming conflicts among manuals.
# If you want to change the names of installed section 7 manual pages,
# the following alternative names are suggested.
@ -103,13 +114,14 @@ MANM_EQN="mandoc_eqn" # default is "eqn"
MANM_TBL="mandoc_tbl" # default is "tbl"
# Some distributions may want to avoid naming conflicts
# with another man(1) utility.
# If you want to change the name of the binary program,
# the following alternative name is suggested.
# Using a different name is possible as well.
# This changes the name of the installed section 1 manual page as well.
# with other man(1) and soelim(1) utilities.
# If you want to change the names of binary programs,
# the following alternative names are suggested.
# Using different names is possible as well.
# This changes the names of the installed section 1 manual pages as well.
BINM_MAN=mman # default is "man"
BINM_SOELIM=msoelim # default is "soelim"
# It is possible to change the utility program used for installation
# and the modes files are installed with. The defaults are:

View File

@ -1,4 +1,4 @@
/* $Id: demandoc.c,v 1.15 2015/02/10 08:05:30 schwarze Exp $ */
/* $Id: demandoc.c,v 1.26 2016/01/08 02:53:13 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -26,14 +26,15 @@
#include <string.h>
#include <unistd.h>
#include "roff.h"
#include "man.h"
#include "mdoc.h"
#include "mandoc.h"
static void pline(int, int *, int *, int);
static void pman(const struct man_node *, int *, int *, int);
static void pman(const struct roff_node *, int *, int *, int);
static void pmandoc(struct mparse *, int, const char *, int);
static void pmdoc(const struct mdoc_node *, int *, int *, int);
static void pmdoc(const struct roff_node *, int *, int *, int);
static void pstring(const char *, int, int *, int);
static void usage(void);
@ -43,7 +44,6 @@ int
main(int argc, char *argv[])
{
struct mparse *mp;
struct mchars *mchars;
int ch, fd, i, list;
extern int optind;
@ -72,14 +72,14 @@ main(int argc, char *argv[])
break;
default:
usage();
return((int)MANDOCLEVEL_BADARG);
return (int)MANDOCLEVEL_BADARG;
}
argc -= optind;
argv += optind;
mchars = mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, mchars, NULL);
mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, NULL);
assert(mp);
if (argc < 1)
@ -87,7 +87,7 @@ main(int argc, char *argv[])
for (i = 0; i < argc; i++) {
mparse_reset(mp);
if (mparse_open(mp, &fd, argv[i]) != MANDOCLEVEL_OK) {
if ((fd = mparse_open(mp, argv[i])) == -1) {
perror(argv[i]);
continue;
}
@ -95,8 +95,8 @@ main(int argc, char *argv[])
}
mparse_free(mp);
mchars_free(mchars);
return((int)MANDOCLEVEL_OK);
mchars_free();
return (int)MANDOCLEVEL_OK;
}
static void
@ -109,21 +109,24 @@ usage(void)
static void
pmandoc(struct mparse *mp, int fd, const char *fn, int list)
{
struct mdoc *mdoc;
struct man *man;
struct roff_man *man;
int line, col;
mparse_readfd(mp, fd, fn);
mparse_result(mp, &mdoc, &man, NULL);
close(fd);
mparse_result(mp, &man, NULL);
line = 1;
col = 0;
if (mdoc)
pmdoc(mdoc_node(mdoc), &line, &col, list);
else if (man)
pman(man_node(man), &line, &col, list);
else
if (man == NULL)
return;
if (man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
pmdoc(man->first->child, &line, &col, list);
} else {
man_validate(man);
pman(man->first->child, &line, &col, list);
}
if ( ! list)
putchar('\n');
@ -233,13 +236,13 @@ pline(int line, int *linep, int *col, int list)
}
static void
pmdoc(const struct mdoc_node *p, int *line, int *col, int list)
pmdoc(const struct roff_node *p, int *line, int *col, int list)
{
for ( ; p; p = p->next) {
if (MDOC_LINE & p->flags)
pline(p->line, line, col, list);
if (MDOC_TEXT == p->type)
if (ROFFT_TEXT == p->type)
pstring(p->string, p->pos, col, list);
if (p->child)
pmdoc(p->child, line, col, list);
@ -247,13 +250,13 @@ pmdoc(const struct mdoc_node *p, int *line, int *col, int list)
}
static void
pman(const struct man_node *p, int *line, int *col, int list)
pman(const struct roff_node *p, int *line, int *col, int list)
{
for ( ; p; p = p->next) {
if (MAN_LINE & p->flags)
pline(p->line, line, col, list);
if (MAN_TEXT == p->type)
if (ROFFT_TEXT == p->type)
pstring(p->string, p->pos, col, list);
if (p->child)
pman(p->child, line, col, list);

10
eqn.7
View File

@ -1,4 +1,4 @@
.\" $Id: eqn.7,v 1.34 2015/03/09 20:17:23 schwarze Exp $
.\" $Id: eqn.7,v 1.35 2015/03/30 16:06:14 schwarze Exp $
.\"
.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 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: March 9 2015 $
.Dd $Mdocdate: March 30 2015 $
.Dt EQN 7
.Os
.Sh NAME
@ -146,7 +146,7 @@ is used as the delimiter for the value
.Ar val .
This allows for arbitrary enclosure of terms (not just quotes), such as
.Pp
.D1 Cm define Ar foo 'bar baz'
.D1 Cm define Ar foo \(aqbar baz\(aq
.D1 Cm define Ar foo cbar bazc
.Pp
It is an error to have an empty
@ -166,8 +166,8 @@ created.
Definitions can create arbitrary strings, for example, the following is
a legal construction.
.Bd -literal -offset indent
define foo 'define'
foo bar 'baz'
define foo \(aqdefine\(aq
foo bar \(aqbaz\(aq
.Ed
.Pp
Self-referencing definitions will raise an error.

45
eqn.c
View File

@ -1,4 +1,4 @@
/* $Id: eqn.c,v 1.58 2015/03/04 12:19:49 schwarze Exp $ */
/* $Id: eqn.c,v 1.61 2016/01/08 00:50:45 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -302,10 +302,10 @@ eqn_read(struct eqn_node **epp, int ln,
while (' ' == *p || '\t' == *p)
p++;
if ('\0' == *p)
return(er);
return er;
mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
ln, pos, "EN %s", p);
return(er);
return er;
}
/*
@ -324,7 +324,7 @@ eqn_read(struct eqn_node **epp, int ln,
ep->sz += sz;
strlcat(ep->data, p + pos, ep->sz + 1);
strlcat(ep->data, " ", ep->sz + 1);
return(ROFF_IGN);
return ROFF_IGN;
}
struct eqn_node *
@ -339,7 +339,7 @@ eqn_alloc(int pos, int line, struct mparse *parse)
p->eqn.pos = pos;
p->gsize = EQN_DEFSIZE;
return(p);
return p;
}
/*
@ -353,9 +353,9 @@ eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
for (i = 0; i < (int)ep->defsz; i++)
if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
ep->defs[i].keysz, key, sz))
return(&ep->defs[i]);
return &ep->defs[i];
return(NULL);
return NULL;
}
/*
@ -382,7 +382,7 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
if (lim >= EQN_NEST_MAX) {
mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
ep->eqn.ln, ep->eqn.pos, NULL);
return(NULL);
return NULL;
}
ep->cur = ep->rew;
@ -390,7 +390,7 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
q = 0;
if ('\0' == *start)
return(NULL);
return NULL;
if (quote == *start) {
ep->cur++;
@ -432,7 +432,7 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
/* Quotes aren't expanded for values. */
if (q || ! repl)
return(start);
return start;
if (NULL != (def = eqn_def_find(ep, start, *sz))) {
diff = def->valsz - *sz;
@ -448,10 +448,11 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
memmove(start + *sz + diff, start + *sz,
(strlen(start) - *sz) + 1);
memcpy(start, def->val, def->valsz);
lim++;
goto again;
}
return(start);
return start;
}
/*
@ -462,7 +463,7 @@ static const char *
eqn_nexttok(struct eqn_node *ep, size_t *sz)
{
return(eqn_next(ep, '"', sz, 1));
return eqn_next(ep, '"', sz, 1);
}
/*
@ -472,7 +473,7 @@ static const char *
eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
{
return(eqn_next(ep, '"', sz, 0));
return eqn_next(ep, '"', sz, 0);
}
/*
@ -498,12 +499,12 @@ eqn_tok_parse(struct eqn_node *ep, char **p)
quoted = ep->data[ep->cur] == '"';
if (NULL == (start = eqn_nexttok(ep, &sz)))
return(EQN_TOK_EOF);
return EQN_TOK_EOF;
if (quoted) {
if (p != NULL)
*p = mandoc_strndup(start, sz);
return(EQN_TOK__MAX);
return EQN_TOK__MAX;
}
for (i = 0; i < EQN_TOK__MAX; i++) {
@ -516,7 +517,7 @@ eqn_tok_parse(struct eqn_node *ep, char **p)
if (i == EQN_TOK__MAX && NULL != p)
*p = mandoc_strndup(start, sz);
return(i);
return i;
}
static void
@ -557,7 +558,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
parent->first = bp;
parent->last = bp;
return(bp);
return bp;
}
/*
@ -587,7 +588,7 @@ eqn_box_makebinary(struct eqn_node *ep,
newb->first = newb->last = b;
newb->first->next = NULL;
b->parent = newb;
return(newb);
return newb;
}
/*
@ -712,7 +713,7 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
*/
if (ep->data == NULL)
return(ROFF_IGN);
return ROFF_IGN;
next_tok:
tok = eqn_tok_parse(ep, &p);
@ -986,7 +987,7 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
parent->right = mandoc_strndup(start, sz);
}
parent = parent->parent;
if (EQN_TOK_BRACE_CLOSE == tok && parent &&
if (tok == EQN_TOK_BRACE_CLOSE &&
(parent->type == EQN_PILE ||
parent->type == EQN_MATRIX))
parent = parent->parent;
@ -1060,7 +1061,7 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
* End of file!
* TODO: make sure we're not in an open subexpression.
*/
return(ROFF_EQN);
return ROFF_EQN;
default:
assert(tok == EQN_TOK__MAX);
assert(NULL != p);
@ -1104,7 +1105,7 @@ eqn_end(struct eqn_node **epp)
ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
ep->eqn.root->expectargs = UINT_MAX;
return(eqn_parse(ep, ep->eqn.root));
return eqn_parse(ep, ep->eqn.root);
}
void

View File

@ -1,114 +0,0 @@
/* $Id: example.style.css,v 1.55 2015/02/10 08:05:30 schwarze Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
* or -Txhtml output mode.
* It mimics the appearance of the legacy man.cgi output.
* See mdoc(7) and man(7) for macro explanations.
*/
div.mandoc { min-width: 102ex;
width: 102ex;
font-family: monospace; } /* This is the outer node of all mandoc -T[x]html documents. */
div.mandoc h1 { margin-bottom: 0ex; font-size: inherit; margin-left: -4ex; } /* Section header (Sh, SH). */
div.mandoc h2 { margin-bottom: 0ex; font-size: inherit; margin-left: -2ex; } /* Sub-section header (Ss, SS). */
div.mandoc table { width: 100%; margin-top: 0ex; margin-bottom: 0ex; } /* All tables. */
div.mandoc td { vertical-align: top; } /* All table cells. */
div.mandoc p { } /* Paragraph: Pp, Lp. */
div.mandoc blockquote { margin-left: 5ex; margin-top: 0ex; margin-bottom: 0ex; } /* D1, Dl. */
div.mandoc div.section { margin-bottom: 2ex; margin-left: 5ex; } /* Sections (Sh, SH). */
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 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 .display { } /* All Bd, D1, Dl. */
div.mandoc .list { } /* All Bl. */
div.mandoc i { } /* Italic: BI, IB, I, (implicit). */
div.mandoc b { } /* Bold: SB, BI, IB, BR, RB, B, (implicit). */
div.mandoc small { } /* Small: SB, SM. */
div.mandoc .emph { font-style: italic; font-weight: normal; } /* Emphasis: Em, Bl -emphasis. */
div.mandoc .symb { font-style: normal; font-weight: bold; } /* Symbolic: Sy, Ms, Bf -symbolic. */
div.mandoc .lit { font-style: normal; font-weight: normal; font-family: monospace; } /* Literal: Dl, Li, Ql, Bf -literal, Bl -literal, Bl -unfilled. */
div.mandoc i.addr { font-weight: normal; } /* Address (Ad). */
div.mandoc i.arg { font-weight: normal; } /* Command argument (Ar). */
div.mandoc span.author { } /* Author name (An). */
div.mandoc b.cmd { font-style: normal; } /* Command (Cm). */
div.mandoc b.config { font-style: normal; } /* Config statement (Cd). */
div.mandoc span.define { } /* Defines (Dv). */
div.mandoc span.desc { } /* Nd. After em-dash. */
div.mandoc b.diag { font-style: normal; } /* Diagnostic (Bl -diag). */
div.mandoc span.env { } /* Environment variables (Ev). */
div.mandoc span.errno { } /* Error string (Er). */
div.mandoc i.farg { font-weight: normal; } /* Function argument (Fa, Fn). */
div.mandoc i.file { font-weight: normal; } /* File (Pa). */
div.mandoc b.flag { font-style: normal; } /* Flag (Fl, Cm). */
div.mandoc b.fname { font-style: normal; } /* Function name (Fa, Fn, Rv). */
div.mandoc i.ftype { font-weight: normal; } /* Function types (Ft, Fn). */
div.mandoc b.includes { font-style: normal; } /* Header includes (In). */
div.mandoc span.lib { } /* Library (Lb). */
div.mandoc i.link-sec { font-weight: normal; } /* Section links (Sx). */
div.mandoc b.macro { font-style: normal; } /* Macro-ish thing (Fd). */
div.mandoc b.name { font-style: normal; } /* Name of utility (Nm). */
div.mandoc span.opt { } /* Options (Op, Oo/Oc). */
div.mandoc span.ref { } /* Citations (Rs). */
div.mandoc span.ref-auth { } /* Reference author (%A). */
div.mandoc i.ref-book { font-weight: normal; } /* Reference book (%B). */
div.mandoc span.ref-city { } /* Reference city (%C). */
div.mandoc span.ref-date { } /* Reference date (%D). */
div.mandoc i.ref-issue { font-weight: normal; } /* Reference issuer/publisher (%I). */
div.mandoc i.ref-jrnl { font-weight: normal; } /* Reference journal (%J). */
div.mandoc span.ref-num { } /* Reference number (%N). */
div.mandoc span.ref-opt { } /* Reference optionals (%O). */
div.mandoc span.ref-page { } /* Reference page (%P). */
div.mandoc span.ref-corp { } /* Reference corporate/foreign author (%Q). */
div.mandoc span.ref-rep { } /* Reference report (%R). */
div.mandoc span.ref-title { text-decoration: underline; } /* Reference title (%T). */
div.mandoc span.ref-vol { } /* Reference volume (%V). */
div.mandoc span.type { font-style: italic; font-weight: normal; } /* Variable types (Vt). */
div.mandoc span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */
div.mandoc b.utility { font-style: normal; } /* Name of utility (Ex). */
div.mandoc b.var { font-style: normal; } /* Variables (Rv). */
div.mandoc a.link-ext { } /* Off-site link (Lk). */
div.mandoc a.link-includes { } /* Include-file link (In). */
div.mandoc a.link-mail { } /* Mailto links (Mt). */
div.mandoc a.link-man { } /* Manual links (Xr). */
div.mandoc a.link-ref { } /* Reference section links (%Q). */
div.mandoc a.link-sec { } /* Section links (Sx). */
div.mandoc dl.list-diag { } /* Formatting for lists. See mdoc(7). */
div.mandoc dt.list-diag { }
div.mandoc dd.list-diag { }
div.mandoc dl.list-hang { }
div.mandoc dt.list-hang { }
div.mandoc dd.list-hang { }
div.mandoc dl.list-inset { }
div.mandoc dt.list-inset { }
div.mandoc dd.list-inset { }
div.mandoc dl.list-ohang { }
div.mandoc dt.list-ohang { }
div.mandoc dd.list-ohang { margin-left: 0ex; }
div.mandoc dl.list-tag { }
div.mandoc dt.list-tag { }
div.mandoc dd.list-tag { }
div.mandoc table.list-col { }
div.mandoc tr.list-col { }
div.mandoc td.list-col { }
div.mandoc ul.list-bul { list-style-type: disc; padding-left: 1em; }
div.mandoc li.list-bul { }
div.mandoc ul.list-dash { list-style-type: none; padding-left: 0em; }
div.mandoc li.list-dash:before { content: "\2014 "; }
div.mandoc ul.list-hyph { list-style-type: none; padding-left: 0em; }
div.mandoc li.list-hyph:before { content: "\2013 "; }
div.mandoc ul.list-item { list-style-type: none; padding-left: 0em; }
div.mandoc li.list-item { }
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; }

3
gmdiff
View File

@ -40,7 +40,8 @@ while [ -n "$1" ]; do
shift
echo " ========== $file ========== "
tbl $file | $EQN | $ROFF -mandoc 2> /tmp/roff.err > /tmp/roff.out
mandoc -Ios='OpenBSD ports' $MOPT $file 2> /tmp/mandoc.err > /tmp/mandoc.out
${MANDOC:=mandoc} -Ios='OpenBSD ports' $MOPT $file \
2> /tmp/mandoc.err > /tmp/mandoc.out
for i in roff mandoc; do
[[ -s /tmp/$i.err ]] && echo "$i errors:" && cat /tmp/$i.err
done

77
html.c
View File

@ -1,4 +1,4 @@
/* $Id: html.c,v 1.185 2015/01/21 20:33:25 schwarze Exp $ */
/* $Id: html.c,v 1.192 2016/01/04 12:45:29 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,9 +7,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -32,6 +32,7 @@
#include "mandoc_aux.h"
#include "out.h"
#include "html.h"
#include "manconf.h"
#include "main.h"
struct htmldata {
@ -129,42 +130,20 @@ static void print_attr(struct html *, const char *, const char *);
void *
html_alloc(const struct mchars *mchars, char *outopts)
html_alloc(const struct manoutput *outopts)
{
struct html *h;
const char *toks[5];
char *v;
toks[0] = "style";
toks[1] = "man";
toks[2] = "includes";
toks[3] = "fragment";
toks[4] = NULL;
h = mandoc_calloc(1, sizeof(struct html));
h->tags.head = NULL;
h->symtab = mchars;
h->style = outopts->style;
h->base_man = outopts->man;
h->base_includes = outopts->includes;
if (outopts->fragment)
h->oflags |= HTML_FRAGMENT;
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
case 0:
h->style = v;
break;
case 1:
h->base_man = v;
break;
case 2:
h->base_includes = v;
break;
case 3:
h->oflags |= HTML_FRAGMENT;
break;
default:
break;
}
return(h);
return h;
}
void
@ -237,13 +216,11 @@ print_metaf(struct html *h, enum mandoc_esc deco)
font = HTMLFONT_BI;
break;
case ESCAPE_FONT:
/* FALLTHROUGH */
case ESCAPE_FONTROMAN:
font = HTMLFONT_NONE;
break;
default:
abort();
/* NOTREACHED */
}
if (h->metaf) {
@ -301,13 +278,10 @@ html_strlen(const char *cp)
cp++;
switch (mandoc_escape(&cp, NULL, NULL)) {
case ESCAPE_ERROR:
return(sz);
return sz;
case ESCAPE_UNICODE:
/* FALLTHROUGH */
case ESCAPE_NUMBERED:
/* FALLTHROUGH */
case ESCAPE_SPECIAL:
/* FALLTHROUGH */
case ESCAPE_OVERSTRIKE:
if (skip)
skip = 0;
@ -321,7 +295,7 @@ html_strlen(const char *cp)
break;
}
}
return(sz);
return sz;
}
static int
@ -342,17 +316,17 @@ print_escape(char c)
printf("&quot;");
break;
case ASCII_NBRSP:
putchar('-');
printf("&nbsp;");
break;
case ASCII_HYPH:
putchar('-');
/* FALLTHROUGH */
break;
case ASCII_BREAK:
break;
default:
return(0);
return 0;
}
return(1);
return 1;
}
static int
@ -391,15 +365,10 @@ print_encode(struct html *h, const char *p, int norecurse)
switch (esc) {
case ESCAPE_FONT:
/* FALLTHROUGH */
case ESCAPE_FONTPREV:
/* FALLTHROUGH */
case ESCAPE_FONTBOLD:
/* FALLTHROUGH */
case ESCAPE_FONTITALIC:
/* FALLTHROUGH */
case ESCAPE_FONTBI:
/* FALLTHROUGH */
case ESCAPE_FONTROMAN:
if (0 == norecurse)
print_metaf(h, esc);
@ -427,7 +396,7 @@ print_encode(struct html *h, const char *p, int norecurse)
continue;
break;
case ESCAPE_SPECIAL:
c = mchars_spec2cp(h->symtab, seq, len);
c = mchars_spec2cp(seq, len);
if (c <= 0)
continue;
break;
@ -452,7 +421,7 @@ print_encode(struct html *h, const char *p, int norecurse)
putchar(c);
}
return(nospace);
return nospace;
}
static void
@ -514,7 +483,7 @@ print_otag(struct html *h, enum htmltag tag,
if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags)
putchar('\n');
return(t);
return t;
}
static void
@ -751,8 +720,8 @@ void
bufcat_id(struct html *h, const char *src)
{
/* Cf. <http://www.w3.org/TR/html4/types.html#h-6.2>. */
/* Cf. <http://www.w3.org/TR/html5/dom.html#the-id-attribute>. */
while ('\0' != *src)
bufcat_fmt(h, "%.2x", *src++);
for (; '\0' != *src; src++)
bufncat(h, *src == ' ' ? "_" : src, 1);
}

6
html.h
View File

@ -1,4 +1,4 @@
/* $Id: html.h,v 1.70 2014/12/02 10:08:06 schwarze Exp $ */
/* $Id: html.h,v 1.72 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -130,7 +130,6 @@ struct html {
struct tagq tags; /* stack of open tags */
struct rofftbl tbl; /* current table */
struct tag *tblt; /* current open table scope */
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 */
@ -143,7 +142,6 @@ struct html {
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
};
__BEGIN_DECLS
struct tbl_span;
struct eqn;
@ -176,5 +174,3 @@ void buffmt_man(struct html *,
void buffmt_includes(struct html *, const char *);
int html_strlen(const char *);
__END_DECLS

5
lib.c
View File

@ -1,4 +1,4 @@
/* $Id: lib.c,v 1.11 2014/08/10 23:54:41 schwarze Exp $ */
/* $Id: lib.c,v 1.13 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -20,6 +20,7 @@
#include <string.h>
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
@ -32,5 +33,5 @@ mdoc_a2lib(const char *p)
#include "lib.in"
return(NULL);
return NULL;
}

View File

@ -1,44 +1,23 @@
/* $Id: libman.h,v 1.67 2014/12/28 14:42:27 schwarze Exp $ */
/* $Id: libman.h,v 1.79 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum man_next {
MAN_NEXT_SIBLING = 0,
MAN_NEXT_CHILD
};
struct man {
struct mparse *parse; /* parse pointer */
const char *defos; /* default OS argument for .TH */
int quick; /* abort parse early */
int flags; /* parse flags */
#define MAN_ELINE (1 << 1) /* Next-line element scope. */
#define MAN_BLINE (1 << 2) /* Next-line block scope. */
#define MAN_LITERAL (1 << 4) /* Literal input. */
#define MAN_NEWLINE (1 << 6) /* first macro/text in a line */
enum man_next next; /* where to put the next node */
struct man_node *last; /* the last parsed node */
struct man_node *first; /* the first parsed node */
struct man_meta meta; /* document meta-data */
struct roff *roff;
};
#define MACRO_PROT_ARGS struct man *man, \
enum mant tok, \
#define MACRO_PROT_ARGS struct roff_man *man, \
int tok, \
int line, \
int ppos, \
int *pos, \
@ -47,30 +26,16 @@ struct man {
struct man_macro {
void (*fp)(MACRO_PROT_ARGS);
int flags;
#define MAN_SCOPED (1 << 0)
#define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */
#define MAN_FSCOPED (1 << 2) /* See blk_imp(). */
#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. */
#define MAN_SCOPED (1 << 0) /* Optional next-line scope. */
#define MAN_NSCOPED (1 << 1) /* Allowed in next-line element scope. */
#define MAN_BSCOPE (1 << 2) /* Break next-line block scope. */
#define MAN_JOIN (1 << 3) /* Join arguments together. */
};
extern const struct man_macro *const man_macros;
__BEGIN_DECLS
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 *);
void man_macroend(struct man *);
void man_valid_post(struct man *);
void man_unscope(struct man *, const struct man_node *);
__END_DECLS
int man_hash_find(const char *);
void man_node_validate(struct roff_man *);
void man_state(struct roff_man *, struct roff_node *);
void man_unscope(struct roff_man *, const struct roff_node *);

View File

@ -1,15 +1,15 @@
/* $Id: libmandoc.h,v 1.55 2015/01/15 04:26:39 schwarze Exp $ */
/* $Id: libmandoc.h,v 1.62 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013, 2014, 2015 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -32,15 +32,13 @@ struct buf {
size_t sz;
};
__BEGIN_DECLS
struct mparse;
struct mchars;
struct tbl_span;
struct eqn;
struct roff;
struct mdoc;
struct man;
struct roff_man;
struct roff_node;
void mandoc_msg(enum mandocerr, struct mparse *,
int, int, const char *);
@ -55,31 +53,25 @@ int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*);
void mdoc_free(struct mdoc *);
struct mdoc *mdoc_alloc(struct roff *, struct mparse *,
const char *, int);
void mdoc_reset(struct mdoc *);
int mdoc_parseln(struct mdoc *, int, char *, int);
void mdoc_endparse(struct mdoc *);
void mdoc_addspan(struct mdoc *, const struct tbl_span *);
void mdoc_addeqn(struct mdoc *, const struct eqn *);
void mdoc_hash_init(void);
int mdoc_parseln(struct roff_man *, int, char *, int);
void mdoc_endparse(struct roff_man *);
void man_free(struct man *);
struct man *man_alloc(struct roff *, struct mparse *,
const char *, int);
void man_reset(struct man *);
int man_parseln(struct man *, int, char *, int);
void man_endparse(struct man *);
void man_addspan(struct man *, const struct tbl_span *);
void man_addeqn(struct man *, const struct eqn *);
void man_hash_init(void);
int man_parseln(struct roff_man *, int, char *, int);
void man_endparse(struct roff_man *);
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 *, const struct mchars *, int);
struct roff *roff_alloc(struct mparse *, int);
void roff_reset(struct roff *);
void roff_man_free(struct roff_man *);
struct roff_man *roff_man_alloc(struct roff *, struct mparse *,
const char *, int);
void roff_man_reset(struct roff_man *);
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);
@ -91,5 +83,3 @@ int roff_getformat(const struct roff *);
const struct tbl_span *roff_span(const struct roff *);
const struct eqn *roff_eqn(const struct roff *);
__END_DECLS

View File

@ -1,53 +1,23 @@
/* $Id: libmdoc.h,v 1.97 2015/02/02 04:26:44 schwarze Exp $ */
/* $Id: libmdoc.h,v 1.108 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013, 2014, 2015 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum mdoc_next {
MDOC_NEXT_SIBLING = 0,
MDOC_NEXT_CHILD
};
struct mdoc {
struct mparse *parse; /* parse pointer */
const char *defos; /* default argument for .Os */
int quick; /* abort parse early */
int flags; /* parse flags */
#define MDOC_LITERAL (1 << 1) /* in a literal scope */
#define MDOC_PBODY (1 << 2) /* in the document body */
#define MDOC_NEWLINE (1 << 3) /* first macro/text in a line */
#define MDOC_PHRASELIT (1 << 4) /* literal within a partila phrase */
#define MDOC_PPHRASE (1 << 5) /* within a partial phrase */
#define MDOC_FREECOL (1 << 6) /* `It' invocation should close */
#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 */
struct mdoc_node *last_es; /* the most recent Es node */
struct mdoc_meta meta; /* document meta-data */
enum mdoc_sec lastnamed;
enum mdoc_sec lastsec;
struct roff *roff;
};
#define MACRO_PROT_ARGS struct mdoc *mdoc, \
enum mdoct tok, \
#define MACRO_PROT_ARGS struct roff_man *mdoc, \
int tok, \
int line, \
int ppos, \
int *pos, \
@ -70,9 +40,7 @@ enum margserr {
ARGS_WORD, /* normal word */
ARGS_PUNCT, /* series of punctuation */
ARGS_QWORD, /* quoted word */
ARGS_PHRASE, /* Ta'd phrase (-column) */
ARGS_PPHRASE, /* tabbed phrase (-column) */
ARGS_PEND /* last phrase (-column) */
ARGS_PHRASE /* Bl -column phrase */
};
/*
@ -94,36 +62,27 @@ enum mdelim {
extern const struct mdoc_macro *const mdoc_macros;
__BEGIN_DECLS
void mdoc_macro(MACRO_PROT_ARGS);
void mdoc_word_alloc(struct mdoc *, int, int, const char *);
void mdoc_word_append(struct mdoc *, const char *);
void mdoc_elem_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
struct mdoc_node *mdoc_block_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
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);
struct mdoc_node *mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
struct mdoc_node *, enum mdoc_endbody);
void mdoc_node_delete(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 *);
void mdoc_elem_alloc(struct roff_man *, int, int,
int, struct mdoc_arg *);
struct roff_node *mdoc_block_alloc(struct roff_man *, int, int,
int, struct mdoc_arg *);
void mdoc_tail_alloc(struct roff_man *, int, int, int);
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, int,
struct roff_node *, enum mdoc_endbody);
void mdoc_node_relink(struct roff_man *, struct roff_node *);
void mdoc_node_validate(struct roff_man *);
void mdoc_state(struct roff_man *, struct roff_node *);
void mdoc_state_reset(struct roff_man *);
int mdoc_hash_find(const char *);
const char *mdoc_a2arch(const char *);
const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *);
enum roff_sec mdoc_a2sec(const char *);
const char *mdoc_a2st(const char *);
const char *mdoc_a2arch(const char *);
void mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
void mdoc_valid_post(struct mdoc *);
void mdoc_argv(struct mdoc *, int, enum mdoct,
void mdoc_argv(struct roff_man *, int, int,
struct mdoc_arg **, int *, char *);
void mdoc_argv_free(struct mdoc_arg *);
enum margserr mdoc_args(struct mdoc *, int,
int *, char *, enum mdoct, char **);
void mdoc_macroend(struct mdoc *);
enum margserr mdoc_args(struct roff_man *, int,
int *, char *, int, char **);
enum mdelim mdoc_isdelim(const char *);
__END_DECLS

View File

@ -1,4 +1,4 @@
/* $Id: libroff.h,v 1.38 2015/01/30 04:11:50 schwarze Exp $ */
/* $Id: libroff.h,v 1.39 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -60,7 +60,6 @@ struct eqn_def {
size_t valsz;
};
__BEGIN_DECLS
struct tbl_node *tbl_alloc(int, int, struct mparse *);
void tbl_restart(int, int, struct tbl_node *);
@ -78,5 +77,3 @@ enum rofferr eqn_end(struct eqn_node **);
void eqn_free(struct eqn_node *);
enum rofferr eqn_read(struct eqn_node **, int,
const char *, int, int *);
__END_DECLS

600
main.c
View File

@ -1,16 +1,16 @@
/* $Id: main.c,v 1.225 2015/03/10 13:50:03 schwarze Exp $ */
/* $Id: main.c,v 1.262 2016/01/08 02:53:13 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -24,21 +24,27 @@
#include <assert.h>
#include <ctype.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "main.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "manpath.h"
#include "tag.h"
#include "main.h"
#include "manconf.h"
#include "mansearch.h"
#if !defined(__GNUC__) || (__GNUC__ < 2)
@ -56,10 +62,6 @@ enum outmode {
OUTMODE_ONE
};
typedef void (*out_mdoc)(void *, const struct mdoc *);
typedef void (*out_man)(void *, const struct man *);
typedef void (*out_free)(void *);
enum outt {
OUTT_ASCII = 0, /* -Tascii */
OUTT_LOCALE, /* -Tlocale */
@ -74,15 +76,11 @@ 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 */
out_mdoc outmdoc; /* mdoc output ptr */
out_man outman; /* man output ptr */
out_free outfree; /* free output ptr */
void *outdata; /* data for output */
char outopts[BUFSIZ]; /* buf of output opts */
struct manoutput *outopts; /* output options */
};
static int fs_lookup(const struct manpaths *,
@ -99,10 +97,9 @@ int mandocdb(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 pid_t spawn_pager(void);
static void parse(struct curparse *, int, const char *);
static void passthrough(const char *, int, int);
static pid_t spawn_pager(struct tag_files *);
static int toptions(struct curparse *, char *);
static void usage(enum argmode) __attribute__((noreturn));
static int woptions(struct curparse *, char *);
@ -110,46 +107,60 @@ static int woptions(struct curparse *, char *);
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static char help_arg[] = "help";
static char *help_argv[] = {help_arg, NULL};
static const char *progname;
static enum mandoclevel rc;
int
main(int argc, char *argv[])
{
struct manconf conf;
struct curparse curp;
struct mansearch search;
struct manpaths paths;
struct tag_files *tag_files;
const char *progname;
char *auxpaths;
char *defos;
unsigned char *uc;
struct manpage *res, *resp;
char *conf_file, *defpaths;
size_t isec, i, sz;
int prio, best_prio, synopsis_only;
int prio, best_prio;
char sec;
enum mandoclevel rc, rctmp;
enum outmode outmode;
int fd;
int show_usage;
int options;
int use_pager;
int status, signum;
int c;
pid_t pager_pid; /* 0: don't use; 1: not yet spawned. */
pid_t pager_pid, tc_pgid, man_pgid, pid;
#if HAVE_PROGNAME
progname = getprogname();
#else
if (argc < 1)
progname = "mandoc";
progname = mandoc_strdup("mandoc");
else if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
++progname;
setprogname(progname);
#endif
#if HAVE_SQLITE3
if (strcmp(progname, BINM_MAKEWHATIS) == 0)
return(mandocdb(argc, argv));
if (strncmp(progname, "mandocdb", 8) == 0 ||
strcmp(progname, BINM_MAKEWHATIS) == 0)
return mandocdb(argc, argv);
#endif
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc exec flock", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
/* Search options. */
memset(&paths, 0, sizeof(struct manpaths));
memset(&conf, 0, sizeof(conf));
conf_file = defpaths = NULL;
auxpaths = NULL;
@ -172,12 +183,13 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
curp.wlevel = MANDOCLEVEL_BADARG;
curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
defos = NULL;
pager_pid = 1;
use_pager = 1;
tag_files = NULL;
show_usage = 0;
synopsis_only = 0;
outmode = OUTMODE_DEF;
while (-1 != (c = getopt(argc, argv,
@ -190,29 +202,24 @@ main(int argc, char *argv[])
conf_file = optarg;
break;
case 'c':
pager_pid = 0;
use_pager = 0;
break;
case 'f':
search.argmode = ARG_WORD;
break;
case 'h':
(void)strlcat(curp.outopts, "synopsis,", BUFSIZ);
synopsis_only = 1;
pager_pid = 0;
conf.output.synopsisonly = 1;
use_pager = 0;
outmode = OUTMODE_ALL;
break;
case 'I':
if (strncmp(optarg, "os=", 3)) {
fprintf(stderr,
"%s: -I %s: Bad argument\n",
progname, optarg);
return((int)MANDOCLEVEL_BADARG);
warnx("-I %s: Bad argument", optarg);
return (int)MANDOCLEVEL_BADARG;
}
if (defos) {
fprintf(stderr,
"%s: -I %s: Duplicate argument\n",
progname, optarg);
return((int)MANDOCLEVEL_BADARG);
warnx("-I %s: Duplicate argument", optarg);
return (int)MANDOCLEVEL_BADARG;
}
defos = mandoc_strdup(optarg + 3);
break;
@ -221,7 +228,7 @@ main(int argc, char *argv[])
break;
case 'K':
if ( ! koptions(&options, optarg))
return((int)MANDOCLEVEL_BADARG);
return (int)MANDOCLEVEL_BADARG;
break;
case 'k':
search.argmode = ARG_EXPR;
@ -238,8 +245,9 @@ main(int argc, char *argv[])
break;
case 'O':
search.outkey = optarg;
(void)strlcat(curp.outopts, optarg, BUFSIZ);
(void)strlcat(curp.outopts, ",", BUFSIZ);
while (optarg != NULL)
manconf_output(&conf.output,
strsep(&optarg, ","));
break;
case 'S':
search.arch = optarg;
@ -249,11 +257,11 @@ main(int argc, char *argv[])
break;
case 'T':
if ( ! toptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
return (int)MANDOCLEVEL_BADARG;
break;
case 'W':
if ( ! woptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
return (int)MANDOCLEVEL_BADARG;
break;
case 'w':
outmode = OUTMODE_FLN;
@ -273,7 +281,7 @@ main(int argc, char *argv[])
switch (search.argmode) {
case ARG_FILE:
outmode = OUTMODE_ALL;
pager_pid = 0;
use_pager = 0;
break;
case ARG_NAME:
outmode = OUTMODE_ONE;
@ -284,6 +292,17 @@ main(int argc, char *argv[])
}
}
if (outmode == OUTMODE_FLN ||
outmode == OUTMODE_LST ||
!isatty(STDOUT_FILENO))
use_pager = 0;
#if HAVE_PLEDGE
if (!use_pager)
if (pledge("stdio rpath flock", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
/* Parse arguments. */
if (argc > 0) {
@ -334,22 +353,28 @@ main(int argc, char *argv[])
/* Access the mandoc database. */
manpath_parse(&paths, conf_file, defpaths, auxpaths);
manconf_parse(&conf, conf_file, defpaths, auxpaths);
#if HAVE_SQLITE3
mansearch_setup(1);
if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
if ( ! mansearch(&search, &conf.manpath,
argc, argv, &res, &sz))
usage(search.argmode);
#else
if (search.argmode != ARG_NAME) {
fputs("mandoc: database support not compiled in\n",
stderr);
return((int)MANDOCLEVEL_BADARG);
return (int)MANDOCLEVEL_BADARG;
}
sz = 0;
#endif
if (sz == 0 && search.argmode == ARG_NAME)
fs_search(&search, &paths, argc, argv, &res, &sz);
if (sz == 0) {
if (search.argmode == ARG_NAME)
fs_search(&search, &conf.manpath,
argc, argv, &res, &sz);
else
warnx("nothing appropriate");
}
if (sz == 0) {
rc = MANDOCLEVEL_BADARG;
@ -404,12 +429,21 @@ main(int argc, char *argv[])
/* mandoc(1) */
if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
return((int)MANDOCLEVEL_BADARG);
#if HAVE_PLEDGE
if (use_pager) {
if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
} else {
if (pledge("stdio rpath", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
}
#endif
curp.mchars = mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg,
curp.mchars, defos);
if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
return (int)MANDOCLEVEL_BADARG;
mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
/*
* Conditionally start up the lookaside buffer before parsing.
@ -418,41 +452,33 @@ main(int argc, char *argv[])
mparse_keep(curp.mp);
if (argc < 1) {
if (pager_pid == 1 && isatty(STDOUT_FILENO))
pager_pid = spawn_pager();
parse(&curp, STDIN_FILENO, "<stdin>", &rc);
if (use_pager)
tag_files = tag_init();
parse(&curp, STDIN_FILENO, "<stdin>");
}
while (argc > 0) {
rctmp = mparse_open(curp.mp, &fd,
resp != NULL ? resp->file : *argv);
if (rc < rctmp)
rc = rctmp;
fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
if (fd != -1) {
if (pager_pid == 1 && isatty(STDOUT_FILENO))
pager_pid = spawn_pager();
if (resp == NULL)
parse(&curp, fd, *argv, &rc);
else if (resp->form & FORM_SRC) {
/* For .so only; ignore failure. */
chdir(paths.paths[resp->ipath]);
parse(&curp, fd, resp->file, &rc);
} else {
rctmp = passthrough(resp->file, fd,
synopsis_only);
if (rc < rctmp)
rc = rctmp;
if (use_pager) {
tag_files = tag_init();
use_pager = 0;
}
rctmp = mparse_wait(curp.mp);
if (rc < rctmp)
rc = rctmp;
if (resp == NULL)
parse(&curp, fd, *argv);
else if (resp->form & FORM_SRC) {
/* For .so only; ignore failure. */
chdir(conf.manpath.paths[resp->ipath]);
parse(&curp, fd, resp->file);
} else
passthrough(resp->file, fd,
conf.output.synopsisonly);
if (argc > 1 && curp.outtype <= OUTT_UTF8)
ascii_sepline(curp.outdata);
}
} else if (rc < MANDOCLEVEL_ERROR)
rc = MANDOCLEVEL_ERROR;
if (MANDOCLEVEL_OK != rc && curp.wstop)
break;
@ -465,14 +491,30 @@ main(int argc, char *argv[])
mparse_reset(curp.mp);
}
if (curp.outfree)
(*curp.outfree)(curp.outdata);
if (curp.outdata != NULL) {
switch (curp.outtype) {
case OUTT_HTML:
html_free(curp.outdata);
break;
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_ASCII:
ascii_free(curp.outdata);
break;
case OUTT_PDF:
case OUTT_PS:
pspdf_free(curp.outdata);
break;
default:
break;
}
}
mparse_free(curp.mp);
mchars_free(curp.mchars);
mchars_free();
out:
if (search.argmode != ARG_FILE) {
manpath_free(&paths);
manconf_free(&conf);
#if HAVE_SQLITE3
mansearch_free(res, sz);
mansearch_setup(0);
@ -482,17 +524,63 @@ main(int argc, char *argv[])
free(defos);
/*
* If a pager is attached, flush the pipe leading to it
* and signal end of file such that the user can browse
* to the end. Then wait for the user to close the pager.
* When using a pager, finish writing both temporary files,
* fork it, wait for the user to close it, and clean up.
*/
if (pager_pid != 0 && pager_pid != 1) {
if (tag_files != NULL) {
fclose(stdout);
waitpid(pager_pid, NULL, 0);
tag_write();
man_pgid = getpgid(0);
tag_files->tcpgid = man_pgid == getpid() ?
getpgid(getppid()) : man_pgid;
pager_pid = 0;
signum = SIGSTOP;
for (;;) {
/* Stop here until moved to the foreground. */
tc_pgid = tcgetpgrp(STDIN_FILENO);
if (tc_pgid != man_pgid) {
if (tc_pgid == pager_pid) {
(void)tcsetpgrp(STDIN_FILENO,
man_pgid);
if (signum == SIGTTIN)
continue;
} else
tag_files->tcpgid = tc_pgid;
kill(0, signum);
continue;
}
/* Once in the foreground, activate the pager. */
if (pager_pid) {
(void)tcsetpgrp(STDIN_FILENO, pager_pid);
kill(pager_pid, SIGCONT);
} else
pager_pid = spawn_pager(tag_files);
/* Wait for the pager to stop or exit. */
while ((pid = waitpid(pager_pid, &status,
WUNTRACED)) == -1 && errno == EINTR)
continue;
if (pid == -1) {
warn("wait");
rc = MANDOCLEVEL_SYSERR;
break;
}
if (!WIFSTOPPED(status))
break;
signum = WSTOPSIG(status);
}
tag_unlink();
}
return((int)rc);
return (int)rc;
}
static void
@ -501,9 +589,9 @@ usage(enum argmode argmode)
switch (argmode) {
case ARG_FILE:
fputs("usage: mandoc [-acfhkl] [-Ios=name] "
"[-Kencoding] [-mformat] [-Ooption]\n"
"\t [-Toutput] [-Wlevel] [file ...]\n", stderr);
fputs("usage: mandoc [-acfhkl] [-I os=name] "
"[-K encoding] [-mformat] [-O option]\n"
"\t [-T output] [-W level] [file ...]\n", stderr);
break;
case ARG_NAME:
fputs("usage: man [-acfhklw] [-C file] [-I os=name] "
@ -559,26 +647,23 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
free(file);
}
mandoc_asprintf(&file, "%s/man%s/%s.*",
mandoc_asprintf(&file, "%s/man%s/%s.[01-9]*",
paths->paths[ipath], sec, name);
globres = glob(file, 0, NULL, &globinfo);
if (globres != 0 && globres != GLOB_NOMATCH)
fprintf(stderr, "%s: %s: glob: %s\n",
progname, file, strerror(errno));
warn("%s: glob", file);
free(file);
if (globres == 0)
file = mandoc_strdup(*globinfo.gl_pathv);
globfree(&globinfo);
if (globres != 0)
return(0);
return 0;
found:
#if HAVE_SQLITE3
fprintf(stderr, "%s: outdated mandoc.db lacks %s(%s) entry,\n"
" consider running # makewhatis %s\n",
progname, name, sec, paths->paths[ipath]);
warnx("outdated mandoc.db lacks %s(%s) entry, run makewhatis %s",
name, sec, paths->paths[ipath]);
#endif
*res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
page = *res + (*ressz - 1);
page->file = file;
@ -588,7 +673,7 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
page->bits = NAME_FILE & NAME_MASK;
page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
page->form = form;
return(1);
return 1;
}
static void
@ -619,9 +704,7 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
return;
}
if (*ressz == lastsz)
fprintf(stderr,
"%s: No entry for %s in the manual.\n",
progname, *argv);
warnx("No entry for %s in the manual.", *argv);
lastsz = *ressz;
argv++;
argc--;
@ -629,111 +712,112 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
}
static void
parse(struct curparse *curp, int fd, const char *file,
enum mandoclevel *level)
parse(struct curparse *curp, int fd, const char *file)
{
enum mandoclevel rc;
struct mdoc *mdoc;
struct man *man;
enum mandoclevel rctmp;
struct roff_man *man;
/* Begin by parsing the file itself. */
assert(file);
assert(fd >= -1);
assert(fd > 0);
rc = mparse_readfd(curp->mp, fd, file);
rctmp = mparse_readfd(curp->mp, fd, file);
if (fd != STDIN_FILENO)
close(fd);
if (rc < rctmp)
rc = rctmp;
/*
* With -Wstop and warnings or errors of at least the requested
* level, do not produce output.
*/
if (MANDOCLEVEL_OK != rc && curp->wstop)
goto cleanup;
if (rctmp != MANDOCLEVEL_OK && curp->wstop)
return;
/* If unset, allocate output dev now (if applicable). */
if ( ! (curp->outman && curp->outmdoc)) {
if (curp->outdata == NULL) {
switch (curp->outtype) {
case OUTT_HTML:
curp->outdata = html_alloc(curp->mchars,
curp->outopts);
curp->outfree = html_free;
curp->outdata = html_alloc(curp->outopts);
break;
case OUTT_UTF8:
curp->outdata = utf8_alloc(curp->mchars,
curp->outopts);
curp->outfree = ascii_free;
curp->outdata = utf8_alloc(curp->outopts);
break;
case OUTT_LOCALE:
curp->outdata = locale_alloc(curp->mchars,
curp->outopts);
curp->outfree = ascii_free;
curp->outdata = locale_alloc(curp->outopts);
break;
case OUTT_ASCII:
curp->outdata = ascii_alloc(curp->mchars,
curp->outopts);
curp->outfree = ascii_free;
curp->outdata = ascii_alloc(curp->outopts);
break;
case OUTT_PDF:
curp->outdata = pdf_alloc(curp->mchars,
curp->outopts);
curp->outfree = pspdf_free;
curp->outdata = pdf_alloc(curp->outopts);
break;
case OUTT_PS:
curp->outdata = ps_alloc(curp->mchars,
curp->outopts);
curp->outfree = pspdf_free;
break;
default:
break;
}
switch (curp->outtype) {
case OUTT_HTML:
curp->outman = html_man;
curp->outmdoc = html_mdoc;
break;
case OUTT_TREE:
curp->outman = tree_man;
curp->outmdoc = tree_mdoc;
break;
case OUTT_MAN:
curp->outmdoc = man_mdoc;
curp->outman = man_man;
break;
case OUTT_PDF:
/* FALLTHROUGH */
case OUTT_ASCII:
/* FALLTHROUGH */
case OUTT_UTF8:
/* FALLTHROUGH */
case OUTT_LOCALE:
/* FALLTHROUGH */
case OUTT_PS:
curp->outman = terminal_man;
curp->outmdoc = terminal_mdoc;
curp->outdata = ps_alloc(curp->outopts);
break;
default:
break;
}
}
mparse_result(curp->mp, &mdoc, &man, NULL);
mparse_result(curp->mp, &man, NULL);
/* Execute the out device, if it exists. */
if (man && curp->outman)
(*curp->outman)(curp->outdata, man);
if (mdoc && curp->outmdoc)
(*curp->outmdoc)(curp->outdata, mdoc);
cleanup:
if (*level < rc)
*level = rc;
if (man == NULL)
return;
if (man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
switch (curp->outtype) {
case OUTT_HTML:
html_mdoc(curp->outdata, man);
break;
case OUTT_TREE:
tree_mdoc(curp->outdata, man);
break;
case OUTT_MAN:
man_mdoc(curp->outdata, man);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
terminal_mdoc(curp->outdata, man);
break;
default:
break;
}
}
if (man->macroset == MACROSET_MAN) {
man_validate(man);
switch (curp->outtype) {
case OUTT_HTML:
html_man(curp->outdata, man);
break;
case OUTT_TREE:
tree_man(curp->outdata, man);
break;
case OUTT_MAN:
man_man(curp->outdata, man);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
terminal_man(curp->outdata, man);
break;
default:
break;
}
}
}
static enum mandoclevel
static void
passthrough(const char *file, int fd, int synopsis_only)
{
const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS";
@ -741,12 +825,12 @@ passthrough(const char *file, int fd, int synopsis_only)
FILE *stream;
const char *syscall;
char *line;
size_t len, off;
ssize_t nw;
char *line, *cp;
size_t linesz;
int print;
fflush(stdout);
line = NULL;
linesz = 0;
if ((stream = fdopen(fd, "r")) == NULL) {
close(fd);
@ -755,48 +839,44 @@ passthrough(const char *file, int fd, int synopsis_only)
}
print = 0;
while ((line = fgetln(stream, &len)) != NULL) {
while (getline(&line, &linesz, stream) != -1) {
cp = line;
if (synopsis_only) {
if (print) {
if ( ! isspace((unsigned char)*line))
if ( ! isspace((unsigned char)*cp))
goto done;
while (len &&
isspace((unsigned char)*line)) {
line++;
len--;
}
while (isspace((unsigned char)*cp))
cp++;
} else {
if ((len == sizeof(synb) &&
! strncmp(line, synb, len - 1)) ||
(len == sizeof(synr) &&
! strncmp(line, synr, len - 1)))
if (strcmp(cp, synb) == 0 ||
strcmp(cp, synr) == 0)
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 (fputs(cp, stdout)) {
fclose(stream);
syscall = "fputs";
goto fail;
}
}
if (ferror(stream)) {
fclose(stream);
syscall = "fgetln";
syscall = "getline";
goto fail;
}
done:
free(line);
fclose(stream);
return(MANDOCLEVEL_OK);
return;
fail:
fprintf(stderr, "%s: %s: SYSERR: %s: %s",
progname, file, syscall, strerror(errno));
return(MANDOCLEVEL_SYSERR);
free(line);
warn("%s: SYSERR: %s", file, syscall);
if (rc < MANDOCLEVEL_SYSERR)
rc = MANDOCLEVEL_SYSERR;
}
static int
@ -812,11 +892,10 @@ koptions(int *options, char *arg)
} else if ( ! strcmp(arg, "us-ascii")) {
*options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
} else {
fprintf(stderr, "%s: -K %s: Bad argument\n",
progname, arg);
return(0);
warnx("-K %s: Bad argument", arg);
return 0;
}
return(1);
return 1;
}
static int
@ -832,12 +911,11 @@ moptions(int *options, char *arg)
else if (0 == strcmp(arg, "an"))
*options |= MPARSE_MAN;
else {
fprintf(stderr, "%s: -m %s: Bad argument\n",
progname, arg);
return(0);
warnx("-m %s: Bad argument", arg);
return 0;
}
return(1);
return 1;
}
static int
@ -866,12 +944,11 @@ toptions(struct curparse *curp, char *arg)
else if (0 == strcmp(arg, "pdf"))
curp->outtype = OUTT_PDF;
else {
fprintf(stderr, "%s: -T %s: Bad argument\n",
progname, arg);
return(0);
warnx("-T %s: Bad argument", arg);
return 0;
}
return(1);
return 1;
}
static int
@ -895,7 +972,6 @@ woptions(struct curparse *curp, char *arg)
curp->wstop = 1;
break;
case 1:
/* FALLTHROUGH */
case 2:
curp->wlevel = MANDOCLEVEL_WARNING;
break;
@ -909,13 +985,12 @@ woptions(struct curparse *curp, char *arg)
curp->wlevel = MANDOCLEVEL_BADARG;
break;
default:
fprintf(stderr, "%s: -W %s: Bad argument\n",
progname, o);
return(0);
warnx("-W %s: Bad argument", o);
return 0;
}
}
return(1);
return 1;
}
static void
@ -924,7 +999,7 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
{
const char *mparse_msg;
fprintf(stderr, "%s: %s:", progname, file);
fprintf(stderr, "%s: %s:", getprogname(), file);
if (line)
fprintf(stderr, "%d:%d:", line, col + 1);
@ -941,55 +1016,21 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
}
static pid_t
spawn_pager(void)
spawn_pager(struct tag_files *tag_files)
{
#define MAX_PAGER_ARGS 16
char *argv[MAX_PAGER_ARGS];
const char *pager;
char *cp;
int fildes[2];
size_t cmdlen;
int argc;
pid_t pager_pid;
if (pipe(fildes) == -1) {
fprintf(stderr, "%s: pipe: %s\n",
progname, strerror(errno));
return(0);
}
switch (pager_pid = fork()) {
case -1:
fprintf(stderr, "%s: fork: %s\n",
progname, strerror(errno));
exit((int)MANDOCLEVEL_SYSERR);
case 0:
break;
default:
close(fildes[0]);
if (dup2(fildes[1], STDOUT_FILENO) == -1) {
fprintf(stderr, "%s: dup output: %s\n",
progname, strerror(errno));
exit((int)MANDOCLEVEL_SYSERR);
}
close(fildes[1]);
return(pager_pid);
}
/* The child 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);
}
close(fildes[0]);
pager = getenv("MANPAGER");
if (pager == NULL || *pager == '\0')
pager = getenv("PAGER");
if (pager == NULL || *pager == '\0')
pager = "/usr/bin/more -s";
pager = "more -s";
cp = mandoc_strdup(pager);
/*
@ -998,7 +1039,7 @@ spawn_pager(void)
*/
argc = 0;
while (argc + 1 < MAX_PAGER_ARGS) {
while (argc + 4 < MAX_PAGER_ARGS) {
argv[argc++] = cp;
cp = strchr(cp, ' ');
if (cp == NULL)
@ -1009,12 +1050,43 @@ spawn_pager(void)
if (*cp == '\0')
break;
}
/* For more(1) and less(1), use the tag file. */
if ((cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
if (strcmp(cp, "less") == 0 || strcmp(cp, "more") == 0) {
argv[argc++] = mandoc_strdup("-T");
argv[argc++] = tag_files->tfn;
}
}
argv[argc++] = tag_files->ofn;
argv[argc] = NULL;
/* Hand over to the pager. */
switch (pager_pid = fork()) {
case -1:
err((int)MANDOCLEVEL_SYSERR, "fork");
case 0:
/* Set pgrp in both parent and child to avoid racing exec. */
(void)setpgid(0, 0);
break;
default:
(void)setpgid(pager_pid, 0);
(void)tcsetpgrp(STDIN_FILENO, pager_pid);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
tag_files->pager_pid = pager_pid;
return pager_pid;
}
/* The child process becomes the pager. */
if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
err((int)MANDOCLEVEL_SYSERR, "pager stdout");
close(tag_files->ofd);
close(tag_files->tfd);
execvp(argv[0], argv);
fprintf(stderr, "%s: exec: %s\n",
progname, strerror(errno));
exit((int)MANDOCLEVEL_SYSERR);
err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
}

45
main.h
View File

@ -1,15 +1,15 @@
/* $Id: main.h,v 1.20 2014/12/31 16:52:40 schwarze Exp $ */
/* $Id: main.h,v 1.24 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -18,11 +18,8 @@
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
__BEGIN_DECLS
struct mchars;
struct mdoc;
struct man;
struct roff_man;
struct manoutput;
/*
* Definitions for main.c-visible output device functions, e.g., -Thtml
@ -31,28 +28,26 @@ struct man;
* terminal output routines with different character settings.
*/
void *html_alloc(const struct mchars *, char *);
void html_mdoc(void *, const struct mdoc *);
void html_man(void *, const struct man *);
void *html_alloc(const struct manoutput *);
void html_mdoc(void *, const struct roff_man *);
void html_man(void *, const struct roff_man *);
void html_free(void *);
void tree_mdoc(void *, const struct mdoc *);
void tree_man(void *, const struct man *);
void tree_mdoc(void *, const struct roff_man *);
void tree_man(void *, const struct roff_man *);
void man_mdoc(void *, const struct mdoc *);
void man_man(void *, const struct man *);
void man_mdoc(void *, const struct roff_man *);
void man_man(void *, const struct roff_man *);
void *locale_alloc(const struct mchars *, char *);
void *utf8_alloc(const struct mchars *, char *);
void *ascii_alloc(const struct mchars *, char *);
void *locale_alloc(const struct manoutput *);
void *utf8_alloc(const struct manoutput *);
void *ascii_alloc(const struct manoutput *);
void ascii_free(void *);
void ascii_sepline(void *);
void *pdf_alloc(const struct mchars *, char *);
void *ps_alloc(const struct mchars *, char *);
void *pdf_alloc(const struct manoutput *);
void *ps_alloc(const struct manoutput *);
void pspdf_free(void *);
void terminal_mdoc(void *, const struct mdoc *);
void terminal_man(void *, const struct man *);
__END_DECLS
void terminal_mdoc(void *, const struct roff_man *);
void terminal_man(void *, const struct roff_man *);

View File

@ -1,13 +0,0 @@
body { font-family: Helvetica, Arial, sans-serif; }
body > div { padding-left: 2em;
padding-top: 1em; }
body > div#mancgi { padding-left: 0em;
padding-top: 0em; }
body > div.results { font-size: smaller; }
#mancgi fieldset { text-align: center;
border: thin solid silver;
border-radius: 1em;
font-size: small; }
#mancgi input[name=expr] { width: 25%; }
.results td.title { vertical-align: top;
padding-right: 1em; }

32
man.1
View File

@ -1,4 +1,4 @@
.\" $Id: man.1,v 1.13 2015/02/16 16:23:54 schwarze Exp $
.\" $Id: man.1,v 1.16 2015/09/21 09:59:02 schwarze Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -31,7 +31,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
.Dd $Mdocdate: February 16 2015 $
.Dd $Mdocdate: September 21 2015 $
.Dt MAN 1
.Os
.Sh NAME
@ -173,12 +173,6 @@ must be a colon
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
@ -194,12 +188,6 @@ the directories specified using the
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 O Ar option Ns = Ns Ar value
Comma-separated output options.
For each output format, the available options are described in the
@ -360,6 +348,13 @@ Any non-empty value of the environment variable
.Ev MANPAGER
will be used instead of the standard pagination program,
.Xr more 1 .
If
.Xr less 1
is used, the interactive
.Ic :t
command can be used to go to the definitions of various terms, for
example command line options, command modifiers, internal commands,
and environment variables.
.It Ev MANPATH
The standard search path used by
.Nm
@ -370,18 +365,13 @@ 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
.Xr more 1
.Fl s
will be used.
.El
.Sh FILES

503
man.c
View File

@ -1,4 +1,4 @@
/* $Id: man.c,v 1.149 2015/01/30 21:28:46 schwarze Exp $ */
/* $Id: man.c,v 1.166 2015/10/22 21:54:23 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -8,9 +8,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -27,11 +27,13 @@
#include <stdio.h>
#include <string.h>
#include "man.h"
#include "mandoc.h"
#include "mandoc_aux.h"
#include "libman.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
@ -48,306 +50,25 @@ const char *const __man_macronames[MAN_MAX] = {
const char * const *man_macronames = __man_macronames;
static void man_alloc1(struct man *);
static void man_breakscope(struct man *, enum mant);
static void man_descope(struct man *, int, int);
static void man_free1(struct man *);
static struct man_node *man_node_alloc(struct man *, int, int,
enum man_type, enum mant);
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 *);
static int man_ptext(struct man *, int, char *, int);
static int man_pmacro(struct man *, int, char *, int);
static void man_descope(struct roff_man *, int, int);
static int man_ptext(struct roff_man *, int, char *, int);
static int man_pmacro(struct roff_man *, int, char *, int);
const struct man_node *
man_node(const struct man *man)
{
return(man->first);
}
const struct man_meta *
man_meta(const struct man *man)
{
return(&man->meta);
}
void
man_reset(struct man *man)
{
man_free1(man);
man_alloc1(man);
}
void
man_free(struct man *man)
{
man_free1(man);
free(man);
}
struct man *
man_alloc(struct roff *roff, struct mparse *parse,
const char *defos, int quick)
{
struct man *p;
p = mandoc_calloc(1, sizeof(struct man));
man_hash_init();
p->parse = parse;
p->defos = defos;
p->quick = quick;
p->roff = roff;
man_alloc1(p);
return(p);
}
void
man_endparse(struct man *man)
{
man_macroend(man);
}
int
man_parseln(struct man *man, int ln, char *buf, int offs)
man_parseln(struct roff_man *man, int ln, char *buf, int offs)
{
if (man->last->type != MAN_EQN || ln > man->last->line)
if (man->last->type != ROFFT_EQN || ln > man->last->line)
man->flags |= MAN_NEWLINE;
return (roff_getcontrol(man->roff, buf, &offs) ?
return roff_getcontrol(man->roff, buf, &offs) ?
man_pmacro(man, ln, buf, offs) :
man_ptext(man, ln, buf, offs));
man_ptext(man, ln, buf, offs);
}
static void
man_free1(struct man *man)
{
if (man->first)
man_node_delete(man, man->first);
free(man->meta.title);
free(man->meta.source);
free(man->meta.date);
free(man->meta.vol);
free(man->meta.msec);
}
static void
man_alloc1(struct man *man)
{
memset(&man->meta, 0, sizeof(struct man_meta));
man->flags = 0;
man->last = mandoc_calloc(1, sizeof(struct man_node));
man->first = man->last;
man->last->type = MAN_ROOT;
man->last->tok = MAN_MAX;
man->next = MAN_NEXT_CHILD;
}
static void
man_node_append(struct man *man, struct man_node *p)
{
assert(man->last);
assert(man->first);
assert(p->type != MAN_ROOT);
switch (man->next) {
case MAN_NEXT_SIBLING:
man->last->next = p;
p->prev = man->last;
p->parent = man->last->parent;
break;
case MAN_NEXT_CHILD:
man->last->child = p;
p->parent = man->last;
break;
default:
abort();
/* NOTREACHED */
}
assert(p->parent);
p->parent->nchild++;
switch (p->type) {
case MAN_BLOCK:
if (p->tok == MAN_SH || p->tok == MAN_SS)
man->flags &= ~MAN_LITERAL;
break;
case MAN_HEAD:
assert(p->parent->type == MAN_BLOCK);
p->parent->head = p;
break;
case MAN_BODY:
assert(p->parent->type == MAN_BLOCK);
p->parent->body = p;
break;
default:
break;
}
man->last = p;
switch (p->type) {
case MAN_TBL:
/* FALLTHROUGH */
case MAN_TEXT:
man_valid_post(man);
break;
default:
break;
}
}
static struct man_node *
man_node_alloc(struct man *man, int line, int pos,
enum man_type type, enum mant tok)
{
struct man_node *p;
p = mandoc_calloc(1, sizeof(struct man_node));
p->line = line;
p->pos = pos;
p->type = type;
p->tok = tok;
if (man->flags & MAN_NEWLINE)
p->flags |= MAN_LINE;
man->flags &= ~MAN_NEWLINE;
return(p);
}
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);
man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
}
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);
man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
}
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);
man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
}
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);
man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
}
void
man_word_alloc(struct man *man, int line, int pos, const char *word)
{
struct man_node *n;
n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
n->string = roff_strdup(man->roff, word);
man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
}
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;
}
/*
* Free all of the resources held by a node. This does NOT unlink a
* node from its context; for that, see man_node_unlink().
*/
static void
man_node_free(struct man_node *p)
{
free(p->string);
free(p);
}
void
man_node_delete(struct man *man, struct man_node *p)
{
while (p->child)
man_node_delete(man, p->child);
man_node_unlink(man, p);
man_node_free(p);
}
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 (ep->ln > man->last->line)
n->flags |= MAN_LINE;
man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
man_descope(man, ep->ln, ep->pos);
}
void
man_addspan(struct man *man, const struct tbl_span *sp)
{
struct man_node *n;
man_breakscope(man, MAN_MAX);
n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
n->span = sp;
man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
man_descope(man, sp->line, 0);
}
static void
man_descope(struct man *man, int line, int offs)
man_descope(struct roff_man *man, int line, int offs)
{
/*
* Co-ordinate what happens with having a next-line scope open:
@ -363,20 +84,20 @@ man_descope(struct man *man, int line, int offs)
return;
man->flags &= ~MAN_BLINE;
man_unscope(man, man->last->parent);
man_body_alloc(man, line, offs, man->last->tok);
roff_body_alloc(man, line, offs, man->last->tok);
}
static int
man_ptext(struct man *man, int line, char *buf, int offs)
man_ptext(struct roff_man *man, int line, char *buf, int offs)
{
int i;
/* Literal free-form text whitespace is preserved. */
if (man->flags & MAN_LITERAL) {
man_word_alloc(man, line, offs, buf + offs);
roff_word_alloc(man, line, offs, buf + offs);
man_descope(man, line, offs);
return(1);
return 1;
}
for (i = offs; buf[i] == ' '; i++)
@ -391,10 +112,10 @@ man_ptext(struct man *man, int line, char *buf, int offs)
/* Allocate a blank entry. */
if (man->last->tok != MAN_SH &&
man->last->tok != MAN_SS) {
man_elem_alloc(man, line, offs, MAN_sp);
man->next = MAN_NEXT_SIBLING;
roff_elem_alloc(man, line, offs, MAN_sp);
man->next = ROFF_NEXT_SIBLING;
}
return(1);
return 1;
}
/*
@ -418,7 +139,7 @@ man_ptext(struct man *man, int line, char *buf, int offs)
buf[i] = '\0';
}
man_word_alloc(man, line, offs, buf + offs);
roff_word_alloc(man, line, offs, buf + offs);
/*
* End-of-sentence check. If the last character is an unescaped
@ -431,15 +152,15 @@ man_ptext(struct man *man, int line, char *buf, int offs)
man->last->flags |= MAN_EOS;
man_descope(man, line, offs);
return(1);
return 1;
}
static int
man_pmacro(struct man *man, int ln, char *buf, int offs)
man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
{
struct man_node *n;
struct roff_node *n;
const char *cp;
enum mant tok;
int tok;
int i, ppos;
int bline;
char mac[5];
@ -457,12 +178,12 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
mac[i] = '\0';
tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
tok = (i > 0 && i < 4) ? man_hash_find(mac) : TOKEN_NONE;
if (tok == MAN_MAX) {
if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, man->parse,
ln, ppos, buf + ppos - 1);
return(1);
return 1;
}
/* Skip a leading escape sequence or tab. */
@ -511,9 +232,9 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
if (man->quick && tok == MAN_SH) {
n = man->last;
if (n->type == MAN_BODY &&
if (n->type == ROFFT_BODY &&
strcmp(n->prev->child->string, "NAME"))
return(2);
return 2;
}
/*
@ -524,20 +245,20 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
if ( ! bline || man->flags & MAN_ELINE ||
man_macros[tok].flags & MAN_NSCOPED)
return(1);
return 1;
assert(man->flags & MAN_BLINE);
man->flags &= ~MAN_BLINE;
man_unscope(man, man->last->parent);
man_body_alloc(man, ln, ppos, man->last->tok);
return(1);
roff_body_alloc(man, ln, ppos, man->last->tok);
return 1;
}
void
man_breakscope(struct man *man, enum mant tok)
man_breakscope(struct roff_man *man, int tok)
{
struct man_node *n;
struct roff_node *n;
/*
* An element next line scope is open,
@ -545,142 +266,104 @@ man_breakscope(struct man *man, enum mant tok)
* Delete the element that is being broken.
*/
if (man->flags & MAN_ELINE && (tok == MAN_MAX ||
if (man->flags & MAN_ELINE && (tok == TOKEN_NONE ||
! (man_macros[tok].flags & MAN_NSCOPED))) {
n = man->last;
assert(n->type != MAN_TEXT);
assert(n->type != ROFFT_TEXT);
if (man_macros[n->tok].flags & MAN_NSCOPED)
n = n->parent;
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
tok == MAN_MAX ? "TS" : man_macronames[tok],
tok == TOKEN_NONE ? "TS" : man_macronames[tok],
man_macronames[n->tok]);
man_node_delete(man, n);
roff_node_delete(man, n);
man->flags &= ~MAN_ELINE;
}
/*
* Weird special case:
* Switching fill mode closes section headers.
*/
if (man->flags & MAN_BLINE &&
(tok == MAN_nf || tok == MAN_fi) &&
(man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
n = man->last;
man_unscope(man, n);
roff_body_alloc(man, n->line, n->pos, n->tok);
man->flags &= ~MAN_BLINE;
}
/*
* A block header next line scope is open,
* and the new macro is not allowed inside block headers.
* Delete the block that is being broken.
*/
if (man->flags & MAN_BLINE && (tok == MAN_MAX ||
if (man->flags & MAN_BLINE && (tok == TOKEN_NONE ||
man_macros[tok].flags & MAN_BSCOPE)) {
n = man->last;
if (n->type == MAN_TEXT)
if (n->type == ROFFT_TEXT)
n = n->parent;
if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
n = n->parent;
assert(n->type == MAN_HEAD);
assert(n->type == ROFFT_HEAD);
n = n->parent;
assert(n->type == MAN_BLOCK);
assert(n->type == ROFFT_BLOCK);
assert(man_macros[n->tok].flags & MAN_SCOPED);
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
tok == MAN_MAX ? "TS" : man_macronames[tok],
tok == TOKEN_NONE ? "TS" : man_macronames[tok],
man_macronames[n->tok]);
man_node_delete(man, n);
roff_node_delete(man, n);
man->flags &= ~MAN_BLINE;
}
}
/*
* Unlink a node from its context. If "man" is provided, the last parse
* point will also be adjusted accordingly.
*/
static void
man_node_unlink(struct man *man, struct man_node *n)
{
/* Adjust siblings. */
if (n->prev)
n->prev->next = n->next;
if (n->next)
n->next->prev = n->prev;
/* Adjust parent. */
if (n->parent) {
n->parent->nchild--;
if (n->parent->child == n)
n->parent->child = n->prev ? n->prev : n->next;
}
/* Adjust parse point, if applicable. */
if (man && man->last == n) {
/*XXX: this can occur when bailing from validation. */
/*assert(NULL == n->next);*/
if (n->prev) {
man->last = n->prev;
man->next = MAN_NEXT_SIBLING;
} else {
man->last = n->parent;
man->next = MAN_NEXT_CHILD;
}
}
if (man && man->first == n)
man->first = NULL;
}
const struct mparse *
man_mparse(const struct man *man)
man_mparse(const struct roff_man *man)
{
assert(man && man->parse);
return(man->parse);
return man->parse;
}
void
man_deroff(char **dest, const struct man_node *n)
man_state(struct roff_man *man, struct roff_node *n)
{
char *cp;
size_t sz;
if (n->type != MAN_TEXT) {
for (n = n->child; n; n = n->next)
man_deroff(dest, n);
return;
switch(n->tok) {
case MAN_nf:
case MAN_EX:
if (man->flags & MAN_LITERAL && ! (n->flags & MAN_VALID))
mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
n->line, n->pos, "nf");
man->flags |= MAN_LITERAL;
break;
case MAN_fi:
case MAN_EE:
if ( ! (man->flags & MAN_LITERAL) &&
! (n->flags & MAN_VALID))
mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
n->line, n->pos, "fi");
man->flags &= ~MAN_LITERAL;
break;
default:
break;
}
/* Skip leading whitespace and escape sequences. */
cp = n->string;
while ('\0' != *cp) {
if ('\\' == *cp) {
cp++;
mandoc_escape((const char **)&cp, NULL, NULL);
} else if (isspace((unsigned char)*cp))
cp++;
else
break;
}
/* Skip trailing whitespace. */
for (sz = strlen(cp); sz; sz--)
if (0 == isspace((unsigned char)cp[sz-1]))
break;
/* Skip empty strings. */
if (0 == sz)
return;
if (NULL == *dest) {
*dest = mandoc_strndup(cp, sz);
return;
}
mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
free(*dest);
*dest = cp;
man->last->flags |= MAN_VALID;
}
void
man_validate(struct roff_man *man)
{
man->last = man->first;
man_node_validate(man);
man->flags &= ~MAN_LITERAL;
}

View File

@ -1,4 +1,4 @@
.\" $Id: man.cgi.8,v 1.11 2014/09/14 19:44:28 schwarze Exp $
.\" $Id: man.cgi.8,v 1.13 2015/11/05 20:55:41 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: September 14 2014 $
.Dd $Mdocdate: November 5 2015 $
.Dt MAN.CGI 8
.Os
.Sh NAME
@ -161,6 +161,9 @@ database inside each manpath.
Configure your web server to execute CGI programs located in
.Pa /cgi-bin .
When using
.Ox
.Xr httpd 8
or
.Xr nginx 8 ,
the
.Xr slowcgi 8
@ -187,14 +190,8 @@ and to be specified without a trailing slash.
When not specified, the CSS files
are assumed to be in the document root.
This is used in generated HTML code.
.It Ev CUSTOMIZE_BEGIN
A HTML string to be inserted right after opening the
.Aq BODY
element.
.It Ev CUSTOMIZE_TITLE
An ASCII string to be used for the HTML
.Aq TITLE
element.
An ASCII string to be used for the HTML <TITLE> element.
.It Ev HTTP_HOST
The FQDN of the (possibly virtual) host the HTTP server is running on.
This is used for
@ -349,15 +346,10 @@ Can be overridden by
The path to the server document root relative to the server root.
This is part of the web server configuration and not specific to
.Nm .
.It Pa /htdocs/man-cgi.css
A style sheet for general
.Nm
styling, referenced from each generated HTML page.
.It Pa /htdocs/man.css
.It Pa /htdocs/mandoc.css
A style sheet for
.Xr mandoc 1
HTML styling, referenced from each generated HTML page after
.Pa man-cgi.css .
HTML styling, referenced from each generated HTML page.
.It Pa /man
Default
.Nm
@ -376,6 +368,12 @@ or any character not contained in the
.Sx Restricted character set ,
.Nm
reports an internal server error and exits without doing anything.
.It Pa /man/header.html
An optional file containing static HTML code to be inserted right
after opening the <BODY> element.
.It Pa /man/footer.html
An optional file containing static HTML code to be inserted right
before closing the <BODY> element.
.It Pa /man/OpenBSD-current/man1/mandoc.1
An example
.Xr mdoc 7

131
man.conf.5 Normal file
View File

@ -0,0 +1,131 @@
.\" $Id: man.conf.5,v 1.3 2015/03/27 21:33:20 schwarze Exp $
.\"
.\" Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: March 27 2015 $
.Dt MAN.CONF 5
.Os
.Sh NAME
.Nm man.conf
.Nd configuration file for man
.Sh DESCRIPTION
This is the configuration file
for the
.Xr man 1 ,
.Xr apropos 1 ,
and
.Xr makewhatis 8
utilities.
Its presence, and all directives, are optional.
.Pp
This file is an ASCII text file.
Leading whitespace on lines, lines starting with
.Sq # ,
and blank lines are ignored.
Words are separated by whitespace.
The first word on each line is the name of a configuration directive.
.Pp
The following directives are supported:
.Bl -tag -width Ds
.It Ic manpath Ar path
Override the default search
.Ar path
for
.Xr man 1 ,
.Xr apropos 1 ,
and
.Xr makewhatis 8 .
It can be used multiple times to specify multiple paths,
with the order determining the manual page search order.
.Pp
Each path is a tree containing subdirectories
whose names consist of the strings
.Sq man
and/or
.Sq cat
followed by the names of sections, usually single digits.
The former are supposed to contain unformatted manual pages in
.Xr mdoc 7
and/or
.Xr man 7
format; file names should end with the name of the section
preceded by a dot.
The latter should contain preformatted manual pages;
file names should end with
.Ql .0 .
.Pp
Creating a
.Xr mandoc.db 5
database with
.Xr makewhatis 8
in each directory configured with
.Ic manpath
is recommended and necessary for
.Xr apropos 1
to work, but not strictly required for
.Xr man 1 .
.It Ic output Ar option Op Ar value
Configure the default value of an output option.
These directives are overridden by the
.Fl O
command line options of the same names.
For details, see the
.Xr mandoc 1
manual.
.Pp
.Bl -column fragment integer "ascii, utf8" -compact
.It Ar option Ta Ar value Ta used by Fl T Ta purpose
.It Ta Ta Ta
.It Ic fragment Ta none Ta Cm html Ta print only body
.It Ic includes Ta string Ta Cm html Ta path to header files
.It Ic indent Ta integer Ta Cm ascii , utf8 Ta left margin
.It Ic man Ta string Ta Cm html Ta path for Xr links
.It Ic paper Ta string Ta Cm ps , pdf Ta paper size
.It Ic style Ta string Ta Cm html Ta CSS file
.It Ic width Ta integer Ta Cm ascii , utf8 Ta right margin
.El
.It Ic _whatdb Ar path Ns Cm /whatis.db
This directive provides the same functionality as
.Ic manpath ,
but using a historic and misleading syntax.
It is kept for backward compatibility for now,
but will eventually be removed.
.El
.Sh FILES
.Pa /etc/man.conf
.Sh EXAMPLES
The following configuration file reproduces the defaults:
installing it is equivalent to not having a
.Nm
file at all.
.Bd -literal -offset indent
manpath /usr/share/man
manpath /usr/X11R6/man
manpath /usr/local/man
.Ed
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr man 1 ,
.Xr makewhatis 8
.Sh HISTORY
A relatively complicated
.Nm
file format first appeared in
.Bx 4.3 Reno .
For
.Ox 5.8 ,
it was redesigned from scratch, aiming for simplicity.
.Sh AUTHORS
.An Ingo Schwarze Aq Mt schwarze@openbsd.org

144
man.h
View File

@ -1,116 +1,66 @@
/* $Id: man.h,v 1.69 2015/01/24 02:41:49 schwarze Exp $ */
/* $Id: man.h,v 1.77 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum mant {
MAN_br = 0,
MAN_TH,
MAN_SH,
MAN_SS,
MAN_TP,
MAN_LP,
MAN_PP,
MAN_P,
MAN_IP,
MAN_HP,
MAN_SM,
MAN_SB,
MAN_BI,
MAN_IB,
MAN_BR,
MAN_RB,
MAN_R,
MAN_B,
MAN_I,
MAN_IR,
MAN_RI,
MAN_sp,
MAN_nf,
MAN_fi,
MAN_RE,
MAN_RS,
MAN_DT,
MAN_UC,
MAN_PD,
MAN_AT,
MAN_in,
MAN_ft,
MAN_OP,
MAN_EX,
MAN_EE,
MAN_UR,
MAN_UE,
MAN_ll,
MAN_MAX
};
#define MAN_br 0
#define MAN_TH 1
#define MAN_SH 2
#define MAN_SS 3
#define MAN_TP 4
#define MAN_LP 5
#define MAN_PP 6
#define MAN_P 7
#define MAN_IP 8
#define MAN_HP 9
#define MAN_SM 10
#define MAN_SB 11
#define MAN_BI 12
#define MAN_IB 13
#define MAN_BR 14
#define MAN_RB 15
#define MAN_R 16
#define MAN_B 17
#define MAN_I 18
#define MAN_IR 19
#define MAN_RI 20
#define MAN_sp 21
#define MAN_nf 22
#define MAN_fi 23
#define MAN_RE 24
#define MAN_RS 25
#define MAN_DT 26
#define MAN_UC 27
#define MAN_PD 28
#define MAN_AT 29
#define MAN_in 30
#define MAN_ft 31
#define MAN_OP 32
#define MAN_EX 33
#define MAN_EE 34
#define MAN_UR 35
#define MAN_UE 36
#define MAN_ll 37
#define MAN_MAX 38
enum man_type {
MAN_TEXT,
MAN_ELEM,
MAN_ROOT,
MAN_BLOCK,
MAN_HEAD,
MAN_BODY,
MAN_TBL,
MAN_EQN
};
struct man_meta {
char *msec; /* `TH' section (1, 3p, etc.) */
char *date; /* `TH' normalised date */
char *vol; /* `TH' volume */
char *title; /* `TH' title (e.g., FOO) */
char *source; /* `TH' source (e.g., GNU) */
int hasbody; /* document is not empty */
};
struct man_node {
struct man_node *parent; /* parent AST node */
struct man_node *child; /* first child AST node */
struct man_node *next; /* sibling AST node */
struct man_node *prev; /* prior sibling AST node */
int nchild; /* number children */
int line;
int pos;
enum mant tok; /* tok or MAN__MAX if none */
int flags;
#define MAN_VALID (1 << 0) /* has been validated */
#define MAN_EOS (1 << 2) /* at sentence boundary */
#define MAN_LINE (1 << 3) /* first macro/text on line */
enum man_type type; /* AST node type */
char *string; /* TEXT node argument */
struct man_node *head; /* BLOCK node HEAD ptr */
struct man_node *tail; /* BLOCK node TAIL ptr */
struct man_node *body; /* BLOCK node BODY ptr */
const struct tbl_span *span; /* TBL */
const struct eqn *eqn; /* EQN */
int aux; /* decoded node data, type-dependent */
};
/* Names of macros. Index is enum mant. */
/* Names of macros. */
extern const char *const *man_macronames;
__BEGIN_DECLS
struct man;
struct roff_man;
const struct man_node *man_node(const struct man *);
const struct man_meta *man_meta(const struct man *);
const struct mparse *man_mparse(const struct man *);
void man_deroff(char **, const struct man_node *);
__END_DECLS
const struct mparse *man_mparse(const struct roff_man *);
void man_validate(struct roff_man *);

View File

@ -1,6 +1,7 @@
/* $Id: man_hash.c,v 1.29 2014/12/01 08:05:52 schwarze Exp $ */
/* $Id: man_hash.c,v 1.34 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -23,6 +24,7 @@
#include <limits.h>
#include <string.h>
#include "roff.h"
#include "man.h"
#include "libman.h"
@ -46,18 +48,15 @@
static unsigned char table[26 * HASH_DEPTH];
/*
* XXX - this hash has global scope, so if intended for use as a library
* with multiple callers, it will need re-invocation protection.
*/
void
man_hash_init(void)
{
int i, j, x;
memset(table, UCHAR_MAX, sizeof(table));
if (*table != '\0')
return;
assert(MAN_MAX < UCHAR_MAX);
memset(table, UCHAR_MAX, sizeof(table));
for (i = 0; i < (int)MAN_MAX; i++) {
x = man_macronames[i][0];
@ -76,27 +75,27 @@ man_hash_init(void)
}
}
enum mant
int
man_hash_find(const char *tmp)
{
int x, y, i;
enum mant tok;
int tok;
if ('\0' == (x = tmp[0]))
return(MAN_MAX);
return TOKEN_NONE;
if ( ! (isalpha((unsigned char)x)))
return(MAN_MAX);
return TOKEN_NONE;
HASH_ROW(x);
for (i = 0; i < HASH_DEPTH; i++) {
if (UCHAR_MAX == (y = table[x + i]))
return(MAN_MAX);
return TOKEN_NONE;
tok = (enum mant)y;
tok = y;
if (0 == strcmp(tmp, man_macronames[tok]))
return(tok);
return tok;
}
return(MAN_MAX);
return TOKEN_NONE;
}

View File

@ -1,4 +1,4 @@
/* $Id: man_html.c,v 1.112 2015/03/03 21:11:34 schwarze Exp $ */
/* $Id: man_html.c,v 1.120 2016/01/08 17:48:09 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,9 +7,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -26,6 +26,7 @@
#include <string.h>
#include "mandoc_aux.h"
#include "roff.h"
#include "man.h"
#include "out.h"
#include "html.h"
@ -36,8 +37,8 @@
#define INDENT 5
#define MAN_ARGS const struct man_meta *man, \
const struct man_node *n, \
#define MAN_ARGS const struct roff_meta *man, \
const struct roff_node *n, \
struct mhtml *mh, \
struct html *h
@ -52,12 +53,11 @@ struct htmlman {
};
static void print_bvspace(struct html *,
const struct man_node *);
static void print_man(MAN_ARGS);
const struct roff_node *);
static void print_man_head(MAN_ARGS);
static void print_man_nodelist(MAN_ARGS);
static void print_man_node(MAN_ARGS);
static int a2width(const struct man_node *,
static int a2width(const struct roff_node *,
struct roffsu *);
static int man_B_pre(MAN_ARGS);
static int man_HP_pre(MAN_ARGS);
@ -129,14 +129,14 @@ static const struct htmlman mans[MAN_MAX] = {
* first, print it.
*/
static void
print_bvspace(struct html *h, const struct man_node *n)
print_bvspace(struct html *h, const struct roff_node *n)
{
if (n->body && n->body->child)
if (MAN_TBL == n->body->child->type)
if (n->body->child->type == ROFFT_TBL)
return;
if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
if (NULL == n->prev)
return;
@ -144,36 +144,31 @@ print_bvspace(struct html *h, const struct man_node *n)
}
void
html_man(void *arg, const struct man *man)
html_man(void *arg, const struct roff_man *man)
{
struct mhtml mh;
memset(&mh, 0, sizeof(struct mhtml));
print_man(man_meta(man), man_node(man), &mh, (struct html *)arg);
putchar('\n');
}
static void
print_man(MAN_ARGS)
{
struct tag *t, *tt;
struct htmlpair tag;
struct html *h;
struct tag *t, *tt;
memset(&mh, 0, sizeof(mh));
PAIR_CLASS_INIT(&tag, "mandoc");
h = (struct html *)arg;
if ( ! (HTML_FRAGMENT & h->oflags)) {
print_gen_decls(h);
t = print_otag(h, TAG_HTML, 0, NULL);
tt = print_otag(h, TAG_HEAD, 0, NULL);
print_man_head(man, n, mh, h);
print_man_head(&man->meta, man->first, &mh, h);
print_tagq(h, tt);
print_otag(h, TAG_BODY, 0, NULL);
print_otag(h, TAG_DIV, 1, &tag);
} else
t = print_otag(h, TAG_DIV, 1, &tag);
print_man_nodelist(man, n, mh, h);
print_man_nodelist(&man->meta, man->first, &mh, h);
print_tagq(h, t);
putchar('\n');
}
static void
@ -208,10 +203,10 @@ print_man_node(MAN_ARGS)
t = h->tags.head;
switch (n->type) {
case MAN_ROOT:
case ROFFT_ROOT:
man_root_pre(man, n, mh, h);
break;
case MAN_TEXT:
case ROFFT_TEXT:
if ('\0' == *n->string) {
print_paragraph(h);
return;
@ -222,12 +217,12 @@ print_man_node(MAN_ARGS)
print_otag(h, TAG_BR, 0, NULL);
print_text(h, n->string);
return;
case MAN_EQN:
case ROFFT_EQN:
if (n->flags & MAN_LINE)
putchar('\n');
print_eqn(h, n->eqn);
break;
case MAN_TBL:
case ROFFT_TBL:
/*
* This will take care of initialising all of the table
* state data for the first table, then tearing it down
@ -266,10 +261,10 @@ print_man_node(MAN_ARGS)
print_stagq(h, t);
switch (n->type) {
case MAN_ROOT:
case ROFFT_ROOT:
man_root_post(man, n, mh, h);
break;
case MAN_EQN:
case ROFFT_EQN:
break;
default:
if (mans[n->tok].post)
@ -279,15 +274,15 @@ print_man_node(MAN_ARGS)
}
static int
a2width(const struct man_node *n, struct roffsu *su)
a2width(const struct roff_node *n, struct roffsu *su)
{
if (MAN_TEXT != n->type)
return(0);
if (n->type != ROFFT_TEXT)
return 0;
if (a2roffsu(n->string, su, SCALE_EN))
return(1);
return 1;
return(0);
return 0;
}
static void
@ -347,8 +342,8 @@ man_root_post(MAN_ARGS)
PAIR_CLASS_INIT(&tag, "foot-os");
print_otag(h, TAG_TD, 1, &tag);
if (man->source)
print_text(h, man->source);
if (man->os)
print_text(h, man->os);
print_tagq(h, t);
}
@ -376,7 +371,7 @@ man_br_pre(MAN_ARGS)
/* So the div isn't empty: */
print_text(h, "\\~");
return(0);
return 0;
}
static int
@ -384,22 +379,22 @@ man_SH_pre(MAN_ARGS)
{
struct htmlpair tag;
if (MAN_BLOCK == n->type) {
if (n->type == ROFFT_BLOCK) {
mh->fl &= ~MANH_LITERAL;
PAIR_CLASS_INIT(&tag, "section");
print_otag(h, TAG_DIV, 1, &tag);
return(1);
} else if (MAN_BODY == n->type)
return(1);
return 1;
} else if (n->type == ROFFT_BODY)
return 1;
print_otag(h, TAG_H1, 0, NULL);
return(1);
return 1;
}
static int
man_alt_pre(MAN_ARGS)
{
const struct man_node *nn;
const struct roff_node *nn;
int i, savelit;
enum htmltag fp;
struct tag *t;
@ -432,7 +427,6 @@ man_alt_pre(MAN_ARGS)
break;
default:
abort();
/* NOTREACHED */
}
if (i)
@ -450,7 +444,7 @@ man_alt_pre(MAN_ARGS)
if (savelit)
mh->fl |= MANH_LITERAL;
return(0);
return 0;
}
static int
@ -460,7 +454,7 @@ man_SM_pre(MAN_ARGS)
print_otag(h, TAG_SMALL, 0, NULL);
if (MAN_SB == n->tok)
print_otag(h, TAG_B, 0, NULL);
return(1);
return 1;
}
static int
@ -468,41 +462,41 @@ man_SS_pre(MAN_ARGS)
{
struct htmlpair tag;
if (MAN_BLOCK == n->type) {
if (n->type == ROFFT_BLOCK) {
mh->fl &= ~MANH_LITERAL;
PAIR_CLASS_INIT(&tag, "subsection");
print_otag(h, TAG_DIV, 1, &tag);
return(1);
} else if (MAN_BODY == n->type)
return(1);
return 1;
} else if (n->type == ROFFT_BODY)
return 1;
print_otag(h, TAG_H2, 0, NULL);
return(1);
return 1;
}
static int
man_PP_pre(MAN_ARGS)
{
if (MAN_HEAD == n->type)
return(0);
else if (MAN_BLOCK == n->type)
if (n->type == ROFFT_HEAD)
return 0;
else if (n->type == ROFFT_BLOCK)
print_bvspace(h, n);
return(1);
return 1;
}
static int
man_IP_pre(MAN_ARGS)
{
const struct man_node *nn;
const struct roff_node *nn;
if (MAN_BODY == n->type) {
if (n->type == ROFFT_BODY) {
print_otag(h, TAG_DD, 0, NULL);
return(1);
} else if (MAN_HEAD != n->type) {
return 1;
} else if (n->type != ROFFT_HEAD) {
print_otag(h, TAG_DL, 0, NULL);
return(1);
return 1;
}
/* FIXME: width specification. */
@ -526,7 +520,7 @@ man_IP_pre(MAN_ARGS)
}
}
return(0);
return 0;
}
static int
@ -534,12 +528,12 @@ man_HP_pre(MAN_ARGS)
{
struct htmlpair tag[2];
struct roffsu su;
const struct man_node *np;
const struct roff_node *np;
if (MAN_HEAD == n->type)
return(0);
else if (MAN_BLOCK != n->type)
return(1);
if (n->type == ROFFT_HEAD)
return 0;
else if (n->type != ROFFT_BLOCK)
return 1;
np = n->head->child;
@ -555,7 +549,7 @@ man_HP_pre(MAN_ARGS)
PAIR_STYLE_INIT(&tag[0], h);
PAIR_CLASS_INIT(&tag[1], "spacer");
print_otag(h, TAG_DIV, 2, tag);
return(1);
return 1;
}
static int
@ -584,7 +578,7 @@ man_OP_pre(MAN_ARGS)
print_stagq(h, tt);
h->flags |= HTML_NOSPACE;
print_text(h, "]");
return(0);
return 0;
}
static int
@ -592,7 +586,7 @@ man_B_pre(MAN_ARGS)
{
print_otag(h, TAG_B, 0, NULL);
return(1);
return 1;
}
static int
@ -600,7 +594,7 @@ man_I_pre(MAN_ARGS)
{
print_otag(h, TAG_I, 0, NULL);
return(1);
return 1;
}
static int
@ -613,7 +607,7 @@ man_literal_pre(MAN_ARGS)
} else
mh->fl |= MANH_LITERAL;
return(0);
return 0;
}
static int
@ -621,14 +615,14 @@ man_in_pre(MAN_ARGS)
{
print_otag(h, TAG_BR, 0, NULL);
return(0);
return 0;
}
static int
man_ign_pre(MAN_ARGS)
{
return(0);
return 0;
}
static int
@ -637,10 +631,10 @@ man_RS_pre(MAN_ARGS)
struct htmlpair tag;
struct roffsu su;
if (MAN_HEAD == n->type)
return(0);
else if (MAN_BODY == n->type)
return(1);
if (n->type == ROFFT_HEAD)
return 0;
else if (n->type == ROFFT_BODY)
return 1;
SCALE_HS_INIT(&su, INDENT);
if (n->head->child)
@ -650,7 +644,7 @@ man_RS_pre(MAN_ARGS)
bufcat_su(h, "margin-left", &su);
PAIR_STYLE_INIT(&tag, h);
print_otag(h, TAG_DIV, 1, &tag);
return(1);
return 1;
}
static int
@ -659,19 +653,19 @@ man_UR_pre(MAN_ARGS)
struct htmlpair tag[2];
n = n->child;
assert(MAN_HEAD == n->type);
if (n->nchild) {
assert(MAN_TEXT == n->child->type);
assert(n->type == ROFFT_HEAD);
if (n->child != NULL) {
assert(n->child->type == ROFFT_TEXT);
PAIR_CLASS_INIT(&tag[0], "link-ext");
PAIR_HREF_INIT(&tag[1], n->child->string);
print_otag(h, TAG_A, 2, tag);
}
assert(MAN_BODY == n->next->type);
if (n->next->nchild)
assert(n->next->type == ROFFT_BODY);
if (n->next->child != NULL)
n = n->next;
print_man_nodelist(man, n->child, mh, h);
return(0);
return 0;
}

View File

@ -1,4 +1,4 @@
/* $Id: man_macro.c,v 1.98 2015/02/06 11:54:36 schwarze Exp $ */
/* $Id: man_macro.c,v 1.114 2016/01/08 17:48:09 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -8,9 +8,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -25,37 +25,27 @@
#include <stdlib.h>
#include <string.h>
#include "man.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
enum rew {
REW_REWIND,
REW_NOHALT,
REW_HALT
};
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,
static int man_args(struct roff_man *, int,
int *, char *, char **);
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 *);
static enum rew rew_block(enum mant, enum man_type,
const struct man_node *);
static void rew_scope(struct roff_man *, int);
const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_NSCOPED }, /* br */
{ in_line_eoln, MAN_BSCOPE }, /* TH */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */
{ blk_imp, MAN_BSCOPE }, /* LP */
{ blk_imp, MAN_BSCOPE }, /* PP */
{ blk_imp, MAN_BSCOPE }, /* P */
@ -73,20 +63,20 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
{ in_line_eoln, MAN_NSCOPED }, /* sp */
{ in_line_eoln, MAN_BSCOPE }, /* nf */
{ in_line_eoln, MAN_BSCOPE }, /* fi */
{ in_line_eoln, MAN_NSCOPED }, /* nf */
{ in_line_eoln, MAN_NSCOPED }, /* fi */
{ blk_close, MAN_BSCOPE }, /* RE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */
{ blk_exp, MAN_BSCOPE }, /* RS */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
{ in_line_eoln, 0 }, /* PD */
{ in_line_eoln, MAN_NSCOPED }, /* PD */
{ in_line_eoln, 0 }, /* AT */
{ in_line_eoln, 0 }, /* in */
{ in_line_eoln, 0 }, /* ft */
{ in_line_eoln, 0 }, /* OP */
{ in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
{ blk_exp, MAN_BSCOPE }, /* UR */
{ blk_close, MAN_BSCOPE }, /* UE */
{ in_line_eoln, 0 }, /* ll */
};
@ -95,9 +85,9 @@ const struct man_macro * const man_macros = __man_macros;
void
man_unscope(struct man *man, const struct man_node *to)
man_unscope(struct roff_man *man, const struct roff_node *to)
{
struct man_node *n;
struct roff_node *n;
to = to->parent;
n = man->last;
@ -115,17 +105,17 @@ man_unscope(struct man *man, const struct man_node *to)
if (man->flags & MAN_ELINE)
man->flags &= ~MAN_ELINE;
else {
assert(n->type == MAN_HEAD);
assert(n->type == ROFFT_HEAD);
n = n->parent;
man->flags &= ~MAN_BLINE;
}
man->last = n;
n = n->parent;
man_node_delete(man, man->last);
roff_node_delete(man, man->last);
continue;
}
if (n->type == MAN_BLOCK &&
man_macros[n->tok].flags & MAN_EXPLICIT)
if (n->type == ROFFT_BLOCK &&
man_macros[n->tok].fp == blk_exp)
mandoc_msg(MANDOCERR_BLK_NOEND,
man->parse, n->line, n->pos,
man_macronames[n->tok]);
@ -140,7 +130,7 @@ man_unscope(struct man *man, const struct man_node *to)
man->last = n;
n = n->parent;
man_valid_post(man);
man->last->flags |= MAN_VALID;
}
/*
@ -151,90 +141,7 @@ man_unscope(struct man *man, const struct man_node *to)
*/
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 (type == MAN_BLOCK && ntok == n->parent->tok &&
n->parent->type == MAN_BODY)
return(REW_REWIND);
return(ntok == n->tok ? REW_HALT : REW_NOHALT);
}
/*
* There are three scope levels: scoped to the root (all), scoped to the
* section (all less sections), and scoped to subsections (all less
* sections and subsections).
*/
static enum rew
rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
{
enum rew c;
/* We cannot progress beyond the root ever. */
if (MAN_ROOT == n->type)
return(REW_HALT);
assert(n->parent);
/* Normal nodes shouldn't go to the level of the root. */
if (MAN_ROOT == n->parent->type)
return(REW_REWIND);
/* Already-validated nodes should be closed out. */
if (MAN_VALID & n->flags)
return(REW_NOHALT);
/* First: rewind to ourselves. */
if (type == n->type && tok == n->tok) {
if (MAN_EXPLICIT & man_macros[n->tok].flags)
return(REW_HALT);
else
return(REW_REWIND);
}
/*
* Next follow the implicit scope-smashings as defined by man.7:
* section, sub-section, etc.
*/
switch (tok) {
case MAN_SH:
break;
case MAN_SS:
/* Rewind to a section, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
return(c);
break;
case MAN_RS:
/* Preserve empty paragraphs before RS. */
if (0 == n->nchild && (MAN_P == n->tok ||
MAN_PP == n->tok || MAN_LP == n->tok))
return(REW_HALT);
/* Rewind to a subsection, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
return(c);
/* Rewind to a section, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
return(c);
break;
default:
/* Rewind to an offsetter, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
return(c);
/* Rewind to a subsection, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
return(c);
/* Rewind to a section, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
return(c);
break;
}
return(REW_NOHALT);
ROFF_NEXT_CHILD : ROFF_NEXT_SIBLING;
}
/*
@ -243,30 +150,40 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
* scopes. When a scope is closed, it must be validated and actioned.
*/
static void
rew_scope(enum man_type type, struct man *man, enum mant tok)
rew_scope(struct roff_man *man, int tok)
{
struct man_node *n;
enum rew c;
struct roff_node *n;
for (n = man->last; n; n = n->parent) {
/*
* Whether we should stop immediately (REW_HALT), stop
* and rewind until this point (REW_REWIND), or keep
* rewinding (REW_NOHALT).
*/
c = rew_dohalt(tok, type, n);
if (REW_HALT == c)
/* Preserve empty paragraphs before RS. */
n = man->last;
if (tok == MAN_RS && n->child == NULL &&
(n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP))
return;
for (;;) {
if (n->type == ROFFT_ROOT)
return;
if (REW_REWIND == c)
break;
if (n->flags & MAN_VALID) {
n = n->parent;
continue;
}
if (n->type != ROFFT_BLOCK) {
if (n->parent->type == ROFFT_ROOT) {
man_unscope(man, n);
return;
} else {
n = n->parent;
continue;
}
}
if (tok != MAN_SH && (n->tok == MAN_SH ||
(tok != MAN_SS && (n->tok == MAN_SS ||
man_macros[n->tok].fp == blk_exp))))
return;
man_unscope(man, n);
n = man->last;
}
/*
* Rewind until the current point. Warn if we're a roff
* instruction that's mowing over explicit scopes.
*/
man_unscope(man, n);
}
@ -276,8 +193,8 @@ rew_scope(enum man_type type, struct man *man, enum mant tok)
void
blk_close(MACRO_PROT_ARGS)
{
enum mant ntok;
const struct man_node *nn;
int ntok;
const struct roff_node *nn;
char *p;
int nrew, target;
@ -288,7 +205,7 @@ blk_close(MACRO_PROT_ARGS)
if ( ! man_args(man, line, pos, buf, &p))
break;
for (nn = man->last->parent; nn; nn = nn->parent)
if (nn->tok == ntok && nn->type == MAN_BLOCK)
if (nn->tok == ntok && nn->type == ROFFT_BLOCK)
nrew++;
target = strtol(p, &p, 10);
if (*p != '\0')
@ -308,17 +225,16 @@ blk_close(MACRO_PROT_ARGS)
break;
default:
abort();
/* NOTREACHED */
}
for (nn = man->last->parent; nn; nn = nn->parent)
if (nn->tok == ntok && nn->type == MAN_BLOCK && ! --nrew)
if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew)
break;
if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, man_macronames[tok]);
rew_scope(MAN_BLOCK, man, MAN_PP);
rew_scope(man, MAN_PP);
} else {
line = man->last->line;
ppos = man->last->pos;
@ -337,18 +253,17 @@ blk_close(MACRO_PROT_ARGS)
void
blk_exp(MACRO_PROT_ARGS)
{
struct man_node *head;
struct roff_node *head;
char *p;
int la;
rew_scope(MAN_BLOCK, man, tok);
man_block_alloc(man, line, ppos, tok);
man_head_alloc(man, line, ppos, tok);
head = man->last;
rew_scope(man, tok);
roff_block_alloc(man, line, ppos, tok);
head = roff_head_alloc(man, line, ppos, tok);
la = *pos;
if (man_args(man, line, pos, buf, &p))
man_word_alloc(man, line, la, p);
roff_word_alloc(man, line, la, p);
if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
@ -356,12 +271,12 @@ blk_exp(MACRO_PROT_ARGS)
man_macronames[tok], buf + *pos);
man_unscope(man, head);
man_body_alloc(man, line, ppos, tok);
roff_body_alloc(man, line, ppos, tok);
}
/*
* Parse an implicit-block macro. These contain a MAN_HEAD and a
* MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
* Parse an implicit-block macro. These contain a ROFFT_HEAD and a
* ROFFT_BODY contained within a ROFFT_BLOCK. Rules for closing out other
* scopes, such as `SH' closing out an `SS', are defined in the rew
* routines.
*/
@ -370,13 +285,13 @@ blk_imp(MACRO_PROT_ARGS)
{
int la;
char *p;
struct man_node *n;
struct roff_node *n;
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;
rew_scope(man, tok);
n = roff_block_alloc(man, line, ppos, tok);
if (n->tok == MAN_SH || n->tok == MAN_SS)
man->flags &= ~MAN_LITERAL;
n = roff_head_alloc(man, line, ppos, tok);
/* Add line arguments. */
@ -384,23 +299,25 @@ blk_imp(MACRO_PROT_ARGS)
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
man_word_alloc(man, line, la, p);
roff_word_alloc(man, line, la, p);
}
/* Close out head and open body (unless MAN_SCOPE). */
/*
* For macros having optional next-line scope,
* keep the head open if there were no arguments.
* For `TP', always keep the head open.
*/
if (man_macros[tok].flags & MAN_SCOPED) {
/* If we're forcing scope (`TP'), keep it open. */
if (man_macros[tok].flags & MAN_FSCOPED) {
man->flags |= MAN_BLINE;
return;
} else if (n == man->last) {
man->flags |= MAN_BLINE;
return;
}
if (man_macros[tok].flags & MAN_SCOPED &&
(tok == MAN_TP || n == man->last)) {
man->flags |= MAN_BLINE;
return;
}
rew_scope(MAN_HEAD, man, tok);
man_body_alloc(man, line, ppos, tok);
/* Close out the head and open the body. */
man_unscope(man, n);
roff_body_alloc(man, line, ppos, tok);
}
void
@ -408,9 +325,9 @@ in_line_eoln(MACRO_PROT_ARGS)
{
int la;
char *p;
struct man_node *n;
struct roff_node *n;
man_elem_alloc(man, line, ppos, tok);
roff_elem_alloc(man, line, ppos, tok);
n = man->last;
for (;;) {
@ -432,10 +349,10 @@ in_line_eoln(MACRO_PROT_ARGS)
if ( ! man_args(man, line, pos, buf, &p))
break;
if (man_macros[tok].flags & MAN_JOIN &&
man->last->type == MAN_TEXT)
man_word_append(man, p);
man->last->type == ROFFT_TEXT)
roff_word_append(man, p);
else
man_word_alloc(man, line, la, p);
roff_word_alloc(man, line, la, p);
}
/*
@ -459,43 +376,28 @@ in_line_eoln(MACRO_PROT_ARGS)
return;
}
assert(man->last->type != MAN_ROOT);
man->next = MAN_NEXT_SIBLING;
assert(man->last->type != ROFFT_ROOT);
man->next = ROFF_NEXT_SIBLING;
/*
* Rewind our element scope. Note that when TH is pruned, we'll
* be back at the root, so make sure that we don't clobber as
* its sibling.
*/
/* Rewind our element scope. */
for ( ; man->last; man->last = man->last->parent) {
man_state(man, man->last);
if (man->last == n)
break;
if (man->last->type == MAN_ROOT)
break;
man_valid_post(man);
}
assert(man->last);
/*
* Same here regarding whether we're back at the root.
*/
if (man->last->type != MAN_ROOT)
man_valid_post(man);
}
void
man_macroend(struct man *man)
man_endparse(struct roff_man *man)
{
man_unscope(man, man->first);
man->flags &= ~MAN_LITERAL;
}
static int
man_args(struct man *man, int line, int *pos, char *buf, char **v)
man_args(struct roff_man *man, int line, int *pos, char *buf, char **v)
{
char *start;
@ -504,8 +406,8 @@ man_args(struct man *man, int line, int *pos, char *buf, char **v)
assert(' ' != *start);
if ('\0' == *start)
return(0);
return 0;
*v = mandoc_getarg(man->parse, v, line, pos);
return(1);
return 1;
}

View File

@ -1,4 +1,4 @@
/* $Id: man_term.c,v 1.169 2015/03/06 15:48:52 schwarze Exp $ */
/* $Id: man_term.c,v 1.187 2016/01/08 17:48:09 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,9 +7,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -26,10 +26,11 @@
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "out.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "out.h"
#include "term.h"
#include "main.h"
@ -47,8 +48,8 @@ struct mtermp {
#define DECL_ARGS struct termp *p, \
struct mtermp *mt, \
struct man_node *n, \
const struct man_meta *meta
struct roff_node *n, \
const struct roff_meta *meta
struct termact {
int (*pre)(DECL_ARGS);
@ -59,10 +60,12 @@ struct termact {
static void print_man_nodelist(DECL_ARGS);
static void print_man_node(DECL_ARGS);
static void print_man_head(struct termp *, const void *);
static void print_man_foot(struct termp *, const void *);
static void print_man_head(struct termp *,
const struct roff_meta *);
static void print_man_foot(struct termp *,
const struct roff_meta *);
static void print_bvspace(struct termp *,
const struct man_node *, int);
const struct roff_node *, int);
static int pre_B(DECL_ARGS);
static int pre_HP(DECL_ARGS);
@ -135,36 +138,32 @@ static const struct termact termacts[MAN_MAX] = {
void
terminal_man(void *arg, const struct man *man)
terminal_man(void *arg, const struct roff_man *man)
{
struct termp *p;
const struct man_meta *meta;
struct man_node *n;
struct roff_node *n;
struct mtermp mt;
p = (struct termp *)arg;
p->overstep = 0;
p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
n = man_node(man)->child;
meta = man_meta(man);
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;
n = man->first->child;
if (p->synopsisonly) {
while (n != NULL) {
if (n->tok == MAN_SH &&
n->child->child->type == MAN_TEXT &&
n->child->child->type == ROFFT_TEXT &&
!strcmp(n->child->child->string, "SYNOPSIS")) {
if (n->child->next->child != NULL)
print_man_nodelist(p, &mt,
n->child->next->child, meta);
n->child->next->child,
&man->meta);
term_newln(p);
break;
}
@ -173,10 +172,10 @@ terminal_man(void *arg, const struct man *man)
} else {
if (p->defindent == 0)
p->defindent = 7;
term_begin(p, print_man_head, print_man_foot, meta);
term_begin(p, print_man_head, print_man_foot, &man->meta);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
print_man_nodelist(p, &mt, n, meta);
print_man_nodelist(p, &mt, n, &man->meta);
term_end(p);
}
}
@ -190,17 +189,17 @@ terminal_man(void *arg, const struct man *man)
* first, print it.
*/
static void
print_bvspace(struct termp *p, const struct man_node *n, int pardist)
print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
{
int i;
term_newln(p);
if (n->body && n->body->child)
if (MAN_TBL == n->body->child->type)
if (n->body->child->type == ROFFT_TBL)
return;
if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
if (NULL == n->prev)
return;
@ -213,15 +212,15 @@ static int
pre_ign(DECL_ARGS)
{
return(0);
return 0;
}
static int
pre_ll(DECL_ARGS)
{
term_setwidth(p, n->nchild ? n->child->string : NULL);
return(0);
term_setwidth(p, n->child != NULL ? n->child->string : NULL);
return 0;
}
static int
@ -229,7 +228,7 @@ pre_I(DECL_ARGS)
{
term_fontrepl(p, TERMFONT_UNDER);
return(1);
return 1;
}
static int
@ -256,7 +255,7 @@ pre_literal(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
}
return(0);
return 0;
}
static int
@ -267,19 +266,19 @@ pre_PD(DECL_ARGS)
n = n->child;
if (n == NULL) {
mt->pardist = 1;
return(0);
return 0;
}
assert(MAN_TEXT == n->type);
assert(n->type == ROFFT_TEXT);
if (a2roffsu(n->string, &su, SCALE_VS))
mt->pardist = term_vspan(p, &su);
return(0);
return 0;
}
static int
pre_alternate(DECL_ARGS)
{
enum termfont font[2];
struct man_node *nn;
struct roff_node *nn;
int savelit, i;
switch (n->tok) {
@ -318,12 +317,15 @@ pre_alternate(DECL_ARGS)
term_fontrepl(p, font[i]);
if (savelit && NULL == nn->next)
mt->fl |= MANT_LITERAL;
print_man_node(p, mt, nn, meta);
assert(nn->type == ROFFT_TEXT);
term_word(p, nn->string);
if (nn->flags & MAN_EOS)
p->flags |= TERMP_SENTENCE;
if (nn->next)
p->flags |= TERMP_NOSPACE;
}
return(0);
return 0;
}
static int
@ -331,7 +333,7 @@ pre_B(DECL_ARGS)
{
term_fontrepl(p, TERMFONT_BOLD);
return(1);
return 1;
}
static int
@ -353,7 +355,7 @@ pre_OP(DECL_ARGS)
term_fontrepl(p, TERMFONT_NONE);
p->flags |= TERMP_NOSPACE;
term_word(p, "]");
return(0);
return 0;
}
static int
@ -363,20 +365,17 @@ pre_ft(DECL_ARGS)
if (NULL == n->child) {
term_fontlast(p);
return(0);
return 0;
}
cp = n->child->string;
switch (*cp) {
case '4':
/* FALLTHROUGH */
case '3':
/* FALLTHROUGH */
case 'B':
term_fontrepl(p, TERMFONT_BOLD);
break;
case '2':
/* FALLTHROUGH */
case 'I':
term_fontrepl(p, TERMFONT_UNDER);
break;
@ -384,16 +383,14 @@ pre_ft(DECL_ARGS)
term_fontlast(p);
break;
case '1':
/* FALLTHROUGH */
case 'C':
/* FALLTHROUGH */
case 'R':
term_fontrepl(p, TERMFONT_NONE);
break;
default:
break;
}
return(0);
return 0;
}
static int
@ -408,7 +405,7 @@ pre_in(DECL_ARGS)
if (NULL == n->child) {
p->offset = mt->offset;
return(0);
return 0;
}
cp = n->child->string;
@ -422,9 +419,9 @@ pre_in(DECL_ARGS)
cp--;
if ( ! a2roffsu(++cp, &su, SCALE_EN))
return(0);
return 0;
v = term_hspan(p, &su);
v = (term_hspan(p, &su) + 11) / 24;
if (less < 0)
p->offset -= p->offset > v ? v : p->offset;
@ -435,7 +432,7 @@ pre_in(DECL_ARGS)
if (p->offset > SHRT_MAX)
p->offset = term_len(p, p->defindent);
return(0);
return 0;
}
static int
@ -447,16 +444,11 @@ pre_sp(DECL_ARGS)
if ((NULL == n->prev && n->parent)) {
switch (n->parent->tok) {
case MAN_SH:
/* FALLTHROUGH */
case MAN_SS:
/* FALLTHROUGH */
case MAN_PP:
/* FALLTHROUGH */
case MAN_LP:
/* FALLTHROUGH */
case MAN_P:
/* FALLTHROUGH */
return(0);
return 0;
default:
break;
}
@ -480,24 +472,35 @@ pre_sp(DECL_ARGS)
for (i = 0; i < len; i++)
term_vspace(p);
return(0);
/*
* Handle an explicit break request in the same way
* as an overflowing line.
*/
if (p->flags & TERMP_BRIND) {
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
}
return 0;
}
static int
pre_HP(DECL_ARGS)
{
struct roffsu su;
const struct man_node *nn;
const struct roff_node *nn;
int len;
switch (n->type) {
case MAN_BLOCK:
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
return(1);
case MAN_BODY:
return 1;
case ROFFT_BODY:
break;
default:
return(0);
return 0;
}
if ( ! (MANT_LITERAL & mt->fl)) {
@ -509,7 +512,7 @@ pre_HP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN)) {
len = term_hspan(p, &su);
len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@ -520,7 +523,7 @@ pre_HP(DECL_ARGS)
p->offset = mt->offset;
p->rmargin = mt->offset + len;
return(1);
return 1;
}
static void
@ -528,8 +531,19 @@ post_HP(DECL_ARGS)
{
switch (n->type) {
case MAN_BODY:
case ROFFT_BODY:
term_newln(p);
/*
* Compatibility with a groff bug.
* The .HP macro uses the undocumented .tag request
* which causes a line break and cancels no-space
* mode even if there isn't any output.
*/
if (n->child == NULL)
term_vspace(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0;
p->offset = mt->offset;
@ -545,7 +559,7 @@ pre_PP(DECL_ARGS)
{
switch (n->type) {
case MAN_BLOCK:
case ROFFT_BLOCK:
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n, mt->pardist);
break;
@ -554,36 +568,36 @@ pre_PP(DECL_ARGS)
break;
}
return(MAN_HEAD != n->type);
return n->type != ROFFT_HEAD;
}
static int
pre_IP(DECL_ARGS)
{
struct roffsu su;
const struct man_node *nn;
const struct roff_node *nn;
int len, savelit;
switch (n->type) {
case MAN_BODY:
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
case MAN_HEAD:
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
case MAN_BLOCK:
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return(1);
return 1;
}
/* Calculate the offset from the optional second argument. */
if ((nn = n->parent->head->child) != NULL &&
(nn = nn->next) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN)) {
len = term_hspan(p, &su);
len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@ -593,7 +607,7 @@ pre_IP(DECL_ARGS)
len = mt->lmargin[mt->lmargincur];
switch (n->type) {
case MAN_HEAD:
case ROFFT_HEAD:
p->offset = mt->offset;
p->rmargin = mt->offset + len;
@ -606,8 +620,8 @@ pre_IP(DECL_ARGS)
if (savelit)
mt->fl |= MANT_LITERAL;
return(0);
case MAN_BODY:
return 0;
case ROFFT_BODY:
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
break;
@ -615,7 +629,7 @@ pre_IP(DECL_ARGS)
break;
}
return(1);
return 1;
}
static void
@ -623,13 +637,13 @@ post_IP(DECL_ARGS)
{
switch (n->type) {
case MAN_HEAD:
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
p->rmargin = p->maxrmargin;
break;
case MAN_BODY:
case ROFFT_BODY:
term_newln(p);
p->offset = mt->offset;
break;
@ -642,22 +656,22 @@ static int
pre_TP(DECL_ARGS)
{
struct roffsu su;
struct man_node *nn;
struct roff_node *nn;
int len, savelit;
switch (n->type) {
case MAN_HEAD:
p->flags |= TERMP_NOBREAK;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
p->trailspace = 1;
break;
case MAN_BODY:
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
case MAN_BLOCK:
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return(1);
return 1;
}
/* Calculate offset. */
@ -665,7 +679,7 @@ pre_TP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
nn->string != NULL && ! (MAN_LINE & nn->flags) &&
a2roffsu(nn->string, &su, SCALE_EN)) {
len = term_hspan(p, &su);
len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@ -675,7 +689,7 @@ pre_TP(DECL_ARGS)
len = mt->lmargin[mt->lmargincur];
switch (n->type) {
case MAN_HEAD:
case ROFFT_HEAD:
p->offset = mt->offset;
p->rmargin = mt->offset + len;
@ -694,18 +708,18 @@ pre_TP(DECL_ARGS)
if (savelit)
mt->fl |= MANT_LITERAL;
return(0);
case MAN_BODY:
return 0;
case ROFFT_BODY:
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
default:
break;
}
return(1);
return 1;
}
static void
@ -713,10 +727,10 @@ post_TP(DECL_ARGS)
{
switch (n->type) {
case MAN_HEAD:
case ROFFT_HEAD:
term_flushln(p);
break;
case MAN_BODY:
case ROFFT_BODY:
term_newln(p);
p->offset = mt->offset;
break;
@ -731,7 +745,7 @@ pre_SS(DECL_ARGS)
int i;
switch (n->type) {
case MAN_BLOCK:
case ROFFT_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@ -743,25 +757,32 @@ pre_SS(DECL_ARGS)
do {
n = n->prev;
} while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT);
} while (n != NULL && n->tok != TOKEN_NONE &&
termacts[n->tok].flags & MAN_NOTEXT);
if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL))
break;
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
case MAN_HEAD:
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = term_len(p, 3);
p->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case MAN_BODY:
case ROFFT_BODY:
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
default:
break;
}
return(1);
return 1;
}
static void
@ -769,10 +790,10 @@ post_SS(DECL_ARGS)
{
switch (n->type) {
case MAN_HEAD:
case ROFFT_HEAD:
term_newln(p);
break;
case MAN_BODY:
case ROFFT_BODY:
term_newln(p);
break;
default:
@ -786,7 +807,7 @@ pre_SH(DECL_ARGS)
int i;
switch (n->type) {
case MAN_BLOCK:
case ROFFT_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@ -805,18 +826,24 @@ pre_SH(DECL_ARGS)
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
case MAN_HEAD:
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = 0;
p->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case MAN_BODY:
case ROFFT_BODY:
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
default:
break;
}
return(1);
return 1;
}
static void
@ -824,10 +851,10 @@ post_SH(DECL_ARGS)
{
switch (n->type) {
case MAN_HEAD:
case ROFFT_HEAD:
term_newln(p);
break;
case MAN_BODY:
case ROFFT_BODY:
term_newln(p);
break;
default:
@ -841,19 +868,21 @@ pre_RS(DECL_ARGS)
struct roffsu su;
switch (n->type) {
case MAN_BLOCK:
case ROFFT_BLOCK:
term_newln(p);
return(1);
case MAN_HEAD:
return(0);
return 1;
case ROFFT_HEAD:
return 0;
default:
break;
}
n = n->parent->head;
n->aux = SHRT_MAX + 1;
if (n->child != NULL && a2roffsu(n->child->string, &su, SCALE_EN))
n->aux = term_hspan(p, &su);
if (n->child == NULL)
n->aux = mt->lmargin[mt->lmargincur];
else if (a2roffsu(n->child->string, &su, SCALE_EN))
n->aux = term_hspan(p, &su) / 24;
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
n->aux = -mt->offset;
else if (n->aux > SHRT_MAX)
@ -866,8 +895,8 @@ pre_RS(DECL_ARGS)
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
return(1);
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
return 1;
}
static void
@ -875,9 +904,9 @@ post_RS(DECL_ARGS)
{
switch (n->type) {
case MAN_BLOCK:
case ROFFT_BLOCK:
return;
case MAN_HEAD:
case ROFFT_HEAD:
return;
default:
term_newln(p);
@ -895,14 +924,14 @@ static int
pre_UR(DECL_ARGS)
{
return (MAN_HEAD != n->type);
return n->type != ROFFT_HEAD;
}
static void
post_UR(DECL_ARGS)
{
if (MAN_BLOCK != n->type)
if (n->type != ROFFT_BLOCK)
return;
term_word(p, "<");
@ -922,7 +951,7 @@ print_man_node(DECL_ARGS)
int c;
switch (n->type) {
case MAN_TEXT:
case ROFFT_TEXT:
/*
* If we have a blank line, output a vertical space.
* If we have a space as the first character, break
@ -937,14 +966,14 @@ print_man_node(DECL_ARGS)
term_word(p, n->string);
goto out;
case MAN_EQN:
case ROFFT_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:
case ROFFT_TBL:
if (p->tbl.cols == NULL)
term_vspace(p);
term_tbl(p, n->span);
@ -1010,13 +1039,11 @@ print_man_nodelist(DECL_ARGS)
}
static void
print_man_foot(struct termp *p, const void *arg)
print_man_foot(struct termp *p, const struct roff_meta *meta)
{
const struct man_meta *meta;
char *title;
size_t datelen, titlen;
meta = (const struct man_meta *)arg;
assert(meta->title);
assert(meta->msec);
assert(meta->date);
@ -1028,8 +1055,8 @@ print_man_foot(struct termp *p, const void *arg)
/*
* Temporary, undocumented option to imitate mdoc(7) output.
* In the bottom right corner, use the source instead of
* the title.
* In the bottom right corner, use the operating system
* instead of the title.
*/
if ( ! p->mdocstyle) {
@ -1039,14 +1066,14 @@ print_man_foot(struct termp *p, const void *arg)
}
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
} else if (meta->source) {
title = mandoc_strdup(meta->source);
} else if (meta->os) {
title = mandoc_strdup(meta->os);
} else {
title = mandoc_strdup("");
}
datelen = term_strlen(p, meta->date);
/* Bottom left corner: manual source. */
/* Bottom left corner: operating system. */
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
@ -1054,8 +1081,8 @@ print_man_foot(struct termp *p, const void *arg)
p->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
if (meta->source)
term_word(p, meta->source);
if (meta->os)
term_word(p, meta->os);
term_flushln(p);
/* At the bottom in the middle: manual date. */
@ -1082,14 +1109,12 @@ print_man_foot(struct termp *p, const void *arg)
}
static void
print_man_head(struct termp *p, const void *arg)
print_man_head(struct termp *p, const struct roff_meta *meta)
{
const struct man_meta *meta;
const char *volume;
char *title;
size_t vollen, titlen;
meta = (const struct man_meta *)arg;
assert(meta->title);
assert(meta->msec);

View File

@ -1,15 +1,15 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012-2016 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -28,13 +28,15 @@
#include <string.h>
#include <time.h>
#include "man.h"
#include "mandoc.h"
#include "mandoc_aux.h"
#include "libman.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
#define CHKARGS struct man *man, struct man_node *n
#define CHKARGS struct roff_man *man, struct roff_node *n
typedef void (*v_check)(CHKARGS);
@ -46,9 +48,7 @@ static void check_text(CHKARGS);
static void post_AT(CHKARGS);
static void post_IP(CHKARGS);
static void post_vs(CHKARGS);
static void post_fi(CHKARGS);
static void post_ft(CHKARGS);
static void post_nf(CHKARGS);
static void post_OP(CHKARGS);
static void post_TH(CHKARGS);
static void post_UC(CHKARGS);
@ -77,8 +77,8 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* IR */
NULL, /* RI */
post_vs, /* sp */
post_nf, /* nf */
post_fi, /* fi */
NULL, /* nf */
NULL, /* fi */
NULL, /* RE */
check_part, /* RS */
NULL, /* DT */
@ -88,8 +88,8 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* in */
post_ft, /* ft */
post_OP, /* OP */
post_nf, /* EX */
post_fi, /* EE */
NULL, /* EX */
NULL, /* EE */
post_UR, /* UR */
NULL, /* UE */
NULL, /* ll */
@ -97,31 +97,39 @@ static v_check man_valids[MAN_MAX] = {
void
man_valid_post(struct man *man)
man_node_validate(struct roff_man *man)
{
struct man_node *n;
struct roff_node *n;
v_check *cp;
n = man->last;
if (n->flags & MAN_VALID)
return;
n->flags |= MAN_VALID;
man->last = man->last->child;
while (man->last != NULL) {
man_node_validate(man);
if (man->last == n)
man->last = man->last->child;
else
man->last = man->last->next;
}
man->last = n;
man->next = ROFF_NEXT_SIBLING;
switch (n->type) {
case MAN_TEXT:
case ROFFT_TEXT:
check_text(man, n);
break;
case MAN_ROOT:
case ROFFT_ROOT:
check_root(man, n);
break;
case MAN_EQN:
/* FALLTHROUGH */
case MAN_TBL:
case ROFFT_EQN:
case ROFFT_TBL:
break;
default:
cp = man_valids + n->tok;
if (*cp)
(*cp)(man, n);
if (man->last == n)
man_state(man, n);
break;
}
}
@ -172,10 +180,10 @@ static void
post_OP(CHKARGS)
{
if (n->nchild == 0)
if (n->child == NULL)
mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
n->line, n->pos, "OP");
else if (n->nchild > 2) {
else if (n->child->next != NULL && n->child->next->next != NULL) {
n = n->child->next->next;
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
n->line, n->pos, "OP ... %s", n->string);
@ -186,7 +194,7 @@ static void
post_UR(CHKARGS)
{
if (n->type == MAN_HEAD && n->child == NULL)
if (n->type == ROFFT_HEAD && n->child == NULL)
mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
n->line, n->pos, "UR");
check_part(man, n);
@ -198,24 +206,18 @@ post_ft(CHKARGS)
char *cp;
int ok;
if (0 == n->nchild)
if (n->child == NULL)
return;
ok = 0;
cp = n->child->string;
switch (*cp) {
case '1':
/* FALLTHROUGH */
case '2':
/* FALLTHROUGH */
case '3':
/* FALLTHROUGH */
case '4':
/* FALLTHROUGH */
case 'I':
/* FALLTHROUGH */
case 'P':
/* FALLTHROUGH */
case 'R':
if ('\0' == cp[1])
ok = 1;
@ -243,7 +245,7 @@ static void
check_part(CHKARGS)
{
if (n->type == MAN_BODY && n->child == NULL)
if (n->type == ROFFT_BODY && n->child == NULL)
mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
n->line, n->pos, man_macronames[n->tok]);
}
@ -253,23 +255,23 @@ check_par(CHKARGS)
{
switch (n->type) {
case MAN_BLOCK:
if (0 == n->body->nchild)
man_node_delete(man, n);
case ROFFT_BLOCK:
if (n->body->child == NULL)
roff_node_delete(man, n);
break;
case MAN_BODY:
if (0 == n->nchild)
case ROFFT_BODY:
if (n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
"%s empty", man_macronames[n->tok]);
break;
case MAN_HEAD:
if (n->nchild)
case ROFFT_HEAD:
if (n->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, n->line, n->pos,
"%s %s%s", man_macronames[n->tok],
n->child->string,
n->nchild > 1 ? " ..." : "");
n->child->next != NULL ? " ..." : "");
break;
default:
break;
@ -281,12 +283,12 @@ post_IP(CHKARGS)
{
switch (n->type) {
case MAN_BLOCK:
if (0 == n->head->nchild && 0 == n->body->nchild)
man_node_delete(man, n);
case ROFFT_BLOCK:
if (n->head->child == NULL && n->body->child == NULL)
roff_node_delete(man, n);
break;
case MAN_BODY:
if (0 == n->parent->head->nchild && 0 == n->nchild)
case ROFFT_BODY:
if (n->parent->head->child == NULL && n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
"%s empty", man_macronames[n->tok]);
@ -299,21 +301,21 @@ post_IP(CHKARGS)
static void
post_TH(CHKARGS)
{
struct man_node *nb;
struct roff_node *nb;
const char *p;
free(man->meta.title);
free(man->meta.vol);
free(man->meta.source);
free(man->meta.os);
free(man->meta.msec);
free(man->meta.date);
man->meta.title = man->meta.vol = man->meta.date =
man->meta.msec = man->meta.source = NULL;
man->meta.msec = man->meta.os = NULL;
nb = n;
/* ->TITLE<- MSEC DATE SOURCE VOL */
/* ->TITLE<- MSEC DATE OS VOL */
n = n->child;
if (n && n->string) {
@ -335,7 +337,7 @@ post_TH(CHKARGS)
nb->line, nb->pos, "TH");
}
/* TITLE ->MSEC<- DATE SOURCE VOL */
/* TITLE ->MSEC<- DATE OS VOL */
if (n)
n = n->next;
@ -347,7 +349,7 @@ post_TH(CHKARGS)
nb->line, nb->pos, "TH %s", man->meta.title);
}
/* TITLE MSEC ->DATE<- SOURCE VOL */
/* TITLE MSEC ->DATE<- OS VOL */
if (n)
n = n->next;
@ -363,14 +365,14 @@ post_TH(CHKARGS)
n ? n->pos : nb->pos, "TH");
}
/* TITLE MSEC DATE ->SOURCE<- VOL */
/* TITLE MSEC DATE ->OS<- VOL */
if (n && (n = n->next))
man->meta.source = mandoc_strdup(n->string);
man->meta.os = mandoc_strdup(n->string);
else if (man->defos != NULL)
man->meta.source = mandoc_strdup(man->defos);
man->meta.os = mandoc_strdup(man->defos);
/* TITLE MSEC DATE SOURCE ->VOL<- */
/* TITLE MSEC DATE OS ->VOL<- */
/* If missing, use the default VOL name for MSEC. */
if (n && (n = n->next))
@ -387,29 +389,7 @@ post_TH(CHKARGS)
* Remove the `TH' node after we've processed it for our
* meta-data.
*/
man_node_delete(man, man->last);
}
static void
post_nf(CHKARGS)
{
if (man->flags & MAN_LITERAL)
mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
n->line, n->pos, "nf");
man->flags |= MAN_LITERAL;
}
static void
post_fi(CHKARGS)
{
if ( ! (MAN_LITERAL & man->flags))
mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
n->line, n->pos, "fi");
man->flags &= ~MAN_LITERAL;
roff_node_delete(man, man->last);
}
static void
@ -427,7 +407,7 @@ post_UC(CHKARGS)
n = n->child;
if (NULL == n || MAN_TEXT != n->type)
if (n == NULL || n->type != ROFFT_TEXT)
p = bsd_versions[0];
else {
s = n->string;
@ -445,8 +425,8 @@ post_UC(CHKARGS)
p = bsd_versions[0];
}
free(man->meta.source);
man->meta.source = mandoc_strdup(p);
free(man->meta.os);
man->meta.os = mandoc_strdup(p);
}
static void
@ -459,12 +439,12 @@ post_AT(CHKARGS)
"System V Release 2",
};
struct roff_node *nn;
const char *p, *s;
struct man_node *nn;
n = n->child;
if (NULL == n || MAN_TEXT != n->type)
if (n == NULL || n->type != ROFFT_TEXT)
p = unix_versions[0];
else {
s = n->string;
@ -474,7 +454,9 @@ post_AT(CHKARGS)
p = unix_versions[1];
else if (0 == strcmp(s, "5")) {
nn = n->next;
if (nn && MAN_TEXT == nn->type && nn->string[0])
if (nn != NULL &&
nn->type == ROFFT_TEXT &&
nn->string[0] != '\0')
p = unix_versions[3];
else
p = unix_versions[2];
@ -482,8 +464,8 @@ post_AT(CHKARGS)
p = unix_versions[0];
}
free(man->meta.source);
man->meta.source = mandoc_strdup(p);
free(man->meta.os);
man->meta.os = mandoc_strdup(p);
}
static void
@ -495,18 +477,17 @@ post_vs(CHKARGS)
switch (n->parent->tok) {
case MAN_SH:
/* FALLTHROUGH */
case MAN_SS:
mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
"%s after %s", man_macronames[n->tok],
man_macronames[n->parent->tok]);
/* FALLTHROUGH */
case MAN_MAX:
case TOKEN_NONE:
/*
* Don't warn about this because it occurs in pod2man
* and would cause considerable (unfixable) warnage.
*/
man_node_delete(man, n);
roff_node_delete(man, n);
break;
default:
break;

48
manconf.h Normal file
View File

@ -0,0 +1,48 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* List of unique, absolute paths to manual trees. */
struct manpaths {
char **paths;
size_t sz;
};
/* Data from -O options and man.conf(5) output directives. */
struct manoutput {
char *includes;
char *man;
char *paper;
char *style;
size_t indent;
size_t width;
int fragment;
int mdoc;
int synopsisonly;
};
struct manconf {
struct manoutput output;
struct manpaths manpath;
};
void manconf_parse(struct manconf *, const char *, char *, char *);
void manconf_output(struct manoutput *, const char *);
void manconf_free(struct manconf *);

177
mandoc.1
View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.1,v 1.155 2015/02/23 13:31:03 schwarze Exp $
.\" $Id: mandoc.1,v 1.164 2015/11/05 17:47:51 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2012, 2014, 2015 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: February 23 2015 $
.Dd $Mdocdate: November 5 2015 $
.Dt MANDOC 1
.Os
.Sh NAME
@ -24,14 +24,12 @@
.Sh SYNOPSIS
.Nm mandoc
.Op Fl acfhkl
.Sm off
.Op Fl I Cm os Li = Ar name
.Sm on
.Op Fl K Ns Ar encoding
.Op Fl I Cm os Ns = Ns Ar name
.Op Fl K Ar encoding
.Op Fl m Ns Ar format
.Op Fl O Ns Ar option
.Op Fl T Ns Ar output
.Op Fl W Ns Ar level
.Op Fl O Ar option
.Op Fl T Ar output
.Op Fl W Ar level
.Op Ar
.Sh DESCRIPTION
The
@ -49,7 +47,7 @@ or
text from stdin, implying
.Fl m Ns Cm andoc ,
and produces
.Fl T Ns Cm locale
.Fl T Cm locale
output.
.Pp
The options are as follows:
@ -77,9 +75,7 @@ This overrides any earlier
and
.Fl l
options.
.Sm off
.It Fl I Cm os Li = Ar name
.Sm on
.It Fl I Cm os Ns = Ns Ar name
Override the default operating system
.Ar name
for the
@ -93,7 +89,7 @@ macro.
Display only the SYNOPSIS lines.
Implies
.Fl c .
.It Fl K Ns Ar encoding
.It Fl K Ar encoding
Specify the input encoding.
The supported
.Ar encoding
@ -141,16 +137,16 @@ See
for available formats.
Defaults to
.Fl m Ns Cm andoc .
.It Fl O Ns Ar option
.It Fl O Ar option
Comma-separated output options.
.It Fl T Ns Ar output
.It Fl T Ar output
Output format.
See
.Sx Output Formats
for available formats.
Defaults to
.Fl T Ns Cm locale .
.It Fl W Ns Ar level
.Fl T Cm locale .
.It Fl W Ar level
Specify the minimum message
.Ar level
to be reported on the standard error output and to affect the exit status.
@ -174,7 +170,7 @@ and
for details.
.Pp
The special option
.Fl W Ns Cm stop
.Fl W Cm stop
tells
.Nm
to exit after parsing a file that causes warnings or errors of at least
@ -185,7 +181,7 @@ If both a
and
.Cm stop
are requested, they can be joined with a comma, for example
.Fl W Ns Cm error , Ns Cm stop .
.Fl W Cm error , Ns Cm stop .
.It Ar file
Read input from zero or more files.
If unspecified, reads from stdin.
@ -254,54 +250,56 @@ The
utility accepts the following
.Fl T
arguments, which correspond to output modes:
.Bl -tag -width "-Tlocale"
.It Fl T Ns Cm ascii
.Bl -tag -width "-T locale"
.It Fl T Cm ascii
Produce 7-bit ASCII output.
See
.Sx ASCII Output .
.It Fl T Ns Cm html
.It Fl T Cm html
Produce HTML5, CSS1, and MathML output.
See
.Sx HTML Output .
.It Fl T Ns Cm lint
.It Fl T Cm lint
Parse only: produce no output.
Implies
.Fl W Ns Cm warning .
.It Fl T Ns Cm locale
.Fl W Cm warning .
.It Fl T Cm locale
Encode output using the current locale.
This is the default.
See
.Sx Locale Output .
.It Fl T Ns Cm man
.It Fl T Cm man
Produce
.Xr man 7
format output.
See
.Sx Man Output .
.It Fl T Ns Cm pdf
.It Fl T Cm pdf
Produce PDF output.
See
.Sx PDF Output .
.It Fl T Ns Cm ps
.It Fl T Cm ps
Produce PostScript output.
See
.Sx PostScript Output .
.It Fl T Ns Cm tree
.It Fl T Cm tree
Produce an indented parse tree.
.It Fl T Ns Cm utf8
See
.Sx Syntax tree output .
.It Fl T Cm utf8
Encode output in the UTF\-8 multi-byte format.
See
.Sx UTF\-8 Output .
.It Fl T Ns Cm xhtml
.It Fl T Cm xhtml
This is a synonym for
.Fl T Ns Cm html .
.Fl T Cm html .
.El
.Pp
If multiple input files are specified, these will be processed by the
corresponding filter in-order.
.Ss ASCII Output
Output produced by
.Fl T Ns Cm ascii
.Fl T Cm ascii
is rendered in standard 7-bit ASCII documented in
.Xr ascii 7 .
.Pp
@ -343,7 +341,7 @@ which will normalise to \(>=58.
.El
.Ss HTML Output
Output produced by
.Fl T Ns Cm html
.Fl T Cm html
conforms to HTML5 using optional self-closing tags.
Default styles use only CSS1.
Equations rendered from
@ -351,11 +349,11 @@ Equations rendered from
blocks use MathML.
.Pp
The
.Pa example.style.css
.Pa mandoc.css
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
.Fl O Cm style ,
.Fl T Cm html
defaults to simple output (via an embedded style-sheet)
readable in any graphical or text-based web
browser.
@ -411,13 +409,13 @@ relative URI.
.El
.Ss Locale Output
Locale-depending output encoding is triggered with
.Fl T Ns Cm locale .
.Fl T Cm locale .
This is the default.
.Pp
This option is not available on all systems: systems without locale
support, or those whose internal representation is not natively UCS-4,
will fall back to
.Fl T Ns Cm ascii .
.Fl T Cm ascii .
See
.Sx ASCII Output
for font style specification and available command-line arguments.
@ -447,7 +445,7 @@ level controls which
are displayed before copying the input to the output.
.Ss PDF Output
PDF-1.1 output may be generated by
.Fl T Ns Cm pdf .
.Fl T Cm pdf .
See
.Sx PostScript Output
for
@ -457,7 +455,7 @@ arguments and defaults.
PostScript
.Qq Adobe-3.0
Level-2 pages may be generated by
.Fl T Ns Cm ps .
.Fl T Cm ps .
Output pages default to letter sized and are rendered in the Times font
family, 11-point.
Margins are calculated as 1/9 the page length and width.
@ -489,11 +487,50 @@ is used.
.El
.Ss UTF\-8 Output
Use
.Fl T Ns Cm utf8
.Fl T Cm utf8
to force a UTF\-8 locale.
See
.Sx Locale Output
for details and options.
.Ss Syntax tree output
Use
.Fl T Cm tree
to show a human readable representation of the syntax tree.
It is useful for debugging the source code of manual pages.
The exact format is subject to change, so don't write parsers for it.
Each output line shows one syntax tree node.
Child nodes are indented with respect to their parent node.
The columns are:
.Pp
.Bl -enum -compact
.It
For macro nodes, the macro name; for text and
.Xr tbl 7
nodes, the content.
There is a special format for
.Xr eqn 7
nodes.
.It
Node type (text, elem, block, head, body, body-end, tail, tbl, eqn).
.It
Flags:
.Bl -dash -compact
.It
An opening parenthesis if the node is an opening delimiter.
.It
An asterisk if the node starts a new input line.
.It
The input line number (starting at one).
.It
A colon.
.It
The input column number (starting at one).
.It
A closing parenthesis if the node is a closing delimiter.
.It
A full stop if the node ends a sentence.
.El
.El
.Sh ENVIRONMENT
.Bl -tag -width MANPAGER
.It Ev MANPAGER
@ -506,7 +543,8 @@ 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
.Xr more 1
.Fl s
will be used.
.El
.Sh EXIT STATUS
@ -525,21 +563,21 @@ they were lower than the requested
.Ar level .
.It 2
At least one warning occurred, but no error, and
.Fl W Ns Cm warning
.Fl W Cm warning
was specified.
.It 3
At least one parsing error occurred,
but no unsupported feature was encountered, and
.Fl W Ns Cm error
.Fl W Cm error
or
.Fl W Ns Cm warning
.Fl W Cm warning
was specified.
.It 4
At least one unsupported feature was encountered, and
.Fl W Ns Cm unsupp ,
.Fl W Ns Cm error
.Fl W Cm unsupp ,
.Fl W Cm error
or
.Fl W Ns Cm warning
.Fl W Cm warning
was specified.
.It 5
Invalid command line arguments were specified.
@ -553,28 +591,28 @@ to exit at once, possibly in the middle of parsing or formatting a file.
.El
.Pp
Note that selecting
.Fl T Ns Cm lint
.Fl T Cm lint
output mode implies
.Fl W Ns Cm warning .
.Fl W Cm warning .
.Sh EXAMPLES
To page manuals to the terminal:
.Pp
.Dl $ mandoc \-Wall,stop mandoc.1 2\*(Gt&1 | less
.Dl $ mandoc \-W all,stop mandoc.1 2\*(Gt&1 | less
.Dl $ mandoc mandoc.1 mdoc.3 mdoc.7 | less
.Pp
To produce HTML manuals with
.Ar style.css
.Pa mandoc.css
as the style-sheet:
.Pp
.Dl $ mandoc \-Thtml -Ostyle=style.css mdoc.7 \*(Gt mdoc.7.html
.Dl $ mandoc \-T html -O style=mandoc.css mdoc.7 \*(Gt mdoc.7.html
.Pp
To check over a large set of manuals:
.Pp
.Dl $ mandoc \-Tlint `find /usr/src -name \e*\e.[1-9]`
.Dl $ mandoc \-T lint \(gafind /usr/src -name \e*\e.[1-9]\(ga
.Pp
To produce a series of PostScript manuals for A4 paper:
.Pp
.Dl $ mandoc \-Tps \-Opaper=a4 mdoc.7 man.7 \*(Gt manuals.ps
.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 \*(Gt manuals.ps
.Pp
Convert a modern
.Xr mdoc 7
@ -584,7 +622,7 @@ format, for use on systems lacking an
.Xr mdoc 7
parser:
.Pp
.Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man
.Dl $ mandoc \-T man foo.mdoc \*(Gt foo.man
.Sh DIAGNOSTICS
Messages displayed by
.Nm
@ -651,7 +689,7 @@ levels except those about non-existent or unreadable input files
are hidden unless their level, or a lower level, is requested using a
.Fl W
option or
.Fl T Ns Cm lint
.Fl T Cm lint
output mode.
.Ss Warnings related to the document prologue
.Bl -ohang
@ -817,7 +855,7 @@ In the SEE ALSO section, an
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.
macros referring to the same section are out of alphabetical order.
.It Sy "unusual Xr punctuation"
.Pq mdoc
In the SEE ALSO section, punctuation between two
@ -937,13 +975,6 @@ list block contains text or macros before the first
.Ic \&It
macro.
The offending children are moved before the beginning of the list.
.It Sy ".Vt block has child macro"
.Pq mdoc
The
.Ic \&Vt
macro supports plain text arguments only.
Formatting may be ugly and semantic searching
for the affected content might not work.
.It Sy "fill mode already enabled, skipping"
.Pq man
A
@ -1569,6 +1600,13 @@ 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 "skipping display without arguments"
.Pq mdoc
A
.Ic \&Bd
block macro does not have any arguments.
The block is discarded, and the block content is displayed in
whatever mode was active before the block.
.It Sy "missing list type, using -item"
.Pq mdoc
A
@ -1767,6 +1805,7 @@ as if they were a text line.
.Xr roff 7 ,
.Xr tbl 7
.Sh AUTHORS
.An -nosplit
The
.Nm
utility was written by
@ -1775,10 +1814,10 @@ and is maintained by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
.Sh BUGS
In
.Fl T Ns Cm html ,
.Fl T Cm html ,
the maximum size of an element attribute is determined by
.Dv BUFSIZ ,
which is usually 1024 bytes.
Be aware of this when setting long link
formats such as
.Fl O Ns Cm style Ns = Ns Ar really/long/link .
.Fl O Cm style Ns = Ns Ar really/long/link .

View File

@ -1,7 +1,7 @@
.\" $Id: mandoc.3,v 1.31 2015/01/15 04:26:40 schwarze Exp $
.\" $Id: mandoc.3,v 1.36 2016/01/08 17:48:09 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 15 2015 $
.Dd $Mdocdate: January 8 2016 $
.Dt MANDOC 3
.Os
.Sh NAME
@ -37,7 +37,6 @@
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel
.Nm mparse_wait ,
.Nd mandoc macro compiler library
.Sh SYNOPSIS
.In sys/types.h
@ -51,7 +50,6 @@
.Fa "int options"
.Fa "enum mandoclevel wlevel"
.Fa "mandocmsg mmsg"
.Fa "const struct mchars *mchars"
.Fa "char *defos"
.Fc
.Ft void
@ -75,10 +73,9 @@
.Fo mparse_keep
.Fa "struct mparse *parse"
.Fc
.Ft "enum mandoclevel"
.Ft int
.Fo mparse_open
.Fa "struct mparse *parse"
.Fa "int *fd"
.Fa "const char *fname"
.Fc
.Ft "enum mandoclevel"
@ -106,10 +103,6 @@
.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
@ -183,6 +176,9 @@ or
parse it with
.Fn mparse_readfd ;
.It
close it with
.Xr close 2 ;
.It
retrieve the syntax tree with
.Fn mparse_result ;
.It
@ -215,12 +211,6 @@ An 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
@ -345,9 +335,6 @@ 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
@ -392,23 +379,15 @@ Declared in
implemented in
.Pa read.c .
.It Fn mparse_open
If the
Open the file for reading.
If that fails and
.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.
does not already end in
.Ql .gz ,
try again after appending
.Ql .gz .
Save the information whether the file is zipped or not.
Return a file descriptor open for reading or -1 on failure.
It can be passed to
.Fn mparse_readfd
or used directly.
@ -423,10 +402,9 @@ or
.Fn mparse_open .
Pass the associated filename in
.Va fname .
Calls
.Fn mparse_wait
before returning.
This function may be called multiple times with different parameters; however,
.Xr close 2
and
.Fn mparse_reset
should be invoked between parses.
Declared in
@ -460,28 +438,6 @@ 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
@ -601,7 +557,7 @@ and
fields), its position in the tree (the
.Va parent ,
.Va child ,
.Va nchild ,
.Va last ,
.Va next
and
.Va prev

133
mandoc.c
View File

@ -1,4 +1,4 @@
/* $Id: mandoc.c,v 1.92 2015/02/20 23:55:10 schwarze Exp $ */
/* $Id: mandoc.c,v 1.98 2015/11/12 22:44:27 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -32,8 +32,6 @@
#include "mandoc_aux.h"
#include "libmandoc.h"
#define DATESIZE 32
static int a2time(time_t *, const char *, const char *);
static char *time2a(time_t);
@ -83,7 +81,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
case 'C':
if ('\'' != **start)
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
*start = ++*end;
gly = ESCAPE_SPECIAL;
term = '\'';
@ -93,9 +91,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
* Escapes taking no arguments at all.
*/
case 'd':
/* FALLTHROUGH */
case 'u':
return(ESCAPE_IGNORE);
case ',':
case '/':
return ESCAPE_IGNORE;
/*
* The \z escape is supposed to output the following
@ -104,26 +103,19 @@ mandoc_escape(const char **end, const char **start, int *sz)
* let us just skip the next character.
*/
case 'z':
return(ESCAPE_SKIPCHAR);
return ESCAPE_SKIPCHAR;
/*
* Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
* 'X' is the trigger. These have opaque sub-strings.
*/
case 'F':
/* FALLTHROUGH */
case 'g':
/* FALLTHROUGH */
case 'k':
/* FALLTHROUGH */
case 'M':
/* FALLTHROUGH */
case 'm':
/* FALLTHROUGH */
case 'n':
/* FALLTHROUGH */
case 'V':
/* FALLTHROUGH */
case 'Y':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
@ -151,21 +143,16 @@ mandoc_escape(const char **end, const char **start, int *sz)
* The \B and \w escapes are handled in roff.c, roff_res().
*/
case 'A':
/* FALLTHROUGH */
case 'b':
/* FALLTHROUGH */
case 'D':
/* FALLTHROUGH */
case 'R':
/* FALLTHROUGH */
case 'X':
/* FALLTHROUGH */
case 'Z':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
case 'o':
if (**start == '\0')
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
if (gly == ESCAPE_ERROR)
gly = ESCAPE_OVERSTRIKE;
term = **start;
@ -177,22 +164,16 @@ mandoc_escape(const char **end, const char **start, int *sz)
* and 'N' resolves to a numerical expression.
*/
case 'h':
/* FALLTHROUGH */
case 'H':
/* FALLTHROUGH */
case 'L':
/* FALLTHROUGH */
case 'l':
/* FALLTHROUGH */
case 'S':
/* FALLTHROUGH */
case 'v':
/* FALLTHROUGH */
case 'x':
if (strchr(" %&()*+-./0123456789:<=>", **start)) {
if ('\0' != **start)
++*end;
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
}
gly = ESCAPE_IGNORE;
term = **start;
@ -205,11 +186,11 @@ mandoc_escape(const char **end, const char **start, int *sz)
*/
case 'N':
if ('\0' == **start)
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
(*end)++;
if (isdigit((unsigned char)**start)) {
*sz = 1;
return(ESCAPE_IGNORE);
return ESCAPE_IGNORE;
}
(*start)++;
while (isdigit((unsigned char)**end))
@ -217,7 +198,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
*sz = *end - *start;
if ('\0' != **end)
(*end)++;
return(ESCAPE_NUMBERED);
return ESCAPE_NUMBERED;
/*
* Sizes get a special category of their own.
@ -243,9 +224,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
term = '\'';
break;
case '3':
/* FALLTHROUGH */
case '2':
/* FALLTHROUGH */
case '1':
*sz = (*end)[-1] == 's' &&
isdigit((unsigned char)(*end)[1]) ? 2 : 1;
@ -279,12 +258,12 @@ mandoc_escape(const char **end, const char **start, int *sz)
while (**end != term) {
switch (**end) {
case '\0':
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
case '\\':
(*end)++;
if (ESCAPE_ERROR ==
mandoc_escape(end, NULL, NULL))
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
break;
default:
(*end)++;
@ -295,7 +274,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
} else {
assert(*sz > 0);
if ((size_t)*sz > strlen(*start))
return(ESCAPE_ERROR);
return ESCAPE_ERROR;
*end += *sz;
}
@ -321,12 +300,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
switch (**start) {
case '3':
/* FALLTHROUGH */
case 'B':
gly = ESCAPE_FONTBOLD;
break;
case '2':
/* FALLTHROUGH */
case 'I':
gly = ESCAPE_FONTITALIC;
break;
@ -334,7 +311,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
gly = ESCAPE_FONTPREV;
break;
case '1':
/* FALLTHROUGH */
case 'R':
gly = ESCAPE_FONTROMAN;
break;
@ -355,6 +331,9 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
if (*sz == 6 && (*start)[1] == '0')
break;
if (*sz == 5 && (*start)[1] == 'D' &&
strchr("89ABCDEF", (*start)[2]) != NULL)
break;
if ((int)strspn(*start + 1, "0123456789ABCDEFabcdef")
+ 1 == *sz)
gly = ESCAPE_UNICODE;
@ -363,7 +342,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
}
return(gly);
return gly;
}
/*
@ -458,7 +437,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
if ('\0' == *cp && (white || ' ' == cp[-1]))
mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL);
return(start);
return start;
}
static int
@ -475,10 +454,10 @@ a2time(time_t *t, const char *fmt, const char *p)
#endif
if (NULL != pp && '\0' == *pp) {
*t = mktime(&tm);
return(1);
return 1;
}
return(0);
return 0;
}
static char *
@ -491,7 +470,7 @@ time2a(time_t t)
tm = localtime(&t);
if (tm == NULL)
return(NULL);
return NULL;
/*
* Reserve space:
@ -499,45 +478,61 @@ time2a(time_t t)
* up to 2 characters for the day + comma + blank
* 4 characters for the year and a terminating '\0'
*/
p = buf = mandoc_malloc(10 + 4 + 4 + 1);
if (0 == (ssz = strftime(p, 10 + 1, "%B ", tm)))
if ((ssz = strftime(p, 10 + 1, "%B ", tm)) == 0)
goto fail;
p += (int)ssz;
if (-1 == (isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday)))
/*
* The output format is just "%d" here, not "%2d" or "%02d".
* That's also the reason why we can't just format the
* date as a whole with "%B %e, %Y" or "%B %d, %Y".
* Besides, the present approach is less prone to buffer
* overflows, in case anybody should ever introduce the bug
* of looking at LC_TIME.
*/
if ((isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday)) == -1)
goto fail;
p += isz;
if (0 == strftime(p, 4 + 1, "%Y", tm))
if (strftime(p, 4 + 1, "%Y", tm) == 0)
goto fail;
return(buf);
return buf;
fail:
free(buf);
return(NULL);
return NULL;
}
char *
mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
{
char *out;
time_t t;
if (NULL == in || '\0' == *in ||
0 == strcmp(in, "$" "Mdocdate$")) {
/* No date specified: use today's date. */
if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) {
mandoc_msg(MANDOCERR_DATE_MISSING, parse, ln, pos, NULL);
time(&t);
return time2a(time(NULL));
}
else if (a2time(&t, "%Y-%m-%d", in))
t = 0;
else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) &&
!a2time(&t, "%b %d, %Y", in)) {
/* Valid mdoc(7) date format. */
if (a2time(&t, "$" "Mdocdate: %b %d %Y $", in) ||
a2time(&t, "%b %d, %Y", in))
return time2a(t);
/* Do not warn about the legacy man(7) format. */
if ( ! a2time(&t, "%Y-%m-%d", in))
mandoc_msg(MANDOCERR_DATE_BAD, parse, ln, pos, in);
t = 0;
}
out = t ? time2a(t) : NULL;
return(out ? out : mandoc_strdup(in));
/* Use any non-mdoc(7) date verbatim. */
return mandoc_strdup(in);
}
int
@ -547,7 +542,7 @@ mandoc_eos(const char *p, size_t sz)
int enclosed, found;
if (0 == sz)
return(0);
return 0;
/*
* End-of-sentence recognition must include situations where
@ -559,28 +554,24 @@ mandoc_eos(const char *p, size_t sz)
for (q = p + (int)sz - 1; q >= p; q--) {
switch (*q) {
case '\"':
/* FALLTHROUGH */
case '\'':
/* FALLTHROUGH */
case ']':
/* FALLTHROUGH */
case ')':
if (0 == found)
enclosed = 1;
break;
case '.':
/* FALLTHROUGH */
case '!':
/* FALLTHROUGH */
case '?':
found = 1;
break;
default:
return(found && (!enclosed || isalnum((unsigned char)*q)));
return found &&
(!enclosed || isalnum((unsigned char)*q));
}
}
return(found && !enclosed);
return found && !enclosed;
}
/*
@ -595,7 +586,7 @@ mandoc_strntoi(const char *p, size_t sz, int base)
long v;
if (sz > 31)
return(-1);
return -1;
memcpy(buf, p, sz);
buf[(int)sz] = '\0';
@ -604,12 +595,12 @@ mandoc_strntoi(const char *p, size_t sz, int base)
v = strtol(buf, &ep, base);
if (buf[0] == '\0' || *ep != '\0')
return(-1);
return -1;
if (v > INT_MAX)
v = INT_MAX;
if (v < INT_MIN)
v = INT_MIN;
return((int)v);
return (int)v;
}

View File

@ -1,4 +1,4 @@
/* $Id: style.css,v 1.31 2015/02/10 08:05:30 schwarze Exp $ */
/* $Id: mandoc.css,v 1.1 2015/11/05 17:47:51 schwarze Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
@ -11,6 +11,19 @@
html { max-width: 880px; margin-left: 1em; }
body { font-size: smaller; font-family: Helvetica,Arial,sans-serif; }
body > div { padding-left: 2em;
padding-top: 1em; }
body > div.mandoc,
body > div#mancgi { padding-left: 0em;
padding-top: 0em; }
body > div.results { font-size: smaller; }
#mancgi fieldset { text-align: center;
border: thin solid silver;
border-radius: 1em;
font-size: small; }
#mancgi input[name=expr] { width: 25%; }
.results td.title { vertical-align: top;
padding-right: 1em; }
h1 { margin-bottom: 1ex; font-size: 110%; margin-left: -4ex; } /* Section header (Sh, SH). */
h2 { margin-bottom: 1ex; font-size: 105%; margin-left: -2ex; } /* Sub-section header (Ss, SS). */
table { width: 100%; margin-top: 0ex; margin-bottom: 0ex; } /* All tables. */

View File

@ -1,15 +1,15 @@
/* $Id: mandoc.h,v 1.201 2015/02/23 13:31:04 schwarze Exp $ */
/* $Id: mandoc.h,v 1.209 2016/01/08 02:53:13 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -86,7 +86,6 @@ enum mandocerr {
MANDOCERR_BLK_NEST, /* blocks badly nested: macro ... */
MANDOCERR_BD_NEST, /* nested displays are not portable: macro ... */
MANDOCERR_BL_MOVE, /* moving content out of list: macro */
MANDOCERR_VT_CHILD, /* .Vt block has child macro: macro */
MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
@ -173,6 +172,7 @@ enum mandocerr {
/* related to request and macro arguments */
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
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 */
@ -408,37 +408,28 @@ enum mandoc_esc {
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
__BEGIN_DECLS
struct mparse;
struct mchars;
struct mdoc;
struct man;
struct roff_man;
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
struct mchars *mchars_alloc(void);
void mchars_free(struct mchars *);
void mchars_alloc(void);
void mchars_free(void);
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 struct mchars *, const char *);
int mchars_spec2cp(const char *, size_t);
const char *mchars_spec2str(const char *, size_t, size_t *);
struct mparse *mparse_alloc(int, enum mandoclevel, mandocmsg, const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
enum mandoclevel mparse_open(struct mparse *, int *, const char *);
int mparse_open(struct mparse *, const char *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
enum mandoclevel mparse_readmem(struct mparse *, void *, size_t,
const char *);
void mparse_reset(struct mparse *);
void mparse_result(struct mparse *,
struct mdoc **, struct man **, char **);
struct roff_man **, char **);
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.4 2014/08/10 23:54:41 schwarze Exp $ */
/* $Id: mandoc_aux.c,v 1.9 2015/11/07 14:22:29 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@ -19,6 +19,9 @@
#include <sys/types.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@ -27,6 +30,7 @@
#include "mandoc.h"
#include "mandoc_aux.h"
int
mandoc_asprintf(char **dest, const char *fmt, ...)
{
@ -37,11 +41,9 @@ mandoc_asprintf(char **dest, const char *fmt, ...)
ret = vasprintf(dest, fmt, ap);
va_end(ap);
if (-1 == ret) {
perror(NULL);
exit((int)MANDOCLEVEL_SYSERR);
}
return(ret);
if (ret == -1)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ret;
}
void *
@ -50,11 +52,9 @@ mandoc_calloc(size_t num, size_t size)
void *ptr;
ptr = calloc(num, size);
if (NULL == ptr) {
perror(NULL);
exit((int)MANDOCLEVEL_SYSERR);
}
return(ptr);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
@ -63,11 +63,9 @@ mandoc_malloc(size_t size)
void *ptr;
ptr = malloc(size);
if (NULL == ptr) {
perror(NULL);
exit((int)MANDOCLEVEL_SYSERR);
}
return(ptr);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
@ -75,11 +73,9 @@ mandoc_realloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
if (NULL == ptr) {
perror(NULL);
exit((int)MANDOCLEVEL_SYSERR);
}
return(ptr);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
@ -87,11 +83,9 @@ mandoc_reallocarray(void *ptr, size_t num, size_t size)
{
ptr = reallocarray(ptr, num, size);
if (NULL == ptr) {
perror(NULL);
exit((int)MANDOCLEVEL_SYSERR);
}
return(ptr);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
char *
@ -100,11 +94,9 @@ mandoc_strdup(const char *ptr)
char *p;
p = strdup(ptr);
if (NULL == p) {
perror(NULL);
exit((int)MANDOCLEVEL_SYSERR);
}
return(p);
if (p == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return p;
}
char *
@ -115,5 +107,5 @@ mandoc_strndup(const char *ptr, size_t sz)
p = mandoc_malloc(sz + 1);
memcpy(p, ptr, sz);
p[(int)sz] = '\0';
return(p);
return p;
}

View File

@ -1,4 +1,4 @@
/* $Id: mandoc_aux.h,v 1.3 2014/12/01 04:05:32 schwarze Exp $ */
/* $Id: mandoc_aux.h,v 1.4 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@ -16,8 +16,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
__BEGIN_DECLS
int mandoc_asprintf(char **, const char *, ...);
void *mandoc_calloc(size_t, size_t);
void *mandoc_malloc(size_t);
@ -25,5 +23,3 @@ void *mandoc_realloc(void *, size_t);
void *mandoc_reallocarray(void *, size_t, size_t);
char *mandoc_strdup(const char *);
char *mandoc_strndup(const char *, size_t);
__END_DECLS

View File

@ -1,8 +1,8 @@
.\" $Id: mandoc_char.7,v 1.59 2015/01/20 19:39:34 schwarze Exp $
.\" $Id: mandoc_char.7,v 1.63 2015/09/02 15:38:35 schwarze Exp $
.\"
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2011, 2013, 2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 20 2015 $
.Dd $Mdocdate: September 2 2015 $
.Dt MANDOC_CHAR 7
.Os
.Sh NAME
@ -49,7 +49,7 @@ names; instead, provide ASCII transcriptions of the names.
.Ss Dashes and Hyphens
In typography there are different types of dashes of various width:
the hyphen (-),
the minus sign (\-),
the minus sign (\(mi),
the en-dash (\(en),
and the em-dash (\(em).
.Pp
@ -64,10 +64,10 @@ lorry-driver
.Pp
The mathematical minus sign is used for negative numbers or subtraction.
It should be written as
.Sq \e- :
.Sq \e(mi :
.Bd -unfilled -offset indent
a = 3 \e- 1;
b = \e-2;
a = 3 \e(mi 1;
b = \e(mi2;
.Ed
.Pp
The en-dash is used to separate the two elements of a range,
@ -142,6 +142,28 @@ Note that on text lines, literal double-quote characters can be used
verbatim.
All other quote-like characters can be used verbatim as well,
even on request and macro lines.
.Ss Accents
In output modes supporting such special output characters, for example
.Fl T Cm pdf ,
some
.Xr roff 7
formatters convert the following ASCII input characters to the
following Unicode special output characters:
.Bl -column x(ga U+2018 -offset indent
.It \(ga Ta U+2018 Ta left single quotation mark
.It \(aq Ta U+2019 Ta right single quotation mark
.It \(ti Ta U+02DC Ta small tilde
.El
.Pp
In prose, this automatic substitution is often desirable;
but when these characters have to be displayed as plain ASCII
characters, for example in source code samples, they require
escaping to render as follows:
.Bl -column x(ga U+2018 -offset indent
.It \e(ga Ta U+0060 Ta grave accent
.It \e(aq Ta U+0027 Ta apostrophe
.It \e(ti Ta U+007E Ta tilde
.El
.Ss Periods
The period
.Pq Sq \&.
@ -196,7 +218,7 @@ Spacing:
.Bl -column "Input" "Description" -offset indent -compact
.It Em Input Ta Em Description
.It Sq \e\ \& Ta unpaddable non-breaking space
.It \e~ Ta paddable non-breaking space
.It \e\(ti Ta paddable non-breaking space
.It \e0 Ta unpaddable, breaking digit-width space
.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode
.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff
@ -371,9 +393,9 @@ Mathematical:
.It \e(ne Ta \(ne Ta not equivalent
.It \e(ap Ta \(ap Ta tilde operator
.It \e(|= Ta \(|= Ta asymptotically equal
.It \e(=~ Ta \(=~ Ta approximately equal
.It \e(~~ Ta \(~~ Ta almost equal
.It \e(~= Ta \(~= Ta almost equal
.It \e(=\(ti Ta \(=~ Ta approximately equal
.It \e(\(ti\(ti Ta \(~~ Ta almost equal
.It \e(\(ti= Ta \(~= Ta almost equal
.It \e(pt Ta \(pt Ta proportionate
.It \e(es Ta \(es Ta empty set
.It \e(mo Ta \(mo Ta element
@ -436,15 +458,15 @@ Accents:
.It \e(a. Ta \(a. Ta dotted
.It \e(a^ Ta \(a^ Ta circumflex
.It \e(aa Ta \(aa Ta acute
.It \e' Ta \' Ta acute
.It \e\(aq Ta \' Ta acute
.It \e(ga Ta \(ga Ta grave
.It \e` Ta \` Ta grave
.It \e\(ga Ta \` Ta grave
.It \e(ab Ta \(ab Ta breve
.It \e(ac Ta \(ac Ta cedilla
.It \e(ad Ta \(ad Ta dieresis
.It \e(ah Ta \(ah Ta caron
.It \e(ao Ta \(ao Ta ring
.It \e(a~ Ta \(a~ Ta tilde
.It \e(a\(ti Ta \(a~ Ta tilde
.It \e(ho Ta \(ho Ta ogonek
.It \e(ha Ta \(ha Ta hat (text)
.It \e(ti Ta \(ti Ta tilde (text)
@ -453,32 +475,32 @@ Accents:
Accented letters:
.Bl -column "Input" "Rendered" "Description" -offset indent -compact
.It Em Input Ta Em Rendered Ta Em Description
.It \e('A Ta \('A Ta acute A
.It \e('E Ta \('E Ta acute E
.It \e('I Ta \('I Ta acute I
.It \e('O Ta \('O Ta acute O
.It \e('U Ta \('U Ta acute U
.It \e('a Ta \('a Ta acute a
.It \e('e Ta \('e Ta acute e
.It \e('i Ta \('i Ta acute i
.It \e('o Ta \('o Ta acute o
.It \e('u Ta \('u Ta acute u
.It \e(`A Ta \(`A Ta grave A
.It \e(`E Ta \(`E Ta grave E
.It \e(`I Ta \(`I Ta grave I
.It \e(`O Ta \(`O Ta grave O
.It \e(`U Ta \(`U Ta grave U
.It \e(`a Ta \(`a Ta grave a
.It \e(`e Ta \(`e Ta grave e
.It \e(`i Ta \(`i Ta grave i
.It \e(`o Ta \(`i Ta grave o
.It \e(`u Ta \(`u Ta grave u
.It \e(~A Ta \(~A Ta tilde A
.It \e(~N Ta \(~N Ta tilde N
.It \e(~O Ta \(~O Ta tilde O
.It \e(~a Ta \(~a Ta tilde a
.It \e(~n Ta \(~n Ta tilde n
.It \e(~o Ta \(~o Ta tilde o
.It \e(\(aqA Ta \('A Ta acute A
.It \e(\(aqE Ta \('E Ta acute E
.It \e(\(aqI Ta \('I Ta acute I
.It \e(\(aqO Ta \('O Ta acute O
.It \e(\(aqU Ta \('U Ta acute U
.It \e(\(aqa Ta \('a Ta acute a
.It \e(\(aqe Ta \('e Ta acute e
.It \e(\(aqi Ta \('i Ta acute i
.It \e(\(aqo Ta \('o Ta acute o
.It \e(\(aqu Ta \('u Ta acute u
.It \e(\(gaA Ta \(`A Ta grave A
.It \e(\(gaE Ta \(`E Ta grave E
.It \e(\(gaI Ta \(`I Ta grave I
.It \e(\(gaO Ta \(`O Ta grave O
.It \e(\(gaU Ta \(`U Ta grave U
.It \e(\(gaa Ta \(`a Ta grave a
.It \e(\(gae Ta \(`e Ta grave e
.It \e(\(gai Ta \(`i Ta grave i
.It \e(\(gao Ta \(`i Ta grave o
.It \e(\(gau Ta \(`u Ta grave u
.It \e(\(tiA Ta \(~A Ta tilde A
.It \e(\(tiN Ta \(~N Ta tilde N
.It \e(\(tiO Ta \(~O Ta tilde O
.It \e(\(tia Ta \(~a Ta tilde a
.It \e(\(tin Ta \(~n Ta tilde n
.It \e(\(tio Ta \(~o Ta tilde o
.It \e(:A Ta \(:A Ta dieresis A
.It \e(:E Ta \(:E Ta dieresis E
.It \e(:I Ta \(:I Ta dieresis I
@ -657,7 +679,7 @@ manual.
.Sh UNICODE CHARACTERS
The escape sequences
.Pp
.Dl \e[uXXXX] and \eC'uXXXX'
.Dl \e[uXXXX] and \eC\(aquXXXX\(aq
.Pp
are interpreted as Unicode codepoints.
The codepoint must be in the range above U+0080 and less than U+10FFFF.
@ -669,10 +691,6 @@ must be given as uppercase characters,
and points must be zero-padded to four characters; if
greater than four characters, no zero padding is allowed.
Unicode surrogates are not allowed.
.\" .Pp
.\" Unicode glyphs attenuate to the
.\" .Sq \&?
.\" character if invalid or not rendered by current output media.
.Sh NUMBERED CHARACTERS
For backward compatibility with existing manuals,
.Xr mandoc 1
@ -685,7 +703,7 @@ escape sequence, inserting the character
from the current character set into the output.
Of course, this is inherently non-portable and is already marked
as deprecated in the Heirloom roff manual.
For example, do not use \eN'34', use \e(dq, or even the plain
For example, do not use \eN\(aq34\(aq, use \e(dq, or even the plain
.Sq \(dq
character where possible.
.Sh COMPATIBILITY
@ -702,14 +720,14 @@ In
.Fl T Ns Cm ascii ,
the
\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product],
\e[coproduct], \e(gr, \e(\-h, and \e(a. special characters render
\e[coproduct], \e(gr, \e(-h, and \e(a. special characters render
differently between mandoc and groff.
.It
In
.Fl T Ns Cm html
and
.Fl T Ns Cm xhtml ,
the \e(~=, \e(nb, and \e(nc special characters render differently
the \e(\(ti=, \e(nb, and \e(nc special characters render differently
between mandoc and groff.
.It
The

View File

@ -54,7 +54,6 @@ require inclusion of the header where that type is defined.
Each of the following headers can be included without including
any other mandoc header.
These headers should be included before any other mandoc headers.
Afterwards, any other mandoc headers can be included as needed.
.Bl -tag -width Ds
.It Qq Pa mandoc_aux.h
Requires
@ -99,14 +98,10 @@ and the functions
described in
.Xr mandoc 3 .
.Pp
Uses the opaque types
Uses the opaque type
.Vt struct mparse
from
.Pa read.c
and
.Vt struct mchars
from
.Pa chars.c
for function prototypes.
Uses the types
.Vt struct mdoc
@ -117,23 +112,45 @@ and
from
.Pa libman.h
as opaque types for function prototypes.
.It Qq Pa roff.h
Provides
.Vt enum mdoc_endbody ,
.Vt enum roff_sec ,
.Vt enum roff_type ,
.Vt struct roff_meta ,
and
.Vt struct roff_node .
.Pp
Uses pointers to the types
.Vt struct mdoc_arg
and
.Vt union mdoc_data
from
.Qq Pa mdoc.h
as opaque struct members.
.El
.Pp
The following two require
.Qq Pa roff.h
but no other mandoc headers.
Afterwards, any other mandoc headers can be included as needed.
.Bl -tag -width Ds
.It Qq Pa mdoc.h
Requires
.In sys/types.h
for
.Vt size_t .
.Vt size_t
and
.Qq Pa roff.h
for
.Vt enum roff_type .
.Pp
Provides
.Vt enum mdoct ,
.Vt enum mdocargt ,
.Vt enum mdoc_type ,
.Vt enum mdoc_sec ,
.Vt enum mdoc_endbody ,
.Vt enum mdoc_disp ,
.Vt enum mdoc_list ,
.Vt enum mdoc_auth ,
.Vt enum mdoc_font ,
.Vt struct mdoc_meta ,
.Vt struct mdoc_argv ,
.Vt struct mdoc_arg ,
.Vt struct mdoc_bd ,
@ -141,7 +158,6 @@ Provides
.Vt struct mdoc_an ,
.Vt struct mdoc_bf ,
.Vt struct mdoc_rs ,
.Vt struct mdoc_node ,
and the functions
.Fn mdoc_*
described in
@ -163,12 +179,12 @@ When this header is included, the same file should not include
or
.Pa libroff.h .
.It Qq Pa man.h
Provides
.Vt enum mant ,
.Vt enum man_type ,
.Vt struct man_meta ,
.Vt struct man_node ,
and the functions
Requires
.Qq Pa roff.h
for
.Vt enum roff_type .
.Pp
Provides the functions
.Fn man_*
described in
.Xr mandoc 3 .
@ -204,11 +220,16 @@ are included, the same file should not include any formatter headers.
Requires
.In sys/types.h
for
.Vt size_t
and
.Vt size_t ,
.Qq Pa mandoc.h
for
.Vt enum mandocerr .
.Vt enum mandocerr ,
and
.Qq Pa roff.h
for
.Vt struct roff_meta
and
.Vt struct roff_node .
.Pp
Provides
.Vt enum rofferr ,
@ -243,8 +264,7 @@ as opaque types for function prototypes.
Requires
.Qq Pa mdoc.h
for
.Vt enum mdoct ,
.Vt enum mdoc_* ,
.Vt enum mdoc_*
and
.Vt struct mdoc_* .
.Pp
@ -274,11 +294,11 @@ or
.Pa libroff.h .
.It Qq Pa libman.h
Requires
.Qq Pa man.h
.Qq Pa roff.h
for
.Vt enum mant
.Vt struct roff_meta
and
.Vt struct man_node.
.Vt struct roff_node .
.Pp
Provides
.Vt enum man_next ,
@ -366,8 +386,6 @@ from
as an opaque type for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa manpath.h
or
.Pa mansearch.h .
.It Qq Pa term.h
Requires
@ -389,11 +407,7 @@ Provides
.Vt struct termp ,
and many terminal formatting functions.
.Pp
Uses the opaque types
.Vt struct mchars
from
.Pa chars.c
and
Uses the opaque type
.Vt struct termp_ps
from
.Pa term_ps.c .
@ -403,11 +417,14 @@ and
.Vt struct eqn
from
.Pa mandoc.h
and
.Vt struct roff_meta
from
.Qq Pa roff.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa html.h ,
.Pa manpath.h
.Pa html.h
or
.Pa mansearch.h .
.It Qq Pa html.h
@ -435,23 +452,13 @@ Provides
.Vt struct html ,
and many HTML formatting functions.
.Pp
Uses the opaque type
.Vt struct mchars
from
.Pa chars.c .
.Pp
When this header is included, the same file should not include
.Pa term.h ,
.Pa manpath.h
.Pa term.h
or
.Pa mansearch.h .
.It Qq Pa main.h
Provides the top level steering functions for all formatters.
.Pp
Uses the opaque type
.Vt struct mchars
from
.Pa chars.c .
Uses the types
.Vt struct mdoc
from
@ -461,25 +468,21 @@ and
from
.Pa libman.h
as opaque types for function prototypes.
.It Qq Pa manpath.h
.It Qq Pa manconf.h
Requires
.In sys/types.h
for
.Vt size_t .
.Pp
Provides
.Vt struct manpaths
.Vt struct manconf ,
.Vt struct manpaths ,
.Vt struct manoutput ,
and the functions
.Fn manpath_manconf ,
.Fn manpath_parse ,
.Fn manconf_parse ,
.Fn manconf_output ,
and
.Fn manpath_free .
.Pp
When this header is included, the same file should not include
.Pa out.h ,
.Pa term.h ,
or
.Pa html.h .
.Fn manconf_free .
.It Qq Pa mansearch.h
Requires
.In sys/types.h
@ -503,7 +506,7 @@ and
Uses
.Vt struct manpaths
from
.Pa manpath.h
.Pa manconf.h
as an opaque type for function prototypes.
.Pp
When this header is included, the same file should not include

63
mandoc_ohash.c Normal file
View File

@ -0,0 +1,63 @@
/* $Id: mandoc_ohash.c,v 1.2 2015/10/19 18:58:47 schwarze Exp $ */
/*
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
static void *hash_alloc(size_t, void *);
static void *hash_calloc(size_t, size_t, void *);
static void hash_free(void *, void *);
void
mandoc_ohash_init(struct ohash *h, unsigned int sz, ptrdiff_t ko)
{
struct ohash_info info;
info.alloc = hash_alloc;
info.calloc = hash_calloc;
info.free = hash_free;
info.data = NULL;
info.key_offset = ko;
ohash_init(h, sz, &info);
}
static void *
hash_alloc(size_t sz, void *arg)
{
return mandoc_malloc(sz);
}
static void *
hash_calloc(size_t n, size_t sz, void *arg)
{
return mandoc_calloc(n, sz);
}
static void
hash_free(void *p, void *arg)
{
free(p);
}

23
mandoc_ohash.h Normal file
View File

@ -0,0 +1,23 @@
/* $Id: mandoc_ohash.h,v 1.2 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if HAVE_OHASH
#include <ohash.h>
#else
#include "compat_ohash.h"
#endif
void mandoc_ohash_init(struct ohash *, unsigned int, ptrdiff_t);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $Id: manpage.c,v 1.10 2015/02/10 08:05:30 schwarze Exp $ */
/* $Id: manpage.c,v 1.13 2015/11/07 17:58:55 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
@ -28,7 +28,7 @@
#include <string.h>
#include <unistd.h>
#include "manpath.h"
#include "manconf.h"
#include "mansearch.h"
static void show(const char *, const char *);
@ -37,13 +37,14 @@ int
main(int argc, char *argv[])
{
int ch, term;
size_t i, sz, len;
size_t i, sz, linesz;
ssize_t len;
struct mansearch search;
struct manpage *res;
char *conf_file, *defpaths, *auxpaths, *cp;
char *conf_file, *defpaths, *auxpaths, *line;
char buf[PATH_MAX];
const char *cmd;
struct manpaths paths;
struct manconf conf;
char *progname;
extern char *optarg;
extern int optind;
@ -57,7 +58,7 @@ main(int argc, char *argv[])
++progname;
auxpaths = defpaths = conf_file = NULL;
memset(&paths, 0, sizeof(struct manpaths));
memset(&conf, 0, sizeof(conf));
memset(&search, 0, sizeof(struct mansearch));
while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
@ -90,21 +91,21 @@ main(int argc, char *argv[])
search.outkey = "Nd";
search.argmode = ARG_EXPR;
manpath_parse(&paths, conf_file, defpaths, auxpaths);
ch = mansearch(&search, &paths, argc, argv, &res, &sz);
manpath_free(&paths);
manconf_parse(&conf, conf_file, defpaths, auxpaths);
ch = mansearch(&search, &conf.manpath, argc, argv, &res, &sz);
manconf_free(&conf);
if (0 == ch)
goto usage;
if (0 == sz) {
free(res);
return(EXIT_FAILURE);
return EXIT_FAILURE;
} else if (1 == sz && term) {
i = 1;
goto show;
} else if (NULL == res)
return(EXIT_FAILURE);
return EXIT_FAILURE;
for (i = 0; i < sz; i++) {
printf("%6zu %s: %s\n",
@ -117,25 +118,29 @@ main(int argc, char *argv[])
for (i = 0; i < sz; i++)
free(res[i].file);
free(res);
return(EXIT_SUCCESS);
return EXIT_SUCCESS;
}
i = 1;
printf("Enter a choice [1]: ");
fflush(stdout);
if (NULL != (cp = fgetln(stdin, &len)))
if ('\n' == cp[--len] && len > 0) {
cp[len] = '\0';
if ((i = atoi(cp)) < 1 || i > sz)
line = NULL;
linesz = 0;
if ((len = getline(&line, &linesz, stdin)) != -1) {
if ('\n' == line[--len] && len > 0) {
line[len] = '\0';
if ((i = atoi(line)) < 1 || i > sz)
i = 0;
}
}
free(line);
if (0 == i) {
for (i = 0; i < sz; i++)
free(res[i].file);
free(res);
return(EXIT_SUCCESS);
return EXIT_SUCCESS;
}
show:
cmd = res[i - 1].form ? "mandoc" : "cat";
@ -154,7 +159,7 @@ main(int argc, char *argv[])
"[-s section] "
"expr ...\n",
progname);
return(EXIT_FAILURE);
return EXIT_FAILURE;
}
static void

219
manpath.c
View File

@ -1,15 +1,15 @@
/* $Id: manpath.c,v 1.19 2014/11/27 00:30:40 schwarze Exp $ */
/* $Id: manpath.c,v 1.29 2015/11/07 17:58:55 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -20,24 +20,27 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc_aux.h"
#include "manpath.h"
#define MAN_CONF_FILE "/etc/man.conf"
#define MAN_CONF_KEY "_whatdb"
#include "manconf.h"
#if !HAVE_MANPATH
static void manconf_file(struct manconf *, const char *);
#endif
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,
manconf_parse(struct manconf *conf, const char *file,
char *defp, char *auxp)
{
#if HAVE_MANPATH
@ -80,7 +83,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, 1);
manpath_parseline(&conf->manpath, buf, 1);
}
free(buf);
@ -89,11 +92,11 @@ manpath_parse(struct manpaths *dirs, const char *file,
char *insert;
/* Always prepend -m. */
manpath_parseline(dirs, auxp, 1);
manpath_parseline(&conf->manpath, auxp, 1);
/* If -M is given, it overrides everything else. */
if (NULL != defp) {
manpath_parseline(dirs, defp, 1);
manpath_parseline(&conf->manpath, defp, 1);
return;
}
@ -104,21 +107,21 @@ manpath_parse(struct manpaths *dirs, const char *file,
/* No MANPATH; use man.conf(5) only. */
if (NULL == defp || '\0' == defp[0]) {
manpath_manconf(dirs, file);
manconf_file(conf, file);
return;
}
/* Prepend man.conf(5) to MANPATH. */
if (':' == defp[0]) {
manpath_manconf(dirs, file);
manpath_parseline(dirs, defp, 0);
manconf_file(conf, file);
manpath_parseline(&conf->manpath, defp, 0);
return;
}
/* Append man.conf(5) to MANPATH. */
if (':' == defp[strlen(defp) - 1]) {
manpath_parseline(dirs, defp, 0);
manpath_manconf(dirs, file);
manpath_parseline(&conf->manpath, defp, 0);
manconf_file(conf, file);
return;
}
@ -126,14 +129,14 @@ manpath_parse(struct manpaths *dirs, const char *file,
insert = strstr(defp, "::");
if (NULL != insert) {
*insert++ = '\0';
manpath_parseline(dirs, defp, 0);
manpath_manconf(dirs, file);
manpath_parseline(dirs, insert + 1, 0);
manpath_parseline(&conf->manpath, defp, 0);
manconf_file(conf, file);
manpath_parseline(&conf->manpath, insert + 1, 0);
return;
}
/* MANPATH overrides man.conf(5) completely. */
manpath_parseline(dirs, defp, 0);
manpath_parseline(&conf->manpath, defp, 0);
#endif
}
@ -165,10 +168,8 @@ manpath_add(struct manpaths *dirs, const char *dir, int complain)
size_t i;
if (NULL == (cp = realpath(dir, buf))) {
if (complain) {
fputs("manpath: ", stderr);
perror(dir);
}
if (complain)
warn("manpath: %s", dir);
return;
}
@ -177,10 +178,8 @@ manpath_add(struct manpaths *dirs, const char *dir, int complain)
return;
if (stat(cp, &sb) == -1) {
if (complain) {
fputs("manpath: ", stderr);
perror(dir);
}
if (complain)
warn("manpath: %s", dir);
return;
}
@ -191,47 +190,147 @@ manpath_add(struct manpaths *dirs, const char *dir, int complain)
}
void
manpath_free(struct manpaths *p)
manconf_free(struct manconf *conf)
{
size_t i;
for (i = 0; i < p->sz; i++)
free(p->paths[i]);
for (i = 0; i < conf->manpath.sz; i++)
free(conf->manpath.paths[i]);
free(p->paths);
free(conf->manpath.paths);
free(conf->output.includes);
free(conf->output.man);
free(conf->output.paper);
free(conf->output.style);
}
#if !HAVE_MANPATH
static void
manconf_file(struct manconf *conf, const char *file)
{
const char *const toks[] = { "manpath", "output", "_whatdb" };
char manpath_default[] = MANPATH_DEFAULT;
FILE *stream;
char *line, *cp, *ep;
size_t linesz, tok, toklen;
ssize_t linelen;
if ((stream = fopen(file, "r")) == NULL)
goto out;
line = NULL;
linesz = 0;
while ((linelen = getline(&line, &linesz, stream)) != -1) {
cp = line;
ep = cp + linelen;
if (ep[-1] != '\n')
break;
*--ep = '\0';
while (isspace((unsigned char)*cp))
cp++;
if (*cp == '#')
continue;
for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
toklen = strlen(toks[tok]);
if (cp + toklen < ep &&
isspace((unsigned char)cp[toklen]) &&
strncmp(cp, toks[tok], toklen) == 0) {
cp += toklen;
while (isspace((unsigned char)*cp))
cp++;
break;
}
}
switch (tok) {
case 2: /* _whatdb */
while (ep > cp && ep[-1] != '/')
ep--;
if (ep == cp)
continue;
*ep = '\0';
/* FALLTHROUGH */
case 0: /* manpath */
manpath_add(&conf->manpath, cp, 0);
*manpath_default = '\0';
break;
case 1: /* output */
manconf_output(&conf->output, cp);
break;
default:
break;
}
}
free(line);
fclose(stream);
out:
if (*manpath_default != '\0')
manpath_parseline(&conf->manpath, manpath_default, 0);
}
#endif
void
manpath_manconf(struct manpaths *dirs, const char *file)
manconf_output(struct manoutput *conf, const char *cp)
{
FILE *stream;
char *p, *q;
size_t len, keysz;
const char *const toks[] = {
"includes", "man", "paper", "style",
"indent", "width", "fragment", "mdoc"
};
keysz = strlen(MAN_CONF_KEY);
assert(keysz > 0);
size_t len, tok;
if (NULL == (stream = fopen(file, "r")))
return;
while (NULL != (p = fgetln(stream, &len))) {
if (0 == len || '\n' != p[--len])
for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
len = strlen(toks[tok]);
if ( ! strncmp(cp, toks[tok], len) &&
strchr(" = ", cp[len]) != NULL) {
cp += len;
if (*cp == '=')
cp++;
while (isspace((unsigned char)*cp))
cp++;
break;
p[len] = '\0';
while (isspace((unsigned char)*p))
p++;
if (strncmp(MAN_CONF_KEY, p, keysz))
continue;
p += keysz;
while (isspace((unsigned char)*p))
p++;
if ('\0' == *p)
continue;
if (NULL == (q = strrchr(p, '/')))
continue;
*q = '\0';
manpath_add(dirs, p, 0);
}
}
fclose(stream);
if (tok < 6 && *cp == '\0')
return;
switch (tok) {
case 0:
if (conf->includes == NULL)
conf->includes = mandoc_strdup(cp);
break;
case 1:
if (conf->man == NULL)
conf->man = mandoc_strdup(cp);
break;
case 2:
if (conf->paper == NULL)
conf->paper = mandoc_strdup(cp);
break;
case 3:
if (conf->style == NULL)
conf->style = mandoc_strdup(cp);
break;
case 4:
if (conf->indent == 0)
conf->indent = strtonum(cp, 0, 1000, NULL);
break;
case 5:
if (conf->width == 0)
conf->width = strtonum(cp, 58, 1000, NULL);
break;
case 6:
conf->fragment = 1;
break;
case 7:
conf->mdoc = 1;
break;
default:
break;
}
}

View File

@ -1,4 +1,4 @@
.\" $Id: mansearch.3,v 1.3 2014/12/12 21:44:33 schwarze Exp $
.\" $Id: mansearch.3,v 1.4 2015/03/27 17:37:25 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: December 12 2014 $
.Dd $Mdocdate: March 27 2015 $
.Dt MANSEARCH 3
.Os
.Sh NAME
@ -23,7 +23,7 @@
.Nd search manual page databases
.Sh SYNOPSIS
.In stdint.h
.In manpath.h
.In manconf.h
.In mansearch.h
.Ft int
.Fo mansearch_setup
@ -53,7 +53,7 @@ Search options, defined in
.In mansearch.h .
.It Fa "const struct manpaths *paths"
Directories to be searched, defined in
.In manpath.h .
.In manconf.h .
.It Fa "int argc" , "char *argv[]"
Search criteria, usually taken from the command line.
.El

View File

@ -1,4 +1,4 @@
/* $Id: mansearch.c,v 1.55 2015/03/11 13:11:22 schwarze Exp $ */
/* $Id: mansearch.c,v 1.64 2016/01/08 15:02:54 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,9 +7,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -21,6 +21,9 @@
#include <sys/types.h>
#include <assert.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@ -34,11 +37,6 @@
#include <string.h>
#include <unistd.h>
#if HAVE_OHASH
#include <ohash.h>
#else
#include "compat_ohash.h"
#endif
#include <sqlite3.h>
#ifndef SQLITE_DETERMINISTIC
#define SQLITE_DETERMINISTIC 0
@ -46,7 +44,8 @@
#include "mandoc.h"
#include "mandoc_aux.h"
#include "manpath.h"
#include "mandoc_ohash.h"
#include "manconf.h"
#include "mansearch.h"
extern int mansearch_keymax;
@ -55,17 +54,17 @@ extern const char *const mansearch_keynames[];
#define SQL_BIND_TEXT(_db, _s, _i, _v) \
do { if (SQLITE_OK != sqlite3_bind_text \
((_s), (_i)++, (_v), -1, SQLITE_STATIC)) \
fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
errx((int)MANDOCLEVEL_SYSERR, "%s", sqlite3_errmsg((_db))); \
} while (0)
#define SQL_BIND_INT64(_db, _s, _i, _v) \
do { if (SQLITE_OK != sqlite3_bind_int64 \
((_s), (_i)++, (_v))) \
fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
errx((int)MANDOCLEVEL_SYSERR, "%s", sqlite3_errmsg((_db))); \
} while (0)
#define SQL_BIND_BLOB(_db, _s, _i, _v) \
do { if (SQLITE_OK != sqlite3_bind_blob \
((_s), (_i)++, (&_v), sizeof(_v), SQLITE_STATIC)) \
fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
errx((int)MANDOCLEVEL_SYSERR, "%s", sqlite3_errmsg((_db))); \
} while (0)
struct expr {
@ -92,9 +91,6 @@ static void buildnames(const struct mansearch *,
const char *, int form);
static char *buildoutput(sqlite3 *, sqlite3_stmt *,
uint64_t, uint64_t);
static void *hash_alloc(size_t, void *);
static void hash_free(void *, void *);
static void *hash_calloc(size_t, size_t, void *);
static struct expr *exprcomp(const struct mansearch *,
int, char *[]);
static void exprfree(struct expr *);
@ -120,8 +116,8 @@ mansearch_setup(int start)
if (start) {
if (NULL != pagecache) {
fprintf(stderr, "pagecache already enabled\n");
return((int)MANDOCLEVEL_BADARG);
warnx("pagecache already enabled");
return (int)MANDOCLEVEL_BADARG;
}
pagecache = mmap(NULL, PC_PAGESIZE * PC_NUMPAGES,
@ -129,32 +125,32 @@ mansearch_setup(int start)
MAP_SHARED | MAP_ANON, -1, 0);
if (MAP_FAILED == pagecache) {
perror("mmap");
warn("mmap");
pagecache = NULL;
return((int)MANDOCLEVEL_SYSERR);
return (int)MANDOCLEVEL_SYSERR;
}
c = sqlite3_config(SQLITE_CONFIG_PAGECACHE,
pagecache, PC_PAGESIZE, PC_NUMPAGES);
if (SQLITE_OK == c)
return((int)MANDOCLEVEL_OK);
return (int)MANDOCLEVEL_OK;
fprintf(stderr, "pagecache: %s\n", sqlite3_errstr(c));
warnx("pagecache: %s", sqlite3_errstr(c));
} else if (NULL == pagecache) {
fprintf(stderr, "pagecache missing\n");
return((int)MANDOCLEVEL_BADARG);
warnx("pagecache missing");
return (int)MANDOCLEVEL_BADARG;
}
if (-1 == munmap(pagecache, PC_PAGESIZE * PC_NUMPAGES)) {
perror("munmap");
warn("munmap");
pagecache = NULL;
return((int)MANDOCLEVEL_SYSERR);
return (int)MANDOCLEVEL_SYSERR;
}
pagecache = NULL;
return((int)MANDOCLEVEL_OK);
return (int)MANDOCLEVEL_OK;
}
int
@ -163,7 +159,6 @@ mansearch(const struct mansearch *search,
int argc, char *argv[],
struct manpage **res, size_t *sz)
{
int fd, rc, c, indexbit;
int64_t pageid;
uint64_t outbit, iterbit;
char buf[PATH_MAX];
@ -173,27 +168,18 @@ mansearch(const struct mansearch *search,
sqlite3 *db;
sqlite3_stmt *s, *s2;
struct match *mp;
struct ohash_info info;
struct ohash htab;
unsigned int idx;
size_t i, j, cur, maxres;
int c, chdir_status, getcwd_status, indexbit;
info.calloc = hash_calloc;
info.alloc = hash_alloc;
info.free = hash_free;
info.key_offset = offsetof(struct match, pageid);
if (argc == 0 || (e = exprcomp(search, argc, argv)) == NULL) {
*sz = 0;
return 0;
}
*sz = cur = maxres = 0;
sql = NULL;
cur = maxres = 0;
*res = NULL;
fd = -1;
e = NULL;
rc = 0;
if (0 == argc)
goto out;
if (NULL == (e = exprcomp(search, argc, argv)))
goto out;
if (NULL != search->outkey) {
outbit = TYPE_Nd;
@ -210,19 +196,18 @@ mansearch(const struct mansearch *search,
outbit = 0;
/*
* Save a descriptor to the current working directory.
* Since pathnames in the "paths" variable might be relative,
* and we'll be chdir()ing into them, we need to keep a handle
* on our current directory from which to start the chdir().
* Remember the original working directory, if possible.
* This will be needed if the second or a later directory
* is given as a relative path.
* Do not error out if the current directory is not
* searchable: Maybe it won't be needed after all.
*/
if (NULL == getcwd(buf, PATH_MAX)) {
perror("getcwd");
goto out;
} else if (-1 == (fd = open(buf, O_RDONLY, 0))) {
perror(buf);
goto out;
}
if (getcwd(buf, PATH_MAX) == NULL) {
getcwd_status = 0;
(void)strlcpy(buf, strerror(errno), sizeof(buf));
} else
getcwd_status = 1;
sql = sql_statement(e);
@ -234,22 +219,28 @@ mansearch(const struct mansearch *search,
* scan it for our match expression.
*/
chdir_status = 0;
for (i = 0; i < paths->sz; i++) {
if (-1 == fchdir(fd)) {
perror(buf);
free(*res);
break;
} else if (-1 == chdir(paths->paths[i])) {
perror(paths->paths[i]);
if (chdir_status && paths->paths[i][0] != '/') {
if ( ! getcwd_status) {
warnx("%s: getcwd: %s", paths->paths[i], buf);
continue;
} else if (chdir(buf) == -1) {
warn("%s", buf);
continue;
}
}
if (chdir(paths->paths[i]) == -1) {
warn("%s", paths->paths[i]);
continue;
}
chdir_status = 1;
c = sqlite3_open_v2(MANDOC_DB, &db,
SQLITE_OPEN_READONLY, NULL);
if (SQLITE_OK != c) {
fprintf(stderr, "%s/%s: %s\n",
paths->paths[i], MANDOC_DB, strerror(errno));
warn("%s/%s", paths->paths[i], MANDOC_DB);
sqlite3_close(db);
continue;
}
@ -271,7 +262,8 @@ mansearch(const struct mansearch *search,
j = 1;
c = sqlite3_prepare_v2(db, sql, -1, &s, NULL);
if (SQLITE_OK != c)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
errx((int)MANDOCLEVEL_SYSERR,
"%s", sqlite3_errmsg(db));
for (ep = e; NULL != ep; ep = ep->next) {
if (NULL == ep->substr) {
@ -282,8 +274,7 @@ mansearch(const struct mansearch *search,
SQL_BIND_INT64(db, s, j, ep->bits);
}
memset(&htab, 0, sizeof(struct ohash));
ohash_init(&htab, 4, &info);
mandoc_ohash_init(&htab, 4, offsetof(struct match, pageid));
/*
* Hash each entry on its [unique] document identifier.
@ -313,7 +304,7 @@ mansearch(const struct mansearch *search,
}
if (SQLITE_DONE != c)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
warnx("%s", sqlite3_errmsg(db));
sqlite3_finalize(s);
@ -322,14 +313,16 @@ mansearch(const struct mansearch *search,
"WHERE pageid=? ORDER BY sec, arch, name",
-1, &s, NULL);
if (SQLITE_OK != c)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
errx((int)MANDOCLEVEL_SYSERR,
"%s", sqlite3_errmsg(db));
c = sqlite3_prepare_v2(db,
"SELECT bits, key, pageid FROM keys "
"WHERE pageid=? AND bits & ?",
-1, &s2, NULL);
if (SQLITE_OK != c)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
errx((int)MANDOCLEVEL_SYSERR,
"%s", sqlite3_errmsg(db));
for (mp = ohash_first(&htab, &idx);
NULL != mp;
@ -370,17 +363,12 @@ mansearch(const struct mansearch *search,
break;
}
qsort(*res, cur, sizeof(struct manpage), manpage_compare);
rc = 1;
out:
if (-1 != fd) {
if (-1 == fchdir(fd))
perror(buf);
close(fd);
}
if (chdir_status && getcwd_status && chdir(buf) == -1)
warn("%s", buf);
exprfree(e);
free(sql);
*sz = cur;
return(rc);
return 1;
}
void
@ -404,9 +392,9 @@ manpage_compare(const void *vp1, const void *vp2)
mp1 = vp1;
mp2 = vp2;
return( (diff = mp2->bits - mp1->bits) ? diff :
(diff = mp1->sec - mp2->sec) ? 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
@ -515,7 +503,7 @@ buildnames(const struct mansearch *search, struct manpage *mpage,
globfree(&globinfo);
}
if (c != SQLITE_DONE)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
warnx("%s", sqlite3_errmsg(db));
sqlite3_reset(s);
/* If none of the files is usable, use the first name. */
@ -565,9 +553,9 @@ buildoutput(sqlite3 *db, sqlite3_stmt *s, uint64_t pageid, uint64_t outbit)
output = newoutput;
}
if (SQLITE_DONE != c)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
warnx("%s", sqlite3_errmsg(db));
sqlite3_reset(s);
return(output);
return output;
}
/*
@ -662,7 +650,7 @@ sql_statement(const struct expr *e)
needop = 1;
}
return(sql);
return sql;
}
/*
@ -745,12 +733,12 @@ exprcomp(const struct mansearch *search, int argc, char *argv[])
toopen = logic = igncase = 0;
}
if ( ! (toopen || logic || igncase || toclose))
return(first);
return first;
fail:
if (NULL != first)
exprfree(first);
return(NULL);
return NULL;
}
static struct expr *
@ -763,7 +751,7 @@ exprterm(const struct mansearch *search, char *buf, int cs)
int i, irc;
if ('\0' == *buf)
return(NULL);
return NULL;
e = mandoc_calloc(1, sizeof(struct expr));
@ -771,7 +759,7 @@ exprterm(const struct mansearch *search, char *buf, int cs)
e->bits = TYPE_Nm;
e->substr = buf;
e->equal = 1;
return(e);
return e;
}
/*
@ -783,7 +771,14 @@ exprterm(const struct mansearch *search, char *buf, int cs)
if (search->argmode == ARG_WORD) {
e->bits = TYPE_Nm;
e->substr = NULL;
#if HAVE_REWB_BSD
mandoc_asprintf(&val, "[[:<:]]%s[[:>:]]", buf);
#elif HAVE_REWB_SYSV
mandoc_asprintf(&val, "\\<%s\\>", buf);
#else
mandoc_asprintf(&val,
"(^|[^a-zA-Z01-9_])%s([^a-zA-Z01-9_]|$)", buf);
#endif
cs = 0;
} else if ((val = strpbrk(buf, "=~")) == NULL) {
e->bits = TYPE_Nm | TYPE_Nd;
@ -807,14 +802,14 @@ exprterm(const struct mansearch *search, char *buf, int cs)
free(val);
if (irc) {
regerror(irc, &e->regexp, errbuf, sizeof(errbuf));
fprintf(stderr, "regcomp: %s\n", errbuf);
warnx("regcomp: %s", errbuf);
free(e);
return(NULL);
return NULL;
}
}
if (e->bits)
return(e);
return e;
/*
* Parse out all possible fields.
@ -836,13 +831,13 @@ exprterm(const struct mansearch *search, char *buf, int cs)
if (i == mansearch_keymax) {
if (strcasecmp(key, "any")) {
free(e);
return(NULL);
return NULL;
}
e->bits |= ~0ULL;
}
}
return(e);
return e;
}
static void
@ -856,24 +851,3 @@ exprfree(struct expr *p)
p = pp;
}
}
static void *
hash_calloc(size_t nmemb, size_t sz, void *arg)
{
return(mandoc_calloc(nmemb, sz));
}
static void *
hash_alloc(size_t sz, void *arg)
{
return(mandoc_malloc(sz));
}
static void
hash_free(void *p, void *arg)
{
free(p);
}

View File

@ -1,4 +1,4 @@
/* $Id: mansearch.h,v 1.23 2014/12/01 08:05:52 schwarze Exp $ */
/* $Id: mansearch.h,v 1.24 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@ -95,7 +95,6 @@ struct mansearch {
int firstmatch; /* first matching database only */
};
__BEGIN_DECLS
struct manpaths;
@ -107,5 +106,3 @@ int mansearch(const struct mansearch *cfg, /* options */
struct manpage **res, /* results */
size_t *ressz); /* results returned */
void mansearch_free(struct manpage *, size_t);
__END_DECLS

View File

@ -1,4 +1,4 @@
.\" $Id: mchars_alloc.3,v 1.2 2014/10/26 18:07:28 schwarze Exp $
.\" $Id: mchars_alloc.3,v 1.3 2015/10/13 22:59:54 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: October 26 2014 $
.Dd $Mdocdate: October 13 2015 $
.Dt MCHARS_ALLOC 3
.Os
.Sh NAME
@ -25,17 +25,13 @@
.Nm mchars_spec2cp ,
.Nm mchars_spec2str
.Nd character table for mandoc
.Sh LIBRARY
.Lb libmandoc
.Sh SYNOPSIS
.In sys/types.h
.In mandoc.h
.Ft "struct mchars *"
.Fn mchars_alloc "void"
.Ft void
.Fo mchars_free
.Fa "struct mchars *table"
.Fc
.Fn mchars_alloc void
.Ft void
.Fn mchars_free void
.Ft char
.Fo mchars_num2char
.Fa "const char *decimal"
@ -48,13 +44,11 @@
.Fc
.Ft int
.Fo mchars_spec2cp
.Fa "const struct mchars *table"
.Fa "const char *name"
.Fa "size_t sz"
.Fc
.Ft "const char *"
.Fo mchars_spec2str
.Fa "const struct mchars *table"
.Fa "const char *name"
.Fa "size_t sz"
.Fa "size_t *rsz"
@ -135,9 +129,9 @@ escape sequences.
.Pp
The function
.Fn mchars_alloc
allocates an opaque
.Vt "struct mchars *"
table object for subsequent use by the following two lookup functions.
initializes a static
.Vt "struct ohash"
object for subsequent use by the following two lookup functions.
When no longer needed, this object can be destroyed with
.Fn mchars_free .
.Pp
@ -149,9 +143,7 @@ special character
.Fa name
consisting of
.Fa sz
characters in the
.Fa table
and returns the corresponding Unicode codepoint.
characters and returns the corresponding Unicode codepoint.
If the
.Ar name
is not recognized, \-1 is returned.
@ -175,9 +167,7 @@ special character
.Fa name
consisting of
.Fa sz
characters in the
.Fa table
and returns an ASCII string representation.
characters and returns an ASCII string representation.
The length of the representation is returned in
.Fa rsz .
In many cases, the meaning of such ASCII representations
@ -215,6 +205,7 @@ These funtions are implemented in the file
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr mandoc_escape 3 ,
.Xr ohash_init 3 ,
.Xr mandoc_char 7 ,
.Xr roff 7
.Sh HISTORY

27
mdoc.7
View File

@ -1,4 +1,4 @@
.\" $Id: mdoc.7,v 1.252 2015/02/23 13:31:04 schwarze Exp $
.\" $Id: mdoc.7,v 1.257 2015/11/05 12:06:45 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: February 23 2015 $
.Dd $Mdocdate: November 5 2015 $
.Dt MDOC 7
.Os
.Sh NAME
@ -304,6 +304,11 @@ Print verbose information.
\&.El
.Ed
.Pp
List the options in alphabetical order,
uppercase before lowercase for each letter and
with no regard to whether an option takes an argument.
Put digits in ascending order before all letter options.
.Pp
Manuals not documenting a command won't include the above fragment.
.Pp
Since the
@ -1622,7 +1627,7 @@ See also
A function name.
Its syntax is as follows:
.Bd -ragged -offset indent
.Pf \. Ns Sx \&Fn
.Pf . Sx \&Fn
.Op Ar functype
.Ar funcname
.Op Oo Ar argtype Oc Ar argname
@ -2093,7 +2098,7 @@ It is suggested to leave it unspecified, in which case
.Xr mandoc 1
uses its
.Fl Ios
argument, or, if that isn't specified either,
argument or, if that isn't specified either,
.Fa sysname
and
.Fa release
@ -2155,19 +2160,23 @@ See also
Close parenthesised context opened by
.Sx \&Po .
.Ss \&Pf
Removes the space between its argument
.Pq Dq prefix
and the following macro.
Removes the space between its argument and the following macro.
Its syntax is as follows:
.Pp
.D1 .Pf Ar prefix macro arguments ...
.Pp
This is equivalent to:
.Pp
.D1 .No Ar prefix No \&Ns Ar macro arguments ...
.D1 .No \e& Ns Ar prefix No \&Ns Ar macro arguments ...
.Pp
The
.Ar prefix
argument is not parsed for macro names or delimiters,
but used verbatim as if it were escaped.
.Pp
Examples:
.Dl ".Pf $ Ar variable_name"
.Dl ".Pf . Ar macro_name"
.Dl ".Pf 0x Ar hex_digits"
.Pp
See also
@ -2267,7 +2276,7 @@ Examples:
\&.%A J. D. Ullman
\&.%B Introduction to Automata Theory, Languages, and Computation
\&.%I Addison-Wesley
\&.%C Reading, Massachusettes
\&.%C Reading, Massachusetts
\&.%D 1979
\&.Re
.Ed

592
mdoc.c
View File

@ -1,4 +1,4 @@
/* $Id: mdoc.c,v 1.238 2015/02/12 13:00:52 schwarze Exp $ */
/* $Id: mdoc.c,v 1.256 2015/10/30 19:04:16 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,9 +7,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -27,13 +27,16 @@
#include <string.h>
#include <time.h>
#include "mdoc.h"
#include "mandoc.h"
#include "mandoc_aux.h"
#include "libmdoc.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libmdoc.h"
const char *const __mdoc_macronames[MDOC_MAX + 1] = {
"text",
"Ap", "Dd", "Dt", "Os",
"Sh", "Ss", "Pp", "D1",
"Dl", "Bd", "Ed", "Bl",
@ -64,8 +67,8 @@ const char *const __mdoc_macronames[MDOC_MAX + 1] = {
"Lk", "Mt", "Brq", "Bro",
"Brc", "%C", "Es", "En",
"Dx", "%Q", "br", "sp",
"%U", "Ta", "ll", "text",
};
"%U", "Ta", "ll",
};
const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"split", "nosplit", "ragged",
@ -79,157 +82,22 @@ const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"symbolic", "nested", "centered"
};
const char * const *mdoc_macronames = __mdoc_macronames;
const char * const *mdoc_macronames = __mdoc_macronames + 1;
const char * const *mdoc_argnames = __mdoc_argnames;
static void mdoc_node_free(struct mdoc_node *);
static void mdoc_node_unlink(struct mdoc *,
struct mdoc_node *);
static void mdoc_free1(struct mdoc *);
static void mdoc_alloc1(struct mdoc *);
static struct mdoc_node *node_alloc(struct mdoc *, int, int,
enum mdoct, enum mdoc_type);
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);
static int mdoc_ptext(struct roff_man *, int, char *, int);
static int mdoc_pmacro(struct roff_man *, int, char *, int);
const struct mdoc_node *
mdoc_node(const struct mdoc *mdoc)
{
return(mdoc->first);
}
const struct mdoc_meta *
mdoc_meta(const struct mdoc *mdoc)
{
return(&mdoc->meta);
}
/*
* Frees volatile resources (parse tree, meta-data, fields).
*/
static void
mdoc_free1(struct mdoc *mdoc)
{
if (mdoc->first)
mdoc_node_delete(mdoc, mdoc->first);
free(mdoc->meta.msec);
free(mdoc->meta.vol);
free(mdoc->meta.arch);
free(mdoc->meta.date);
free(mdoc->meta.title);
free(mdoc->meta.os);
free(mdoc->meta.name);
}
/*
* Allocate all volatile resources (parse tree, meta-data, fields).
*/
static void
mdoc_alloc1(struct mdoc *mdoc)
{
memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
mdoc->flags = 0;
mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
mdoc->first = mdoc->last;
mdoc->last->type = MDOC_ROOT;
mdoc->last->tok = MDOC_MAX;
mdoc->next = MDOC_NEXT_CHILD;
}
/*
* Free up volatile resources (see mdoc_free1()) then re-initialises the
* data with mdoc_alloc1(). After invocation, parse data has been reset
* and the parser is ready for re-invocation on a new tree; however,
* cross-parse non-volatile data is kept intact.
*/
void
mdoc_reset(struct mdoc *mdoc)
{
mdoc_free1(mdoc);
mdoc_alloc1(mdoc);
}
/*
* Completely free up all volatile and non-volatile parse resources.
* After invocation, the pointer is no longer usable.
*/
void
mdoc_free(struct mdoc *mdoc)
{
mdoc_free1(mdoc);
free(mdoc);
}
/*
* Allocate volatile and non-volatile parse resources.
*/
struct mdoc *
mdoc_alloc(struct roff *roff, struct mparse *parse,
const char *defos, int quick)
{
struct mdoc *p;
p = mandoc_calloc(1, sizeof(struct mdoc));
p->parse = parse;
p->defos = defos;
p->quick = quick;
p->roff = roff;
mdoc_hash_init();
mdoc_alloc1(p);
return(p);
}
void
mdoc_endparse(struct mdoc *mdoc)
{
mdoc_macroend(mdoc);
}
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 (ep->ln > mdoc->last->line)
n->flags |= MDOC_LINE;
node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
}
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;
node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
}
/*
* Main parse routine. Parses a single line -- really just hands off to
* the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
*/
int
mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
{
if (mdoc->last->type != MDOC_EQN || ln > mdoc->last->line)
if (mdoc->last->type != ROFFT_EQN || ln > mdoc->last->line)
mdoc->flags |= MDOC_NEWLINE;
/*
@ -243,231 +111,80 @@ mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
else
mdoc->flags &= ~MDOC_SYNOPSIS;
return(roff_getcontrol(mdoc->roff, buf, &offs) ?
return roff_getcontrol(mdoc->roff, buf, &offs) ?
mdoc_pmacro(mdoc, ln, buf, offs) :
mdoc_ptext(mdoc, ln, buf, offs));
mdoc_ptext(mdoc, ln, buf, offs);
}
void
mdoc_macro(MACRO_PROT_ARGS)
{
assert(tok < MDOC_MAX);
assert(tok > TOKEN_NONE && tok < MDOC_MAX);
if (mdoc->flags & MDOC_PBODY) {
if (tok == MDOC_Dt) {
mandoc_vmsg(MANDOCERR_DT_LATE,
mdoc->parse, line, ppos,
"Dt %s", buf + *pos);
return;
}
} else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) {
if (mdoc->meta.title == NULL) {
mandoc_vmsg(MANDOCERR_DT_NOTITLE,
mdoc->parse, line, ppos, "%s %s",
mdoc_macronames[tok], buf + *pos);
mdoc->meta.title = mandoc_strdup("UNTITLED");
}
if (NULL == mdoc->meta.vol)
mdoc->meta.vol = mandoc_strdup("LOCAL");
mdoc->flags |= MDOC_PBODY;
}
(*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
}
static void
node_append(struct mdoc *mdoc, struct mdoc_node *p)
{
assert(mdoc->last);
assert(mdoc->first);
assert(MDOC_ROOT != p->type);
switch (mdoc->next) {
case MDOC_NEXT_SIBLING:
mdoc->last->next = p;
p->prev = mdoc->last;
p->parent = mdoc->last->parent;
break;
case MDOC_NEXT_CHILD:
mdoc->last->child = p;
p->parent = mdoc->last;
break;
default:
abort();
/* NOTREACHED */
}
p->parent->nchild++;
/*
* Copy over the normalised-data pointer of our parent. Not
* everybody has one, but copying a null pointer is fine.
*/
switch (p->type) {
case MDOC_BODY:
if (ENDBODY_NOT != p->end)
break;
/* FALLTHROUGH */
case MDOC_TAIL:
/* FALLTHROUGH */
case MDOC_HEAD:
p->norm = p->parent->norm;
break;
default:
break;
}
mdoc_valid_pre(mdoc, p);
switch (p->type) {
case MDOC_HEAD:
assert(MDOC_BLOCK == p->parent->type);
p->parent->head = p;
break;
case MDOC_TAIL:
assert(MDOC_BLOCK == p->parent->type);
p->parent->tail = p;
break;
case MDOC_BODY:
if (p->end)
break;
assert(MDOC_BLOCK == p->parent->type);
p->parent->body = p;
break;
default:
break;
}
mdoc->last = p;
switch (p->type) {
case MDOC_TBL:
/* FALLTHROUGH */
case MDOC_TEXT:
mdoc_valid_post(mdoc);
break;
default:
break;
}
}
static struct mdoc_node *
node_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, enum mdoc_type type)
{
struct mdoc_node *p;
p = mandoc_calloc(1, sizeof(struct mdoc_node));
p->sec = mdoc->lastsec;
p->line = line;
p->pos = pos;
p->tok = tok;
p->type = type;
/* Flag analysis. */
if (MDOC_SYNOPSIS & mdoc->flags)
p->flags |= MDOC_SYNPRETTY;
else
p->flags &= ~MDOC_SYNPRETTY;
if (MDOC_NEWLINE & mdoc->flags)
p->flags |= MDOC_LINE;
mdoc->flags &= ~MDOC_NEWLINE;
return(p);
}
void
mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, int tok)
{
struct mdoc_node *p;
struct roff_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
p = roff_node_alloc(mdoc, line, pos, ROFFT_TAIL, tok);
roff_node_append(mdoc, p);
mdoc->next = ROFF_NEXT_CHILD;
}
struct mdoc_node *
mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
struct roff_node *
mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok,
struct roff_node *body, enum mdoc_endbody end)
{
struct mdoc_node *p;
assert(mdoc->first);
assert(mdoc->last);
p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
return(p);
}
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);
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
return(p);
}
struct mdoc_node *
mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
struct mdoc_node *body, enum mdoc_endbody end)
{
struct mdoc_node *p;
struct roff_node *p;
body->flags |= MDOC_ENDED;
body->parent->flags |= MDOC_ENDED;
p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
p = roff_node_alloc(mdoc, line, pos, ROFFT_BODY, tok);
p->body = body;
p->norm = body->norm;
p->end = end;
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_SIBLING;
return(p);
roff_node_append(mdoc, p);
mdoc->next = ROFF_NEXT_SIBLING;
return p;
}
struct mdoc_node *
mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
struct roff_node *
mdoc_block_alloc(struct roff_man *mdoc, int line, int pos,
int tok, struct mdoc_arg *args)
{
struct mdoc_node *p;
struct roff_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK);
p = roff_node_alloc(mdoc, line, pos, ROFFT_BLOCK, tok);
p->args = args;
if (p->args)
(args->refcnt)++;
switch (tok) {
case MDOC_Bd:
/* FALLTHROUGH */
case MDOC_Bf:
/* FALLTHROUGH */
case MDOC_Bl:
/* FALLTHROUGH */
case MDOC_En:
/* FALLTHROUGH */
case MDOC_Rs:
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
break;
default:
break;
}
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
return(p);
roff_node_append(mdoc, p);
mdoc->next = ROFF_NEXT_CHILD;
return p;
}
void
mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
int tok, struct mdoc_arg *args)
{
struct mdoc_node *p;
struct roff_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM);
p = roff_node_alloc(mdoc, line, pos, ROFFT_ELEM, tok);
p->args = args;
if (p->args)
(args->refcnt)++;
@ -479,106 +196,17 @@ mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
default:
break;
}
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
roff_node_append(mdoc, p);
mdoc->next = ROFF_NEXT_CHILD;
}
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);
node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
}
void
mdoc_word_append(struct mdoc *mdoc, const char *p)
{
struct mdoc_node *n;
char *addstr, *newstr;
n = mdoc->last;
addstr = roff_strdup(mdoc->roff, p);
mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
free(addstr);
free(n->string);
n->string = newstr;
mdoc->next = MDOC_NEXT_SIBLING;
}
static void
mdoc_node_free(struct mdoc_node *p)
mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p)
{
if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type)
free(p->norm);
if (p->string)
free(p->string);
if (p->args)
mdoc_argv_free(p->args);
free(p);
}
static void
mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
{
/* Adjust siblings. */
if (n->prev)
n->prev->next = n->next;
if (n->next)
n->next->prev = n->prev;
/* Adjust parent. */
if (n->parent) {
n->parent->nchild--;
if (n->parent->child == n)
n->parent->child = n->prev ? n->prev : n->next;
if (n->parent->last == n)
n->parent->last = n->prev ? n->prev : NULL;
}
/* Adjust parse point, if applicable. */
if (mdoc && mdoc->last == n) {
if (n->prev) {
mdoc->last = n->prev;
mdoc->next = MDOC_NEXT_SIBLING;
} else {
mdoc->last = n->parent;
mdoc->next = MDOC_NEXT_CHILD;
}
}
if (mdoc && mdoc->first == n)
mdoc->first = NULL;
}
void
mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
{
while (p->child) {
assert(p->nchild);
mdoc_node_delete(mdoc, p->child);
}
assert(0 == p->nchild);
mdoc_node_unlink(mdoc, p);
mdoc_node_free(p);
}
void
mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
{
mdoc_node_unlink(mdoc, p);
node_append(mdoc, p);
roff_node_unlink(mdoc, p);
p->prev = p->next = NULL;
roff_node_append(mdoc, p);
}
/*
@ -586,37 +214,37 @@ mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
* control character.
*/
static int
mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
{
struct roff_node *n;
char *c, *ws, *end;
struct mdoc_node *n;
assert(mdoc->last);
n = mdoc->last;
/*
* Divert directly to list processing if we're encountering a
* columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
* (a MDOC_BODY means it's already open, in which case we should
* columnar ROFFT_BLOCK with or without a prior ROFFT_BLOCK entry
* (a ROFFT_BODY means it's already open, in which case we should
* process within its context in the normal way).
*/
if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
if (n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
/* `Bl' is open without any children. */
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
return(1);
return 1;
}
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
if (n->tok == MDOC_It && n->type == ROFFT_BLOCK &&
NULL != n->parent &&
MDOC_Bl == n->parent->tok &&
LIST_column == n->parent->norm->Bl.type) {
/* `Bl' has block-level `It' children. */
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
return(1);
return 1;
}
/*
@ -673,16 +301,16 @@ 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.
*/
mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL);
mdoc->next = MDOC_NEXT_SIBLING;
mdoc_valid_post(mdoc);
return(1);
roff_elem_alloc(mdoc, line, offs, MDOC_sp);
mdoc->last->flags |= MDOC_VALID | MDOC_ENDED;
mdoc->next = ROFF_NEXT_SIBLING;
return 1;
}
mdoc_word_alloc(mdoc, line, offs, buf+offs);
roff_word_alloc(mdoc, line, offs, buf+offs);
if (mdoc->flags & MDOC_LITERAL)
return(1);
return 1;
/*
* End-of-sentence check. If the last character is an unescaped
@ -694,7 +322,7 @@ 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);
return 1;
}
/*
@ -702,11 +330,11 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
* character.
*/
static int
mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
{
struct mdoc_node *n;
struct roff_node *n;
const char *cp;
enum mdoct tok;
int tok;
int i, sv;
char mac[5];
@ -723,12 +351,12 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
mac[i] = '\0';
tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : TOKEN_NONE;
if (tok == MDOC_MAX) {
if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
ln, sv, buf + sv - 1);
return(1);
return 1;
}
/* Skip a leading escape sequence or tab. */
@ -767,7 +395,7 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
return(1);
return 1;
}
n = mdoc->last;
@ -778,11 +406,11 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
* context around the parsed macro.
*/
if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
if (n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
return(1);
return 1;
}
/*
@ -791,13 +419,13 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
* then open an `It' block context around the parsed macro.
*/
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
if (n->tok == MDOC_It && n->type == ROFFT_BLOCK &&
NULL != n->parent &&
MDOC_Bl == n->parent->tok &&
LIST_column == n->parent->norm->Bl.type) {
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
return(1);
return 1;
}
/* Normal processing of a macro. */
@ -808,9 +436,9 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
if (mdoc->quick && MDOC_Sh == tok &&
SEC_NAME != mdoc->last->sec)
return(2);
return 2;
return(1);
return 1;
}
enum mdelim
@ -818,82 +446,44 @@ mdoc_isdelim(const char *p)
{
if ('\0' == p[0])
return(DELIM_NONE);
return DELIM_NONE;
if ('\0' == p[1])
switch (p[0]) {
case '(':
/* FALLTHROUGH */
case '[':
return(DELIM_OPEN);
return DELIM_OPEN;
case '|':
return(DELIM_MIDDLE);
return DELIM_MIDDLE;
case '.':
/* FALLTHROUGH */
case ',':
/* FALLTHROUGH */
case ';':
/* FALLTHROUGH */
case ':':
/* FALLTHROUGH */
case '?':
/* FALLTHROUGH */
case '!':
/* FALLTHROUGH */
case ')':
/* FALLTHROUGH */
case ']':
return(DELIM_CLOSE);
return DELIM_CLOSE;
default:
return(DELIM_NONE);
return DELIM_NONE;
}
if ('\\' != p[0])
return(DELIM_NONE);
return DELIM_NONE;
if (0 == strcmp(p + 1, "."))
return(DELIM_CLOSE);
return DELIM_CLOSE;
if (0 == strcmp(p + 1, "fR|\\fP"))
return(DELIM_MIDDLE);
return DELIM_MIDDLE;
return(DELIM_NONE);
return DELIM_NONE;
}
void
mdoc_deroff(char **dest, const struct mdoc_node *n)
mdoc_validate(struct roff_man *mdoc)
{
char *cp;
size_t sz;
if (MDOC_TEXT != n->type) {
for (n = n->child; n; n = n->next)
mdoc_deroff(dest, n);
return;
}
/* Skip leading whitespace. */
for (cp = n->string; '\0' != *cp; cp++)
if (0 == isspace((unsigned char)*cp))
break;
/* Skip trailing whitespace. */
for (sz = strlen(cp); sz; sz--)
if (0 == isspace((unsigned char)cp[sz-1]))
break;
/* Skip empty strings. */
if (0 == sz)
return;
if (NULL == *dest) {
*dest = mandoc_strndup(cp, sz);
return;
}
mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
free(*dest);
*dest = cp;
mdoc->last = mdoc->first;
mdoc_node_validate(mdoc);
mdoc_state_reset(mdoc);
}

371
mdoc.h
View File

@ -1,4 +1,4 @@
/* $Id: mdoc.h,v 1.136 2015/02/12 12:24:33 schwarze Exp $ */
/* $Id: mdoc.h,v 1.144 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,141 +7,139 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enum mdoct {
MDOC_Ap = 0,
MDOC_Dd,
MDOC_Dt,
MDOC_Os,
MDOC_Sh,
MDOC_Ss,
MDOC_Pp,
MDOC_D1,
MDOC_Dl,
MDOC_Bd,
MDOC_Ed,
MDOC_Bl,
MDOC_El,
MDOC_It,
MDOC_Ad,
MDOC_An,
MDOC_Ar,
MDOC_Cd,
MDOC_Cm,
MDOC_Dv,
MDOC_Er,
MDOC_Ev,
MDOC_Ex,
MDOC_Fa,
MDOC_Fd,
MDOC_Fl,
MDOC_Fn,
MDOC_Ft,
MDOC_Ic,
MDOC_In,
MDOC_Li,
MDOC_Nd,
MDOC_Nm,
MDOC_Op,
MDOC_Ot,
MDOC_Pa,
MDOC_Rv,
MDOC_St,
MDOC_Va,
MDOC_Vt,
MDOC_Xr,
MDOC__A,
MDOC__B,
MDOC__D,
MDOC__I,
MDOC__J,
MDOC__N,
MDOC__O,
MDOC__P,
MDOC__R,
MDOC__T,
MDOC__V,
MDOC_Ac,
MDOC_Ao,
MDOC_Aq,
MDOC_At,
MDOC_Bc,
MDOC_Bf,
MDOC_Bo,
MDOC_Bq,
MDOC_Bsx,
MDOC_Bx,
MDOC_Db,
MDOC_Dc,
MDOC_Do,
MDOC_Dq,
MDOC_Ec,
MDOC_Ef,
MDOC_Em,
MDOC_Eo,
MDOC_Fx,
MDOC_Ms,
MDOC_No,
MDOC_Ns,
MDOC_Nx,
MDOC_Ox,
MDOC_Pc,
MDOC_Pf,
MDOC_Po,
MDOC_Pq,
MDOC_Qc,
MDOC_Ql,
MDOC_Qo,
MDOC_Qq,
MDOC_Re,
MDOC_Rs,
MDOC_Sc,
MDOC_So,
MDOC_Sq,
MDOC_Sm,
MDOC_Sx,
MDOC_Sy,
MDOC_Tn,
MDOC_Ux,
MDOC_Xc,
MDOC_Xo,
MDOC_Fo,
MDOC_Fc,
MDOC_Oo,
MDOC_Oc,
MDOC_Bk,
MDOC_Ek,
MDOC_Bt,
MDOC_Hf,
MDOC_Fr,
MDOC_Ud,
MDOC_Lb,
MDOC_Lp,
MDOC_Lk,
MDOC_Mt,
MDOC_Brq,
MDOC_Bro,
MDOC_Brc,
MDOC__C,
MDOC_Es,
MDOC_En,
MDOC_Dx,
MDOC__Q,
MDOC_br,
MDOC_sp,
MDOC__U,
MDOC_Ta,
MDOC_ll,
MDOC_MAX
};
#define MDOC_Ap 0
#define MDOC_Dd 1
#define MDOC_Dt 2
#define MDOC_Os 3
#define MDOC_Sh 4
#define MDOC_Ss 5
#define MDOC_Pp 6
#define MDOC_D1 7
#define MDOC_Dl 8
#define MDOC_Bd 9
#define MDOC_Ed 10
#define MDOC_Bl 11
#define MDOC_El 12
#define MDOC_It 13
#define MDOC_Ad 14
#define MDOC_An 15
#define MDOC_Ar 16
#define MDOC_Cd 17
#define MDOC_Cm 18
#define MDOC_Dv 19
#define MDOC_Er 20
#define MDOC_Ev 21
#define MDOC_Ex 22
#define MDOC_Fa 23
#define MDOC_Fd 24
#define MDOC_Fl 25
#define MDOC_Fn 26
#define MDOC_Ft 27
#define MDOC_Ic 28
#define MDOC_In 29
#define MDOC_Li 30
#define MDOC_Nd 31
#define MDOC_Nm 32
#define MDOC_Op 33
#define MDOC_Ot 34
#define MDOC_Pa 35
#define MDOC_Rv 36
#define MDOC_St 37
#define MDOC_Va 38
#define MDOC_Vt 39
#define MDOC_Xr 40
#define MDOC__A 41
#define MDOC__B 42
#define MDOC__D 43
#define MDOC__I 44
#define MDOC__J 45
#define MDOC__N 46
#define MDOC__O 47
#define MDOC__P 48
#define MDOC__R 49
#define MDOC__T 50
#define MDOC__V 51
#define MDOC_Ac 52
#define MDOC_Ao 53
#define MDOC_Aq 54
#define MDOC_At 55
#define MDOC_Bc 56
#define MDOC_Bf 57
#define MDOC_Bo 58
#define MDOC_Bq 59
#define MDOC_Bsx 60
#define MDOC_Bx 61
#define MDOC_Db 62
#define MDOC_Dc 63
#define MDOC_Do 64
#define MDOC_Dq 65
#define MDOC_Ec 66
#define MDOC_Ef 67
#define MDOC_Em 68
#define MDOC_Eo 69
#define MDOC_Fx 70
#define MDOC_Ms 71
#define MDOC_No 72
#define MDOC_Ns 73
#define MDOC_Nx 74
#define MDOC_Ox 75
#define MDOC_Pc 76
#define MDOC_Pf 77
#define MDOC_Po 78
#define MDOC_Pq 79
#define MDOC_Qc 80
#define MDOC_Ql 81
#define MDOC_Qo 82
#define MDOC_Qq 83
#define MDOC_Re 84
#define MDOC_Rs 85
#define MDOC_Sc 86
#define MDOC_So 87
#define MDOC_Sq 88
#define MDOC_Sm 89
#define MDOC_Sx 90
#define MDOC_Sy 91
#define MDOC_Tn 92
#define MDOC_Ux 93
#define MDOC_Xc 94
#define MDOC_Xo 95
#define MDOC_Fo 96
#define MDOC_Fc 97
#define MDOC_Oo 98
#define MDOC_Oc 99
#define MDOC_Bk 100
#define MDOC_Ek 101
#define MDOC_Bt 102
#define MDOC_Hf 103
#define MDOC_Fr 104
#define MDOC_Ud 105
#define MDOC_Lb 106
#define MDOC_Lp 107
#define MDOC_Lk 108
#define MDOC_Mt 109
#define MDOC_Brq 110
#define MDOC_Bro 111
#define MDOC_Brc 112
#define MDOC__C 113
#define MDOC_Es 114
#define MDOC_En 115
#define MDOC_Dx 116
#define MDOC__Q 117
#define MDOC_br 118
#define MDOC_sp 119
#define MDOC__U 120
#define MDOC_Ta 121
#define MDOC_ll 122
#define MDOC_MAX 123
enum mdocargt {
MDOC_Split, /* -split */
@ -174,61 +172,6 @@ enum mdocargt {
MDOC_ARG_MAX
};
enum mdoc_type {
MDOC_TEXT,
MDOC_ELEM,
MDOC_HEAD,
MDOC_TAIL,
MDOC_BODY,
MDOC_BLOCK,
MDOC_TBL,
MDOC_EQN,
MDOC_ROOT
};
/*
* Section (named/unnamed) of `Sh'. Note that these appear in the
* conventional order imposed by mdoc.7. In the case of SEC_NONE, no
* section has been invoked (this shouldn't happen). SEC_CUSTOM refers
* to other sections.
*/
enum mdoc_sec {
SEC_NONE = 0,
SEC_NAME, /* NAME */
SEC_LIBRARY, /* LIBRARY */
SEC_SYNOPSIS, /* SYNOPSIS */
SEC_DESCRIPTION, /* DESCRIPTION */
SEC_CONTEXT, /* CONTEXT */
SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */
SEC_RETURN_VALUES, /* RETURN VALUES */
SEC_ENVIRONMENT, /* ENVIRONMENT */
SEC_FILES, /* FILES */
SEC_EXIT_STATUS, /* EXIT STATUS */
SEC_EXAMPLES, /* EXAMPLES */
SEC_DIAGNOSTICS, /* DIAGNOSTICS */
SEC_COMPATIBILITY, /* COMPATIBILITY */
SEC_ERRORS, /* ERRORS */
SEC_SEE_ALSO, /* SEE ALSO */
SEC_STANDARDS, /* STANDARDS */
SEC_HISTORY, /* HISTORY */
SEC_AUTHORS, /* AUTHORS */
SEC_CAVEATS, /* CAVEATS */
SEC_BUGS, /* BUGS */
SEC_SECURITY, /* SECURITY */
SEC_CUSTOM,
SEC__MAX
};
struct mdoc_meta {
char *msec; /* `Dt' section (1, 3p, etc.) */
char *vol; /* `Dt' volume (implied) */
char *arch; /* `Dt' arch (i386, etc.) */
char *date; /* `Dd' normalised date */
char *title; /* `Dt' title (FOO, etc.) */
char *os; /* `Os' system (OpenBSD, etc.) */
char *name; /* leading `Nm' name */
};
/*
* An argument to a macro (multiple values = `-column xxx yyy').
*/
@ -251,16 +194,6 @@ struct mdoc_arg {
unsigned int refcnt;
};
/*
* Indicates that a BODY's formatting has ended, but the scope is still
* open. Used for syntax-broken blocks.
*/
enum mdoc_endbody {
ENDBODY_NOT = 0,
ENDBODY_SPACE, /* is broken: append a space */
ENDBODY_NOSPACE /* is broken: don't append a space */
};
enum mdoc_list {
LIST__NONE = 0,
LIST_bullet, /* -bullet */
@ -337,59 +270,15 @@ union mdoc_data {
struct mdoc_bd Bd;
struct mdoc_bf Bf;
struct mdoc_bl Bl;
struct mdoc_node *Es;
struct roff_node *Es;
struct mdoc_rs Rs;
};
/*
* Single node in tree-linked AST.
*/
struct mdoc_node {
struct mdoc_node *parent; /* parent AST node */
struct mdoc_node *child; /* first child AST node */
struct mdoc_node *last; /* last child AST node */
struct mdoc_node *next; /* sibling AST node */
struct mdoc_node *prev; /* prior sibling AST node */
int nchild; /* number children */
int line; /* parse line */
int pos; /* parse column */
enum mdoct tok; /* tok or MDOC__MAX if none */
int flags;
#define MDOC_VALID (1 << 0) /* has been validated */
#define MDOC_ENDED (1 << 1) /* gone past body end mark */
#define MDOC_EOS (1 << 2) /* at sentence boundary */
#define MDOC_LINE (1 << 3) /* first macro/text on line */
#define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting */
#define MDOC_BROKEN (1 << 5) /* must validate parent when ending */
#define MDOC_DELIMO (1 << 6)
#define MDOC_DELIMC (1 << 7)
enum mdoc_type type; /* AST node type */
enum mdoc_sec sec; /* current named section */
union mdoc_data *norm; /* normalised args */
int prev_font; /* before entering this node */
/* FIXME: these can be union'd to shave a few bytes. */
struct mdoc_arg *args; /* BLOCK/ELEM */
struct mdoc_node *head; /* BLOCK */
struct mdoc_node *body; /* BLOCK/ENDBODY */
struct mdoc_node *tail; /* BLOCK */
char *string; /* TEXT */
const struct tbl_span *span; /* TBL */
const struct eqn *eqn; /* EQN */
enum mdoc_endbody end; /* BODY */
};
/* Names of macros. Index is enum mdoct. */
/* Names of macros. */
extern const char *const *mdoc_macronames;
/* Names of macro args. Index is enum mdocargt. */
extern const char *const *mdoc_argnames;
__BEGIN_DECLS
struct mdoc;
const struct mdoc_node *mdoc_node(const struct mdoc *);
const struct mdoc_meta *mdoc_meta(const struct mdoc *);
void mdoc_deroff(char **, const struct mdoc_node *);
__END_DECLS
void mdoc_validate(struct roff_man *);

View File

@ -1,15 +1,15 @@
/* $Id: mdoc_argv.c,v 1.100 2015/02/04 18:59:45 schwarze Exp $ */
/* $Id: mdoc_argv.c,v 1.107 2015/10/17 00:21:07 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2012, 2014, 2015 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -24,11 +24,12 @@
#include <stdio.h>
#include <string.h>
#include "mdoc.h"
#include "mandoc.h"
#include "mandoc_aux.h"
#include "libmdoc.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
#include "libmdoc.h"
#define MULTI_STEP 5 /* pre-allocate argument values */
#define DELIMSZ 6 /* max possible size of a delimiter */
@ -51,12 +52,12 @@ struct mdocarg {
};
static void argn_free(struct mdoc_arg *, int);
static enum margserr args(struct mdoc *, int, int *,
static enum margserr args(struct roff_man *, int, int *,
char *, enum argsflag, char **);
static int args_checkpunct(const char *, int);
static void argv_multi(struct mdoc *, int,
static void argv_multi(struct roff_man *, int,
struct mdoc_argv *, int *, char *);
static void argv_single(struct mdoc *, int,
static void argv_single(struct roff_man *, int,
struct mdoc_argv *, int *, char *);
static const enum argvflag argvflags[MDOC_ARG_MAX] = {
@ -275,7 +276,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
* Some flags take no argument, some one, some multiple.
*/
void
mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
mdoc_argv(struct roff_man *mdoc, int line, int tok,
struct mdoc_arg **reta, int *pos, char *buf)
{
struct mdoc_argv tmpv;
@ -412,18 +413,18 @@ argn_free(struct mdoc_arg *p, int iarg)
}
enum margserr
mdoc_args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum mdoct tok, char **v)
mdoc_args(struct roff_man *mdoc, int line, int *pos,
char *buf, int tok, char **v)
{
struct mdoc_node *n;
struct roff_node *n;
char *v_local;
enum argsflag fl;
if (v == NULL)
v = &v_local;
fl = tok == MDOC_MAX ? ARGSFL_NONE : mdocargs[tok].flags;
fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags;
if (tok != MDOC_It)
return(args(mdoc, line, pos, buf, fl, v));
return args(mdoc, line, pos, buf, fl, v);
/*
* We know that we're in an `It', so it's reasonable to expect
@ -439,105 +440,82 @@ mdoc_args(struct mdoc *mdoc, int line, int *pos,
break;
}
return(args(mdoc, line, pos, buf, fl, v));
return args(mdoc, line, pos, buf, fl, v);
}
static enum margserr
args(struct mdoc *mdoc, int line, int *pos,
args(struct roff_man *mdoc, int line, int *pos,
char *buf, enum argsflag fl, char **v)
{
char *p, *pp;
char *p;
int pairs;
enum margserr rc;
if ('\0' == buf[*pos]) {
if (MDOC_PPHRASE & mdoc->flags)
return(ARGS_EOLN);
/*
* If we're not in a partial phrase and the flag for
* being a phrase literal is still set, the punctuation
* is unterminated.
*/
if (MDOC_PHRASELIT & mdoc->flags)
if (buf[*pos] == '\0') {
if (mdoc->flags & MDOC_PHRASELIT &&
! (mdoc->flags & MDOC_PHRASE)) {
mandoc_msg(MANDOCERR_ARG_QUOTE,
mdoc->parse, line, *pos, NULL);
mdoc->flags &= ~MDOC_PHRASELIT;
return(ARGS_EOLN);
mdoc->flags &= ~MDOC_PHRASELIT;
}
return ARGS_EOLN;
}
*v = &buf[*pos];
*v = buf + *pos;
if (ARGSFL_DELIM == fl)
if (args_checkpunct(buf, *pos))
return(ARGS_PUNCT);
if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos))
return ARGS_PUNCT;
/*
* First handle TABSEP items, restricted to `Bl -column'. This
* ignores conventional token parsing and instead uses tabs or
* `Ta' macros to separate phrases. Phrases are parsed again
* for arguments at a later phase.
* Tabs in `It' lines in `Bl -column' can't be escaped.
* Phrases are reparsed for `Ta' and other macros later.
*/
if (ARGSFL_TABSEP == fl) {
/* Scan ahead to tab (can't be escaped). */
p = strchr(*v, '\t');
pp = NULL;
if (fl == ARGSFL_TABSEP) {
if ((p = strchr(*v, '\t')) != NULL) {
/* Scan ahead to unescaped `Ta'. */
if ( ! (MDOC_PHRASELIT & mdoc->flags))
for (pp = *v; ; pp++) {
if (NULL == (pp = strstr(pp, "Ta")))
break;
if (pp > *v && ' ' != *(pp - 1))
continue;
if (' ' == *(pp + 2) || '\0' == *(pp + 2))
break;
}
/*
* Words right before and right after
* tab characters are not parsed,
* unless there is a blank in between.
*/
/* By default, assume a phrase. */
rc = ARGS_PHRASE;
if (p[-1] != ' ')
mdoc->flags |= MDOC_PHRASEQL;
if (p[1] != ' ')
mdoc->flags |= MDOC_PHRASEQN;
/*
* Adjust new-buffer position to be beyond delimiter
* mark (e.g., Ta -> end + 2).
*/
if (p && pp) {
*pos += pp < p ? 2 : 1;
rc = pp < p ? ARGS_PHRASE : ARGS_PPHRASE;
p = pp < p ? pp : p;
} else if (p && ! pp) {
rc = ARGS_PPHRASE;
*pos += 1;
} else if (pp && ! p) {
p = pp;
*pos += 2;
/*
* One or more blanks after a tab cause
* one leading blank in the next column.
* So skip all but one of them.
*/
*pos += (int)(p - *v) + 1;
while (buf[*pos] == ' ' && buf[*pos + 1] == ' ')
(*pos)++;
/*
* A tab at the end of an input line
* switches to the next column.
*/
if (buf[*pos] == '\0' || buf[*pos + 1] == '\0')
mdoc->flags |= MDOC_PHRASEQN;
} else {
rc = ARGS_PEND;
p = strchr(*v, 0);
p = strchr(*v, '\0');
if (p[-1] == ' ')
mandoc_msg(MANDOCERR_SPACE_EOL,
mdoc->parse, line, *pos, NULL);
*pos += (int)(p - *v);
}
/* Whitespace check for eoln case... */
if ('\0' == *p && ' ' == *(p - 1))
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, *pos, NULL);
/* Skip any trailing blank characters. */
while (p > *v && p[-1] == ' ' &&
(p - 1 == *v || p[-2] != '\\'))
p--;
*p = '\0';
*pos += (int)(p - *v);
/* Strip delimiter's preceding whitespace. */
pp = p - 1;
while (pp > *v && ' ' == *pp) {
if (pp > *v && '\\' == *(pp - 1))
break;
pp--;
}
*(pp + 1) = 0;
/* Strip delimiter's proceeding whitespace. */
for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++)
/* Skip ahead. */ ;
return(rc);
return ARGS_PHRASE;
}
/*
@ -548,11 +526,11 @@ args(struct mdoc *mdoc, int line, int *pos,
* Whitespace is NOT involved in literal termination.
*/
if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) {
if ( ! (MDOC_PHRASELIT & mdoc->flags))
if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') {
if ( ! (mdoc->flags & MDOC_PHRASELIT))
*v = &buf[++(*pos)];
if (MDOC_PPHRASE & mdoc->flags)
if (mdoc->flags & MDOC_PHRASE)
mdoc->flags |= MDOC_PHRASELIT;
pairs = 0;
@ -572,19 +550,18 @@ args(struct mdoc *mdoc, int line, int *pos,
if (pairs)
buf[*pos - pairs] = '\0';
if ('\0' == buf[*pos]) {
if (MDOC_PPHRASE & mdoc->flags)
return(ARGS_QWORD);
mandoc_msg(MANDOCERR_ARG_QUOTE,
mdoc->parse, line, *pos, NULL);
return(ARGS_QWORD);
if (buf[*pos] == '\0') {
if ( ! (mdoc->flags & MDOC_PHRASE))
mandoc_msg(MANDOCERR_ARG_QUOTE,
mdoc->parse, line, *pos, NULL);
return ARGS_QWORD;
}
mdoc->flags &= ~MDOC_PHRASELIT;
buf[(*pos)++] = '\0';
if ('\0' == buf[*pos])
return(ARGS_QWORD);
return ARGS_QWORD;
while (' ' == buf[*pos])
(*pos)++;
@ -593,13 +570,22 @@ args(struct mdoc *mdoc, int line, int *pos,
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, *pos, NULL);
return(ARGS_QWORD);
return ARGS_QWORD;
}
p = &buf[*pos];
*v = mandoc_getarg(mdoc->parse, &p, line, pos);
return(ARGS_WORD);
/*
* After parsing the last word in this phrase,
* tell lookup() whether or not to interpret it.
*/
if (*p == '\0' && mdoc->flags & MDOC_PHRASEQL) {
mdoc->flags &= ~MDOC_PHRASEQL;
mdoc->flags |= MDOC_PHRASEQF;
}
return ARGS_WORD;
}
/*
@ -621,11 +607,11 @@ args_checkpunct(const char *buf, int i)
dbuf[j] = buf[i];
if (DELIMSZ == j)
return(0);
return 0;
dbuf[j] = '\0';
if (DELIM_CLOSE != mdoc_isdelim(dbuf))
return(0);
return 0;
while (' ' == buf[i])
i++;
@ -638,22 +624,22 @@ args_checkpunct(const char *buf, int i)
dbuf[j++] = buf[i++];
if (DELIMSZ == j)
return(0);
return 0;
dbuf[j] = '\0';
d = mdoc_isdelim(dbuf);
if (DELIM_NONE == d || DELIM_OPEN == d)
return(0);
return 0;
while (' ' == buf[i])
i++;
}
return('\0' == buf[i]);
return '\0' == buf[i];
}
static void
argv_multi(struct mdoc *mdoc, int line,
argv_multi(struct roff_man *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
@ -675,7 +661,7 @@ argv_multi(struct mdoc *mdoc, int line,
}
static void
argv_single(struct mdoc *mdoc, int line,
argv_single(struct roff_man *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;

View File

@ -1,6 +1,7 @@
/* $Id: mdoc_hash.c,v 1.21 2014/08/10 23:54:41 schwarze Exp $ */
/* $Id: mdoc_hash.c,v 1.26 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2015 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
@ -25,22 +26,22 @@
#include <stdio.h>
#include <string.h>
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
static unsigned char table[27 * 12];
/*
* XXX - this hash has global scope, so if intended for use as a library
* with multiple callers, it will need re-invocation protection.
*/
void
mdoc_hash_init(void)
{
int i, j, major;
const char *p;
if (*table != '\0')
return;
memset(table, UCHAR_MAX, sizeof(table));
for (i = 0; i < (int)MDOC_MAX; i++) {
@ -61,32 +62,32 @@ mdoc_hash_init(void)
}
}
enum mdoct
int
mdoc_hash_find(const char *p)
{
int major, i, j;
if (0 == p[0])
return(MDOC_MAX);
return TOKEN_NONE;
if ( ! isalpha((unsigned char)p[0]) && '%' != p[0])
return(MDOC_MAX);
return TOKEN_NONE;
if (isalpha((unsigned char)p[1]))
major = 12 * (tolower((unsigned char)p[1]) - 97);
else if ('1' == p[1])
major = 12 * 26;
else
return(MDOC_MAX);
return TOKEN_NONE;
if (p[2] && p[3])
return(MDOC_MAX);
return TOKEN_NONE;
for (j = 0; j < 12; j++) {
if (UCHAR_MAX == (i = table[major + j]))
break;
if (0 == strcmp(p, mdoc_macronames[i]))
return((enum mdoct)i);
return i;
}
return(MDOC_MAX);
return TOKEN_NONE;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_macro.c,v 1.183 2015/02/12 12:24:33 schwarze Exp $ */
/* $Id: mdoc_macro.c,v 1.206 2015/10/20 02:01:32 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -7,9 +7,9 @@
* 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
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -26,10 +26,12 @@
#include <string.h>
#include <time.h>
#include "mdoc.h"
#include "mandoc.h"
#include "libmdoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
#include "roff_int.h"
#include "libmdoc.h"
static void blk_full(MACRO_PROT_ARGS);
static void blk_exp_close(MACRO_PROT_ARGS);
@ -41,18 +43,19 @@ static void in_line_argn(MACRO_PROT_ARGS);
static void in_line(MACRO_PROT_ARGS);
static void phrase_ta(MACRO_PROT_ARGS);
static void dword(struct mdoc *, int, int, const char *,
enum mdelim, int);
static void append_delims(struct mdoc *, int, int *, char *);
static enum mdoct lookup(struct mdoc *, enum mdoct,
int, int, const char *);
static void append_delims(struct roff_man *, int, int *, char *);
static void dword(struct roff_man *, int, int, const char *,
enum mdelim, int);
static int find_pending(struct roff_man *, int, int, int,
struct roff_node *);
static int lookup(struct roff_man *, int, int, int, const char *);
static int macro_or_word(MACRO_PROT_ARGS, int);
static int parse_rest(struct mdoc *, enum mdoct,
int, int *, char *);
static enum mdoct rew_alt(enum mdoct);
static void rew_elem(struct mdoc *, enum mdoct);
static void rew_last(struct mdoc *, const struct mdoc_node *);
static void rew_pending(struct mdoc *, const struct mdoc_node *);
static int parse_rest(struct roff_man *, int, int, int *, char *);
static int rew_alt(int);
static void rew_elem(struct roff_man *, int);
static void rew_last(struct roff_man *, const struct roff_node *);
static void rew_pending(struct roff_man *,
const struct roff_node *);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
@ -207,9 +210,9 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
* are errors.
*/
void
mdoc_macroend(struct mdoc *mdoc)
mdoc_endparse(struct roff_man *mdoc)
{
struct mdoc_node *n;
struct roff_node *n;
/* Scan for open explicit scopes. */
@ -217,7 +220,7 @@ mdoc_macroend(struct mdoc *mdoc)
mdoc->last->parent : mdoc->last;
for ( ; n; n = n->parent)
if (n->type == MDOC_BLOCK &&
if (n->type == ROFFT_BLOCK &&
mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
@ -225,86 +228,87 @@ mdoc_macroend(struct mdoc *mdoc)
/* Rewind to the first. */
rew_last(mdoc, mdoc->first);
mdoc_state_reset(mdoc);
}
/*
* Look up the macro at *p called by "from",
* or as a line macro if from == MDOC_MAX.
* or as a line macro if from == TOKEN_NONE.
*/
static enum mdoct
lookup(struct mdoc *mdoc, enum mdoct from, int line, int ppos, const char *p)
static int
lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
{
enum mdoct res;
int res;
if (from == MDOC_MAX || mdoc_macros[from].flags & MDOC_PARSED) {
if (mdoc->flags & MDOC_PHRASEQF) {
mdoc->flags &= ~MDOC_PHRASEQF;
return TOKEN_NONE;
}
if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
res = mdoc_hash_find(p);
if (res != MDOC_MAX) {
if (res != TOKEN_NONE) {
if (mdoc_macros[res].flags & MDOC_CALLABLE)
return(res);
return res;
if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll)
mandoc_msg(MANDOCERR_MACRO_CALL,
mdoc->parse, line, ppos, p);
}
}
return(MDOC_MAX);
return TOKEN_NONE;
}
/*
* Rewind up to and including a specific node.
*/
static void
rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
rew_last(struct roff_man *mdoc, const struct roff_node *to)
{
struct mdoc_node *n, *np;
assert(to);
mdoc->next = MDOC_NEXT_SIBLING;
if (to->flags & MDOC_VALID)
return;
while (mdoc->last != to) {
/*
* Save the parent here, because we may delete the
* mdoc->last node in the post-validation phase and reset
* it to mdoc->last->parent, causing a step in the closing
* out to be lost.
*/
np = mdoc->last->parent;
mdoc_valid_post(mdoc);
n = mdoc->last;
mdoc->last = np;
assert(mdoc->last);
mdoc->last->last = n;
mdoc_state(mdoc, mdoc->last);
mdoc->last->flags |= MDOC_VALID | MDOC_ENDED;
mdoc->last = mdoc->last->parent;
}
mdoc_valid_post(mdoc);
mdoc_state(mdoc, mdoc->last);
mdoc->last->flags |= MDOC_VALID | MDOC_ENDED;
mdoc->next = ROFF_NEXT_SIBLING;
}
/*
* Rewind up to a specific block, including all blocks that broke it.
*/
static void
rew_pending(struct mdoc *mdoc, const struct mdoc_node *n)
rew_pending(struct roff_man *mdoc, const struct roff_node *n)
{
for (;;) {
rew_last(mdoc, n);
switch (n->type) {
case MDOC_HEAD:
mdoc_body_alloc(mdoc, n->line, n->pos, n->tok);
return;
case MDOC_BLOCK:
break;
default:
return;
}
if ( ! (n->flags & MDOC_BROKEN))
return;
if (mdoc->last == n) {
switch (n->type) {
case ROFFT_HEAD:
roff_body_alloc(mdoc, n->line, n->pos,
n->tok);
return;
case ROFFT_BLOCK:
break;
default:
return;
}
if ( ! (n->flags & MDOC_BROKEN))
return;
} else
n = mdoc->last;
for (;;) {
if ((n = n->parent) == NULL)
return;
if (n->type == MDOC_BLOCK ||
n->type == MDOC_HEAD) {
if (n->type == ROFFT_BLOCK ||
n->type == ROFFT_HEAD) {
if (n->flags & MDOC_ENDED)
break;
else
@ -318,67 +322,104 @@ rew_pending(struct mdoc *mdoc, const struct mdoc_node *n)
* For a block closing macro, return the corresponding opening one.
* Otherwise, return the macro itself.
*/
static enum mdoct
rew_alt(enum mdoct tok)
static int
rew_alt(int tok)
{
switch (tok) {
case MDOC_Ac:
return(MDOC_Ao);
return MDOC_Ao;
case MDOC_Bc:
return(MDOC_Bo);
return MDOC_Bo;
case MDOC_Brc:
return(MDOC_Bro);
return MDOC_Bro;
case MDOC_Dc:
return(MDOC_Do);
return MDOC_Do;
case MDOC_Ec:
return(MDOC_Eo);
return MDOC_Eo;
case MDOC_Ed:
return(MDOC_Bd);
return MDOC_Bd;
case MDOC_Ef:
return(MDOC_Bf);
return MDOC_Bf;
case MDOC_Ek:
return(MDOC_Bk);
return MDOC_Bk;
case MDOC_El:
return(MDOC_Bl);
return MDOC_Bl;
case MDOC_Fc:
return(MDOC_Fo);
return MDOC_Fo;
case MDOC_Oc:
return(MDOC_Oo);
return MDOC_Oo;
case MDOC_Pc:
return(MDOC_Po);
return MDOC_Po;
case MDOC_Qc:
return(MDOC_Qo);
return MDOC_Qo;
case MDOC_Re:
return(MDOC_Rs);
return MDOC_Rs;
case MDOC_Sc:
return(MDOC_So);
return MDOC_So;
case MDOC_Xc:
return(MDOC_Xo);
return MDOC_Xo;
default:
return(tok);
return tok;
}
/* NOTREACHED */
}
static void
rew_elem(struct mdoc *mdoc, enum mdoct tok)
rew_elem(struct roff_man *mdoc, int tok)
{
struct mdoc_node *n;
struct roff_node *n;
n = mdoc->last;
if (MDOC_ELEM != n->type)
if (n->type != ROFFT_ELEM)
n = n->parent;
assert(MDOC_ELEM == n->type);
assert(n->type == ROFFT_ELEM);
assert(tok == n->tok);
rew_last(mdoc, n);
}
/*
* If there is an open sub-block of the target requiring
* explicit close-out, postpone closing out the target until
* the rew_pending() call closing out the sub-block.
*/
static int
find_pending(struct roff_man *mdoc, int tok, int line, int ppos,
struct roff_node *target)
{
struct roff_node *n;
int irc;
irc = 0;
for (n = mdoc->last; n != NULL && n != target; n = n->parent) {
if (n->flags & MDOC_ENDED) {
if ( ! (n->flags & MDOC_VALID))
n->flags |= MDOC_BROKEN;
continue;
}
if (n->type == ROFFT_BLOCK &&
mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
irc = 1;
n->flags = MDOC_BROKEN;
if (target->type == ROFFT_HEAD)
target->flags = MDOC_ENDED;
else if ( ! (target->flags & MDOC_ENDED)) {
mandoc_vmsg(MANDOCERR_BLK_NEST,
mdoc->parse, line, ppos,
"%s breaks %s", mdoc_macronames[tok],
mdoc_macronames[n->tok]);
mdoc_endbody_alloc(mdoc, line, ppos,
tok, target, ENDBODY_NOSPACE);
}
}
}
return irc;
}
/*
* Allocate a word and check whether it's punctuation or not.
* Punctuation consists of those tokens found in mdoc_isdelim().
*/
static void
dword(struct mdoc *mdoc, int line, int col, const char *p,
dword(struct roff_man *mdoc, int line, int col, const char *p,
enum mdelim d, int may_append)
{
@ -387,13 +428,13 @@ dword(struct mdoc *mdoc, int line, int col, const char *p,
if (may_append &&
! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) &&
d == DELIM_NONE && mdoc->last->type == MDOC_TEXT &&
d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT &&
mdoc_isdelim(mdoc->last->string) == DELIM_NONE) {
mdoc_word_append(mdoc, p);
roff_word_append(mdoc, p);
return;
}
mdoc_word_alloc(mdoc, line, col, p);
roff_word_alloc(mdoc, line, col, p);
/*
* If the word consists of a bare delimiter,
@ -412,7 +453,7 @@ dword(struct mdoc *mdoc, int line, int col, const char *p,
}
static void
append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
{
char *p;
int la;
@ -422,7 +463,8 @@ append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
for (;;) {
la = *pos;
if (mdoc_args(mdoc, line, pos, buf, MDOC_MAX, &p) == ARGS_EOLN)
if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) ==
ARGS_EOLN)
break;
dword(mdoc, line, la, p, DELIM_MAX, 1);
@ -452,26 +494,26 @@ static int
macro_or_word(MACRO_PROT_ARGS, int parsed)
{
char *p;
enum mdoct ntok;
int ntok;
p = buf + ppos;
ntok = MDOC_MAX;
ntok = TOKEN_NONE;
if (*p == '"')
p++;
else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
ntok = lookup(mdoc, tok, line, ppos, p);
if (ntok == MDOC_MAX) {
dword(mdoc, line, ppos, p, DELIM_MAX, tok == MDOC_MAX ||
if (ntok == TOKEN_NONE) {
dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
mdoc_macros[tok].flags & MDOC_JOIN);
return(0);
return 0;
} else {
if (mdoc_macros[tok].fp == in_line_eoln)
rew_elem(mdoc, tok);
mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
if (tok == MDOC_MAX)
if (tok == TOKEN_NONE)
append_delims(mdoc, line, pos, buf);
return(1);
return 1;
}
}
@ -481,15 +523,16 @@ macro_or_word(MACRO_PROT_ARGS, int parsed)
static void
blk_exp_close(MACRO_PROT_ARGS)
{
struct mdoc_node *body; /* Our own body. */
struct mdoc_node *endbody; /* Our own end marker. */
struct mdoc_node *itblk; /* An It block starting later. */
struct mdoc_node *later; /* A sub-block starting later. */
struct mdoc_node *n; /* Search back to our block. */
struct roff_node *body; /* Our own body. */
struct roff_node *endbody; /* Our own end marker. */
struct roff_node *itblk; /* An It block starting later. */
struct roff_node *later; /* A sub-block starting later. */
struct roff_node *n; /* Search back to our block. */
struct roff_node *target; /* For find_pending(). */
int j, lastarg, maxargs, nl;
int j, lastarg, maxargs, nl, pending;
enum margserr ac;
enum mdoct atok, ntok;
int atok, ntok;
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
@ -522,13 +565,13 @@ blk_exp_close(MACRO_PROT_ARGS)
/* Remember the start of our own body. */
if (n->type == MDOC_BODY && atok == n->tok) {
if (n->type == ROFFT_BODY && atok == n->tok) {
if (n->end == ENDBODY_NOT)
body = n;
continue;
}
if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm)
if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm)
continue;
if (n->tok == MDOC_It) {
@ -575,7 +618,7 @@ blk_exp_close(MACRO_PROT_ARGS)
*/
if (maxargs)
mdoc->next = MDOC_NEXT_CHILD;
mdoc->next = ROFF_NEXT_CHILD;
break;
}
@ -596,12 +639,14 @@ blk_exp_close(MACRO_PROT_ARGS)
if (body == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
line, ppos, mdoc_macronames[tok]);
if (later != NULL)
later->flags &= ~MDOC_BROKEN;
if (maxargs && endbody == NULL) {
/*
* Stray .Ec without previous .Eo:
* Break the output line, keep the arguments.
*/
mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
roff_elem_alloc(mdoc, line, ppos, MDOC_br);
rew_elem(mdoc, MDOC_br);
}
} else if (endbody == NULL) {
@ -623,38 +668,47 @@ blk_exp_close(MACRO_PROT_ARGS)
if (endbody != NULL)
n = endbody;
ntok = TOKEN_NONE;
for (j = 0; ; j++) {
lastarg = *pos;
if (j == maxargs && n != NULL) {
rew_pending(mdoc, n);
n = NULL;
}
if (j == maxargs && n != NULL)
rew_last(mdoc, n);
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
ntok = ac == ARGS_QWORD ? MDOC_MAX :
ntok = ac == ARGS_QWORD ? TOKEN_NONE :
lookup(mdoc, tok, line, lastarg, p);
if (ntok == MDOC_MAX) {
if (ntok == TOKEN_NONE) {
dword(mdoc, line, lastarg, p, DELIM_MAX,
MDOC_JOIN & mdoc_macros[tok].flags);
continue;
}
if (n != NULL) {
rew_pending(mdoc, n);
n = NULL;
}
if (n != NULL)
rew_last(mdoc, n);
mdoc->flags &= ~MDOC_NEWLINE;
mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
break;
}
if (n != NULL)
rew_pending(mdoc, n);
if (n != NULL) {
if (ntok != TOKEN_NONE && n->flags & MDOC_BROKEN) {
target = n;
do
target = target->parent;
while ( ! (target->flags & MDOC_ENDED));
pending = find_pending(mdoc, ntok, line, ppos,
target);
} else
pending = 0;
if ( ! pending)
rew_pending(mdoc, n);
}
if (nl)
append_delims(mdoc, line, pos, buf);
}
@ -663,7 +717,7 @@ static void
in_line(MACRO_PROT_ARGS)
{
int la, scope, cnt, firstarg, mayopen, nc, nl;
enum mdoct ntok;
int ntok;
enum margserr ac;
enum mdelim d;
struct mdoc_arg *arg;
@ -678,15 +732,10 @@ in_line(MACRO_PROT_ARGS)
switch (tok) {
case MDOC_An:
/* FALLTHROUGH */
case MDOC_Ar:
/* FALLTHROUGH */
case MDOC_Fl:
/* FALLTHROUGH */
case MDOC_Mt:
/* FALLTHROUGH */
case MDOC_Nm:
/* FALLTHROUGH */
case MDOC_Pa:
nc = 1;
break;
@ -730,7 +779,7 @@ in_line(MACRO_PROT_ARGS)
}
ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
MDOC_MAX : lookup(mdoc, tok, line, la, p);
TOKEN_NONE : lookup(mdoc, tok, line, la, p);
/*
* In this case, we've located a submacro and must
@ -739,7 +788,7 @@ in_line(MACRO_PROT_ARGS)
* or raise a warning.
*/
if (ntok != MDOC_MAX) {
if (ntok != TOKEN_NONE) {
if (scope)
rew_elem(mdoc, tok);
if (nc && ! cnt) {
@ -847,10 +896,10 @@ blk_full(MACRO_PROT_ARGS)
{
int la, nl, parsed;
struct mdoc_arg *arg;
struct mdoc_node *blk; /* Our own or a broken block. */
struct mdoc_node *head; /* Our own head. */
struct mdoc_node *body; /* Our own body. */
struct mdoc_node *n;
struct roff_node *blk; /* Our own or a broken block. */
struct roff_node *head; /* Our own head. */
struct roff_node *body; /* Our own body. */
struct roff_node *n;
enum margserr ac, lac;
char *p;
@ -873,7 +922,7 @@ blk_full(MACRO_PROT_ARGS)
n->flags |= MDOC_BROKEN;
continue;
}
if (n->type != MDOC_BLOCK)
if (n->type != ROFFT_BLOCK)
continue;
if (tok == MDOC_It && n->tok == MDOC_Bl) {
@ -890,7 +939,6 @@ blk_full(MACRO_PROT_ARGS)
if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
switch (tok) {
case MDOC_Sh:
/* FALLTHROUGH */
case MDOC_Ss:
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos,
@ -938,7 +986,7 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
line, ppos, "It %s", buf + *pos);
mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
roff_elem_alloc(mdoc, line, ppos, MDOC_br);
rew_elem(mdoc, MDOC_br);
return;
}
@ -972,34 +1020,47 @@ blk_full(MACRO_PROT_ARGS)
*/
if (tok == MDOC_Nd) {
head = mdoc_head_alloc(mdoc, line, ppos, tok);
head = roff_head_alloc(mdoc, line, ppos, tok);
rew_last(mdoc, head);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
body = roff_body_alloc(mdoc, line, ppos, tok);
}
if (tok == MDOC_Bk)
mdoc->flags |= MDOC_KEEP;
ac = ARGS_PEND;
ac = ARGS_EOLN;
for (;;) {
/*
* If we are right after a tab character,
* do not parse the first word for macros.
*/
if (mdoc->flags & MDOC_PHRASEQN) {
mdoc->flags &= ~MDOC_PHRASEQN;
mdoc->flags |= MDOC_PHRASEQF;
}
la = *pos;
lac = ac;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
if (ac == ARGS_EOLN) {
if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE)
if (lac != ARGS_PHRASE ||
! (mdoc->flags & MDOC_PHRASEQF))
break;
/*
* This is necessary: if the last token on a
* line is a `Ta' or tab, then we'll get
* ARGS_EOLN, so we must be smart enough to
* reopen our scope if the last parse was a
* phrase or partial phrase.
* This line ends in a tab; start the next
* column now, with a leading blank.
*/
if (body != NULL)
rew_last(mdoc, body);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
body = roff_body_alloc(mdoc, line, ppos, tok);
roff_word_alloc(mdoc, line, ppos, "\\&");
break;
}
if (tok == MDOC_Bd || tok == MDOC_Bk) {
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
mdoc->parse, line, la, "%s ... %s",
@ -1016,13 +1077,11 @@ blk_full(MACRO_PROT_ARGS)
/*
* Emit leading punctuation (i.e., punctuation before
* the MDOC_HEAD) for non-phrase types.
* the ROFFT_HEAD) for non-phrase types.
*/
if (head == NULL &&
ac != ARGS_PEND &&
ac != ARGS_PHRASE &&
ac != ARGS_PPHRASE &&
ac != ARGS_QWORD &&
mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
@ -1032,11 +1091,9 @@ blk_full(MACRO_PROT_ARGS)
/* Open a head if one hasn't been opened. */
if (head == NULL)
head = mdoc_head_alloc(mdoc, line, ppos, tok);
head = roff_head_alloc(mdoc, line, ppos, tok);
if (ac == ARGS_PHRASE ||
ac == ARGS_PEND ||
ac == ARGS_PPHRASE) {
if (ac == ARGS_PHRASE) {
/*
* If we haven't opened a body yet, rewind the
@ -1044,20 +1101,18 @@ blk_full(MACRO_PROT_ARGS)
*/
rew_last(mdoc, body == NULL ? head : body);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
body = roff_body_alloc(mdoc, line, ppos, tok);
/*
* Process phrases: set whether we're in a
* partial-phrase (this effects line handling)
* then call down into the phrase parser.
*/
/* Process to the tab or to the end of the line. */
if (ac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
if (ac == ARGS_PEND && lac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
parse_rest(mdoc, MDOC_MAX, line, &la, buf);
mdoc->flags &= ~MDOC_PPHRASE;
mdoc->flags |= MDOC_PHRASE;
parse_rest(mdoc, TOKEN_NONE, line, &la, buf);
mdoc->flags &= ~MDOC_PHRASE;
/* There may have been `Ta' macros. */
while (body->next != NULL)
body = body->next;
continue;
}
@ -1068,37 +1123,18 @@ blk_full(MACRO_PROT_ARGS)
if (blk->flags & MDOC_VALID)
return;
if (head == NULL)
head = mdoc_head_alloc(mdoc, line, ppos, tok);
head = roff_head_alloc(mdoc, line, ppos, tok);
if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
append_delims(mdoc, line, pos, buf);
if (body != NULL)
goto out;
/*
* If there is an open (i.e., unvalidated) sub-block requiring
* explicit close-out, postpone switching the current block from
* head to body until the rew_pending() call closing out that
* sub-block.
*/
for (n = mdoc->last; n && n != head; n = n->parent) {
if (n->flags & MDOC_ENDED) {
if ( ! (n->flags & MDOC_VALID))
n->flags |= MDOC_BROKEN;
continue;
}
if (n->type == MDOC_BLOCK &&
mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
n->flags = MDOC_BROKEN;
head->flags = MDOC_ENDED;
}
}
if (head->flags & MDOC_ENDED)
if (find_pending(mdoc, tok, line, ppos, head))
return;
/* Close out scopes to remain in a consistent state. */
rew_last(mdoc, head);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
body = roff_body_alloc(mdoc, line, ppos, tok);
out:
if (mdoc->flags & MDOC_FREECOL) {
rew_last(mdoc, body);
@ -1113,9 +1149,9 @@ blk_part_imp(MACRO_PROT_ARGS)
int la, nl;
enum margserr ac;
char *p;
struct mdoc_node *blk; /* saved block context */
struct mdoc_node *body; /* saved body context */
struct mdoc_node *n;
struct roff_node *blk; /* saved block context */
struct roff_node *body; /* saved body context */
struct roff_node *n;
nl = MDOC_NEWLINE & mdoc->flags;
@ -1129,7 +1165,7 @@ blk_part_imp(MACRO_PROT_ARGS)
*/
blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok));
rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
/*
* Open the body scope "on-demand", that is, after we've
@ -1150,42 +1186,15 @@ blk_part_imp(MACRO_PROT_ARGS)
}
if (body == NULL)
body = mdoc_body_alloc(mdoc, line, ppos, tok);
body = roff_body_alloc(mdoc, line, ppos, tok);
if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
break;
}
if (body == NULL)
body = mdoc_body_alloc(mdoc, line, ppos, tok);
body = roff_body_alloc(mdoc, line, ppos, tok);
/*
* If there is an open sub-block requiring explicit close-out,
* postpone closing out the current block until the
* rew_pending() call closing out the sub-block.
*/
for (n = mdoc->last; n && n != body && n != blk->parent;
n = n->parent) {
if (n->flags & MDOC_ENDED) {
if ( ! (n->flags & MDOC_VALID))
n->flags |= MDOC_BROKEN;
continue;
}
if (n->type == MDOC_BLOCK &&
mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
n->flags |= MDOC_BROKEN;
if ( ! (body->flags & MDOC_ENDED)) {
mandoc_vmsg(MANDOCERR_BLK_NEST,
mdoc->parse, line, ppos,
"%s breaks %s", mdoc_macronames[tok],
mdoc_macronames[n->tok]);
mdoc_endbody_alloc(mdoc, line, ppos,
tok, body, ENDBODY_NOSPACE);
}
}
}
assert(n == body);
if (body->flags & MDOC_ENDED)
if (find_pending(mdoc, tok, line, ppos, body))
return;
rew_last(mdoc, body);
@ -1206,7 +1215,7 @@ blk_part_exp(MACRO_PROT_ARGS)
{
int la, nl;
enum margserr ac;
struct mdoc_node *head; /* keep track of head */
struct roff_node *head; /* keep track of head */
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
@ -1217,7 +1226,7 @@ blk_part_exp(MACRO_PROT_ARGS)
* case of `Eo'); and a body that may be empty.
*/
mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
roff_block_alloc(mdoc, line, ppos, tok);
head = NULL;
for (;;) {
la = *pos;
@ -1234,11 +1243,11 @@ blk_part_exp(MACRO_PROT_ARGS)
}
if (head == NULL) {
head = mdoc_head_alloc(mdoc, line, ppos, tok);
head = roff_head_alloc(mdoc, line, ppos, tok);
if (tok == MDOC_Eo) /* Not parsed. */
dword(mdoc, line, la, p, DELIM_MAX, 0);
rew_last(mdoc, head);
mdoc_body_alloc(mdoc, line, ppos, tok);
roff_body_alloc(mdoc, line, ppos, tok);
if (tok == MDOC_Eo)
continue;
}
@ -1250,8 +1259,8 @@ blk_part_exp(MACRO_PROT_ARGS)
/* Clean-up to leave in a consistent state. */
if (head == NULL) {
rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok));
mdoc_body_alloc(mdoc, line, ppos, tok);
rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
roff_body_alloc(mdoc, line, ppos, tok);
}
if (nl)
append_delims(mdoc, line, pos, buf);
@ -1263,7 +1272,7 @@ in_line_argn(MACRO_PROT_ARGS)
struct mdoc_arg *arg;
char *p;
enum margserr ac;
enum mdoct ntok;
int ntok;
int state; /* arg#; -1: not yet open; -2: closed */
int la, maxargs, nl;
@ -1279,16 +1288,12 @@ in_line_argn(MACRO_PROT_ARGS)
switch (tok) {
case MDOC_Ap:
/* FALLTHROUGH */
case MDOC_Ns:
/* FALLTHROUGH */
case MDOC_Ux:
maxargs = 0;
break;
case MDOC_Bx:
/* FALLTHROUGH */
case MDOC_Es:
/* FALLTHROUGH */
case MDOC_Xr:
maxargs = 2;
break;
@ -1332,9 +1337,9 @@ in_line_argn(MACRO_PROT_ARGS)
}
ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ?
MDOC_MAX : lookup(mdoc, tok, line, la, p);
TOKEN_NONE : lookup(mdoc, tok, line, la, p);
if (ntok != MDOC_MAX) {
if (ntok != TOKEN_NONE) {
if (state >= 0) {
rew_elem(mdoc, tok);
state = -2;
@ -1377,16 +1382,16 @@ in_line_argn(MACRO_PROT_ARGS)
static void
in_line_eoln(MACRO_PROT_ARGS)
{
struct mdoc_node *n;
struct roff_node *n;
struct mdoc_arg *arg;
if ((tok == MDOC_Pp || tok == MDOC_Lp) &&
! (mdoc->flags & MDOC_SYNOPSIS)) {
n = mdoc->last;
if (mdoc->next == MDOC_NEXT_SIBLING)
if (mdoc->next == ROFF_NEXT_SIBLING)
n = n->parent;
if (n->tok == MDOC_Nm)
rew_last(mdoc, mdoc->last->parent);
rew_last(mdoc, n->parent);
}
if (buf[*pos] == '\0' &&
@ -1409,16 +1414,16 @@ in_line_eoln(MACRO_PROT_ARGS)
* or until the next macro, call that macro, and return 1.
*/
static int
parse_rest(struct mdoc *mdoc, enum mdoct tok, int line, int *pos, char *buf)
parse_rest(struct roff_man *mdoc, int tok, int line, int *pos, char *buf)
{
int la;
for (;;) {
la = *pos;
if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
return(0);
return 0;
if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
return(1);
return 1;
}
}
@ -1444,7 +1449,7 @@ ctx_synopsis(MACRO_PROT_ARGS)
static void
phrase_ta(MACRO_PROT_ARGS)
{
struct mdoc_node *body, *n;
struct roff_node *body, *n;
/* Make sure we are in a column list or ignore this macro. */
@ -1452,7 +1457,7 @@ phrase_ta(MACRO_PROT_ARGS)
for (n = mdoc->last; n != NULL; n = n->parent) {
if (n->flags & MDOC_ENDED)
continue;
if (n->tok == MDOC_It && n->type == MDOC_BODY)
if (n->tok == MDOC_It && n->type == ROFFT_BODY)
body = n;
if (n->tok == MDOC_Bl)
break;
@ -1467,6 +1472,6 @@ phrase_ta(MACRO_PROT_ARGS)
/* Advance to the next column. */
rew_last(mdoc, body);
mdoc_body_alloc(mdoc, line, ppos, MDOC_It);
parse_rest(mdoc, MDOC_MAX, line, pos, buf);
roff_body_alloc(mdoc, line, ppos, MDOC_It);
parse_rest(mdoc, TOKEN_NONE, line, pos, buf);
}

View File

@ -1,6 +1,6 @@
/* $Id: mdoc_man.c,v 1.88 2015/02/17 20:37:17 schwarze Exp $ */
/* $Id: mdoc_man.c,v 1.96 2016/01/08 17:48:09 schwarze Exp $ */
/*
* Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011-2016 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -22,14 +22,15 @@
#include <stdio.h>
#include <string.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "out.h"
#include "man.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "out.h"
#include "main.h"
#define DECL_ARGS const struct mdoc_meta *meta, struct mdoc_node *n
#define DECL_ARGS const struct roff_meta *meta, struct roff_node *n
struct manact {
int (*cond)(DECL_ARGS); /* DON'T run actions */
@ -107,7 +108,7 @@ static int pre_sm(DECL_ARGS);
static int pre_sp(DECL_ARGS);
static int pre_sect(DECL_ARGS);
static int pre_sy(DECL_ARGS);
static void pre_syn(const struct mdoc_node *);
static void pre_syn(const struct roff_node *);
static int pre_vt(DECL_ARGS);
static int pre_ux(DECL_ARGS);
static int pre_xr(DECL_ARGS);
@ -116,7 +117,7 @@ static void print_line(const char *, int);
static void print_block(const char *, int);
static void print_offs(const char *, int);
static void print_width(const struct mdoc_bl *,
const struct mdoc_node *);
const struct roff_node *);
static void print_count(int *);
static void print_node(DECL_ARGS);
@ -467,7 +468,7 @@ print_offs(const char *v, int keywords)
* Set up the indentation for a list item; used from pre_it().
*/
static void
print_width(const struct mdoc_bl *bl, const struct mdoc_node *child)
print_width(const struct mdoc_bl *bl, const struct roff_node *child)
{
char buf[24];
struct roffsu su;
@ -492,7 +493,7 @@ print_width(const struct mdoc_bl *bl, const struct mdoc_node *child)
/* XXX Rough estimation, might have multiple parts. */
if (bl->type == LIST_enum)
chsz = (bl->count > 8) + 1;
else if (child != NULL && child->type == MDOC_TEXT)
else if (child != NULL && child->type == ROFFT_TEXT)
chsz = strlen(child->string);
else
chsz = 0;
@ -531,7 +532,7 @@ print_count(int *count)
}
void
man_man(void *arg, const struct man *man)
man_man(void *arg, const struct roff_man *man)
{
/*
@ -544,18 +545,14 @@ man_man(void *arg, const struct man *man)
}
void
man_mdoc(void *arg, const struct mdoc *mdoc)
man_mdoc(void *arg, const struct roff_man *mdoc)
{
const struct mdoc_meta *meta;
struct mdoc_node *n;
meta = mdoc_meta(mdoc);
n = mdoc_node(mdoc)->child;
struct roff_node *n;
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
meta->title,
(meta->msec == NULL ? "" : meta->msec),
meta->date, meta->os, meta->vol);
mdoc->meta.title,
(mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
/* Disable hyphenation and if nroff, disable justification. */
printf(".nh\n.if n .ad l");
@ -566,10 +563,8 @@ man_mdoc(void *arg, const struct mdoc *mdoc)
fontqueue.head = fontqueue.tail = mandoc_malloc(8);
*fontqueue.tail = 'R';
}
while (n != NULL) {
print_node(meta, n);
n = n->next;
}
for (n = mdoc->first->child; n != NULL; n = n->next)
print_node(&mdoc->meta, n);
putchar('\n');
}
@ -577,7 +572,7 @@ static void
print_node(DECL_ARGS)
{
const struct manact *act;
struct mdoc_node *sub;
struct roff_node *sub;
int cond, do_sub;
/*
@ -592,7 +587,7 @@ print_node(DECL_ARGS)
do_sub = 1;
n->flags &= ~MDOC_ENDED;
if (MDOC_TEXT == n->type) {
if (n->type == ROFFT_TEXT) {
/*
* Make sure that we don't happen to start with a
* control character at the start of a line.
@ -615,7 +610,8 @@ print_node(DECL_ARGS)
*/
act = manacts + n->tok;
cond = act->cond == NULL || (*act->cond)(meta, n);
if (cond && act->pre && (n->end == ENDBODY_NOT || n->nchild))
if (cond && act->pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
do_sub = (*act->pre)(meta, n);
}
@ -648,14 +644,14 @@ static int
cond_head(DECL_ARGS)
{
return(MDOC_HEAD == n->type);
return n->type == ROFFT_HEAD;
}
static int
cond_body(DECL_ARGS)
{
return(MDOC_BODY == n->type);
return n->type == ROFFT_BODY;
}
static int
@ -665,10 +661,10 @@ pre_enc(DECL_ARGS)
prefix = manacts[n->tok].prefix;
if (NULL == prefix)
return(1);
return 1;
print_word(prefix);
outflags &= ~MMAN_spc;
return(1);
return 1;
}
static void
@ -686,37 +682,36 @@ post_enc(DECL_ARGS)
static int
pre_ex(DECL_ARGS)
{
int nchild;
struct roff_node *nch;
outflags |= MMAN_br | MMAN_nl;
print_word("The");
nchild = n->nchild;
for (n = n->child; n; n = n->next) {
for (nch = n->child; nch != NULL; nch = nch->next) {
font_push('B');
print_word(n->string);
print_word(nch->string);
font_pop();
if (n->next == NULL)
if (nch->next == NULL)
continue;
if (nchild > 2) {
if (nch->prev != NULL || nch->next->next != NULL) {
outflags &= ~MMAN_spc;
print_word(",");
}
if (n->next->next == NULL)
if (nch->next->next == NULL)
print_word("and");
}
if (nchild > 1)
if (n->child != NULL && n->child->next != NULL)
print_word("utilities exit\\~0");
else
print_word("utility exits\\~0");
print_word("on success, and\\~>0 if an error occurs.");
outflags |= MMAN_nl;
return(0);
return 0;
}
static void
@ -754,7 +749,7 @@ pre__t(DECL_ARGS)
outflags &= ~MMAN_spc;
} else
font_push('I');
return(1);
return 1;
}
static void
@ -778,14 +773,14 @@ static int
pre_sect(DECL_ARGS)
{
if (MDOC_HEAD == n->type) {
if (n->type == ROFFT_HEAD) {
outflags |= MMAN_sp;
print_block(manacts[n->tok].prefix, 0);
print_word("");
putchar('\"');
outflags &= ~MMAN_spc;
}
return(1);
return 1;
}
/*
@ -795,7 +790,7 @@ static void
post_sect(DECL_ARGS)
{
if (MDOC_HEAD != n->type)
if (n->type != ROFFT_HEAD)
return;
outflags &= ~MMAN_spc;
print_word("");
@ -807,7 +802,7 @@ post_sect(DECL_ARGS)
/* See mdoc_term.c, synopsis_pre() for comments. */
static void
pre_syn(const struct mdoc_node *n)
pre_syn(const struct roff_node *n)
{
if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
@ -823,13 +818,9 @@ pre_syn(const struct mdoc_node *n)
switch (n->prev->tok) {
case MDOC_Fd:
/* FALLTHROUGH */
case MDOC_Fn:
/* FALLTHROUGH */
case MDOC_Fo:
/* FALLTHROUGH */
case MDOC_In:
/* FALLTHROUGH */
case MDOC_Vt:
outflags |= MMAN_sp;
break;
@ -853,18 +844,18 @@ pre_an(DECL_ARGS)
case AUTH_split:
outflags &= ~MMAN_An_nosplit;
outflags |= MMAN_An_split;
return(0);
return 0;
case AUTH_nosplit:
outflags &= ~MMAN_An_split;
outflags |= MMAN_An_nosplit;
return(0);
return 0;
default:
if (MMAN_An_split & outflags)
outflags |= MMAN_br;
else if (SEC_AUTHORS == n->sec &&
! (MMAN_An_nosplit & outflags))
outflags |= MMAN_An_split;
return(1);
return 1;
}
}
@ -875,17 +866,17 @@ pre_ap(DECL_ARGS)
outflags &= ~MMAN_spc;
print_word("'");
outflags &= ~MMAN_spc;
return(0);
return 0;
}
static int
pre_aq(DECL_ARGS)
{
print_word(n->nchild == 1 &&
print_word(n->child != NULL && n->child->next == NULL &&
n->child->tok == MDOC_Mt ? "<" : "\\(la");
outflags &= ~MMAN_spc;
return(1);
return 1;
}
static void
@ -893,7 +884,7 @@ post_aq(DECL_ARGS)
{
outflags &= ~(MMAN_spc | MMAN_nl);
print_word(n->nchild == 1 &&
print_word(n->child != NULL && n->child->next == NULL &&
n->child->tok == MDOC_Mt ? ">" : "\\(ra");
}
@ -909,7 +900,7 @@ pre_bd(DECL_ARGS)
if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
outflags |= MMAN_sp;
print_offs(n->norm->Bd.offs, 1);
return(1);
return 1;
}
static void
@ -932,12 +923,12 @@ pre_bf(DECL_ARGS)
{
switch (n->type) {
case MDOC_BLOCK:
return(1);
case MDOC_BODY:
case ROFFT_BLOCK:
return 1;
case ROFFT_BODY:
break;
default:
return(0);
return 0;
}
switch (n->norm->Bf.font) {
case FONT_Em:
@ -950,14 +941,14 @@ pre_bf(DECL_ARGS)
font_push('R');
break;
}
return(1);
return 1;
}
static void
post_bf(DECL_ARGS)
{
if (MDOC_BODY == n->type)
if (n->type == ROFFT_BODY)
font_pop();
}
@ -966,13 +957,13 @@ pre_bk(DECL_ARGS)
{
switch (n->type) {
case MDOC_BLOCK:
return(1);
case MDOC_BODY:
case ROFFT_BLOCK:
return 1;
case ROFFT_BODY:
outflags |= MMAN_Bk;
return(1);
return 1;
default:
return(0);
return 0;
}
}
@ -980,7 +971,7 @@ static void
post_bk(DECL_ARGS)
{
if (MDOC_BODY == n->type)
if (n->type == ROFFT_BODY)
outflags &= ~MMAN_Bk;
}
@ -1002,21 +993,21 @@ pre_bl(DECL_ARGS)
switch (n->norm->Bl.type) {
case LIST_enum:
n->norm->Bl.count = 0;
return(1);
return 1;
case LIST_column:
break;
default:
return(1);
return 1;
}
if (n->nchild) {
if (n->child != NULL) {
print_line(".TS", MMAN_nl);
for (icol = 0; icol < n->norm->Bl.ncols; icol++)
print_word("l");
print_word(".");
}
outflags |= MMAN_nl;
return(1);
return 1;
}
static void
@ -1025,7 +1016,7 @@ post_bl(DECL_ARGS)
switch (n->norm->Bl.type) {
case LIST_column:
if (n->nchild)
if (n->child != NULL)
print_line(".TE", 0);
break;
case LIST_enum:
@ -1056,7 +1047,7 @@ pre_br(DECL_ARGS)
{
outflags |= MMAN_br;
return(0);
return 0;
}
static int
@ -1071,12 +1062,12 @@ pre_bx(DECL_ARGS)
}
print_word("BSD");
if (NULL == n)
return(0);
return 0;
outflags &= ~MMAN_spc;
print_word("-");
outflags &= ~MMAN_spc;
print_word(n->string);
return(0);
return 0;
}
static int
@ -1084,7 +1075,7 @@ pre_dl(DECL_ARGS)
{
print_offs("6n", 0);
return(1);
return 1;
}
static void
@ -1103,7 +1094,7 @@ pre_em(DECL_ARGS)
{
font_push('I');
return(1);
return 1;
}
static int
@ -1112,11 +1103,11 @@ pre_en(DECL_ARGS)
if (NULL == n->norm->Es ||
NULL == n->norm->Es->child)
return(1);
return 1;
print_word(n->norm->Es->child->string);
outflags &= ~MMAN_spc;
return(1);
return 1;
}
static void
@ -1146,7 +1137,7 @@ pre_eo(DECL_ARGS)
n->parent->head->child != NULL && (n->child != NULL ||
(n->parent->tail != NULL && n->parent->tail->child != NULL)))
outflags &= ~(MMAN_spc | MMAN_nl);
return(1);
return 1;
}
static void
@ -1189,7 +1180,7 @@ pre_fa(DECL_ARGS)
if (NULL != (n = n->next))
print_word(",");
}
return(0);
return 0;
}
static void
@ -1206,7 +1197,7 @@ pre_fd(DECL_ARGS)
pre_syn(n);
font_push('B');
return(1);
return 1;
}
static void
@ -1223,9 +1214,9 @@ pre_fl(DECL_ARGS)
font_push('B');
print_word("\\-");
if (n->nchild)
if (n->child != NULL)
outflags &= ~MMAN_spc;
return(1);
return 1;
}
static void
@ -1233,9 +1224,9 @@ post_fl(DECL_ARGS)
{
font_pop();
if ( ! (n->nchild ||
if (!(n->child != NULL ||
n->next == NULL ||
n->next->type == MDOC_TEXT ||
n->next->type == ROFFT_TEXT ||
n->next->flags & MDOC_LINE))
outflags &= ~MMAN_spc;
}
@ -1248,7 +1239,7 @@ pre_fn(DECL_ARGS)
n = n->child;
if (NULL == n)
return(0);
return 0;
if (MDOC_SYNPRETTY & n->flags)
print_block(".HP 4n", MMAN_nl);
@ -1263,7 +1254,7 @@ pre_fn(DECL_ARGS)
n = n->next;
if (NULL != n)
pre_fa(meta, n);
return(0);
return 0;
}
static void
@ -1282,17 +1273,17 @@ pre_fo(DECL_ARGS)
{
switch (n->type) {
case MDOC_BLOCK:
case ROFFT_BLOCK:
pre_syn(n);
break;
case MDOC_HEAD:
case ROFFT_HEAD:
if (n->child == NULL)
return(0);
return 0;
if (MDOC_SYNPRETTY & n->flags)
print_block(".HP 4n", MMAN_nl);
font_push('B');
break;
case MDOC_BODY:
case ROFFT_BODY:
outflags &= ~(MMAN_spc | MMAN_nl);
print_word("(");
outflags &= ~MMAN_spc;
@ -1300,7 +1291,7 @@ pre_fo(DECL_ARGS)
default:
break;
}
return(1);
return 1;
}
static void
@ -1308,11 +1299,11 @@ post_fo(DECL_ARGS)
{
switch (n->type) {
case MDOC_HEAD:
case ROFFT_HEAD:
if (n->child != NULL)
font_pop();
break;
case MDOC_BODY:
case ROFFT_BODY:
post_fn(meta, n);
break;
default:
@ -1326,7 +1317,7 @@ pre_ft(DECL_ARGS)
pre_syn(n);
font_push('I');
return(1);
return 1;
}
static int
@ -1343,7 +1334,7 @@ pre_in(DECL_ARGS)
outflags &= ~MMAN_spc;
font_push('I');
}
return(1);
return 1;
}
static void
@ -1365,10 +1356,10 @@ post_in(DECL_ARGS)
static int
pre_it(DECL_ARGS)
{
const struct mdoc_node *bln;
const struct roff_node *bln;
switch (n->type) {
case MDOC_HEAD:
case ROFFT_HEAD:
outflags |= MMAN_PP | MMAN_nl;
bln = n->parent->parent;
if (0 == bln->norm->Bl.comp ||
@ -1378,22 +1369,18 @@ pre_it(DECL_ARGS)
outflags &= ~MMAN_br;
switch (bln->norm->Bl.type) {
case LIST_item:
return(0);
return 0;
case LIST_inset:
/* FALLTHROUGH */
case LIST_diag:
/* FALLTHROUGH */
case LIST_ohang:
if (bln->norm->Bl.type == LIST_diag)
print_line(".B \"", 0);
else
print_line(".R \"", 0);
outflags &= ~MMAN_spc;
return(1);
return 1;
case LIST_bullet:
/* FALLTHROUGH */
case LIST_dash:
/* FALLTHROUGH */
case LIST_hyphen:
print_width(&bln->norm->Bl, NULL);
TPremain = 0;
@ -1405,31 +1392,31 @@ pre_it(DECL_ARGS)
print_word("-");
font_pop();
outflags |= MMAN_nl;
return(0);
return 0;
case LIST_enum:
print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
print_count(&bln->norm->Bl.count);
outflags |= MMAN_nl;
return(0);
return 0;
case LIST_hang:
print_width(&bln->norm->Bl, n->child);
TPremain = 0;
outflags |= MMAN_nl;
return(1);
return 1;
case LIST_tag:
print_width(&bln->norm->Bl, n->child);
putchar('\n');
outflags &= ~MMAN_spc;
return(1);
return 1;
default:
return(1);
return 1;
}
default:
break;
}
return(1);
return 1;
}
/*
@ -1462,12 +1449,12 @@ mid_it(void)
static void
post_it(DECL_ARGS)
{
const struct mdoc_node *bln;
const struct roff_node *bln;
bln = n->parent->parent;
switch (n->type) {
case MDOC_HEAD:
case ROFFT_HEAD:
switch (bln->norm->Bl.type) {
case LIST_diag:
outflags &= ~MMAN_spc;
@ -1480,18 +1467,13 @@ post_it(DECL_ARGS)
break;
}
break;
case MDOC_BODY:
case ROFFT_BODY:
switch (bln->norm->Bl.type) {
case LIST_bullet:
/* FALLTHROUGH */
case LIST_dash:
/* FALLTHROUGH */
case LIST_hyphen:
/* FALLTHROUGH */
case LIST_enum:
/* FALLTHROUGH */
case LIST_hang:
/* FALLTHROUGH */
case LIST_tag:
assert(Bl_stack_len);
Bl_stack[--Bl_stack_len] = 0;
@ -1532,10 +1514,10 @@ post_lb(DECL_ARGS)
static int
pre_lk(DECL_ARGS)
{
const struct mdoc_node *link, *descr;
const struct roff_node *link, *descr;
if (NULL == (link = n->child))
return(0);
return 0;
if (NULL != (descr = link->next)) {
font_push('I');
@ -1550,7 +1532,7 @@ pre_lk(DECL_ARGS)
font_push('B');
print_word(link->string);
font_pop();
return(0);
return 0;
}
static int
@ -1558,7 +1540,7 @@ pre_ll(DECL_ARGS)
{
print_line(".ll", 0);
return(1);
return 1;
}
static int
@ -1566,7 +1548,7 @@ pre_li(DECL_ARGS)
{
font_push('R');
return(1);
return 1;
}
static int
@ -1574,16 +1556,16 @@ pre_nm(DECL_ARGS)
{
char *name;
if (MDOC_BLOCK == n->type) {
if (n->type == ROFFT_BLOCK) {
outflags |= MMAN_Bk;
pre_syn(n);
}
if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
return(1);
if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
return 1;
name = n->child ? n->child->string : meta->name;
if (NULL == name)
return(0);
if (MDOC_HEAD == n->type) {
return 0;
if (n->type == ROFFT_HEAD) {
if (NULL == n->parent->prev)
outflags |= MMAN_sp;
print_block(".HP", 0);
@ -1593,7 +1575,7 @@ pre_nm(DECL_ARGS)
font_push('B');
if (NULL == n->child)
print_word(meta->name);
return(1);
return 1;
}
static void
@ -1601,12 +1583,11 @@ post_nm(DECL_ARGS)
{
switch (n->type) {
case MDOC_BLOCK:
case ROFFT_BLOCK:
outflags &= ~MMAN_Bk;
break;
case MDOC_HEAD:
/* FALLTHROUGH */
case MDOC_ELEM:
case ROFFT_HEAD:
case ROFFT_ELEM:
if (n->child != NULL || meta->name != NULL)
font_pop();
break;
@ -1620,7 +1601,7 @@ pre_no(DECL_ARGS)
{
outflags |= MMAN_spc_force;
return(1);
return 1;
}
static int
@ -1628,7 +1609,7 @@ pre_ns(DECL_ARGS)
{
outflags &= ~MMAN_spc;
return(0);
return 0;
}
static void
@ -1647,7 +1628,7 @@ pre_pp(DECL_ARGS)
outflags |= MMAN_PP;
outflags |= MMAN_sp | MMAN_nl;
outflags &= ~MMAN_br;
return(0);
return 0;
}
static int
@ -1658,40 +1639,39 @@ pre_rs(DECL_ARGS)
outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
outflags &= ~MMAN_br;
}
return(1);
return 1;
}
static int
pre_rv(DECL_ARGS)
{
int nchild;
struct roff_node *nch;
outflags |= MMAN_br | MMAN_nl;
nchild = n->nchild;
if (nchild > 0) {
if (n->child != NULL) {
print_word("The");
for (n = n->child; n; n = n->next) {
for (nch = n->child; nch != NULL; nch = nch->next) {
font_push('B');
print_word(n->string);
print_word(nch->string);
font_pop();
outflags &= ~MMAN_spc;
print_word("()");
if (n->next == NULL)
if (nch->next == NULL)
continue;
if (nchild > 2) {
if (nch->prev != NULL || nch->next->next != NULL) {
outflags &= ~MMAN_spc;
print_word(",");
}
if (n->next->next == NULL)
if (nch->next->next == NULL)
print_word("and");
}
if (nchild > 1)
if (n->child != NULL && n->child->next != NULL)
print_word("functions return");
else
print_word("function returns");
@ -1710,14 +1690,14 @@ pre_rv(DECL_ARGS)
print_word("is set to indicate the error.");
outflags |= MMAN_nl;
return(0);
return 0;
}
static int
pre_skip(DECL_ARGS)
{
return(0);
return 0;
}
static int
@ -1734,7 +1714,7 @@ pre_sm(DECL_ARGS)
if (MMAN_Sm & outflags)
outflags |= MMAN_spc;
return(0);
return 0;
}
static int
@ -1746,7 +1726,7 @@ pre_sp(DECL_ARGS)
print_line(".PP", 0);
} else
print_line(".sp", 0);
return(1);
return 1;
}
static void
@ -1761,7 +1741,7 @@ pre_sy(DECL_ARGS)
{
font_push('B');
return(1);
return 1;
}
static int
@ -1770,24 +1750,24 @@ pre_vt(DECL_ARGS)
if (MDOC_SYNPRETTY & n->flags) {
switch (n->type) {
case MDOC_BLOCK:
case ROFFT_BLOCK:
pre_syn(n);
return(1);
case MDOC_BODY:
return 1;
case ROFFT_BODY:
break;
default:
return(0);
return 0;
}
}
font_push('I');
return(1);
return 1;
}
static void
post_vt(DECL_ARGS)
{
if (MDOC_SYNPRETTY & n->flags && MDOC_BODY != n->type)
if (n->flags & MDOC_SYNPRETTY && n->type != ROFFT_BODY)
return;
font_pop();
}
@ -1798,16 +1778,16 @@ pre_xr(DECL_ARGS)
n = n->child;
if (NULL == n)
return(0);
return 0;
print_node(meta, n);
n = n->next;
if (NULL == n)
return(0);
return 0;
outflags &= ~MMAN_spc;
print_word("(");
print_node(meta, n);
print_word(")");
return(0);
return 0;
}
static int
@ -1816,9 +1796,9 @@ pre_ux(DECL_ARGS)
print_word(manacts[n->tok].prefix);
if (NULL == n->child)
return(0);
return 0;
outflags &= ~MMAN_spc;
print_word("\\ ");
outflags &= ~MMAN_spc;
return(1);
return 1;
}

292
mdoc_state.c Normal file
View File

@ -0,0 +1,292 @@
/* $Id: mdoc_state.c,v 1.3 2015/10/30 18:53:54 schwarze Exp $ */
/*
* Copyright (c) 2014, 2015 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.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
#include "libmdoc.h"
#define STATE_ARGS struct roff_man *mdoc, struct roff_node *n
typedef void (*state_handler)(STATE_ARGS);
static void state_bd(STATE_ARGS);
static void state_bl(STATE_ARGS);
static void state_dl(STATE_ARGS);
static void state_sh(STATE_ARGS);
static void state_sm(STATE_ARGS);
static const state_handler state_handlers[MDOC_MAX] = {
NULL, /* Ap */
NULL, /* Dd */
NULL, /* Dt */
NULL, /* Os */
state_sh, /* Sh */
NULL, /* Ss */
NULL, /* Pp */
NULL, /* D1 */
state_dl, /* Dl */
state_bd, /* Bd */
NULL, /* Ed */
state_bl, /* Bl */
NULL, /* El */
NULL, /* It */
NULL, /* Ad */
NULL, /* An */
NULL, /* Ar */
NULL, /* Cd */
NULL, /* Cm */
NULL, /* Dv */
NULL, /* Er */
NULL, /* Ev */
NULL, /* Ex */
NULL, /* Fa */
NULL, /* Fd */
NULL, /* Fl */
NULL, /* Fn */
NULL, /* Ft */
NULL, /* Ic */
NULL, /* In */
NULL, /* Li */
NULL, /* Nd */
NULL, /* Nm */
NULL, /* Op */
NULL, /* Ot */
NULL, /* Pa */
NULL, /* Rv */
NULL, /* St */
NULL, /* Va */
NULL, /* Vt */
NULL, /* Xr */
NULL, /* %A */
NULL, /* %B */
NULL, /* %D */
NULL, /* %I */
NULL, /* %J */
NULL, /* %N */
NULL, /* %O */
NULL, /* %P */
NULL, /* %R */
NULL, /* %T */
NULL, /* %V */
NULL, /* Ac */
NULL, /* Ao */
NULL, /* Aq */
NULL, /* At */
NULL, /* Bc */
NULL, /* Bf */
NULL, /* Bo */
NULL, /* Bq */
NULL, /* Bsx */
NULL, /* Bx */
NULL, /* Db */
NULL, /* Dc */
NULL, /* Do */
NULL, /* Dq */
NULL, /* Ec */
NULL, /* Ef */
NULL, /* Em */
NULL, /* Eo */
NULL, /* Fx */
NULL, /* Ms */
NULL, /* No */
NULL, /* Ns */
NULL, /* Nx */
NULL, /* Ox */
NULL, /* Pc */
NULL, /* Pf */
NULL, /* Po */
NULL, /* Pq */
NULL, /* Qc */
NULL, /* Ql */
NULL, /* Qo */
NULL, /* Qq */
NULL, /* Re */
NULL, /* Rs */
NULL, /* Sc */
NULL, /* So */
NULL, /* Sq */
state_sm, /* Sm */
NULL, /* Sx */
NULL, /* Sy */
NULL, /* Tn */
NULL, /* Ux */
NULL, /* Xc */
NULL, /* Xo */
NULL, /* Fo */
NULL, /* Fc */
NULL, /* Oo */
NULL, /* Oc */
NULL, /* Bk */
NULL, /* Ek */
NULL, /* Bt */
NULL, /* Hf */
NULL, /* Fr */
NULL, /* Ud */
NULL, /* Lb */
NULL, /* Lp */
NULL, /* Lk */
NULL, /* Mt */
NULL, /* Brq */
NULL, /* Bro */
NULL, /* Brc */
NULL, /* %C */
NULL, /* Es */
NULL, /* En */
NULL, /* Dx */
NULL, /* %Q */
NULL, /* br */
NULL, /* sp */
NULL, /* %U */
NULL, /* Ta */
NULL, /* ll */
};
void
mdoc_state(struct roff_man *mdoc, struct roff_node *n)
{
state_handler handler;
if (n->tok == TOKEN_NONE)
return;
if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
mdoc->flags |= MDOC_PBODY;
handler = state_handlers[n->tok];
if (*handler)
(*handler)(mdoc, n);
}
void
mdoc_state_reset(struct roff_man *mdoc)
{
roff_setreg(mdoc->roff, "nS", 0, '=');
mdoc->flags = 0;
}
static void
state_bd(STATE_ARGS)
{
enum mdocargt arg;
if (n->type != ROFFT_HEAD &&
(n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
return;
if (n->parent->args == NULL)
return;
arg = n->parent->args->argv[0].arg;
if (arg != MDOC_Literal && arg != MDOC_Unfilled)
return;
state_dl(mdoc, n);
}
static void
state_bl(STATE_ARGS)
{
if (n->type != ROFFT_HEAD || n->parent->args == NULL)
return;
switch(n->parent->args->argv[0].arg) {
case MDOC_Diag:
n->norm->Bl.type = LIST_diag;
break;
case MDOC_Column:
n->norm->Bl.type = LIST_column;
break;
default:
break;
}
}
static void
state_dl(STATE_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
mdoc->flags |= MDOC_LITERAL;
break;
case ROFFT_BODY:
mdoc->flags &= ~MDOC_LITERAL;
break;
default:
break;
}
}
static void
state_sh(STATE_ARGS)
{
struct roff_node *nch;
char *secname;
if (n->type != ROFFT_HEAD)
return;
if ( ! (n->flags & MDOC_VALID)) {
secname = NULL;
deroff(&secname, n);
/*
* Set the section attribute for the BLOCK, HEAD,
* and HEAD children; the latter can only be TEXT
* nodes, so no recursion is needed. For other
* nodes, including the .Sh BODY, this is done
* when allocating the node data structures, but
* for .Sh BLOCK and HEAD, the section is still
* unknown at that time.
*/
n->sec = n->parent->sec = secname == NULL ?
SEC_CUSTOM : mdoc_a2sec(secname);
for (nch = n->child; nch != NULL; nch = nch->next)
nch->sec = n->sec;
free(secname);
}
if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
roff_setreg(mdoc->roff, "nS", 1, '=');
mdoc->flags |= MDOC_SYNOPSIS;
} else {
roff_setreg(mdoc->roff, "nS", 0, '=');
mdoc->flags &= ~MDOC_SYNOPSIS;
}
}
static void
state_sm(STATE_ARGS)
{
if (n->child == NULL)
mdoc->flags ^= MDOC_SMOFF;
else if ( ! strcmp(n->child->string, "on"))
mdoc->flags &= ~MDOC_SMOFF;
else if ( ! strcmp(n->child->string, "off"))
mdoc->flags |= MDOC_SMOFF;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4
msec.c
View File

@ -1,4 +1,4 @@
/* $Id: msec.c,v 1.14 2014/12/21 14:14:35 schwarze Exp $ */
/* $Id: msec.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -32,5 +32,5 @@ mandoc_a2msec(const char *p)
#include "msec.in"
return(NULL);
return NULL;
}

13
out.c
View File

@ -1,4 +1,4 @@
/* $Id: out.c,v 1.59 2015/01/30 04:11:50 schwarze Exp $ */
/* $Id: out.c,v 1.62 2015/10/12 00:08:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -51,7 +51,7 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
dst->unit = def == SCALE_MAX ? SCALE_BU : def;
dst->scale = strtod(src, &endptr);
if (endptr == src)
return(0);
return 0;
switch (*endptr++) {
case 'c':
@ -89,12 +89,12 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
/* FALLTHROUGH */
default:
if (SCALE_MAX == def)
return(0);
return 0;
dst->unit = def;
break;
}
return(*endptr == '\0' ? 2 : 1);
return *endptr == '\0' ? 2 : 1;
}
/*
@ -240,18 +240,14 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
switch (dp->layout->pos) {
case TBL_CELL_HORIZ:
/* FALLTHROUGH */
case TBL_CELL_DHORIZ:
sz = (*tbl->len)(1, tbl->arg);
if (col->width < sz)
col->width = sz;
break;
case TBL_CELL_LONG:
/* FALLTHROUGH */
case TBL_CELL_CENTRE:
/* FALLTHROUGH */
case TBL_CELL_LEFT:
/* FALLTHROUGH */
case TBL_CELL_RIGHT:
tblcalc_literal(tbl, col, dp);
break;
@ -262,7 +258,6 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
break;
default:
abort();
/* NOTREACHED */
}
}

5
out.h
View File

@ -1,4 +1,4 @@
/* $Id: out.h,v 1.26 2014/12/01 08:05:52 schwarze Exp $ */
/* $Id: out.h,v 1.27 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -60,12 +60,9 @@ struct rofftbl {
(p)->scale = (v); } \
while (/* CONSTCOND */ 0)
__BEGIN_DECLS
struct tbl_span;
int a2roffsu(const char *, struct roffsu *, enum roffscale);
void tblcalc(struct rofftbl *tbl,
const struct tbl_span *, size_t);
__END_DECLS

View File

@ -1,4 +1,4 @@
/* $Id: preconv.c,v 1.14 2015/03/06 09:24:59 kristaps Exp $ */
/* $Id: preconv.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@ -92,17 +92,17 @@ preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
*oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
*ii = (char *)cu - ib->buf;
*filenc &= ~MPARSE_LATIN1;
return(1);
return 1;
latin:
if ( ! (*filenc & MPARSE_LATIN1))
return(0);
return 0;
*oi += snprintf(ob->buf + *oi, 11,
"\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
*filenc &= ~MPARSE_UTF8;
return(1);
return 1;
}
int
@ -123,7 +123,7 @@ preconv_cue(const struct buf *b, size_t offset)
if ((sz = (size_t)(eoln - ln)) < 10 ||
memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
return(MPARSE_UTF8 | MPARSE_LATIN1);
return MPARSE_UTF8 | MPARSE_LATIN1;
/* Move after the header and adjust for the trailer. */
@ -162,15 +162,15 @@ preconv_cue(const struct buf *b, size_t offset)
sz--;
}
if (0 == sz)
return(0);
return 0;
/* Check us against known encodings. */
if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
return(MPARSE_UTF8);
return MPARSE_UTF8;
if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
return(MPARSE_LATIN1);
return(0);
return MPARSE_LATIN1;
return 0;
}
return(MPARSE_UTF8 | MPARSE_LATIN1);
return MPARSE_UTF8 | MPARSE_LATIN1;
}

300
read.c
View File

@ -1,16 +1,16 @@
/* $Id: read.c,v 1.131 2015/03/11 13:05:20 schwarze Exp $ */
/* $Id: read.c,v 1.148 2016/01/08 02:53:13 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@ -23,10 +23,12 @@
#include <sys/mman.h>
#include <sys/stat.h>
#endif
#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@ -35,22 +37,21 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zlib.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "libmandoc.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#define REPARSE_LIMIT 1000
struct mparse {
struct man *pman; /* persistent man parser */
struct mdoc *pmdoc; /* persistent mdoc parser */
struct man *man; /* man parser */
struct mdoc *mdoc; /* mdoc parser */
struct roff_man *man; /* man parser */
struct roff *roff; /* roff parser (!NULL) */
const struct mchars *mchars; /* character table */
char *sodest; /* filename pointed to by .so */
const char *file; /* filename of current input file */
struct buf *primary; /* buffer currently being parsed */
@ -60,10 +61,10 @@ struct mparse {
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
int options; /* parser options */
int gzip; /* current input file is gzipped */
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 *);
@ -130,7 +131,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"blocks badly nested",
"nested displays are not portable",
"moving content out of list",
".Vt block has child macro",
"fill mode already enabled, skipping",
"fill mode already disabled, skipping",
"line scope broken",
@ -217,6 +217,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
/* related to request and macro arguments */
"escaped character not allowed in a name",
"NOT IMPLEMENTED: Bd -file",
"skipping display without arguments",
"missing list type, using -item",
"missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN",
@ -290,24 +291,22 @@ choose_parser(struct mparse *curp)
}
}
if (format == MPARSE_MDOC) {
if (NULL == curp->pmdoc)
curp->pmdoc = mdoc_alloc(
curp->roff, curp, curp->defos,
MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pmdoc);
curp->mdoc = curp->pmdoc;
return;
if (curp->man == NULL) {
curp->man = roff_man_alloc(curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
curp->man->macroset = MACROSET_MAN;
curp->man->first->tok = TOKEN_NONE;
}
/* Fall back to man(7) as a last resort. */
if (NULL == curp->pman)
curp->pman = man_alloc(
curp->roff, curp, curp->defos,
MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pman);
curp->man = curp->pman;
if (format == MPARSE_MDOC) {
mdoc_hash_init();
curp->man->macroset = MACROSET_MDOC;
curp->man->first->tok = TOKEN_NONE;
} else {
man_hash_init();
curp->man->macroset = MACROSET_MAN;
curp->man->first->tok = TOKEN_NONE;
}
}
/*
@ -329,7 +328,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
int of;
int lnn; /* line number in the real file */
int fd;
pid_t save_child;
unsigned char c;
memset(&ln, 0, sizeof(ln));
@ -541,10 +539,9 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
if (curp->secondary)
curp->secondary->sz -= pos + 1;
save_file = curp->file;
save_child = curp->child;
if (mparse_open(curp, &fd, ln.buf + of) ==
MANDOCLEVEL_OK) {
if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
mparse_readfd(curp, fd, ln.buf + of);
close(fd);
curp->file = save_file;
} else {
curp->file = save_file;
@ -559,7 +556,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
of = 0;
mparse_buf_r(curp, ln, of, 0);
}
curp->child = save_child;
pos = 0;
continue;
default:
@ -573,7 +569,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
* parsers with each one.
*/
if ( ! (curp->man || curp->mdoc))
if (curp->man == NULL ||
curp->man->macroset == MACROSET_NONE)
choose_parser(curp);
/*
@ -585,19 +582,13 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
* Do the same for ROFF_EQN.
*/
if (rr == ROFF_TBL) {
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) :
roff_addtbl(curp->man, span);
else if (rr == ROFF_EQN)
roff_addeqn(curp->man, roff_eqn(curp->roff));
else if ((curp->man->macroset == MACROSET_MDOC ?
mdoc_parseln(curp->man, curp->line, ln.buf, of) :
man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
break;
@ -618,15 +609,15 @@ static int
read_whole_file(struct mparse *curp, const char *file, int fd,
struct buf *fb, int *with_mmap)
{
gzFile gz;
size_t off;
ssize_t ssz;
#if HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
perror(file);
exit((int)MANDOCLEVEL_SYSERR);
}
if (fstat(fd, &st) == -1)
err((int)MANDOCLEVEL_SYSERR, "%s", file);
/*
* If we're a regular file, try just reading in the whole entry
@ -635,19 +626,25 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
* concerned that this is going to tank any machines.
*/
if (S_ISREG(st.st_mode)) {
if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
if (st.st_size > 0x7fffffff) {
mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
return(0);
return 0;
}
*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);
return 1;
}
#endif
if (curp->gzip) {
if ((gz = gzdopen(fd, "rb")) == NULL)
err((int)MANDOCLEVEL_SYSERR, "%s", file);
} else
gz = NULL;
/*
* 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.
@ -666,43 +663,35 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
resize_buf(fb, 65536);
}
ssz = read(fd, fb->buf + (int)off, fb->sz - off);
ssz = curp->gzip ?
gzread(gz, fb->buf + (int)off, fb->sz - off) :
read(fd, fb->buf + (int)off, fb->sz - off);
if (ssz == 0) {
fb->sz = off;
return(1);
}
if (ssz == -1) {
perror(file);
exit((int)MANDOCLEVEL_SYSERR);
return 1;
}
if (ssz == -1)
err((int)MANDOCLEVEL_SYSERR, "%s", file);
off += (size_t)ssz;
}
free(fb->buf);
fb->buf = NULL;
return(0);
return 0;
}
static void
mparse_end(struct mparse *curp)
{
if (curp->mdoc == NULL &&
curp->man == NULL &&
curp->sodest == NULL) {
if (curp->options & MPARSE_MDOC)
curp->mdoc = curp->pmdoc;
else {
if (curp->pman == NULL)
curp->pman = man_alloc(
curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
curp->man = curp->pman;
}
}
if (curp->mdoc)
mdoc_endparse(curp->mdoc);
if (curp->man)
if (curp->man == NULL && curp->sodest == NULL)
curp->man = roff_man_alloc(curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->man->macroset == MACROSET_NONE)
curp->man->macroset = MACROSET_MAN;
if (curp->man->macroset == MACROSET_MDOC)
mdoc_endparse(curp->man);
else
man_endparse(curp->man);
roff_endparse(curp->roff);
}
@ -757,7 +746,7 @@ mparse_readmem(struct mparse *curp, void *buf, size_t len,
blk.sz = len;
mparse_parse_buffer(curp, blk, file);
return(curp->file_status);
return curp->file_status;
}
/*
@ -784,107 +773,48 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
#endif
free(blk.buf);
}
if (fd != STDIN_FILENO && close(fd) == -1)
perror(file);
mparse_wait(curp);
return(curp->file_status);
return curp->file_status;
}
enum mandoclevel
mparse_open(struct mparse *curp, int *fd, const char *file)
int
mparse_open(struct mparse *curp, const char *file)
{
int pfd[2];
int save_errno;
char *cp;
int fd;
curp->file = file;
cp = strrchr(file, '.');
curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
/* Unless zipped, try to just open the file. */
/* First try to use the filename as it is. */
if ((cp = strrchr(file, '.')) == NULL ||
strcmp(cp + 1, "gz")) {
curp->child = 0;
if ((*fd = open(file, O_RDONLY)) != -1)
return(MANDOCLEVEL_OK);
if ((fd = open(file, O_RDONLY)) != -1)
return fd;
/* Open failed; try to append ".gz". */
/*
* If that doesn't work and the filename doesn't
* already end in .gz, try appending .gz.
*/
if ( ! curp->gzip) {
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;
fd = open(file, O_RDONLY);
free(cp);
*fd = -1;
curp->child = 0;
mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
return(MANDOCLEVEL_ERROR);
}
/* Run gunzip(1). */
if (pipe(pfd) == -1) {
perror("pipe");
exit((int)MANDOCLEVEL_SYSERR);
}
switch (curp->child = fork()) {
case -1:
perror("fork");
exit((int)MANDOCLEVEL_SYSERR);
case 0:
close(pfd[0]);
if (dup2(pfd[1], STDOUT_FILENO) == -1) {
perror("dup");
exit((int)MANDOCLEVEL_SYSERR);
if (fd != -1) {
curp->gzip = 1;
return fd;
}
execlp("gunzip", "gunzip", "-c", file, NULL);
perror("exec");
exit((int)MANDOCLEVEL_SYSERR);
default:
close(pfd[1]);
*fd = pfd[0];
return(MANDOCLEVEL_OK);
}
}
enum mandoclevel
mparse_wait(struct mparse *curp)
{
int status;
/* Neither worked, give up. */
if (curp->child == 0)
return(MANDOCLEVEL_OK);
if (waitpid(curp->child, &status, 0) == -1) {
perror("wait");
exit((int)MANDOCLEVEL_SYSERR);
}
curp->child = 0;
if (WIFSIGNALED(status)) {
mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
"gunzip died from signal %d", WTERMSIG(status));
return(MANDOCLEVEL_ERROR);
}
if (WEXITSTATUS(status)) {
mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
"gunzip failed with code %d", WEXITSTATUS(status));
return(MANDOCLEVEL_ERROR);
}
return(MANDOCLEVEL_OK);
mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
return -1;
}
struct mparse *
mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
const struct mchars *mchars, const char *defos)
const char *defos)
{
struct mparse *curp;
@ -895,18 +825,18 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
curp->mmsg = mmsg;
curp->defos = defos;
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,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MAN)
curp->pman = man_alloc(
curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
return(curp);
curp->roff = roff_alloc(curp, options);
curp->man = roff_man_alloc( curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MDOC) {
mdoc_hash_init();
curp->man->macroset = MACROSET_MDOC;
} else if (curp->options & MPARSE_MAN) {
man_hash_init();
curp->man->macroset = MACROSET_MAN;
}
curp->man->first->tok = TOKEN_NONE;
return curp;
}
void
@ -915,16 +845,12 @@ mparse_reset(struct mparse *curp)
roff_reset(curp->roff);
if (curp->mdoc)
mdoc_reset(curp->mdoc);
if (curp->man)
man_reset(curp->man);
if (curp->man != NULL)
roff_man_reset(curp->man);
if (curp->secondary)
curp->secondary->sz = 0;
curp->file_status = MANDOCLEVEL_OK;
curp->mdoc = NULL;
curp->man = NULL;
free(curp->sodest);
curp->sodest = NULL;
@ -934,10 +860,7 @@ void
mparse_free(struct mparse *curp)
{
if (curp->pmdoc)
mdoc_free(curp->pmdoc);
if (curp->pman)
man_free(curp->pman);
roff_man_free(curp->man);
if (curp->roff)
roff_free(curp->roff);
if (curp->secondary)
@ -949,17 +872,14 @@ mparse_free(struct mparse *curp)
}
void
mparse_result(struct mparse *curp,
struct mdoc **mdoc, struct man **man, char **sodest)
mparse_result(struct mparse *curp, struct roff_man **man,
char **sodest)
{
if (sodest && NULL != (*sodest = curp->sodest)) {
*mdoc = NULL;
*man = NULL;
return;
}
if (mdoc)
*mdoc = curp->mdoc;
if (man)
*man = curp->man;
}
@ -1002,13 +922,13 @@ const char *
mparse_strerror(enum mandocerr er)
{
return(mandocerrs[er]);
return mandocerrs[er];
}
const char *
mparse_strlevel(enum mandoclevel lvl)
{
return(mandoclevels[lvl]);
return mandoclevels[lvl];
}
void
@ -1024,5 +944,5 @@ mparse_getkeep(const struct mparse *p)
{
assert(p->secondary);
return(p->secondary->sz ? p->secondary->buf : NULL);
return p->secondary->sz ? p->secondary->buf : NULL;
}

34
roff.7
View File

@ -1,7 +1,7 @@
.\" $Id: roff.7,v 1.70 2015/02/17 17:16:52 schwarze Exp $
.\" $Id: roff.7,v 1.75 2015/09/24 18:41:22 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2010, 2011, 2013-2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 17 2015 $
.Dd $Mdocdate: September 24 2015 $
.Dt ROFF 7
.Os
.Sh NAME
@ -665,6 +665,8 @@ produces
.D1 \efI\e^XtFree\e^\efP.
.Pp
in the input stream, and thus in the output: \fI\^XtFree\^\fP.
Each occurrence of \e\e$* is replaced with all the arguments,
joined together with single blank characters.
.Pp
Since macros and user-defined strings share a common string table,
defining a macro
@ -1057,8 +1059,6 @@ If the first character of COND is
.Pq string defined ,
.Sq e
.Pq even page ,
.Sq r
.Pq register accessed ,
.Sq t
.Pq troff mode ,
or
@ -1066,6 +1066,11 @@ or
.Pq vroff mode ,
COND evaluates to false.
.It
If the first character of COND is
.Sq r ,
it evaluates to true if the rest of COND is the name of an existing
number register; otherwise, it 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
@ -1337,7 +1342,7 @@ Currently unsupported.
Temporarily turn off line numbering.
Currently unsupported.
.Ss \&nop
Exexute the rest of the input line as a request or macro line.
Execute the rest of the input line as a request or macro line.
Currently unsupported.
.Ss \&nr
Define or change a register.
@ -1579,7 +1584,7 @@ Set tab stops.
Takes an arbitrary number of arguments.
Currently unsupported.
.Ss \&tc
Change tab repetion character.
Change tab repetition character.
Currently unsupported.
.Ss \&TE
End a table context.
@ -1679,7 +1684,7 @@ Notify on change of string or macro.
This is a Heirloom extension and currently ignored.
.Ss \&watchlength
On change, report the contents of macros and strings
up to the sepcified length.
up to the specified length.
This is a Heirloom extension and currently ignored.
.Ss \&watchn
Notify on change of register.
@ -1774,7 +1779,7 @@ minimum (not available in C)
maximum (not available in C)
.El
.Pp
There is no concept of precendence; evaluation proceeds from left to right,
There is no concept of precedence; evaluation proceeds from left to right,
except when subexpressions are enclosed in parantheses.
Inside parentheses, whitespace is ignored.
.Sh ESCAPE SEQUENCE REFERENCE
@ -1834,9 +1839,15 @@ For short names, there are variants
.No \e* Ns Ar c
and
.No \e*( Ns Ar cc .
.Ss \e,
Left italic correction (groff extension); ignored by
.Xr mandoc 1 .
.Ss \e-
Special character
.Dq mathematical minus sign .
.Ss \e/
Right italic correction (groff extension); ignored by
.Xr mandoc 1 .
.Ss \e[ Ns Ar name ]
.Sx Special Characters
with names of arbitrary length, see
@ -2028,10 +2039,7 @@ Print
with zero width and height; ignored by
.Xr mandoc 1 .
.Ss \ez
Output the next character without advancing the cursor position;
approximated in
.Xr mandoc 1
by simply skipping the next character.
Output the next character without advancing the cursor position.
.Sh COMPATIBILITY
The
.Xr mandoc 1

785
roff.c

File diff suppressed because it is too large Load Diff

164
roff.h Normal file
View File

@ -0,0 +1,164 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct mdoc_arg;
union mdoc_data;
enum roff_macroset {
MACROSET_NONE = 0,
MACROSET_MDOC,
MACROSET_MAN
};
enum roff_sec {
SEC_NONE = 0,
SEC_NAME,
SEC_LIBRARY,
SEC_SYNOPSIS,
SEC_DESCRIPTION,
SEC_CONTEXT,
SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */
SEC_RETURN_VALUES,
SEC_ENVIRONMENT,
SEC_FILES,
SEC_EXIT_STATUS,
SEC_EXAMPLES,
SEC_DIAGNOSTICS,
SEC_COMPATIBILITY,
SEC_ERRORS,
SEC_SEE_ALSO,
SEC_STANDARDS,
SEC_HISTORY,
SEC_AUTHORS,
SEC_CAVEATS,
SEC_BUGS,
SEC_SECURITY,
SEC_CUSTOM,
SEC__MAX
};
enum roff_type {
ROFFT_ROOT,
ROFFT_BLOCK,
ROFFT_HEAD,
ROFFT_BODY,
ROFFT_TAIL,
ROFFT_ELEM,
ROFFT_TEXT,
ROFFT_TBL,
ROFFT_EQN
};
enum roff_next {
ROFF_NEXT_SIBLING = 0,
ROFF_NEXT_CHILD
};
/*
* Indicates that a BODY's formatting has ended, but
* the scope is still open. Used for badly nested blocks.
*/
enum mdoc_endbody {
ENDBODY_NOT = 0,
ENDBODY_SPACE, /* Is broken: append a space. */
ENDBODY_NOSPACE /* Is broken: don't append a space. */
};
struct roff_node {
struct roff_node *parent; /* Parent AST node. */
struct roff_node *child; /* First child AST node. */
struct roff_node *last; /* Last child AST node. */
struct roff_node *next; /* Sibling AST node. */
struct roff_node *prev; /* Prior sibling AST node. */
struct roff_node *head; /* BLOCK */
struct roff_node *body; /* BLOCK/ENDBODY */
struct roff_node *tail; /* BLOCK */
struct mdoc_arg *args; /* BLOCK/ELEM */
union mdoc_data *norm; /* Normalized arguments. */
char *string; /* TEXT */
const struct tbl_span *span; /* TBL */
const struct eqn *eqn; /* EQN */
int line; /* Input file line number. */
int pos; /* Input file column number. */
int tok; /* Request or macro ID. */
#define TOKEN_NONE (-1) /* No request or macro. */
int flags;
#define MDOC_VALID (1 << 0) /* Has been validated. */
#define MDOC_ENDED (1 << 1) /* Gone past body end mark. */
#define MDOC_EOS (1 << 2) /* At sentence boundary. */
#define MDOC_LINE (1 << 3) /* First macro/text on line. */
#define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting. */
#define MDOC_BROKEN (1 << 5) /* Must validate parent when ending. */
#define MDOC_DELIMO (1 << 6)
#define MDOC_DELIMC (1 << 7)
#define MAN_VALID MDOC_VALID
#define MAN_EOS MDOC_EOS
#define MAN_LINE MDOC_LINE
int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */
enum roff_type type; /* AST node type. */
enum roff_sec sec; /* Current named section. */
enum mdoc_endbody end; /* BODY */
};
struct roff_meta {
char *msec; /* Manual section, usually a digit. */
char *vol; /* Manual volume title. */
char *os; /* Operating system. */
char *arch; /* Machine architecture. */
char *title; /* Manual title, usually CAPS. */
char *name; /* Leading manual name. */
char *date; /* Normalized date. */
int hasbody; /* Document is not empty. */
};
struct roff_man {
struct roff_meta meta; /* Document meta-data. */
struct mparse *parse; /* Parse pointer. */
struct roff *roff; /* Roff parser state data. */
const char *defos; /* Default operating system. */
struct roff_node *first; /* The first node parsed. */
struct roff_node *last; /* The last node parsed. */
struct roff_node *last_es; /* The most recent Es node. */
int quick; /* Abort parse early. */
int flags; /* Parse flags. */
#define MDOC_LITERAL (1 << 1) /* In a literal scope. */
#define MDOC_PBODY (1 << 2) /* In the document body. */
#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */
#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */
#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */
#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */
#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. */
#define MAN_ELINE (1 << 11) /* Next-line element scope. */
#define MAN_BLINE (1 << 12) /* Next-line block scope. */
#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */
#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */
#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */
#define MAN_LITERAL MDOC_LITERAL
#define MAN_NEWLINE MDOC_NEWLINE
enum roff_macroset macroset; /* Kind of high-level macros used. */
enum roff_sec lastsec; /* Last section seen. */
enum roff_sec lastnamed; /* Last standard section seen. */
enum roff_next next; /* Where to put the next node. */
};
void deroff(char **, const struct roff_node *);

41
roff_int.h Normal file
View File

@ -0,0 +1,41 @@
/* $Id: roff_int.h,v 1.7 2015/11/07 14:01:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct roff_node *roff_node_alloc(struct roff_man *, int, int,
enum roff_type, int);
void roff_node_append(struct roff_man *, struct roff_node *);
void roff_word_alloc(struct roff_man *, int, int, const char *);
void roff_word_append(struct roff_man *, const char *);
void roff_elem_alloc(struct roff_man *, int, int, int);
struct roff_node *roff_block_alloc(struct roff_man *, int, int, int);
struct roff_node *roff_head_alloc(struct roff_man *, int, int, int);
struct roff_node *roff_body_alloc(struct roff_man *, int, int, int);
void roff_addeqn(struct roff_man *, const struct eqn *);
void roff_addtbl(struct roff_man *, const struct tbl_span *);
void roff_node_unlink(struct roff_man *, struct roff_node *);
void roff_node_free(struct roff_node *);
void roff_node_delete(struct roff_man *, struct roff_node *);
/*
* Functions called from roff.c need to be declared here,
* not in libmdoc.h or libman.h, even if they are specific
* to either the mdoc(7) or the man(7) parser.
*/
void man_breakscope(struct roff_man *, int);
void mdoc_argv_free(struct mdoc_arg *);

86
soelim.1 Normal file
View File

@ -0,0 +1,86 @@
.\" $Id: soelim.1,v 1.3 2015/05/20 22:59:12 schwarze Exp $
.\"
.\" Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
.\"
.Dd $Mdocdate: May 20 2015 $
.Dt SOELIM 1
.Os
.Sh NAME
.Nm soelim
.Nd interpret .so requests in manpages
.Sh SYNOPSIS
.Nm
.Op Fl Crtv
.Op Fl I Ar dir
.Op Ar files ...
.Sh DESCRIPTION
.Nm
reads
.Ar files
lines by lines.
.Pp
If a line starts by:
.Dq .so anotherfile
it replace the line by processing
.Dq anotherfile .
Otherwise the line is printed to stdout.
.Bl -tag -width "-I dir"
.It Fl C
Recognise
.Em .so
when not followed by a space character.
.It Fl r
Compatibility with GNU groff's
.Xr soelim 1
(does nothing).
.It Fl t
Compatibility with GNU groff's
.Xr soelim 1
(does nothing).
.It Fl v
Compatibility with GNU groff's
.Xr soelim 1
(does nothing).
.It Fl I Ar dir
This option specify directories where
.Nm
searches for files (both those on the command line and those named in
.Dq .so
directive.)
This options may be specified multiple times. The directories will be searched
in the order specified.
.El
.Pp
The files are always searched first in the current directory.
.Pp
A file specified with an absolute path will be opened directly without
performing a search.
.Sh SEE ALSO
.Xr mandoc 1
.Sh AUTHORS
This version of the
.Nm
utility was written by
.An Baptiste Daroussin Aq Mt bapt@freebsd.org .

182
soelim.c Normal file
View File

@ -0,0 +1,182 @@
/* $Id: soelim.c,v 1.5 2015/11/07 14:22:29 schwarze Exp $ */
/*
* Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
* 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
* in this position and unchanged.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "config.h"
#include <sys/types.h>
#include <ctype.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_STRINGLIST
#include <stringlist.h>
#else
#include "compat_stringlist.h"
#endif
#include <unistd.h>
#define C_OPTION 0x1
static StringList *includes;
static void
usage(void)
{
fprintf(stderr, "usage: soelim [-Crtv] [-I dir] [files]\n");
exit(EXIT_FAILURE);
}
static FILE *
soelim_fopen(const char *name)
{
FILE *f;
char path[PATH_MAX];
size_t i;
if (strcmp(name, "-") == 0)
return (stdin);
if ((f = fopen(name, "r")) != NULL)
return (f);
if (*name == '/') {
warn("can't open '%s'", name);
return (NULL);
}
for (i = 0; i < includes->sl_cur; i++) {
snprintf(path, sizeof(path), "%s/%s", includes->sl_str[i],
name);
if ((f = fopen(path, "r")) != NULL)
return (f);
}
warn("can't open '%s'", name);
return (f);
}
static int
soelim_file(FILE *f, int flag)
{
char *line = NULL;
char *walk, *cp;
size_t linecap = 0;
ssize_t linelen;
if (f == NULL)
return (1);
while ((linelen = getline(&line, &linecap, f)) > 0) {
if (strncmp(line, ".so", 3) != 0) {
printf("%s", line);
continue;
}
walk = line + 3;
if (!isspace(*walk) && ((flag & C_OPTION) == 0)) {
printf("%s", line);
continue;
}
while (isspace(*walk))
walk++;
cp = walk;
while (*cp != '\0' && !isspace(*cp))
cp++;
*cp = 0;
if (cp < line + linelen)
cp++;
if (*walk == '\0') {
printf("%s", line);
continue;
}
if (soelim_file(soelim_fopen(walk), flag) == 1) {
free(line);
return (1);
}
if (*cp != '\0')
printf("%s", cp);
}
free(line);
fclose(f);
return (0);
}
int
main(int argc, char **argv)
{
int ch, i;
int ret = 0;
int flags = 0;
includes = sl_init();
if (includes == NULL)
err(EXIT_FAILURE, "sl_init()");
while ((ch = getopt(argc, argv, "CrtvI:")) != -1) {
switch (ch) {
case 'C':
flags |= C_OPTION;
break;
case 'r':
case 'v':
case 't':
/* stub compatibility with groff's soelim */
break;
case 'I':
sl_add(includes, optarg);
break;
default:
sl_free(includes, 0);
usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
ret = soelim_file(stdin, flags);
for (i = 0; i < argc; i++)
ret = soelim_file(soelim_fopen(argv[i]), flags);
sl_free(includes, 0);
return (ret);
}

5
st.c
View File

@ -1,4 +1,4 @@
/* $Id: st.c,v 1.11 2014/08/10 23:54:41 schwarze Exp $ */
/* $Id: st.c,v 1.13 2015/10/06 18:32:20 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -20,6 +20,7 @@
#include <string.h>
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
@ -32,5 +33,5 @@ mdoc_a2st(const char *p)
#include "st.in"
return(NULL);
return NULL;
}

192
tag.c Normal file
View File

@ -0,0 +1,192 @@
/* $Id: tag.c,v 1.11 2015/11/20 21:59:54 schwarze Exp $ */
/*
* Copyright (c) 2015 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.
*/
#include "config.h"
#include <sys/types.h>
#include <signal.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
#include "tag.h"
struct tag_entry {
size_t line;
int prio;
char s[];
};
static void tag_signal(int);
static struct ohash tag_data;
static struct tag_files tag_files;
/*
* Prepare for using a pager.
* Not all pagers are capable of using a tag file,
* but for simplicity, create it anyway.
*/
struct tag_files *
tag_init(void)
{
struct sigaction sa;
int ofd;
ofd = -1;
tag_files.tfd = -1;
tag_files.tcpgid = -1;
/* Save the original standard output for use by the pager. */
if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
goto fail;
/* Create both temporary output files. */
(void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
sizeof(tag_files.ofn));
(void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
sizeof(tag_files.tfn));
memset(&sa, 0, sizeof(sa));
sigfillset(&sa.sa_mask);
sa.sa_handler = tag_signal;
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
if ((ofd = mkstemp(tag_files.ofn)) == -1)
goto fail;
if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
goto fail;
if (dup2(ofd, STDOUT_FILENO) == -1)
goto fail;
close(ofd);
/*
* Set up the ohash table to collect output line numbers
* where various marked-up terms are documented.
*/
mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
return &tag_files;
fail:
tag_unlink();
if (ofd != -1)
close(ofd);
if (tag_files.ofd != -1)
close(tag_files.ofd);
if (tag_files.tfd != -1)
close(tag_files.tfd);
*tag_files.ofn = '\0';
*tag_files.tfn = '\0';
tag_files.ofd = -1;
tag_files.tfd = -1;
return NULL;
}
/*
* Set the line number where a term is defined,
* unless it is already defined at a higher priority.
*/
void
tag_put(const char *s, int prio, size_t line)
{
struct tag_entry *entry;
size_t len;
unsigned int slot;
if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL)
return;
slot = ohash_qlookup(&tag_data, s);
entry = ohash_find(&tag_data, slot);
if (entry == NULL) {
len = strlen(s) + 1;
entry = mandoc_malloc(sizeof(*entry) + len);
memcpy(entry->s, s, len);
ohash_insert(&tag_data, slot, entry);
} else if (entry->prio <= prio)
return;
entry->line = line;
entry->prio = prio;
}
/*
* Write out the tags file using the previously collected
* information and clear the ohash table while going along.
*/
void
tag_write(void)
{
FILE *stream;
struct tag_entry *entry;
unsigned int slot;
if (tag_files.tfd <= 0)
return;
stream = fdopen(tag_files.tfd, "w");
entry = ohash_first(&tag_data, &slot);
while (entry != NULL) {
if (stream != NULL)
fprintf(stream, "%s %s %zu\n",
entry->s, tag_files.ofn, entry->line);
free(entry);
entry = ohash_next(&tag_data, &slot);
}
ohash_delete(&tag_data);
if (stream != NULL)
fclose(stream);
}
void
tag_unlink(void)
{
pid_t tc_pgid;
if (tag_files.tcpgid != -1) {
tc_pgid = tcgetpgrp(STDIN_FILENO);
if (tc_pgid == tag_files.pager_pid ||
tc_pgid == getpgid(0) ||
getpgid(tc_pgid) == -1)
(void)tcsetpgrp(STDIN_FILENO, tag_files.tcpgid);
}
if (*tag_files.ofn != '\0')
unlink(tag_files.ofn);
if (*tag_files.tfn != '\0')
unlink(tag_files.tfn);
}
static void
tag_signal(int signum)
{
struct sigaction sa;
tag_unlink();
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_DFL;
sigaction(signum, &sa, NULL);
kill(getpid(), signum);
/* NOTREACHED */
_exit(1);
}

View File

@ -1,7 +1,6 @@
/* $Id: manpath.h,v 1.7 2014/12/01 04:05:32 schwarze Exp $ */
/* $Id: tag.h,v 1.7 2015/11/20 21:59:54 schwarze Exp $ */
/*
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -16,19 +15,17 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Unsorted list of unique, absolute paths to be searched for manual
* databases.
*/
struct manpaths {
size_t sz;
char **paths;
struct tag_files {
char ofn[20];
char tfn[20];
int ofd;
int tfd;
pid_t tcpgid;
pid_t pager_pid;
};
__BEGIN_DECLS
void manpath_manconf(struct manpaths *, const char *);
void manpath_parse(struct manpaths *, const char *, char *, char *);
void manpath_free(struct manpaths *);
__END_DECLS
struct tag_files *tag_init(void);
void tag_put(const char *, int, size_t);
void tag_write(void);
void tag_unlink(void);

18
tbl.c
View File

@ -1,4 +1,4 @@
/* $Id: tbl.c,v 1.39 2015/01/30 17:32:16 schwarze Exp $ */
/* $Id: tbl.c,v 1.40 2015/10/06 18:32:20 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -66,7 +66,7 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
if (*cp == ';') {
tbl_option(tbl, ln, p, &pos);
if (p[pos] == '\0')
return(ROFF_IGN);
return ROFF_IGN;
}
}
@ -75,15 +75,15 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
switch (tbl->part) {
case TBL_PART_LAYOUT:
tbl_layout(tbl, ln, p, pos);
return(ROFF_IGN);
return ROFF_IGN;
case TBL_PART_CDATA:
return(tbl_cdata(tbl, ln, p, pos) ? ROFF_TBL : ROFF_IGN);
return tbl_cdata(tbl, ln, p, pos) ? ROFF_TBL : ROFF_IGN;
default:
break;
}
tbl_data(tbl, ln, p, pos);
return(ROFF_TBL);
return ROFF_TBL;
}
struct tbl_node *
@ -98,7 +98,7 @@ tbl_alloc(int pos, int line, struct mparse *parse)
tbl->part = TBL_PART_OPTS;
tbl->opts.tab = '\t';
tbl->opts.decimal = '.';
return(tbl);
return tbl;
}
void
@ -155,7 +155,7 @@ tbl_span(struct tbl_node *tbl)
: tbl->first_span;
if (span)
tbl->current_span = span;
return(span);
return span;
}
int
@ -177,7 +177,7 @@ tbl_end(struct tbl_node **tblp)
if (sp == NULL) {
mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse,
tbl->line, tbl->pos, NULL);
return(0);
return 0;
}
return(1);
return 1;
}

View File

@ -1,4 +1,4 @@
/* $Id: tbl_data.c,v 1.39 2015/01/30 17:32:16 schwarze Exp $ */
/* $Id: tbl_data.c,v 1.41 2015/10/06 18:32:20 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -132,11 +132,12 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
if (p[pos] == tbl->opts.tab) {
tbl->part = TBL_PART_DATA;
pos++;
getdata(tbl, tbl->last_span, ln, p, &pos);
return(1);
while (p[pos] != '\0')
getdata(tbl, tbl->last_span, ln, p, &pos);
return 1;
} else if (p[pos] == '\0') {
tbl->part = TBL_PART_DATA;
return(1);
return 1;
}
/* Fallthrough: T} is part of a word. */
@ -156,7 +157,7 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
ln, pos, dat->string);
return(0);
return 0;
}
static struct tbl_span *
@ -177,7 +178,7 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
dp->prev->next = dp;
tbl->last_span = dp;
return(dp);
return dp;
}
void

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