Import mandoc 1.14.2

This commit is contained in:
Baptiste Daroussin 2017-07-31 19:17:54 +00:00
parent 7ad21139cd
commit 75b6c55cb0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/mdocml/dist/; revision=321807
svn path=/vendor/mdocml/1.14.2/; revision=321808; tag=vendor/mandoc/1.14.2
83 changed files with 3787 additions and 1972 deletions

26
INSTALL
View File

@ -1,22 +1,24 @@
$Id: INSTALL,v 1.18 2017/02/08 12:24:10 schwarze Exp $
$Id: INSTALL,v 1.20 2017/07/28 14:57:56 schwarze Exp $
About the portable mandoc distribution
--------------------------------------
The mandoc manpage compiler toolset (formerly called "mdocml")
is a suite of tools compiling mdoc(7), the roff(7) macro language
of choice for BSD manual pages, and man(7), the predominant
historical language for UNIX manuals.
About mdocml, the portable mandoc distribution
----------------------------------------------
The mandoc manpage compiler toolset is a suite of tools compiling
mdoc(7), the roff(7) macro language of choice for BSD manual pages,
and man(7), the predominant historical language for UNIX manuals.
It includes a man(1) manual viewer and additional tools.
For general information, see <http://mdocml.bsd.lv/>.
For general information, see <http://mandoc.bsd.lv/>.
In case you have questions or want to provide feedback, read
<http://mdocml.bsd.lv/contact.html>. Consider subscribing to the
<http://mandoc.bsd.lv/contact.html>. Consider subscribing to the
discuss@ mailing list mentioned on that page. If you intend to
help with the development of mandoc, consider subscribing to the
tech@ mailing list, too.
Enjoy using the mandoc toolset!
Ingo Schwarze, Karlsruhe, February 2017
Ingo Schwarze, Karlsruhe, July 2017
Installation
@ -25,7 +27,7 @@ Before manually installing mandoc on your system, please check
whether the newest version of mandoc is already installed by default
or available via a binary package or a ports system. A list of the
latest bundled and ported versions of mandoc for various operating
systems is maintained at <http://mdocml.bsd.lv/ports.html>.
systems is maintained at <http://mandoc.bsd.lv/ports.html>.
Regarding how packages and ports are maintained for your operating
system, please consult your operating system documentation.
@ -35,7 +37,7 @@ To install mandoc manually, the following steps are needed:
run the command "echo BUILD_CGI=1 >> configure.local".
Then run "cp cgi.h.example cgi.h" and edit cgi.h as desired.
2. If you also want to build the new catman(8) utility, run the
2. If you also want to build the catman(8) utility, run the
command "echo BUILD_CATMAN=1 >> configure.local". Note that it
is unlikely to be a drop-in replacement providing the same
functionality as your system's "catman", if your operating
@ -75,7 +77,7 @@ command like "make DESTDIR=... install". Read the *-install targets
in the "Makefile" to understand how DESTDIR is used.
9. Run the command "sudo makewhatis" to build mandoc.db(5) databases
in all the directory trees configured in step 6. Whenever installing
in all the directory trees configured in step 3. Whenever installing
new manual pages, re-run makewhatis(8) to update the databases, or
apropos(1) will not find the new pages.

View File

@ -1,7 +1,7 @@
$Id: LICENSE,v 1.15 2017/02/21 00:37:03 schwarze Exp $
$Id: LICENSE,v 1.17 2017/06/23 15:58:14 schwarze Exp $
With the exceptions noted below, all code and documentation
contained in the mdocml toolkit is protected by the Copyright
contained in the mandoc toolkit is protected by the Copyright
of the following developers:
Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
@ -13,7 +13,7 @@ Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.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) 2008, 2017 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>
@ -22,7 +22,7 @@ See the individual source files for information about who contributed
to which file during which years.
The mdocml distribution as a whole is distributed by its developers
The mandoc distribution as a whole is distributed by its developers
under the following license:
Permission to use, copy, modify, and distribute this software for any

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.512 2017/05/07 17:31:45 schwarze Exp $
# $Id: Makefile,v 1.516 2017/07/20 16:24:53 schwarze Exp $
#
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
# Copyright (c) 2011, 2013-2017 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.
VERSION = 1.14.1
VERSION = 1.14.2
# === LIST OF FILES ====================================================
@ -38,6 +38,7 @@ TESTSRCS = test-be32toh.c \
test-progname.c \
test-recvmsg.c \
test-reallocarray.c \
test-recallocarray.c \
test-rewb-bsd.c \
test-rewb-sysv.c \
test-sandbox_init.c \
@ -64,6 +65,7 @@ SRCS = att.c \
compat_ohash.c \
compat_progname.c \
compat_reallocarray.c \
compat_recallocarray.c \
compat_strcasestr.c \
compat_stringlist.c \
compat_strlcat.c \
@ -92,6 +94,7 @@ SRCS = att.c \
mandoc.c \
mandoc_aux.c \
mandoc_ohash.c \
mandoc_xr.c \
mandocd.c \
mandocdb.c \
manpath.c \
@ -178,6 +181,7 @@ DISTFILES = INSTALL \
mandoc_html.3 \
mandoc_malloc.3 \
mandoc_ohash.h \
mandoc_xr.h \
mandocd.8 \
mansearch.3 \
mansearch.h \
@ -227,6 +231,7 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
mandoc.o \
mandoc_aux.o \
mandoc_ohash.o \
mandoc_xr.o \
msec.o \
preconv.o \
read.o
@ -240,6 +245,7 @@ COMPAT_OBJS = compat_err.o \
compat_ohash.o \
compat_progname.o \
compat_reallocarray.o \
compat_recallocarray.o \
compat_strcasestr.o \
compat_strlcat.o \
compat_strlcpy.o \
@ -341,9 +347,6 @@ WWW_MANS = apropos.1.html \
mdoc.h.html \
roff.h.html
WWW_OBJS = mdocml.tar.gz \
mdocml.sha256
# === USER CONFIGURATION ===============================================
include Makefile.local
@ -354,7 +357,7 @@ all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local
install: base-install $(INSTALL_TARGETS)
www: $(WWW_OBJS) $(WWW_MANS)
www: $(WWW_MANS)
$(WWW_MANS): mandoc
@ -372,10 +375,10 @@ clean:
rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS)
rm -f mandoc $(MAIN_OBJS)
rm -f man.cgi $(CGI_OBJS)
rm -f mandocd catman $(MANDOCD_OBJS)
rm -f mandocd catman catman.o $(MANDOCD_OBJS)
rm -f demandoc $(DEMANDOC_OBJS)
rm -f soelim $(SOELIM_OBJS)
rm -f $(WWW_MANS) $(WWW_OBJS)
rm -f $(WWW_MANS) mandoc.tar.gz mandoc.sha256
rm -rf *.dSYM
base-install: mandoc demandoc soelim
@ -509,13 +512,7 @@ soelim: $(SOELIM_OBJS)
# --- maintainer targets ---
www-install: www
mkdir -p $(HTDOCDIR)/snapshots
$(INSTALL_DATA) $(WWW_MANS) mandoc.css $(HTDOCDIR)
$(INSTALL_DATA) $(WWW_OBJS) $(HTDOCDIR)/snapshots
$(INSTALL_DATA) mdocml.tar.gz \
$(HTDOCDIR)/snapshots/mdocml-$(VERSION).tar.gz
$(INSTALL_DATA) mdocml.sha256 \
$(HTDOCDIR)/snapshots/mdocml-$(VERSION).sha256
depend: config.h
mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
@ -542,24 +539,25 @@ regress-distcheck:
! -name '*.out_ascii' \
! -name '*.out_utf8' \
! -name '*.out_html' \
! -name '*.out_markdown' \
! -name '*.out_lint' \
! -path regress/regress.pl \
! -path regress/regress.pl.1
dist: mdocml.sha256
dist: mandoc.sha256
mdocml.sha256: mdocml.tar.gz
sha256 mdocml.tar.gz > $@
mandoc.sha256: mandoc.tar.gz
sha256 mandoc.tar.gz > $@
mdocml.tar.gz: $(DISTFILES)
mandoc.tar.gz: $(DISTFILES)
ls regress/*/*/*.mandoc_* && exit 1 || true
mkdir -p .dist/mdocml-$(VERSION)/
$(INSTALL) -m 0644 $(DISTFILES) .dist/mdocml-$(VERSION)
cp -pR regress .dist/mdocml-$(VERSION)
find .dist/mdocml-$(VERSION)/regress \
mkdir -p .dist/mandoc-$(VERSION)/
$(INSTALL) -m 0644 $(DISTFILES) .dist/mandoc-$(VERSION)
cp -pR regress .dist/mandoc-$(VERSION)
find .dist/mandoc-$(VERSION)/regress \
-type d -name CVS -print0 | xargs -0 rm -rf
chmod 755 .dist/mdocml-$(VERSION)/configure
( cd .dist/ && tar zcf ../$@ mdocml-$(VERSION) )
chmod 755 .dist/mandoc-$(VERSION)/configure
( cd .dist/ && tar zcf ../$@ mandoc-$(VERSION) )
rm -rf .dist/
# === SUFFIX RULES =====================================================

View File

@ -1,4 +1,4 @@
att.o: att.c config.h roff.h mdoc.h libmdoc.h
att.o: att.c config.h mandoc.h roff.h mdoc.h libmdoc.h
catman.o: catman.c config.h compat_fts.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
@ -11,6 +11,7 @@ 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_recallocarray.o: compat_recallocarray.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
@ -24,44 +25,45 @@ dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h
dba_write.o: dba_write.c config.h dba_write.h
dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h
dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.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
demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h
eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.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_aux.h mandoc.h roff.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
lib.o: lib.c config.h mandoc.h roff.h mdoc.h libmdoc.h lib.in
main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.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_html.o: man_html.c config.h mandoc_aux.h roff.h man.h out.h html.h main.h
man_html.o: man_html.c config.h mandoc_aux.h mandoc.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.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h
mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.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 dba_array.h dba.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 dbm.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 roff_int.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_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.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_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.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
mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.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_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h roff_int.h
read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h
roff.o: roff.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h libmandoc.h roff_int.h libroff.h predefs.in
roff_html.o: roff_html.c roff.h out.h html.h
roff_term.o: roff_term.c roff.h out.h term.h
roff_html.o: roff_html.c mandoc.h roff.h out.h html.h
roff_term.o: roff_term.c mandoc.h roff.h out.h term.h
roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h
soelim.o: soelim.c config.h compat_stringlist.h
st.o: st.c config.h roff.h mdoc.h libmdoc.h st.in
st.o: st.c config.h mandoc.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

98
NEWS
View File

@ -1,6 +1,92 @@
$Id: NEWS,v 1.21 2017/02/21 00:37:03 schwarze Exp $
$Id: NEWS,v 1.26 2017/07/28 14:57:56 schwarze Exp $
This file lists the most important changes in the mdocml.bsd.lv distribution.
This file lists the most important changes in the mandoc.bsd.lv distribution.
Changes in version 1.14.2, released on July 28, 2017
--- MAJOR NEW FEATURES ---
* New mdoc(7) -Tmarkdown output mode.
* For -Thtml, implement internal hyperlinks pointing to authoritative
definitions of various syntax elements, similar to the ctags(1)-like
less(1) :t internal searching in terminal mode.
* Provide a superset of the functionality of the former mdoclint(1)
utility and a new -Wstyle message level with several new messages,
including validity checking of .Xr cross references.
* tbl(7): Implement automatic line breaking inside individual table
cells, and several other formatting improvements.
* eqn(7): Complete rewrite of the lexer, resulting in several bugfixes.
* Continue parser unification, in particular allowing generation
of syntax tree nodes on the roff(7) level, allowing implementation
of many additional roff requests.
--- REMOVED FUNCTIONALITY ---
* Delete the manpage(1) utility. It was never enabled in any release.
* Delete the -Txhtml command line option. It has been an obsolete
alias for the -Thtml output mode for more than two years.
--- MINOR NEW FEATURES ---
* -Tlint now puts parser messages on stdout instead of stderr,
making commands like "man -l -Tlint *.1" useful.
* mdoc(7): Various .Lk formatting improvements.
* mdoc(7) -Thtml: Better CSS for .Bl lists.
* man(7): Implement the .MT/.ME block macro (mailto hyperlink).
* man(7): Implement the .DT macro (restore default tab positions).
* man(7): Improved support for manuals generated with reStructuredText
by partial support for the \n[an-margin] number register.
* man(7) -Thtml: Support deep linking to .SH and .SS headers.
* tbl(7): Implement the "allbox" table option.
* tbl(7): Implement the column spacing and the 'w' (minimum column
width) layout modifiers.
* tbl(7): Significant improvements of the manual page.
* eqn(7): Much improved font selection, including recognition of
well-known function names, and a few other formatting improvements.
* eqn(7) -Thtml: Use <mn> and <mo> in addition to <mi>.
* roff(7): Implement the .ce (centering), .mc (margin character),
.rj (right justify), .ta (define tab stops), .ti (temporary indent),
.als (macro alias), .ec and .eo (escape character control),
.po (page offset), and .rn (macro rename) requests.
* roff(7) .am: Implement appending to mdoc(7) and man(7) macros.
* roff(7): implement the \h (horizontol motion), \l (horizontal
line drawing), and \p (break output line) escape sequences,
and also several additional character escape sequences.
* roff(7): Implement the 'd' conditional (macro or string defined).
* man.cgi(8) now uses pledge(2), too.
* regress.pl(1): simpler user interface, better summary output,
simpler code, and no more recursion.
--- THANKS TO ---
* Anthony Bentley (OpenBSD) for the implementation of .MT/.ME,
reports of many bugs and missing features, and suggestions
for a number of feature and documentation improvements.
* Sebastien Marie (OpenBSD) for two source code patches and
for some useful discussions.
* Florian Obser (OpenBSD) for a bugfix patch and a bug report.
* Jonathan Gray (OpenBSD) for several bug reports from afl(1)
and several more from static analysis tools.
* Theo Buehler (OpenBSD) for several bug reports, most from afl(1).
* Jason McIntyre (OpenBSD) for many useful discussions about a
wide variety of topics, lots of continuous testing, a number of
bug reports, and some suggestions for messages and documentation.
* Thomas Klausner (NetBSD) for lots of help while migrating
mdoclint(1) functionality to mandoc -Tlint, for suggesting
several useful new messages, and for release testing.
* Reyk Floeter (OpenBSD) and Vsevolod Stakhov (FreeBSD) for
suggesting a markdown output mode.
* Thomas Guettler for suggesting -Thtml internal hyperlinks.
* Yuri Pankov (Illumos) for inspiring new warning messages and
for extensive release testing.
* Anton Lindqvist and TJ Townsend (both OpenBSD) and Jan Stary
for multiple bug reports.
* Leah Neukirchen (Void Linux) for bug reports and release testing.
* Michael Stapelberg (Debian) for suggesting feature improvements
and for release testing.
* Martin Natano and Theo de Raadt (both OpenBSD), Andreas Voegele,
Gabriel Guzman, Gonzalo Tornaria, Markus Waldeck, and Raf Czlonka
for bug reports.
* Antoine Jacoutot (OpenBSD) and Steffen Nurpmeso for suggesting
feature improvements.
* Dag-Erling Smoergrav (FreeBSD) for inspiring new warning messages.
* Ted Unangst and Marc Espie (OpenBSD) for providing useful ideas.
* Svyatoslav Mishyn (Crux Linux) for release testing.
* Carsten Kunze (Heirloom roff) for help keeping mandoc and groff
compatible and for committing some of my patches to groff.
Changes in version 1.14.1, released on February 21, 2017
@ -274,11 +360,11 @@ Changes in version 1.13.3, released on March 13, 2015
* New -Wunsupp message level.
--- POTENTIONALLY SECURITY RELEVANT BUGFIXES ---
* Fix a potential write buffer overrun on incomplete string conditionals.
http://mdocml.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.241
http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.241
* Fix a potential write buffer overrun on backslash at EOF in a conditional.
http://mdocml.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.247
http://mandoc.bsd.lv/cgi-bin/cvsweb/roff.c#rev1.247
* Fix a use after free sometimes hit when validation deletes a block.
http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_macro.c#rev1.180
http://mandoc.bsd.lv/cgi-bin/cvsweb/mdoc_macro.c#rev1.180
--- MAJOR FUNCTIONALLY RELEVANT BUGFIXES ---
* Let man(1) show manuals for the current architecture by default,
and support the MACHINE environment variable.
@ -889,4 +975,4 @@ Changes in version 1.9.15, released on February 18, 2010
* and column lengths handled correctly.
For older releases, see the ChangeLog files
in http://mdocml.bsd.lv/snapshots/ .
in http://mandoc.bsd.lv/snapshots/ .

110
TODO
View File

@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
* $Id: TODO,v 1.237 2017/05/16 19:06:30 schwarze Exp $
* $Id: TODO,v 1.246 2017/07/24 11:15:12 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@ -65,21 +65,10 @@ are mere guesses, and some may be wrong.
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
loc * exist ** algo ** size ** imp **
- \h horizontal move
#2 most important issue naddy@ Mon, 16 Feb 2015 20:59:17 +0100
found in cclive(1) nasm(1) bogofilter(1) asciidoc/DocBook output
bentley@ on discuss@ Sat, 21 Sep 2013 22:29:34 -0600
naddy@ Thu, 4 Dec 2014 16:26:41 +0100
loc ** exist ** algo ** size * imp *** (parser reorg helps a lot)
- \n+ and \n- numerical register increment and decrement
found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
loc * exist * algo * size * imp **
- \n(.$ macro argument count number register; ocserv(8) by autogen
found by sthen@ Thu, 19 Feb 2015 22:03:01 +0000
loc * exist ** algo * size * imp **
- \w'' improve width measurements
would not be very useful without an expression parser, see below
needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
@ -183,22 +172,6 @@ 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 ***
- break long text into lines inside cells
net/lftp(1) from jirib via bentley@ Sep 13, 2016
- layout l1 for a column of max text width 3 reduces the following
inter-column spacing for groff, but not for mandoc
net/lftp(1) from jirib via bentley@ Sep 13, 2016
- 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
@ -240,6 +213,16 @@ are mere guesses, and some may be wrong.
see User's Guide (Second Edition) page 5 section 15.
loc ** exist ** algo ** size ** imp **
- GNU eqn converts some operators to special characters, for example,
input HYPHEN-MINUS becomes output \(mi, unless it is part of a
quoted word. mandoc(1) only does this when the operator is
surrounded by blanks, not when it is part of an unquoted word.
Also, check whether there are more such cases (e.g., +?).
reported by bentley@ 20 Jun 2017 02:04:29 -0600
- Primes, opprime, and '
bentley@ Thu, 13 Jul 2017 23:14:20 -0600
--- missing misc features ----------------------------------------------
- italic correction (\/) in PostScript mode
@ -359,6 +342,12 @@ are mere guesses, and some may be wrong.
.Vt vs .Vt/.Va vs .Ft/.Va vs .Ft/.Fa ...
from kristaps@ Tue, 08 Jun 2010 11:13:32 +0200
- implicit whitespace around inline equations
example code: where '$times$' denotes matrix multiplication
must not have an HTML line break, nor a blank, before <math>
partial solution: html.c {"math", HTML_NLINSIDE | HTML_INDENT},
bentley@ Thu, 13 Jul 2017 19:00:59 -0600
- in enclosures, mandoc sometimes fancies a bogus end of sentence
reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059
loc * exist ** algo *** size * imp ***
@ -421,9 +410,6 @@ are mere guesses, and some may be wrong.
Steffen Nurpmeso Sat, 08 Nov 2014 13:34:59 +0100
loc * exist ** algo ** size * imp **
- .Lk formatting for long links with line breaks
Franco Fichtner 8 Oct 2013 00:33:42 +0200
- In .Bl -enum -width 0n, groff continues one the same line after
the number, mandoc breaks the line.
mail to kristaps@ Mon, 20 Jul 2009 02:21:39 +0200
@ -450,16 +436,6 @@ are mere guesses, and some may be wrong.
Probably, this should be fixed somewhere in termp_it_pre(), not sure.
loc * exist ** algo ** size * imp **
- .Nx 1.0a
should be "NetBSD 1.0A", not "NetBSD 1.0a",
see OpenBSD ccdconfig(8).
loc * exist * algo * size * imp **
- In .Bl -tag, if a tag exceeds the right margin and must be continued
on the next line, it must be indented by -width, not width+1;
see "rule block|pass" in OpenBSD ifconfig(8).
loc * exist *** algo ** size * imp **
- When the -width string contains macros, the macros must be rendered
before measuring the width, for example
.Bl -tag -width ".Dv message"
@ -495,15 +471,24 @@ are mere guesses, and some may be wrong.
* 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
- style message about macros inside .Bd -literal and .Dl, in particular
font changing macros like .Cm, .Ar, .Fa (from the mdoclint TODO)
- style message about mismatches between the section number in the
file name (if it is known) and the section number in .Dt
(from the mdoclint TODO)
- style message about NULL without .Dv (from the mdoclint TODO)
- style message about error constants without .Er (from the mdoclint TODO)
- warn when .Sh or .Ss contain other macros
Steffen Nurpmeso, savannah.gnu.org/bugs/index.php?45034
loc * exist * algo * size * imp **
- style message about violations of the convention
.An name Aq Mt localpart@domain in AUTHORS (from the mdoclint TODO)
- warn about attempts to call non-callable macros
Steffen Nurpmeso Tue, 11 Nov 2014 22:55:16 +0100
Note that formatting is inconsistent in groff.
@ -512,25 +497,25 @@ are mere guesses, and some may be wrong.
all over mdoc_macro.c and all subtly different.
loc ** exist ** algo ** size ** imp **
- style message about suspicious uses of - vs. \- vs. \(mi
e.g. -1 is likely wrong (from the mdoclint TODO)
- warn about punctuation - e.g. ',' and ';' - at the beginning
of a text line, if it is likely intended to follow the preceding
output without intervening whitespace, in particular after a
macro line (from the mdoclint TODO)
- mandoc_special does not really check the escape sequence,
but just the overall format
loc ** exist ** algo *** size ** imp **
- integrate mdoclint into mandoc ("end-of-line whitespace" thread)
from jmc@ Mon, 13 Jul 2009 17:12:09 +0100
from kristaps@ Mon, 13 Jul 2009 18:34:53 +0200
from jmc@ Mon, 13 Jul 2009 17:45:37 +0059
from kristaps@ Mon, 13 Jul 2009 19:02:03 +0200
(mostly done, check what remains)
- -Tlint parser errors and warnings to stdout
to tech@mdocml, naddy@ Wed, 28 Sep 2011 11:21:46 +0200
wait! kristaps@ Sun, 02 Oct 2011 17:12:52 +0200
************************************************************************
* documentation issues
************************************************************************
- dashes, hyphens, and minus signs in manual pages
jmc@ Fri, 28 Mar 2014 07:19:27 +0000
- mark macros as: page structure domain, manual domain, general text domain
is this useful?
@ -543,11 +528,6 @@ are mere guesses, and some may be wrong.
* performance issues
************************************************************************
- Why are we using MAP_SHARED, not MAP_PRIVATE for mmap(2)?
from kristaps@ Sat, 09 Aug 2014 13:51:36 +0200
Several areas can be cleaned up to make mandoc even faster. These are
- the PDF file is HUGE: this can be reduced by using relative offsets
************************************************************************
@ -565,13 +545,13 @@ Several areas can be cleaned up to make mandoc even faster. These are
same-line from different-line input. That plainly doesn't work
with user-defined macros, leading to random breakage.
- Is it possible to further simplify ENDBODY_SPACE?
- Find better ways to prevent endless loops
in roff(7) macro and string expansion.
- Finish cleanup of date handling.
Decide which formats should be recognized where.
Update both mdoc(7) and man(7) documentation.
Triggered by Tim van der Molen Tue, 22 Feb 2011 20:30:45 +0100
- make buffers for parsing functions const
christos@ via wiz@ Fri, 18 Dec 2015 17:10:01 +0100
- struct mparse refactoring
Steffen Nurpmeso Thu, 04 Sep 2014 12:50:00 +0200

View File

@ -1,4 +1,4 @@
.\" $Id: apropos.1,v 1.45 2017/03/27 18:51:36 schwarze Exp $
.\" $Id: apropos.1,v 1.46 2017/07/04 23:40:01 schwarze Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012, 2014, 2017 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 27 2017 $
.Dd $Mdocdate: July 4 2017 $
.Dt APROPOS 1
.Os
.Sh NAME
@ -407,7 +407,7 @@ variables:
.Dl $ apropos \-s 3 Va=optind \-a Va=optarg
.Pp
Do exactly the same as calling
.Xr whatis 1
.Nm whatis
with the argument
.Qq ssh :
.Pp

3
att.c
View File

@ -1,4 +1,4 @@
/* $Id: att.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
/* $Id: att.c,v 1.16 2017/06/24 14:38:32 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -19,6 +19,7 @@
#include <sys/types.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"

12
cgi.c
View File

@ -1,4 +1,4 @@
/* $Id: cgi.c,v 1.154 2017/04/19 01:00:03 schwarze Exp $ */
/* $Id: cgi.c,v 1.156 2017/06/24 14:38:32 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@usta.de>
@ -140,16 +140,16 @@ html_putchar(char c)
{
switch (c) {
case ('"'):
case '"':
printf("&quot;");
break;
case ('&'):
case '&':
printf("&amp;");
break;
case ('>'):
case '>':
printf("&gt;");
break;
case ('<'):
case '<':
printf("&lt;");
break;
default:
@ -832,7 +832,7 @@ resp_format(const struct req *req, const char *file)
mchars_alloc();
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
MANDOCLEVEL_BADARG, NULL, req->q.manpath);
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath);
mparse_readfd(mp, fd, file);
close(fd);

View File

@ -1,4 +1,4 @@
/* $Id: chars.c,v 1.70 2017/06/02 12:43:52 schwarze Exp $ */
/* $Id: chars.c,v 1.71 2017/06/14 20:57:07 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -61,6 +61,7 @@ static struct ln lines[] = {
{ "ba", "|", 0x007c },
{ "br", "|", 0x2502 },
{ "ul", "_", 0x005f },
{ "ru", "_", 0x005f },
{ "rn", "-", 0x203e },
{ "bb", "|", 0x00a6 },
{ "sl", "/", 0x002f },

108
compat_recallocarray.c Normal file
View File

@ -0,0 +1,108 @@
#include "config.h"
#if HAVE_RECALLOCARRAY
int dummy;
#else
/* $Id: compat_recallocarray.c,v 1.1 2017/06/12 19:05:47 schwarze Exp $ */
/* $OpenBSD: malloc.c,v 1.225 2017/05/13 07:11:29 otto Exp $ */
/*
* Copyright (c) 2017 Otto Moerbeek <otto@drijf.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
/*
* Even though specified in POSIX, the PAGESIZE and PAGE_SIZE
* macros have very poor portability. Since we only use this
* to avoid free() overhead for small shrinking, simply pick
* an arbitrary number.
*/
#define MALLOC_PAGESIZE (1UL << 12)
void *
recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
{
size_t oldsize, newsize;
void *newptr;
if (ptr == NULL)
return calloc(newnmemb, size);
if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
newnmemb > 0 && SIZE_MAX / newnmemb < size) {
errno = ENOMEM;
return NULL;
}
newsize = newnmemb * size;
if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
errno = EINVAL;
return NULL;
}
oldsize = oldnmemb * size;
/*
* Don't bother too much if we're shrinking just a bit,
* we do not shrink for series of small steps, oh well.
*/
if (newsize <= oldsize) {
size_t d = oldsize - newsize;
if (d < oldsize / 2 && d < MALLOC_PAGESIZE) {
memset((char *)ptr + newsize, 0, d);
return ptr;
}
}
newptr = malloc(newsize);
if (newptr == NULL)
return NULL;
if (newsize > oldsize) {
memcpy(newptr, ptr, oldsize);
memset((char *)newptr + oldsize, 0, newsize - oldsize);
} else
memcpy(newptr, ptr, newsize);
/*
* At this point, the OpenBSD implementation calls
* explicit_bzero() on the old memory before it is
* freed. Since explicit_bzero() is hard to implement
* portably and we don't handle confidential data in
* mandoc in the first place, simply free the memory
* without clearing it.
*/
free(ptr);
return newptr;
}
#endif /* !HAVE_RECALLOCARRAY */

13
configure vendored
View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# $Id: configure,v 1.62 2017/03/04 16:36:29 schwarze Exp $
# $Id: configure,v 1.64 2017/07/01 09:47:30 schwarze Exp $
#
# Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
#
@ -35,6 +35,7 @@ echo "config.log: writing..."
SOURCEDIR=`dirname "$0"`
MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
OSNAME=
UTF8_LOCALE=
@ -73,6 +74,7 @@ HAVE_PATH_MAX=
HAVE_PLEDGE=
HAVE_PROGNAME=
HAVE_REALLOCARRAY=
HAVE_RECALLOCARRAY=
HAVE_RECVMSG=
HAVE_REWB_BSD=
HAVE_REWB_SYSV=
@ -229,6 +231,7 @@ runtest pledge PLEDGE || true
runtest sandbox_init SANDBOX_INIT || true
runtest progname PROGNAME || true
runtest reallocarray REALLOCARRAY || true
runtest recallocarray RECALLOCARRAY || true
runtest rewb-bsd REWB_BSD || true
runtest rewb-sysv REWB_SYSV || true
runtest strcasestr STRCASESTR || true
@ -348,7 +351,8 @@ cat << __HEREDOC__
__HEREDOC__
[ ${HAVE_GETLINE} -eq 0 -o ${HAVE_REALLOCARRAY} -eq 0 -o \
[ ${HAVE_GETLINE} -eq 0 -o \
${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \
${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 ] \
&& echo "#include <sys/types.h>"
[ ${HAVE_VASPRINTF} -eq 0 ] && echo "#include <stdarg.h>"
@ -356,6 +360,7 @@ __HEREDOC__
echo
echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\""
echo "#define MANPATH_BASE \"${MANPATH_BASE}\""
echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\""
[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\""
[ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\""
@ -383,6 +388,7 @@ cat << __HEREDOC__
#define HAVE_PLEDGE ${HAVE_PLEDGE}
#define HAVE_PROGNAME ${HAVE_PROGNAME}
#define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY}
#define HAVE_RECALLOCARRAY ${HAVE_RECALLOCARRAY}
#define HAVE_REWB_BSD ${HAVE_REWB_BSD}
#define HAVE_REWB_SYSV ${HAVE_REWB_SYSV}
#define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT}
@ -434,6 +440,9 @@ fi
[ ${HAVE_REALLOCARRAY} -eq 0 ] && \
echo "extern void *reallocarray(void *, size_t, size_t);"
[ ${HAVE_RECALLOCARRAY} -eq 0 ] && \
echo "extern void *recallocarray(void *, size_t, size_t, size_t);"
[ ${HAVE_STRCASESTR} -eq 0 ] && \
echo "extern char *strcasestr(const char *, const char *);"

View File

@ -1,4 +1,4 @@
# $Id: configure.local.example,v 1.30 2017/03/04 16:36:29 schwarze Exp $
# $Id: configure.local.example,v 1.33 2017/07/20 16:24:53 schwarze Exp $
#
# Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
#
@ -20,7 +20,7 @@
# and put any of these settings into it if ./configure autodetection
# fails or if you want to make different choices for other reasons.
# If autodetection fails, please tell <tech@mdocml.bsd.lv>.
# If autodetection fails, please tell <tech@mandoc.bsd.lv>.
# We recommend that you write ./configure.local from scratch and
# only put the lines there you need. This file contains examples.
@ -62,6 +62,11 @@ UTF8_LOCALE=en_US.UTF-8
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
# Validation of cross references with mandoc -Tlint only looks
# for manual pages in the following directories:
MANPATH_BASE="/usr/share/man:/usr/X11R6/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.
@ -292,6 +297,7 @@ HAVE_PATH_MAX=0
HAVE_PLEDGE=0
HAVE_PROGNAME=0
HAVE_REALLOCARRAY=0
HAVE_RECALLOCARRAY=0
HAVE_REWB_BSD=0
HAVE_REWB_SYSV=0
HAVE_STRCASESTR=0

View File

@ -1,4 +1,4 @@
/* $Id: demandoc.c,v 1.28 2017/01/10 13:47:00 schwarze Exp $ */
/* $Id: demandoc.c,v 1.29 2017/06/24 14:38:32 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -25,10 +25,10 @@
#include <string.h>
#include <unistd.h>
#include "mandoc.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 roff_node *, int *, int *, int);
@ -78,7 +78,8 @@ main(int argc, char *argv[])
argv += optind;
mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, NULL);
mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL,
MANDOC_OS_OTHER, NULL);
assert(mp);
if (argc < 1)

6
eqn.7
View File

@ -1,4 +1,4 @@
.\" $Id: eqn.7,v 1.35 2015/03/30 16:06:14 schwarze Exp $
.\" $Id: eqn.7,v 1.36 2017/07/20 11:07:27 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 30 2015 $
.Dd $Mdocdate: July 20 2017 $
.Dt EQN 7
.Os
.Sh NAME
@ -125,7 +125,7 @@ int (integral), sum (summation), grad (gradient), del (vector
differential), times (multiply), cdot (center-dot), nothing (zero-width
space), approx (approximately equals), prime (prime), half (one-half),
partial (partial differential), inf (infinity), >> (much greater), <<
(much less), \-> (left arrow), <\- (right arrow), +\- (plus-minus), !=
(much less), <\- (left arrow), \-> (right arrow), +\- (plus-minus), !=
(not equal), == (equivalence), <= (less-than-equal), and >=
(more-than-equal).
The character escape sequences documented in

874
eqn.c

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $Id: eqn_html.c,v 1.11 2017/01/17 01:47:51 schwarze Exp $ */
/* $Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -20,6 +20,7 @@
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -33,7 +34,10 @@ eqn_box(struct html *p, const struct eqn_box *bp)
{
struct tag *post, *row, *cell, *t;
const struct eqn_box *child, *parent;
const char *cp;
size_t i, j, rows;
enum htmltag tag;
enum eqn_fontt font;
if (NULL == bp)
return;
@ -47,7 +51,8 @@ eqn_box(struct html *p, const struct eqn_box *bp)
if (EQN_MATRIX == bp->type) {
if (NULL == bp->first)
goto out;
if (EQN_LIST != bp->first->type) {
if (bp->first->type != EQN_LIST ||
bp->first->expectargs == 1) {
eqn_box(p, bp->first);
goto out;
}
@ -87,28 +92,28 @@ eqn_box(struct html *p, const struct eqn_box *bp)
}
switch (bp->pos) {
case (EQNPOS_TO):
case EQNPOS_TO:
post = print_otag(p, TAG_MOVER, "");
break;
case (EQNPOS_SUP):
case EQNPOS_SUP:
post = print_otag(p, TAG_MSUP, "");
break;
case (EQNPOS_FROM):
case EQNPOS_FROM:
post = print_otag(p, TAG_MUNDER, "");
break;
case (EQNPOS_SUB):
case EQNPOS_SUB:
post = print_otag(p, TAG_MSUB, "");
break;
case (EQNPOS_OVER):
case EQNPOS_OVER:
post = print_otag(p, TAG_MFRAC, "");
break;
case (EQNPOS_FROMTO):
case EQNPOS_FROMTO:
post = print_otag(p, TAG_MUNDEROVER, "");
break;
case (EQNPOS_SUBSUP):
case EQNPOS_SUBSUP:
post = print_otag(p, TAG_MSUBSUP, "");
break;
case (EQNPOS_SQRT):
case EQNPOS_SQRT:
post = print_otag(p, TAG_MSQRT, "");
break;
default:
@ -127,18 +132,68 @@ eqn_box(struct html *p, const struct eqn_box *bp)
if (EQN_PILE == bp->type) {
assert(NULL == post);
if (bp->first != NULL && bp->first->type == EQN_LIST)
if (bp->first != NULL &&
bp->first->type == EQN_LIST &&
bp->first->expectargs > 1)
post = print_otag(p, TAG_MTABLE, "");
} else if (bp->type == EQN_LIST &&
} else if (bp->type == EQN_LIST && bp->expectargs > 1 &&
bp->parent && bp->parent->type == EQN_PILE) {
assert(NULL == post);
post = print_otag(p, TAG_MTR, "");
print_otag(p, TAG_MTD, "");
}
if (NULL != bp->text) {
assert(NULL == post);
post = print_otag(p, TAG_MI, "");
if (bp->text != NULL) {
assert(post == NULL);
tag = TAG_MI;
cp = bp->text;
if (isdigit((unsigned char)cp[0]) ||
(cp[0] == '.' && isdigit((unsigned char)cp[1]))) {
tag = TAG_MN;
while (*++cp != '\0') {
if (*cp != '.' &&
isdigit((unsigned char)*cp) == 0) {
tag = TAG_MI;
break;
}
}
} else if (*cp != '\0' && isalpha((unsigned char)*cp) == 0) {
tag = TAG_MO;
while (*cp != '\0') {
if (cp[0] == '\\' && cp[1] != '\0') {
cp++;
mandoc_escape(&cp, NULL, NULL);
} else if (isalnum((unsigned char)*cp)) {
tag = TAG_MI;
break;
} else
cp++;
}
}
font = bp->font;
if (bp->text[0] != '\0' &&
(((tag == TAG_MN || tag == TAG_MO) &&
font == EQNFONT_ROMAN) ||
(tag == TAG_MI && font == (bp->text[1] == '\0' ?
EQNFONT_ITALIC : EQNFONT_ROMAN))))
font = EQNFONT_NONE;
switch (font) {
case EQNFONT_NONE:
post = print_otag(p, tag, "");
break;
case EQNFONT_ROMAN:
post = print_otag(p, tag, "?", "fontstyle", "normal");
break;
case EQNFONT_BOLD:
case EQNFONT_FAT:
post = print_otag(p, tag, "?", "fontweight", "bold");
break;
case EQNFONT_ITALIC:
post = print_otag(p, tag, "?", "fontstyle", "italic");
break;
default:
abort();
}
print_text(p, bp->text);
} else if (NULL == post) {
if (NULL != bp->left || NULL != bp->right)
@ -172,14 +227,17 @@ eqn_box(struct html *p, const struct eqn_box *bp)
}
void
print_eqn(struct html *p, const struct eqn *ep)
print_eqn(struct html *p, const struct eqn_box *bp)
{
struct tag *t;
if (bp->first == NULL)
return;
t = print_otag(p, TAG_MATH, "c", "eqn");
p->flags |= HTML_NONOSPACE;
eqn_box(p, ep->root);
eqn_box(p, bp);
p->flags &= ~HTML_NONOSPACE;
print_tagq(p, t);

View File

@ -1,4 +1,4 @@
/* $Id: eqn_term.c,v 1.9 2017/02/12 14:19:01 schwarze Exp $ */
/* $Id: eqn_term.c,v 1.13 2017/07/08 14:51:04 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -40,10 +40,10 @@ static void eqn_box(struct termp *, const struct eqn_box *);
void
term_eqn(struct termp *p, const struct eqn *ep)
term_eqn(struct termp *p, const struct eqn_box *bp)
{
eqn_box(p, ep->root);
eqn_box(p, bp);
p->flags &= ~TERMP_NOSPACE;
}
@ -51,21 +51,40 @@ static void
eqn_box(struct termp *p, const struct eqn_box *bp)
{
const struct eqn_box *child;
int delim;
if (bp->type == EQN_LIST ||
/* Delimiters around this box? */
if ((bp->type == EQN_LIST && bp->expectargs > 1) ||
(bp->type == EQN_PILE && (bp->prev || bp->next)) ||
(bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
(bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT ||
/* Diacritic followed by ^ or _. */
((bp->top != NULL || bp->bottom != NULL) &&
bp->parent->type == EQN_SUBEXPR &&
bp->parent->pos != EQNPOS_OVER && bp->next != NULL) ||
/* Nested over, sub, sup, from, to. */
(bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT &&
((bp->parent->type == EQN_LIST && bp->expectargs == 1) ||
(bp->parent->type == EQN_SUBEXPR &&
bp->pos != EQNPOS_SQRT)))))) {
if (bp->parent->type == EQN_SUBEXPR && bp->prev != NULL)
p->flags |= TERMP_NOSPACE;
term_word(p, bp->left != NULL ? bp->left : "(");
p->flags |= TERMP_NOSPACE;
}
delim = 1;
} else
delim = 0;
/* Handle Fonts and text. */
if (bp->font != EQNFONT_NONE)
term_fontpush(p, fontmap[(int)bp->font]);
if (bp->text != NULL)
term_word(p, bp->text);
/* Special box types. */
if (bp->pos == EQNPOS_SQRT) {
term_word(p, "sqrt");
if (bp->first != NULL) {
@ -96,29 +115,25 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
} else {
child = bp->first;
if (bp->type == EQN_MATRIX &&
child != NULL && child->type == EQN_LIST)
child != NULL &&
child->type == EQN_LIST &&
child->expectargs > 1)
child = child->first;
while (child != NULL) {
eqn_box(p,
bp->type == EQN_PILE &&
child->type == EQN_LIST &&
child->expectargs > 1 &&
child->args == 1 ?
child->first : child);
child = child->next;
}
}
/* Handle Fonts and diacritics. */
if (bp->font != EQNFONT_NONE)
term_fontpop(p);
if (bp->type == EQN_LIST ||
(bp->type == EQN_PILE && (bp->prev || bp->next)) ||
(bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
p->flags |= TERMP_NOSPACE;
term_word(p, bp->right != NULL ? bp->right : ")");
if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
p->flags |= TERMP_NOSPACE;
}
if (bp->top != NULL) {
p->flags |= TERMP_NOSPACE;
term_word(p, bp->top);
@ -127,4 +142,13 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
p->flags |= TERMP_NOSPACE;
term_word(p, "_");
}
/* Right delimiter after this box? */
if (delim) {
p->flags |= TERMP_NOSPACE;
term_word(p, bp->right != NULL ? bp->right : ")");
if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
p->flags |= TERMP_NOSPACE;
}
}

2
gmdiff
View File

@ -43,7 +43,7 @@ while [ -n "$1" ]; do
shift
echo " ========== $file ========== "
$ROFF -mandoc $file 2> /tmp/roff.err > /tmp/roff.out
${MANDOC:=mandoc} -Ios='OpenBSD ports' $MOPT $file \
${MANDOC:=mandoc} -Ios=OpenBSD $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

80
html.c
View File

@ -1,4 +1,4 @@
/* $Id: html.c,v 1.213 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: html.c,v 1.219 2017/07/15 17:57:51 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -87,6 +87,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"math", HTML_NLALL | HTML_INDENT},
{"mrow", 0},
{"mi", 0},
{"mn", 0},
{"mo", 0},
{"msup", 0},
{"msub", 0},
@ -345,16 +346,18 @@ static int
print_encode(struct html *h, const char *p, const char *pend, int norecurse)
{
char numbuf[16];
size_t sz;
int c, len, nospace;
struct tag *t;
const char *seq;
size_t sz;
int c, len, breakline, nospace;
enum mandoc_esc esc;
static const char rejs[9] = { '\\', '<', '>', '&', '"',
static const char rejs[10] = { ' ', '\\', '<', '>', '&', '"',
ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
if (pend == NULL)
pend = strchr(p, '\0');
breakline = 0;
nospace = 0;
while (p < pend) {
@ -365,14 +368,28 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
}
for (sz = strcspn(p, rejs); sz-- && p < pend; p++)
if (*p == ' ')
print_endword(h);
else
print_byte(h, *p);
print_byte(h, *p);
if (breakline &&
(p >= pend || *p == ' ' || *p == ASCII_NBRSP)) {
t = print_otag(h, TAG_DIV, "");
print_text(h, "\\~");
print_tagq(h, t);
breakline = 0;
while (p < pend && (*p == ' ' || *p == ASCII_NBRSP))
p++;
continue;
}
if (p >= pend)
break;
if (*p == ' ') {
print_endword(h);
p++;
continue;
}
if (print_escape(h, *p++))
continue;
@ -417,6 +434,9 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
if (c <= 0)
continue;
break;
case ESCAPE_BREAK:
breakline = 1;
continue;
case ESCAPE_NOSPACE:
if ('\0' == *p)
nospace = 1;
@ -433,7 +453,7 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
(c > 0x7E && c < 0xA0))
c = 0xFFFD;
if (c > 0x7E) {
(void)snprintf(numbuf, sizeof(numbuf), "&#%d;", c);
(void)snprintf(numbuf, sizeof(numbuf), "&#x%.4X;", c);
print_word(h, numbuf);
} else if (print_escape(h, c) == 0)
print_byte(h, c);
@ -496,7 +516,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
print_indent(h);
else if ((h->flags & HTML_NOSPACE) == 0) {
if (h->flags & HTML_KEEP)
print_word(h, "&#160;");
print_word(h, "&#x00A0;");
else {
if (h->flags & HTML_PREKEEP)
h->flags |= HTML_KEEP;
@ -603,25 +623,29 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
case 'u':
su = va_arg(ap, struct roffsu *);
break;
case 'v':
i = va_arg(ap, int);
su = &mysu;
SCALE_VS_INIT(su, i);
break;
case 'w':
if ((arg2 = va_arg(ap, char *)) == NULL)
break;
su = &mysu;
a2width(arg2, su);
if ((arg2 = va_arg(ap, char *)) != NULL) {
su = &mysu;
a2width(arg2, su);
}
if (*fmt == '*') {
if (su != NULL && su->unit == SCALE_EN &&
su->scale > 5.9 && su->scale < 6.1)
su = NULL;
fmt++;
}
if (*fmt == '+') {
/* Increase to make even bold text fit. */
su->scale *= 1.2;
/* Add padding. */
su->scale += 3.0;
if (su != NULL) {
/* Make even bold text fit. */
su->scale *= 1.2;
/* Add padding. */
su->scale += 3.0;
}
fmt++;
}
if (*fmt == '-') {
su->scale *= -1.0;
if (su != NULL)
su->scale *= -1.0;
fmt++;
}
break;
@ -632,9 +656,6 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
/* Second letter: style name. */
switch (*fmt++) {
case 'b':
attr = "margin-bottom";
break;
case 'h':
attr = "height";
break;
@ -644,9 +665,6 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
case 'l':
attr = "margin-left";
break;
case 't':
attr = "margin-top";
break;
case 'w':
attr = "width";
break;
@ -759,7 +777,7 @@ print_text(struct html *h, const char *word)
h->flags |= HTML_KEEP;
print_endword(h);
} else
print_word(h, "&#160;");
print_word(h, "&#x00A0;");
}
assert(NULL == h->metaf);

7
html.h
View File

@ -1,4 +1,4 @@
/* $Id: html.h,v 1.85 2017/05/04 22:16:09 schwarze Exp $ */
/* $Id: html.h,v 1.87 2017/07/08 14:51:04 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -51,6 +51,7 @@ enum htmltag {
TAG_MATH,
TAG_MROW,
TAG_MI,
TAG_MN,
TAG_MO,
TAG_MSUP,
TAG_MSUB,
@ -114,7 +115,7 @@ struct html {
struct roff_node;
struct tbl_span;
struct eqn;
struct eqn_box;
void roff_html_pre(struct html *, const struct roff_node *);
@ -126,7 +127,7 @@ void print_stagq(struct html *, const struct tag *);
void print_text(struct html *, const char *);
void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
void print_eqn(struct html *, const struct eqn *);
void print_eqn(struct html *, const struct eqn_box *);
void print_paragraph(struct html *);
void print_endline(struct html *);

3
lib.c
View File

@ -1,4 +1,4 @@
/* $Id: lib.c,v 1.13 2015/10/06 18:32:19 schwarze Exp $ */
/* $Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -20,6 +20,7 @@
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"

View File

@ -1,7 +1,7 @@
/* $Id: libmandoc.h,v 1.67 2017/04/29 12:45:41 schwarze Exp $ */
/* $Id: libmandoc.h,v 1.70 2017/07/08 17:52:49 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013, 2014, 2015, 2017 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,8 +23,6 @@ enum rofferr {
ROFF_REPARSE, /* re-run main parser on the result */
ROFF_SO, /* include another file */
ROFF_IGN, /* ignore current line */
ROFF_TBL, /* a table row was successfully parsed */
ROFF_EQN /* an equation was successfully parsed */
};
struct buf {
@ -34,8 +32,6 @@ struct buf {
struct mparse;
struct tbl_span;
struct eqn;
struct roff;
struct roff_man;
@ -45,7 +41,7 @@ void mandoc_vmsg(enum mandocerr, struct mparse *,
int, int, const char *, ...)
__attribute__((__format__ (__printf__, 5, 6)));
char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct mparse *, char *, int, int);
char *mandoc_normdate(struct roff_man *, char *, int, int);
int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*);
@ -75,6 +71,3 @@ char *roff_strdup(const struct roff *, const char *);
int roff_getcontrol(const struct roff *,
const char *, int *);
int roff_getformat(const struct roff *);
const struct tbl_span *roff_span(const struct roff *);
const struct eqn *roff_eqn(const struct roff *);

View File

@ -1,7 +1,7 @@
/* $Id: libroff.h,v 1.39 2015/11/07 14:01:16 schwarze Exp $ */
/* $Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015, 2017 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
@ -38,15 +38,15 @@ struct tbl_node {
};
struct eqn_node {
struct eqn eqn; /* syntax tree of this equation */
struct mparse *parse; /* main parser, for error reporting */
struct eqn_node *next; /* singly linked list of equations */
struct roff_node *node; /* syntax tree of this equation */
struct eqn_def *defs; /* array of definitions */
char *data; /* source code of this equation */
char *start; /* first byte of the current token */
char *end; /* first byte of the next token */
size_t defsz; /* number of definitions */
size_t sz; /* length of the source code */
size_t cur; /* parse point in the source code */
size_t rew; /* beginning of the current token */
size_t toksz; /* length of the current token */
int gsize; /* default point size */
int delim; /* in-line delimiters enabled */
char odelim; /* in-line opening delimiter */
@ -65,15 +65,16 @@ struct tbl_node *tbl_alloc(int, int, struct mparse *);
void tbl_restart(int, int, struct tbl_node *);
void tbl_free(struct tbl_node *);
void tbl_reset(struct tbl_node *);
enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
void tbl_read(struct tbl_node *, int, const char *, int);
void tbl_option(struct tbl_node *, int, const char *, int *);
void tbl_layout(struct tbl_node *, int, const char *, int);
void tbl_data(struct tbl_node *, int, const char *, int);
int tbl_cdata(struct tbl_node *, int, const char *, int);
void tbl_cdata(struct tbl_node *, int, const char *, int);
const struct tbl_span *tbl_span(struct tbl_node *);
int tbl_end(struct tbl_node **);
struct eqn_node *eqn_alloc(int, int, struct mparse *);
enum rofferr eqn_end(struct eqn_node **);
int tbl_end(struct tbl_node *);
struct eqn_node *eqn_alloc(struct mparse *);
void eqn_box_free(struct eqn_box *);
void eqn_free(struct eqn_node *);
enum rofferr eqn_read(struct eqn_node **, int,
const char *, int, int *);
void eqn_parse(struct eqn_node *);
void eqn_read(struct eqn_node *, const char *);
void eqn_reset(struct eqn_node *);

153
main.c
View File

@ -1,4 +1,4 @@
/* $Id: main.c,v 1.292 2017/06/03 12:17:25 schwarze Exp $ */
/* $Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -43,6 +43,7 @@
#include "mandoc_aux.h"
#include "mandoc.h"
#include "mandoc_xr.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
@ -74,21 +75,24 @@ enum outt {
struct curparse {
struct mparse *mp;
enum mandoclevel wlevel; /* ignore messages below this */
int wstop; /* stop after a file with a warning */
enum outt outtype; /* which output to use */
void *outdata; /* data for output */
struct manoutput *outopts; /* output options */
void *outdata; /* data for output */
char *os_s; /* operating system for display */
int wstop; /* stop after a file with a warning */
enum mandocerr mmin; /* ignore messages below this */
enum mandoc_os os_e; /* check base system conventions */
enum outt outtype; /* which output to use */
};
int mandocdb(int, char *[]);
static void check_xr(const char *);
static int fs_lookup(const struct manpaths *,
size_t ipath, const char *,
const char *, const char *,
struct manpage **, size_t *);
static void fs_search(const struct mansearch *,
static int fs_search(const struct mansearch *,
const struct manpaths *, int, char**,
struct manpage **, size_t *);
static int koptions(int *, char *);
@ -107,6 +111,7 @@ 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 enum mandoclevel rc;
static FILE *mmsg_stream;
int
@ -119,7 +124,7 @@ main(int argc, char *argv[])
struct manpage *res, *resp;
const char *progname, *sec, *thisarg;
char *conf_file, *defpaths, *auxpaths;
char *defos, *oarg;
char *oarg;
unsigned char *uc;
size_t i, sz;
int prio, best_prio;
@ -183,10 +188,10 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
curp.wlevel = MANDOCLEVEL_BADARG;
curp.mmin = MANDOCERR_MAX;
curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
defos = NULL;
mmsg_stream = stderr;
use_pager = 1;
tag_files = NULL;
@ -222,11 +227,11 @@ main(int argc, char *argv[])
warnx("-I %s: Bad argument", optarg);
return (int)MANDOCLEVEL_BADARG;
}
if (defos) {
if (curp.os_s != NULL) {
warnx("-I %s: Duplicate argument", optarg);
return (int)MANDOCLEVEL_BADARG;
}
defos = mandoc_strdup(optarg + 3);
curp.os_s = mandoc_strdup(optarg + 3);
break;
case 'K':
if ( ! koptions(&options, optarg))
@ -446,7 +451,8 @@ main(int argc, char *argv[])
moptions(&options, auxpaths);
mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
curp.mp = mparse_alloc(options, curp.mmin, mmsg,
curp.os_e, curp.os_s);
/*
* Conditionally start up the lookaside buffer before parsing.
@ -472,7 +478,7 @@ main(int argc, char *argv[])
parse(&curp, fd, *argv);
else if (resp->form == FORM_SRC) {
/* For .so only; ignore failure. */
chdir(conf.manpath.paths[resp->ipath]);
(void)chdir(conf.manpath.paths[resp->ipath]);
parse(&curp, fd, resp->file);
} else
passthrough(resp->file, fd,
@ -515,6 +521,7 @@ main(int argc, char *argv[])
break;
}
}
mandoc_xr_free();
mparse_free(curp.mp);
mchars_free();
@ -524,7 +531,7 @@ main(int argc, char *argv[])
mansearch_free(res, sz);
}
free(defos);
free(curp.os_s);
/*
* When using a pager, finish writing both temporary files,
@ -658,12 +665,23 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
if (globres == 0)
file = mandoc_strdup(*globinfo.gl_pathv);
globfree(&globinfo);
if (globres != 0)
if (globres == 0)
goto found;
if (res != NULL || ipath + 1 != paths->sz)
return 0;
mandoc_asprintf(&file, "%s.%s", name, sec);
globres = access(file, R_OK);
free(file);
return globres != -1;
found:
warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
if (res == NULL) {
free(file);
return 1;
}
*res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
page = *res + (*ressz - 1);
page->file = file;
@ -676,7 +694,7 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
return 1;
}
static void
static int
fs_search(const struct mansearch *cfg, const struct manpaths *paths,
int argc, char **argv, struct manpage **res, size_t *ressz)
{
@ -688,7 +706,8 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
assert(cfg->argmode == ARG_NAME);
*res = NULL;
if (res != NULL)
*res = NULL;
*ressz = lastsz = 0;
while (argc) {
for (ipath = 0; ipath < paths->sz; ipath++) {
@ -696,19 +715,20 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
if (fs_lookup(paths, ipath, cfg->sec,
cfg->arch, *argv, res, ressz) &&
cfg->firstmatch)
return;
return 1;
} else for (isec = 0; isec < nsec; isec++)
if (fs_lookup(paths, ipath, sections[isec],
cfg->arch, *argv, res, ressz) &&
cfg->firstmatch)
return;
return 1;
}
if (*ressz == lastsz)
if (res != NULL && *ressz == lastsz)
warnx("No entry for %s in the manual.", *argv);
lastsz = *ressz;
argv++;
argc--;
}
return 0;
}
static void
@ -745,6 +765,7 @@ parse(struct curparse *curp, int fd, const char *file)
if (man == NULL)
return;
mandoc_xr_reset();
if (man->macroset == MACROSET_MDOC) {
if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
mdoc_validate(man);
@ -796,9 +817,46 @@ parse(struct curparse *curp, int fd, const char *file)
break;
}
}
if (curp->mmin < MANDOCERR_STYLE)
check_xr(file);
mparse_updaterc(curp->mp, &rc);
}
static void
check_xr(const char *file)
{
static struct manpaths paths;
struct mansearch search;
struct mandoc_xr *xr;
char *cp;
size_t sz;
if (paths.sz == 0)
manpath_base(&paths);
for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) {
if (xr->line == -1)
continue;
search.arch = NULL;
search.sec = xr->sec;
search.outkey = NULL;
search.argmode = ARG_NAME;
search.firstmatch = 1;
if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz))
continue;
if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz))
continue;
if (xr->count == 1)
mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec);
else
mandoc_asprintf(&cp, "Xr %s %s (%d times)",
xr->name, xr->sec, xr->count);
mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
file, xr->line, xr->pos + 1, cp);
free(cp);
}
}
static void
outdata_alloc(struct curparse *curp)
{
@ -937,7 +995,8 @@ toptions(struct curparse *curp, char *arg)
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
curp->wlevel = MANDOCLEVEL_STYLE;
curp->mmin = MANDOCERR_BASE;
mmsg_stream = stdout;
} else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man"))
@ -966,16 +1025,19 @@ static int
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
const char *toks[8];
const char *toks[11];
toks[0] = "stop";
toks[1] = "all";
toks[2] = "style";
toks[3] = "warning";
toks[4] = "error";
toks[5] = "unsupp";
toks[6] = "fatal";
toks[7] = NULL;
toks[2] = "base";
toks[3] = "style";
toks[4] = "warning";
toks[5] = "error";
toks[6] = "unsupp";
toks[7] = "fatal";
toks[8] = "openbsd";
toks[9] = "netbsd";
toks[10] = NULL;
while (*arg) {
o = arg;
@ -985,19 +1047,30 @@ woptions(struct curparse *curp, char *arg)
break;
case 1:
case 2:
curp->wlevel = MANDOCLEVEL_STYLE;
curp->mmin = MANDOCERR_BASE;
break;
case 3:
curp->wlevel = MANDOCLEVEL_WARNING;
curp->mmin = MANDOCERR_STYLE;
break;
case 4:
curp->wlevel = MANDOCLEVEL_ERROR;
curp->mmin = MANDOCERR_WARNING;
break;
case 5:
curp->wlevel = MANDOCLEVEL_UNSUPP;
curp->mmin = MANDOCERR_ERROR;
break;
case 6:
curp->wlevel = MANDOCLEVEL_BADARG;
curp->mmin = MANDOCERR_UNSUPP;
break;
case 7:
curp->mmin = MANDOCERR_MAX;
break;
case 8:
curp->mmin = MANDOCERR_BASE;
curp->os_e = MANDOC_OS_OPENBSD;
break;
case 9:
curp->mmin = MANDOCERR_BASE;
curp->os_e = MANDOC_OS_NETBSD;
break;
default:
warnx("-W %s: Bad argument", o);
@ -1013,21 +1086,21 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
{
const char *mparse_msg;
fprintf(stderr, "%s: %s:", getprogname(),
fprintf(mmsg_stream, "%s: %s:", getprogname(),
file == NULL ? "<stdin>" : file);
if (line)
fprintf(stderr, "%d:%d:", line, col + 1);
fprintf(mmsg_stream, "%d:%d:", line, col + 1);
fprintf(stderr, " %s", mparse_strlevel(lvl));
fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
if (NULL != (mparse_msg = mparse_strerror(t)))
fprintf(stderr, ": %s", mparse_msg);
if ((mparse_msg = mparse_strerror(t)) != NULL)
fprintf(mmsg_stream, ": %s", mparse_msg);
if (msg)
fprintf(stderr, ": %s", msg);
fprintf(mmsg_stream, ": %s", msg);
fputc('\n', stderr);
fputc('\n', mmsg_stream);
}
static pid_t

18
man.7
View File

@ -1,4 +1,4 @@
.\" $Id: man.7,v 1.135 2017/05/07 21:44:49 schwarze Exp $
.\" $Id: man.7,v 1.136 2017/06/25 11:42:02 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -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: May 7 2017 $
.Dd $Mdocdate: June 25 2017 $
.Dt MAN 7
.Os
.Sh NAME
@ -466,6 +466,20 @@ See also
.Sx \&PP ,
and
.Sx \&TP .
.Ss \&ME
End a mailto block.
This is a non-standard GNU extension, included only for compatibility.
See
.Sx \&MT .
.Ss \&MT
Begin a mailto block.
This is a non-standard GNU extension, included only for compatibility.
It has the following syntax:
.Bd -literal -offset indent
.Pf \. Sx \&MT Ar address
link description to be shown
.Pf \. Sx ME
.Ed
.Ss \&OP
Optional command-line argument.
This is a non-standard GNU extension, included only for compatibility.

44
man.c
View File

@ -1,4 +1,4 @@
/* $Id: man.c,v 1.174 2017/06/03 15:55:24 schwarze Exp $ */
/* $Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -76,6 +76,8 @@ static int
man_ptext(struct roff_man *man, int line, char *buf, int offs)
{
int i;
const char *cp, *sp;
char *ep;
/* Literal free-form text whitespace is preserved. */
@ -89,19 +91,36 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
/* Skip leading whitespace. */ ;
/*
* Blank lines are ignored in next line scope and right
* after headings but add a single vertical space elsewhere.
* Blank lines are ignored in next line scope
* and right after headings and cancel preceding \c,
* but add a single vertical space elsewhere.
*/
if (buf[i] == '\0') {
if (man->flags & (MAN_ELINE | MAN_BLINE))
if (man->flags & (MAN_ELINE | MAN_BLINE)) {
mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
line, 0, NULL);
else if (man->last->tok != MAN_SH &&
man->last->tok != MAN_SS) {
roff_elem_alloc(man, line, offs, ROFF_sp);
man->next = ROFF_NEXT_SIBLING;
return 1;
}
if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
return 1;
switch (man->last->type) {
case ROFFT_TEXT:
sp = man->last->string;
cp = ep = strchr(sp, '\0') - 2;
if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
break;
while (cp > sp && cp[-1] == '\\')
cp--;
if ((ep - cp) % 2)
break;
*ep = '\0';
return 1;
default:
break;
}
roff_elem_alloc(man, line, offs, ROFF_sp);
man->next = ROFF_NEXT_SIBLING;
return 1;
}
@ -263,8 +282,10 @@ man_breakscope(struct roff_man *man, int tok)
if (man->flags & MAN_ELINE && (tok < MAN_TH ||
! (man_macros[tok].flags & MAN_NSCOPED))) {
n = man->last;
assert(n->type != ROFFT_TEXT);
if (man_macros[n->tok].flags & MAN_NSCOPED)
if (n->type == ROFFT_TEXT)
n = n->parent;
if (n->tok < MAN_TH ||
man_macros[n->tok].flags & MAN_NSCOPED)
n = n->parent;
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
@ -300,7 +321,8 @@ man_breakscope(struct roff_man *man, int tok)
n = man->last;
if (n->type == ROFFT_TEXT)
n = n->parent;
if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
if (n->tok < MAN_TH ||
(man_macros[n->tok].flags & MAN_BSCOPE) == 0)
n = n->parent;
assert(n->type == ROFFT_HEAD);

View File

@ -1,4 +1,4 @@
.\" $Id: man.options.1,v 1.6 2017/02/02 20:10:51 schwarze Exp $
.\" $Id: man.options.1,v 1.7 2017/07/04 23:40:01 schwarze Exp $
.\"
.\" Copyright (c) 2017 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: February 2 2017 $
.Dd $Mdocdate: July 4 2017 $
.Dt MAN.OPTIONS 1
.Os
.Sh NAME
@ -1297,11 +1297,17 @@ the Unix Archive of the Unix Heritage Society
.It
the CSRG Archive CD-ROMs
.It
the FreeBSD SVN repository
the
.Fx
SVN repository
.It
the OpenBSD CVS repository
the
.Ox
CVS repository
.It
the NetBSD CVS repository
the
.Nx
CVS repository
.It
the GNU roff (groff) git repository
.It

View File

@ -1,4 +1,4 @@
/* $Id: man_html.c,v 1.143 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: man_html.c,v 1.145 2017/06/25 11:42:02 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -26,6 +26,7 @@
#include <string.h>
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "out.h"
@ -105,6 +106,8 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ NULL, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */
{ NULL, NULL }, /* UE */
{ man_UR_pre, NULL }, /* MT */
{ NULL, NULL }, /* ME */
};
static const struct htmlman *const mans = __mans - MAN_TH;
@ -229,6 +232,7 @@ print_man_node(MAN_ARGS)
case MAN_P: /* reopen .nf in the body. */
case MAN_RS:
case MAN_UR:
case MAN_MT:
fillmode(h, MAN_fi);
break;
default:
@ -643,11 +647,17 @@ man_RS_pre(MAN_ARGS)
static int
man_UR_pre(MAN_ARGS)
{
char *cp;
n = n->child;
assert(n->type == ROFFT_HEAD);
if (n->child != NULL) {
assert(n->child->type == ROFFT_TEXT);
print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
if (n->tok == MAN_MT) {
mandoc_asprintf(&cp, "mailto:%s", n->child->string);
print_otag(h, TAG_A, "cTh", "Mt", cp);
free(cp);
} else
print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
}
assert(n->next->type == ROFFT_BODY);

View File

@ -1,4 +1,4 @@
/* $Id: man_macro.c,v 1.120 2017/05/05 15:17:32 schwarze Exp $ */
/* $Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -69,12 +69,14 @@ const struct man_macro __man_macros[MAN_MAX - MAN_TH] = {
{ in_line_eoln, 0 }, /* UC */
{ in_line_eoln, MAN_NSCOPED }, /* PD */
{ in_line_eoln, 0 }, /* AT */
{ in_line_eoln, 0 }, /* in */
{ in_line_eoln, MAN_NSCOPED }, /* in */
{ in_line_eoln, 0 }, /* OP */
{ in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE }, /* UR */
{ blk_close, MAN_BSCOPE }, /* UE */
{ blk_exp, MAN_BSCOPE }, /* MT */
{ blk_close, MAN_BSCOPE }, /* ME */
};
const struct man_macro *const man_macros = __man_macros - MAN_TH;
@ -217,6 +219,9 @@ blk_close(MACRO_PROT_ARGS)
case MAN_UE:
ntok = MAN_UR;
break;
case MAN_ME:
ntok = MAN_MT;
break;
default:
abort();
}
@ -235,6 +240,10 @@ blk_close(MACRO_PROT_ARGS)
ntok = man->last->tok;
man_unscope(man, nn);
if (tok == MAN_RE && nn->head->aux > 0)
roff_setreg(man->roff, "an-margin",
nn->head->aux, '-');
/* Move a trailing paragraph behind the block. */
if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
@ -256,8 +265,17 @@ blk_exp(MACRO_PROT_ARGS)
head = roff_head_alloc(man, line, ppos, tok);
la = *pos;
if (man_args(man, line, pos, buf, &p))
if (man_args(man, line, pos, buf, &p)) {
roff_word_alloc(man, line, la, p);
if (tok == MAN_RS) {
if (roff_getreg(man->roff, "an-margin") == 0)
roff_setreg(man->roff, "an-margin",
7 * 24, '=');
if ((head->aux = strtod(p, NULL) * 24.0) > 0)
roff_setreg(man->roff, "an-margin",
head->aux, '+');
}
}
if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,

View File

@ -1,4 +1,4 @@
/* $Id: man_term.c,v 1.204 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: man_term.c,v 1.208 2017/06/25 11:42:02 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -128,6 +128,8 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
{ pre_UR, post_UR, 0 }, /* MT */
{ NULL, NULL, 0 }, /* ME */
};
static const struct termact *termacts = __termacts - MAN_TH;
@ -141,6 +143,9 @@ terminal_man(void *arg, const struct roff_man *man)
size_t save_defindent;
p = (struct termp *)arg;
save_defindent = p->defindent;
if (p->synopsisonly == 0 && p->defindent == 0)
p->defindent = 7;
p->tcol->rmargin = p->maxrmargin = p->defrmargin;
term_tab_set(p, NULL);
term_tab_set(p, "T");
@ -167,16 +172,13 @@ terminal_man(void *arg, const struct roff_man *man)
n = n->next;
}
} else {
save_defindent = p->defindent;
if (p->defindent == 0)
p->defindent = 7;
term_begin(p, print_man_head, print_man_foot, &man->meta);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
print_man_nodelist(p, &mt, n, &man->meta);
term_end(p);
p->defindent = save_defindent;
}
p->defindent = save_defindent;
}
/*
@ -377,7 +379,7 @@ pre_in(DECL_ARGS)
if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
return 0;
v = (term_hspan(p, &su) + 11) / 24;
v = term_hen(p, &su);
if (less < 0)
p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
@ -426,7 +428,7 @@ pre_HP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24;
len = term_hen(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@ -511,7 +513,7 @@ pre_IP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
(nn = nn->next) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24;
len = term_hen(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@ -593,7 +595,7 @@ pre_TP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
nn->string != NULL && ! (NODE_LINE & nn->flags) &&
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24;
len = term_hen(p, &su);
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
else if (len > SHRT_MAX)
@ -797,7 +799,7 @@ pre_RS(DECL_ARGS)
if (n->child == NULL)
n->aux = mt->lmargin[mt->lmargincur];
else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
n->aux = term_hspan(p, &su) / 24;
n->aux = term_hen(p, &su);
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
n->aux = -mt->offset;
else if (n->aux > SHRT_MAX)
@ -872,7 +874,10 @@ print_man_node(DECL_ARGS)
* before printing the line's data.
*/
if (*n->string == '\0') {
term_vspace(p);
if (p->flags & TERMP_NONEWLINE)
term_newln(p);
else
term_vspace(p);
return;
} else if (*n->string == ' ' && n->flags & NODE_LINE &&
(p->flags & TERMP_NONEWLINE) == 0)

View File

@ -47,11 +47,12 @@ static void check_text(CHKARGS);
static void post_AT(CHKARGS);
static void post_IP(CHKARGS);
static void post_vs(CHKARGS);
static void post_OP(CHKARGS);
static void post_TH(CHKARGS);
static void post_UC(CHKARGS);
static void post_UR(CHKARGS);
static void post_in(CHKARGS);
static void post_vs(CHKARGS);
static const v_check __man_valids[MAN_MAX - MAN_TH] = {
post_TH, /* TH */
@ -82,12 +83,14 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
post_UC, /* UC */
NULL, /* PD */
post_AT, /* AT */
NULL, /* in */
post_in, /* in */
post_OP, /* OP */
NULL, /* EX */
NULL, /* EE */
post_UR, /* UR */
NULL, /* UE */
post_UR, /* MT */
NULL, /* ME */
};
static const v_check *man_valids = __man_valids - MAN_TH;
@ -167,8 +170,14 @@ check_root(CHKARGS)
man->meta.title = mandoc_strdup("");
man->meta.msec = mandoc_strdup("");
man->meta.date = man->quick ? mandoc_strdup("") :
mandoc_normdate(man->parse, NULL, n->line, n->pos);
mandoc_normdate(man, NULL, n->line, n->pos);
}
if (man->meta.os_e &&
(man->meta.rcsids & (1 << man->meta.os_e)) == 0)
mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0,
man->meta.os_e == MANDOC_OS_OPENBSD ?
"(OpenBSD)" : "(NetBSD)");
}
static void
@ -202,10 +211,9 @@ post_OP(CHKARGS)
static void
post_UR(CHKARGS)
{
if (n->type == ROFFT_HEAD && n->child == NULL)
mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
n->line, n->pos, "UR");
mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse,
n->line, n->pos, roff_name[n->tok]);
check_part(man, n);
}
@ -323,8 +331,7 @@ post_TH(CHKARGS)
if (n && n->string && '\0' != n->string[0]) {
man->meta.date = man->quick ?
mandoc_strdup(n->string) :
mandoc_normdate(man->parse, n->string,
n->line, n->pos);
mandoc_normdate(man, n->string, n->line, n->pos);
} else {
man->meta.date = mandoc_strdup("");
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
@ -336,8 +343,14 @@ post_TH(CHKARGS)
if (n && (n = n->next))
man->meta.os = mandoc_strdup(n->string);
else if (man->defos != NULL)
man->meta.os = mandoc_strdup(man->defos);
else if (man->os_s != NULL)
man->meta.os = mandoc_strdup(man->os_s);
if (man->meta.os_e == MANDOC_OS_OTHER && man->meta.os != NULL) {
if (strstr(man->meta.os, "OpenBSD") != NULL)
man->meta.os_e = MANDOC_OS_OPENBSD;
else if (strstr(man->meta.os, "NetBSD") != NULL)
man->meta.os_e = MANDOC_OS_NETBSD;
}
/* TITLE MSEC DATE OS ->VOL<- */
/* If missing, use the default VOL name for MSEC. */
@ -435,6 +448,22 @@ post_AT(CHKARGS)
man->meta.os = mandoc_strdup(p);
}
static void
post_in(CHKARGS)
{
char *s;
if (n->parent->tok != MAN_TP ||
n->parent->type != ROFFT_HEAD ||
n->child == NULL ||
*n->child->string == '+' ||
*n->child->string == '-')
return;
mandoc_asprintf(&s, "+%s", n->child->string);
free(n->child->string);
n->child->string = s;
}
static void
post_vs(CHKARGS)
{

View File

@ -1,6 +1,6 @@
/* $OpenBSD$ */
/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */
/*
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@ -47,3 +47,4 @@ struct manconf {
void manconf_parse(struct manconf *, const char *, char *, char *);
int manconf_output(struct manoutput *, const char *, int);
void manconf_free(struct manconf *);
void manpath_base(struct manpaths *);

392
mandoc.1
View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.1,v 1.196 2017/06/08 00:23:30 schwarze Exp $
.\" $Id: mandoc.1,v 1.217 2017/07/20 15:26:41 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2012, 2014-2017 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: June 8 2017 $
.Dd $Mdocdate: July 20 2017 $
.Dt MANDOC 1
.Os
.Sh NAME
@ -75,11 +75,6 @@ and for the
.Xr man 7
.Ic \&TH
macro.
This can also be used to perform style checks according to the
conventions of one operating system while running on a different
operating system; see
.Sx Style messages
for details.
.It Fl K Ar encoding
Specify the input encoding.
The supported
@ -151,14 +146,33 @@ to be reported on the standard error output and to affect the exit status.
The
.Ar level
can be
.Cm base ,
.Cm style ,
.Cm warning ,
.Cm error ,
or
.Cm unsupp ;
.Cm unsupp .
The
.Cm base
level automatically derives the operating system from the contents of the
.Ic \&Os
macro, from the
.Fl Ios
command line option, or from the
.Xr uname 3
return value.
The levels
.Cm openbsd
and
.Cm netbsd
are variants of
.Cm base
that bypass autodetection and request validation of base system
conventions for a particular operating system.
The level
.Cm all
is an alias for
.Cm style .
.Cm base .
By default,
.Nm
is silent.
@ -224,7 +238,9 @@ See
.It Fl T Cm lint
Parse only: produce no output.
Implies
.Fl W Cm style .
.Fl W Cm all
and redirects parser messages, which usually appear
on standard error output, to standard output.
.It Fl T Cm locale
Encode output using the current locale.
This is the default.
@ -301,8 +317,7 @@ Increasing this is not recommended; it may result in degraded formatting,
for example overfull lines or ugly line breaks.
.It Cm width Ns = Ns Ar width
The output width is set to
.Ar width ,
which will normalise to \(>=58.
.Ar width .
.El
.Ss HTML Output
Output produced by
@ -597,19 +612,23 @@ option:
.Pp
.Bl -tag -width Ds -compact
.It 0
No style suggestions, warnings or errors occurred, or those that
did were ignored because they were lower than the requested
No base system convention violations, style suggestions, warnings,
or errors occurred, or those that did were ignored because they
were lower than the requested
.Ar level .
.It 1
At least one style suggestion occurred, but no warning or error, and
At least one base system convention violation or style suggestion
occurred, but no warning or error, and
.Fl W Cm base
or
.Fl W Cm style
was specified.
.It 2
At least one warning occurred, but no error, and
.Fl W Cm warning
or
.Fl W Cm style
was specified.
or a lower
.Ar level
was requested.
.It 3
At least one parsing error occurred,
but no unsupported feature was encountered, and
@ -637,7 +656,7 @@ to exit at once, possibly in the middle of parsing or formatting a file.
Note that selecting
.Fl T Cm lint
output mode implies
.Fl W Cm style .
.Fl W Cm all .
.Sh EXAMPLES
To page manuals to the terminal:
.Pp
@ -670,12 +689,19 @@ parser:
Messages displayed by
.Nm
follow this format:
.Pp
.D1 Nm Ns : Ar file : Ns Ar line : Ns Ar column : level : message : macro args
.Bd -ragged -offset indent
.Nm :
.Ar file : Ns Ar line : Ns Ar column : level : message : macro args
.Pq Ar os
.Ed
.Pp
Line and column numbers start at 1.
Both are omitted for messages referring to an input file as a whole.
Macro names and arguments are omitted where meaningless.
The
.Ar os
operating system specifier is omitted for messages that are relevant
for all operating systems.
Fatal messages about invalid command line arguments
or operating system errors, for example when memory is exhausted,
may also omit the
@ -695,32 +721,13 @@ so using GNU troff instead of
.Nm
to process the file may be preferable.
.It Cm error
An input file contains invalid syntax that cannot be safely interpreted.
By discarding part of the input or inserting missing tokens,
the parser is able to continue, and the error does not prevent
generation of formatted output, but typically, preparing that
output involves information loss, broken document structure
or unintended formatting, no matter whether
.Nm
or GNU troff is used.
In many cases, the output of
.Nm
and GNU troff is identical, but in some,
.Nm
is more resilient than GNU troff with respect to malformed input.
.Pp
Non-existent or unreadable input files are also reported on the
.Cm error
level.
In that case, the parser cannot even be started and no output
is produced from those input files.
Indicates a risk of information loss or severe misformatting,
in most cases caused by serious syntax errors.
.It Cm warning
An input file uses obsolete, discouraged or non-portable syntax.
All the same, the meaning of the input is unambiguous and a correct
rendering can be produced.
Documents causing warnings may render poorly when using other
formatting tools instead of
.Nm .
Indicates a risk that the information shown or its formatting
may mismatch the author's intent in minor ways.
Additionally, syntax errors are classified at least as warnings,
even if they do not usually cause misformatting.
.It Cm style
An input file uses dubious or discouraged style.
This is not a complaint about the syntax, and probably neither
@ -733,9 +740,21 @@ so it may occasionally issue bogus suggestions.
Please use your good judgement to decide whether any particular
.Cm style
suggestion really justifies a change to the input file.
.It Cm base
A convertion used in the base system of a specific operating system
is not adhered to.
These are not markup mistakes, and neither the quality of formatting
nor portability are in danger.
Messages of the
.Cm base
level are printed with the more intuitive
.Cm style
.Ar level
tag.
.El
.Pp
Messages of the
.Cm base ,
.Cm style ,
.Cm warning ,
.Cm error ,
@ -747,9 +766,15 @@ are hidden unless their level, or a lower level, is requested using a
option or
.Fl T Cm lint
output mode.
.Ss Style messages
As indicated below, some style checks are only performed if a
specific operating system name occurs in the arguments of the
.Pp
As indicated below, all
.Cm base
and some
.Cm style
checks are only performed if a specific operating system name occurs
in the arguments of the
.Fl W
command line option, of the
.Ic \&Os
macro, of the
.Fl Ios
@ -757,7 +782,98 @@ command line option, or, if neither are present, in the return value
of the
.Xr uname 3
function.
.Ss Conventions for base system manuals
.Bl -ohang
.It Sy "Mdocdate found"
.Pq mdoc , Nx
The
.Ic \&Dd
macro uses CVS
.Ic Mdocdate
keyword substitution, which is not supported by the
.Nx
base system.
Consider using the conventional
.Dq "Month dd, yyyy"
format instead.
.It Sy "Mdocdate missing"
.Pq mdoc , Ox
The
.Ic \&Dd
macro does not use CVS
.Ic Mdocdate
keyword substitution, but using it is conventionally expected in the
.Ox
base system.
.It Sy "unknown architecture"
.Pq mdoc , Ox , Nx
The third argument of the
.Ic \&Dt
macro does not match any of the architectures this operating system
is running on.
.It Sy "operating system explicitly specified"
.Pq mdoc , Ox , Nx
The
.Ic \&Os
macro has an argument.
In the base system, it is conventionally left blank.
.It Sy "RCS id missing"
.Pq Ox , Nx
The manual page lacks the comment line with the RCS identifier
generated by CVS
.Ic OpenBSD
or
.Ic NetBSD
keyword substitution as conventionally used in these operating systems.
.It Sy "referenced manual not found"
.Pq mdoc
An
.Ic \&Xr
macro references a manual page that is not found in the base system.
The path to look for base system manuals is configurable at compile
time and defaults to
.Pa /usr/share/man : /usr/X11R6/man .
.El
.Ss Style suggestions
.Bl -ohang
.It Sy "legacy man(7) date format"
.Pq mdoc
The
.Ic \&Dd
macro uses the legacy
.Xr man 7
date format
.Dq yyyy-dd-mm .
Consider using the conventional
.Xr mdoc 7
date format
.Dq "Month dd, yyyy"
instead.
.It Sy "lower case character in document title"
.Pq mdoc , man
The title is still used as given in the
.Ic \&Dt
or
.Ic \&TH
macro.
.It Sy "duplicate RCS id"
A single manual page contains two copies of the RCS identifier for
the same operating system.
Consider deleting the later instance and moving the first one up
to the top of the page.
.It Sy "typo in section name"
.Pq mdoc
Fuzzy string matching revealed that the argument of an
.Ic \&Sh
macro is similar, but not identical to a standard section name.
.It Sy "unterminated quoted argument"
.Pq roff
Macro arguments can be enclosed in double quote characters
such that space characters and macro names contained in the quoted
argument need not be escaped.
The closing quote of the last argument of a macro can be omitted.
However, omitting it is not recommended because it makes the code
harder to read.
.It Sy "useless macro"
.Pq mdoc
A
@ -793,11 +909,55 @@ list contains two consecutive
entries describing the same
.Ic \&Er
number.
.It Sy "description line ends with a full stop"
.It Sy "trailing delimiter"
.Pq mdoc
Do not use punctuation at the end of an
.Ic \&Nd
block.
The last argument of an
.Ic \&Ex , \&Fo , \&Nd , \&Nm , \&Os , \&Sh , \&Ss , \&St ,
or
.Ic \&Sx
macro ends with a trailing delimiter.
This is usually bad style and often indicates typos.
Most likely, the delimiter can be removed.
.It Sy "no blank before trailing delimiter"
.Pq mdoc
The last argument of a macro that supports trailing delimiter
arguments is longer than one byte and ends with a trailing delimiter.
Consider inserting a blank such that the delimiter becomes a separate
argument, thus moving it out of the scope of the macro.
.It Sy "fill mode already enabled, skipping"
.Pq man
A
.Ic \&fi
request occurs even though the document is still in fill mode,
or already switched back to fill mode.
It has no effect.
.It Sy "fill mode already disabled, skipping"
.Pq man
An
.Ic \&nf
request occurs even though the document already switched to no-fill mode
and did not switch back to fill mode yet.
It has no effect.
.It Sy "function name without markup"
.Pq mdoc
A word followed by an empty pair of parentheses occurs on a text line.
Consider using an
.Ic \&Fn
or
.Ic \&Xr
macro.
.It Sy "whitespace at end of input line"
.Pq mdoc , man , roff
Whitespace at the end of input lines is almost never semantically
significant \(em but in the odd case where it might be, it is
extremely confusing when reviewing and maintaining documents.
.It Sy "bad comment style"
.Pq roff
Comment lines start with a dot, a backslash, and a double-quote character.
The
.Nm
utility treats the line as a comment line even without the backslash,
but leaving out the backslash might not be portable.
.El
.Ss Warnings related to the document prologue
.Bl -ohang
@ -813,13 +973,6 @@ macro before the first non-prologue macro.
There is no
.Ic \&TH
macro, or it has no arguments.
.It Sy "lower case character in document title"
.Pq mdoc , man
The title is still used as given in the
.Ic \&Dt
or
.Ic \&TH
macro.
.It Sy "missing manual section, using \(dq\(dq"
.Pq mdoc , man
A
@ -855,13 +1008,17 @@ The date given in a
or
.Ic \&TH
macro does not follow the conventional format.
.It Sy "date in the future, using it anyway"
.Pq mdoc , man
The date given in a
.Ic \&Dd
or
.Ic \&TH
macro is more than a day ahead of the current system
.Xr time 3 .
.It Sy "missing Os macro, using \(dq\(dq"
.Pq mdoc
The default or current system is not shown in this case.
.It Sy "duplicate prologue macro"
.Pq mdoc
One of the prologue macros occurs more than once.
The last instance overrides all previous ones.
.It Sy "late prologue macro"
.Pq mdoc
A
@ -869,17 +1026,6 @@ A
or
.Ic \&Os
macro occurs after some non-prologue macro, but still takes effect.
.It Sy "skipping late title macro"
.Pq mdoc
The
.Ic \&Dt
macro appears after the first non-prologue macro.
Traditional formatters cannot handle this because
they write the page header before parsing the document body.
Even though this technical restriction does not apply to
.Nm ,
traditional semantics is preserved.
The late macro is discarded including its arguments.
.It Sy "prologue macros out of order"
.Pq mdoc
The prologue macros are not given in the conventional order
@ -971,6 +1117,24 @@ The same standard section title occurs more than once.
.Pq mdoc
A standard section header occurs in a section of the manual
where it normally isn't useful.
.It Sy "cross reference to self"
.Pq mdoc
An
.Ic \&Xr
macro refers to a name and section matching the section of the present
manual page and a name mentioned in an
.Ic \&Nm
macro in the NAME or SYNOPSIS section, or in an
.Ic \&Fn
or
.Ic \&Fo
macro in the SYNOPSIS.
Consider using
.Ic \&Nm
or
.Ic \&Fn
instead of
.Ic \&Xr .
.It Sy "unusual Xr order"
.Pq mdoc
In the SEE ALSO section, an
@ -1057,7 +1221,9 @@ The paragraph macro is moved after the end of the list.
.Pq mdoc
An input line begins with an
.Ic \&Ns
macro.
macro, or the next argument after an
.Ic \&Ns
macro is an isolated closing delimiter.
The macro is ignored.
.It Sy "blocks badly nested"
.Pq mdoc
@ -1098,20 +1264,12 @@ 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 "fill mode already enabled, skipping"
.Pq man
A
.Ic \&fi
request occurs even though the document is still in fill mode,
or already switched back to fill mode.
It has no effect.
.It Sy "fill mode already disabled, skipping"
.Pq man
An
.Ic \&nf
request occurs even though the document already switched to no-fill mode
and did not switch back to fill mode yet.
It has no effect.
.It Sy "first macro on line"
Inside a
.Ic \&Bl Fl column
list, a
.Ic \&Ta
macro occurs as the first macro on a line, which is not portable.
.It Sy "line scope broken"
.Pq man
While parsing the next-line scope of the previous macro,
@ -1165,6 +1323,7 @@ A
.Ic \&Bl ,
.Ic \&D1 ,
.Ic \&Dl ,
.Ic \&MT ,
.Ic \&RS ,
or
.Ic \&UR
@ -1242,6 +1401,17 @@ list, an
.Ic \&It
block is empty.
An empty list item is shown.
.It Sy "missing argument, using next line"
.Pq mdoc
An
.Ic \&It
macro in a
.Ic \&Bd Fl column
list has no arguments.
While
.Nm
uses the text or macros of the following line, if any, for the cell,
other formatters may misformat the list.
.It Sy "missing font type, using \efR"
.Pq mdoc
A
@ -1300,6 +1470,8 @@ An empty pair of square brackets is shown.
.It Sy "missing resource identifier, using \(dq\(dq"
.Pq man
The
.Ic \&MT
or
.Ic \&UR
macro is invoked without any argument.
An empty pair of angle brackets is shown.
@ -1311,14 +1483,6 @@ An empty box is inserted.
.El
.Ss "Warnings related to bad macro arguments"
.Bl -ohang
.It Sy "unterminated quoted argument"
.Pq roff
Macro arguments can be enclosed in double quote characters
such that space characters and macro names contained in the quoted
argument need not be escaped.
The closing quote of the last argument of a macro can be omitted.
However, omitting it is not recommended because it makes the code
harder to read.
.It Sy "duplicate argument"
.Pq mdoc
A
@ -1460,22 +1624,10 @@ As an implementation dependent choice, tab characters on text lines
are passed through to the formatters in any case.
Given that the text before the tab character will be filled,
it is hard to predict which tab stop position the tab will advance to.
.It Sy "whitespace at end of input line"
.Pq mdoc , man , roff
Whitespace at the end of input lines is almost never semantically
significant \(em but in the odd case where it might be, it is
extremely confusing when reviewing and maintaining documents.
.It Sy "new sentence, new line"
.Pq mdoc
A new sentence starts in the middle of a text line.
Start it on a new input line to help formatters produce correct spacing.
.It Sy "bad comment style"
.Pq roff
Comment lines start with a dot, a backslash, and a double-quote character.
The
.Nm
utility treats the line as a comment line even without the backslash,
but leaving out the backslash might not be portable.
.It Sy "invalid escape sequence"
.Pq roff
An escape sequence has an invalid opening argument delimiter, lacks the
@ -1582,6 +1734,21 @@ and any remaining cells stay empty.
.El
.Ss "Errors related to roff, mdoc, and man code"
.Bl -ohang
.It Sy "duplicate prologue macro"
.Pq mdoc
One of the prologue macros occurs more than once.
The last instance overrides all previous ones.
.It Sy "skipping late title macro"
.Pq mdoc
The
.Ic \&Dt
macro appears after the first non-prologue macro.
Traditional formatters cannot handle this because
they write the page header before parsing the document body.
Even though this technical restriction does not apply to
.Nm ,
traditional semantics is preserved.
The late macro is discarded including its arguments.
.It Sy "input stack limit exceeded, infinite loop?"
.Pq roff
Explicit recursion limits are implemented for the following features,
@ -1652,7 +1819,7 @@ An
.Xr mdoc 7
block closing macro, a
.Xr man 7
.Ic \&RE
.Ic \&ME , \&RE
or
.Ic \&UE
macro, an
@ -1686,7 +1853,7 @@ At the end of the document, an explicit
block, a
.Xr man 7
next-line scope or
.Ic \&RS
.Ic \&MT , \&RS
or
.Ic \&UR
block, an equation, table, or
@ -1858,6 +2025,7 @@ A macro or request is invoked with too many arguments:
.Bl -dash -offset 2n -width 2n -compact
.It
.Ic \&Fo ,
.Ic \&MT ,
.Ic \&PD ,
.Ic \&RS ,
.Ic \&UR ,

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.3,v 1.39 2017/05/17 23:39:31 schwarze Exp $
.\" $Id: mandoc.3,v 1.41 2017/07/04 23:40:01 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010-2017 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: May 17 2017 $
.Dd $Mdocdate: July 4 2017 $
.Dt MANDOC 3
.Os
.Sh NAME
@ -35,7 +35,7 @@
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel ,
.Nm mparse_updaterc
.Nm mparse_updaterc
.Nd mandoc macro compiler library
.Sh SYNOPSIS
.In sys/types.h
@ -47,9 +47,10 @@
.Ft struct mparse *
.Fo mparse_alloc
.Fa "int options"
.Fa "enum mandoclevel wlevel"
.Fa "enum mandocerr mmin"
.Fa "mandocmsg mmsg"
.Fa "char *defos"
.Fa "enum mandoc_os oe_e"
.Fa "char *os_s"
.Fc
.Ft void
.Fo (*mandocmsg)
@ -304,12 +305,15 @@ This is for example useful in
.Xr makewhatis 8
.Fl Q
to quickly build minimal databases.
.It Ar wlevel
.It Ar mmin
Can be set to
.Dv MANDOCLEVEL_BADARG ,
.Dv MANDOCLEVEL_ERROR ,
.Dv MANDOCERR_BASE ,
.Dv MANDOCERR_STYLE ,
.Dv MANDOCERR_WARNING ,
.Dv MANDOCERR_ERROR ,
.Dv MANDOCERR_UNSUPP ,
or
.Dv MANDOCLEVEL_WARNING .
.Dv MANDOCERR_MAX .
Messages below the selected level will be suppressed.
.It Ar mmsg
A callback function to handle errors and warnings.
@ -319,10 +323,19 @@ for an example.
If printing of error messages is not desired,
.Dv NULL
may be passed.
.It Ar defos
.It Ar os_e
Operating system to check base system conventions for.
If
.Dv MANDOC_OS_OTHER ,
the system is automatically detected from
.Ic \&Os ,
.Fl Ios ,
or
.Xr uname 3 .
.It Ar os_s
A default string for the
.Xr mdoc 7
.Sq \&Os
.Ic \&Os
macro, overriding the
.Dv OSNAME
preprocessor definition and the results of
@ -650,10 +663,10 @@ TEXT end
.Ed
.Pp
Here, the formatting of the
.Sq \&Ao
.Ic \&Ao
block extends from TEXT ao to TEXT ac,
while the formatting of the
.Sq \&Bo
.Ic \&Bo
block extends from TEXT bo to TEXT bc.
It renders as follows in
.Fl T Ns Cm ascii

View File

@ -1,4 +1,4 @@
/* $Id: mandoc.c,v 1.100 2017/06/02 19:21:23 schwarze Exp $ */
/* $Id: mandoc.c,v 1.103 2017/07/03 13:40:19 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -28,8 +28,9 @@
#include <string.h>
#include <time.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "libmandoc.h"
static int a2time(time_t *, const char *, const char *);
@ -95,6 +96,8 @@ mandoc_escape(const char **end, const char **start, int *sz)
case ',':
case '/':
return ESCAPE_IGNORE;
case 'p':
return ESCAPE_BREAK;
/*
* The \z escape is supposed to output the following
@ -518,27 +521,38 @@ time2a(time_t t)
}
char *
mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
{
char *cp;
time_t t;
/* 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);
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, ln, pos, NULL);
return time2a(time(NULL));
}
/* Valid mdoc(7) date format. */
if (a2time(&t, "$" "Mdocdate: %b %d %Y $", in) ||
a2time(&t, "%b %d, %Y", in))
return time2a(t);
a2time(&t, "%b %d, %Y", in)) {
cp = time2a(t);
if (t > time(NULL) + 86400)
mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
ln, pos, cp);
return cp;
}
/* Do not warn about the legacy man(7) format. */
/* In man(7), do not warn about the legacy format. */
if ( ! a2time(&t, "%Y-%m-%d", in))
mandoc_msg(MANDOCERR_DATE_BAD, parse, ln, pos, in);
if (a2time(&t, "%Y-%m-%d", in) == 0)
mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, in);
else if (t > time(NULL) + 86400)
mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse, ln, pos, in);
else if (man->macroset == MACROSET_MDOC)
mandoc_vmsg(MANDOCERR_DATE_LEGACY, man->parse,
ln, pos, "Dd %s", in);
/* Use any non-mdoc(7) date verbatim. */

View File

@ -1,4 +1,4 @@
/* $Id: mandoc.css,v 1.18 2017/03/13 20:22:18 schwarze Exp $ */
/* $Id: mandoc.css,v 1.22 2017/07/16 18:45:00 schwarze Exp $ */
/*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*/
@ -18,6 +18,7 @@ a.selflink { border-bottom: thin dotted;
color: inherit;
font: inherit;
text-decoration: inherit; }
* { clear: both }
/* Search form and search results. */
@ -79,39 +80,47 @@ li.It-dash:before {
ul.Bl-item { list-style-type: none;
padding-left: 0em; }
li.It-item { }
ul.Bl-compact > li {
margin-top: 0ex; }
ol.Bl-enum { padding-left: 2em; }
li.It-enum { }
ol.Bl-compact > li {
margin-top: 0ex; }
dl.Bl-diag { }
dt.It-diag { }
dd.It-diag { }
dd.It-diag { margin-left: 0ex; }
b.It-diag { font-style: normal; }
dl.Bl-hang { }
dt.It-hang { }
dd.It-hang { }
dd.It-hang { margin-left: 10.2ex; }
dl.Bl-inset { }
dt.It-inset { }
dd.It-inset { }
dd.It-inset { margin-left: 0ex; }
dl.Bl-ohang { }
dt.It-ohang { }
dd.It-ohang { margin-left: 0ex; }
dl.Bl-tag { margin-left: 8ex; }
dl.Bl-tag { margin-left: 10.2ex; }
dt.It-tag { float: left;
clear: both;
margin-top: 0ex;
margin-left: -8ex;
margin-left: -10.2ex;
padding-right: 2ex;
vertical-align: top; }
dd.It-tag { width: 100%;
dd.It-tag { clear: right;
width: 100%;
margin-top: 0ex;
margin-left: 0ex;
vertical-align: top;
overflow: auto; }
dl.Bl-compact > dt {
margin-top: 0ex; }
table.Bl-column { }
tr.It-column { }
td.It-column { margin-top: 1em; }
table.Bl-compact > tbody > tr > td {
margin-top: 0ex; }
cite.Rs { font-style: normal;
font-weight: normal; }

View File

@ -1,4 +1,4 @@
/* $Id: mandoc.h,v 1.226 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: mandoc.h,v 1.245 2017/07/08 14:51:04 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -44,28 +44,46 @@ enum mandoclevel {
enum mandocerr {
MANDOCERR_OK,
MANDOCERR_BASE, /* ===== start of base system conventions ===== */
MANDOCERR_MDOCDATE, /* Mdocdate found: Dd ... */
MANDOCERR_MDOCDATE_MISSING, /* Mdocdate missing: Dd ... */
MANDOCERR_ARCH_BAD, /* unknown architecture: Dt ... arch */
MANDOCERR_OS_ARG, /* operating system explicitly specified: Os ... */
MANDOCERR_RCS_MISSING, /* RCS id missing */
MANDOCERR_XR_BAD, /* referenced manual not found: Xr name sec */
MANDOCERR_STYLE, /* ===== start of style suggestions ===== */
MANDOCERR_DATE_LEGACY, /* legacy man(7) date format: Dd ... */
MANDOCERR_TITLE_CASE, /* lower case character in document title */
MANDOCERR_RCS_REP, /* duplicate RCS id: ... */
MANDOCERR_SEC_TYPO, /* typo in section name: Sh ... */
MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
MANDOCERR_MACRO_USELESS, /* useless macro: macro */
MANDOCERR_BX, /* consider using OS macro: macro */
MANDOCERR_ER_ORDER, /* errnos out of order: Er ... */
MANDOCERR_ER_REP, /* duplicate errno: Er ... */
MANDOCERR_ND_DOT, /* description line ends with a full stop */
MANDOCERR_DELIM, /* trailing delimiter: macro ... */
MANDOCERR_DELIM_NB, /* no blank before trailing delimiter: macro ... */
MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
MANDOCERR_FUNC, /* function name without markup: name() */
MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
MANDOCERR_COMMENT_BAD, /* bad comment style */
MANDOCERR_WARNING, /* ===== start of warnings ===== */
/* related to the prologue */
MANDOCERR_DT_NOTITLE, /* missing manual title, using UNTITLED: line */
MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */
MANDOCERR_TITLE_CASE, /* lower case character in document title */
MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */
MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */
MANDOCERR_DATE_MISSING, /* missing date, using today's date */
MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */
MANDOCERR_DATE_FUTURE, /* date in the future, using it anyway: date */
MANDOCERR_OS_MISSING, /* missing Os macro, using "" */
MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
MANDOCERR_PROLOG_LATE, /* late prologue macro: macro */
MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
MANDOCERR_PROLOG_ORDER, /* prologue macros out of order: macros */
/* related to document structure */
@ -83,6 +101,7 @@ enum mandocerr {
MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */
MANDOCERR_SEC_REP, /* duplicate section title: Sh title */
MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */
MANDOCERR_XR_SELF, /* cross reference to self: Xr name sec */
MANDOCERR_XR_ORDER, /* unusual Xr order: ... after ... */
MANDOCERR_XR_PUNCT, /* unusual Xr punctuation: ... after ... */
MANDOCERR_AN_MISSING, /* AUTHORS section without An macro */
@ -96,8 +115,7 @@ 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_FI_SKIP, /* fill mode already enabled, skipping: fi */
MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
MANDOCERR_TA_LINE, /* first macro on line: Ta */
MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
MANDOCERR_BLK_BLANK, /* skipping blank line in line scope */
@ -114,6 +132,7 @@ enum mandocerr {
MANDOCERR_FO_NOHEAD, /* missing function name, using "": Fo */
MANDOCERR_IT_NOHEAD, /* empty head in list item: Bl -type It */
MANDOCERR_IT_NOBODY, /* empty list item: Bl -type It */
MANDOCERR_IT_NOARG, /* missing argument, using next line: Bl -c It */
MANDOCERR_BF_NOFONT, /* missing font type, using \fR: Bf */
MANDOCERR_BF_BADFONT, /* unknown font type, using \fR: Bf font */
MANDOCERR_PF_SKIP, /* nothing follows prefix: Pf arg */
@ -125,7 +144,6 @@ enum mandocerr {
MANDOCERR_EQN_NOBOX, /* missing eqn box, using "": op */
/* related to bad arguments */
MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
MANDOCERR_ARG_REP, /* duplicate argument: macro arg */
MANDOCERR_AN_REP, /* skipping duplicate argument: An -arg */
MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */
@ -144,9 +162,7 @@ enum mandocerr {
/* related to plain text */
MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */
MANDOCERR_FI_TAB, /* tab in filled text */
MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
MANDOCERR_EOS, /* new sentence, new line */
MANDOCERR_COMMENT_BAD, /* bad comment style */
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
@ -172,6 +188,8 @@ enum mandocerr {
/* related to document structure and macros */
MANDOCERR_FILE, /* cannot open file */
MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
MANDOCERR_CHAR_BAD, /* skipping bad character: number */
MANDOCERR_MACRO, /* skipping unknown macro: macro */
@ -316,11 +334,9 @@ struct tbl_span {
};
enum eqn_boxt {
EQN_ROOT, /* root of parse tree */
EQN_TEXT, /* text (number, variable, whatever) */
EQN_SUBEXPR, /* nested `eqn' subexpression */
EQN_LIST, /* list (braces, etc.) */
EQN_LISTONE, /* singleton list */
EQN_PILE, /* vertical pile */
EQN_MATRIX /* pile of piles */
};
@ -385,17 +401,6 @@ struct eqn_box {
enum eqn_pilet pile; /* equation piling */
};
/*
* An equation consists of a tree of expressions starting at a given
* line and position.
*/
struct eqn {
char *name; /* identifier (or NULL) */
struct eqn_box *root; /* root mathematical expression */
int ln; /* invocation line */
int pos; /* invocation position */
};
/*
* Parse options.
*/
@ -406,6 +411,12 @@ struct eqn {
#define MPARSE_UTF8 16 /* accept UTF-8 input */
#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */
enum mandoc_os {
MANDOC_OS_OTHER = 0,
MANDOC_OS_NETBSD,
MANDOC_OS_OPENBSD
};
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
ESCAPE_IGNORE, /* escape to be ignored */
@ -418,6 +429,7 @@ enum mandoc_esc {
ESCAPE_FONTPREV, /* previous font mode */
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
ESCAPE_BREAK, /* break the output line */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
ESCAPE_HORIZ, /* horizontal movement */
ESCAPE_HLINE, /* horizontal line drawing */
@ -440,7 +452,8 @@ const char *mchars_uc2str(int);
int mchars_num2uc(const char *, size_t);
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 *);
struct mparse *mparse_alloc(int, enum mandocerr, mandocmsg,
enum mandoc_os, const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
int mparse_open(struct mparse *, const char *);

View File

@ -1,7 +1,7 @@
/* $Id: mandoc_aux.c,v 1.9 2015/11/07 14:22:29 schwarze Exp $ */
/* $Id: mandoc_aux.c,v 1.10 2017/06/12 19:05:47 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015, 2017 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
@ -71,7 +71,6 @@ mandoc_malloc(size_t size)
void *
mandoc_realloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
@ -81,13 +80,21 @@ mandoc_realloc(void *ptr, size_t size)
void *
mandoc_reallocarray(void *ptr, size_t num, size_t size)
{
ptr = reallocarray(ptr, num, size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
void *
mandoc_recallocarray(void *ptr, size_t oldnum, size_t num, size_t size)
{
ptr = recallocarray(ptr, oldnum, num, size);
if (ptr == NULL)
err((int)MANDOCLEVEL_SYSERR, NULL);
return ptr;
}
char *
mandoc_strdup(const char *ptr)
{

View File

@ -1,7 +1,7 @@
/* $Id: mandoc_aux.h,v 1.6 2017/02/17 14:31:52 schwarze Exp $ */
/* $Id: mandoc_aux.h,v 1.7 2017/06/12 19:05:47 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2017 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,5 +22,6 @@ void *mandoc_calloc(size_t, size_t);
void *mandoc_malloc(size_t);
void *mandoc_realloc(void *, size_t);
void *mandoc_reallocarray(void *, size_t, size_t);
void *mandoc_recallocarray(void *, size_t, size_t, size_t);
char *mandoc_strdup(const char *);
char *mandoc_strndup(const char *, size_t);

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc_char.7,v 1.66 2017/06/02 12:43:52 schwarze Exp $
.\" $Id: mandoc_char.7,v 1.67 2017/06/14 20:57:07 schwarze Exp $
.\"
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@ -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: June 2 2017 $
.Dd $Mdocdate: June 14 2017 $
.Dt MANDOC_CHAR 7
.Os
.Sh NAME
@ -260,6 +260,7 @@ Lines:
.It \e(ba Ta \(ba Ta bar
.It \e(br Ta \(br Ta box rule
.It \e(ul Ta \(ul Ta underscore
.It \e(ru Ta \(ru Ta underscore (width 0.5m)
.It \e(rn Ta \(rn Ta overline
.It \e(bb Ta \(bb Ta broken bar
.It \e(sl Ta \(sl Ta forward slash

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc_escape.3,v 1.3 2015/01/21 20:33:25 schwarze Exp $
.\" $Id: mandoc_escape.3,v 1.4 2017/07/04 23:40:01 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: January 21 2015 $
.Dd $Mdocdate: July 4 2017 $
.Dt MANDOC_ESCAPE 3
.Os
.Sh NAME
@ -122,7 +122,7 @@ library, see the file
.Pa roff.c ,
.It
above all externally by the
.Xr mandoc
.Xr mandoc 1
formatting modules, in particular
.Fl Tascii
and

View File

@ -1,4 +1,4 @@
.Dd December 1, 2014
.Dd $Mdocdate: July 8 2017 $
.Dt MANDOC_HEADERS 3
.Os
.Sh NAME
@ -87,6 +87,7 @@ Provides
.Vt enum mandoc_esc ,
.Vt enum mandocerr ,
.Vt enum mandoclevel ,
.Vt enum mandoc_os ,
.Vt enum tbl_cellt ,
.Vt enum tbl_datt ,
.Vt enum tbl_spant ,
@ -100,7 +101,6 @@ Provides
.Vt struct tbl_dat ,
.Vt struct tbl_span ,
.Vt struct eqn_box ,
.Vt struct eqn ,
the function prototype typedef
.Fn mandocmsg ,
the function
@ -122,11 +122,24 @@ Uses the type
from
.Pa roff.h
as an opaque type for function prototypes.
.It Qq Pa mandoc_xr.h
Provides
.Vt struct mandoc_xr
and the functions
.Fn mandoc_xr_reset ,
.Fn mandoc_xr_add ,
.Fn mandoc_xr_get ,
and
.Fn mandoc_xr_free .
.It Qq Pa roff.h
Requires
.Qq Pa mandoc_ohash.h
for
.Vt struct ohash .
.Vt struct ohash
and
.Qq Pa mandoc.h
for
.Vt enum mandoc_os .
.Pp
Provides
.Vt enum mdoc_endbody ,
@ -251,17 +264,11 @@ and
from
.Pa roff.c
for function prototypes.
Uses the types
.Vt struct tbl_span
and
.Vt struct eqn
from
.Pa mandoc.h
and
Uses the type
.Vt struct roff_man
from
.Pa roff.h
as opaque types for function prototypes.
as an opaque type for function prototypes.
.It Qq Pa roff_int.h
Requires
.Qq Pa roff.h
@ -278,16 +285,11 @@ because the latter two are needed by
.Qq Pa roff.c .
.Pp
Uses the types
.Vt struct eqn
and
.Vt struct tbl_span
from
.Pa mandoc.h ,
.Vt struct roff_man
and
.Vt struct roff_node
from
.Pa roff.h ,
.Pa roff.h
and
.Vt struct mdoc_arg
from
@ -359,16 +361,13 @@ or
Requires
.In sys/types.h
for
.Vt size_t ,
.Vt size_t
and
.Qq Pa mandoc.h
for
.Vt struct tbl_*
and
.Vt struct eqn ,
and
.Qq Pa libmandoc.h
for
.Vt enum rofferr .
.Vt struct eqn_box .
.Pp
Provides
.Vt enum tbl_part ,
@ -448,7 +447,7 @@ from
Uses
.Vt struct tbl_span
and
.Vt struct eqn
.Vt struct eqn_box
from
.Pa mandoc.h
and
@ -489,7 +488,7 @@ and many HTML formatting functions.
Uses
.Vt struct tbl_span
and
.Vt struct eqn
.Vt struct eqn_box
from
.Pa mandoc.h
and
@ -535,8 +534,9 @@ Provides
and the functions
.Fn manconf_parse ,
.Fn manconf_output ,
.Fn manconf_free ,
and
.Fn manconf_free .
.Fn manpath_base .
.It Qq Pa mansearch.h
Requires
.In sys/types.h

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc_html.3,v 1.8 2017/05/12 17:58:21 schwarze Exp $
.\" $Id: mandoc_html.3,v 1.10 2017/07/15 17:57:51 schwarze Exp $
.\"
.\" Copyright (c) 2014, 2017 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: May 12 2017 $
.Dd $Mdocdate: July 15 2017 $
.Dt MANDOC_HTML 3
.Os
.Sh NAME
@ -219,11 +219,6 @@ argument, used as a style value.
Requires one
.Vt struct roffsu *
argument, used as a length.
.It Cm v
Requires one
.Vt int
argument, interpreted as a vertical length in units of
.Dv SCALE_VS .
.It Cm w
Requires one
.Vt char *
@ -236,12 +231,15 @@ nothing is printed for this pair.
.Pp
The
.Cm w
argument type letter can optionally be followed by one or two
argument type letter can optionally be followed by one, two, or three
modifier letters.
The modifier
.Cm *
suppresses printing of the pair if the argument matches 6n.
The modifier
.Cm +
increases the width by 10% to make even bold text fit
and adds two units for padding between columns.
increases the width by 20% to make even bold text fit
and adds three units for padding between columns.
The modifier
.Cm \-
makes the width negative by multiplying it with \-1.
@ -249,10 +247,6 @@ makes the width negative by multiplying it with \-1.
.Pp
Style name letters decide what to do with the preceding argument:
.Bl -tag -width 1n -offset indent
.It Cm b
Set
.Cm margin-bottom
to the given length.
.It Cm h
Set
.Cm height
@ -265,10 +259,6 @@ to the given length.
Set
.Cm margin-left
to the given length.
.It Cm t
Set
.Cm margin-top
to the given length.
.It Cm w
Set
.Cm width

121
mandoc_xr.c Normal file
View File

@ -0,0 +1,121 @@
/* $Id: mandoc_xr.c,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */
/*
* Copyright (c) 2017 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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
#include "mandoc_xr.h"
static struct ohash *xr_hash = NULL;
static struct mandoc_xr *xr_first = NULL;
static struct mandoc_xr *xr_last = NULL;
static void mandoc_xr_clear(void);
static void
mandoc_xr_clear(void)
{
struct mandoc_xr *xr;
unsigned int slot;
if (xr_hash == NULL)
return;
for (xr = ohash_first(xr_hash, &slot); xr != NULL;
xr = ohash_next(xr_hash, &slot))
free(xr);
ohash_delete(xr_hash);
}
void
mandoc_xr_reset(void)
{
if (xr_hash == NULL)
xr_hash = mandoc_malloc(sizeof(*xr_hash));
else
mandoc_xr_clear();
mandoc_ohash_init(xr_hash, 5,
offsetof(struct mandoc_xr, hashkey));
xr_first = xr_last = NULL;
}
int
mandoc_xr_add(const char *sec, const char *name, int line, int pos)
{
struct mandoc_xr *xr, *oxr;
const char *pend;
size_t ssz, nsz, tsz;
unsigned int slot;
int ret;
uint32_t hv;
if (xr_hash == NULL)
return 0;
ssz = strlen(sec) + 1;
nsz = strlen(name) + 1;
tsz = ssz + nsz;
xr = mandoc_malloc(sizeof(*xr) + tsz);
xr->next = NULL;
xr->sec = xr->hashkey;
xr->name = xr->hashkey + ssz;
xr->line = line;
xr->pos = pos;
xr->count = 1;
memcpy(xr->sec, sec, ssz);
memcpy(xr->name, name, nsz);
pend = xr->hashkey + tsz;
hv = ohash_interval(xr->hashkey, &pend);
slot = ohash_lookup_memory(xr_hash, xr->hashkey, tsz, hv);
if ((oxr = ohash_find(xr_hash, slot)) == NULL) {
ohash_insert(xr_hash, slot, xr);
if (xr_first == NULL)
xr_first = xr;
else
xr_last->next = xr;
xr_last = xr;
return 0;
}
oxr->count++;
ret = (oxr->line == -1) ^ (xr->line == -1);
if (xr->line == -1)
oxr->line = -1;
free(xr);
return ret;
}
struct mandoc_xr *
mandoc_xr_get(void)
{
return xr_first;
}
void
mandoc_xr_free(void)
{
mandoc_xr_clear();
free(xr_hash);
xr_hash = NULL;
}

31
mandoc_xr.h Normal file
View File

@ -0,0 +1,31 @@
/* $Id: mandoc_xr.h,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */
/*
* Copyright (c) 2017 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.
*/
struct mandoc_xr {
struct mandoc_xr *next;
char *sec;
char *name;
int line; /* Or -1 for this page's own names. */
int pos;
int count;
char hashkey[];
};
void mandoc_xr_reset(void);
int mandoc_xr_add(const char *, const char *, int, int);
struct mandoc_xr *mandoc_xr_get(void);
void mandoc_xr_free(void);

View File

@ -1,4 +1,4 @@
/* $Id: mandocd.c,v 1.5 2017/02/17 14:31:52 schwarze Exp $ */
/* $Id: mandocd.c,v 1.6 2017/06/24 14:38:32 schwarze Exp $ */
/*
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -171,7 +171,7 @@ main(int argc, char *argv[])
mchars_alloc();
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
MANDOCLEVEL_BADARG, NULL, defos);
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, defos);
memset(&options, 0, sizeof(options));
switch (outtype) {

View File

@ -1,4 +1,4 @@
/* $Id: mandocdb.c,v 1.250 2017/05/17 22:27:12 schwarze Exp $ */
/* $Id: mandocdb.c,v 1.253 2017/07/28 14:48:25 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -420,7 +420,8 @@ mandocdb(int argc, char *argv[])
exitcode = (int)MANDOCLEVEL_OK;
mchars_alloc();
mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL, NULL);
mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
MANDOC_OS_OTHER, NULL);
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
@ -2129,7 +2130,7 @@ dbwrite(struct dba *dba)
dba_array_start(dba->pages);
if (dba_array_next(dba->pages) == NULL) {
if (unlink(MANDOC_DB) == -1)
if (unlink(MANDOC_DB) == -1 && errno != ENOENT)
say(MANDOC_DB, "&unlink");
return;
}

View File

@ -1,4 +1,4 @@
/* $Id: manpath.c,v 1.33 2017/02/10 15:45:28 schwarze Exp $ */
/* $Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@ -91,6 +91,13 @@ manconf_parse(struct manconf *conf, const char *file,
manpath_parseline(&conf->manpath, defp, 0);
}
void
manpath_base(struct manpaths *dirs)
{
char path_base[] = MANPATH_BASE;
manpath_parseline(dirs, path_base, 0);
}
/*
* Parse a FULL pathname from a colon-separated list of arrays.
*/
@ -299,7 +306,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
mandoc_asprintf(&oldval, "%zu", conf->width);
break;
}
conf->width = strtonum(cp, 58, 1000, &errstr);
conf->width = strtonum(cp, 1, 1000, &errstr);
if (errstr == NULL)
return 0;
warnx("-O width=%s is %s", cp, errstr);

View File

@ -104,7 +104,8 @@ mansearch(const struct mansearch *search,
}
cur = maxres = 0;
*res = NULL;
if (res != NULL)
*res = NULL;
outkey = KEY_Nd;
if (search->outkey != NULL)
@ -173,6 +174,10 @@ mansearch(const struct mansearch *search,
lstmatch(search->arch, page->arch) == 0)
continue;
if (res == NULL) {
cur = 1;
break;
}
if (cur + 1 > maxres) {
maxres += 1024;
*res = mandoc_reallocarray(*res,
@ -204,12 +209,13 @@ mansearch(const struct mansearch *search,
if (cur && search->firstmatch)
break;
}
qsort(*res, cur, sizeof(struct manpage), manpage_compare);
if (res != NULL)
qsort(*res, cur, sizeof(struct manpage), manpage_compare);
if (chdir_status && getcwd_status && chdir(buf) == -1)
warn("%s", buf);
exprfree(e);
*sz = cur;
return 1;
return res != NULL || cur;
}
/*
@ -388,13 +394,29 @@ static int
manpage_compare(const void *vp1, const void *vp2)
{
const struct manpage *mp1, *mp2;
const char *cp1, *cp2;
size_t sz1, sz2;
int diff;
mp1 = vp1;
mp2 = vp2;
return (diff = mp2->bits - mp1->bits) ? diff :
(diff = mp1->sec - mp2->sec) ? diff :
strcasecmp(mp1->names, mp2->names);
if ((diff = mp2->bits - mp1->bits) ||
(diff = mp1->sec - mp2->sec))
return diff;
/* Fall back to alphabetic ordering of names. */
sz1 = strcspn(mp1->names, "(");
sz2 = strcspn(mp2->names, "(");
if (sz1 < sz2)
sz1 = sz2;
if ((diff = strncasecmp(mp1->names, mp2->names, sz1)))
return diff;
/* For identical names and sections, prefer arch-dependent. */
cp1 = strchr(mp1->names + sz1, '/');
cp2 = strchr(mp2->names + sz2, '/');
return cp1 != NULL && cp2 != NULL ? strcasecmp(cp1, cp2) :
cp1 != NULL ? -1 : cp2 != NULL ? 1 : 0;
}
static char *

25
mdoc.7
View File

@ -1,4 +1,4 @@
.\" $Id: mdoc.7,v 1.264 2017/05/05 15:54:59 schwarze Exp $
.\" $Id: mdoc.7,v 1.269 2017/07/20 16:24:53 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013-2017 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: May 5 2017 $
.Dd $Mdocdate: July 20 2017 $
.Dt MDOC 7
.Os
.Sh NAME
@ -477,7 +477,7 @@ in the alphabetical
.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off
.It Sx \&Bk , \&Ek Ta keep block: Fl words
.El
.Ss Semantic markup for command line utilities:
.Ss Semantic markup for command line utilities
.Bl -column "Brq, Bro, Brc" description
.It Sx \&Nm Ta start a SYNOPSIS block with the name of a utility
.It Sx \&Fl Ta command line options (flags) (>=0 arguments)
@ -488,7 +488,7 @@ in the alphabetical
.It Sx \&Ev Ta environmental variable (>0 arguments)
.It Sx \&Pa Ta file system path (>=0 arguments)
.El
.Ss Semantic markup for function libraries:
.Ss Semantic markup for function libraries
.Bl -column "Brq, Bro, Brc" description
.It Sx \&Lb Ta function library (one argument)
.It Sx \&In Ta include file (one argument)
@ -509,7 +509,7 @@ in the alphabetical
.It Sx \&Er Ta error constant (>0 arguments)
.It Sx \&Ev Ta environmental variable (>0 arguments)
.El
.Ss Various semantic markup:
.Ss Various semantic markup
.Bl -column "Brq, Bro, Brc" description
.It Sx \&An Ta author name (>0 arguments)
.It Sx \&Lk Ta hyperlink: Ar uri Op Ar name
@ -735,7 +735,7 @@ A version of
.At .
.It Cm III
.At III .
.It Cm V[.[1-4]]?
.It Cm V | V.[1-4]
A version of
.At V .
.El
@ -1850,10 +1850,10 @@ The tab cell delimiter may only be used within the
.Sx \&It
line itself; on following lines, only the
.Sx \&Ta
macro can be used to delimit cells, and
macro can be used to delimit cells, and portability requires that
.Sx \&Ta
is only recognised as a macro when called by other macros,
not as the first macro on a line.
is called by other macros: some parsers do not recognize it when
it appears as the first macro on a line.
.Pp
Note that quoted strings may span tab-delimited cells on an
.Sx \&It
@ -2575,11 +2575,6 @@ The second and last Technical Corrigendum.
.br
This standard is also called
X/Open Portability Guide version 7.
.Pp
.It \-p1003.1-2013
.St -p1003.1-2013
.br
This is the first Technical Corrigendum.
.El
.It Other standards
.Pp
@ -3203,7 +3198,7 @@ but produces large indentations.
.Xr tbl 7
.Pp
The web page
.Lk http://mdocml.bsd.lv/mdoc/ "extended documentation for the mdoc language"
.Lk http://mandoc.bsd.lv/mdoc/ "extended documentation for the mdoc language"
provides a few tutorial-style pages for beginners, an extensive style
guide for advanced authors, and an alphabetic index helping to choose
the best macros for various kinds of content.

30
mdoc.c
View File

@ -1,4 +1,4 @@
/* $Id: mdoc.c,v 1.266 2017/06/07 20:58:49 schwarze Exp $ */
/* $Id: mdoc.c,v 1.267 2017/06/17 13:06:16 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -179,6 +179,7 @@ static int
mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
{
struct roff_node *n;
const char *cp, *sp;
char *c, *ws, *end;
n = mdoc->last;
@ -244,15 +245,30 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, (int)(ws-buf), NULL);
/*
* Blank lines are allowed in no-fill mode
* and cancel preceding \c,
* but add a single vertical space elsewhere.
*/
if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
switch (mdoc->last->type) {
case ROFFT_TEXT:
sp = mdoc->last->string;
cp = end = strchr(sp, '\0') - 2;
if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
break;
while (cp > sp && cp[-1] == '\\')
cp--;
if ((end - cp) % 2)
break;
*end = '\0';
return 1;
default:
break;
}
mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
line, (int)(c - buf), NULL);
/*
* Insert a `sp' in the case of a blank line. Technically,
* blank lines aren't allowed, but enough manuals assume this
* behaviour that we want to work around it.
*/
roff_elem_alloc(mdoc, line, offs, ROFF_sp);
mdoc->last->flags |= NODE_VALID | NODE_ENDED;
mdoc->next = ROFF_NEXT_SIBLING;

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_html.c,v 1.289 2017/05/30 16:31:29 schwarze Exp $ */
/* $Id: mdoc_html.c,v 1.294 2017/07/15 17:57:51 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -27,6 +27,7 @@
#include <unistd.h>
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "out.h"
@ -714,10 +715,7 @@ mdoc_it_pre(MDOC_ARGS)
case ROFFT_HEAD:
return 0;
case ROFFT_BODY:
if (bl->norm->Bl.comp)
print_otag(h, TAG_LI, "csvt", cattr, 0);
else
print_otag(h, TAG_LI, "c", cattr);
print_otag(h, TAG_LI, "c", cattr);
break;
default:
break;
@ -729,15 +727,12 @@ mdoc_it_pre(MDOC_ARGS)
case LIST_ohang:
switch (n->type) {
case ROFFT_HEAD:
if (bl->norm->Bl.comp)
print_otag(h, TAG_DT, "csvt", cattr, 0);
else
print_otag(h, TAG_DT, "c", cattr);
print_otag(h, TAG_DT, "c", cattr);
if (type == LIST_diag)
print_otag(h, TAG_B, "c", cattr);
break;
case ROFFT_BODY:
print_otag(h, TAG_DD, "cswl", cattr,
print_otag(h, TAG_DD, "csw*+l", cattr,
bl->norm->Bl.width);
break;
default:
@ -751,7 +746,7 @@ mdoc_it_pre(MDOC_ARGS)
(n->parent->prev == NULL ||
n->parent->prev->body == NULL ||
n->parent->prev->body->child != NULL)) {
t = print_otag(h, TAG_DT, "csw+-l",
t = print_otag(h, TAG_DT, "csw*+-l",
cattr, bl->norm->Bl.width);
print_text(h, "\\ ");
print_tagq(h, t);
@ -759,7 +754,7 @@ mdoc_it_pre(MDOC_ARGS)
print_text(h, "\\ ");
print_tagq(h, t);
}
print_otag(h, TAG_DT, "csw+-l", cattr,
print_otag(h, TAG_DT, "csw*+-l", cattr,
bl->norm->Bl.width);
break;
case ROFFT_BODY:
@ -779,10 +774,7 @@ mdoc_it_pre(MDOC_ARGS)
case ROFFT_HEAD:
break;
case ROFFT_BODY:
if (bl->norm->Bl.comp)
print_otag(h, TAG_TD, "csvt", cattr, 0);
else
print_otag(h, TAG_TD, "c", cattr);
print_otag(h, TAG_TD, "c", cattr);
break;
default:
print_otag(h, TAG_TR, "c", cattr);
@ -797,9 +789,9 @@ mdoc_it_pre(MDOC_ARGS)
static int
mdoc_bl_pre(MDOC_ARGS)
{
char cattr[21];
struct tag *t;
struct mdoc_bl *bl;
const char *cattr;
size_t i;
enum htmltag elemtype;
@ -834,50 +826,52 @@ mdoc_bl_pre(MDOC_ARGS)
switch (bl->type) {
case LIST_bullet:
elemtype = TAG_UL;
cattr = "Bl-bullet";
(void)strlcpy(cattr, "Bl-bullet", sizeof(cattr));
break;
case LIST_dash:
case LIST_hyphen:
elemtype = TAG_UL;
cattr = "Bl-dash";
(void)strlcpy(cattr, "Bl-dash", sizeof(cattr));
break;
case LIST_item:
elemtype = TAG_UL;
cattr = "Bl-item";
(void)strlcpy(cattr, "Bl-item", sizeof(cattr));
break;
case LIST_enum:
elemtype = TAG_OL;
cattr = "Bl-enum";
(void)strlcpy(cattr, "Bl-enum", sizeof(cattr));
break;
case LIST_diag:
elemtype = TAG_DL;
cattr = "Bl-diag";
(void)strlcpy(cattr, "Bl-diag", sizeof(cattr));
break;
case LIST_hang:
elemtype = TAG_DL;
cattr = "Bl-hang";
(void)strlcpy(cattr, "Bl-hang", sizeof(cattr));
break;
case LIST_inset:
elemtype = TAG_DL;
cattr = "Bl-inset";
(void)strlcpy(cattr, "Bl-inset", sizeof(cattr));
break;
case LIST_ohang:
elemtype = TAG_DL;
cattr = "Bl-ohang";
(void)strlcpy(cattr, "Bl-ohang", sizeof(cattr));
break;
case LIST_tag:
cattr = "Bl-tag";
if (bl->offs)
print_otag(h, TAG_DIV, "cswl", cattr, bl->offs);
print_otag(h, TAG_DL, "csw+l", cattr, bl->width);
print_otag(h, TAG_DIV, "cswl", "Bl-tag", bl->offs);
print_otag(h, TAG_DL, "csw*+l", bl->comp ?
"Bl-tag Bl-compact" : "Bl-tag", bl->width);
return 1;
case LIST_column:
elemtype = TAG_TABLE;
cattr = "Bl-column";
(void)strlcpy(cattr, "Bl-column", sizeof(cattr));
break;
default:
abort();
}
if (bl->comp)
(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
print_otag(h, elemtype, "cswl", cattr, bl->offs);
return 1;
}
@ -1322,12 +1316,16 @@ mdoc_lk_pre(MDOC_ARGS)
punct = punct->next;
/* Link target and link text. */
descr = link->next;
if (descr == punct)
descr = link; /* no text */
t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
for (descr = link->next; descr != punct; descr = descr->next) {
do {
if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
h->flags |= HTML_NOSPACE;
print_text(h, descr->string);
}
descr = descr->next;
} while (descr != punct);
print_tagq(h, t);
/* Trailing punctuation. */

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_man.c,v 1.119 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: mdoc_man.c,v 1.122 2017/06/14 22:51:25 schwarze Exp $ */
/*
* Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
*
@ -125,14 +125,16 @@ static void print_count(int *);
static void print_node(DECL_ARGS);
static const void_fp roff_manacts[ROFF_MAX] = {
pre_br,
pre_onearg,
pre_ft,
pre_onearg,
pre_onearg,
pre_sp,
pre_ta,
pre_onearg,
pre_br, /* br */
pre_onearg, /* ce */
pre_ft, /* ft */
pre_onearg, /* ll */
pre_onearg, /* mc */
pre_onearg, /* po */
pre_onearg, /* rj */
pre_sp, /* sp */
pre_ta, /* ta */
pre_onearg, /* ti */
};
static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
@ -196,8 +198,8 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
{ NULL, NULL, NULL, NULL, NULL }, /* Bsx */
{ NULL, NULL, NULL, NULL, NULL }, /* Bx */
{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bsx */
{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bx */
{ NULL, pre_skip, NULL, NULL, NULL }, /* Db */
{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
@ -206,12 +208,12 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
{ cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
{ NULL, NULL, NULL, NULL, NULL }, /* Fx */
{ NULL, pre_bk, post_bk, NULL, NULL }, /* Fx */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
{ NULL, pre_no, NULL, NULL, NULL }, /* No */
{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
{ NULL, NULL, NULL, NULL, NULL }, /* Nx */
{ NULL, NULL, NULL, NULL, NULL }, /* Ox */
{ NULL, pre_bk, post_bk, NULL, NULL }, /* Nx */
{ NULL, pre_bk, post_bk, NULL, NULL }, /* Ox */
{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
@ -252,7 +254,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
{ NULL, pre_skip, NULL, NULL, NULL }, /* Es */
{ cond_body, pre_en, post_en, NULL, NULL }, /* En */
{ NULL, NULL, NULL, NULL, NULL }, /* Dx */
{ NULL, pre_bk, post_bk, NULL, NULL }, /* Dx */
{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
@ -990,11 +992,11 @@ post_bf(DECL_ARGS)
static int
pre_bk(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
return 1;
case ROFFT_BODY:
case ROFFT_ELEM:
outflags |= MMAN_Bk;
return 1;
default:
@ -1005,9 +1007,18 @@ pre_bk(DECL_ARGS)
static void
post_bk(DECL_ARGS)
{
if (n->type == ROFFT_BODY)
switch (n->type) {
case ROFFT_ELEM:
while ((n = n->parent) != NULL)
if (n->tok == MDOC_Bk)
return;
/* FALLTHROUGH */
case ROFFT_BODY:
outflags &= ~MMAN_Bk;
break;
default:
break;
}
}
static int

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_markdown.c,v 1.22 2017/05/30 16:31:29 schwarze Exp $ */
/* $Id: mdoc_markdown.c,v 1.23 2017/06/14 01:31:26 schwarze Exp $ */
/*
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@ -493,7 +493,7 @@ md_word(const char *s)
{
const char *seq, *prevfont, *currfont, *nextfont;
char c;
int bs, sz, uc;
int bs, sz, uc, breakline;
/* No spacing before closing delimiters. */
if (s[0] != '\0' && s[1] == '\0' &&
@ -510,6 +510,7 @@ md_word(const char *s)
if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
outflags &= ~MD_spc;
breakline = 0;
prevfont = currfont = "";
while ((c = *s++) != '\0') {
bs = 0;
@ -595,6 +596,9 @@ md_word(const char *s)
case ESCAPE_FONTPREV:
nextfont = prevfont;
break;
case ESCAPE_BREAK:
breakline = 1;
break;
case ESCAPE_NOSPACE:
case ESCAPE_SKIPCHAR:
case ESCAPE_OVERSTRIKE:
@ -642,6 +646,13 @@ md_word(const char *s)
if (bs)
putchar('\\');
md_char(c);
if (breakline &&
(*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
printf(" \n");
breakline = 0;
while (*s == ' ' || *s == ASCII_NBRSP)
s++;
}
}
if (*currfont != '\0') {
outflags &= ~MD_spc;

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_term.c,v 1.363 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: mdoc_term.c,v 1.364 2017/06/14 17:51:15 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -540,7 +540,7 @@ a2width(const struct termp *p, const char *v)
SCALE_HS_INIT(&su, term_strlen(p, v));
su.scale /= term_strlen(p, "0");
}
return term_hspan(p, &su) / 24;
return term_hen(p, &su);
}
/*
@ -686,7 +686,7 @@ termp_it_pre(DECL_ARGS)
SCALE_HS_INIT(&su,
term_strlen(p, bl->norm->Bl.cols[i]));
su.scale /= term_strlen(p, "0");
offset += term_hspan(p, &su) / 24 + dcol;
offset += term_hen(p, &su) + dcol;
}
/*
@ -704,7 +704,7 @@ termp_it_pre(DECL_ARGS)
*/
SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i]));
su.scale /= term_strlen(p, "0");
width = term_hspan(p, &su) / 24 + dcol;
width = term_hen(p, &su) + dcol;
break;
default:
if (NULL == bl->norm->Bl.width)

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_validate.c,v 1.332 2017/06/08 00:23:30 schwarze Exp $ */
/* $Id: mdoc_validate.c,v 1.350 2017/07/20 12:54:02 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -33,6 +33,7 @@
#include "mandoc_aux.h"
#include "mandoc.h"
#include "mandoc_xr.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
@ -53,13 +54,14 @@ typedef void (*v_post)(POST_ARGS);
static int build_list(struct roff_man *, int);
static void check_text(struct roff_man *, int, int, char *);
static void check_bsd(struct roff_man *, int, int, char *);
static void check_argv(struct roff_man *,
struct roff_node *, struct mdoc_argv *);
static void check_args(struct roff_man *, struct roff_node *);
static void check_toptext(struct roff_man *, int, int, const char *);
static int child_an(const struct roff_node *);
static size_t macro2len(enum roff_tok);
static void rewrite_macro2len(struct roff_man *, char **);
static int similar(const char *, const char *);
static void post_an(POST_ARGS);
static void post_an_norm(POST_ARGS);
@ -75,6 +77,8 @@ static void post_bx(POST_ARGS);
static void post_defaults(POST_ARGS);
static void post_display(POST_ARGS);
static void post_dd(POST_ARGS);
static void post_delim(POST_ARGS);
static void post_delim_nb(POST_ARGS);
static void post_dt(POST_ARGS);
static void post_en(POST_ARGS);
static void post_es(POST_ARGS);
@ -106,6 +110,7 @@ static void post_sh_authors(POST_ARGS);
static void post_sm(POST_ARGS);
static void post_st(POST_ARGS);
static void post_std(POST_ARGS);
static void post_sx(POST_ARGS);
static void post_useless(POST_ARGS);
static void post_xr(POST_ARGS);
static void post_xx(POST_ARGS);
@ -124,33 +129,33 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_bl, /* Bl */
NULL, /* El */
post_it, /* It */
NULL, /* Ad */
post_delim_nb, /* Ad */
post_an, /* An */
NULL, /* Ap */
post_defaults, /* Ar */
NULL, /* Cd */
NULL, /* Cm */
NULL, /* Dv */
NULL, /* Er */
NULL, /* Ev */
post_delim_nb, /* Cm */
post_delim_nb, /* Dv */
post_delim_nb, /* Er */
post_delim_nb, /* Ev */
post_ex, /* Ex */
post_fa, /* Fa */
NULL, /* Fd */
NULL, /* Fl */
post_delim_nb, /* Fl */
post_fn, /* Fn */
NULL, /* Ft */
NULL, /* Ic */
NULL, /* In */
post_delim_nb, /* Ft */
post_delim_nb, /* Ic */
post_delim_nb, /* In */
post_defaults, /* Li */
post_nd, /* Nd */
post_nm, /* Nm */
NULL, /* Op */
post_delim_nb, /* Op */
post_obsolete, /* Ot */
post_defaults, /* Pa */
post_rv, /* Rv */
post_st, /* St */
NULL, /* Va */
NULL, /* Vt */
post_delim_nb, /* Va */
post_delim_nb, /* Vt */
post_xr, /* Xr */
NULL, /* %A */
post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */
@ -164,12 +169,12 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */
NULL, /* %V */
NULL, /* Ac */
NULL, /* Ao */
NULL, /* Aq */
post_delim_nb, /* Ao */
post_delim_nb, /* Aq */
post_at, /* At */
NULL, /* Bc */
post_bf, /* Bf */
NULL, /* Bo */
post_delim_nb, /* Bo */
NULL, /* Bq */
post_xx, /* Bsx */
post_bx, /* Bx */
@ -179,50 +184,50 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
NULL, /* Dq */
NULL, /* Ec */
NULL, /* Ef */
NULL, /* Em */
post_delim_nb, /* Em */
NULL, /* Eo */
post_xx, /* Fx */
NULL, /* Ms */
post_delim_nb, /* Ms */
NULL, /* No */
post_ns, /* Ns */
post_xx, /* Nx */
post_xx, /* Ox */
NULL, /* Pc */
NULL, /* Pf */
NULL, /* Po */
NULL, /* Pq */
post_delim_nb, /* Po */
post_delim_nb, /* Pq */
NULL, /* Qc */
NULL, /* Ql */
NULL, /* Qo */
NULL, /* Qq */
post_delim_nb, /* Ql */
post_delim_nb, /* Qo */
post_delim_nb, /* Qq */
NULL, /* Re */
post_rs, /* Rs */
NULL, /* Sc */
NULL, /* So */
NULL, /* Sq */
post_delim_nb, /* So */
post_delim_nb, /* Sq */
post_sm, /* Sm */
post_hyph, /* Sx */
NULL, /* Sy */
post_sx, /* Sx */
post_delim_nb, /* Sy */
post_useless, /* Tn */
post_xx, /* Ux */
NULL, /* Xc */
NULL, /* Xo */
post_fo, /* Fo */
NULL, /* Fc */
NULL, /* Oo */
post_delim_nb, /* Oo */
NULL, /* Oc */
post_bk, /* Bk */
NULL, /* Ek */
post_eoln, /* Bt */
NULL, /* Hf */
post_obsolete, /* Hf */
post_obsolete, /* Fr */
post_eoln, /* Ud */
post_lb, /* Lb */
post_par, /* Lp */
NULL, /* Lk */
post_delim_nb, /* Lk */
post_defaults, /* Mt */
NULL, /* Brq */
NULL, /* Bro */
post_delim_nb, /* Brq */
post_delim_nb, /* Bro */
NULL, /* Brc */
NULL, /* %C */
post_es, /* Es */
@ -303,10 +308,11 @@ mdoc_node_validate(struct roff_man *mdoc)
if (n->sec != SEC_SYNOPSIS ||
(n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd))
check_text(mdoc, n->line, n->pos, n->string);
if (n->parent->tok == MDOC_Sh ||
n->parent->tok == MDOC_Ss ||
n->parent->tok == MDOC_It)
check_bsd(mdoc, n->line, n->pos, n->string);
if (n->parent->tok == MDOC_It ||
(n->parent->type == ROFFT_BODY &&
(n->parent->tok == MDOC_Sh ||
n->parent->tok == MDOC_Ss)))
check_toptext(mdoc, n->line, n->pos, n->string);
break;
case ROFFT_EQN:
case ROFFT_TBL:
@ -389,9 +395,12 @@ check_text(struct roff_man *mdoc, int ln, int pos, char *p)
}
static void
check_bsd(struct roff_man *mdoc, int ln, int pos, char *p)
check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p)
{
const char *cp;
const char *cp, *cpr;
if (*p == '\0')
return;
if ((cp = strstr(p, "OpenBSD")) != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
@ -405,6 +414,142 @@ check_bsd(struct roff_man *mdoc, int ln, int pos, char *p)
if ((cp = strstr(p, "DragonFly")) != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
ln, pos + (cp - p), "Dx");
cp = p;
while ((cp = strstr(cp + 1, "()")) != NULL) {
for (cpr = cp - 1; cpr >= p; cpr--)
if (*cpr != '_' && !isalnum((unsigned char)*cpr))
break;
if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) {
cpr++;
mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse,
ln, pos + (cpr - p),
"%.*s()", (int)(cp - cpr), cpr);
}
}
}
static void
post_delim(POST_ARGS)
{
const struct roff_node *nch;
const char *lc;
enum mdelim delim;
enum roff_tok tok;
tok = mdoc->last->tok;
nch = mdoc->last->last;
if (nch == NULL || nch->type != ROFFT_TEXT)
return;
lc = strchr(nch->string, '\0') - 1;
if (lc < nch->string)
return;
delim = mdoc_isdelim(lc);
if (delim == DELIM_NONE || delim == DELIM_OPEN)
return;
if (*lc == ')' && (tok == MDOC_Nd || tok == MDOC_Sh ||
tok == MDOC_Ss || tok == MDOC_Fo))
return;
mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse,
nch->line, nch->pos + (lc - nch->string),
"%s%s %s", roff_name[tok],
nch == mdoc->last->child ? "" : " ...", nch->string);
}
static void
post_delim_nb(POST_ARGS)
{
const struct roff_node *nch;
const char *lc, *cp;
int nw;
enum mdelim delim;
enum roff_tok tok;
/*
* Find candidates: at least two bytes,
* the last one a closing or middle delimiter.
*/
tok = mdoc->last->tok;
nch = mdoc->last->last;
if (nch == NULL || nch->type != ROFFT_TEXT)
return;
lc = strchr(nch->string, '\0') - 1;
if (lc <= nch->string)
return;
delim = mdoc_isdelim(lc);
if (delim == DELIM_NONE || delim == DELIM_OPEN)
return;
/*
* Reduce false positives by allowing various cases.
*/
/* Escaped delimiters. */
if (lc > nch->string + 1 && lc[-2] == '\\' &&
(lc[-1] == '&' || lc[-1] == 'e'))
return;
/* Specific byte sequences. */
switch (*lc) {
case ')':
for (cp = lc; cp >= nch->string; cp--)
if (*cp == '(')
return;
break;
case '.':
if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.')
return;
if (lc[-1] == '.')
return;
break;
case ';':
if (tok == MDOC_Vt)
return;
break;
case '?':
if (lc[-1] == '?')
return;
break;
case ']':
for (cp = lc; cp >= nch->string; cp--)
if (*cp == '[')
return;
break;
case '|':
if (lc == nch->string + 1 && lc[-1] == '|')
return;
default:
break;
}
/* Exactly two non-alphanumeric bytes. */
if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1]))
return;
/* At least three alphabetic words with a sentence ending. */
if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em ||
tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq ||
tok == MDOC_Sy)) {
nw = 0;
for (cp = lc - 1; cp >= nch->string; cp--) {
if (*cp == ' ') {
nw++;
if (cp > nch->string && cp[-1] == ',')
cp--;
} else if (isalpha((unsigned int)*cp)) {
if (nw > 1)
return;
} else
break;
}
}
mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse,
nch->line, nch->pos + (lc - nch->string),
"%s%s %s", roff_name[tok],
nch == mdoc->last->child ? "" : " ...", nch->string);
}
static void
@ -555,7 +700,7 @@ post_bl_norm(POST_ARGS)
switch (n->norm->Bl.type) {
case LIST_tag:
if (NULL == n->norm->Bl.width)
if (n->norm->Bl.width == NULL)
mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
n->line, n->pos, "Bl -tag");
break;
@ -564,19 +709,20 @@ post_bl_norm(POST_ARGS)
case LIST_ohang:
case LIST_inset:
case LIST_item:
if (n->norm->Bl.width)
if (n->norm->Bl.width != NULL)
mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
wa->line, wa->pos, "Bl -%s",
mdoc_argnames[mdoclt]);
n->norm->Bl.width = NULL;
break;
case LIST_bullet:
case LIST_dash:
case LIST_hyphen:
if (NULL == n->norm->Bl.width)
if (n->norm->Bl.width == NULL)
n->norm->Bl.width = "2n";
break;
case LIST_enum:
if (NULL == n->norm->Bl.width)
if (n->norm->Bl.width == NULL)
n->norm->Bl.width = "3n";
break;
default:
@ -782,6 +928,8 @@ post_lb(POST_ARGS)
struct roff_node *n;
const char *p;
post_delim_nb(mdoc);
n = mdoc->last;
assert(n->child->type == ROFFT_TEXT);
mdoc->next = ROFF_NEXT_CHILD;
@ -851,6 +999,8 @@ post_std(POST_ARGS)
{
struct roff_node *n;
post_delim(mdoc);
n = mdoc->last;
if (n->args && n->args->argc == 1)
if (n->args->argv[0].arg == MDOC_Std)
@ -987,6 +1137,8 @@ post_fname(POST_ARGS)
if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
n->line, n->pos + pos, n->string);
if (n->sec == SEC_SYNOPSIS && mdoc->meta.msec != NULL)
mandoc_xr_add(mdoc->meta.msec, n->string, -1, -1);
}
static void
@ -1018,7 +1170,8 @@ post_fo(POST_ARGS)
"Fo ... %s", n->child->next->string);
while (n->child != n->last)
roff_node_delete(mdoc, n->last);
}
} else
post_delim(mdoc);
post_fname(mdoc);
}
@ -1042,6 +1195,7 @@ post_fa(POST_ARGS)
break;
}
}
post_delim_nb(mdoc);
}
static void
@ -1051,6 +1205,11 @@ post_nm(POST_ARGS)
n = mdoc->last;
if ((n->sec == SEC_NAME || n->sec == SEC_SYNOPSIS) &&
n->child != NULL && n->child->type == ROFFT_TEXT &&
mdoc->meta.msec != NULL)
mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1);
if (n->last != NULL &&
(n->last->tok == MDOC_Pp ||
n->last->tok == MDOC_Lp))
@ -1064,8 +1223,18 @@ post_nm(POST_ARGS)
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
n->line, n->pos, "Nm");
if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) ||
(n->child != NULL && n->child->type == ROFFT_TEXT) ||
switch (n->type) {
case ROFFT_ELEM:
post_delim_nb(mdoc);
break;
case ROFFT_HEAD:
post_delim(mdoc);
break;
default:
return;
}
if ((n->child != NULL && n->child->type == ROFFT_TEXT) ||
mdoc->meta.name == NULL)
return;
@ -1079,7 +1248,6 @@ static void
post_nd(POST_ARGS)
{
struct roff_node *n;
size_t sz;
n = mdoc->last;
@ -1093,11 +1261,8 @@ post_nd(POST_ARGS)
if (n->child == NULL)
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
n->line, n->pos, "Nd");
else if (n->last->type == ROFFT_TEXT &&
(sz = strlen(n->last->string)) != 0 &&
n->last->string[sz - 1] == '.')
mandoc_msg(MANDOCERR_ND_DOT, mdoc->parse,
n->last->line, n->last->pos + sz - 1, NULL);
else
post_delim(mdoc);
post_hyph(mdoc);
}
@ -1154,17 +1319,18 @@ post_defaults(POST_ARGS)
{
struct roff_node *nn;
if (mdoc->last->child != NULL) {
post_delim_nb(mdoc);
return;
}
/*
* The `Ar' defaults to "file ..." if no value is provided as an
* argument; the `Mt' and `Pa' macros use "~"; the `Li' just
* gets an empty string.
*/
if (mdoc->last->child != NULL)
return;
nn = mdoc->last;
switch (nn->tok) {
case MDOC_Ar:
mdoc->next = ROFF_NEXT_CHILD;
@ -1228,6 +1394,8 @@ post_an(POST_ARGS)
if (nch == NULL)
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
np->line, np->pos, "An");
else
post_delim_nb(mdoc);
} else if (nch != NULL)
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
nch->line, nch->pos, "An ... %s", nch->string);
@ -1255,6 +1423,9 @@ post_xx(POST_ARGS)
{
struct roff_node *n;
const char *os;
char *v;
post_delim_nb(mdoc);
n = mdoc->last;
switch (n->tok) {
@ -1269,6 +1440,20 @@ post_xx(POST_ARGS)
break;
case MDOC_Nx:
os = "NetBSD";
if (n->child == NULL)
break;
v = n->child->string;
if ((v[0] != '0' && v[0] != '1') || v[1] != '.' ||
v[2] < '0' || v[2] > '9' ||
v[3] < 'a' || v[3] > 'z' || v[4] != '\0')
break;
n->child->flags |= NODE_NOPRT;
mdoc->next = ROFF_NEXT_CHILD;
roff_word_alloc(mdoc, n->child->line, n->child->pos, v);
v = mdoc->last->string;
v[3] = toupper((unsigned char)v[3]);
mdoc->last->flags |= NODE_NOSRC;
mdoc->last = n;
break;
case MDOC_Ox:
os = "OpenBSD";
@ -1335,15 +1520,30 @@ post_it(POST_ARGS)
assert(nit->head->child == NULL);
i = 0;
for (nch = nit->child; nch != NULL; nch = nch->next)
if (nch->type == ROFFT_BODY)
i++;
if (nit->head->next->child == NULL &&
nit->head->next->next == NULL) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
nit->line, nit->pos, "It");
roff_node_delete(mdoc, nit);
break;
}
i = 0;
for (nch = nit->child; nch != NULL; nch = nch->next) {
if (nch->type != ROFFT_BODY)
continue;
if (i++ && nch->flags & NODE_LINE)
mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse,
nch->line, nch->pos, "Ta");
}
if (i < cols || i > cols + 1)
mandoc_vmsg(MANDOCERR_BL_COL,
mdoc->parse, nit->line, nit->pos,
"%d columns, %d cells", cols, i);
else if (nit->head->next->child != NULL &&
nit->head->next->child->line > nit->line)
mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse,
nit->line, nit->pos, "Bl -column It");
break;
default:
abort();
@ -1585,7 +1785,7 @@ post_bl(POST_ARGS)
nchild = nnext;
}
if (mdoc->meta.os_e != MDOC_OS_NETBSD)
if (mdoc->meta.os_e != MANDOC_OS_NETBSD)
return;
prev_Er = NULL;
@ -1604,11 +1804,12 @@ post_bl(POST_ARGS)
if (order > 0)
mandoc_vmsg(MANDOCERR_ER_ORDER,
mdoc->parse, nnext->line, nnext->pos,
"Er %s %s", prev_Er, nnext->string);
"Er %s %s (NetBSD)",
prev_Er, nnext->string);
else if (order == 0)
mandoc_vmsg(MANDOCERR_ER_REP,
mdoc->parse, nnext->line, nnext->pos,
"Er %s", prev_Er);
"Er %s (NetBSD)", prev_Er);
}
prev_Er = nnext->string;
}
@ -1661,14 +1862,35 @@ post_sm(POST_ARGS)
static void
post_root(POST_ARGS)
{
const char *openbsd_arch[] = {
"alpha", "amd64", "arm64", "armv7", "hppa", "i386",
"landisk", "loongson", "luna88k", "macppc", "mips64",
"octeon", "sgi", "socppc", "sparc64", NULL
};
const char *netbsd_arch[] = {
"acorn26", "acorn32", "algor", "alpha", "amiga",
"arc", "atari",
"bebox", "cats", "cesfic", "cobalt", "dreamcast",
"emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5",
"hp300", "hpcarm", "hpcmips", "hpcsh", "hppa",
"i386", "ibmnws", "luna68k",
"mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc",
"netwinder", "news68k", "newsmips", "next68k",
"pc532", "playstation2", "pmax", "pmppc", "prep",
"sandpoint", "sbmips", "sgimips", "shark",
"sparc", "sparc64", "sun2", "sun3",
"vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL
};
const char **arches[] = { NULL, netbsd_arch, openbsd_arch };
struct roff_node *n;
const char **arch;
/* Add missing prologue data. */
if (mdoc->meta.date == NULL)
mdoc->meta.date = mdoc->quick ?
mandoc_strdup("") :
mandoc_normdate(mdoc->parse, NULL, 0, 0);
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
mandoc_normdate(mdoc, NULL, 0, 0);
if (mdoc->meta.title == NULL) {
mandoc_msg(MANDOCERR_DT_NOTITLE,
@ -1683,6 +1905,27 @@ post_root(POST_ARGS)
mandoc_msg(MANDOCERR_OS_MISSING,
mdoc->parse, 0, 0, NULL);
mdoc->meta.os = mandoc_strdup("");
} else if (mdoc->meta.os_e &&
(mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0)
mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0,
mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
"(OpenBSD)" : "(NetBSD)");
if (mdoc->meta.arch != NULL &&
(arch = arches[mdoc->meta.os_e]) != NULL) {
while (*arch != NULL && strcmp(*arch, mdoc->meta.arch))
arch++;
if (*arch == NULL) {
n = mdoc->first->child;
while (n->tok != MDOC_Dt)
n = n->next;
n = n->child->next->next;
mandoc_vmsg(MANDOCERR_ARCH_BAD,
mdoc->parse, n->line, n->pos,
"Dt ... %s %s", mdoc->meta.arch,
mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
"(OpenBSD)" : "(NetBSD)");
}
}
/* Check that we begin with a proper `Sh'. */
@ -1815,10 +2058,20 @@ post_hyph(POST_ARGS)
static void
post_ns(POST_ARGS)
{
struct roff_node *n;
if (mdoc->last->flags & NODE_LINE)
n = mdoc->last;
if (n->flags & NODE_LINE ||
(n->next != NULL && n->next->flags & NODE_DELIMC))
mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
mdoc->last->line, mdoc->last->pos, NULL);
n->line, n->pos, NULL);
}
static void
post_sx(POST_ARGS)
{
post_delim(mdoc);
post_hyph(mdoc);
}
static void
@ -1981,11 +2234,54 @@ post_sh_authors(POST_ARGS)
mdoc->last->line, mdoc->last->pos, NULL);
}
/*
* Return an upper bound for the string distance (allowing
* transpositions). Not a full Levenshtein implementation
* because Levenshtein is quadratic in the string length
* and this function is called for every standard name,
* so the check for each custom name would be cubic.
* The following crude heuristics is linear, resulting
* in quadratic behaviour for checking one custom name,
* which does not cause measurable slowdown.
*/
static int
similar(const char *s1, const char *s2)
{
const int maxdist = 3;
int dist = 0;
while (s1[0] != '\0' && s2[0] != '\0') {
if (s1[0] == s2[0]) {
s1++;
s2++;
continue;
}
if (++dist > maxdist)
return INT_MAX;
if (s1[1] == s2[1]) { /* replacement */
s1++;
s2++;
} else if (s1[0] == s2[1] && s1[1] == s2[0]) {
s1 += 2; /* transposition */
s2 += 2;
} else if (s1[0] == s2[1]) /* insertion */
s2++;
else if (s1[1] == s2[0]) /* deletion */
s1++;
else
return INT_MAX;
}
dist += strlen(s1) + strlen(s2);
return dist > maxdist ? INT_MAX : dist;
}
static void
post_sh_head(POST_ARGS)
{
struct roff_node *nch;
const char *goodsec;
const char *const *testsec;
int dist, mindist;
enum roff_sec sec;
/*
@ -2023,8 +2319,25 @@ post_sh_head(POST_ARGS)
/* We don't care about custom sections after this. */
if (sec == SEC_CUSTOM)
if (sec == SEC_CUSTOM) {
if ((nch = mdoc->last->child) == NULL ||
nch->type != ROFFT_TEXT || nch->next != NULL)
return;
goodsec = NULL;
mindist = INT_MAX;
for (testsec = secnames + 1; *testsec != NULL; testsec++) {
dist = similar(nch->string, *testsec);
if (dist < mindist) {
goodsec = *testsec;
mindist = dist;
}
}
if (goodsec != NULL)
mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse,
nch->line, nch->pos, "Sh %s instead of %s",
nch->string, goodsec);
return;
}
/*
* Check whether our non-custom section is being repeated or is
@ -2090,9 +2403,15 @@ post_xr(POST_ARGS)
if (nch->next == NULL) {
mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse,
n->line, n->pos, "Xr %s", nch->string);
return;
} else {
assert(nch->next == n->last);
if(mandoc_xr_add(nch->next->string, nch->string,
nch->line, nch->pos))
mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse,
nch->line, nch->pos, "Xr %s %s",
nch->string, nch->next->string);
}
assert(nch->next == n->last);
post_delim_nb(mdoc);
}
static void
@ -2105,6 +2424,7 @@ post_ignpar(POST_ARGS)
post_prevpar(mdoc);
return;
case ROFFT_HEAD:
post_delim(mdoc);
post_hyph(mdoc);
return;
case ROFFT_BODY:
@ -2224,7 +2544,7 @@ post_dd(POST_ARGS)
if (n->child == NULL || n->child->string[0] == '\0') {
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
mandoc_normdate(mdoc, NULL, n->line, n->pos);
return;
}
@ -2233,7 +2553,7 @@ post_dd(POST_ARGS)
if (mdoc->quick)
mdoc->meta.date = datestr;
else {
mdoc->meta.date = mandoc_normdate(mdoc->parse,
mdoc->meta.date = mandoc_normdate(mdoc,
datestr, n->line, n->pos);
free(datestr);
}
@ -2341,6 +2661,8 @@ post_bx(POST_ARGS)
struct roff_node *n, *nch;
const char *macro;
post_delim_nb(mdoc);
n = mdoc->last;
nch = n->child;
@ -2405,6 +2727,8 @@ post_os(POST_ARGS)
mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
n->line, n->pos, "Os");
post_delim(mdoc);
/*
* Set the operating system by way of the `Os' macro.
* The order of precedence is:
@ -2420,8 +2744,8 @@ post_os(POST_ARGS)
if (mdoc->meta.os)
goto out;
if (mdoc->defos) {
mdoc->meta.os = mandoc_strdup(mdoc->defos);
if (mdoc->os_s != NULL) {
mdoc->meta.os = mandoc_strdup(mdoc->os_s);
goto out;
}
@ -2440,9 +2764,43 @@ post_os(POST_ARGS)
mdoc->meta.os = mandoc_strdup(defbuf);
#endif /*!OSNAME*/
out: mdoc->meta.os_e = strstr(mdoc->meta.os, "OpenBSD") != NULL ?
MDOC_OS_OPENBSD : strstr(mdoc->meta.os, "NetBSD") != NULL ?
MDOC_OS_NETBSD : MDOC_OS_OTHER;
out:
if (mdoc->meta.os_e == MANDOC_OS_OTHER) {
if (strstr(mdoc->meta.os, "OpenBSD") != NULL)
mdoc->meta.os_e = MANDOC_OS_OPENBSD;
else if (strstr(mdoc->meta.os, "NetBSD") != NULL)
mdoc->meta.os_e = MANDOC_OS_NETBSD;
}
/*
* This is the earliest point where we can check
* Mdocdate conventions because we don't know
* the operating system earlier.
*/
if (n->child != NULL)
mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse,
n->child->line, n->child->pos,
"Os %s (%s)", n->child->string,
mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
"OpenBSD" : "NetBSD");
while (n->tok != MDOC_Dd)
if ((n = n->prev) == NULL)
return;
if ((n = n->child) == NULL)
return;
if (strncmp(n->string, "$" "Mdocdate", 9)) {
if (mdoc->meta.os_e == MANDOC_OS_OPENBSD)
mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING,
mdoc->parse, n->line, n->pos,
"Dd %s (OpenBSD)", n->string);
} else {
if (mdoc->meta.os_e == MANDOC_OS_NETBSD)
mandoc_vmsg(MANDOCERR_MDOCDATE,
mdoc->parse, n->line, n->pos,
"Dd %s (NetBSD)", n->string);
}
}
enum roff_sec

View File

@ -1,4 +1,4 @@
/* $Id: msec.in,v 1.7 2014/08/26 11:21:40 schwarze Exp $ */
/* $Id: msec.in,v 1.8 2017/06/24 17:37:06 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -32,9 +32,3 @@ LINE("6", "Games Manual")
LINE("7", "Miscellaneous Information Manual")
LINE("8", "System Manager\'s Manual")
LINE("9", "Kernel Developer\'s Manual")
LINE("X11", "X11 Developer\'s Manual")
LINE("X11R6", "X11 Developer\'s Manual")
LINE("unass", "Unassociated")
LINE("local", "Local")
LINE("draft", "Draft")
LINE("paper", "Paper")

48
out.c
View File

@ -1,4 +1,4 @@
/* $Id: out.c,v 1.65 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -20,6 +20,7 @@
#include <sys/types.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -85,10 +86,8 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
case 'v':
dst->unit = SCALE_VS;
break;
case '\0':
endptr--;
/* FALLTHROUGH */
default:
endptr--;
if (SCALE_MAX == def)
return NULL;
dst->unit = def;
@ -105,7 +104,7 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
*/
void
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
size_t totalwidth)
size_t offset, size_t rmargin)
{
struct roffsu su;
const struct tbl_opts *opts;
@ -142,8 +141,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
if (1 < spans)
continue;
icol = dp->layout->col;
if (maxcol < icol)
maxcol = icol;
while (maxcol < icol)
tbl->cols[++maxcol].spacing = SIZE_MAX;
col = tbl->cols + icol;
col->flags |= dp->layout->flags;
if (dp->layout->flags & TBL_CELL_WIGN)
@ -156,8 +155,15 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
(*tbl->sulen)(&su, tbl->arg);
if (col->width < dp->layout->width)
col->width = dp->layout->width;
tblcalc_data(tbl, col, opts, dp, dp->block ?
totalwidth / (sp->opts->cols + 1) : 0);
if (dp->layout->spacing != SIZE_MAX &&
(col->spacing == SIZE_MAX ||
col->spacing < dp->layout->spacing))
col->spacing = dp->layout->spacing;
tblcalc_data(tbl, col, opts, dp,
dp->block == 0 ? 0 :
dp->layout->width ? dp->layout->width :
rmargin ? (rmargin + sp->opts->cols / 2)
/ (sp->opts->cols + 1) : 0);
}
}
@ -171,6 +177,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
ewidth = xwidth = 0;
for (icol = 0; icol <= maxcol; icol++) {
col = tbl->cols + icol;
if (col->spacing == SIZE_MAX || icol == maxcol)
col->spacing = 3;
if (col->flags & TBL_CELL_EQUAL) {
necol++;
if (ewidth < col->width)
@ -194,7 +202,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
continue;
if (col->width == ewidth)
continue;
if (nxcol && totalwidth)
if (nxcol && rmargin)
xwidth += ewidth - col->width;
col->width = ewidth;
}
@ -206,13 +214,13 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
* Distribute the available width evenly.
*/
if (nxcol && totalwidth) {
if (nxcol && rmargin) {
xwidth += 3*maxcol +
(opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
2 : !!opts->lvert + !!opts->rvert);
if (xwidth >= totalwidth)
if (rmargin <= offset + xwidth)
return;
xwidth = totalwidth - xwidth;
xwidth = rmargin - offset - xwidth;
/*
* Emulate a bug in GNU tbl width calculation that
@ -281,11 +289,13 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
const char *str; /* Beginning of the first line. */
const char *beg; /* Beginning of the current line. */
char *end; /* End of the current line. */
size_t sz; /* Length of the current line. */
size_t lsz; /* Length of the current line. */
size_t wsz; /* Length of the current word. */
if (dp->string == NULL || *dp->string == '\0')
return;
str = mw ? mandoc_strdup(dp->string) : dp->string;
lsz = 0;
for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
end = mw ? strchr(beg, ' ') : NULL;
if (end != NULL) {
@ -293,9 +303,13 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
while (*end == ' ')
end++;
}
sz = (*tbl->slen)(beg, tbl->arg);
if (col->width < sz)
col->width = sz;
wsz = (*tbl->slen)(beg, tbl->arg);
if (mw && lsz && lsz + 1 + wsz <= mw)
lsz += 1 + wsz;
else
lsz = wsz;
if (col->width < lsz)
col->width = lsz;
}
if (mw)
free((void *)str);

5
out.h
View File

@ -1,4 +1,4 @@
/* $Id: out.h,v 1.29 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: out.h,v 1.31 2017/06/27 18:25:02 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -33,6 +33,7 @@ enum roffscale {
struct roffcol {
size_t width; /* width of cell */
size_t decimal; /* decimal position in cell */
size_t spacing; /* spacing after the column */
int flags; /* layout flags, see tbl_cell */
};
@ -68,4 +69,4 @@ struct tbl_span;
const char *a2roffsu(const char *, struct roffsu *, enum roffscale);
void tblcalc(struct rofftbl *tbl,
const struct tbl_span *, size_t);
const struct tbl_span *, size_t, size_t);

103
read.c
View File

@ -1,4 +1,4 @@
/* $Id: read.c,v 1.173 2017/06/08 00:23:30 schwarze Exp $ */
/* $Id: read.c,v 1.192 2017/07/20 14:36:36 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -24,9 +24,6 @@
#include <assert.h>
#include <ctype.h>
#if HAVE_ERR
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@ -42,7 +39,6 @@
#include "mdoc.h"
#include "man.h"
#include "libmandoc.h"
#include "roff_int.h"
#define REPARSE_LIMIT 1000
@ -53,10 +49,10 @@ struct mparse {
const char *file; /* filename of current input file */
struct buf *primary; /* buffer currently being parsed */
struct buf *secondary; /* preprocessed copy of input */
const char *defos; /* default operating system */
const char *os_s; /* default operating system */
mandocmsg mmsg; /* warning/error message handler */
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
enum mandocerr mmin; /* ignore messages below this */
int options; /* parser options */
int gzip; /* current input file is gzipped */
int filenc; /* encoding of the current file */
@ -75,7 +71,7 @@ static void mparse_parse_buffer(struct mparse *, struct buf,
static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
MANDOCERR_OK,
MANDOCERR_STYLE,
MANDOCERR_OK,
MANDOCERR_WARNING,
MANDOCERR_ERROR,
MANDOCERR_UNSUPP,
@ -86,28 +82,46 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
static const char * const mandocerrs[MANDOCERR_MAX] = {
"ok",
"base system convention",
"Mdocdate found",
"Mdocdate missing",
"unknown architecture",
"operating system explicitly specified",
"RCS id missing",
"referenced manual not found",
"generic style suggestion",
"legacy man(7) date format",
"lower case character in document title",
"duplicate RCS id",
"typo in section name",
"unterminated quoted argument",
"useless macro",
"consider using OS macro",
"errnos out of order",
"duplicate errno",
"description line ends with a full stop",
"trailing delimiter",
"no blank before trailing delimiter",
"fill mode already enabled, skipping",
"fill mode already disabled, skipping",
"function name without markup",
"whitespace at end of input line",
"bad comment style",
"generic warning",
/* related to the prologue */
"missing manual title, using UNTITLED",
"missing manual title, using \"\"",
"lower case character in document title",
"missing manual section, using \"\"",
"unknown manual section",
"missing date, using today's date",
"cannot parse date, using it verbatim",
"date in the future, using it anyway",
"missing Os macro, using \"\"",
"duplicate prologue macro",
"late prologue macro",
"skipping late title macro",
"prologue macros out of order",
/* related to document structure */
@ -125,6 +139,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"sections out of conventional order",
"duplicate section title",
"unexpected section",
"cross reference to self",
"unusual Xr order",
"unusual Xr punctuation",
"AUTHORS section without An macro",
@ -138,8 +153,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"blocks badly nested",
"nested displays are not portable",
"moving content out of list",
"fill mode already enabled, skipping",
"fill mode already disabled, skipping",
"first macro on line",
"line scope broken",
"skipping blank line in line scope",
@ -156,6 +170,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"missing function name, using \"\"",
"empty head in list item",
"empty list item",
"missing argument, using next line",
"missing font type, using \\fR",
"unknown font type, using \\fR",
"nothing follows prefix",
@ -167,7 +182,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"missing eqn box, using \"\"",
/* related to bad macro arguments */
"unterminated quoted argument",
"duplicate argument",
"skipping duplicate argument",
"skipping duplicate display type",
@ -186,9 +200,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
/* related to plain text */
"blank line in fill mode, using .sp",
"tab in filled text",
"whitespace at end of input line",
"new sentence, new line",
"bad comment style",
"invalid escape sequence",
"undefined string, using \"\"",
@ -214,6 +226,8 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
/* related to document structure and macros */
NULL,
"duplicate prologue macro",
"skipping late title macro",
"input stack limit exceeded, infinite loop?",
"skipping bad character",
"skipping unknown macro",
@ -325,7 +339,6 @@ choose_parser(struct mparse *curp)
static int
mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
const struct tbl_span *span;
struct buf ln;
const char *save_file;
char *cp;
@ -516,21 +529,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
if (curp->man->macroset == MACROSET_NONE)
choose_parser(curp);
/*
* Lastly, push down into the parsers themselves.
* If libroff returns ROFF_TBL, then add it to the
* currently open parse. Since we only get here if
* there does exist data (see tbl_data.c), we're
* guaranteed that something's been allocated.
* Do the same for ROFF_EQN.
*/
if (rr == ROFF_TBL)
while ((span = roff_span(curp->roff)) != NULL)
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 ?
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;
@ -558,8 +557,11 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
size_t off;
ssize_t ssz;
if (fstat(fd, &st) == -1)
err((int)MANDOCLEVEL_SYSERR, "%s", file);
if (fstat(fd, &st) == -1) {
mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
"fstat: %s", strerror(errno));
return 0;
}
/*
* If we're a regular file, try just reading in the whole entry
@ -581,8 +583,11 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
if (curp->gzip) {
if ((gz = gzdopen(fd, "rb")) == NULL)
err((int)MANDOCLEVEL_SYSERR, "%s", file);
if ((gz = gzdopen(fd, "rb")) == NULL) {
mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
"gzdopen: %s", strerror(errno));
return 0;
}
} else
gz = NULL;
@ -611,8 +616,11 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
fb->sz = off;
return 1;
}
if (ssz == -1)
err((int)MANDOCLEVEL_SYSERR, "%s", file);
if (ssz == -1) {
mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
"read: %s", strerror(errno));
break;
}
off += (size_t)ssz;
}
@ -748,20 +756,20 @@ mparse_open(struct mparse *curp, const char *file)
}
struct mparse *
mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
const char *defos)
mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg,
enum mandoc_os os_e, const char *os_s)
{
struct mparse *curp;
curp = mandoc_calloc(1, sizeof(struct mparse));
curp->options = options;
curp->wlevel = wlevel;
curp->mmin = mmin;
curp->mmsg = mmsg;
curp->defos = defos;
curp->os_s = os_s;
curp->roff = roff_alloc(curp, options);
curp->man = roff_man_alloc( curp->roff, curp, curp->defos,
curp->man = roff_man_alloc(curp->roff, curp, curp->os_s,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MDOC) {
curp->man->macroset = MACROSET_MDOC;
@ -773,6 +781,7 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
}
curp->man->first->tok = TOKEN_NONE;
curp->man->meta.os_e = os_e;
return curp;
}
@ -848,13 +857,13 @@ mandoc_msg(enum mandocerr er, struct mparse *m,
{
enum mandoclevel level;
if (er < m->mmin && er != MANDOCERR_FILE)
return;
level = MANDOCLEVEL_UNSUPP;
while (er < mandoclimits[level])
level--;
if (level < m->wlevel && er != MANDOCERR_FILE)
return;
if (m->mmsg)
(*m->mmsg)(er, level, m->file, ln, col, msg);

70
roff.7
View File

@ -1,4 +1,4 @@
.\" $Id: roff.7,v 1.86 2017/06/07 00:50:34 schwarze Exp $
.\" $Id: roff.7,v 1.94 2017/07/05 12:25:17 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010,2011,2013-2015,2017 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: June 7 2017 $
.Dd $Mdocdate: July 5 2017 $
.Dt ROFF 7
.Os
.Sh NAME
@ -180,7 +180,7 @@ single-character
two-character
.Sq \e*(XX ,
and N-character
.Sq \e*[N] .
.Sq \e* Ns Bq N .
.Pp
Examples:
.Bl -tag -width Ds -offset indent -compact
@ -412,7 +412,6 @@ Create an alias for a number register.
Currently unsupported.
.It Ic \&als Ar newname oldname
Create an alias for a request, string, macro, or diversion.
Currently unsupported.
.It Ic \&am Ar macroname Op Ar endmacro
Append to a macro definition.
The syntax of this request is the same as that of
@ -1045,8 +1044,6 @@ If the first character of
is
.Sq c
.Pq character available ,
.Sq d
.Pq string defined ,
.Sq e
.Pq even page ,
.Sq t
@ -1059,6 +1056,15 @@ it evaluates to false.
If the first character of
.Ar condition
is
.Sq d ,
it evaluates to true if the rest of
.Ar condition
is the name of an existing user defined macro or string;
otherwise, it evaluates to false.
.It
If the first character of
.Ar condition
is
.Sq r ,
it evaluates to true if the rest of
.Ar condition
@ -1435,8 +1441,15 @@ Currently ignored.
Print all number registers on standard error output.
Currently ignored.
.It Ic \&po Op Oo Cm + Ns | Ns Cm - Oc Ns Ar offset
Set horizontal page offset.
Currently ignored.
Set a horizontal page offset.
If no argument is specified, the page offset is reverted to its
previous value.
If a sign is specified, the new page offset is calculated relative
to the current one; otherwise, it is absolute.
The argument follows the syntax of
.Sx Scaling Widths
and the default scaling unit is
.Cm m .
.It Ic \&ps Op Oo Cm + Ns | Ns Cm - Oc Ns size
Change point size.
Currently ignored.
@ -1477,7 +1490,9 @@ This is a Heirloom extension and currently ignored.
Justify the next
.Ar N
input lines to the right margin without filling.
Currently ignored.
.Ar N
defaults to 1.
An argument of 0 or less ends right adjustment.
.It Ic \&rm Ar macroname
Remove a request, macro or string.
.It Ic \&rn Ar oldname newname
@ -1783,7 +1798,7 @@ logical and (corresponds to C
.Ic && )
.It Ic \&:
logical or (corresponds to C
.Ic \&|| )
.Ic || )
.It Ic <?
minimum (not available in C)
.It Ic >?
@ -1839,7 +1854,7 @@ instead.
.Sx Special Characters
with two-letter names, see
.Xr mandoc_char 7 .
.Ss \e*[ Ns Ar name ]
.Ss \e* Ns Bq Ar name
Interpolate the string with the
.Ar name ;
see
@ -1859,7 +1874,7 @@ Special character
.Ss \e/
Right italic correction (groff extension); ignored by
.Xr mandoc 1 .
.Ss \e[ Ns Ar name ]
.Ss \e Ns Bq Ar name
.Sx Special Characters
with names of arbitrary length, see
.Xr mandoc_char 7 .
@ -1915,14 +1930,14 @@ Move down by half a line; ignored by
.Xr mandoc 1 .
.Ss \ee
Backslash special character.
.Ss \eF[ Ns Ar name ]
.Ss \eF Ns Bq Ar name
Switch font family (groff extension); ignored by
.Xr mandoc 1 .
For short names, there are variants
.No \eF Ns Ar c
and
.No \eF( Ns Ar cc .
.Ss \ef[ Ns Ar name ]
.Ss \ef Ns Bq Ar name
Switch to the font
.Ar name ,
see
@ -1931,7 +1946,7 @@ For short names, there are variants
.No \ef Ns Ar c
and
.No \ef( Ns Ar cc .
.Ss \eg[ Ns Ar name ]
.Ss \eg Ns Bq Ar name
Interpolate the format of a number register; ignored by
.Xr mandoc 1 .
For short names, there are variants
@ -1941,11 +1956,14 @@ and
.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
Set the height of the current font; ignored by
.Xr mandoc 1 .
.Ss \eh\(aq Ns Ar width Ns \(aq
Horizontal motion relative to the current position.
.Ss \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns \(aq
Horizontal motion.
If the vertical bar is given, the motion is relative to the current
indentation.
Otherwise, it is relative to the current position.
The default scaling unit is
.Cm m .
.Ss \ek[ Ns Ar name ]
.Ss \ek Ns Bq Ar name
Mark horizontal input place in register; ignored by
.Xr mandoc 1 .
For short names, there are variants
@ -1960,14 +1978,14 @@ Draw a horizontal line of
.Ar width
using the glyph
.Ar c .
.Ss \eM[ Ns Ar name ]
.Ss \eM Ns Bq Ar name
Set fill (background) color (groff extension); ignored by
.Xr mandoc 1 .
For short names, there are variants
.No \eM Ns Ar c
and
.No \eM( Ns Ar cc .
.Ss \em[ Ns Ar name ]
.Ss \em Ns Bq Ar name
Set glyph drawing color (groff extension); ignored by
.Xr mandoc 1 .
For short names, there are variants
@ -1978,7 +1996,7 @@ and
Character
.Ar number
on the current font.
.Ss \en[ Ns Ar name ]
.Ss \en Ns Bq Ar name
Interpolate the number register
.Ar name .
For short names, there are variants
@ -1991,6 +2009,8 @@ Overstrike, writing all the characters contained in the
to the same output position.
In terminal and HTML output modes,
only the last one of the characters is visible.
.Ss \ep
Break the output line at the end of the current word.
.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq
Set number register; ignored by
.Xr mandoc 1 .
@ -2003,9 +2023,9 @@ Change point size; ignored by
Alternative forms
.No \es Ns Oo +|- Oc Ns Ar n ,
.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq ,
.No \es Ns [ Oo +|- Oc Ns Ar number ] ,
.No \es Ns Bq Oo +|- Oc Ns Ar number ,
and
.No \es Ns Oo +|- Oc Ns [ Ar number Ns ]
.No \es Ns Oo +|- Oc Ns Bq Ar number
are also parsed and ignored.
.Ss \et
Horizontal tab; ignored by
@ -2013,7 +2033,7 @@ Horizontal tab; ignored by
.Ss \eu
Move up by half a line; ignored by
.Xr mandoc 1 .
.Ss \eV[ Ns Ar name ]
.Ss \eV Ns Bq Ar name
Interpolate an environment variable; ignored by
.Xr mandoc 1 .
For short names, there are variants
@ -2040,7 +2060,7 @@ as device control function; ignored in nroff mode and by
.Ss \ex\(aq Ns Ar number Ns \(aq
Extra line space function; ignored by
.Xr mandoc 1 .
.Ss \eY[ Ns Ar name ]
.Ss \eY Ns Bq Ar name
Output a string as a device control function; ignored in nroff mode and by
.Xr mandoc 1 .
For short names, there are variants

619
roff.c

File diff suppressed because it is too large Load Diff

21
roff.h
View File

@ -1,4 +1,4 @@
/* $Id: roff.h,v 1.52 2017/06/07 23:29:49 schwarze Exp $ */
/* $Id: roff.h,v 1.58 2017/07/08 14:51:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -26,12 +26,6 @@ enum roff_macroset {
MACROSET_MAN
};
enum mdoc_os {
MDOC_OS_OTHER = 0,
MDOC_OS_NETBSD,
MDOC_OS_OPENBSD
};
enum roff_sec {
SEC_NONE = 0,
SEC_NAME,
@ -77,6 +71,8 @@ enum roff_tok {
ROFF_ft,
ROFF_ll,
ROFF_mc,
ROFF_po,
ROFF_rj,
ROFF_sp,
ROFF_ta,
ROFF_ti,
@ -244,7 +240,6 @@ enum roff_tok {
ROFF_pm,
ROFF_pn,
ROFF_pnr,
ROFF_po,
ROFF_ps,
ROFF_psbb,
ROFF_pshape,
@ -257,7 +252,6 @@ enum roff_tok {
ROFF_return,
ROFF_rfschar,
ROFF_rhang,
ROFF_rj,
ROFF_rm,
ROFF_rn,
ROFF_rnn,
@ -473,6 +467,8 @@ enum roff_tok {
MAN_EE,
MAN_UR,
MAN_UE,
MAN_MT,
MAN_ME,
MAN_MAX
};
@ -503,7 +499,7 @@ struct roff_node {
union mdoc_data *norm; /* Normalized arguments. */
char *string; /* TEXT */
const struct tbl_span *span; /* TBL */
const struct eqn *eqn; /* EQN */
struct eqn_box *eqn; /* EQN */
int line; /* Input file line number. */
int pos; /* Input file column number. */
int flags;
@ -534,7 +530,8 @@ struct roff_meta {
char *name; /* Leading manual name. */
char *date; /* Normalized date. */
int hasbody; /* Document is not empty. */
enum mdoc_os os_e; /* Operating system. */
int rcsids; /* Bits indexed by enum mandoc_os. */
enum mandoc_os os_e; /* Operating system. */
};
struct roff_man {
@ -543,7 +540,7 @@ struct roff_man {
struct roff *roff; /* Roff parser state data. */
struct ohash *mdocmac; /* Mdoc macro lookup table. */
struct ohash *manmac; /* Man macro lookup table. */
const char *defos; /* Default operating system. */
const char *os_s; /* 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. */

View File

@ -1,4 +1,4 @@
/* $Id: roff_html.c,v 1.8 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: roff_html.c,v 1.11 2017/06/24 14:38:33 schwarze Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -20,6 +20,7 @@
#include <assert.h>
#include <stddef.h>
#include "mandoc.h"
#include "roff.h"
#include "out.h"
#include "html.h"
@ -38,6 +39,8 @@ static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = {
NULL, /* ft */
NULL, /* ll */
NULL, /* mc */
NULL, /* po */
roff_html_pre_ce, /* rj */
roff_html_pre_sp, /* sp */
NULL, /* ta */
NULL, /* ti */

View File

@ -1,4 +1,4 @@
/* $Id: roff_int.h,v 1.7 2015/11/07 14:01:16 schwarze Exp $ */
/* $Id: roff_int.h,v 1.9 2017/07/08 17:52:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -25,8 +25,6 @@ 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 *);

View File

@ -1,4 +1,4 @@
/* $Id: roff_term.c,v 1.10 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
/*
* Copyright (c) 2010, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@ -19,6 +19,7 @@
#include <assert.h>
#include <stddef.h>
#include "mandoc.h"
#include "roff.h"
#include "out.h"
#include "term.h"
@ -32,6 +33,7 @@ static void roff_term_pre_ce(ROFF_TERM_ARGS);
static void roff_term_pre_ft(ROFF_TERM_ARGS);
static void roff_term_pre_ll(ROFF_TERM_ARGS);
static void roff_term_pre_mc(ROFF_TERM_ARGS);
static void roff_term_pre_po(ROFF_TERM_ARGS);
static void roff_term_pre_sp(ROFF_TERM_ARGS);
static void roff_term_pre_ta(ROFF_TERM_ARGS);
static void roff_term_pre_ti(ROFF_TERM_ARGS);
@ -42,6 +44,8 @@ static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
roff_term_pre_ft, /* ft */
roff_term_pre_ll, /* ll */
roff_term_pre_mc, /* mc */
roff_term_pre_po, /* po */
roff_term_pre_ce, /* rj */
roff_term_pre_sp, /* sp */
roff_term_pre_ta, /* ta */
roff_term_pre_ti, /* ti */
@ -69,33 +73,34 @@ roff_term_pre_br(ROFF_TERM_ARGS)
static void
roff_term_pre_ce(ROFF_TERM_ARGS)
{
const struct roff_node *nch;
const struct roff_node *nc1, *nc2;
size_t len, lm;
roff_term_pre_br(p, n);
lm = p->tcol->offset;
n = n->child->next;
while (n != NULL) {
nch = n;
nc1 = n->child->next;
while (nc1 != NULL) {
nc2 = nc1;
len = 0;
do {
if (n->type == ROFFT_TEXT) {
if (nc2->type == ROFFT_TEXT) {
if (len)
len++;
len += term_strlen(p, nch->string);
len += term_strlen(p, nc2->string);
}
nch = nch->next;
} while (nch != NULL && (n->type != ROFFT_TEXT ||
(n->flags & NODE_LINE) == 0));
nc2 = nc2->next;
} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
(nc2->flags & NODE_LINE) == 0));
p->tcol->offset = len >= p->tcol->rmargin ? 0 :
lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
n->tok == ROFF_rj ? p->tcol->rmargin - len :
(lm + p->tcol->rmargin - len) / 2;
while (n != nch) {
if (n->type == ROFFT_TEXT)
term_word(p, n->string);
while (nc1 != nc2) {
if (nc1->type == ROFFT_TEXT)
term_word(p, nc1->string);
else
roff_term_pre(p, n);
n = n->next;
roff_term_pre(p, nc1);
nc1 = nc1->next;
}
p->flags |= TERMP_NOSPACE;
term_flushln(p);
@ -150,6 +155,28 @@ roff_term_pre_mc(ROFF_TERM_ARGS)
p->flags |= TERMP_ENDMC;
}
static void
roff_term_pre_po(ROFF_TERM_ARGS)
{
struct roffsu su;
static int po, polast;
int ponew;
if (n->child != NULL &&
a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
ponew = term_hen(p, &su);
if (*n->child->string == '+' ||
*n->child->string == '-')
ponew += po;
} else
ponew = polast;
polast = po;
po = ponew;
ponew = po - polast + (int)p->tcol->offset;
p->tcol->offset = ponew > 0 ? ponew : 0;
}
static void
roff_term_pre_sp(ROFF_TERM_ARGS)
{
@ -203,7 +230,7 @@ roff_term_pre_ti(ROFF_TERM_ARGS)
if (a2roffsu(cp, &su, SCALE_EM) == NULL)
return;
len = term_hspan(p, &su) / 24;
len = term_hen(p, &su);
if (sign == 0) {
p->ti = len - p->tcol->offset;

View File

@ -1,4 +1,4 @@
/* $Id: roff_validate.c,v 1.7 2017/06/06 15:01:04 schwarze Exp $ */
/* $Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */
/*
* Copyright (c) 2010, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@ -36,6 +36,8 @@ static const roff_valid_fp roff_valids[ROFF_MAX] = {
roff_valid_ft, /* ft */
NULL, /* ll */
NULL, /* mc */
NULL, /* po */
NULL, /* rj */
NULL, /* sp */
NULL, /* ta */
NULL, /* ti */

View File

@ -1,4 +1,4 @@
.\" $Id: soelim.1,v 1.4 2017/03/18 19:56:01 schwarze Exp $
.\" $Id: soelim.1,v 1.5 2017/07/04 23:40:01 schwarze Exp $
.\"
.\" Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
.\" All rights reserved.
@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd $Mdocdate: March 18 2017 $
.Dd $Mdocdate: July 4 2017 $
.Dt SOELIM 1
.Os
.Sh NAME
@ -53,15 +53,15 @@ Recognise
when not followed by a space character.
.It Fl r
Compatibility with GNU groff's
.Xr soelim 1
.Nm soelim
(does nothing).
.It Fl t
Compatibility with GNU groff's
.Xr soelim 1
.Nm soelim
(does nothing).
.It Fl v
Compatibility with GNU groff's
.Xr soelim 1
.Nm soelim
(does nothing).
.It Fl I Ar dir
This option specify directories where

3
st.c
View File

@ -1,4 +1,4 @@
/* $Id: st.c,v 1.13 2015/10/06 18:32:20 schwarze Exp $ */
/* $Id: st.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -20,6 +20,7 @@
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"

3
st.in
View File

@ -1,4 +1,4 @@
/* $Id: st.in,v 1.28 2015/02/17 20:37:17 schwarze Exp $ */
/* $Id: st.in,v 1.29 2017/06/24 13:49:29 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -34,7 +34,6 @@ LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(LqPOSIX.1\\(Rq)")
LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(LqPOSIX.1\\(Rq)")
LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(LqPOSIX.1\\(Rq)")
LINE("-p1003.1-2013", "IEEE Std 1003.1-2008/Cor 1-2013 (\\(LqPOSIX.1\\(Rq)")
LINE("-p1003.1", "IEEE Std 1003.1 (\\(LqPOSIX.1\\(Rq)")
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(LqPOSIX.1b\\(Rq)")
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(LqPOSIX.1b\\(Rq)")

440
tbl.7
View File

@ -1,4 +1,4 @@
.\" $Id: tbl.7,v 1.27 2017/06/08 18:11:22 schwarze Exp $
.\" $Id: tbl.7,v 1.28 2017/06/28 00:59:57 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2014, 2015, 2017 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: June 8 2017 $
.Dd $Mdocdate: June 28 2017 $
.Dt TBL 7
.Os
.Sh NAME
@ -24,128 +24,43 @@
.Sh DESCRIPTION
The
.Nm tbl
language is a table-formatting language.
language formats tables.
It is used within
.Xr mdoc 7
and
.Xr man 7
.Ux
manual pages.
pages.
This manual describes the subset of the
.Nm
language accepted by the
.Xr mandoc 1
utility.
.Pp
Tables within
.Xr mdoc 7
or
.Xr man 7
are enclosed by the
.Sq TS
and
.Sq TE
macro tags, whose precise syntax is documented in
.Xr roff 7 .
Tables consist of a series of options on a single line, followed by the
table layout, followed by data.
.Pp
For example, the following creates a boxed table with digits centered in
the cells.
.Bd -literal -offset indent
\&.TS
tab(:) box;
c5 c5 c5.
1:2:3
4:5:6
\&.TE
.Ed
.Pp
When formatted, the following output is produced:
.Bd -filled -offset indent -compact
.TS
tab(:) box;
c5 c5 c5.
1:2:3
4:5:6
.TE
.Ed
.Sh TABLE STRUCTURE
Tables are enclosed by the
.Sq TS
and
.Sq TE
Each table is started with a
.Xr roff 7
macros.
A table consists of an optional single line of table
.Sx Options
terminated by a semicolon, followed by one or more lines of
.Ic \&TS
macro, consist of at most one line of
.Sx Options ,
one or more
.Sx Layout
specifications terminated by a period, then
.Sx Data .
lines, one or more
.Sx Data
lines, and ends with a
.Ic \&TE
macro.
All input must be 7-bit ASCII.
Example:
.Bd -literal -offset indent
\&.TS
box tab(:);
c | c
| c | c.
1:2
3:4
\&.TE
.Ed
.Pp
Table data is
.Em pre-processed ,
that is, data rows are parsed then inserted into the underlying stream
of input data.
This allows data rows to be interspersed by arbitrary
.Xr roff 7 ,
.Xr mdoc 7 ,
and
.Xr man 7
macros such as
.Bd -literal -offset indent
\&.TS
tab(:);
c c c.
1:2:3
\&.Ao
3:2:1
\&.Ac
\&.TE
.Ed
.Pp
in the case of
.Xr mdoc 7
or
.Bd -literal -offset indent
\&.TS
tab(:);
c c c.
\&.ds ab 2
1:\e*(ab:3
\&.I
3:2:1
\&.TE
.Ed
.Pp
in the case of
.Xr man 7 .
.Ss Options
The first line of a table may contain options separated by spaces, tabs,
or commas and terminated by a semicolon.
If the first line does not have a terminating semicolon, it is assumed
that no options are specified and instead a
If the first input line of a table ends with a semicolon, it contains
case-insensitive options separated by spaces, tabs, or commas.
Otherwise, it is interpreted as the first
.Sx Layout
is processed.
Some options require arguments enclosed by parentheses.
The following case-insensitive options are available:
line.
.Pp
The following options are available.
Some of them require arguments enclosed in parentheses:
.Bl -tag -width Ds
.It Cm allbox
Draw a single-line box around each table cell.
Currently treated as a synonym for
.Cm box .
.It Cm box
Draw a single-line box around the table.
For GNU compatibility, this may also be invoked with
@ -185,73 +100,77 @@ Suppress warnings about tables exceeding the current line length.
This is a GNU extension and currently ignored.
.It Cm tab
Use the single-character argument as a delimiter between data cells.
By default, the tab character is used.
By default, the horizontal tabulator character is used.
.El
.Ss Layout
The table layout follows
The table layout follows an
.Sx Options
or a
.Sq \&T&
macro invocation.
Layout specifies how data rows are displayed on output.
Each layout line corresponds to a line of data; the last layout line
applies to all remaining data lines.
Layout lines may also be separated by a comma.
Each layout cell consists of one of the following case-insensitive keys:
line or a
.Xr roff 7
.Ic \&TS
or
.Ic \&T&
macro.
Each layout line specifies how one line of
.Sx Data
is formatted.
The last layout line ends with a full stop.
It also applies to all remaining data lines.
Multiple layout lines can be joined by commas on a single physical
input line.
.Pp
Each layout line consists of one or more layout cell specifications,
optionally separated by whitespace.
The following case-insensitive key characters start a new cell
specification:
.Bl -tag -width 2n
.It Cm c
Center a literal string within its column.
Center the string in this cell.
.It Cm r
Right-justify a literal string within its column.
Right-justify the string in this cell.
.It Cm l
Left-justify a literal string within its column.
Left-justify the string in this cell.
.It Cm n
Justify a number around its last decimal point.
If the decimal point is not found on the number, it's assumed to trail
the number.
If no decimal point is found in the number,
it is assumed to trail the number.
.It Cm s
Horizontally span columns from the last
.No non- Ns Cm s
data cell.
It is an error if spanning columns follow a
.Cm \-
.Pf non- Cm s
layout cell.
It is an error if a column span follows a
.Cm _
or
.Cm \(ba
cell, or come first.
This option is not supported by
.Xr mandoc 1 .
.Cm =
cell, or comes first on a layout line.
The combined cell as a whole consumes only one cell
of the corresponding data line.
.It Cm a
Left-justify a literal string and pad with one space.
Left-justify a string and pad with one space.
.It Cm ^
Vertically span rows from the last
.No non- Ns Cm ^
data cell.
It is an error to invoke a vertical span on the first layout row.
Unlike a horizontal spanner, you must specify an empty cell (if it not
empty, the data is discarded) in the corresponding data cell.
.It Cm \-
Replace the data cell (its contents will be lost) with a single
horizontal line.
This may also be invoked with
.Cm _ .
.Pf non- Cm ^
layout cell.
It is an error to invoke a vertical span on the first layout line.
Unlike a horizontal span, a vertical span consumes a data cell
and discards the content.
.It Cm _
Draw a single horizontal line in this cell.
This consumes a data cell and discards the content.
It may also be invoked with
.Cm \- .
.It Cm =
Replace the data cell (its contents will be lost) with a double
horizontal line.
.It Cm \(ba
Emit a vertical bar instead of data.
.It Cm \(ba\(ba
Emit a double-vertical bar instead of data.
Draw a double horizontal line in this cell.
This consumes a data cell and discards the content.
.El
.Pp
Keys may be followed by a set of modifiers.
A modifier is either a modifier key or a natural number for specifying
the spacing to the right of the column.
The following case-insensitive modifier keys are available:
Each cell key may be followed by zero or more of the following
case-insensitive modifiers:
.Bl -tag -width 2n
.It Cm b
Use a bold font for the contents of this column.
Use a bold font for the contents of this cell.
.It Cm d
Move cell content down to the last cell of a vertical span.
Move content down to the last row of this vertical span.
Currently ignored.
.It Cm e
Make this column wider to match the maximum width
@ -259,12 +178,12 @@ of any other column also having the
.Cm e
modifier.
.It Cm f
The next character selects the font to use for this column.
The next character selects the font to use for this cell.
See the
.Xr roff 7
manual for supported one-character font names.
.It Cm i
Use an italic font for the contents of this column.
Use an italic font for the contents of this cell.
.It Cm m
Specify a cell start macro.
This is a GNU extension and currently unsupported.
@ -277,14 +196,14 @@ Set the vertical line spacing to the following unsigned argument,
or change it by the following signed argument.
Currently ignored.
.It Cm t
Do not vertically center cell content in the vertical span,
leave it at the top.
Do not vertically center content in this vertical span,
leave it in the top row.
Currently ignored.
.It Cm u
Move cell content up by half a table line.
Move cell content up by half a table row.
Currently ignored.
.It Cm w
Specify the minimum column width.
Specify a minimum column width.
.It Cm x
After determining the width of all other columns, distribute the
rest of the line length among all columns having the
@ -292,40 +211,185 @@ rest of the line length among all columns having the
modifier.
.It Cm z
Do not use this cell for determining the width of this column.
.It Cm \&|
Draw a single vertical line to the right of this cell.
.It Cm ||
Draw a double vertical line to the right of this cell.
.El
.Pp
For example, the following layout specifies a center-justified column of
minimum width 10, followed by vertical bar, followed by a left-justified
column of minimum width 10, another vertical bar, then a column using
bold font justified about the decimal point in numbers:
.Pp
.Dl cw10 | lw10 | nfB
If a modifier consists of decimal digits,
it specifies a minimum spacing in units of
.Cm n
between this column and the next column to the right.
The default is 3.
If there is a vertical line, it is drawn inside the spacing.
.Ss Data
The data section follows the last layout row.
By default, cells in a data section are delimited by a tab.
This behaviour may be changed with the
The data section follows the last
.Sx Layout
line.
Each data line consists of one or more data cells, delimited by
.Cm tab
option.
If
.Cm _
characters.
.Pp
If a data cells contains only the single character
.Ql _
or
.Cm =
is specified, a single or double line, respectively, is drawn across the
data field.
If
.Cm \e-
.Ql = ,
a single or double horizontal line is drawn across the cell,
joining its neighbours.
If a data cells contains only the two character sequence
.Ql \e_
or
.Cm \e=
is specified, a line is drawn within the data field (i.e. terminating
within the cell and not draw to the border).
If the last cell of a line is
.Cm T{ ,
all subsequent lines are included as part of the cell until
.Cm T}
is specified as its own data cell.
It may then be followed by a tab
.Pq or as designated by Cm tab
or an end-of-line to terminate the row.
.Ql \e= ,
a single or double horizontal line is drawn inside the cell,
not joining its neighbours.
If a data line contains nothing but the single character
.Ql _
or
.Ql = ,
a horizontal line across the whole table is inserted
without consuming a layout row.
.Pp
In place of any data cell, a text block can be used.
It starts with
.Ic \&T{
at the end of a physical input line.
Input line breaks inside the text block
neither end the text block nor its data cell.
It only ends if
.Ic \&T}
occurs at the beginning of a physical input line and is followed
by an end-of-cell indicator.
If the
.Ic \&T}
is followed by the end of the physical input line, the text block,
the data cell, and the data line ends at this point.
If the
.Ic \&T}
is followed by the
.Cm tab
character, only the text block and the data cell end,
but the data line continues with the data cell following the
.Cm tab
character.
If
.Ic \&T}
is followed by any other character, it does not end the text block,
which instead continues to the following physical input line.
.Sh EXAMPLES
String justification and font selection:
.Bd -literal -offset indent
\&.TS
rb c lb
r ci l.
r center l
ri ce le
right c left
\&.TE
.Ed
.Bd -filled -offset indent
.TS
rb c lb
r ci l.
r center l
ri ce le
right c left
.TE
.Ed
.Pp
Some ports in
.Ox 6.1
to show number alignment and line drawing:
.Bd -literal -offset indent
\&.TS
box tab(:);
r| l
r n.
software:version
_
AFL:2.39b
Mutt:1.8.0
Ruby:1.8.7.374
TeX Live:2015
\&.TE
.Ed
.Bd -filled -offset indent
.TS
box tab(:);
r| l
r n.
software:version
_
AFL:2.39b
Mutt:1.8.0
Ruby:1.8.7.374
TeX Live:2015
.TE
.Ed
.sp 2v
Spans and skipping width calculations:
.Bd -literal -offset indent
\&.TS
box tab(:);
lz s | rt
lt| cb| ^
^ | rz s.
left:r
l:center:
:right
\&.TE
.Ed
.Bd -filled -offset indent
.TS
box tab(:);
lz s | rt
lt| cb| ^
^ | rz s.
left:r
l:center:
:right
.TE
.Ed
.sp 2v
Text blocks, specifying spacings and specifying and equalizing
column widths, putting lines into individual cells, and overriding
.Cm allbox :
.Bd -literal -offset indent
\&.TS
allbox tab(:);
le le||7 lw10.
The fourth line:_:line 1
of this column:=:line 2
determines:\_:line 3
the column width.:T{
This text is too wide to fit into a column of width 17.
T}:line 4
T{
No break here.
T}::line 5
\&.TE
.Ed
.Bd -filled -offset indent
.TS
allbox tab(:);
le le||7 lw10.
The fourth line:_:line 1
of this column:=:line 2
determines:\_:line 3
the column width.:T{
This text is too wide to fit into a column of width 17.
T}:line 4
T{
No break here.
T}::line 5
.TE
.Ed
.sp 2v
These examples were constructed to demonstrate many
.Nm
features in a compact way.
In real manual pages, keep tables as simple as possible:
Like that, they usually look better, are less fragile, and more portable.
.Sh COMPATIBILITY
The
.Xr mandoc 1
@ -363,4 +427,6 @@ utility.
This
.Nm
reference was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
and
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .

21
tbl.c
View File

@ -1,4 +1,4 @@
/* $Id: tbl.c,v 1.41 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: tbl.c,v 1.42 2017/07/08 17:52:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -31,7 +31,7 @@
#include "libroff.h"
enum rofferr
void
tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
{
const char *cp;
@ -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;
}
}
@ -75,15 +75,14 @@ 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;
break;
case TBL_PART_CDATA:
return tbl_cdata(tbl, ln, p, pos) ? ROFF_TBL : ROFF_IGN;
tbl_cdata(tbl, ln, p, pos);
break;
default:
tbl_data(tbl, ln, p, pos);
break;
}
tbl_data(tbl, ln, p, pos);
return ROFF_TBL;
}
struct tbl_node *
@ -160,14 +159,10 @@ tbl_span(struct tbl_node *tbl)
}
int
tbl_end(struct tbl_node **tblp)
tbl_end(struct tbl_node *tbl)
{
struct tbl_node *tbl;
struct tbl_span *sp;
tbl = *tblp;
*tblp = NULL;
if (tbl->part == TBL_PART_CDATA)
mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
tbl->line, tbl->pos, "TE");

View File

@ -1,4 +1,4 @@
/* $Id: tbl_data.c,v 1.42 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: tbl_data.c,v 1.45 2017/07/08 17:52:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -51,17 +51,26 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
cp = cp->next;
/*
* Stop processing when we reach the end of the available layout
* cells. This means that we have extra input.
* If the current layout row is out of cells, allocate
* a new cell if another row of the table has at least
* this number of columns, or discard the input if we
* are beyond the last column of the table as a whole.
*/
if (cp == NULL) {
mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
ln, *pos, p + *pos);
/* Skip to the end... */
while (p[*pos])
(*pos)++;
return;
if (dp->layout->last->col + 1 < dp->opts->cols) {
cp = mandoc_calloc(1, sizeof(*cp));
cp->pos = TBL_CELL_LEFT;
dp->layout->last->next = cp;
cp->col = dp->layout->last->col + 1;
dp->layout->last = cp;
} else {
mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
ln, *pos, p + *pos);
while (p[*pos])
(*pos)++;
return;
}
}
dat = mandoc_calloc(1, sizeof(*dat));
@ -119,7 +128,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
tbl->parse, ln, sv, dat->string);
}
int
void
tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_dat *dat;
@ -134,10 +143,10 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
pos++;
while (p[pos] != '\0')
getdata(tbl, tbl->last_span, ln, p, &pos);
return 1;
return;
} else if (p[pos] == '\0') {
tbl->part = TBL_PART_DATA;
return 1;
return;
}
/* Fallthrough: T} is part of a word. */
@ -157,8 +166,6 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
if (dat->layout->pos == TBL_CELL_DOWN)
mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
ln, pos, dat->string);
return 0;
}
static struct tbl_span *
@ -185,58 +192,50 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
void
tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_span *dp;
struct tbl_row *rp;
struct tbl_cell *cp;
struct tbl_span *sp;
/*
* Choose a layout row: take the one following the last parsed
* span's. If that doesn't exist, use the last parsed span's.
* If there's no last parsed span, use the first row. Lastly,
* if the last span was a horizontal line, use the same layout
* (it doesn't "consume" the layout).
*/
rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
sp->layout->next : sp->layout;
if (tbl->last_span != NULL) {
if (tbl->last_span->pos == TBL_SPAN_DATA) {
for (rp = tbl->last_span->layout->next;
rp != NULL && rp->first != NULL;
rp = rp->next) {
switch (rp->first->pos) {
case TBL_CELL_HORIZ:
dp = newspan(tbl, ln, rp);
dp->pos = TBL_SPAN_HORIZ;
continue;
case TBL_CELL_DHORIZ:
dp = newspan(tbl, ln, rp);
dp->pos = TBL_SPAN_DHORIZ;
continue;
default:
break;
}
break;
}
} else
rp = tbl->last_span->layout;
if (rp == NULL)
rp = tbl->last_span->layout;
} else
rp = tbl->first_row;
assert(rp);
dp = newspan(tbl, ln, rp);
assert(rp != NULL);
if ( ! strcmp(p, "_")) {
dp->pos = TBL_SPAN_HORIZ;
sp = newspan(tbl, ln, rp);
sp->pos = TBL_SPAN_HORIZ;
return;
} else if ( ! strcmp(p, "=")) {
dp->pos = TBL_SPAN_DHORIZ;
sp = newspan(tbl, ln, rp);
sp->pos = TBL_SPAN_DHORIZ;
return;
}
dp->pos = TBL_SPAN_DATA;
/*
* If the layout row contains nothing but horizontal lines,
* allocate an empty span for it and assign the current span
* to the next layout row accepting data.
*/
while (rp->next != NULL) {
if (rp->last->col + 1 < tbl->opts.cols)
break;
for (cp = rp->first; cp != NULL; cp = cp->next)
if (cp->pos != TBL_CELL_HORIZ &&
cp->pos != TBL_CELL_DHORIZ)
break;
if (cp != NULL)
break;
sp = newspan(tbl, ln, rp);
sp->pos = TBL_SPAN_DATA;
rp = rp->next;
}
/* Process a real data row. */
sp = newspan(tbl, ln, rp);
sp->pos = TBL_SPAN_DATA;
while (p[pos] != '\0')
getdata(tbl, dp, ln, p, &pos);
getdata(tbl, sp, ln, p, &pos);
}

View File

@ -1,4 +1,4 @@
/* $Id: tbl_html.c,v 1.21 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: tbl_html.c,v 1.22 2017/06/12 20:14:18 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -83,7 +83,7 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
h->tbl.sulen = html_tbl_sulen;
tblcalc(&h->tbl, sp, 0);
tblcalc(&h->tbl, sp, 0, 0);
}
assert(NULL == h->tblt);

View File

@ -1,4 +1,4 @@
/* $Id: tbl_layout.c,v 1.42 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: tbl_layout.c,v 1.44 2017/06/27 18:25:02 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -20,6 +20,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -298,6 +299,8 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
tbl->parse, ln, pos, NULL);
cell_alloc(tbl, tbl->first_row,
TBL_CELL_LEFT);
if (tbl->opts.lvert < tbl->first_row->vert)
tbl->opts.lvert = tbl->first_row->vert;
return;
}
@ -355,6 +358,7 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
struct tbl_cell *p, *pp;
p = mandoc_calloc(1, sizeof(*p));
p->spacing = SIZE_MAX;
p->pos = pos;
if ((pp = rp->last) != NULL) {

View File

@ -1,4 +1,4 @@
/* $Id: tbl_term.c,v 1.46 2017/06/08 18:11:22 schwarze Exp $ */
/* $Id: tbl_term.c,v 1.56 2017/07/08 13:43:15 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
@ -28,11 +28,15 @@
#include "out.h"
#include "term.h"
#define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \
(cp)->pos == TBL_CELL_DHORIZ)
static size_t term_tbl_len(size_t, void *);
static size_t term_tbl_strlen(const char *, void *);
static size_t term_tbl_sulen(const struct roffsu *, void *);
static void tbl_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *,
const struct tbl_cell *,
const struct tbl_dat *,
const struct roffcol *);
static void tbl_literal(struct termp *, const struct tbl_dat *,
@ -47,7 +51,7 @@ static void tbl_word(struct termp *, const struct tbl_dat *);
static size_t
term_tbl_sulen(const struct roffsu *su, void *arg)
{
return term_hspan((const struct termp *)arg, su) / 24;
return term_hen((const struct termp *)arg, su);
}
static size_t
@ -65,15 +69,16 @@ term_tbl_len(size_t sz, void *arg)
void
term_tbl(struct termp *tp, const struct tbl_span *sp)
{
const struct tbl_cell *cp;
const struct tbl_cell *cp, *cpn, *cpp;
const struct tbl_dat *dp;
static size_t offset;
size_t tsz;
int ic, horiz, spans, vert;
size_t coloff, tsz;
int ic, horiz, spans, vert, more;
char fc;
/* Inhibit printing of spaces: we do padding ourselves. */
tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE | TERMP_BRNEVER;
tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
/*
* The first time we're invoked for a given table block,
@ -86,7 +91,18 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tbl.sulen = term_tbl_sulen;
tp->tbl.arg = tp;
tblcalc(&tp->tbl, sp, tp->tcol->rmargin - tp->tcol->offset);
tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin);
/* Tables leak .ta settings to subsequent text. */
term_tab_set(tp, NULL);
coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
sp->opts->lvert;
for (ic = 0; ic < sp->opts->cols; ic++) {
coloff += tp->tbl.cols[ic].width;
term_tab_iset(coloff);
coloff += tp->tbl.cols[ic].spacing;
}
/* Center the table as a whole. */
@ -94,9 +110,11 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
if (sp->opts->opts & TBL_OPT_CENTRE) {
tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
for (ic = 0; ic < sp->opts->cols; ic++)
tsz += tp->tbl.cols[ic].width + 3;
tsz -= 3;
for (ic = 0; ic + 1 < sp->opts->cols; ic++)
tsz += tp->tbl.cols[ic].width +
tp->tbl.cols[ic].spacing;
if (sp->opts->cols)
tsz += tp->tbl.cols[sp->opts->cols - 1].width;
if (offset + tsz > tp->tcol->rmargin)
tsz -= 1;
tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
@ -106,140 +124,377 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Horizontal frame at the start of boxed tables. */
if (sp->opts->opts & TBL_OPT_DBOX)
tbl_hrule(tp, sp, 2);
tbl_hrule(tp, sp, 3);
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
tbl_hrule(tp, sp, 1);
tbl_hrule(tp, sp, 2);
}
/* Vertical frame at the start of each row. */
/* Set up the columns. */
horiz = sp->pos == TBL_SPAN_HORIZ || sp->pos == TBL_SPAN_DHORIZ;
tp->flags |= TERMP_MULTICOL;
horiz = 0;
switch (sp->pos) {
case TBL_SPAN_HORIZ:
case TBL_SPAN_DHORIZ:
horiz = 1;
term_setcol(tp, 1);
break;
case TBL_SPAN_DATA:
term_setcol(tp, sp->opts->cols + 2);
coloff = tp->tcol->offset;
if (sp->layout->vert ||
(sp->prev != NULL && sp->prev->layout->vert) ||
sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
term_word(tp, horiz ? "+" : "|");
else if (sp->opts->lvert)
tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1);
/* Set up a column for a left vertical frame. */
/*
* Now print the actual data itself depending on the span type.
* Match data cells to column numbers.
*/
if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
sp->opts->lvert)
coloff++;
tp->tcol->rmargin = coloff;
/* Set up the data columns. */
if (sp->pos == TBL_SPAN_DATA) {
cp = sp->layout->first;
dp = sp->first;
spans = 0;
for (ic = 0; ic < sp->opts->cols; ic++) {
/*
* Remeber whether we need a vertical bar
* after this cell.
*/
vert = cp == NULL ? 0 : cp->vert;
/*
* Print the data and advance to the next cell.
*/
if (spans == 0) {
tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic);
tp->tcol++;
tp->tcol->offset = coloff;
}
coloff += tp->tbl.cols[ic].width;
tp->tcol->rmargin = coloff;
if (ic + 1 < sp->opts->cols)
coloff += tp->tbl.cols[ic].spacing;
if (spans) {
spans--;
continue;
}
if (dp == NULL)
continue;
spans = dp->spans;
if (ic || sp->layout->first->pos != TBL_CELL_SPAN)
dp = dp->next;
}
/* Set up a column for a right vertical frame. */
tp->tcol++;
tp->tcol->offset = coloff + 1;
tp->tcol->rmargin = tp->maxrmargin;
/* Spans may have reduced the number of columns. */
tp->lasttcol = tp->tcol - tp->tcols;
/* Fill the buffers for all data columns. */
tp->tcol = tp->tcols;
cp = cpn = sp->layout->first;
dp = sp->first;
spans = 0;
for (ic = 0; ic < sp->opts->cols; ic++) {
if (cpn != NULL) {
cp = cpn;
cpn = cpn->next;
}
if (spans) {
spans--;
continue;
}
tp->tcol++;
tp->col = 0;
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
if (dp == NULL)
continue;
spans = dp->spans;
if (cp->pos != TBL_CELL_SPAN)
dp = dp->next;
}
break;
}
do {
/* Print the vertical frame at the start of each row. */
tp->tcol = tp->tcols;
fc = '\0';
if (sp->layout->vert ||
(sp->next != NULL && sp->next->layout->vert &&
sp->next->pos == TBL_SPAN_DATA) ||
(sp->prev != NULL && sp->prev->layout->vert &&
(horiz || (IS_HORIZ(sp->layout->first) &&
!IS_HORIZ(sp->prev->layout->first)))) ||
sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
else if (horiz && sp->opts->lvert)
fc = '-';
if (fc != '\0') {
(*tp->advance)(tp, tp->tcols->offset);
(*tp->letter)(tp, fc);
tp->viscol = tp->tcol->offset + 1;
}
/* Print the data cells. */
more = 0;
if (horiz) {
tbl_hrule(tp, sp, 0);
term_flushln(tp);
} else {
cp = sp->layout->first;
cpn = sp->next == NULL ? NULL :
sp->next->layout->first;
cpp = sp->prev == NULL ? NULL :
sp->prev->layout->first;
dp = sp->first;
spans = 0;
for (ic = 0; ic < sp->opts->cols; ic++) {
/*
* Figure out whether to print a
* vertical line after this cell
* and advance to next layout cell.
*/
if (cp != NULL) {
vert = cp->vert;
switch (cp->pos) {
case TBL_CELL_HORIZ:
fc = '-';
break;
case TBL_CELL_DHORIZ:
fc = '=';
break;
default:
fc = ' ';
break;
}
} else {
vert = 0;
fc = ' ';
}
if (cpp != NULL) {
if (vert == 0 &&
cp != NULL &&
((IS_HORIZ(cp) &&
!IS_HORIZ(cpp)) ||
(cp->next != NULL &&
cpp->next != NULL &&
IS_HORIZ(cp->next) &&
!IS_HORIZ(cpp->next))))
vert = cpp->vert;
cpp = cpp->next;
}
if (vert == 0 &&
sp->opts->opts & TBL_OPT_ALLBOX)
vert = 1;
if (cpn != NULL) {
if (vert == 0)
vert = cpn->vert;
cpn = cpn->next;
}
if (cp != NULL)
cp = cp->next;
/*
* Skip later cells in a span,
* figure out whether to start a span,
* and advance to next data cell.
*/
if (spans) {
spans--;
continue;
}
if (dp != NULL) {
spans = dp->spans;
dp = dp->next;
if (ic || sp->layout->first->pos
!= TBL_CELL_SPAN)
dp = dp->next;
}
} else
spans--;
if (cp != NULL)
cp = cp->next;
/*
* Separate columns, except in the middle
* of spans and after the last cell.
*/
/*
* Print one line of text in the cell
* and remember whether there is more.
*/
if (ic + 1 == sp->opts->cols || spans)
continue;
tp->tcol++;
if (tp->tcol->col < tp->tcol->lastcol)
term_flushln(tp);
if (tp->tcol->col < tp->tcol->lastcol)
more = 1;
tbl_char(tp, ASCII_NBRSP, 1);
if (vert > 0)
tbl_char(tp, '|', vert);
if (vert < 2)
tbl_char(tp, ASCII_NBRSP, 2 - vert);
/*
* Vertical frames between data cells,
* but not after the last column.
*/
if (fc == ' ' && ((vert == 0 &&
(cp == NULL || !IS_HORIZ(cp))) ||
tp->tcol + 1 == tp->tcols + tp->lasttcol))
continue;
if (tp->viscol < tp->tcol->rmargin) {
(*tp->advance)(tp, tp->tcol->rmargin
- tp->viscol);
tp->viscol = tp->tcol->rmargin;
}
while (tp->viscol < tp->tcol->rmargin +
tp->tbl.cols[ic].spacing / 2) {
(*tp->letter)(tp, fc);
tp->viscol++;
}
if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
continue;
if (fc == ' ' && cp != NULL) {
switch (cp->pos) {
case TBL_CELL_HORIZ:
fc = '-';
break;
case TBL_CELL_DHORIZ:
fc = '=';
break;
default:
break;
}
}
if (tp->tbl.cols[ic].spacing) {
(*tp->letter)(tp, fc == ' ' ? '|' :
vert ? '+' : fc);
tp->viscol++;
}
if (fc != ' ') {
if (cp != NULL &&
cp->pos == TBL_CELL_HORIZ)
fc = '-';
else if (cp != NULL &&
cp->pos == TBL_CELL_DHORIZ)
fc = '=';
else
fc = ' ';
}
if (tp->tbl.cols[ic].spacing > 2 &&
(vert > 1 || fc != ' ')) {
(*tp->letter)(tp, fc == ' ' ? '|' :
vert > 1 ? '+' : fc);
tp->viscol++;
}
}
}
} else if (horiz)
tbl_hrule(tp, sp, 0);
/* Vertical frame at the end of each row. */
/* Print the vertical frame at the end of each row. */
if (sp->layout->last->vert ||
(sp->prev != NULL && sp->prev->layout->last->vert) ||
(sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
term_word(tp, horiz ? "+" : " |");
else if (sp->opts->rvert)
tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1);
term_flushln(tp);
fc = '\0';
if ((sp->layout->last->vert &&
sp->layout->last->col + 1 == sp->opts->cols) ||
(sp->next != NULL &&
sp->next->layout->last->vert &&
sp->next->layout->last->col + 1 == sp->opts->cols) ||
(sp->prev != NULL &&
sp->prev->layout->last->vert &&
sp->prev->layout->last->col + 1 == sp->opts->cols &&
(horiz || (IS_HORIZ(sp->layout->last) &&
!IS_HORIZ(sp->prev->layout->last)))) ||
(sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
else if (horiz && sp->opts->rvert)
fc = '-';
if (fc != '\0') {
if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
sp->layout->last->col + 1 < sp->opts->cols)) {
tp->tcol++;
(*tp->advance)(tp,
tp->tcol->offset > tp->viscol ?
tp->tcol->offset - tp->viscol : 1);
}
(*tp->letter)(tp, fc);
}
(*tp->endline)(tp);
tp->viscol = 0;
} while (more);
/*
* If we're the last row, clean up after ourselves: clear the
* existing table configuration and set it to NULL.
* Clean up after this row. If it is the last line
* of the table, print the box line and clean up
* column data; otherwise, print the allbox line.
*/
term_setcol(tp, 1);
tp->flags &= ~TERMP_MULTICOL;
tp->tcol->rmargin = tp->maxrmargin;
if (sp->next == NULL) {
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
tbl_hrule(tp, sp, 1);
tbl_hrule(tp, sp, 2);
tp->skipvsp = 1;
}
if (sp->opts->opts & TBL_OPT_DBOX) {
tbl_hrule(tp, sp, 2);
tbl_hrule(tp, sp, 3);
tp->skipvsp = 2;
}
assert(tp->tbl.cols);
free(tp->tbl.cols);
tp->tbl.cols = NULL;
tp->tcol->offset = offset;
}
tp->flags &= ~(TERMP_NONOSPACE | TERMP_BRNEVER);
} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
(sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
sp->next->next != NULL))
tbl_hrule(tp, sp, 1);
tp->flags &= ~TERMP_NONOSPACE;
}
/*
* Kinds of horizontal rulers:
* 0: inside the table (single or double line with crossings)
* 1: inner frame (single line with crossings and ends)
* 2: outer frame (single line without crossings with ends)
* 1: inside the table (single or double line with crossings and ends)
* 2: inner frame (single line with crossings and ends)
* 3: outer frame (single line without crossings with ends)
*/
static void
tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
{
const struct tbl_cell *c1, *c2;
const struct tbl_cell *cp, *cpn, *cpp;
const struct roffcol *col;
int vert;
char line, cross;
line = (kind == 0 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
cross = (kind < 2) ? '+' : '-';
line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
cross = (kind < 3) ? '+' : '-';
if (kind)
term_word(tp, "+");
c1 = sp->layout->first;
c2 = sp->prev == NULL ? NULL : sp->prev->layout->first;
if (c2 == c1)
c2 = NULL;
cp = sp->layout->first;
cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
if (cpp == cp)
cpp = NULL;
cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
if (cpn == cp)
cpn = NULL;
for (;;) {
tbl_char(tp, line, tp->tbl.cols[c1->col].width + 1);
vert = c1->vert;
if ((c1 = c1->next) == NULL)
col = tp->tbl.cols + cp->col;
tbl_char(tp, line, col->width + col->spacing / 2);
vert = cp->vert;
if ((cp = cp->next) == NULL)
break;
if (c2 != NULL) {
if (vert < c2->vert)
vert = c2->vert;
c2 = c2->next;
if (cpp != NULL) {
if (vert < cpp->vert)
vert = cpp->vert;
cpp = cpp->next;
}
if (vert)
tbl_char(tp, cross, vert);
if (vert < 2)
tbl_char(tp, line, 2 - vert);
if (cpn != NULL) {
if (vert < cpn->vert)
vert = cpn->vert;
cpn = cpn->next;
}
if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
vert = 1;
if (col->spacing)
tbl_char(tp, vert ? cross : line, 1);
if (col->spacing > 2)
tbl_char(tp, vert > 1 ? cross : line, 1);
if (col->spacing > 4)
tbl_char(tp, line, (col->spacing - 3) / 2);
}
if (kind) {
term_word(tp, "+");
@ -249,18 +504,25 @@ tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
static void
tbl_data(struct termp *tp, const struct tbl_opts *opts,
const struct tbl_dat *dp,
const struct roffcol *col)
const struct tbl_cell *cp, const struct tbl_dat *dp,
const struct roffcol *col)
{
if (dp == NULL) {
tbl_char(tp, ASCII_NBRSP, col->width);
switch (cp->pos) {
case TBL_CELL_HORIZ:
tbl_char(tp, '-', col->width);
return;
case TBL_CELL_DHORIZ:
tbl_char(tp, '=', col->width);
return;
default:
break;
}
if (dp == NULL)
return;
switch (dp->pos) {
case TBL_DATA_NONE:
tbl_char(tp, ASCII_NBRSP, col->width);
return;
case TBL_DATA_HORIZ:
case TBL_DATA_NHORIZ:
@ -274,13 +536,7 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
break;
}
switch (dp->layout->pos) {
case TBL_CELL_HORIZ:
tbl_char(tp, '-', col->width);
break;
case TBL_CELL_DHORIZ:
tbl_char(tp, '=', col->width);
break;
switch (cp->pos) {
case TBL_CELL_LONG:
case TBL_CELL_CENTRE:
case TBL_CELL_LEFT:
@ -291,7 +547,7 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
tbl_number(tp, opts, dp, col);
break;
case TBL_CELL_DOWN:
tbl_char(tp, ASCII_NBRSP, col->width);
case TBL_CELL_SPAN:
break;
default:
abort();

132
term.c
View File

@ -1,4 +1,4 @@
/* $Id: term.c,v 1.268 2017/06/08 12:54:58 schwarze Exp $ */
/* $Id: term.c,v 1.274 2017/07/28 14:25:48 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -39,6 +39,18 @@ static void encode1(struct termp *, int);
static void endline(struct termp *);
void
term_setcol(struct termp *p, size_t maxtcol)
{
if (maxtcol > p->maxtcol) {
p->tcols = mandoc_recallocarray(p->tcols,
p->maxtcol, maxtcol, sizeof(*p->tcols));
p->maxtcol = maxtcol;
}
p->lasttcol = maxtcol - 1;
p->tcol = p->tcols;
}
void
term_free(struct termp *p)
{
@ -104,6 +116,7 @@ term_flushln(struct termp *p)
size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */
int ntab; /* number of tabs to prepend */
int breakline; /* after this word */
vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
0 : p->tcol->offset - p->viscol;
@ -116,9 +129,9 @@ term_flushln(struct termp *p)
p->maxrmargin - p->viscol - vbl : 0;
vis = vend = 0;
if (p->lasttcol == 0)
if ((p->flags & TERMP_MULTICOL) == 0)
p->tcol->col = 0;
while (p->tcol->col < p->lastcol) {
while (p->tcol->col < p->tcol->lastcol) {
/*
* Handle literal tab characters: collapse all
@ -126,7 +139,7 @@ term_flushln(struct termp *p)
*/
ntab = 0;
while (p->tcol->col < p->lastcol &&
while (p->tcol->col < p->tcol->lastcol &&
p->tcol->buf[p->tcol->col] == '\t') {
vend = term_tab_next(vis);
vbl += vend - vis;
@ -143,7 +156,13 @@ term_flushln(struct termp *p)
*/
jhy = 0;
for (j = p->tcol->col; j < p->lastcol; j++) {
breakline = 0;
for (j = p->tcol->col; j < p->tcol->lastcol; j++) {
if (p->tcol->buf[j] == '\n') {
if ((p->flags & TERMP_BRIND) == 0)
breakline = 1;
continue;
}
if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
break;
@ -178,7 +197,7 @@ term_flushln(struct termp *p)
if (vend > bp && jhy == 0 && vis > 0 &&
(p->flags & TERMP_BRNEVER) == 0) {
if (p->lasttcol)
if (p->flags & TERMP_MULTICOL)
return;
endline(p);
@ -206,14 +225,16 @@ term_flushln(struct termp *p)
* Write out the rest of the word.
*/
for ( ; p->tcol->col < p->lastcol; p->tcol->col++) {
for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) {
if (vend > bp && jhy > 0 && p->tcol->col > jhy)
break;
if (p->tcol->buf[p->tcol->col] == '\n')
continue;
if (p->tcol->buf[p->tcol->col] == '\t')
break;
if (p->tcol->buf[p->tcol->col] == ' ') {
j = p->tcol->col;
while (p->tcol->col < p->lastcol &&
while (p->tcol->col < p->tcol->lastcol &&
p->tcol->buf[p->tcol->col] == ' ')
p->tcol->col++;
dv = (p->tcol->col - j) * (*p->width)(p, ' ');
@ -248,6 +269,26 @@ term_flushln(struct termp *p)
p->tcol->buf[p->tcol->col]);
}
vis = vend;
if (breakline == 0)
continue;
/* Explicitly requested output line break. */
if (p->flags & TERMP_MULTICOL)
return;
endline(p);
breakline = 0;
vis = vend = 0;
/* Re-establish indentation. */
vbl = p->tcol->offset;
maxvis = p->tcol->rmargin > vbl ?
p->tcol->rmargin - vbl : 0;
bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
p->maxrmargin > vbl ? p->maxrmargin - vbl : 0;
}
/*
@ -260,10 +301,13 @@ term_flushln(struct termp *p)
else
vis = 0;
p->col = p->lastcol = 0;
p->col = p->tcol->col = p->tcol->lastcol = 0;
p->minbl = p->trailspace;
p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
if (p->flags & TERMP_MULTICOL)
return;
/* Trailing whitespace is significant in some columns. */
if (vis && vbl && (TERMP_BRTRSP & p->flags))
@ -305,7 +349,7 @@ term_newln(struct termp *p)
{
p->flags |= TERMP_NOSPACE;
if (p->lastcol || p->viscol)
if (p->tcol->lastcol || p->viscol)
term_flushln(p);
}
@ -472,6 +516,9 @@ term_word(struct termp *p, const char *word)
case ESCAPE_FONTPREV:
term_fontlast(p);
continue;
case ESCAPE_BREAK:
bufferc(p, '\n');
continue;
case ESCAPE_NOSPACE:
if (p->flags & TERMP_BACKAFTER)
p->flags &= ~TERMP_BACKAFTER;
@ -479,9 +526,14 @@ term_word(struct termp *p, const char *word)
p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
continue;
case ESCAPE_HORIZ:
if (*seq == '|') {
seq++;
uc = -p->col;
} else
uc = 0;
if (a2roffsu(seq, &su, SCALE_EM) == NULL)
continue;
uc = term_hspan(p, &su) / 24;
uc += term_hen(p, &su);
if (uc > 0)
while (uc-- > 0)
bufferc(p, ASCII_NBRSP);
@ -500,19 +552,19 @@ term_word(struct termp *p, const char *word)
}
continue;
case ESCAPE_HLINE:
if ((seq = a2roffsu(seq, &su, SCALE_EM)) == NULL)
if ((cp = a2roffsu(seq, &su, SCALE_EM)) == NULL)
continue;
uc = term_hspan(p, &su) / 24;
uc = term_hen(p, &su);
if (uc <= 0) {
if (p->tcol->rmargin <= p->tcol->offset)
continue;
lsz = p->tcol->rmargin - p->tcol->offset;
} else
lsz = uc;
if (*seq == '\0')
if (*cp == seq[-1])
uc = -1;
else if (*seq == '\\') {
seq++;
else if (*cp == '\\') {
seq = cp + 1;
esc = mandoc_escape(&seq, &cp, &sz);
switch (esc) {
case ESCAPE_UNICODE:
@ -529,7 +581,7 @@ term_word(struct termp *p, const char *word)
break;
}
} else
uc = *seq;
uc = *cp;
if (uc < 0x20 || (uc > 0x7E && uc < 0xA0))
uc = '_';
if (p->enc == TERMENC_ASCII) {
@ -565,12 +617,12 @@ term_word(struct termp *p, const char *word)
}
}
/* Trim trailing backspace/blank pair. */
if (p->lastcol > 2 &&
(p->tcol->buf[p->lastcol - 1] == ' ' ||
p->tcol->buf[p->lastcol - 1] == '\t'))
p->lastcol -= 2;
if (p->col > p->lastcol)
p->col = p->lastcol;
if (p->tcol->lastcol > 2 &&
(p->tcol->buf[p->tcol->lastcol - 1] == ' ' ||
p->tcol->buf[p->tcol->lastcol - 1] == '\t'))
p->tcol->lastcol -= 2;
if (p->col > p->tcol->lastcol)
p->col = p->tcol->lastcol;
continue;
default:
continue;
@ -613,10 +665,10 @@ bufferc(struct termp *p, char c)
}
if (p->col + 1 >= p->tcol->maxcols)
adjbuf(p->tcol, p->col + 1);
if (p->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
p->tcol->buf[p->col] = c;
if (p->lastcol < ++p->col)
p->lastcol = p->col;
if (p->tcol->lastcol < ++p->col)
p->tcol->lastcol = p->col;
}
/*
@ -659,10 +711,10 @@ encode1(struct termp *p, int c)
p->tcol->buf[p->col++] = c;
p->tcol->buf[p->col++] = '\b';
}
if (p->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
p->tcol->buf[p->col] = c;
if (p->lastcol < ++p->col)
p->lastcol = p->col;
if (p->tcol->lastcol < ++p->col)
p->tcol->lastcol = p->col;
if (p->flags & TERMP_BACKAFTER) {
p->flags |= TERMP_BACKBEFORE;
p->flags &= ~TERMP_BACKAFTER;
@ -688,7 +740,7 @@ encode(struct termp *p, const char *word, size_t sz)
isgraph((unsigned char)word[i]))
encode1(p, word[i]);
else {
if (p->lastcol <= p->col ||
if (p->tcol->lastcol <= p->col ||
(word[i] != ' ' && word[i] != ASCII_NBRSP))
p->tcol->buf[p->col] = word[i];
p->col++;
@ -705,8 +757,8 @@ encode(struct termp *p, const char *word, size_t sz)
}
}
}
if (p->lastcol < p->col)
p->lastcol = p->col;
if (p->tcol->lastcol < p->col)
p->tcol->lastcol = p->col;
}
void
@ -919,7 +971,7 @@ term_vspan(const struct termp *p, const struct roffsu *su)
}
/*
* Convert a scaling width to basic units, rounding down.
* Convert a scaling width to basic units, rounding towards 0.
*/
int
term_hspan(const struct termp *p, const struct roffsu *su)
@ -927,3 +979,17 @@ term_hspan(const struct termp *p, const struct roffsu *su)
return (*p->hspan)(p, su);
}
/*
* Convert a scaling width to basic units, rounding to closest.
*/
int
term_hen(const struct termp *p, const struct roffsu *su)
{
int bu;
if ((bu = (*p->hspan)(p, su)) >= 0)
return (bu + 11) / 24;
else
return -((-bu + 11) / 24);
}

12
term.h
View File

@ -1,4 +1,4 @@
/* $Id: term.h,v 1.126 2017/06/07 20:01:19 schwarze Exp $ */
/* $Id: term.h,v 1.130 2017/07/08 14:51:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -36,7 +36,7 @@ enum termfont {
TERMFONT__MAX
};
struct eqn;
struct eqn_box;
struct roff_meta;
struct roff_node;
struct tbl_span;
@ -52,6 +52,7 @@ struct termp_tbl {
struct termp_col {
int *buf; /* Output buffer. */
size_t maxcols; /* Allocated bytes in buf. */
size_t lastcol; /* Last byte in buf. */
size_t col; /* Byte in buf to be written. */
size_t rmargin; /* Current right margin. */
size_t offset; /* Current left margin. */
@ -69,7 +70,6 @@ struct termp {
size_t lastrmargin; /* Right margin before the last ll. */
size_t maxrmargin; /* Max right margin. */
size_t col; /* Byte position in buf. */
size_t lastcol; /* Bytes in buf. */
size_t viscol; /* Chars on current line. */
size_t trailspace; /* See term_flushln(). */
size_t minbl; /* Minimum blanks before next field. */
@ -98,6 +98,7 @@ struct termp {
#define TERMP_NOBUF (1 << 17) /* Bypass output buffer. */
#define TERMP_NEWMC (1 << 18) /* No .mc printed yet. */
#define TERMP_ENDMC (1 << 19) /* Next break ends .mc mode. */
#define TERMP_MULTICOL (1 << 20) /* Multiple column mode. */
enum termtype type; /* Terminal, PS, or PDF. */
enum termenc enc; /* Type of encoding. */
enum termfont fontl; /* Last font set. */
@ -125,9 +126,10 @@ const char *ascii_uc2str(int);
void roff_term_pre(struct termp *, const struct roff_node *);
void term_eqn(struct termp *, const struct eqn *);
void term_eqn(struct termp *, const struct eqn_box *);
void term_tbl(struct termp *, const struct tbl_span *);
void term_free(struct termp *);
void term_setcol(struct termp *, size_t);
void term_newln(struct termp *);
void term_vspace(struct termp *);
void term_word(struct termp *, const char *);
@ -138,11 +140,13 @@ void term_end(struct termp *);
void term_setwidth(struct termp *, const char *);
int term_hspan(const struct termp *, const struct roffsu *);
int term_hen(const struct termp *, const struct roffsu *);
int term_vspan(const struct termp *, const struct roffsu *);
size_t term_strlen(const struct termp *, const char *);
size_t term_len(const struct termp *, size_t);
void term_tab_set(const struct termp *, const char *);
void term_tab_iset(size_t);
size_t term_tab_next(size_t);
void term_fontpush(struct termp *, enum termfont);

View File

@ -1,4 +1,4 @@
/* $Id: term_ascii.c,v 1.57 2017/06/07 17:38:26 schwarze Exp $ */
/* $Id: term_ascii.c,v 1.58 2017/06/14 14:24:20 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -293,7 +293,7 @@ ascii_uc2str(int uc)
"<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
"<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
"<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
"<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
"<98>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>",
"\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
"<deg>","+-", "2", "3", "'", ",\bu", "<par>",".",

View File

@ -52,7 +52,7 @@ term_tab_set(const struct termp *p, const char *arg)
recording_period = 0;
if (tabs.d == 0) {
a2roffsu(".8i", &su, SCALE_IN);
tabs.d = term_hspan(p, &su) / 24;
tabs.d = term_hen(p, &su);
}
return;
}
@ -81,13 +81,28 @@ term_tab_set(const struct termp *p, const char *arg)
/* Append the new position. */
pos = term_hspan(p, &su);
pos = term_hen(p, &su);
tl->t[tl->n] = pos;
if (add && tl->n)
tl->t[tl->n] += tl->t[tl->n - 1];
tl->n++;
}
/*
* Simplified version without a parser,
* never incremental, never periodic, for use by tbl(7).
*/
void
term_tab_iset(size_t inc)
{
if (tabs.a.n >= tabs.a.s) {
tabs.a.s += 8;
tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s,
sizeof(*tabs.a.t));
}
tabs.a.t[tabs.a.n++] = inc;
}
size_t
term_tab_next(size_t prev)
{
@ -97,10 +112,6 @@ term_tab_next(size_t prev)
if (i == tabs.a.n) {
if (tabs.p.n == 0)
return prev;
/*
return i ? prev :
(prev / tabs.d + 1) * tabs.d;
*/
tabs.a.n += tabs.p.n;
if (tabs.a.s < tabs.a.n) {
tabs.a.s = tabs.a.n;
@ -111,7 +122,7 @@ term_tab_next(size_t prev)
tabs.a.t[i + j] = tabs.p.t[j] +
(i ? tabs.a.t[i - 1] : 0);
}
if (prev < tabs.a.t[i] / 24)
return tabs.a.t[i] / 24;
if (prev < tabs.a.t[i])
return tabs.a.t[i];
}
}

11
test-recallocarray.c Normal file
View File

@ -0,0 +1,11 @@
#include <stdlib.h>
int
main(void)
{
void *p;
if ((p = calloc(2, 2)) == NULL)
return 1;
return !recallocarray(p, 2, 3, 2);
}

10
tree.c
View File

@ -1,4 +1,4 @@
/* $Id: tree.c,v 1.74 2017/04/24 23:06:18 schwarze Exp $ */
/* $Id: tree.c,v 1.77 2017/07/08 14:51:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -202,7 +202,7 @@ print_mdoc(const struct roff_node *n, int indent)
}
if (n->eqn)
print_box(n->eqn->root->first, indent + 4);
print_box(n->eqn->first, indent + 4);
if (n->child)
print_mdoc(n->child, indent +
(n->type == ROFFT_BLOCK ? 2 : 4));
@ -287,7 +287,7 @@ print_man(const struct roff_node *n, int indent)
}
if (n->eqn)
print_box(n->eqn->root->first, indent + 4);
print_box(n->eqn->first, indent + 4);
if (n->child)
print_man(n->child, indent +
(n->type == ROFFT_BLOCK ? 2 : 4));
@ -313,10 +313,6 @@ print_box(const struct eqn_box *ep, int indent)
t = NULL;
switch (ep->type) {
case EQN_ROOT:
t = "eqn-root";
break;
case EQN_LISTONE:
case EQN_LIST:
t = "eqn-list";
break;