aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2015-03-02 16:45:41 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2015-03-02 16:45:41 +0000
commitd3c5aaa494431ae3a2463cc5ca6c9b8f3bf733c0 (patch)
tree753baea8b04e6b54660a1e68b1d9fe4e18f51002
parent2612bc21b4df390b151333c85302d3829cb86e93 (diff)
downloadsrc-d3c5aaa494431ae3a2463cc5ca6c9b8f3bf733c0.tar.gz
src-d3c5aaa494431ae3a2463cc5ca6c9b8f3bf733c0.zip
Import CVS snapshot of mandoc as of 20150302
Notes
Notes: svn path=/vendor/mdocml/dist/; revision=279524
-rw-r--r--LICENSE7
-rw-r--r--Makefile19
-rw-r--r--Makefile.depend4
-rw-r--r--Makefile.local30
-rw-r--r--TODO42
-rw-r--r--apropos.18
-rw-r--r--cgi.c36
-rw-r--r--chars.c4
-rw-r--r--chars.in26
-rw-r--r--compat_fts.c13
-rw-r--r--compat_strtonum.c76
-rwxr-xr-xconfigure16
-rw-r--r--configure.local.example62
-rw-r--r--demandoc.c37
-rw-r--r--eqn.711
-rw-r--r--eqn.c125
-rw-r--r--eqn_term.c21
-rw-r--r--example.style.css8
-rw-r--r--gmdiff22
-rw-r--r--html.c55
-rw-r--r--libman.h3
-rw-r--r--libmandoc.h13
-rw-r--r--libmdoc.h4
-rw-r--r--libroff.h16
-rw-r--r--main.c311
-rw-r--r--main.h4
-rw-r--r--man-cgi.css6
-rw-r--r--man.189
-rw-r--r--man.7127
-rw-r--r--man.c134
-rw-r--r--man.h4
-rw-r--r--man_html.c16
-rw-r--r--man_macro.c84
-rw-r--r--man_term.c217
-rw-r--r--man_validate.c73
-rw-r--r--mandoc.1549
-rw-r--r--mandoc.348
-rw-r--r--mandoc.c28
-rw-r--r--mandoc.db.512
-rw-r--r--mandoc.h112
-rw-r--r--mandoc_char.732
-rw-r--r--mandoc_escape.315
-rw-r--r--mandoc_headers.311
-rw-r--r--mandocdb.c68
-rw-r--r--manpage.c12
-rw-r--r--mansearch.c103
-rw-r--r--mdoc.7212
-rw-r--r--mdoc.c23
-rw-r--r--mdoc.h12
-rw-r--r--mdoc_argv.c4
-rw-r--r--mdoc_html.c115
-rw-r--r--mdoc_macro.c756
-rw-r--r--mdoc_man.c131
-rw-r--r--mdoc_term.c235
-rw-r--r--mdoc_validate.c628
-rw-r--r--msec.c3
-rw-r--r--out.c141
-rw-r--r--preconv.c135
-rw-r--r--read.c264
-rw-r--r--roff.7884
-rw-r--r--roff.c839
-rw-r--r--st.in90
-rw-r--r--style.css4
-rw-r--r--tbl.3129
-rw-r--r--tbl.7139
-rw-r--r--tbl.c115
-rw-r--r--tbl_data.c151
-rw-r--r--tbl_html.c26
-rw-r--r--tbl_layout.c395
-rw-r--r--tbl_opts.c295
-rw-r--r--tbl_term.c278
-rw-r--r--term.c118
-rw-r--r--term.h15
-rw-r--r--term_ascii.c29
-rw-r--r--term_ps.c41
-rw-r--r--test-strtonum.c42
-rw-r--r--tree.c39
77 files changed, 5304 insertions, 3697 deletions
diff --git a/LICENSE b/LICENSE
index 12bf65ade9c7..080c04fa2607 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,16 +1,17 @@
-$Id: LICENSE,v 1.5 2014/12/11 07:56:24 schwarze Exp $
+$Id: LICENSE,v 1.7 2015/02/16 14:56:22 schwarze Exp $
With the exceptions noted below, all code and documentation
contained in the mdocml toolkit is protected by the Copyright
of the following developers:
Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
-Copyright (c) 2010, 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
-Copyright (c) 1998, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
See the individual source files for information about who contributed
diff --git a/Makefile b/Makefile
index e3f48f711798..d686e01455d6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.453 2014/12/09 09:14:33 schwarze Exp $
+# $Id: Makefile,v 1.456 2015/02/16 16:23:54 schwarze Exp $
#
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
# Copyright (c) 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,6 +15,8 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+VERSION = 1.13.2
+
# === LIST OF FILES ====================================================
TESTSRCS = test-dirent-namlen.c \
@@ -31,6 +33,7 @@ TESTSRCS = test-dirent-namlen.c \
test-strlcpy.c \
test-strptime.c \
test-strsep.c \
+ test-strtonum.c \
test-wchar.c
SRCS = att.c \
@@ -46,6 +49,7 @@ SRCS = att.c \
compat_strlcat.c \
compat_strlcpy.c \
compat_strsep.c \
+ compat_strtonum.c \
demandoc.c \
eqn.c \
eqn_html.c \
@@ -189,7 +193,8 @@ COMPAT_OBJS = compat_fgetln.o \
compat_strcasestr.o \
compat_strlcat.o \
compat_strlcpy.o \
- compat_strsep.o
+ compat_strsep.o \
+ compat_strtonum.o
MANDOC_HTML_OBJS = eqn_html.o \
html.o \
@@ -211,6 +216,7 @@ BASE_OBJS = $(MANDOC_HTML_OBJS) \
$(MANDOC_MAN_OBJS) \
$(MANDOC_TERM_OBJS) \
main.o \
+ manpath.o \
out.o \
tree.o
@@ -218,8 +224,7 @@ MAIN_OBJS = $(BASE_OBJS)
DB_OBJS = mandocdb.o \
mansearch.o \
- mansearch_const.o \
- manpath.o
+ mansearch_const.o
CGI_OBJS = $(MANDOC_HTML_OBJS) \
cgi.o \
@@ -308,10 +313,12 @@ base-install: base-build
mkdir -p $(DESTDIR)$(MANDIR)/man3
mkdir -p $(DESTDIR)$(MANDIR)/man7
$(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR)
+ ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_MAN)
$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h \
$(DESTDIR)$(INCLUDEDIR)
$(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
+ $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
$(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/${MANM_MAN}.7
@@ -330,12 +337,10 @@ db-install: base-build
mkdir -p $(DESTDIR)$(MANDIR)/man5
mkdir -p $(DESTDIR)$(MANDIR)/man8
ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_APROPOS)
- ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_MAN)
ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_WHATIS)
ln -f $(DESTDIR)$(BINDIR)/mandoc \
$(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS)
$(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1
- $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1
ln -f $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 \
$(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1
$(INSTALL_MAN) mansearch.3 $(DESTDIR)$(MANDIR)/man3
@@ -377,7 +382,7 @@ demandoc: $(DEMANDOC_OBJS) libmandoc.a
www-install: www
mkdir -p $(HTDOCDIR)/snapshots
- $(INSTALL_DATA) $(WWW_MANS) style.css $(HTDOCDIR)/man
+ $(INSTALL_DATA) $(WWW_MANS) style.css $(HTDOCDIR)
$(INSTALL_DATA) $(WWW_OBJS) $(HTDOCDIR)/snapshots
$(INSTALL_DATA) mdocml.tar.gz \
$(HTDOCDIR)/snapshots/mdocml-$(VERSION).tar.gz
diff --git a/Makefile.depend b/Makefile.depend
index a61de19fcdd7..54af8bce33ec 100644
--- a/Makefile.depend
+++ b/Makefile.depend
@@ -11,6 +11,7 @@ compat_strcasestr.o: compat_strcasestr.c config.h
compat_strlcat.o: compat_strlcat.c config.h
compat_strlcpy.o: compat_strlcpy.c config.h
compat_strsep.o: compat_strsep.c config.h
+compat_strtonum.o: compat_strtonum.c config.h
demandoc.o: demandoc.c config.h man.h mdoc.h mandoc.h
eqn.o: eqn.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h
@@ -39,7 +40,7 @@ mdoc_macro.o: mdoc_macro.c config.h mdoc.h mandoc.h libmdoc.h libmandoc.h
mdoc_man.o: mdoc_man.c config.h mandoc.h mandoc_aux.h out.h man.h mdoc.h main.h
mdoc_term.o: mdoc_term.c config.h mandoc.h mandoc_aux.h out.h term.h mdoc.h main.h
mdoc_validate.o: mdoc_validate.c config.h mdoc.h mandoc.h mandoc_aux.h libmdoc.h libmandoc.h
-msec.o: msec.c config.h libmandoc.h msec.in
+msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
out.o: out.c config.h mandoc_aux.h mandoc.h out.h
preconv.o: preconv.c config.h mandoc.h libmandoc.h
read.o: read.c config.h mandoc.h mandoc_aux.h libmandoc.h mdoc.h man.h
@@ -69,4 +70,5 @@ test-strlcat.o: test-strlcat.c
test-strlcpy.o: test-strlcpy.c
test-strptime.o: test-strptime.c
test-strsep.o: test-strsep.c
+test-strtonum.o: test-strtonum.c
test-wchar.o: test-wchar.c
diff --git a/Makefile.local b/Makefile.local
new file mode 100644
index 000000000000..b197fdfdb2b2
--- /dev/null
+++ b/Makefile.local
@@ -0,0 +1,30 @@
+BUILD_TARGETS = base-build
+INSTALL_TARGETS = base-install db-install
+CFLAGS = -g -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -I/usr/local/include
+DBLIB = -L/usr/local/lib -lsqlite3
+STATIC = -static
+PREFIX = /usr/local
+BINDIR = /usr/local/bin
+SBINDIR = /usr/local/sbin
+INCLUDEDIR = /usr/local/include/mandoc
+LIBDIR = /usr/local/lib/mandoc
+MANDIR = /usr/local/man
+EXAMPLEDIR = /usr/local/share/examples/mandoc
+WWWPREFIX = /var/www
+HTDOCDIR = /var/www/htdocs
+CGIBINDIR = /var/www/cgi-bin
+BINM_APROPOS = apropos
+BINM_MAN = man
+BINM_WHATIS = whatis
+BINM_MAKEWHATIS = makewhatis
+MANM_MAN = man
+MANM_MDOC = mdoc
+MANM_ROFF = roff
+MANM_EQN = eqn
+MANM_TBL = tbl
+INSTALL = install
+INSTALL_PROGRAM = install -m 0555
+INSTALL_LIB = install -m 0444
+INSTALL_MAN = install -m 0444
+INSTALL_DATA = install -m 0444
+MAIN_OBJS = $(BASE_OBJS) $(DB_OBJS)
diff --git a/TODO b/TODO
index b213e8b92c26..ebd488ccee6a 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
-* $Id: TODO,v 1.195 2014/12/13 13:14:39 schwarze Exp $
+* $Id: TODO,v 1.201 2015/02/20 13:47:28 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@@ -60,7 +60,7 @@ are mere guesses, and some may be wrong.
- .fc (field control)
found by naddy@ in xloadimage(1)
loc ** exist *** algo * size * imp *
-
+
- .nr third argument (auto-increment step size, requires \n+)
found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
loc * exist * algo * size * imp **
@@ -69,31 +69,37 @@ are mere guesses, and some may be wrong.
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
loc *** exist *** algo *** size ** imp *
-- .ta (tab settings) occurs in ircbug(1) and probably gnats(1)
- reported by brad@ Sat, 15 Jan 2011 15:50:51 -0500
+- .ta (tab settings)
+ #1 most important issue naddy@ Mon, 16 Feb 2015 20:59:17 +0100
+ ircbug(1) gnats(1) reported by brad@ Sat, 15 Jan 2011 15:50:51 -0500
also Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
also posix2time(3) Carsten Kunze Mon, 1 Dec 2014 13:03:10 +0100
loc ** exist *** algo ** size ** imp ***
- .ti (temporary indent)
- found by naddy@ in xloadimage(1)
+ found by naddy@ in xloadimage(1) [devel/libvstr] vstr(3)
found by bentley@ in nmh(1) Mon, 23 Apr 2012 13:38:28 -0600
loc ** exist ** algo ** size * imp ** (parser reorg helps a lot)
-- .while and .shift
+- .while and .shift
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
loc * exist ** algo ** size ** imp **
- \h horizontal move
- found in cclive(1) and nasm(1) asciidoc/DocBook output
+ #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)
+ 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
@@ -105,10 +111,6 @@ are mere guesses, and some may be wrong.
--- missing mdoc features ----------------------------------------------
-- fix bad block nesting involving multiple identical explicit blocks
- see the OpenBSD mdoc_macro.c 1.47 commit message
- loc * exist *** algo *** size * imp **
-
- .Bl -column .Xo support is missing
ultimate goal:
restore .Xr and .Dv to
@@ -255,6 +257,10 @@ are mere guesses, and some may be wrong.
--- compatibility checks -----------------------------------------------
+- write a configure check for [[:<:]] support and provide some
+ fallback for whatis(1) when it doesn't work;
+ Svyatoslav Mishyn Wed, 17 Dec 2014 11:07:10 +0200
+
- is .Bk implemented correctly in modern groff?
sobrado@ Tue, 19 Apr 2011 22:12:55 +0200
@@ -347,6 +353,10 @@ are mere guesses, and some may be wrong.
reminded by jmc@ Thu, 23 Sep 2010 18:13:39 +0059
loc * exist ** algo *** size * imp ***
+- a line starting with "\fB something" counts as starting with whitespace
+ and triggers a line break; found in audio/normalize-mp3(1)
+ loc ** exist * algo ** size * imp **
+
- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc
reveals lots of bugs both in groff and mandoc...
reported by bentley@ Wed, 22 May 2013 23:49:30 -0600
@@ -457,7 +467,7 @@ are mere guesses, and some may be wrong.
loc * exist * algo * size * imp *
- trailing whitespace must be ignored even when followed by a font escape,
- see for example
+ see for example
makes
\fBdig \fR
operate in batch mode
@@ -531,7 +541,7 @@ are mere guesses, and some may be wrong.
How does SQLITE_CONFIG_PAGECACHE actually work? Document it!
from kristaps@ Sat, 09 Aug 2014 13:51:36 +0200
-Several areas can be cleaned up to make mandoc even faster. These are
+Several areas can be cleaned up to make mandoc even faster. These are
- improve hashing mechanism for macros (quite important: performance)
@@ -540,7 +550,7 @@ 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
- instead of re-initialising the roff predefined-strings set before each
- parse, create a read-only version the first time and copy it
+ parse, create a read-only version the first time and copy it
loc * exist ** algo ** size * imp **
************************************************************************
@@ -556,7 +566,7 @@ Several areas can be cleaned up to make mandoc even faster. These are
- 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.
diff --git a/apropos.1 b/apropos.1
index e2075349f553..532e4dd7ff74 100644
--- a/apropos.1
+++ b/apropos.1
@@ -1,4 +1,4 @@
-.\" $Id: apropos.1,v 1.36 2014/10/25 01:03:52 schwarze Exp $
+.\" $Id: apropos.1,v 1.37 2015/02/16 16:23:54 schwarze Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 25 2014 $
+.Dd $Mdocdate: February 16 2015 $
.Dt APROPOS 1
.Os
.Sh NAME
@@ -24,7 +24,7 @@
.Nd search manual page databases
.Sh SYNOPSIS
.Nm
-.Op Fl acfhklVw
+.Op Fl acfhklw
.Op Fl C Ar file
.Op Fl M Ar path
.Op Fl m Ar path
@@ -162,8 +162,6 @@ By default, pages from all sections are shown.
See
.Xr man 1
for a listing of sections.
-.It Fl V
-Print version and exit.
.It Fl w
Instead of showing title lines, show the pathnames of the matching
manual pages, just like
diff --git a/cgi.c b/cgi.c
index 65064ab2ad6c..05d1b8a0df01 100644
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-/* $Id: cgi.c,v 1.102 2014/11/26 17:55:27 schwarze Exp $ */
+/* $Id: cgi.c,v 1.104 2015/02/10 08:05:30 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@usta.de>
@@ -58,10 +58,10 @@ static void catman(const struct req *, const char *);
static void format(const struct req *, const char *);
static void html_print(const char *);
static void html_putchar(char);
-static int http_decode(char *);
+static int http_decode(char *);
static void http_parse(struct req *, const char *);
static void http_print(const char *);
-static void http_putchar(char);
+static void http_putchar(char);
static void http_printquery(const struct req *, const char *);
static void pathgen(struct req *);
static void pg_error_badrequest(const char *);
@@ -186,7 +186,7 @@ http_print(const char *p)
static void
html_print(const char *p)
{
-
+
if (NULL == p)
return;
while ('\0' != *p)
@@ -621,7 +621,7 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
for (i = 0; i < sz; i++) {
printf("<TR>\n"
"<TD CLASS=\"title\">\n"
- "<A HREF=\"%s/%s/%s?",
+ "<A HREF=\"%s/%s/%s?",
scriptname, req->q.manpath, r[i].file);
http_printquery(req, "&amp;");
printf("\">");
@@ -701,7 +701,7 @@ catman(const struct req *req, const char *file)
while (NULL != (p = fgetln(f, &len))) {
bold = italic = 0;
for (i = 0; i < (int)len - 1; i++) {
- /*
+ /*
* This means that the catpage is out of state.
* Ignore it and keep going (although the
* catpage is bogus).
@@ -742,7 +742,7 @@ catman(const struct req *req, const char *file)
continue;
}
- /*
+ /*
* Handle funny behaviour troff-isms.
* These grok'd from the original man2html.c.
*/
@@ -780,7 +780,7 @@ catman(const struct req *req, const char *file)
}
/* Bold mode. */
-
+
if (italic)
printf("</I>");
if ( ! bold)
@@ -791,9 +791,9 @@ catman(const struct req *req, const char *file)
html_putchar(p[i]);
}
- /*
+ /*
* Clean up the last character.
- * We can get to a newline; don't print that.
+ * We can get to a newline; don't print that.
*/
if (italic)
@@ -822,7 +822,6 @@ format(const struct req *req, const char *file)
struct man *man;
void *vp;
char *opts;
- enum mandoclevel rc;
int fd;
int usepath;
@@ -832,18 +831,11 @@ format(const struct req *req, const char *file)
}
mchars = mchars_alloc();
- mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL,
+ mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL,
mchars, req->q.manpath);
- rc = mparse_readfd(mp, fd, file);
+ mparse_readfd(mp, fd, file);
close(fd);
- if (rc >= MANDOCLEVEL_FATAL) {
- fprintf(stderr, "fatal mandoc error: %s/%s\n",
- req->q.manpath, file);
- pg_error_internal();
- return;
- }
-
usepath = strcmp(req->q.manpath, req->p[0]);
mandoc_asprintf(&opts,
"fragment,man=%s?query=%%N&sec=%%S%s%s%s%s",
@@ -899,7 +891,7 @@ pg_show(struct req *req, const char *fullpath)
pg_error_badrequest(
"You did not specify a page to show.");
return;
- }
+ }
manpath = mandoc_strndup(fullpath, file - fullpath);
file++;
@@ -1064,7 +1056,7 @@ main(void)
MAN_DIR, strerror(errno));
pg_error_internal();
return(EXIT_FAILURE);
- }
+ }
memset(&req, 0, sizeof(struct req));
pathgen(&req);
diff --git a/chars.c b/chars.c
index fe0b17dea823..6b5eba953728 100644
--- a/chars.c
+++ b/chars.c
@@ -1,4 +1,4 @@
-/* $Id: chars.c,v 1.65 2014/10/29 00:17:43 schwarze Exp $ */
+/* $Id: chars.c,v 1.66 2015/02/17 20:37:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -38,7 +38,7 @@ struct ln {
int unicode;
};
-#define LINES_MAX 330
+#define LINES_MAX 332
#define CHAR(in, ch, code) \
{ NULL, (in), (ch), (code) },
diff --git a/chars.in b/chars.in
index 752015c1b6d4..ac72aba8588c 100644
--- a/chars.in
+++ b/chars.in
@@ -1,4 +1,4 @@
-/* $Id: chars.in,v 1.49 2014/11/06 22:28:36 schwarze Exp $ */
+/* $Id: chars.in,v 1.52 2015/02/17 20:37:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -70,8 +70,10 @@ CHAR("ti", "~", 126)
/* Quotes. */
CHAR("Bq", ",,", 8222)
CHAR("bq", ",", 8218)
-CHAR("lq", "``", 8220)
-CHAR("rq", "\'\'", 8221)
+CHAR("lq", "\"", 8220)
+CHAR("rq", "\"", 8221)
+CHAR("Lq", "``", 8220)
+CHAR("Rq", "''", 8221)
CHAR("oq", "`", 8216)
CHAR("cq", "\'", 8217)
CHAR("aq", "\'", 39)
@@ -91,30 +93,30 @@ CHAR("ra", ">", 10217)
CHAR("bv", "|", 9130)
CHAR("braceex", "|", 9130)
CHAR("bracketlefttp", "|", 9121)
-CHAR("bracketleftbp", "|", 9123)
+CHAR("bracketleftbt", "|", 9123)
CHAR("bracketleftex", "|", 9122)
CHAR("bracketrighttp", "|", 9124)
-CHAR("bracketrightbp", "|", 9126)
+CHAR("bracketrightbt", "|", 9126)
CHAR("bracketrightex", "|", 9125)
CHAR("lt", ",-", 9127)
CHAR("bracelefttp", ",-", 9127)
CHAR("lk", "{", 9128)
CHAR("braceleftmid", "{", 9128)
CHAR("lb", "`-", 9129)
-CHAR("braceleftbp", "`-", 9129)
+CHAR("braceleftbt", "`-", 9129)
CHAR("braceleftex", "|", 9130)
CHAR("rt", "-.", 9131)
CHAR("bracerighttp", "-.", 9131)
CHAR("rk", "}", 9132)
CHAR("bracerightmid", "}", 9132)
CHAR("rb", "-\'", 9133)
-CHAR("bracerightbp", "-\'", 9133)
+CHAR("bracerightbt", "-\'", 9133)
CHAR("bracerightex", "|", 9130)
CHAR("parenlefttp", "/", 9115)
-CHAR("parenleftbp", "\\", 9117)
+CHAR("parenleftbt", "\\", 9117)
CHAR("parenleftex", "|", 9116)
CHAR("parenrighttp", "\\", 9118)
-CHAR("parenrightbp", "/", 9120)
+CHAR("parenrightbt", "/", 9120)
CHAR("parenrightex", "|", 9119)
/* Greek characters. */
@@ -281,10 +283,10 @@ CHAR("!=", "!=", 8800)
CHAR("==", "==", 8801)
CHAR("ne", "!==", 8802)
CHAR("=~", "=~", 8773)
-CHAR("-~", "-~", 8771)
+CHAR("|=", "-~", 8771)
CHAR("ap", "~", 8764)
CHAR("~~", "~~", 8776)
-CHAR("~=", "~=", 8780)
+CHAR("~=", "~=", 8776)
CHAR("pt", "oc", 8733)
CHAR("es", "{}", 8709)
CHAR("mo", "E", 8712)
@@ -357,7 +359,7 @@ CHAR("Fn", ",\bf", 402)
CHAR("ba", "|", 124)
CHAR("br", "|", 9474)
CHAR("ul", "_", 95)
-CHAR("rl", "-", 8254)
+CHAR("rn", "-", 8254)
CHAR("bb", "|", 166)
CHAR("sl", "/", 47)
CHAR("rs", "\\", 92)
diff --git a/compat_fts.c b/compat_fts.c
index d6e99e611aa8..194c56552460 100644
--- a/compat_fts.c
+++ b/compat_fts.c
@@ -6,8 +6,8 @@ int dummy;
#else
-/* $Id: compat_fts.c,v 1.6 2014/12/11 18:20:07 schwarze Exp $ */
-/* $OpenBSD: fts.c,v 1.49 2014/11/23 00:14:22 guenther Exp $ */
+/* $Id: compat_fts.c,v 1.8 2015/02/07 07:53:01 schwarze Exp $ */
+/* $OpenBSD: fts.c,v 1.50 2015/01/16 16:48:51 deraadt Exp $ */
/*-
* Copyright (c) 1990, 1993, 1994
@@ -38,7 +38,6 @@ int dummy;
* SUCH DAMAGE.
*/
-#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -51,6 +50,8 @@ int dummy;
#include <unistd.h>
#include "compat_fts.h"
+#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
+
static FTSENT *fts_alloc(FTS *, const char *, size_t);
static FTSENT *fts_build(FTS *);
static void fts_lfree(FTSENT *);
@@ -62,10 +63,12 @@ static unsigned short fts_stat(FTS *, FTSENT *);
static int fts_safe_changedir(FTS *, FTSENT *, int, const char *);
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
-#define MAX(a,b) (((a)>(b))?(a):(b))
#ifndef O_DIRECTORY
#define O_DIRECTORY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
#define CLR(opt) (sp->fts_options &= ~(opt))
#define ISSET(opt) (sp->fts_options & (opt))
@@ -97,7 +100,7 @@ fts_open(char * const *argv, int options, void *dummy)
* Start out with 1K of path space, and enough, in any case,
* to hold the user's paths.
*/
- if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX)))
+ if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX)))
goto mem1;
/* Allocate/initialize root's parent. */
diff --git a/compat_strtonum.c b/compat_strtonum.c
new file mode 100644
index 000000000000..628e5d51b86b
--- /dev/null
+++ b/compat_strtonum.c
@@ -0,0 +1,76 @@
+#include "config.h"
+
+#if HAVE_STRTONUM
+
+int dummy;
+
+#else
+
+/* $Id: compat_strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $ */
+/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ int error = 0;
+ char *ep;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval) {
+ error = INVALID;
+ } else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
+
+#endif /* !HAVE_STRTONUM */
diff --git a/configure b/configure
index 57ac898f248c..000d11ecc4cd 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -31,10 +31,6 @@ echo "config.log: writing..."
# Initialize all variables here,
# such that nothing can leak in from the environment.
-VERSION="1.13.2"
-echo "VERSION=\"${VERSION}\"" 1>&2
-echo "VERSION=\"${VERSION}\"" 1>&3
-
OSNAME=
CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make -f -`
@@ -56,6 +52,7 @@ HAVE_STRLCAT=
HAVE_STRLCPY=
HAVE_STRPTIME=
HAVE_STRSEP=
+HAVE_STRTONUM=
HAVE_WCHAR=
HAVE_SQLITE3=
@@ -70,6 +67,7 @@ INCLUDEDIR=
LIBDIR=
MANDIR=
EXAMPLEDIR=
+HOMEBREWDIR=
WWWPREFIX="/var/www"
HTDOCDIR=
@@ -176,6 +174,7 @@ runtest strlcat STRLCAT || true
runtest strlcpy STRLCPY || true
runtest strptime STRPTIME || true
runtest strsep STRSEP || true
+runtest strtonum STRTONUM || true
runtest wchar WCHAR || true
# --- sqlite3 ---
@@ -274,8 +273,8 @@ __HEREDOC__
[ ${HAVE_FGETLN} -eq 0 ] && echo "#include <stdio.h>"
echo
-echo "#define VERSION \"${VERSION}\""
[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\""
+[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\""
cat << __HEREDOC__
#define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN}
@@ -289,6 +288,7 @@ cat << __HEREDOC__
#define HAVE_STRLCPY ${HAVE_STRLCPY}
#define HAVE_STRPTIME ${HAVE_STRPTIME}
#define HAVE_STRSEP ${HAVE_STRSEP}
+#define HAVE_STRTONUM ${HAVE_STRTONUM}
#define HAVE_WCHAR ${HAVE_WCHAR}
#define HAVE_SQLITE3 ${HAVE_SQLITE3}
#define HAVE_SQLITE3_ERRSTR ${HAVE_SQLITE3_ERRSTR}
@@ -341,6 +341,9 @@ __HEREDOC__
[ ${HAVE_STRSEP} -eq 0 ] && \
echo "extern char *strsep(char **, const char *);"
+[ ${HAVE_STRTONUM} -eq 0 ] && \
+ echo "extern long long strtonum(const char *, long long, long long, const char **);"
+
echo
echo "#endif /* MANDOC_CONFIG_H */"
@@ -379,7 +382,6 @@ INSTALL_TARGETS="base-install"
[ ${BUILD_CGI} -gt 0 ] && INSTALL_TARGETS="${INSTALL_TARGETS} cgi-install"
cat << __HEREDOC__
-VERSION = ${VERSION}
BUILD_TARGETS = ${BUILD_TARGETS}
INSTALL_TARGETS = ${INSTALL_TARGETS}
CFLAGS = ${CFLAGS}
diff --git a/configure.local.example b/configure.local.example
index 037d48a48f99..bb391591cf5d 100644
--- a/configure.local.example
+++ b/configure.local.example
@@ -1,6 +1,6 @@
-# $Id: configure.local.example,v 1.2 2014/12/09 09:14:33 schwarze Exp $
+# $Id: configure.local.example,v 1.6 2015/02/16 14:56:22 schwarze Exp $
#
-# Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -74,6 +74,21 @@ LIBDIR="${PREFIX}/lib/mandoc"
MANDIR="${PREFIX}/man"
EXAMPLEDIR="${PREFIX}/share/examples/mandoc"
+# The man(1) utility needs to know where the manuals reside.
+# We know of two ways to tell it: via manpath(1) or man.conf(5).
+# The latter is used by OpenBSD and NetBSD, the former by most
+# other systems.
+
+# Force usage of manpath(1).
+# If it is not installed or not operational,
+# man(1), makewhatis(8), and apropos(1) will not work properly.
+HAVE_MANPATH=1
+
+# Force usage of man.conf(5).
+# If it does not exist or contains no valid configuration,
+# man(1), makewhatis(8), and apropos(1) will not work properly.
+HAVE_MANPATH=0
+
# Some distributions may want to avoid naming conflicts among manuals.
# If you want to change the names of installed section 7 manual pages,
# the following alternative names are suggested.
@@ -87,6 +102,15 @@ MANM_ROFF="mandoc_roff" # default is "roff"
MANM_EQN="mandoc_eqn" # default is "eqn"
MANM_TBL="mandoc_tbl" # default is "tbl"
+# Some distributions may want to avoid naming conflicts
+# with another man(1) utility.
+# If you want to change the name of the binary program,
+# the following alternative name is suggested.
+# Using a different name is possible as well.
+# This changes the name of the installed section 1 manual page as well.
+
+BINM_MAN=mman # default is "man"
+
# It is possible to change the utility program used for installation
# and the modes files are installed with. The defaults are:
@@ -121,38 +145,29 @@ DBLIB="-L/usr/local/lib -lsqlite3"
CFLAGS="${CFLAGS} -I/usr/local/include"
-# The man(1) utility needs to know where the manuals reside.
-# We know of two ways to tell it: via manpath(1) or man.conf(5).
-# The latter is used by OpenBSD and NetBSD, the former by most
-# other systems.
-
-# Force usage of manpath(1).
-# If it is not installed or not operational,
-# makewhatis(8) and apropos(1) will not work properly.
-
-HAVE_MANPATH=1
-
-# Force usage of man.conf(5).
-# If it does not exist or contains no valid configuration,
-# makewhatis(8) and apropos(1) will not work properly.
-
-HAVE_MANPATH=0
-
# Some distributions may want to avoid naming conflicts
-# with groff, man-db, or other tools.
-# If you want to change the names of binary programs,
+# with another implementation of apropos(1) and makewhatis(8).
+# If you want to change the names of the binary programs,
# the following alternative names are suggested.
# Using other names is possible as well.
# This changes the names of the installed section 1 and section 8
# manual pages as well.
-# It is possible to set only one or a few of these variables,
+# It is possible to set only one or two of these variables,
# there is no need to copy the whole block.
BINM_APROPOS=mapropos # default is "apropos"
-BINM_MAN=mman # default is "man"
BINM_WHATIS=mwhatis # default is "whatis"
BINM_MAKEWHATIS=mandocdb # default is "makewhatis"
+# When using the "homebrew" package manager on Mac OS X, the actual
+# manuals are located in a so-called "cellar" and only symlinked
+# into the manual trees. To allow mandoc to follow such symlinks,
+# you have to specify the physical location of the cellar as returned
+# by realpath(3), for example:
+
+PREFIX="/usr/local"
+HOMEBREWDIR="${PREFIX}/Cellar"
+
# --- user settings related man.cgi ------------------------------------
# By default, building man.cgi(8) is disabled. To enable it, copy
@@ -211,6 +226,7 @@ HAVE_STRLCAT=0
HAVE_STRLCPY=0
HAVE_STRPTIME=0
HAVE_STRSEP=0
+HAVE_STRTONUM=0
HAVE_SQLITE3=0
HAVE_SQLITE3_ERRSTR=0
diff --git a/demandoc.c b/demandoc.c
index e9aa62afb2ba..f515931d8b91 100644
--- a/demandoc.c
+++ b/demandoc.c
@@ -1,4 +1,4 @@
-/* $Id: demandoc.c,v 1.12 2014/10/28 17:36:19 schwarze Exp $ */
+/* $Id: demandoc.c,v 1.15 2015/02/10 08:05:30 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -44,11 +44,12 @@ main(int argc, char *argv[])
{
struct mparse *mp;
struct mchars *mchars;
- int ch, i, list;
+ int ch, fd, i, list;
extern int optind;
- progname = strrchr(argv[0], '/');
- if (progname == NULL)
+ if (argc < 1)
+ progname = "demandoc";
+ else if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
++progname;
@@ -78,15 +79,19 @@ main(int argc, char *argv[])
argv += optind;
mchars = mchars_alloc();
- mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, mchars, NULL);
+ mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, mchars, NULL);
assert(mp);
- if (0 == argc)
+ if (argc < 1)
pmandoc(mp, STDIN_FILENO, "<stdin>", list);
for (i = 0; i < argc; i++) {
mparse_reset(mp);
- pmandoc(mp, -1, argv[i], list);
+ if (mparse_open(mp, &fd, argv[i]) != MANDOCLEVEL_OK) {
+ perror(argv[i]);
+ continue;
+ }
+ pmandoc(mp, fd, argv[i], list);
}
mparse_free(mp);
@@ -108,16 +113,12 @@ pmandoc(struct mparse *mp, int fd, const char *fn, int list)
struct man *man;
int line, col;
- if (mparse_readfd(mp, fd, fn) >= MANDOCLEVEL_FATAL) {
- fprintf(stderr, "%s: Parse failure\n", fn);
- return;
- }
-
+ mparse_readfd(mp, fd, fn);
mparse_result(mp, &mdoc, &man, NULL);
line = 1;
col = 0;
- if (mdoc)
+ if (mdoc)
pmdoc(mdoc_node(mdoc), &line, &col, list);
else if (man)
pman(man_node(man), &line, &col, list);
@@ -167,7 +168,7 @@ again:
end = p - 1;
while (end > start)
- if ('.' == *end || ',' == *end ||
+ if ('.' == *end || ',' == *end ||
'\'' == *end || '"' == *end ||
')' == *end || '!' == *end ||
'?' == *end || ':' == *end ||
@@ -199,7 +200,7 @@ again:
/*
* Print the input word, skipping any special characters.
*/
- while ('\0' != *p)
+ while ('\0' != *p)
if ('\\' == *p) {
p++;
esc = mandoc_escape(&p, NULL, NULL);
@@ -220,7 +221,7 @@ pline(int line, int *linep, int *col, int list)
/*
* Print out as many lines as needed to reach parity with the
- * original input.
+ * original input.
*/
while (*linep < line) {
@@ -240,7 +241,7 @@ pmdoc(const struct mdoc_node *p, int *line, int *col, int list)
pline(p->line, line, col, list);
if (MDOC_TEXT == p->type)
pstring(p->string, p->pos, col, list);
- if (p->child)
+ if (p->child)
pmdoc(p->child, line, col, list);
}
}
@@ -254,7 +255,7 @@ pman(const struct man_node *p, int *line, int *col, int list)
pline(p->line, line, col, list);
if (MAN_TEXT == p->type)
pstring(p->string, p->pos, col, list);
- if (p->child)
+ if (p->child)
pman(p->child, line, col, list);
}
}
diff --git a/eqn.7 b/eqn.7
index c1e9c7634d4a..182fd4cfd719 100644
--- a/eqn.7
+++ b/eqn.7
@@ -1,4 +1,4 @@
-.\" $Id: eqn.7,v 1.31 2014/10/12 11:57:38 schwarze Exp $
+.\" $Id: eqn.7,v 1.33 2015/01/29 00:33:57 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: October 12 2014 $
+.Dd $Mdocdate: January 29 2015 $
.Dt EQN 7
.Os
.Sh NAME
@@ -122,7 +122,7 @@ lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta,
upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA,
THETA, UPSILON, XI, inter (intersection), union (union), prod (product),
int (integral), sum (summation), grad (gradient), del (vector
-differential), times (multiply), cdot (centre-dot), nothing (zero-width
+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), !=
@@ -457,11 +457,6 @@ The
and
.Cm down Ar n
commands are also ignored.
-.It
-Inline equations and the
-.Cm delim
-control statement are not yet implemented in
-.Xr mandoc 1 .
.El
.Sh SEE ALSO
.Xr mandoc 1 ,
diff --git a/eqn.c b/eqn.c
index a64031b29b9c..8737c6620f15 100644
--- a/eqn.c
+++ b/eqn.c
@@ -1,7 +1,7 @@
-/* $Id: eqn.c,v 1.56 2014/10/25 15:06:30 schwarze Exp $ */
+/* $Id: eqn.c,v 1.57 2015/01/28 21:11:53 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -31,8 +31,6 @@
#include "libmandoc.h"
#include "libroff.h"
-#define EQN_MSG(t, x) \
- mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
#define STRNEQ(p1, sz1, p2, sz2) \
((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
@@ -266,6 +264,21 @@ static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
{ ">=", ">=" }, /* EQNSYM_moreequal */
};
+static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
+static void eqn_box_free(struct eqn_box *);
+static struct eqn_box *eqn_box_makebinary(struct eqn_node *,
+ enum eqn_post, struct eqn_box *);
+static void eqn_def(struct eqn_node *);
+static struct eqn_def *eqn_def_find(struct eqn_node *, const char *, size_t);
+static void eqn_delim(struct eqn_node *);
+static const char *eqn_next(struct eqn_node *, char, size_t *, int);
+static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
+static const char *eqn_nexttok(struct eqn_node *, size_t *);
+static enum rofferr eqn_parse(struct eqn_node *, struct eqn_box *);
+static enum eqn_tok eqn_tok_parse(struct eqn_node *, char **);
+static void eqn_undef(struct eqn_node *);
+
+
enum rofferr
eqn_read(struct eqn_node **epp, int ln,
const char *p, int pos, int *offs)
@@ -365,7 +378,8 @@ again:
/* Prevent self-definitions. */
if (lim >= EQN_NEST_MAX) {
- EQN_MSG(MANDOCERR_ROFFLOOP, ep);
+ mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, NULL);
return(NULL);
}
@@ -406,7 +420,8 @@ again:
ep->cur++;
} else {
if (q)
- EQN_MSG(MANDOCERR_ARG_QUOTE, ep);
+ mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, NULL);
next = strchr(start, '\0');
*sz = (size_t)(next - start);
ep->cur += *sz;
@@ -600,23 +615,27 @@ eqn_delim(struct eqn_node *ep)
/*
* Undefine a previously-defined string.
*/
-static int
+static void
eqn_undef(struct eqn_node *ep)
{
const char *start;
struct eqn_def *def;
size_t sz;
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
- } else if (NULL != (def = eqn_def_find(ep, start, sz)))
- def->keysz = 0;
-
- return(1);
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "undef");
+ return;
+ }
+ if ((def = eqn_def_find(ep, start, sz)) == NULL)
+ return;
+ free(def->key);
+ free(def->val);
+ def->key = def->val = NULL;
+ def->keysz = def->valsz = 0;
}
-static int
+static void
eqn_def(struct eqn_node *ep)
{
const char *start;
@@ -624,9 +643,10 @@ eqn_def(struct eqn_node *ep)
struct eqn_def *def;
int i;
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "define");
+ return;
}
/*
@@ -646,47 +666,51 @@ eqn_def(struct eqn_node *ep)
ep->defs[i].key = ep->defs[i].val = NULL;
}
- ep->defs[i].keysz = sz;
- ep->defs[i].key = mandoc_realloc(
- ep->defs[i].key, sz + 1);
-
- memcpy(ep->defs[i].key, start, sz);
- ep->defs[i].key[(int)sz] = '\0';
- def = &ep->defs[i];
+ def = ep->defs + i;
+ free(def->key);
+ def->key = mandoc_strndup(start, sz);
+ def->keysz = sz;
}
start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
-
- if (NULL == start) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(-1);
+ if (start == NULL) {
+ mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
+ free(def->key);
+ free(def->val);
+ def->key = def->val = NULL;
+ def->keysz = def->valsz = 0;
+ return;
}
-
+ free(def->val);
+ def->val = mandoc_strndup(start, sz);
def->valsz = sz;
- def->val = mandoc_realloc(def->val, sz + 1);
- memcpy(def->val, start, sz);
- def->val[(int)sz] = '\0';
- return(1);
}
/*
* Recursively parse an eqn(7) expression.
*/
-static int
+static enum rofferr
eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
{
+ char sym[64];
+ struct eqn_box *cur;
+ const char *start;
char *p;
+ size_t i, sz;
enum eqn_tok tok, subtok;
enum eqn_post pos;
- struct eqn_box *cur;
- int rc, size;
- size_t i, sz;
- char sym[64];
- const char *start;
+ int size;
assert(parent != NULL);
+
+ /*
+ * Empty equation.
+ * Do not add it to the high-level syntax tree.
+ */
+
if (ep->data == NULL)
- return(-1);
+ return(ROFF_IGN);
next_tok:
tok = eqn_tok_parse(ep, &p);
@@ -694,20 +718,17 @@ next_tok:
this_tok:
switch (tok) {
case (EQN_TOK_UNDEF):
- if ((rc = eqn_undef(ep)) <= 0)
- return(rc);
+ eqn_undef(ep);
break;
case (EQN_TOK_NDEFINE):
case (EQN_TOK_DEFINE):
- if ((rc = eqn_def(ep)) <= 0)
- return(rc);
+ eqn_def(ep);
break;
case (EQN_TOK_TDEFINE):
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else if (NULL == eqn_next(ep,
- ep->data[(int)ep->cur], NULL, 0))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
+ if (eqn_nextrawtok(ep, NULL) == NULL ||
+ eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "tdefine");
break;
case (EQN_TOK_DELIM):
eqn_delim(ep);
@@ -1037,7 +1058,7 @@ this_tok:
* End of file!
* TODO: make sure we're not in an open subexpression.
*/
- return(0);
+ return(ROFF_EQN);
default:
assert(tok == EQN_TOK__MAX);
assert(NULL != p);
@@ -1081,7 +1102,7 @@ eqn_end(struct eqn_node **epp)
ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
ep->eqn.root->expectargs = UINT_MAX;
- return(0 == eqn_parse(ep, ep->eqn.root) ? ROFF_EQN : ROFF_IGN);
+ return(eqn_parse(ep, ep->eqn.root));
}
void
diff --git a/eqn_term.c b/eqn_term.c
index 010a152e2567..5f2818b4052b 100644
--- a/eqn_term.c
+++ b/eqn_term.c
@@ -1,7 +1,7 @@
-/* $Id: eqn_term.c,v 1.7 2014/10/12 14:49:39 schwarze Exp $ */
+/* $Id: eqn_term.c,v 1.8 2015/01/01 15:36:08 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -79,14 +79,17 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
bp->pos == EQNPOS_TO) ? "^" : "_");
p->flags |= TERMP_NOSPACE;
child = child->next;
- eqn_box(p, child);
- if (bp->pos == EQNPOS_FROMTO ||
- bp->pos == EQNPOS_SUBSUP) {
- p->flags |= TERMP_NOSPACE;
- term_word(p, "^");
- p->flags |= TERMP_NOSPACE;
- child = child->next;
+ if (child != NULL) {
eqn_box(p, child);
+ if (bp->pos == EQNPOS_FROMTO ||
+ bp->pos == EQNPOS_SUBSUP) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, "^");
+ p->flags |= TERMP_NOSPACE;
+ child = child->next;
+ if (child != NULL)
+ eqn_box(p, child);
+ }
}
} else {
child = bp->first;
diff --git a/example.style.css b/example.style.css
index 905412b52d31..90eb4a274f2e 100644
--- a/example.style.css
+++ b/example.style.css
@@ -1,4 +1,4 @@
-/* $Id: example.style.css,v 1.54 2014/12/10 22:19:45 schwarze Exp $ */
+/* $Id: example.style.css,v 1.55 2015/02/10 08:05:30 schwarze Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
* or -Txhtml output mode.
@@ -6,8 +6,8 @@
* See mdoc(7) and man(7) for macro explanations.
*/
-div.mandoc { min-width: 102ex;
- width: 102ex;
+div.mandoc { min-width: 102ex;
+ width: 102ex;
font-family: monospace; } /* This is the outer node of all mandoc -T[x]html documents. */
div.mandoc h1 { margin-bottom: 0ex; font-size: inherit; margin-left: -4ex; } /* Section header (Sh, SH). */
div.mandoc h2 { margin-bottom: 0ex; font-size: inherit; margin-left: -2ex; } /* Sub-section header (Ss, SS). */
@@ -39,7 +39,7 @@ div.mandoc .lit { font-style: normal; font-weight: normal; font-family: monosp
div.mandoc i.addr { font-weight: normal; } /* Address (Ad). */
div.mandoc i.arg { font-weight: normal; } /* Command argument (Ar). */
div.mandoc span.author { } /* Author name (An). */
-div.mandoc b.cmd { font-style: normal; } /* Command (Cm). */
+div.mandoc b.cmd { font-style: normal; } /* Command (Cm). */
div.mandoc b.config { font-style: normal; } /* Config statement (Cd). */
div.mandoc span.define { } /* Defines (Dv). */
div.mandoc span.desc { } /* Nd. After em-dash. */
diff --git a/gmdiff b/gmdiff
index 2c7ba4b343ca..ae27726ee525 100644
--- a/gmdiff
+++ b/gmdiff
@@ -19,20 +19,32 @@ if [ `id -u` -eq 0 ]; then
fi
if [ $# -eq 0 ]; then
- echo "usage: $0 manual_source_file ..."
+ echo "usage: $0 -h manual_source_file ..."
exit 1
fi
+if [ "X$1" = "X-h" ]; then
+ shift
+ export PATH="/usr/local/heirloom-doctools/bin:$PATH"
+ EQN="neqn"
+ ROFF="nroff"
+ MOPT="-Omdoc $MOPT"
+else
+ EQN="eqn -Tascii"
+ ROFF="groff -ww -Tascii -P -c"
+fi
+MOPT="-Werror $MOPT"
+
while [ -n "$1" ]; do
file=$1
shift
echo " ========== $file ========== "
- tbl $file | groff -mandoc -Tascii -P -c 2> /tmp/groff.err > /tmp/groff.out
- mandoc -Ios='OpenBSD ports' -Werror $file 2> /tmp/mandoc.err > /tmp/mandoc.out
- for i in groff mandoc; do
+ tbl $file | $EQN | $ROFF -mandoc 2> /tmp/roff.err > /tmp/roff.out
+ mandoc -Ios='OpenBSD ports' $MOPT $file 2> /tmp/mandoc.err > /tmp/mandoc.out
+ for i in roff mandoc; do
[[ -s /tmp/$i.err ]] && echo "$i errors:" && cat /tmp/$i.err
done
- diff -au /tmp/groff.out /tmp/mandoc.out 2>&1
+ diff -au /tmp/roff.out /tmp/mandoc.out 2>&1
done
exit 0
diff --git a/html.c b/html.c
index fe16224e8e36..487dacda947f 100644
--- a/html.c
+++ b/html.c
@@ -1,7 +1,7 @@
-/* $Id: html.c,v 1.183 2014/12/02 10:08:06 schwarze Exp $ */
+/* $Id: html.c,v 1.185 2015/01/21 20:33:25 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -121,7 +121,7 @@ static const char *const roffscales[SCALE_MAX] = {
};
static void bufncat(struct html *, const char *, size_t);
-static void print_ctag(struct html *, enum htmltag);
+static void print_ctag(struct html *, struct tag *);
static int print_escape(char);
static int print_encode(struct html *, const char *, int);
static void print_metaf(struct html *, enum mandoc_esc);
@@ -307,6 +307,8 @@ html_strlen(const char *cp)
case ESCAPE_NUMBERED:
/* FALLTHROUGH */
case ESCAPE_SPECIAL:
+ /* FALLTHROUGH */
+ case ESCAPE_OVERSTRIKE:
if (skip)
skip = 0;
else
@@ -433,6 +435,11 @@ print_encode(struct html *h, const char *p, int norecurse)
if ('\0' == *p)
nospace = 1;
continue;
+ case ESCAPE_OVERSTRIKE:
+ if (len == 0)
+ continue;
+ c = seq[len - 1];
+ break;
default:
continue;
}
@@ -511,14 +518,26 @@ print_otag(struct html *h, enum htmltag tag,
}
static void
-print_ctag(struct html *h, enum htmltag tag)
+print_ctag(struct html *h, struct tag *tag)
{
- printf("</%s>", htmltags[tag].name);
- if (HTML_CLRLINE & htmltags[tag].flags) {
+ /*
+ * Remember to close out and nullify the current
+ * meta-font and table, if applicable.
+ */
+ if (tag == h->metaf)
+ h->metaf = NULL;
+ if (tag == h->tblt)
+ h->tblt = NULL;
+
+ printf("</%s>", htmltags[tag->tag].name);
+ if (HTML_CLRLINE & htmltags[tag->tag].flags) {
h->flags |= HTML_NOSPACE;
putchar('\n');
}
+
+ h->tags.head = tag->next;
+ free(tag);
}
void
@@ -580,17 +599,7 @@ print_tagq(struct html *h, const struct tag *until)
struct tag *tag;
while ((tag = h->tags.head) != NULL) {
- /*
- * Remember to close out and nullify the current
- * meta-font and table, if applicable.
- */
- if (tag == h->metaf)
- h->metaf = NULL;
- if (tag == h->tblt)
- h->tblt = NULL;
- print_ctag(h, tag->tag);
- h->tags.head = tag->next;
- free(tag);
+ print_ctag(h, tag);
if (until && tag == until)
return;
}
@@ -604,17 +613,7 @@ print_stagq(struct html *h, const struct tag *suntil)
while ((tag = h->tags.head) != NULL) {
if (suntil && tag == suntil)
return;
- /*
- * Remember to close out and nullify the current
- * meta-font and table, if applicable.
- */
- if (tag == h->metaf)
- h->metaf = NULL;
- if (tag == h->tblt)
- h->tblt = NULL;
- print_ctag(h, tag->tag);
- h->tags.head = tag->next;
- free(tag);
+ print_ctag(h, tag);
}
}
diff --git a/libman.h b/libman.h
index b26c2b60efe2..8d115b3abeda 100644
--- a/libman.h
+++ b/libman.h
@@ -1,4 +1,4 @@
-/* $Id: libman.h,v 1.66 2014/12/01 04:05:31 schwarze Exp $ */
+/* $Id: libman.h,v 1.67 2014/12/28 14:42:27 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -23,6 +23,7 @@ enum man_next {
struct man {
struct mparse *parse; /* parse pointer */
+ const char *defos; /* default OS argument for .TH */
int quick; /* abort parse early */
int flags; /* parse flags */
#define MAN_ELINE (1 << 1) /* Next-line element scope. */
diff --git a/libmandoc.h b/libmandoc.h
index 6aa8b8dcf0f3..11feebdc1019 100644
--- a/libmandoc.h
+++ b/libmandoc.h
@@ -1,4 +1,4 @@
-/* $Id: libmandoc.h,v 1.51 2014/12/01 08:05:52 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.55 2015/01/15 04:26:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -24,8 +24,7 @@ enum rofferr {
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 */
- ROFF_ERR /* badness: puke and stop */
+ ROFF_EQN /* an equation was successfully parsed */
};
struct buf {
@@ -37,7 +36,6 @@ __BEGIN_DECLS
struct mparse;
struct mchars;
-enum mandocerr;
struct tbl_span;
struct eqn;
struct roff;
@@ -62,15 +60,16 @@ struct mdoc *mdoc_alloc(struct roff *, struct mparse *,
const char *, int);
void mdoc_reset(struct mdoc *);
int mdoc_parseln(struct mdoc *, int, char *, int);
-int mdoc_endparse(struct mdoc *);
+void mdoc_endparse(struct mdoc *);
void mdoc_addspan(struct mdoc *, const struct tbl_span *);
void mdoc_addeqn(struct mdoc *, const struct eqn *);
void man_free(struct man *);
-struct man *man_alloc(struct roff *, struct mparse *, int);
+struct man *man_alloc(struct roff *, struct mparse *,
+ const char *, int);
void man_reset(struct man *);
int man_parseln(struct man *, int, char *, int);
-int man_endparse(struct man *);
+void man_endparse(struct man *);
void man_addspan(struct man *, const struct tbl_span *);
void man_addeqn(struct man *, const struct eqn *);
diff --git a/libmdoc.h b/libmdoc.h
index b245213a8f22..527fe0270375 100644
--- a/libmdoc.h
+++ b/libmdoc.h
@@ -1,4 +1,4 @@
-/* $Id: libmdoc.h,v 1.96 2014/12/01 04:05:32 schwarze Exp $ */
+/* $Id: libmdoc.h,v 1.97 2015/02/02 04:26:44 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -106,7 +106,7 @@ struct mdoc_node *mdoc_block_alloc(struct mdoc *, int, int,
struct mdoc_node *mdoc_head_alloc(struct mdoc *, int, int, enum mdoct);
void mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct);
struct mdoc_node *mdoc_body_alloc(struct mdoc *, int, int, enum mdoct);
-void mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
+struct mdoc_node *mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
struct mdoc_node *, enum mdoc_endbody);
void mdoc_node_delete(struct mdoc *, struct mdoc_node *);
void mdoc_node_relink(struct mdoc *, struct mdoc_node *);
diff --git a/libroff.h b/libroff.h
index dd7ad75a947c..08ed1f7925d2 100644
--- a/libroff.h
+++ b/libroff.h
@@ -1,7 +1,7 @@
-/* $Id: libroff.h,v 1.33 2014/12/01 08:05:52 schwarze Exp $ */
+/* $Id: libroff.h,v 1.38 2015/01/30 04:11:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -34,8 +34,6 @@ struct tbl_node {
struct tbl_span *first_span;
struct tbl_span *current_span;
struct tbl_span *last_span;
- struct tbl_head *first_head;
- struct tbl_head *last_head;
struct tbl_node *next;
};
@@ -69,12 +67,12 @@ 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);
-int tbl_option(struct tbl_node *, int, const char *);
-int tbl_layout(struct tbl_node *, int, const char *);
-int tbl_data(struct tbl_node *, int, const char *);
-int tbl_cdata(struct tbl_node *, int, const char *);
+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);
const struct tbl_span *tbl_span(struct tbl_node *);
-void tbl_end(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 **);
void eqn_free(struct eqn_node *);
diff --git a/main.c b/main.c
index ec6e98006471..236c3c88d16a 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
-/* $Id: main.c,v 1.205 2014/12/11 19:19:35 schwarze Exp $ */
+/* $Id: main.c,v 1.222 2015/02/27 16:02:10 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -19,11 +19,13 @@
#include "config.h"
#include <sys/types.h>
+#include <sys/param.h> /* MACHINE */
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <glob.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -82,6 +84,13 @@ struct curparse {
char outopts[BUFSIZ]; /* buf of output opts */
};
+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 *,
+ const struct manpaths *, int, char**,
+ struct manpage **, size_t *);
static int koptions(int *, char *);
#if HAVE_SQLITE3
int mandocdb(int, char**);
@@ -91,13 +100,10 @@ static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
static void parse(struct curparse *, int,
const char *, enum mandoclevel *);
-#if HAVE_SQLITE3
static enum mandoclevel passthrough(const char *, int, int);
-#endif
static void spawn_pager(void);
static int toptions(struct curparse *, char *);
static void usage(enum argmode) __attribute__((noreturn));
-static void version(void) __attribute__((noreturn));
static int woptions(struct curparse *, char *);
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
@@ -114,14 +120,13 @@ main(int argc, char *argv[])
struct manpaths paths;
char *auxpaths;
char *defos;
-#if HAVE_SQLITE3
+ unsigned char *uc;
struct manpage *res, *resp;
char *conf_file, *defpaths;
size_t isec, i, sz;
int prio, best_prio, synopsis_only;
char sec;
-#endif
- enum mandoclevel rc;
+ enum mandoclevel rc, rctmp;
enum outmode outmode;
int fd;
int show_usage;
@@ -129,8 +134,9 @@ main(int argc, char *argv[])
int options;
int c;
- progname = strrchr(argv[0], '/');
- if (progname == NULL)
+ if (argc < 1)
+ progname = "mandoc";
+ else if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
++progname;
@@ -143,9 +149,7 @@ main(int argc, char *argv[])
/* Search options. */
memset(&paths, 0, sizeof(struct manpaths));
-#if HAVE_SQLITE3
conf_file = defpaths = NULL;
-#endif
auxpaths = NULL;
memset(&search, 0, sizeof(struct mansearch));
@@ -166,15 +170,13 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
- curp.wlevel = MANDOCLEVEL_FATAL;
+ curp.wlevel = MANDOCLEVEL_BADARG;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
defos = NULL;
use_pager = 1;
show_usage = 0;
-#if HAVE_SQLITE3
synopsis_only = 0;
-#endif
outmode = OUTMODE_DEF;
while (-1 != (c = getopt(argc, argv,
@@ -184,9 +186,7 @@ main(int argc, char *argv[])
outmode = OUTMODE_ALL;
break;
case 'C':
-#if HAVE_SQLITE3
conf_file = optarg;
-#endif
break;
case 'c':
use_pager = 0;
@@ -196,22 +196,20 @@ main(int argc, char *argv[])
break;
case 'h':
(void)strlcat(curp.outopts, "synopsis,", BUFSIZ);
-#if HAVE_SQLITE3
synopsis_only = 1;
-#endif
use_pager = 0;
outmode = OUTMODE_ALL;
break;
case 'I':
if (strncmp(optarg, "os=", 3)) {
fprintf(stderr,
- "%s: -I%s: Bad argument\n",
+ "%s: -I %s: Bad argument\n",
progname, optarg);
return((int)MANDOCLEVEL_BADARG);
}
if (defos) {
fprintf(stderr,
- "%s: -I%s: Duplicate argument\n",
+ "%s: -I %s: Duplicate argument\n",
progname, optarg);
return((int)MANDOCLEVEL_BADARG);
}
@@ -232,9 +230,7 @@ main(int argc, char *argv[])
outmode = OUTMODE_ALL;
break;
case 'M':
-#if HAVE_SQLITE3
defpaths = optarg;
-#endif
break;
case 'm':
auxpaths = optarg;
@@ -261,9 +257,6 @@ main(int argc, char *argv[])
case 'w':
outmode = OUTMODE_FLN;
break;
- case 'V':
- version();
- /* NOTREACHED */
default:
show_usage = 1;
break;
@@ -292,11 +285,11 @@ main(int argc, char *argv[])
/* Parse arguments. */
- argc -= optind;
- argv += optind;
-#if HAVE_SQLITE3
+ if (argc > 0) {
+ argc -= optind;
+ argv += optind;
+ }
resp = NULL;
-#endif
/*
* Quirks for help(1)
@@ -309,13 +302,19 @@ main(int argc, char *argv[])
argv = help_argv;
argc = 1;
}
- } else if (argv[0] != NULL &&
- isdigit((unsigned char)argv[0][0]) &&
- (argv[0][1] == '\0' || !strcmp(argv[0], "3p"))) {
- search.sec = argv[0];
+ } else if (argc > 1 &&
+ ((uc = argv[0]) != NULL) &&
+ ((isdigit(uc[0]) && (uc[1] == '\0' ||
+ (isalpha(uc[1]) && uc[2] == '\0'))) ||
+ (uc[0] == 'n' && uc[1] == '\0'))) {
+ search.sec = uc;
argv++;
argc--;
}
+ if (search.arch == NULL)
+ search.arch = getenv("MACHINE");
+ if (search.arch == NULL)
+ search.arch = MACHINE;
}
rc = MANDOCLEVEL_OK;
@@ -323,7 +322,6 @@ main(int argc, char *argv[])
/* man(1), whatis(1), apropos(1) */
if (search.argmode != ARG_FILE) {
-#if HAVE_SQLITE3
if (argc == 0)
usage(search.argmode);
@@ -334,15 +332,23 @@ main(int argc, char *argv[])
/* Access the mandoc database. */
manpath_parse(&paths, conf_file, defpaths, auxpaths);
+#if HAVE_SQLITE3
mansearch_setup(1);
if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
usage(search.argmode);
- resp = res;
+#else
+ if (search.argmode != ARG_NAME) {
+ fputs("mandoc: database support not compiled in\n",
+ stderr);
+ return((int)MANDOCLEVEL_BADARG);
+ }
+ sz = 0;
+#endif
+
+ if (sz == 0 && search.argmode == ARG_NAME)
+ fs_search(&search, &paths, argc, argv, &res, &sz);
if (sz == 0) {
- if (search.argmode == ARG_NAME)
- fprintf(stderr, "%s: No entry for %s "
- "in the manual.\n", progname, argv[0]);
rc = MANDOCLEVEL_BADARG;
goto out;
}
@@ -361,6 +367,7 @@ main(int argc, char *argv[])
/* Iterate all matching manuals. */
+ resp = res;
for (i = 0; i < sz; i++) {
if (outmode == OUTMODE_FLN)
puts(res[i].file);
@@ -390,21 +397,13 @@ main(int argc, char *argv[])
if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
goto out;
-#else
- fputs("mandoc: database support not compiled in\n",
- stderr);
- return((int)MANDOCLEVEL_BADARG);
-#endif
}
/* mandoc(1) */
- if ( ! moptions(&options, auxpaths))
+ if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
return((int)MANDOCLEVEL_BADARG);
- if (use_pager && isatty(STDOUT_FILENO))
- spawn_pager();
-
curp.mchars = mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg,
curp.mchars, defos);
@@ -415,37 +414,53 @@ main(int argc, char *argv[])
if (OUTT_MAN == curp.outtype)
mparse_keep(curp.mp);
- if (argc == 0)
+ if (argc < 1) {
+ if (use_pager && isatty(STDOUT_FILENO))
+ spawn_pager();
parse(&curp, STDIN_FILENO, "<stdin>", &rc);
+ }
- while (argc) {
-#if HAVE_SQLITE3
- if (resp != NULL) {
- rc = mparse_open(curp.mp, &fd, resp->file);
- if (fd == -1)
- /* nothing */;
+ while (argc > 0) {
+ rctmp = mparse_open(curp.mp, &fd,
+ resp != NULL ? resp->file : *argv);
+ if (rc < rctmp)
+ rc = rctmp;
+
+ if (fd != -1) {
+ if (use_pager && isatty(STDOUT_FILENO))
+ spawn_pager();
+ use_pager = 0;
+
+ if (resp == NULL)
+ parse(&curp, fd, *argv, &rc);
else if (resp->form & FORM_SRC) {
/* For .so only; ignore failure. */
chdir(paths.paths[resp->ipath]);
parse(&curp, fd, resp->file, &rc);
- } else
- rc = passthrough(resp->file, fd,
+ } else {
+ rctmp = passthrough(resp->file, fd,
synopsis_only);
- resp++;
- } else
-#endif
- {
- rc = mparse_open(curp.mp, &fd, *argv++);
- if (fd != -1)
- parse(&curp, fd, argv[-1], &rc);
- }
+ if (rc < rctmp)
+ rc = rctmp;
+ }
+
+ rctmp = mparse_wait(curp.mp);
+ if (rc < rctmp)
+ rc = rctmp;
- if (mparse_wait(curp.mp) != MANDOCLEVEL_OK)
- rc = MANDOCLEVEL_SYSERR;
+ if (argc > 1 && curp.outtype <= OUTT_UTF8)
+ ascii_sepline(curp.outdata);
+ }
if (MANDOCLEVEL_OK != rc && curp.wstop)
break;
- argc--;
+
+ if (resp != NULL)
+ resp++;
+ else
+ argv++;
+ if (--argc)
+ mparse_reset(curp.mp);
}
if (curp.outfree)
@@ -453,14 +468,14 @@ main(int argc, char *argv[])
mparse_free(curp.mp);
mchars_free(curp.mchars);
-#if HAVE_SQLITE3
out:
if (search.argmode != ARG_FILE) {
manpath_free(&paths);
+#if HAVE_SQLITE3
mansearch_free(res, sz);
mansearch_setup(0);
- }
#endif
+ }
free(defos);
@@ -468,35 +483,29 @@ out:
}
static void
-version(void)
-{
-
- printf("mandoc %s\n", VERSION);
- exit((int)MANDOCLEVEL_OK);
-}
-
-static void
usage(enum argmode argmode)
{
switch (argmode) {
case ARG_FILE:
- fputs("usage: mandoc [-acfhklV] [-Ios=name] "
+ fputs("usage: mandoc [-acfhkl] [-Ios=name] "
"[-Kencoding] [-mformat] [-Ooption]\n"
"\t [-Toutput] [-Wlevel] [file ...]\n", stderr);
break;
case ARG_NAME:
- fputs("usage: man [-acfhklVw] [-C file] "
- "[-M path] [-m path] [-S arch] [-s section]\n"
+ fputs("usage: man [-acfhklw] [-C file] [-I os=name] "
+ "[-K encoding] [-M path] [-m path]\n"
+ "\t [-O option=value] [-S subsection] [-s section] "
+ "[-T output] [-W level]\n"
"\t [section] name ...\n", stderr);
break;
case ARG_WORD:
- fputs("usage: whatis [-acfhklVw] [-C file] "
+ fputs("usage: whatis [-acfhklw] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] name ...\n", stderr);
break;
case ARG_EXPR:
- fputs("usage: apropos [-acfhklVw] [-C file] "
+ fputs("usage: apropos [-acfhklw] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] expression ...\n", stderr);
break;
@@ -504,6 +513,108 @@ usage(enum argmode argmode)
exit((int)MANDOCLEVEL_BADARG);
}
+static int
+fs_lookup(const struct manpaths *paths, size_t ipath,
+ const char *sec, const char *arch, const char *name,
+ struct manpage **res, size_t *ressz)
+{
+ glob_t globinfo;
+ struct manpage *page;
+ char *file;
+ int form, globres;
+
+ form = FORM_SRC;
+ mandoc_asprintf(&file, "%s/man%s/%s.%s",
+ paths->paths[ipath], sec, name, sec);
+ if (access(file, R_OK) != -1)
+ goto found;
+ free(file);
+
+ mandoc_asprintf(&file, "%s/cat%s/%s.0",
+ paths->paths[ipath], sec, name);
+ if (access(file, R_OK) != -1) {
+ form = FORM_CAT;
+ goto found;
+ }
+ free(file);
+
+ if (arch != NULL) {
+ mandoc_asprintf(&file, "%s/man%s/%s/%s.%s",
+ paths->paths[ipath], sec, arch, name, sec);
+ if (access(file, R_OK) != -1)
+ goto found;
+ free(file);
+ }
+
+ mandoc_asprintf(&file, "%s/man%s/%s.*",
+ paths->paths[ipath], sec, name);
+ globres = glob(file, 0, NULL, &globinfo);
+ if (globres != 0 && globres != GLOB_NOMATCH)
+ fprintf(stderr, "%s: %s: glob: %s\n",
+ progname, file, strerror(errno));
+ free(file);
+ if (globres == 0)
+ file = mandoc_strdup(*globinfo.gl_pathv);
+ globfree(&globinfo);
+ if (globres != 0)
+ return(0);
+
+found:
+#if HAVE_SQLITE3
+ fprintf(stderr, "%s: outdated mandoc.db lacks %s(%s) entry,\n"
+ " consider running # makewhatis %s\n",
+ progname, name, sec, paths->paths[ipath]);
+#endif
+
+ *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
+ page = *res + (*ressz - 1);
+ page->file = file;
+ page->names = NULL;
+ page->output = NULL;
+ page->ipath = ipath;
+ page->bits = NAME_FILE & NAME_MASK;
+ page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
+ page->form = form;
+ return(1);
+}
+
+static void
+fs_search(const struct mansearch *cfg, const struct manpaths *paths,
+ int argc, char **argv, struct manpage **res, size_t *ressz)
+{
+ const char *const sections[] =
+ {"1", "8", "6", "2", "3", "3p", "5", "7", "4", "9"};
+ const size_t nsec = sizeof(sections)/sizeof(sections[0]);
+
+ size_t ipath, isec, lastsz;
+
+ assert(cfg->argmode == ARG_NAME);
+
+ *res = NULL;
+ *ressz = lastsz = 0;
+ while (argc) {
+ for (ipath = 0; ipath < paths->sz; ipath++) {
+ if (cfg->sec != NULL) {
+ if (fs_lookup(paths, ipath, cfg->sec,
+ cfg->arch, *argv, res, ressz) &&
+ cfg->firstmatch)
+ return;
+ } else for (isec = 0; isec < nsec; isec++)
+ if (fs_lookup(paths, ipath, sections[isec],
+ cfg->arch, *argv, res, ressz) &&
+ cfg->firstmatch)
+ return;
+ }
+ if (*ressz == lastsz)
+ fprintf(stderr,
+ "%s: No entry for %s in the manual.\n",
+ progname, *argv);
+ lastsz = *ressz;
+ argv++;
+ argc--;
+ }
+}
+
static void
parse(struct curparse *curp, int fd, const char *file,
enum mandoclevel *level)
@@ -519,11 +630,6 @@ parse(struct curparse *curp, int fd, const char *file,
rc = mparse_readfd(curp->mp, fd, file);
- /* Stop immediately if the parse has failed. */
-
- if (MANDOCLEVEL_FATAL <= rc)
- goto cleanup;
-
/*
* With -Wstop and warnings or errors of at least the requested
* level, do not produce output.
@@ -609,15 +715,11 @@ parse(struct curparse *curp, int fd, const char *file,
if (mdoc && curp->outmdoc)
(*curp->outmdoc)(curp->outdata, mdoc);
- cleanup:
-
- mparse_reset(curp->mp);
-
+cleanup:
if (*level < rc)
*level = rc;
}
-#if HAVE_SQLITE3
static enum mandoclevel
passthrough(const char *file, int fd, int synopsis_only)
{
@@ -631,6 +733,8 @@ passthrough(const char *file, int fd, int synopsis_only)
ssize_t nw;
int print;
+ fflush(stdout);
+
if ((stream = fdopen(fd, "r")) == NULL) {
close(fd);
syscall = "fdopen";
@@ -681,7 +785,6 @@ fail:
progname, file, syscall, strerror(errno));
return(MANDOCLEVEL_SYSERR);
}
-#endif
static int
koptions(int *options, char *arg)
@@ -696,7 +799,7 @@ koptions(int *options, char *arg)
} else if ( ! strcmp(arg, "us-ascii")) {
*options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
} else {
- fprintf(stderr, "%s: -K%s: Bad argument\n",
+ fprintf(stderr, "%s: -K %s: Bad argument\n",
progname, arg);
return(0);
}
@@ -716,7 +819,7 @@ moptions(int *options, char *arg)
else if (0 == strcmp(arg, "an"))
*options |= MPARSE_MAN;
else {
- fprintf(stderr, "%s: -m%s: Bad argument\n",
+ fprintf(stderr, "%s: -m %s: Bad argument\n",
progname, arg);
return(0);
}
@@ -750,7 +853,7 @@ toptions(struct curparse *curp, char *arg)
else if (0 == strcmp(arg, "pdf"))
curp->outtype = OUTT_PDF;
else {
- fprintf(stderr, "%s: -T%s: Bad argument\n",
+ fprintf(stderr, "%s: -T %s: Bad argument\n",
progname, arg);
return(0);
}
@@ -762,14 +865,15 @@ static int
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
- const char *toks[6];
+ const char *toks[7];
toks[0] = "stop";
toks[1] = "all";
toks[2] = "warning";
toks[3] = "error";
- toks[4] = "fatal";
- toks[5] = NULL;
+ toks[4] = "unsupp";
+ toks[5] = "fatal";
+ toks[6] = NULL;
while (*arg) {
o = arg;
@@ -786,10 +890,13 @@ woptions(struct curparse *curp, char *arg)
curp->wlevel = MANDOCLEVEL_ERROR;
break;
case 4:
- curp->wlevel = MANDOCLEVEL_FATAL;
+ curp->wlevel = MANDOCLEVEL_UNSUPP;
+ break;
+ case 5:
+ curp->wlevel = MANDOCLEVEL_BADARG;
break;
default:
- fprintf(stderr, "%s: -W%s: Bad argument\n",
+ fprintf(stderr, "%s: -W %s: Bad argument\n",
progname, o);
return(0);
}
diff --git a/main.h b/main.h
index 147c22f59464..9b04a7816aec 100644
--- a/main.h
+++ b/main.h
@@ -1,6 +1,7 @@
-/* $Id: main.h,v 1.19 2014/12/01 08:05:52 schwarze Exp $ */
+/* $Id: main.h,v 1.20 2014/12/31 16:52:40 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -45,6 +46,7 @@ void *locale_alloc(const struct mchars *, char *);
void *utf8_alloc(const struct mchars *, char *);
void *ascii_alloc(const struct mchars *, char *);
void ascii_free(void *);
+void ascii_sepline(void *);
void *pdf_alloc(const struct mchars *, char *);
void *ps_alloc(const struct mchars *, char *);
diff --git a/man-cgi.css b/man-cgi.css
index 5300267cfbc1..256e8c6693ef 100644
--- a/man-cgi.css
+++ b/man-cgi.css
@@ -1,10 +1,10 @@
body { font-family: Helvetica, Arial, sans-serif; }
-body > div { padding-left: 2em;
+body > div { padding-left: 2em;
padding-top: 1em; }
-body > div#mancgi { padding-left: 0em;
+body > div#mancgi { padding-left: 0em;
padding-top: 0em; }
body > div.results { font-size: smaller; }
-#mancgi fieldset { text-align: center;
+#mancgi fieldset { text-align: center;
border: thin solid silver;
border-radius: 1em;
font-size: small; }
diff --git a/man.1 b/man.1
index 0d26fd281e79..85802967e627 100644
--- a/man.1
+++ b/man.1
@@ -1,9 +1,9 @@
-.\" $Id: man.1,v 1.7 2014/11/11 02:43:41 schwarze Exp $
+.\" $Id: man.1,v 1.13 2015/02/16 16:23:54 schwarze Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
-.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
-.Dd $Mdocdate: November 11 2014 $
+.Dd $Mdocdate: February 16 2015 $
.Dt MAN 1
.Os
.Sh NAME
@@ -39,12 +39,17 @@
.Nd display manual pages
.Sh SYNOPSIS
.Nm man
-.Op Fl acfhklVw
+.Op Fl acfhklw
.Op Fl C Ar file
+.Op Fl I Cm os Ns = Ns Ar name
+.Op Fl K Ar encoding
.Op Fl M Ar path
.Op Fl m Ar path
+.Op Fl O Ar option Ns = Ns Ar value
.Op Fl S Ar subsection
.Op Fl s Ar section
+.Op Fl T Ar output
+.Op Fl W Ar level
.Op Ar section
.Ar name ...
.Sh DESCRIPTION
@@ -95,12 +100,34 @@ This overrides any earlier
and
.Fl l
options.
+.It Fl I Cm os Ns = Ns Ar name
+Override the default operating system
+.Ar name
+for the
+.Xr mdoc 7
+.Ic \&Os
+and for the
+.Xr man 7
+.Ic \&TH
+macro.
.It Fl h
Display only the SYNOPSIS lines of the requested manual pages.
Implies
.Fl a
and
.Fl c .
+.It Fl K Ar encoding
+Specify the input encoding.
+The supported
+.Ar encoding
+arguments are
+.Cm us-ascii ,
+.Cm iso-8859-1 ,
+and
+.Cm utf-8 .
+By default, the encoding is automatically detected as described in the
+.Xr mandoc 1
+manual.
.It Fl k
A synonym for
.Xr apropos 1 .
@@ -173,6 +200,11 @@ are specified by the
line in the
.Nm
configuration file.
+.It Fl O Ar option Ns = Ns Ar value
+Comma-separated output options.
+For each output format, the available options are described in the
+.Xr mandoc 1
+manual.
.It Fl S Ar subsection
Restricts the directories that
.Nm
@@ -242,8 +274,43 @@ specifies the possible
.Ar section
values, and their search order.
Additional sections may be specified.
-.It Fl V
-Print version and exit.
+.It Fl T Ar output
+Select the output format.
+The default is
+.Cm locale .
+The other output modes
+.Cm ascii ,
+.Cm html ,
+.Cm lint ,
+.Cm man ,
+.Cm pdf ,
+.Cm ps ,
+.Cm tree ,
+and
+.Cm utf8
+are described in the
+.Xr mandoc 1
+manual.
+.It Fl W Ar level
+Specify the minimum message
+.Ar level
+to be reported on the standard error output and to affect the exit status.
+The
+.Ar level
+can be
+.Cm warning ,
+.Cm error ,
+or
+.Cm unsupp ;
+.Cm all
+is an alias for
+.Cm warning .
+By default,
+.Nm
+is silent.
+See the
+.Xr mandoc 1
+manual for details.
.It Fl w
List the pathnames of the manual pages which
.Nm
@@ -254,14 +321,6 @@ and
combination.
.El
.Pp
-The
-.Nm
-utility also supports the options
-.Fl IKOTW
-described in the
-.Xr mandoc 1
-manual.
-.Pp
Guidelines for writing
man pages can be found in
.Xr mdoc 7 .
@@ -355,7 +414,7 @@ utility is compliant with the
specification.
.Pp
The flags
-.Op Fl aCcfhMmSsw ,
+.Op Fl aCcfhIKlMmOSsTWw ,
as well as the environment variables
.Ev MACHINE ,
.Ev MANPAGER ,
diff --git a/man.7 b/man.7
index 4b64d7f442f4..bfeec51650e4 100644
--- a/man.7
+++ b/man.7
@@ -1,7 +1,7 @@
-.\" $Id: man.7,v 1.127 2014/06/22 16:39:45 schwarze Exp $
+.\" $Id: man.7,v 1.132 2015/01/29 00:33:57 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
@@ -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 22 2014 $
+.Dd $Mdocdate: January 29 2015 $
.Dt MAN 7
.Os
.Sh NAME
@@ -369,11 +369,11 @@ Begin a paragraph whose initial output line is left-justified, but
subsequent output lines are indented, with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&HP
-.Op Cm width
+.Op Ar width
.Ed
.Pp
The
-.Cm width
+.Ar width
argument is a
.Xr roff 7
scaling width.
@@ -413,11 +413,11 @@ and
Begin an indented paragraph with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&IP
-.Op Cm head Op Cm width
+.Op Ar head Op Ar width
.Ed
.Pp
The
-.Cm width
+.Ar width
argument is a
.Xr roff 7
scaling width defining the left margin.
@@ -425,7 +425,7 @@ It's saved for later paragraph left-margins; if unspecified, the saved or
default width is used.
.Pp
The
-.Cm head
+.Ar head
argument is used as a leading term, flushed to the left margin.
This is useful for bulleted paragraphs and so on.
.Pp
@@ -470,13 +470,13 @@ This is a non-standard GNU extension, included only for compatibility.
It has the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&OP
-.Cm key Op Cm value
+.Ar key Op Ar value
.Ed
.Pp
The
-.Cm key
+.Ar key
is usually a command-line flag and
-.Cm value
+.Ar value
its argument.
.Ss \&P
Synonym for
@@ -495,11 +495,11 @@ Specify the vertical space to be inserted before each new paragraph.
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&PD
-.Op Cm height
+.Op Ar height
.Ed
.Pp
The
-.Cm height
+.Ar height
argument is a
.Xr roff 7
scaling width.
@@ -555,9 +555,29 @@ and
.Ss \&RE
Explicitly close out the scope of a prior
.Sx \&RS .
-The default left margin is restored to the state of the original
+The default left margin is restored to the state before that
.Sx \&RS
invocation.
+.Pp
+The syntax is as follows:
+.Bd -filled -offset indent
+.Pf \. Sx \&RE
+.Op Ar level
+.Ed
+.Pp
+Without an argument, the most recent
+.Sx \&RS
+block is closed out.
+If
+.Ar level
+is 1, all open
+.Sx \&RS
+blocks are closed out.
+Otherwise,
+.Ar level No \(mi 1
+nested
+.Sx \&RS
+blocks remain open.
.Ss \&RI
Text is rendered alternately in roman (the default font) and italics.
Whitespace between arguments is omitted in output.
@@ -578,11 +598,11 @@ Temporarily reset the default left margin.
This has the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&RS
-.Op Cm width
+.Op Ar width
.Ed
.Pp
The
-.Cm width
+.Ar width
argument is a
.Xr roff 7
scaling width.
@@ -607,7 +627,8 @@ The scope of a sub-section is closed by a subsequent sub-section,
section, or end of file.
The paragraph left-margin width is reset to the default.
.Ss \&TH
-Sets the title of the manual page with the following syntax:
+Sets the title of the manual page for use in the page header
+and footer with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&TH
.Ar title section date
@@ -629,6 +650,11 @@ is empty or not specified, the current date is used.
The optional
.Ar source
string specifies the organisation providing the utility.
+When unspecified,
+.Xr mandoc 1
+uses its
+.Fl Ios
+argument.
The
.Ar volume
string replaces the default rendered volume, which is dictated by the
@@ -645,11 +671,11 @@ Subsequent output lines are indented.
The syntax is as follows:
.Bd -filled -offset indent
.Pf \. Sx \&TP
-.Op Cm width
+.Op Ar width
.Ed
.Pp
The
-.Cm width
+.Ar width
argument is a
.Xr roff 7
scaling width.
@@ -694,15 +720,13 @@ End literal mode begun by
.Ss \&in
Indent relative to the current indentation:
.Pp
-.D1 Pf \. Sx \&in Op Cm width
+.D1 Pf \. Sx \&in Op Ar width
.Pp
If
-.Cm width
+.Ar width
is signed, the new offset is relative.
Otherwise, it is absolute.
This value is reset upon the next paragraph, section, or sub-section.
-.Ss \&na
-Don't align to the right margin.
.Ss \&nf
Begin literal mode: all subsequent free-form lines have their end of
line boundaries preserved.
@@ -716,11 +740,11 @@ or
Insert vertical spaces into output with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&sp
-.Op Cm height
+.Op Ar height
.Ed
.Pp
The
-.Cm height
+.Ar height
argument is a scaling width as described in
.Xr roff 7 .
If 0, this is equivalent to the
@@ -754,10 +778,9 @@ is equivalent to
If next-line macros are invoked consecutively, only the last is used.
If a next-line macro is followed by a non-next-line macro, an error is
raised, except for
-.Sx \&br ,
-.Sx \&sp ,
+.Sx \&br
and
-.Sx \&na .
+.Sx \&sp .
.Pp
The syntax is as follows:
.Bd -literal -offset indent
@@ -788,7 +811,6 @@ The syntax is as follows:
.It Sx \&br Ta 0 Ta current Ta compat
.It Sx \&fi Ta 0 Ta current Ta compat
.It Sx \&in Ta 1 Ta current Ta compat
-.It Sx \&na Ta 0 Ta current Ta compat
.It Sx \&nf Ta 0 Ta current Ta compat
.It Sx \&sp Ta 1 Ta current Ta compat
.El
@@ -872,53 +894,6 @@ until the end of the macro scope.
Note that macros like
.Sx \&BR
open and close a font scope for each argument.
-.Sh COMPATIBILITY
-This section mentions some areas of questionable portability between
-implementations of the
-.Nm
-language.
-More incompatibilities exist.
-.Pp
-.Bl -dash -compact
-.It
-Do not depend on
-.Sx \&SH
-or
-.Sx \&SS
-to close out a literal context opened with
-.Sx \&nf .
-This behaviour may not be portable.
-.It
-troff suppresses a newline before
-.Sq \(aq
-macro output; in mandoc, it is an alias for the standard
-.Sq \&.
-control character.
-.It
-In page header lines, GNU troff versions up to and including 1.21
-only print
-.Ar volume
-names explicitly specified in the
-.Sx \&TH
-macro; mandoc and newer groff print the default volume name
-corresponding to the
-.Ar section
-number when no
-.Ar volume
-is given, like in
-.Xr mdoc 7 .
-.El
-.Pp
-The
-.Sx EE ,
-.Sx EX ,
-.Sx OP ,
-.Sx UE ,
-and
-.Sx UR
-macros are part of the GNU extended
-.Nm
-macro set, and may not be portable to non-GNU troff implementations.
.Sh SEE ALSO
.Xr man 1 ,
.Xr mandoc 1 ,
diff --git a/man.c b/man.c
index 048db26f9a2b..4e7a398d9bbe 100644
--- a/man.c
+++ b/man.c
@@ -1,7 +1,7 @@
-/* $Id: man.c,v 1.145 2014/11/28 06:27:05 schwarze Exp $ */
+/* $Id: man.c,v 1.149 2015/01/30 21:28:46 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -39,7 +39,7 @@ const char *const __man_macronames[MAN_MAX] = {
"IP", "HP", "SM", "SB",
"BI", "IB", "BR", "RB",
"R", "B", "I", "IR",
- "RI", "na", "sp", "nf",
+ "RI", "sp", "nf",
"fi", "RE", "RS", "DT",
"UC", "PD", "AT", "in",
"ft", "OP", "EX", "EE",
@@ -48,6 +48,10 @@ const char *const __man_macronames[MAN_MAX] = {
const char * const *man_macronames = __man_macronames;
+static void man_alloc1(struct man *);
+static void man_breakscope(struct man *, enum mant);
+static void man_descope(struct man *, int, int);
+static void man_free1(struct man *);
static struct man_node *man_node_alloc(struct man *, int, int,
enum man_type, enum mant);
static void man_node_append(struct man *, struct man_node *);
@@ -56,9 +60,6 @@ static void man_node_unlink(struct man *,
struct man_node *);
static int man_ptext(struct man *, int, char *, int);
static int man_pmacro(struct man *, int, char *, int);
-static void man_free1(struct man *);
-static void man_alloc1(struct man *);
-static void man_descope(struct man *, int, int);
const struct man_node *
@@ -92,7 +93,8 @@ man_free(struct man *man)
}
struct man *
-man_alloc(struct roff *roff, struct mparse *parse, int quick)
+man_alloc(struct roff *roff, struct mparse *parse,
+ const char *defos, int quick)
{
struct man *p;
@@ -100,6 +102,7 @@ man_alloc(struct roff *roff, struct mparse *parse, int quick)
man_hash_init();
p->parse = parse;
+ p->defos = defos;
p->quick = quick;
p->roff = roff;
@@ -107,12 +110,11 @@ man_alloc(struct roff *roff, struct mparse *parse, int quick)
return(p);
}
-int
+void
man_endparse(struct man *man)
{
man_macroend(man);
- return(1);
}
int
@@ -336,6 +338,7 @@ man_addspan(struct man *man, const struct tbl_span *sp)
{
struct man_node *n;
+ man_breakscope(man, MAN_MAX);
n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
n->span = sp;
man_node_append(man, n);
@@ -492,62 +495,11 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
ln, offs - 1, NULL);
/*
- * Remove prior ELINE macro, as it's being clobbered by a new
- * macro. Note that NSCOPED macros do not close out ELINE
- * macros---they don't print text---so we let those slip by.
+ * Some macros break next-line scopes; otherwise, remember
+ * whether we are in next-line scope for a block head.
*/
- if ( ! (man_macros[tok].flags & MAN_NSCOPED) &&
- man->flags & MAN_ELINE) {
- n = man->last;
- assert(MAN_TEXT != n->type);
-
- /* Remove repeated NSCOPED macros causing ELINE. */
-
- if (man_macros[n->tok].flags & MAN_NSCOPED)
- n = n->parent;
-
- mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line,
- n->pos, "%s breaks %s", man_macronames[tok],
- man_macronames[n->tok]);
-
- man_node_delete(man, n);
- man->flags &= ~MAN_ELINE;
- }
-
- /*
- * Remove prior BLINE macro that is being clobbered.
- */
- if ((man->flags & MAN_BLINE) &&
- (man_macros[tok].flags & MAN_BSCOPE)) {
- n = man->last;
-
- /* Might be a text node like 8 in
- * .TP 8
- * .SH foo
- */
- if (n->type == MAN_TEXT)
- n = n->parent;
-
- /* Remove element that didn't end BLINE, if any. */
- if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
- n = n->parent;
-
- assert(n->type == MAN_HEAD);
- n = n->parent;
- assert(n->type == MAN_BLOCK);
- assert(man_macros[n->tok].flags & MAN_SCOPED);
-
- mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line,
- n->pos, "%s breaks %s", man_macronames[tok],
- man_macronames[n->tok]);
-
- man_node_delete(man, n);
- man->flags &= ~MAN_BLINE;
- }
-
- /* Remember whether we are in next-line scope for a block head. */
-
+ man_breakscope(man, tok);
bline = man->flags & MAN_BLINE;
/* Call to handler... */
@@ -582,6 +534,62 @@ man_pmacro(struct man *man, int ln, char *buf, int offs)
return(1);
}
+void
+man_breakscope(struct man *man, enum mant tok)
+{
+ struct man_node *n;
+
+ /*
+ * An element next line scope is open,
+ * and the new macro is not allowed inside elements.
+ * Delete the element that is being broken.
+ */
+
+ if (man->flags & MAN_ELINE && (tok == MAN_MAX ||
+ ! (man_macros[tok].flags & MAN_NSCOPED))) {
+ n = man->last;
+ assert(n->type != MAN_TEXT);
+ if (man_macros[n->tok].flags & MAN_NSCOPED)
+ n = n->parent;
+
+ mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
+ n->line, n->pos, "%s breaks %s",
+ tok == MAN_MAX ? "TS" : man_macronames[tok],
+ man_macronames[n->tok]);
+
+ man_node_delete(man, n);
+ man->flags &= ~MAN_ELINE;
+ }
+
+ /*
+ * A block header next line scope is open,
+ * and the new macro is not allowed inside block headers.
+ * Delete the block that is being broken.
+ */
+
+ if (man->flags & MAN_BLINE && (tok == MAN_MAX ||
+ man_macros[tok].flags & MAN_BSCOPE)) {
+ n = man->last;
+ if (n->type == MAN_TEXT)
+ n = n->parent;
+ if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
+ n = n->parent;
+
+ assert(n->type == MAN_HEAD);
+ n = n->parent;
+ assert(n->type == MAN_BLOCK);
+ assert(man_macros[n->tok].flags & MAN_SCOPED);
+
+ mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
+ n->line, n->pos, "%s breaks %s",
+ tok == MAN_MAX ? "TS" : man_macronames[tok],
+ man_macronames[n->tok]);
+
+ man_node_delete(man, n);
+ man->flags &= ~MAN_BLINE;
+ }
+}
+
/*
* Unlink a node from its context. If "man" is provided, the last parse
* point will also be adjusted accordingly.
diff --git a/man.h b/man.h
index 08bfcc8e4de5..9e8eb03e5717 100644
--- a/man.h
+++ b/man.h
@@ -1,4 +1,4 @@
-/* $Id: man.h,v 1.67 2014/12/01 04:05:32 schwarze Exp $ */
+/* $Id: man.h,v 1.69 2015/01/24 02:41:49 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -38,7 +38,6 @@ enum mant {
MAN_I,
MAN_IR,
MAN_RI,
- MAN_na,
MAN_sp,
MAN_nf,
MAN_fi,
@@ -99,6 +98,7 @@ struct man_node {
struct man_node *body; /* BLOCK node BODY ptr */
const struct tbl_span *span; /* TBL */
const struct eqn *eqn; /* EQN */
+ int aux; /* decoded node data, type-dependent */
};
/* Names of macros. Index is enum mant. */
diff --git a/man_html.c b/man_html.c
index 1455e1e4aec9..0e0fad9e3d73 100644
--- a/man_html.c
+++ b/man_html.c
@@ -1,7 +1,7 @@
-/* $Id: man_html.c,v 1.107 2014/12/04 02:05:42 schwarze Exp $ */
+/* $Id: man_html.c,v 1.111 2015/02/10 08:05:30 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -100,7 +100,6 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_I_pre, NULL }, /* I */
{ man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */
- { man_ign_pre, NULL }, /* na */
{ man_br_pre, NULL }, /* sp */
{ man_literal_pre, NULL }, /* nf */
{ man_literal_pre, NULL }, /* fi */
@@ -193,9 +192,10 @@ static void
print_man_nodelist(MAN_ARGS)
{
- print_man_node(man, n, mh, h);
- if (n->next)
- print_man_nodelist(man, n->next, mh, h);
+ while (n != NULL) {
+ print_man_node(man, n, mh, h);
+ n = n->next;
+ }
}
static void
@@ -216,7 +216,7 @@ print_man_node(MAN_ARGS)
print_paragraph(h);
return;
}
- if (n->flags & MAN_LINE && (*n->string == ' ' ||
+ if (n->flags & MAN_LINE && (*n->string == ' ' ||
(n->prev != NULL && mh->fl & MANH_LITERAL &&
! (h->flags & HTML_NONEWLINE))))
print_otag(h, TAG_BR, 0, NULL);
@@ -362,7 +362,7 @@ man_br_pre(MAN_ARGS)
if (MAN_sp == n->tok) {
if (NULL != (n = n->child))
if ( ! a2roffsu(n->string, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(n->string));
+ su.scale = 1.0;
} else
su.scale = 0.0;
diff --git a/man_macro.c b/man_macro.c
index 1b8965899edc..c86ab6f13f01 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -1,7 +1,7 @@
-/* $Id: man_macro.c,v 1.91 2014/11/28 05:51:32 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.98 2015/02/06 11:54:36 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -72,11 +72,10 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
- { in_line_eoln, MAN_NSCOPED }, /* na */
{ in_line_eoln, MAN_NSCOPED }, /* sp */
{ in_line_eoln, MAN_BSCOPE }, /* nf */
{ in_line_eoln, MAN_BSCOPE }, /* fi */
- { blk_close, 0 }, /* RE */
+ { blk_close, MAN_BSCOPE }, /* RE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
@@ -88,7 +87,7 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
- { blk_close, 0 }, /* UE */
+ { blk_close, MAN_BSCOPE }, /* UE */
{ in_line_eoln, 0 }, /* ll */
};
@@ -279,10 +278,30 @@ blk_close(MACRO_PROT_ARGS)
{
enum mant ntok;
const struct man_node *nn;
+ char *p;
+ int nrew, target;
+ nrew = 1;
switch (tok) {
case MAN_RE:
ntok = MAN_RS;
+ if ( ! man_args(man, line, pos, buf, &p))
+ break;
+ for (nn = man->last->parent; nn; nn = nn->parent)
+ if (nn->tok == ntok && nn->type == MAN_BLOCK)
+ nrew++;
+ target = strtol(p, &p, 10);
+ if (*p != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ line, p - buf, "RE ... %s", p);
+ if (target == 0)
+ target = 1;
+ nrew -= target;
+ if (nrew < 1) {
+ mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
+ line, ppos, "RE %d", target);
+ return;
+ }
break;
case MAN_UE:
ntok = MAN_UR;
@@ -293,45 +312,50 @@ blk_close(MACRO_PROT_ARGS)
}
for (nn = man->last->parent; nn; nn = nn->parent)
- if (nn->tok == ntok && nn->type == MAN_BLOCK)
+ if (nn->tok == ntok && nn->type == MAN_BLOCK && ! --nrew)
break;
if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, man_macronames[tok]);
rew_scope(MAN_BLOCK, man, MAN_PP);
- } else
+ } else {
+ line = man->last->line;
+ ppos = man->last->pos;
+ ntok = man->last->tok;
man_unscope(man, nn);
+
+ /* Move a trailing paragraph behind the block. */
+
+ if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
+ *pos = strlen(buf);
+ blk_imp(man, ntok, line, ppos, pos, buf);
+ }
+ }
}
void
blk_exp(MACRO_PROT_ARGS)
{
- struct man_node *n;
- int la;
+ struct man_node *head;
char *p;
+ int la;
rew_scope(MAN_BLOCK, man, tok);
man_block_alloc(man, line, ppos, tok);
man_head_alloc(man, line, ppos, tok);
+ head = man->last;
- for (;;) {
- la = *pos;
- if ( ! man_args(man, line, pos, buf, &p))
- break;
+ la = *pos;
+ if (man_args(man, line, pos, buf, &p))
man_word_alloc(man, line, la, p);
- }
- assert(man);
- assert(tok != MAN_MAX);
-
- for (n = man->last; n; n = n->parent)
- if (n->tok == tok) {
- assert(n->type == MAN_HEAD);
- man_unscope(man, n);
- break;
- }
+ if (buf[*pos] != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS,
+ man->parse, line, *pos, "%s ... %s",
+ man_macronames[tok], buf + *pos);
+ man_unscope(man, head);
man_body_alloc(man, line, ppos, tok);
}
@@ -390,6 +414,20 @@ in_line_eoln(MACRO_PROT_ARGS)
n = man->last;
for (;;) {
+ if (buf[*pos] != '\0' && (tok == MAN_br ||
+ tok == MAN_fi || tok == MAN_nf)) {
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ man->parse, line, *pos, "%s %s",
+ man_macronames[tok], buf + *pos);
+ break;
+ }
+ if (buf[*pos] != '\0' && man->last != n &&
+ (tok == MAN_PD || tok == MAN_ft || tok == MAN_sp)) {
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS,
+ man->parse, line, *pos, "%s ... %s",
+ man_macronames[tok], buf + *pos);
+ break;
+ }
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
diff --git a/man_term.c b/man_term.c
index 9a9abafdbc5b..ab75851f2b28 100644
--- a/man_term.c
+++ b/man_term.c
@@ -1,7 +1,7 @@
-/* $Id: man_term.c,v 1.159 2014/12/04 02:05:42 schwarze Exp $ */
+/* $Id: man_term.c,v 1.168 2015/01/30 22:04:44 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,6 +21,7 @@
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -37,7 +38,7 @@
struct mtermp {
int fl;
#define MANT_LITERAL (1 << 0)
- size_t lmargin[MAXMARGINS]; /* margins (incl. visible page) */
+ int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
size_t offset; /* default offset to visible page */
@@ -46,7 +47,7 @@ struct mtermp {
#define DECL_ARGS struct termp *p, \
struct mtermp *mt, \
- const struct man_node *n, \
+ struct man_node *n, \
const struct man_meta *meta
struct termact {
@@ -56,9 +57,6 @@ struct termact {
#define MAN_NOTEXT (1 << 0) /* Never has text children. */
};
-static int a2width(const struct termp *, const char *);
-static size_t a2height(const struct termp *, const char *);
-
static void print_man_nodelist(DECL_ARGS);
static void print_man_node(DECL_ARGS);
static void print_man_head(struct termp *, const void *);
@@ -116,7 +114,6 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
- { pre_ign, NULL, MAN_NOTEXT }, /* na */
{ pre_sp, NULL, MAN_NOTEXT }, /* sp */
{ pre_literal, NULL, 0 }, /* nf */
{ pre_literal, NULL, 0 }, /* fi */
@@ -184,29 +181,6 @@ terminal_man(void *arg, const struct man *man)
}
}
-
-static size_t
-a2height(const struct termp *p, const char *cp)
-{
- struct roffsu su;
-
- if ( ! a2roffsu(cp, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(cp));
-
- return(term_vspan(p, &su));
-}
-
-static int
-a2width(const struct termp *p, const char *cp)
-{
- struct roffsu su;
-
- if ( ! a2roffsu(cp, &su, SCALE_EN))
- return(-1);
-
- return((int)term_hspan(p, &su));
-}
-
/*
* Printing leading vertical space before a block.
* This is used for the paragraph macros.
@@ -288,14 +262,16 @@ pre_literal(DECL_ARGS)
static int
pre_PD(DECL_ARGS)
{
+ struct roffsu su;
n = n->child;
- if (0 == n) {
+ if (n == NULL) {
mt->pardist = 1;
return(0);
}
assert(MAN_TEXT == n->type);
- mt->pardist = atoi(n->string);
+ if (a2roffsu(n->string, &su, SCALE_VS))
+ mt->pardist = term_vspan(p, &su);
return(0);
}
@@ -303,7 +279,7 @@ static int
pre_alternate(DECL_ARGS)
{
enum termfont font[2];
- const struct man_node *nn;
+ struct man_node *nn;
int savelit, i;
switch (n->tok) {
@@ -423,9 +399,10 @@ pre_ft(DECL_ARGS)
static int
pre_in(DECL_ARGS)
{
- int len, less;
- size_t v;
+ struct roffsu su;
const char *cp;
+ size_t v;
+ int less;
term_newln(p);
@@ -444,10 +421,10 @@ pre_in(DECL_ARGS)
else
cp--;
- if ((len = a2width(p, ++cp)) < 0)
+ if ( ! a2roffsu(++cp, &su, SCALE_EN))
return(0);
- v = (size_t)len;
+ v = term_hspan(p, &su);
if (less < 0)
p->offset -= p->offset > v ? v : p->offset;
@@ -455,6 +432,8 @@ pre_in(DECL_ARGS)
p->offset += v;
else
p->offset = v;
+ if (p->offset > SHRT_MAX)
+ p->offset = term_len(p, p->defindent);
return(0);
}
@@ -462,9 +441,8 @@ pre_in(DECL_ARGS)
static int
pre_sp(DECL_ARGS)
{
- char *s;
- size_t i, len;
- int neg;
+ struct roffsu su;
+ int i, len;
if ((NULL == n->prev && n->parent)) {
switch (n->parent->tok) {
@@ -484,29 +462,20 @@ pre_sp(DECL_ARGS)
}
}
- neg = 0;
- switch (n->tok) {
- case MAN_br:
+ if (n->tok == MAN_br)
len = 0;
- break;
- default:
- if (NULL == n->child) {
- len = 1;
- break;
- }
- s = n->child->string;
- if ('-' == *s) {
- neg = 1;
- s++;
- }
- len = a2height(p, s);
- break;
+ else if (n->child == NULL)
+ len = 1;
+ else {
+ if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
+ su.scale = 1.0;
+ len = term_vspan(p, &su);
}
- if (0 == len)
+ if (len == 0)
term_newln(p);
- else if (neg)
- p->skipvsp += len;
+ else if (len < 0)
+ p->skipvsp -= len;
else
for (i = 0; i < len; i++)
term_vspace(p);
@@ -517,9 +486,9 @@ pre_sp(DECL_ARGS)
static int
pre_HP(DECL_ARGS)
{
- size_t len, one;
- int ival;
+ struct roffsu su;
const struct man_node *nn;
+ int len;
switch (n->type) {
case MAN_BLOCK:
@@ -536,25 +505,21 @@ pre_HP(DECL_ARGS)
p->trailspace = 2;
}
- len = mt->lmargin[mt->lmargincur];
- ival = -1;
-
/* Calculate offset. */
- if (NULL != (nn = n->parent->head->child))
- if ((ival = a2width(p, nn->string)) >= 0)
- len = (size_t)ival;
-
- one = term_len(p, 1);
- if (len < one)
- len = one;
+ if ((nn = n->parent->head->child) != NULL &&
+ a2roffsu(nn->string, &su, SCALE_EN)) {
+ len = term_hspan(p, &su);
+ if (len < 0 && (size_t)(-len) > mt->offset)
+ len = -mt->offset;
+ else if (len > SHRT_MAX)
+ len = term_len(p, p->defindent);
+ mt->lmargin[mt->lmargincur] = len;
+ } else
+ len = mt->lmargin[mt->lmargincur];
p->offset = mt->offset;
p->rmargin = mt->offset + len;
-
- if (ival >= 0)
- mt->lmargin[mt->lmargincur] = (size_t)ival;
-
return(1);
}
@@ -595,9 +560,9 @@ pre_PP(DECL_ARGS)
static int
pre_IP(DECL_ARGS)
{
+ struct roffsu su;
const struct man_node *nn;
- size_t len;
- int savelit, ival;
+ int len, savelit;
switch (n->type) {
case MAN_BODY:
@@ -614,28 +579,23 @@ pre_IP(DECL_ARGS)
return(1);
}
- len = mt->lmargin[mt->lmargincur];
- ival = -1;
-
/* Calculate the offset from the optional second argument. */
- if (NULL != (nn = n->parent->head->child))
- if (NULL != (nn = nn->next))
- if ((ival = a2width(p, nn->string)) >= 0)
- len = (size_t)ival;
+ if ((nn = n->parent->head->child) != NULL &&
+ (nn = nn->next) != NULL &&
+ a2roffsu(nn->string, &su, SCALE_EN)) {
+ len = term_hspan(p, &su);
+ if (len < 0 && (size_t)(-len) > mt->offset)
+ len = -mt->offset;
+ else if (len > SHRT_MAX)
+ len = term_len(p, p->defindent);
+ mt->lmargin[mt->lmargincur] = len;
+ } else
+ len = mt->lmargin[mt->lmargincur];
switch (n->type) {
case MAN_HEAD:
- /* Handle zero-width lengths. */
- if (0 == len)
- len = term_len(p, 1);
-
p->offset = mt->offset;
p->rmargin = mt->offset + len;
- if (ival < 0)
- break;
-
- /* Set the saved left-margin. */
- mt->lmargin[mt->lmargincur] = (size_t)ival;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
@@ -681,9 +641,9 @@ post_IP(DECL_ARGS)
static int
pre_TP(DECL_ARGS)
{
- const struct man_node *nn;
- size_t len;
- int savelit, ival;
+ struct roffsu su;
+ struct man_node *nn;
+ int len, savelit;
switch (n->type) {
case MAN_HEAD:
@@ -700,22 +660,22 @@ pre_TP(DECL_ARGS)
return(1);
}
- len = (size_t)mt->lmargin[mt->lmargincur];
- ival = -1;
-
/* Calculate offset. */
- if (NULL != (nn = n->parent->head->child))
- if (nn->string && 0 == (MAN_LINE & nn->flags))
- if ((ival = a2width(p, nn->string)) >= 0)
- len = (size_t)ival;
+ if ((nn = n->parent->head->child) != NULL &&
+ nn->string != NULL && ! (MAN_LINE & nn->flags) &&
+ a2roffsu(nn->string, &su, SCALE_EN)) {
+ len = term_hspan(p, &su);
+ if (len < 0 && (size_t)(-len) > mt->offset)
+ len = -mt->offset;
+ else if (len > SHRT_MAX)
+ len = term_len(p, p->defindent);
+ mt->lmargin[mt->lmargincur] = len;
+ } else
+ len = mt->lmargin[mt->lmargincur];
switch (n->type) {
case MAN_HEAD:
- /* Handle zero-length properly. */
- if (0 == len)
- len = term_len(p, 1);
-
p->offset = mt->offset;
p->rmargin = mt->offset + len;
@@ -734,9 +694,6 @@ pre_TP(DECL_ARGS)
if (savelit)
mt->fl |= MANT_LITERAL;
- if (ival >= 0)
- mt->lmargin[mt->lmargincur] = (size_t)ival;
-
return(0);
case MAN_BODY:
p->offset = mt->offset + len;
@@ -881,8 +838,7 @@ post_SH(DECL_ARGS)
static int
pre_RS(DECL_ARGS)
{
- int ival;
- size_t sz;
+ struct roffsu su;
switch (n->type) {
case MAN_BLOCK:
@@ -894,13 +850,16 @@ pre_RS(DECL_ARGS)
break;
}
- sz = term_len(p, p->defindent);
+ n = n->parent->head;
+ n->aux = SHRT_MAX + 1;
+ if (n->child != NULL && a2roffsu(n->child->string, &su, SCALE_EN))
+ n->aux = term_hspan(p, &su);
+ if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
+ n->aux = -mt->offset;
+ else if (n->aux > SHRT_MAX)
+ n->aux = term_len(p, p->defindent);
- if (NULL != (n = n->parent->head->child))
- if ((ival = a2width(p, n->string)) >= 0)
- sz = (size_t)ival;
-
- mt->offset += sz;
+ mt->offset += n->aux;
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
@@ -914,8 +873,6 @@ pre_RS(DECL_ARGS)
static void
post_RS(DECL_ARGS)
{
- int ival;
- size_t sz;
switch (n->type) {
case MAN_BLOCK:
@@ -927,13 +884,7 @@ post_RS(DECL_ARGS)
break;
}
- sz = term_len(p, p->defindent);
-
- if (NULL != (n = n->parent->head->child))
- if ((ival = a2width(p, n->string)) >= 0)
- sz = (size_t)ival;
-
- mt->offset = mt->offset < sz ? 0 : mt->offset - sz;
+ mt->offset -= n->parent->head->aux;
p->offset = mt->offset;
if (--mt->lmarginsz < MAXMARGINS)
@@ -998,7 +949,7 @@ print_man_node(DECL_ARGS)
* Tables are preceded by a newline. Then process a
* table line, which will cause line termination,
*/
- if (TBL_SPAN_FIRST & n->span->flags)
+ if (n->span->prev == NULL)
term_newln(p);
term_tbl(p, n->span);
return;
@@ -1056,10 +1007,10 @@ static void
print_man_nodelist(DECL_ARGS)
{
- print_man_node(p, mt, n, meta);
- if ( ! n->next)
- return;
- print_man_nodelist(p, mt, n->next, meta);
+ while (n != NULL) {
+ print_man_node(p, mt, n, meta);
+ n = n->next;
+ }
}
static void
diff --git a/man_validate.c b/man_validate.c
index 5688bb548aaf..93ee9b3f208b 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -38,10 +38,6 @@
typedef void (*v_check)(CHKARGS);
-static void check_eq0(CHKARGS);
-static void check_eq2(CHKARGS);
-static void check_le1(CHKARGS);
-static void check_le5(CHKARGS);
static void check_par(CHKARGS);
static void check_part(CHKARGS);
static void check_root(CHKARGS);
@@ -53,6 +49,7 @@ static void post_vs(CHKARGS);
static void post_fi(CHKARGS);
static void post_ft(CHKARGS);
static void post_nf(CHKARGS);
+static void post_OP(CHKARGS);
static void post_TH(CHKARGS);
static void post_UC(CHKARGS);
static void post_UR(CHKARGS);
@@ -79,7 +76,6 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* I */
NULL, /* IR */
NULL, /* RI */
- check_eq0, /* na */
post_vs, /* sp */
post_nf, /* nf */
post_fi, /* fi */
@@ -87,11 +83,11 @@ static v_check man_valids[MAN_MAX] = {
check_part, /* RS */
NULL, /* DT */
post_UC, /* UC */
- check_le1, /* PD */
+ NULL, /* PD */
post_AT, /* AT */
NULL, /* in */
post_ft, /* ft */
- check_eq2, /* OP */
+ post_OP, /* OP */
post_nf, /* EX */
post_fi, /* EE */
post_UR, /* UR */
@@ -172,29 +168,27 @@ check_text(CHKARGS)
n->line, n->pos + (p - cp), NULL);
}
-#define INEQ_DEFINE(x, ineq, name) \
-static void \
-check_##name(CHKARGS) \
-{ \
- if (n->nchild ineq (x)) \
- return; \
- mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
- "line arguments %s %d (have %d)", \
- #ineq, (x), n->nchild); \
-}
+static void
+post_OP(CHKARGS)
+{
-INEQ_DEFINE(0, ==, eq0)
-INEQ_DEFINE(2, ==, eq2)
-INEQ_DEFINE(1, <=, le1)
-INEQ_DEFINE(5, <=, le5)
+ if (n->nchild == 0)
+ mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
+ n->line, n->pos, "OP");
+ else if (n->nchild > 2) {
+ n = n->child->next->next;
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ n->line, n->pos, "OP ... %s", n->string);
+ }
+}
static void
post_UR(CHKARGS)
{
- if (MAN_HEAD == n->type && 1 != n->nchild)
- mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
- n->pos, "line arguments eq 1 (have %d)", n->nchild);
+ if (n->type == MAN_HEAD && n->child == NULL)
+ mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
+ n->line, n->pos, "UR");
check_part(man, n);
}
@@ -243,19 +237,15 @@ post_ft(CHKARGS)
n->line, n->pos, "ft %s", cp);
*cp = '\0';
}
-
- if (1 < n->nchild)
- mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
- n->pos, "want one child (have %d)", n->nchild);
}
static void
check_part(CHKARGS)
{
- if (MAN_BODY == n->type && 0 == n->nchild)
- mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
- n->pos, "want children (have none)");
+ if (n->type == MAN_BODY && n->child == NULL)
+ mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
+ n->line, n->pos, man_macronames[n->tok]);
}
static void
@@ -312,8 +302,6 @@ post_TH(CHKARGS)
struct man_node *nb;
const char *p;
- check_le5(man, n);
-
free(man->meta.title);
free(man->meta.vol);
free(man->meta.source);
@@ -379,6 +367,8 @@ post_TH(CHKARGS)
if (n && (n = n->next))
man->meta.source = mandoc_strdup(n->string);
+ else if (man->defos != NULL)
+ man->meta.source = mandoc_strdup(man->defos);
/* TITLE MSEC DATE SOURCE ->VOL<- */
/* If missing, use the default VOL name for MSEC. */
@@ -389,6 +379,10 @@ post_TH(CHKARGS)
(NULL != (p = mandoc_a2msec(man->meta.msec))))
man->meta.vol = mandoc_strdup(p);
+ if (n != NULL && (n = n->next) != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ n->line, n->pos, "TH ... %s", n->string);
+
/*
* Remove the `TH' node after we've processed it for our
* meta-data.
@@ -400,9 +394,7 @@ static void
post_nf(CHKARGS)
{
- check_eq0(man, n);
-
- if (MAN_LITERAL & man->flags)
+ if (man->flags & MAN_LITERAL)
mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
n->line, n->pos, "nf");
@@ -413,8 +405,6 @@ static void
post_fi(CHKARGS)
{
- check_eq0(man, n);
-
if ( ! (MAN_LITERAL & man->flags))
mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
n->line, n->pos, "fi");
@@ -500,11 +490,6 @@ static void
post_vs(CHKARGS)
{
- if (n->tok == MAN_br)
- check_eq0(man, n);
- else
- check_le1(man, n);
-
if (NULL != n->prev)
return;
diff --git a/mandoc.1 b/mandoc.1
index 45a6b0cf7e64..e218ed7af89c 100644
--- a/mandoc.1
+++ b/mandoc.1
@@ -1,7 +1,7 @@
-.\" $Id: mandoc.1,v 1.128 2014/12/02 11:31:51 schwarze Exp $
+.\" $Id: mandoc.1,v 1.155 2015/02/23 13:31:03 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: December 2 2014 $
+.Dd $Mdocdate: February 23 2015 $
.Dt MANDOC 1
.Os
.Sh NAME
@@ -23,7 +23,7 @@
.Nd format and display UNIX manuals
.Sh SYNOPSIS
.Nm mandoc
-.Op Fl acfhklV
+.Op Fl acfhkl
.Sm off
.Op Fl I Cm os Li = Ar name
.Sm on
@@ -85,6 +85,9 @@ Override the default operating system
for the
.Xr mdoc 7
.Sq \&Os
+and for the
+.Xr man 7
+.Sq \&TH
macro.
.It Fl h
Display only the SYNOPSIS lines.
@@ -147,8 +150,6 @@ See
for available formats.
Defaults to
.Fl T Ns Cm locale .
-.It Fl V
-Print version and exit.
.It Fl W Ns Ar level
Specify the minimum message
.Ar level
@@ -159,12 +160,13 @@ can be
.Cm warning ,
.Cm error ,
or
-.Cm fatal .
-The default is
-.Fl W Ns Cm fatal ;
-.Fl W Ns Cm all
+.Cm unsupp ;
+.Cm all
is an alias for
-.Fl W Ns Cm warning .
+.Cm warning .
+By default,
+.Nm
+is silent.
See
.Sx EXIT STATUS
and
@@ -317,9 +319,6 @@ Emboldened characters are rendered as
The special characters documented in
.Xr mandoc_char 7
are rendered best-effort in an ASCII equivalent.
-If no equivalent is found,
-.Sq \&?
-is used instead.
.Pp
Output width is limited to 78 visible columns unless literal input lines
exceed this limit.
@@ -340,7 +339,7 @@ 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 \(>=60.
+which will normalise to \(>=58.
.El
.Ss HTML Output
Output produced by
@@ -529,19 +528,25 @@ At least one warning occurred, but no error, and
.Fl W Ns Cm warning
was specified.
.It 3
-At least one parsing error occurred, but no fatal error, and
+At least one parsing error occurred,
+but no unsupported feature was encountered, and
.Fl W Ns Cm error
or
.Fl W Ns Cm warning
was specified.
.It 4
-A fatal parsing error occurred.
+At least one unsupported feature was encountered, and
+.Fl W Ns Cm unsupp ,
+.Fl W Ns Cm error
+or
+.Fl W Ns Cm warning
+was specified.
.It 5
Invalid command line arguments were specified.
No input files have been read.
.It 6
-An operating system error occurred, for example memory exhaustion or an
-error accessing input files.
+An operating system error occurred, for example exhaustion
+of memory, file descriptors, or process table entries.
Such errors cause
.Nm
to exit at once, possibly in the middle of parsing or formatting a file.
@@ -600,22 +605,34 @@ fields.
.Pp
Message levels have the following meanings:
.Bl -tag -width "warning"
-.It Cm syserr
-Opening or reading an input file failed, so the parser cannot
-even be started and no output is produced from that input file.
-.It Cm fatal
-The parser is unable to parse a given input file at all.
-No formatted output is produced from that input file.
-.It Cm error
-An input file contains syntax that cannot be safely interpreted,
-either because it is invalid or because
+.It Cm unsupp
+An input file uses unsupported low-level
+.Xr roff 7
+features.
+The output may be incomplete and/or misformatted,
+so using GNU troff instead of
.Nm
-does not implement it yet.
+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.
+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.
.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
@@ -626,10 +643,12 @@ formatting tools instead of
.El
.Pp
Messages of the
-.Cm warning
+.Cm warning ,
+.Cm error ,
and
-.Cm error
-levels are hidden unless their level, or a lower level, is requested using a
+.Cm unsupp
+levels except those about non-existent or unreadable input files
+are hidden unless their level, or a lower level, is requested using a
.Fl W
option or
.Fl T Ns Cm lint
@@ -708,9 +727,9 @@ macro occurs after some non-prologue macro, but still takes effect.
.Pq mdoc
The
.Ic \&Dt
-macro can only occur before the first non-prologue macro
-because traditional formatters write the page header
-before parsing the document body.
+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.
@@ -752,17 +771,33 @@ This may confuse
.Xr makewhatis 8
and
.Xr apropos 1 .
-.It Sy "bad NAME section contents"
+.It Sy "NAME section without name"
+.Pq mdoc
+The NAME section does not contain any
+.Ic \&Nm
+child macro.
+.It Sy "NAME section without description"
.Pq mdoc
-The last node in the NAME section is not an
+The NAME section lacks the mandatory
.Ic \&Nd
-macro, or any preceding macro is not
-.Ic \&Nm ,
-or the NAME section is completely empty.
-This may confuse
-.Xr makewhatis 8
+child macro.
+.It Sy "description not at the end of NAME"
+.Pq mdoc
+The NAME section does contain an
+.Ic \&Nd
+child macro, but other content follows it.
+.It Sy "bad NAME section content"
+.Pq mdoc
+The NAME section contains plain text or macros other than
+.Ic \&Nm
and
-.Xr apropos 1 .
+.Ic \&Nd .
+.It Sy "missing description line, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Nd
+macro lacks the required argument.
+The title line of the manual will end after the dash.
.It Sy "sections out of conventional order"
.Pq mdoc
A standard section occurs after another section it usually precedes.
@@ -809,7 +844,7 @@ manual for replacements.
.Pq mdoc
The name of a macro that is not callable appears on a macro line.
It is printed verbatim.
-If the intention is to call it, move it to its own line;
+If the intention is to call it, move it to its own input line;
otherwise, escape it by prepending
.Sq \e& .
.It Sy "skipping paragraph macro"
@@ -968,6 +1003,18 @@ clause.
.It Sy "skipping empty macro"
.Pq mdoc
The indicated macro has no arguments and hence no effect.
+.It Sy "empty block"
+.Pq mdoc , man
+A
+.Ic \&Bd ,
+.Ic \&Bk ,
+.Ic \&Bl ,
+.Ic \&D1 ,
+.Ic \&Dl ,
+.Ic \&RS ,
+or
+.Ic \&UR
+block contains nothing in its body and will produce no output.
.It Sy "empty argument, using 0n"
.Pq mdoc
The required width is missing after
@@ -977,12 +1024,6 @@ or
.Fl offset
or
.Fl width.
-.It Sy "argument count wrong"
-.Pq mdoc , man
-The indicated macro has too few or too many arguments.
-The syntax tree will contain the wrong number of arguments as given.
-Formatting behaviour depends on the specific macro in question.
-Note that the same message may also occur as an ERROR, see below.
.It Sy "missing display type, using -ragged"
.Pq mdoc
The
@@ -1014,6 +1055,12 @@ The
macro is called without an argument before
.Ic \&Nm
has first been called with an argument.
+.It Sy "missing function name, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Fo
+macro is called without an argument.
+No function name is printed.
.It Sy "empty head in list item"
.Pq mdoc
In a
@@ -1041,21 +1088,18 @@ list, an
.Ic \&It
block is empty.
An empty list item is shown.
-.It Sy "missing font type"
+.It Sy "missing font type, using \efR"
.Pq mdoc
A
.Ic \&Bf
macro has no argument.
-It switches to the default font,
-.Cm \efR .
-.It Sy "unknown font type"
+It switches to the default font.
+.It Sy "unknown font type, using \efR"
.Pq mdoc
The
.Ic \&Bf
argument is invalid.
-The default font
-.Cm \efR
-is used instead.
+The default font is used instead.
.It Sy "nothing follows prefix"
.Pq mdoc
A
@@ -1064,6 +1108,14 @@ macro has no argument, or only one argument and no macro follows
on the same input line.
This defeats its purpose; in particular, spacing is not suppressed
before the text or macros following on the next input line.
+.It Sy "empty reference block"
+.Pq mdoc
+An
+.Ic \&Rs
+macro is immediately followed by an
+.Ic \&Re
+macro on the next input line.
+Such an empty block does not produce any output.
.It Sy "missing -std argument, adding it"
.Pq mdoc
An
@@ -1078,6 +1130,18 @@ The
utility assumes
.Fl std
even when it is not specified, but other implementations may not.
+.It Sy "missing option string, using \(dq\(dq"
+.Pq man
+The
+.Ic \&OP
+macro is invoked without any argument.
+An empty pair of square brackets is shown.
+.It Sy "missing resource identifier, using \(dq\(dq"
+.Pq man
+The
+.Ic \&UR
+macro is invoked without any argument.
+An empty pair of angle brackets is shown.
.It Sy "missing eqn box, using \(dq\(dq"
.Pq eqn
A diacritic mark or a binary operator is found,
@@ -1142,6 +1206,15 @@ list has a
.Fl width
argument.
That has no effect.
+.It Sy "wrong number of cells"
+In a line of a
+.Ic \&Bl Fl column
+list, the number of tabs or
+.Ic \&Ta
+macros is less than the number expected from the list header line
+or exceeds the expected number by more than one.
+Missing cells remain empty, and all cells exceeding the number of
+columns are joined into one single cell.
.It Sy "unknown AT&T UNIX version"
.Pq mdoc
An
@@ -1193,6 +1266,12 @@ request or a
layout modifier has an unknown
.Ar font
argument.
+.It Sy "odd number of characters in request"
+.Pq roff
+A
+.Ic \&tr
+request contains an odd number of characters.
+The last character is mapped to the blank character.
.El
.Ss "Warnings related to plain text"
.Bl -ohang
@@ -1249,23 +1328,86 @@ its value is implicitly set to the empty string.
However, defining strings explicitly before use
keeps the code more readable.
.El
-.Ss "Errors related to equations"
-.Bl -inset -compact
-.It "unexpected equation scope closure"
-.It "equation scope open on exit"
-.It "overlapping equation scopes"
-.It "unexpected end of equation"
+.Ss "Warnings related to tables"
+.Bl -ohang
+.It Sy "tbl line starts with span"
+.Pq tbl
+The first cell in a table layout line is a horizontal span
+.Pq Sq Cm s .
+Data provided for this cell is ignored, and nothing is printed in the cell.
+.It Sy "tbl column starts with span"
+.Pq tbl
+The first line of a table layout specification
+requests a vertical span
+.Pq Sq Cm ^ .
+Data provided for this cell is ignored, and nothing is printed in the cell.
+.It Sy "skipping vertical bar in tbl layout"
+.Pq tbl
+A table layout specification contains more than two consecutive vertical bars.
+A double bar is printed, all additional bars are discarded.
.El
.Ss "Errors related to tables"
-.Bl -inset -compact
-.It "bad table syntax"
-.It "bad table option"
-.It "bad table layout"
-.It "no table layout cells specified"
-.It "no table data cells specified"
-.It "ignore data in cell"
-.It "data block still open"
-.It "ignoring extra data cells"
+.Bl -ohang
+.It Sy "non-alphabetic character in tbl options"
+.Pq tbl
+The table options line contains a character other than a letter,
+blank, or comma where the beginning of an option name is expected.
+The character is ignored.
+.It Sy "skipping unknown tbl option"
+.Pq tbl
+The table options line contains a string of letters that does not
+match any known option name.
+The word is ignored.
+.It Sy "missing tbl option argument"
+.Pq tbl
+A table option that requires an argument is not followed by an
+opening parenthesis, or the opening parenthesis is immediately
+followed by a closing parenthesis.
+The option is ignored.
+.It Sy "wrong tbl option argument size"
+.Pq tbl
+A table option argument contains an invalid number of characters.
+Both the option and the argument are ignored.
+.It Sy "empty tbl layout"
+.Pq tbl
+A table layout specification is completely empty,
+specifying zero lines and zero columns.
+As a fallback, a single left-justified column is used.
+.It Sy "invalid character in tbl layout"
+.Pq tbl
+A table layout specification contains a character that can neither
+be interpreted as a layout key character nor as a layout modifier,
+or a modifier precedes the first key.
+The invalid character is discarded.
+.It Sy "unmatched parenthesis in tbl layout"
+.Pq tbl
+A table layout specification contains an opening parenthesis,
+but no matching closing parenthesis.
+The rest of the input line, starting from the parenthesis, has no effect.
+.It Sy "tbl without any data cells"
+.Pq tbl
+A table does not contain any data cells.
+It will probably produce no output.
+.It Sy "ignoring data in spanned tbl cell"
+.Pq tbl
+A table cell is marked as a horizontal span
+.Pq Sq Cm s
+or vertical span
+.Pq Sq Cm ^
+in the table layout, but it contains data.
+The data is ignored.
+.It Sy "ignoring extra tbl data cells"
+.Pq tbl
+A data line contains more cells than the corresponding layout line.
+The data in the extra cells is ignored.
+.It Sy "data block open at end of tbl"
+.Pq tbl
+A data block is opened with
+.Cm T{ ,
+but never closed with a matching
+.Cm T} .
+The remaining data lines of the table are all put into one cell,
+and any remaining cells stay empty.
.El
.Ss "Errors related to roff, mdoc, and man code"
.Bl -ohang
@@ -1307,6 +1449,11 @@ or
macro.
It may be mistyped or unsupported.
The request or macro is discarded including its arguments.
+.It Sy "skipping insecure request"
+.Pq roff
+An input file attempted to run a shell command
+or to read or write an external file.
+Such attempts are denied for security reasons.
.It Sy "skipping item outside list"
.Pq mdoc , eqn
An
@@ -1343,6 +1490,16 @@ right delimiter or closing brace, or the end of an equation, table, or
.Xr roff 7
conditional request is encountered but no matching block is open.
The offending request or macro is discarded.
+.It Sy "fewer RS blocks open, skipping"
+.Pq man
+The
+.Ic \&RE
+macro is invoked with an argument, but less than the specified number of
+.Ic \&RS
+blocks is open.
+The
+.Ic \&RE
+macro is discarded.
.It Sy "inserting missing end of block"
.Pq mdoc , tbl
Various
@@ -1351,7 +1508,7 @@ macros as well as tables require explicit closing by dedicated macros.
A block that doesn't support bad nesting
ends before all of its children are properly closed.
The open child nodes are closed implicitly.
-.It Sy "scope open on exit"
+.It Sy "appending missing end of block"
.Pq mdoc , man , eqn , tbl , roff
At the end of the document, an explicit
.Xr mdoc 7
@@ -1401,12 +1558,6 @@ When parsing for a request or a user-defined macro name to be called,
only the escape sequence is discarded.
The characters preceding it are used as the request or macro name,
the characters following it are used as the arguments to the request or macro.
-.It Sy "argument count wrong"
-.Pq mdoc , man , roff
-The indicated request or macro has too few or too many arguments.
-The syntax tree will contain the wrong number of arguments as given.
-Formatting behaviour depends on the specific request or macro in question.
-Note that the same message may also occur as a WARNING, see above.
.It Sy "NOT IMPLEMENTED: Bd -file"
.Pq mdoc
For security reasons, the
@@ -1457,6 +1608,29 @@ or
.Ic \&gsize
statement has a non-numeric or negative argument or no argument at all.
The invalid request or statement is ignored.
+.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
+.Pq roff
+For security reasons,
+.Nm
+allows
+.Ic \&so
+file inclusion requests only with relative paths
+and only without ascending to any parent directory.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+.Nm
+only shows the path as it appears behind
+.Ic \&so .
+.It Sy ".so request failed"
+.Pq roff
+Servicing a
+.Ic \&so
+request requires reading an external file, but the file could not be
+opened.
+.Nm
+only shows the path as it appears behind
+.Ic \&so .
.It Sy "skipping all arguments"
.Pq mdoc , man , eqn , roff
An
@@ -1466,7 +1640,10 @@ An
.Ic \&Ef ,
.Ic \&Ek ,
.Ic \&El ,
+.Ic \&Lp ,
+.Ic \&Pp ,
.Ic \&Re ,
+.Ic \&Rs ,
or
.Ic \&Ud
macro, an
@@ -1484,19 +1661,57 @@ or
.Ic \&EN
macro, or a
.Xr roff 7
+.Ic \&br ,
+.Ic \&fi ,
+or
+.Ic \&nf
+request or
.Sq \&..
block closing request is invoked with at least one argument.
All arguments are ignored.
.It Sy "skipping excess arguments"
-.Pq mdoc , roff
-The
-.Ic \&Bf
-macro is invoked with more than one argument, or a request of the
+.Pq mdoc , man , roff
+A macro or request is invoked with too many arguments:
+.Bl -dash -offset 2n -width 2n -compact
+.It
+.Ic \&Fo ,
+.Ic \&PD ,
+.Ic \&RS ,
+.Ic \&UR ,
+.Ic \&ft ,
+or
+.Ic \&sp
+with more than one argument
+.It
+.Ic \&An
+with another argument after
+.Fl split
+or
+.Fl nosplit
+.It
+.Ic \&RE
+with more than one argument or with a non-integer argument
+.It
+.Ic \&OP
+or a request of the
.Ic \&de
-family is invoked with more than two arguments.
+family with more than two arguments
+.It
+.Ic \&Dt
+with more than three arguments
+.It
+.Ic \&TH
+with more than five arguments
+.It
+.Ic \&Bd ,
+.Ic \&Bk ,
+or
+.Ic \&Bl
+with invalid arguments
+.El
The excess arguments are ignored.
.El
-.Ss FATAL errors
+.Ss Unsupported features
.Bl -ohang
.It Sy "input too large"
.Pq mdoc , man
@@ -1506,116 +1721,45 @@ cannot handle input files larger than its arbitrary size limit
of 2^31 bytes (2 Gigabytes).
Since useful manuals are always small, this is not a problem in practice.
Parsing is aborted as soon as the condition is detected.
-.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
+.It Sy "unsupported control character"
.Pq roff
-For security reasons,
+An ASCII control character supported by other
+.Xr roff 7
+implementations but not by
.Nm
-allows
-.Ic \&so
-file inclusion requests only with relative paths
-and only without ascending to any parent directory.
-By requesting the inclusion of a sensitive file, a malicious document
-might otherwise trick a privileged user into inadvertently displaying
-the file on the screen, revealing the file content to bystanders.
-The parser exits immediately.
-.It Sy ".so request failed"
+was found in an input file.
+It is replaced by a question mark.
+.It Sy "unsupported roff request"
.Pq roff
-Servicing a
-.Ic \&so
-request requires reading an external file.
-While trying to do so, an
-.Xr open 2 ,
-.Xr stat 2 ,
-or
-.Xr read 2
-system call failed.
-The parser exits immediately.
-Before showing this message,
-.Nm
-always shows another message explaining why the system call failed.
-.El
-.Sh COMPATIBILITY
-This section summarises
-.Nm
-compatibility with GNU troff.
-Each input and output format is separately noted.
-.Ss ASCII Compatibility
-.Bl -bullet -compact
-.It
-Unrenderable unicode codepoints specified with
-.Sq \e[uNNNN]
-escapes are printed as
-.Sq \&?
-in mandoc.
-In GNU troff, these raise an error.
-.It
-The
-.Sq \&Bd \-literal
-and
-.Sq \&Bd \-unfilled
-macros of
-.Xr mdoc 7
-in
-.Fl T Ns Cm ascii
-are synonyms, as are \-filled and \-ragged.
-.It
-In historic GNU troff, the
-.Sq \&Pa
-.Xr mdoc 7
-macro does not underline when scoped under an
-.Sq \&It
-in the FILES section.
-This behaves correctly in
-.Nm .
-.It
-A list or display following the
-.Sq \&Ss
-.Xr mdoc 7
-macro in
-.Fl T Ns Cm ascii
-does not assert a prior vertical break, just as it doesn't with
-.Sq \&Sh .
-.It
-The
-.Sq \&na
-.Xr man 7
-macro in
-.Fl T Ns Cm ascii
-has no effect.
-.It
-Words aren't hyphenated.
-.El
-.Ss HTML Compatibility
-.Bl -bullet -compact
-.It
-The
-.Sq \efP
-escape will revert the font to the previous
-.Sq \ef
-escape, not to the last rendered decoration, which is now dictated by
-CSS instead of hard-coded.
-It also will not span past the current scope,
-for the same reason.
-Note that in
-.Sx ASCII Output
-mode, this will work fine.
-.It
-The
+An input file contains a
+.Xr roff 7
+request supported by GNU troff or Heirloom troff but not by
+.Nm ,
+and it is likely that this will cause information loss
+or considerable misformatting.
+.It Sy "eqn delim option in tbl"
+.Pq eqn , tbl
+The options line of a table defines equation delimiters.
+Any equation source code contained in the table will be printed unformatted.
+.It Sy "unsupported table layout modifier"
+.Pq tbl
+A table layout specification contains an
+.Sq Cm m
+modifier.
+The modifier is discarded.
+.It Sy "ignoring macro in table"
+.Pq tbl , mdoc , man
+A table contains an invocation of an
.Xr mdoc 7
-.Sq \&Bl \-hang
-and
-.Sq \&Bl \-tag
-list types render similarly (no break following overreached left-hand
-side) due to the expressive constraints of HTML.
-.It
-The
+or
.Xr man 7
-.Sq IP
-and
-.Sq TP
-lists render similarly.
+macro or of an undefined macro.
+The macro is ignored, and its arguments are handled
+as if they were a text line.
.El
.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr man 1 ,
.Xr eqn 7 ,
.Xr man 7 ,
.Xr mandoc_char 7 ,
@@ -1626,32 +1770,15 @@ lists render similarly.
The
.Nm
utility was written by
-.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
-.Sh CAVEATS
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and is maintained by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
+.Sh BUGS
In
-.Fl T Ns Cm html
-and
-.Fl T Ns Cm xhtml ,
+.Fl T Ns Cm html ,
the maximum size of an element attribute is determined by
.Dv BUFSIZ ,
which is usually 1024 bytes.
Be aware of this when setting long link
formats such as
.Fl O Ns Cm style Ns = Ns Ar really/long/link .
-.Pp
-Nesting elements within next-line element scopes of
-.Fl m Ns Cm an ,
-such as
-.Sq br
-within an empty
-.Sq B ,
-will confuse
-.Fl T Ns Cm html
-and
-.Fl T Ns Cm xhtml
-and cause them to forget the formatting of the prior next-line scope.
-.Pp
-The
-.Sq \(aq
-control character is an alias for the standard macro control character
-and does not emit a line-break as stipulated in GNU troff.
diff --git a/mandoc.3 b/mandoc.3
index f05fdac997bf..a41e25b934d0 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -1,7 +1,7 @@
-.\" $Id: mandoc.3,v 1.29 2014/11/26 23:42:14 schwarze Exp $
+.\" $Id: mandoc.3,v 1.31 2015/01/15 04:26:40 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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: November 26 2014 $
+.Dd $Mdocdate: January 15 2015 $
.Dt MANDOC 3
.Os
.Sh NAME
@@ -39,11 +39,10 @@
.Nm mparse_strlevel
.Nm mparse_wait ,
.Nd mandoc macro compiler library
-.Sh LIBRARY
-.Lb libmandoc
.Sh SYNOPSIS
.In sys/types.h
.In mandoc.h
+.Pp
.Fd "#define ASCII_NBRSP"
.Fd "#define ASCII_HYPH"
.Fd "#define ASCII_BREAK"
@@ -176,10 +175,15 @@ initiate a parsing sequence with
and
.Fn mparse_alloc ;
.It
-parse files or file descriptors with
+open a file with
+.Xr open 2
+or
+.Fn mparse_open ;
+.It
+parse it with
.Fn mparse_readfd ;
.It
-retrieve a parsed syntax tree, if the parse was successful, with
+retrieve the syntax tree with
.Fn mparse_result ;
.It
iterate over parse nodes with
@@ -206,7 +210,7 @@ and
.Ss Types
.Bl -ohang
.It Vt "enum mandocerr"
-A fatal error, error, or warning message during parsing.
+An error or warning message during parsing.
.It Vt "enum mandoclevel"
A classification of an
.Vt "enum mandocerr"
@@ -227,7 +231,7 @@ This may be used across parsed input if
.Fn mparse_reset
is called between parses.
.It Vt "mandocmsg"
-A prototype for a function to handle fatal error, error, and warning
+A prototype for a function to handle error and warning
messages emitted by the parser.
.El
.Ss Functions
@@ -331,7 +335,7 @@ This is for example useful in
to quickly build minimal databases.
.It Ar wlevel
Can be set to
-.Dv MANDOCLEVEL_FATAL ,
+.Dv MANDOCLEVEL_BADARG ,
.Dv MANDOCLEVEL_ERROR ,
or
.Dv MANDOCLEVEL_WARNING .
@@ -413,17 +417,12 @@ Declared in
implemented in
.Pa read.c .
.It Fn mparse_readfd
-Parse a file or file descriptor.
-If
-.Va fd
-is -1, open
-.Va fname
-with
+Parse a file descriptor opened with
+.Xr open 2
+or
.Fn mparse_open .
-Otherwise,
-.Va fname
-is assumed to be the name associated with
-.Va fd .
+Pass the associated filename in
+.Va fname .
Calls
.Fn mparse_wait
before returning.
@@ -444,14 +443,7 @@ implemented in
.Pa read.c .
.It Fn mparse_result
Obtain the result of a parse.
-Only successful parses
-.Po
-i.e., those where
-.Fn mparse_readfd
-returned less than MANDOCLEVEL_FATAL
-.Pc
-should invoke this function, in which case one of the three pointers will
-be filled in.
+One of the three pointers will be filled in.
Declared in
.In mandoc.h ,
implemented in
diff --git a/mandoc.c b/mandoc.c
index 2ec179ea2302..0619420cb196 100644
--- a/mandoc.c
+++ b/mandoc.c
@@ -1,7 +1,7 @@
-/* $Id: mandoc.c,v 1.88 2014/10/28 13:24:44 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.92 2015/02/20 23:55:10 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -156,16 +156,18 @@ mandoc_escape(const char **end, const char **start, int *sz)
/* FALLTHROUGH */
case 'D':
/* FALLTHROUGH */
- case 'o':
- /* FALLTHROUGH */
case 'R':
/* FALLTHROUGH */
case 'X':
/* FALLTHROUGH */
case 'Z':
- if ('\0' == **start)
- return(ESCAPE_ERROR);
gly = ESCAPE_IGNORE;
+ /* FALLTHROUGH */
+ case 'o':
+ if (**start == '\0')
+ return(ESCAPE_ERROR);
+ if (gly == ESCAPE_ERROR)
+ gly = ESCAPE_OVERSTRIKE;
term = **start;
*start = ++*end;
break;
@@ -225,7 +227,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
/* See +/- counts as a sign. */
if ('+' == **end || '-' == **end || ASCII_HYPH == **end)
- (*end)++;
+ *start = ++*end;
switch (**end) {
case '(':
@@ -240,6 +242,14 @@ mandoc_escape(const char **end, const char **start, int *sz)
*start = ++*end;
term = '\'';
break;
+ case '3':
+ /* FALLTHROUGH */
+ case '2':
+ /* FALLTHROUGH */
+ case '1':
+ *sz = (*end)[-1] == 's' &&
+ isdigit((unsigned char)(*end)[1]) ? 2 : 1;
+ break;
default:
*sz = 1;
break;
@@ -480,6 +490,8 @@ time2a(time_t t)
int isz;
tm = localtime(&t);
+ if (tm == NULL)
+ return(NULL);
/*
* Reserve space:
diff --git a/mandoc.db.5 b/mandoc.db.5
index e3452ffe89db..60908bc4d397 100644
--- a/mandoc.db.5
+++ b/mandoc.db.5
@@ -1,4 +1,4 @@
-.\" $Id: mandoc.db.5,v 1.2 2014/09/03 18:09:14 schwarze Exp $
+.\" $Id: mandoc.db.5,v 1.3 2014/12/30 21:34:57 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: September 3 2014 $
+.Dd $Mdocdate: December 30 2014 $
.Dt MANDOC.DB 5
.Os
.Sh NAME
@@ -117,14 +117,14 @@ documented in
The string found in those contexts.
.El
.Sh FILES
-.Bl -tag -width /usr/share/mandoc.db -compact
-.It Pa /usr/share/mandoc.db
+.Bl -tag -width /usr/share/man/mandoc.db -compact
+.It Pa /usr/share/man/mandoc.db
The manual page database for the base system.
-.It Pa /usr/X11R6/mandoc.db
+.It Pa /usr/X11R6/man/mandoc.db
The same for the
.Xr X 7
Window System.
-.It Pa /usr/local/mandoc.db
+.It Pa /usr/local/man/mandoc.db
The same for
.Xr packages 7 .
.El
diff --git a/mandoc.h b/mandoc.h
index e4cdccbc43f3..eb8a1aa6f298 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -1,7 +1,7 @@
-/* $Id: mandoc.h,v 1.176 2014/12/01 08:05:52 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.201 2015/02/23 13:31:04 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -31,7 +31,7 @@ enum mandoclevel {
MANDOCLEVEL_RESERVED,
MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
MANDOCLEVEL_ERROR, /* input has been thrown away */
- MANDOCLEVEL_FATAL, /* input is borked */
+ MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */
MANDOCLEVEL_BADARG, /* bad argument in invocation */
MANDOCLEVEL_SYSERR, /* system error */
MANDOCLEVEL_MAX
@@ -65,7 +65,11 @@ enum mandocerr {
MANDOCERR_DOC_EMPTY, /* no document body */
MANDOCERR_SEC_BEFORE, /* content before first section header: macro */
MANDOCERR_NAMESEC_FIRST, /* first section is not NAME: Sh title */
- MANDOCERR_NAMESEC_BAD, /* bad NAME section contents: macro */
+ MANDOCERR_NAMESEC_NONM, /* NAME section without name */
+ MANDOCERR_NAMESEC_NOND, /* NAME section without description */
+ MANDOCERR_NAMESEC_ND, /* description not at the end of NAME */
+ MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */
+ MANDOCERR_ND_EMPTY, /* missing description line, using "" */
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 */
@@ -91,18 +95,22 @@ enum mandocerr {
MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
MANDOCERR_COND_EMPTY, /* conditional request controls empty scope */
MANDOCERR_MACRO_EMPTY, /* skipping empty macro: macro */
+ MANDOCERR_BLK_EMPTY, /* empty block: macro */
MANDOCERR_ARG_EMPTY, /* empty argument, using 0n: macro arg */
- MANDOCERR_ARGCWARN, /* argument count wrong */
MANDOCERR_BD_NOTYPE, /* missing display type, using -ragged: Bd */
MANDOCERR_BL_LATETYPE, /* list type is not the first argument: Bl arg */
MANDOCERR_BL_NOWIDTH, /* missing -width in -tag list, using 8n */
MANDOCERR_EX_NONAME, /* missing utility name, using "": Ex */
+ MANDOCERR_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_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 */
+ MANDOCERR_RS_EMPTY, /* empty reference block: Rs */
MANDOCERR_ARG_STD, /* missing -std argument, adding it: macro */
+ MANDOCERR_OP_EMPTY, /* missing option string, using "": OP */
+ MANDOCERR_UR_NOHEAD, /* missing resource identifier, using "": UR */
MANDOCERR_EQN_NOBOX, /* missing eqn box, using "": op */
/* related to bad arguments */
@@ -112,12 +120,14 @@ enum mandocerr {
MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */
MANDOCERR_BL_REP, /* skipping duplicate list type: Bl -type */
MANDOCERR_BL_SKIPW, /* skipping -width argument: Bl -type */
+ MANDOCERR_BL_COL, /* wrong number of cells */
MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */
MANDOCERR_FA_COMMA, /* comma in function argument: arg */
MANDOCERR_FN_PAREN, /* parenthesis in function name: arg */
MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
+ MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
/* related to plain text */
MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */
@@ -127,65 +137,61 @@ enum mandocerr {
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
- MANDOCERR_ERROR, /* ===== start of errors ===== */
+ /* related to tables */
+ MANDOCERR_TBLLAYOUT_SPAN, /* tbl line starts with span */
+ MANDOCERR_TBLLAYOUT_DOWN, /* tbl column starts with span */
+ MANDOCERR_TBLLAYOUT_VERT, /* skipping vertical bar in tbl layout */
- /* related to equations */
- MANDOCERR_EQNNSCOPE, /* unexpected equation scope closure*/
- MANDOCERR_EQNSCOPE, /* equation scope open on exit */
- MANDOCERR_EQNBADSCOPE, /* overlapping equation scopes */
- MANDOCERR_EQNEOF, /* unexpected end of equation */
+ MANDOCERR_ERROR, /* ===== start of errors ===== */
/* related to tables */
- MANDOCERR_TBL, /* bad table syntax */
- MANDOCERR_TBLOPT, /* bad table option */
- MANDOCERR_TBLLAYOUT, /* bad table layout */
- MANDOCERR_TBLNOLAYOUT, /* no table layout cells specified */
- MANDOCERR_TBLNODATA, /* no table data cells specified */
- MANDOCERR_TBLIGNDATA, /* ignore data in cell */
- MANDOCERR_TBLBLOCK, /* data block still open */
- MANDOCERR_TBLEXTRADAT, /* ignoring extra data cells */
+ MANDOCERR_TBLOPT_ALPHA, /* non-alphabetic character in tbl options */
+ MANDOCERR_TBLOPT_BAD, /* skipping unknown tbl option: option */
+ MANDOCERR_TBLOPT_NOARG, /* missing tbl option argument: option */
+ MANDOCERR_TBLOPT_ARGSZ, /* wrong tbl option argument size: option */
+ MANDOCERR_TBLLAYOUT_NONE, /* empty tbl layout */
+ MANDOCERR_TBLLAYOUT_CHAR, /* invalid character in tbl layout: char */
+ MANDOCERR_TBLLAYOUT_PAR, /* unmatched parenthesis in tbl layout */
+ MANDOCERR_TBLDATA_NONE, /* tbl without any data cells */
+ MANDOCERR_TBLDATA_SPAN, /* ignoring data in spanned tbl cell: data */
+ MANDOCERR_TBLDATA_EXTRA, /* ignoring extra tbl data cells: data */
+ MANDOCERR_TBLDATA_BLK, /* data block open at end of tbl: macro */
/* related to document structure and macros */
+ MANDOCERR_FILE, /* cannot open file */
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
- MANDOCERR_BADCHAR, /* skipping bad character: number */
+ MANDOCERR_CHAR_BAD, /* skipping bad character: number */
MANDOCERR_MACRO, /* skipping unknown macro: macro */
+ MANDOCERR_REQ_INSEC, /* skipping insecure request: request */
MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */
MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */
MANDOCERR_BLK_NOTOPEN, /* skipping end of block that is not open */
+ MANDOCERR_RE_NOTOPEN, /* fewer RS blocks open, skipping: RE arg */
MANDOCERR_BLK_BROKEN, /* inserting missing end of block: macro ... */
MANDOCERR_BLK_NOEND, /* appending missing end of block: macro */
/* related to request and macro arguments */
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
- MANDOCERR_ARGCOUNT, /* argument count wrong */
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
MANDOCERR_IT_NONUM, /* skipping request without numeric argument */
+ MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
+ MANDOCERR_SO_FAIL, /* .so request failed */
MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */
MANDOCERR_DIVZERO, /* divide by zero */
- MANDOCERR_FATAL, /* ===== start of fatal errors ===== */
+ MANDOCERR_UNSUPP, /* ===== start of unsupported features ===== */
MANDOCERR_TOOLARGE, /* input too large */
- MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
- MANDOCERR_SO_FAIL, /* .so request failed */
-
- /* ===== system errors ===== */
-
- MANDOCERR_SYSDUP, /* cannot dup file descriptor */
- MANDOCERR_SYSEXEC, /* cannot exec */
- MANDOCERR_SYSEXIT, /* gunzip failed with code */
- MANDOCERR_SYSFORK, /* cannot fork */
- MANDOCERR_SYSOPEN, /* cannot open file */
- MANDOCERR_SYSPIPE, /* cannot open pipe */
- MANDOCERR_SYSREAD, /* cannot read file */
- MANDOCERR_SYSSIG, /* gunzip died from signal */
- MANDOCERR_SYSSTAT, /* cannot stat file */
- MANDOCERR_SYSWAIT, /* wait failed */
+ MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
+ MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
+ MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
+ MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
+ MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
MANDOCERR_MAX
};
@@ -193,7 +199,6 @@ enum mandocerr {
struct tbl_opts {
char tab; /* cell-separator */
char decimal; /* decimal point */
- int linesize;
int opts;
#define TBL_OPT_CENTRE (1 << 0)
#define TBL_OPT_EXPAND (1 << 1)
@@ -202,19 +207,10 @@ struct tbl_opts {
#define TBL_OPT_ALLBOX (1 << 4)
#define TBL_OPT_NOKEEP (1 << 5)
#define TBL_OPT_NOSPACE (1 << 6)
+#define TBL_OPT_NOWARN (1 << 7)
int cols; /* number of columns */
-};
-
-/*
- * The head of a table specifies all of its columns. When formatting a
- * tbl_span, iterate over these and plug in data from the tbl_span when
- * appropriate, using tbl_cell as a guide to placement.
- */
-struct tbl_head {
- int ident; /* 0 <= unique id < cols */
- int vert; /* width of preceding vertical line */
- struct tbl_head *next;
- struct tbl_head *prev;
+ int lvert; /* width of left vertical line */
+ int rvert; /* width of right vertical line */
};
enum tbl_cellt {
@@ -235,9 +231,10 @@ enum tbl_cellt {
*/
struct tbl_cell {
struct tbl_cell *next;
- int vert; /* width of preceding vertical line */
+ int vert; /* width of subsequent vertical line */
enum tbl_cellt pos;
size_t spacing;
+ int col; /* column number, starting from 0 */
int flags;
#define TBL_CELL_TALIGN (1 << 0) /* t, T */
#define TBL_CELL_BALIGN (1 << 1) /* d, D */
@@ -247,7 +244,6 @@ struct tbl_cell {
#define TBL_CELL_UP (1 << 5) /* u, U */
#define TBL_CELL_WIGN (1 << 6) /* z, Z */
#define TBL_CELL_WMAX (1 << 7) /* x, X */
- struct tbl_head *head;
};
/*
@@ -257,7 +253,7 @@ struct tbl_row {
struct tbl_row *next;
struct tbl_cell *first;
struct tbl_cell *last;
- int vert; /* trailing vertical line */
+ int vert; /* width of left vertical line */
};
enum tbl_datt {
@@ -292,16 +288,13 @@ enum tbl_spant {
*/
struct tbl_span {
struct tbl_opts *opts;
- struct tbl_head *head;
struct tbl_row *layout; /* layout row */
struct tbl_dat *first;
struct tbl_dat *last;
+ struct tbl_span *prev;
+ struct tbl_span *next;
int line; /* parse line */
- int flags;
-#define TBL_SPAN_FIRST (1 << 0)
-#define TBL_SPAN_LAST (1 << 1)
enum tbl_spant pos;
- struct tbl_span *next;
};
enum eqn_boxt {
@@ -408,7 +401,8 @@ enum mandoc_esc {
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
- ESCAPE_SKIPCHAR /* skip the next character */
+ ESCAPE_SKIPCHAR, /* skip the next character */
+ ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
};
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
diff --git a/mandoc_char.7 b/mandoc_char.7
index 8d8356652ef5..806b990f1755 100644
--- a/mandoc_char.7
+++ b/mandoc_char.7
@@ -1,4 +1,4 @@
-.\" $Id: mandoc_char.7,v 1.56 2013/12/26 17:23:42 schwarze Exp $
+.\" $Id: mandoc_char.7,v 1.59 2015/01/20 19:39:34 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: December 26 2013 $
+.Dd $Mdocdate: January 20 2015 $
.Dt MANDOC_CHAR 7
.Os
.Sh NAME
@@ -210,7 +210,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(rl Ta \(rl Ta overline
+.It \e(rn Ta \(rn Ta overline
.It \e(bb Ta \(bb Ta broken bar
.It \e(sl Ta \(sl Ta forward slash
.It \e(rs Ta \(rs Ta backward slash
@@ -273,7 +273,7 @@ Quotes:
.El
.Pp
Brackets:
-.Bl -column "xxbracketrightbpx" Rendered Description -offset indent -compact
+.Bl -column "xxbracketrightbtx" Rendered Description -offset indent -compact
.It Em Input Ta Em Rendered Ta Em Description
.It \e(lB Ta \(lB Ta left bracket
.It \e(rB Ta \(rB Ta right bracket
@@ -284,30 +284,30 @@ Brackets:
.It \e(bv Ta \(bv Ta brace extension
.It \e[braceex] Ta \[braceex] Ta brace extension
.It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket
-.It \e[bracketleftbp] Ta \[bracketleftbp] Ta bottom-left hooked bracket
+.It \e[bracketleftbt] Ta \[bracketleftbt] Ta bottom-left hooked bracket
.It \e[bracketleftex] Ta \[bracketleftex] Ta left hooked bracket extension
.It \e[bracketrighttp] Ta \[bracketrighttp] Ta top-right hooked bracket
-.It \e[bracketrightbp] Ta \[bracketrightbp] Ta bottom-right hooked bracket
+.It \e[bracketrightbt] Ta \[bracketrightbt] Ta bottom-right hooked bracket
.It \e[bracketrightex] Ta \[bracketrightex] Ta right hooked bracket extension
.It \e(lt Ta \(lt Ta top-left hooked brace
.It \e[bracelefttp] Ta \[bracelefttp] Ta top-left hooked brace
.It \e(lk Ta \(lk Ta mid-left hooked brace
.It \e[braceleftmid] Ta \[braceleftmid] Ta mid-left hooked brace
.It \e(lb Ta \(lb Ta bottom-left hooked brace
-.It \e[braceleftbp] Ta \[braceleftbp] Ta bottom-left hooked brace
+.It \e[braceleftbt] Ta \[braceleftbt] Ta bottom-left hooked brace
.It \e[braceleftex] Ta \[braceleftex] Ta left hooked brace extension
.It \e(rt Ta \(rt Ta top-left hooked brace
.It \e[bracerighttp] Ta \[bracerighttp] Ta top-right hooked brace
.It \e(rk Ta \(rk Ta mid-right hooked brace
.It \e[bracerightmid] Ta \[bracerightmid] Ta mid-right hooked brace
.It \e(rb Ta \(rb Ta bottom-right hooked brace
-.It \e[bracerightbp] Ta \[bracerightbp] Ta bottom-right hooked brace
+.It \e[bracerightbt] Ta \[bracerightbt] Ta bottom-right hooked brace
.It \e[bracerightex] Ta \[bracerightex] Ta right hooked brace extension
.It \e[parenlefttp] Ta \[parenlefttp] Ta top-left hooked parenthesis
-.It \e[parenleftbp] Ta \[parenleftbp] Ta bottom-left hooked parenthesis
+.It \e[parenleftbt] Ta \[parenleftbt] Ta bottom-left hooked parenthesis
.It \e[parenleftex] Ta \[parenleftex] Ta left hooked parenthesis extension
.It \e[parenrighttp] Ta \[parenrighttp] Ta top-right hooked parenthesis
-.It \e[parenrightbp] Ta \[parenrightbp] Ta bottom-right hooked parenthesis
+.It \e[parenrightbt] Ta \[parenrightbt] Ta bottom-right hooked parenthesis
.It \e[parenrightex] Ta \[parenrightex] Ta right hooked parenthesis extension
.El
.Pp
@@ -352,7 +352,7 @@ Mathematical:
.It \e(-+ Ta \(-+ Ta minus-plus
.It \e(+- Ta \(+- Ta plus-minus
.It \e[t+-] Ta \[t+-] Ta plus-minus (text)
-.It \e(pc Ta \(pc Ta centre-dot
+.It \e(pc Ta \(pc Ta center-dot
.It \e(mu Ta \(mu Ta multiply
.It \e[tmu] Ta \[tmu] Ta multiply (text)
.It \e(c* Ta \(c* Ta circle-multiply
@@ -369,11 +369,11 @@ Mathematical:
.It \e(!= Ta \(!= Ta not equal
.It \e(== Ta \(== Ta equivalent
.It \e(ne Ta \(ne Ta not equivalent
-.It \e(=~ Ta \(=~ Ta congruent
-.It \e(-~ Ta \(-~ Ta asymptotically congruent
-.It \e(ap Ta \(ap Ta asymptotically similar
-.It \e(~~ Ta \(~~ Ta approximately similar
-.It \e(~= Ta \(~= Ta approximately equal
+.It \e(ap Ta \(ap Ta tilde operator
+.It \e(|= Ta \(|= Ta asymptotically equal
+.It \e(=~ Ta \(=~ Ta approximately equal
+.It \e(~~ Ta \(~~ Ta almost equal
+.It \e(~= Ta \(~= Ta almost equal
.It \e(pt Ta \(pt Ta proportionate
.It \e(es Ta \(es Ta empty set
.It \e(mo Ta \(mo Ta element
diff --git a/mandoc_escape.3 b/mandoc_escape.3
index f381b6297fd0..fec298b87a04 100644
--- a/mandoc_escape.3
+++ b/mandoc_escape.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc_escape.3,v 1.2 2014/10/28 14:06:31 schwarze Exp $
+.\" $Id: mandoc_escape.3,v 1.3 2015/01/21 20:33:25 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,14 +14,12 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 28 2014 $
+.Dd $Mdocdate: January 21 2015 $
.Dt MANDOC_ESCAPE 3
.Os
.Sh NAME
.Nm mandoc_escape
.Nd parse roff escape sequences
-.Sh LIBRARY
-.Lb libmandoc
.Sh SYNOPSIS
.In sys/types.h
.In mandoc.h
@@ -119,8 +117,8 @@ in turn contain other escape sequences,
for error detection internally by the
.Xr roff 7
parser part of the
-.Lb libmandoc ,
-see the file
+.Xr mandoc 3
+library, see the file
.Pa roff.c ,
.It
above all externally by the
@@ -256,6 +254,10 @@ Such ASCII character escape sequences can be rendered using the function
described in the
.Xr mchars_alloc 3
manual.
+.It Dv ESCAPE_OVERSTRIKE
+The escape sequence
+.Ic \eo
+followed by an argument delimited by an arbitrary character.
.It Dv ESCAPE_IGNORE
.Bl -bullet -width 2n
.It
@@ -288,7 +290,6 @@ The escape sequences
.Ic \eA ,
.Ic \eb ,
.Ic \eD ,
-.Ic \eo ,
.Ic \eR ,
.Ic \eX ,
and
diff --git a/mandoc_headers.3 b/mandoc_headers.3
index aa8754e46ec8..79d90fff58d2 100644
--- a/mandoc_headers.3
+++ b/mandoc_headers.3
@@ -47,7 +47,7 @@ HTML formatters
search tools
.El
.Pp
-Note that mere usage of an opaque type does
+Note that mere usage of an opaque struct type does
.Em not
require inclusion of the header where that type is defined.
.Ss Parser interface
@@ -204,7 +204,11 @@ are included, the same file should not include any formatter headers.
Requires
.In sys/types.h
for
-.Vt size_t .
+.Vt size_t
+and
+.Qq Pa mandoc.h
+for
+.Vt enum mandocerr .
.Pp
Provides
.Vt enum rofferr ,
@@ -222,8 +226,7 @@ from
.Pa roff.c
for function prototypes.
Uses the types
-.Vt enum mandocerr ,
-.Vt struct tbl_span ,
+.Vt struct tbl_span
and
.Vt struct eqn
from
diff --git a/mandocdb.c b/mandocdb.c
index a2fac2027d50..9270e5cd1afe 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -1,7 +1,7 @@
-/* $Id: mandocdb.c,v 1.179 2014/12/09 07:29:42 schwarze Exp $ */
+/* $Id: mandocdb.c,v 1.185 2015/02/27 16:22:09 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -350,7 +350,8 @@ mandocdb(int argc, char *argv[])
mpages_info.alloc = mlinks_info.alloc = hash_alloc;
mpages_info.calloc = mlinks_info.calloc = hash_calloc;
- mpages_info.free = mlinks_info.free = hash_free;
+ mpages_info.free = mlinks_info.free = hash_free;
+ mpages_info.data = mlinks_info.data = NULL;
mpages_info.key_offset = offsetof(struct mpage, inodev);
mlinks_info.key_offset = offsetof(struct mlink, file);
@@ -441,7 +442,7 @@ mandocdb(int argc, char *argv[])
exitcode = (int)MANDOCLEVEL_OK;
mchars = mchars_alloc();
- mp = mparse_alloc(mparse_options, MANDOCLEVEL_FATAL, NULL,
+ mp = mparse_alloc(mparse_options, MANDOCLEVEL_BADARG, NULL,
mchars, NULL);
ohash_init(&mpages, 6, &mpages_info);
ohash_init(&mlinks, 6, &mlinks_info);
@@ -612,7 +613,11 @@ treescan(void)
say(path, "&realpath");
continue;
}
- if (strstr(buf, basedir) != buf) {
+ if (strstr(buf, basedir) != buf
+#ifdef HOMEBREWDIR
+ && strstr(buf, HOMEBREWDIR) != buf
+#endif
+ ) {
if (warnings) say("",
"%s: outside base directory", buf);
continue;
@@ -667,7 +672,8 @@ treescan(void)
say(path, "Skip pdf");
continue;
} else if ( ! use_all &&
- ((FORM_SRC == dform && strcmp(fsec, dsec)) ||
+ ((FORM_SRC == dform &&
+ strncmp(fsec, dsec, strlen(dsec))) ||
(FORM_CAT == dform && strcmp(fsec, "0")))) {
if (warnings)
say(path, "Wrong filename suffix");
@@ -817,6 +823,10 @@ filescan(const char *file)
start = buf;
else if (strstr(buf, basedir) == buf)
start = buf + strlen(basedir);
+#ifdef HOMEBREWDIR
+ else if (strstr(buf, HOMEBREWDIR) == buf)
+ start = buf;
+#endif
else {
exitcode = (int)MANDOCLEVEL_BADARG;
say("", "%s: outside base directory", buf);
@@ -852,6 +862,7 @@ filescan(const char *file)
if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
sizeof(mlink->file)) {
say(start, "Filename too long");
+ free(mlink);
return;
}
@@ -1100,11 +1111,11 @@ mpages_merge(struct mparse *mp)
char *cp;
int fd;
unsigned int pslot;
- enum mandoclevel lvl;
str_info.alloc = hash_alloc;
str_info.calloc = hash_calloc;
str_info.free = hash_free;
+ str_info.data = NULL;
str_info.key_offset = offsetof(struct str, key);
if ( ! nodb)
@@ -1113,7 +1124,7 @@ mpages_merge(struct mparse *mp)
mpage = ohash_first(&mpages, &pslot);
while (mpage != NULL) {
mlinks_undupe(mpage);
- if (mpage->mlinks == NULL) {
+ if ((mlink = mpage->mlinks) == NULL) {
mpage = ohash_next(&mpages, &pslot);
continue;
}
@@ -1126,22 +1137,19 @@ mpages_merge(struct mparse *mp)
man = NULL;
sodest = NULL;
- mparse_open(mp, &fd, mpage->mlinks->file);
+ mparse_open(mp, &fd, mlink->file);
if (fd == -1) {
- say(mpage->mlinks->file, "&open");
+ say(mlink->file, "&open");
goto nextpage;
}
/*
- * Try interpreting the file as mdoc(7) or man(7)
- * source code, unless it is already known to be
- * formatted. Fall back to formatted mode.
+ * Interpret the file as mdoc(7) or man(7) source
+ * code, unless it is known to be formatted.
*/
- if (mpage->mlinks->dform != FORM_CAT ||
- mpage->mlinks->fform != FORM_CAT) {
- lvl = mparse_readfd(mp, fd, mpage->mlinks->file);
- if (lvl < MANDOCLEVEL_FATAL)
- mparse_result(mp, &mdoc, &man, &sodest);
+ if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) {
+ mparse_readfd(mp, fd, mlink->file);
+ mparse_result(mp, &mdoc, &man, &sodest);
}
if (sodest != NULL) {
@@ -1158,7 +1166,6 @@ mpages_merge(struct mparse *mp)
/* The .so target exists. */
mpage_dest = mlink_dest->mpage;
- mlink = mpage->mlinks;
while (1) {
mlink->mpage = mpage_dest;
@@ -1198,26 +1205,20 @@ mpages_merge(struct mparse *mp)
mandoc_strdup(mdoc_meta(mdoc)->title);
} else if (man != NULL) {
mpage->form = FORM_SRC;
- mpage->sec =
- mandoc_strdup(man_meta(man)->msec);
- mpage->arch =
- mandoc_strdup(mpage->mlinks->arch);
- mpage->title =
- mandoc_strdup(man_meta(man)->title);
+ mpage->sec = mandoc_strdup(man_meta(man)->msec);
+ mpage->arch = mandoc_strdup(mlink->arch);
+ mpage->title = mandoc_strdup(man_meta(man)->title);
} else {
mpage->form = FORM_CAT;
- mpage->sec =
- mandoc_strdup(mpage->mlinks->dsec);
- mpage->arch =
- mandoc_strdup(mpage->mlinks->arch);
- mpage->title =
- mandoc_strdup(mpage->mlinks->name);
+ mpage->sec = mandoc_strdup(mlink->dsec);
+ mpage->arch = mandoc_strdup(mlink->arch);
+ mpage->title = mandoc_strdup(mlink->name);
}
putkey(mpage, mpage->sec, TYPE_sec);
if (*mpage->arch != '\0')
putkey(mpage, mpage->arch, TYPE_arch);
- for (mlink = mpage->mlinks; mlink; mlink = mlink->next) {
+ for ( ; mlink != NULL; mlink = mlink->next) {
if ('\0' != *mlink->dsec)
putkey(mpage, mlink->dsec, TYPE_sec);
if ('\0' != *mlink->fsec)
@@ -1243,11 +1244,12 @@ mpages_merge(struct mparse *mp)
mlink_check(mpage, mlink);
dbadd(mpage);
+ mlink = mpage->mlinks;
nextpage:
if (mparse_wait(mp) != MANDOCLEVEL_OK) {
exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&wait gunzip");
+ say(mlink->file, "&wait gunzip");
}
ohash_delete(&strings);
ohash_delete(&names);
diff --git a/manpage.c b/manpage.c
index 70eb06b69ceb..999f3d324762 100644
--- a/manpage.c
+++ b/manpage.c
@@ -1,4 +1,4 @@
-/* $Id: manpage.c,v 1.9 2014/08/17 03:24:47 schwarze Exp $ */
+/* $Id: manpage.c,v 1.10 2015/02/10 08:05:30 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -107,7 +107,7 @@ main(int argc, char *argv[])
return(EXIT_FAILURE);
for (i = 0; i < sz; i++) {
- printf("%6zu %s: %s\n",
+ printf("%6zu %s: %s\n",
i + 1, res[i].names, res[i].output);
free(res[i].names);
free(res[i].output);
@@ -148,11 +148,11 @@ show:
/* NOTREACHED */
usage:
fprintf(stderr, "usage: %s [-C conf] "
- "[-M paths] "
+ "[-M paths] "
"[-m paths] "
"[-S arch] "
"[-s section] "
- "expr ...\n",
+ "expr ...\n",
progname);
return(EXIT_FAILURE);
}
@@ -174,9 +174,9 @@ show(const char *cmd, const char *file)
} else if (pid > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[1]);
- cmd = NULL != getenv("MANPAGER") ?
+ cmd = NULL != getenv("MANPAGER") ?
getenv("MANPAGER") :
- (NULL != getenv("PAGER") ?
+ (NULL != getenv("PAGER") ?
getenv("PAGER") : "more");
execlp(cmd, cmd, (char *)NULL);
perror(cmd);
diff --git a/mansearch.c b/mansearch.c
index dbfbe0255fd4..27cfa65568a1 100644
--- a/mansearch.c
+++ b/mansearch.c
@@ -1,7 +1,7 @@
-/* $Id: mansearch.c,v 1.52 2014/12/06 01:23:24 schwarze Exp $ */
+/* $Id: mansearch.c,v 1.54 2015/02/27 16:02:10 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,6 +24,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <glob.h>
#include <limits.h>
#include <regex.h>
#include <stdio.h>
@@ -85,7 +86,8 @@ struct match {
int form; /* bit field: formatted, zipped? */
};
-static void buildnames(struct manpage *, sqlite3 *,
+static void buildnames(const struct mansearch *,
+ struct manpage *, sqlite3 *,
sqlite3_stmt *, uint64_t,
const char *, int form);
static char *buildoutput(sqlite3 *, sqlite3_stmt *,
@@ -96,8 +98,6 @@ static void *hash_calloc(size_t, size_t, void *);
static struct expr *exprcomp(const struct mansearch *,
int, char *[]);
static void exprfree(struct expr *);
-static struct expr *exprspec(struct expr *, uint64_t,
- const char *, const char *);
static struct expr *exprterm(const struct mansearch *, char *, int);
static int manpage_compare(const void *, const void *);
static void sql_append(char **sql, size_t *sz,
@@ -343,14 +343,16 @@ mansearch(const struct mansearch *search,
mpage->bits = mp->bits;
mpage->sec = 10;
mpage->form = mp->form;
- buildnames(mpage, db, s, mp->pageid,
+ buildnames(search, mpage, db, s, mp->pageid,
paths->paths[i], mp->form);
- mpage->output = TYPE_Nd & outbit ?
- mp->desc : outbit ?
- buildoutput(db, s2, mp->pageid, outbit) : NULL;
-
+ if (mpage->names != NULL) {
+ mpage->output = TYPE_Nd & outbit ?
+ mp->desc : outbit ?
+ buildoutput(db, s2, mp->pageid, outbit) :
+ NULL;
+ cur++;
+ }
free(mp);
- cur++;
}
sqlite3_finalize(s);
@@ -407,17 +409,19 @@ manpage_compare(const void *vp1, const void *vp2)
}
static void
-buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
+buildnames(const struct mansearch *search, struct manpage *mpage,
+ sqlite3 *db, sqlite3_stmt *s,
uint64_t pageid, const char *path, int form)
{
- char *newnames, *prevsec, *prevarch;
+ glob_t globinfo;
+ char *firstname, *newnames, *prevsec, *prevarch;
const char *oldnames, *sep1, *name, *sec, *sep2, *arch, *fsec;
size_t i;
- int c;
+ int c, globres;
mpage->file = NULL;
mpage->names = NULL;
- prevsec = prevarch = NULL;
+ firstname = prevsec = prevarch = NULL;
i = 1;
SQL_BIND_INT64(db, s, i, pageid);
while (SQLITE_ROW == (c = sqlite3_step(s))) {
@@ -432,10 +436,15 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
sep1 = ", ";
}
- /* Fetch the next name. */
+ /* Fetch the next name, rejecting sec/arch mismatches. */
sec = (const char *)sqlite3_column_text(s, 0);
+ if (search->sec != NULL && strcasecmp(sec, search->sec))
+ continue;
arch = (const char *)sqlite3_column_text(s, 1);
+ if (search->arch != NULL && *arch != '\0' &&
+ strcasecmp(arch, search->arch))
+ continue;
name = (const char *)sqlite3_column_text(s, 2);
/* Remember the first section found. */
@@ -487,11 +496,34 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
sep2 = *arch == '\0' ? "" : "/";
mandoc_asprintf(&mpage->file, "%s/%s%s%s%s/%s.%s",
path, sep1, sec, sep2, arch, name, fsec);
+ if (access(mpage->file, R_OK) != -1)
+ continue;
+
+ /* Handle unusual file name extensions. */
+
+ if (firstname == NULL)
+ firstname = mpage->file;
+ else
+ free(mpage->file);
+ mandoc_asprintf(&mpage->file, "%s/%s%s%s%s/%s.*",
+ path, sep1, sec, sep2, arch, name);
+ globres = glob(mpage->file, 0, NULL, &globinfo);
+ free(mpage->file);
+ mpage->file = globres ? NULL :
+ mandoc_strdup(*globinfo.gl_pathv);
+ globfree(&globinfo);
}
if (c != SQLITE_DONE)
fprintf(stderr, "%s\n", sqlite3_errmsg(db));
sqlite3_reset(s);
+ /* If none of the files is usable, use the first name. */
+
+ if (mpage->file == NULL)
+ mpage->file = firstname;
+ else if (mpage->file != firstname)
+ free(firstname);
+
/* Append one final section to the names. */
if (prevsec != NULL) {
@@ -645,8 +677,7 @@ exprcomp(const struct mansearch *search, int argc, char *argv[])
struct expr *first, *prev, *cur, *next;
first = cur = NULL;
- logic = igncase = toclose = 0;
- toopen = NULL != search->sec || NULL != search->arch;
+ logic = igncase = toopen = toclose = 0;
for (i = 0; i < argc; i++) {
if (0 == strcmp("(", argv[i])) {
@@ -712,17 +743,8 @@ exprcomp(const struct mansearch *search, int argc, char *argv[])
toopen = logic = igncase = 0;
}
- if (toopen || logic || igncase || toclose)
- goto fail;
-
- if (NULL != search->sec || NULL != search->arch)
- cur->close++;
- if (NULL != search->arch)
- cur = exprspec(cur, TYPE_arch, search->arch, "^(%s|any)$");
- if (NULL != search->sec)
- exprspec(cur, TYPE_sec, search->sec, "^%s$");
-
- return(first);
+ if ( ! (toopen || logic || igncase || toclose))
+ return(first);
fail:
if (NULL != first)
@@ -731,29 +753,6 @@ fail:
}
static struct expr *
-exprspec(struct expr *cur, uint64_t key, const char *value,
- const char *format)
-{
- char errbuf[BUFSIZ];
- char *cp;
- int irc;
-
- mandoc_asprintf(&cp, format, value);
- cur->next = mandoc_calloc(1, sizeof(struct expr));
- cur = cur->next;
- cur->and = 1;
- cur->bits = key;
- if (0 != (irc = regcomp(&cur->regexp, cp,
- REG_EXTENDED | REG_NOSUB | REG_ICASE))) {
- regerror(irc, &cur->regexp, errbuf, sizeof(errbuf));
- fprintf(stderr, "regcomp: %s\n", errbuf);
- cur->substr = value;
- }
- free(cp);
- return(cur);
-}
-
-static struct expr *
exprterm(const struct mansearch *search, char *buf, int cs)
{
char errbuf[BUFSIZ];
diff --git a/mdoc.7 b/mdoc.7
index a9b0fe2f3ac2..d4c8ccd11c4b 100644
--- a/mdoc.7
+++ b/mdoc.7
@@ -1,4 +1,4 @@
-.\" $Id: mdoc.7,v 1.245 2014/11/30 21:56:18 schwarze Exp $
+.\" $Id: mdoc.7,v 1.252 2015/02/23 13:31:04 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 30 2014 $
+.Dd $Mdocdate: February 23 2015 $
.Dt MDOC 7
.Os
.Sh NAME
@@ -454,6 +454,7 @@ in the alphabetical
.Op Fl compact
.It Sx \&D1 Ta indented display (one line)
.It Sx \&Dl Ta indented literal display (one line)
+.It Sx \&Ql Ta in-line literal display: Ql text
.It Sx \&Bl , \&El Ta list block:
.Fl Ar type
.Op Fl width Ar val
@@ -528,7 +529,6 @@ in the alphabetical
.It Sx \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text
.It Sx \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text
.It Sx \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text
-.It Sx \&Ql Ta single-quoted literal text: Ql text
.It Sx \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text
.It Sx \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text
.It Sx \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text
@@ -777,7 +777,7 @@ The
must be one of the following:
.Bl -tag -width 13n -offset indent
.It Fl centered
-Produce one output line from each input line, and centre-justify each line.
+Produce one output line from each input line, and center-justify each line.
Using this display type is not recommended; many
.Nm
implementations render it poorly.
@@ -822,7 +822,7 @@ which has no effect;
.Cm right ,
which justifies to the right margin; or
.Cm center ,
-which aligns around an imagined centre axis.
+which aligns around an imagined center axis.
.It
A macro invocation, which selects a predefined width
associated with that macro.
@@ -1256,7 +1256,9 @@ Examples:
.Dl \&.Dl % mandoc mdoc.7 \e(ba less
.Pp
See also
+.Sx \&Ql ,
.Sx \&Bd
+.Fl literal ,
and
.Sx \&D1 .
.Ss \&Do
@@ -1314,38 +1316,26 @@ it should by convention be all caps.
The manual section.
This may be one of
.Cm 1
-.Pq utilities ,
+.Pq General Commands ,
.Cm 2
-.Pq system calls ,
+.Pq System Calls ,
.Cm 3
-.Pq libraries ,
+.Pq Library Functions ,
.Cm 3p
-.Pq Perl libraries ,
+.Pq Perl Library ,
.Cm 4
-.Pq devices ,
+.Pq Device Drivers ,
.Cm 5
-.Pq file formats ,
+.Pq File Formats ,
.Cm 6
-.Pq games ,
+.Pq Games ,
.Cm 7
-.Pq miscellaneous ,
+.Pq Miscellaneous Information ,
.Cm 8
-.Pq system utilities ,
-.Cm 9
-.Pq kernel functions ,
-.Cm X11
-.Pq X Window System ,
-.Cm X11R6
-.Pq X Window System ,
-.Cm unass
-.Pq unassociated ,
-.Cm local
-.Pq local system ,
-.Cm draft
-.Pq draft manual ,
+.Pq System Manager's Manual ,
or
-.Cm paper
-.Pq paper .
+.Cm 9
+.Pq Kernel Developer's Manual .
It should correspond to the manual's filename suffix and defaults to
the empty string if unspecified.
.It Ar arch
@@ -1768,17 +1758,18 @@ is preferred for displaying code; the
.Sx \&Ic
macro is used when referring to specific instructions.
.Ss \&In
-An
-.Dq include
-file.
+The name of an include file.
+This macro is most often used in section 2, 3, and 9 manual pages.
+.Pp
When invoked as the first macro on an input line in the
.Em SYNOPSIS
section, the argument is displayed in angle brackets
and preceded by
-.Dq #include ,
+.Qq #include ,
and a blank line is inserted in front if there is a preceding
function declaration.
-This is most often used in section 2, 3, and 9 manual pages.
+In other sections, it only encloses its argument in angle brackets
+and causes no line break.
.Pp
Examples:
.Dl \&.In sys/types.h
@@ -1939,11 +1930,9 @@ Examples:
.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv
.Ss \&Nd
A one line description of the manual's content.
-This may only be invoked in the
-.Em SYNOPSIS
-section subsequent the
-.Sx \&Nm
-macro.
+This is the mandatory last macro of the
+.Em NAME
+section and not appropriate for other sections.
.Pp
Examples:
.Dl Pf . Sx \&Nd mdoc language reference
@@ -2100,8 +2089,16 @@ Its syntax is as follows:
The optional
.Ar system
parameter specifies the relevant operating system or environment.
-Left unspecified, it defaults to the local operating system version.
-This is the suggested form.
+It is suggested to leave it unspecified, in which case
+.Xr mandoc 1
+uses its
+.Fl Ios
+argument, or, if that isn't specified either,
+.Fa sysname
+and
+.Fa release
+as returned by
+.Xr uname 3 .
.Pp
Examples:
.Dl \&.Os
@@ -2205,11 +2202,21 @@ See also
Close quoted context opened by
.Sx \&Qo .
.Ss \&Ql
-Format a single-quoted literal.
+In-line literal display.
+This can for example be used for complete command invocations and
+for multi-word code fragments when more specific markup is not
+appropriate and an indented display is not desired.
+While
+.Xr mandoc 1
+always encloses the arguments in single quotes, other formatters
+usually omit the quotes on non-terminal output devices when the
+arguments have three or more characters.
+.Pp
See also
-.Sx \&Qq
+.Sx \&Dl
and
-.Sx \&Sq .
+.Sx \&Bd
+.Fl literal .
.Ss \&Qo
Multi-line version of
.Sx \&Qq .
@@ -3125,50 +3132,13 @@ Manually switching the font using the
font escape sequences is never required.
.Sh COMPATIBILITY
This section provides an incomplete list of compatibility issues
-between mandoc and other troff implementations, at this time limited
-to GNU troff
+between mandoc and GNU troff
.Pq Qq groff .
-The term
-.Qq historic groff
-refers to groff versions before 1.17,
-which featured a significant update of the
-.Pa doc.tmac
-file.
-.Pp
-Heirloom troff, the other significant troff implementation accepting
-\-mdoc, is similar to historic groff.
.Pp
The following problematic behaviour is found in groff:
-.ds hist (Historic groff only.)
.Pp
.Bl -dash -compact
.It
-Display macros
-.Po
-.Sx \&Bd ,
-.Sx \&Dl ,
-and
-.Sx \&D1
-.Pc
-may not be nested.
-\*[hist]
-.It
-.Sx \&At
-with unknown arguments produces no output at all.
-\*[hist]
-Newer groff and mandoc print
-.Qq AT&T UNIX
-and the arguments.
-.It
-.Sx \&Bl Fl column
-does not recognise trailing punctuation characters when they immediately
-precede tabulator characters, but treats them as normal text and
-outputs a space before them.
-.It
-.Sx \&Bd Fl ragged compact
-does not start a new line.
-\*[hist]
-.It
.Sx \&Dd
with non-standard arguments behaves very strangely.
When there are three arguments, they are printed verbatim.
@@ -3177,53 +3147,6 @@ but without any arguments the string
.Dq Epoch
is printed.
.It
-.Sx \&Fl
-does not print a dash for an empty argument.
-\*[hist]
-.It
-.Sx \&Fn
-does not start a new line unless invoked as the line macro in the
-.Em SYNOPSIS
-section.
-\*[hist]
-.It
-.Sx \&Fo
-with
-.Pf non- Sx \&Fa
-children causes inconsistent spacing between arguments.
-In mandoc, a single space is always inserted between arguments.
-.It
-.Sx \&Ft
-in the
-.Em SYNOPSIS
-causes inconsistent vertical spacing, depending on whether a prior
-.Sx \&Fn
-has been invoked.
-See
-.Sx \&Ft
-and
-.Sx \&Fn
-for the normalised behaviour in mandoc.
-.It
-.Sx \&In
-ignores additional arguments and is not treated specially in the
-.Em SYNOPSIS .
-\*[hist]
-.It
-.Sx \&It
-sometimes requires a
-.Fl nested
-flag.
-\*[hist]
-In new groff and mandoc, any list may be nested by default and
-.Fl enum
-lists will restart the sequence only for the sub-list.
-.It
-.Sx \&Li
-followed by a delimiter is incorrectly used in some manuals
-instead of properly quoting that character, which sometimes works with
-historic groff.
-.It
.Sx \&Lk
only accepts a single link-name argument; the remainder is misformatted.
.It
@@ -3237,19 +3160,6 @@ can only be called by other macros, but not at the beginning of a line.
.Sx \&%C
is not implemented (up to and including groff-1.22.2).
.It
-Historic groff only allows up to eight or nine arguments per macro input
-line, depending on the exact situation.
-Providing more arguments causes garbled output.
-The number of arguments on one input line is not limited with mandoc.
-.It
-Historic groff has many un-callable macros.
-Most of these (excluding some block-level macros) are callable
-in new groff and mandoc.
-.It
-.Sq \(ba
-(vertical bar) is not fully supported as a delimiter.
-\*[hist]
-.It
.Sq \ef
.Pq font face
and
@@ -3267,13 +3177,27 @@ The following features are unimplemented in mandoc:
.Bl -dash -compact
.It
.Sx \&Bd
-.Fl file Ar file .
+.Fl file Ar file
+is unsupported for security reasons.
+.It
+.Sx \&Bd
+.Fl filled
+does not adjust the right margin, but is an alias for
+.Sx \&Bd
+.Fl ragged .
+.It
+.Sx \&Bd
+.Fl literal
+does not use a literal font, but is an alias for
+.Sx \&Bd
+.Fl unfilled .
.It
.Sx \&Bd
.Fl offset Cm center
and
-.Fl offset Cm right .
-Groff does not implement centred and flush-right rendering either,
+.Fl offset Cm right
+don't work.
+Groff does not implement centered and flush-right rendering either,
but produces large indentations.
.El
.Sh SEE ALSO
diff --git a/mdoc.c b/mdoc.c
index 3e80bc7786a5..027ecbeb317f 100644
--- a/mdoc.c
+++ b/mdoc.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc.c,v 1.233 2014/11/28 06:27:05 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.238 2015/02/12 13:00:52 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -190,12 +190,11 @@ mdoc_alloc(struct roff *roff, struct mparse *parse,
return(p);
}
-int
+void
mdoc_endparse(struct mdoc *mdoc)
{
mdoc_macroend(mdoc);
- return(1);
}
void
@@ -364,7 +363,6 @@ node_alloc(struct mdoc *mdoc, int line, int pos,
p->sec = mdoc->lastsec;
p->line = line;
p->pos = pos;
- p->lastline = line;
p->tok = tok;
p->type = type;
@@ -415,18 +413,21 @@ mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
return(p);
}
-void
+struct mdoc_node *
mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
struct mdoc_node *body, enum mdoc_endbody end)
{
struct mdoc_node *p;
+ body->flags |= MDOC_ENDED;
+ body->parent->flags |= MDOC_ENDED;
p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
- p->pending = body;
+ p->body = body;
p->norm = body->norm;
p->end = end;
node_append(mdoc, p);
mdoc->next = MDOC_NEXT_SIBLING;
+ return(p);
}
struct mdoc_node *
@@ -600,8 +601,8 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
* process within its context in the normal way).
*/
- if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->norm->Bl.type) {
+ if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
+ n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
/* `Bl' is open without any children. */
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
@@ -777,8 +778,8 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
* context around the parsed macro.
*/
- if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->norm->Bl.type) {
+ if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
+ n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
return(1);
diff --git a/mdoc.h b/mdoc.h
index f7c933d562e9..e45786d4aa6a 100644
--- a/mdoc.h
+++ b/mdoc.h
@@ -1,6 +1,7 @@
-/* $Id: mdoc.h,v 1.132 2014/12/01 04:05:32 schwarze Exp $ */
+/* $Id: mdoc.h,v 1.136 2015/02/12 12:24:33 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -352,25 +353,24 @@ struct mdoc_node {
int nchild; /* number children */
int line; /* parse line */
int pos; /* parse column */
- int lastline; /* the node ends on this line */
enum mdoct tok; /* tok or MDOC__MAX if none */
int flags;
#define MDOC_VALID (1 << 0) /* has been validated */
+#define MDOC_ENDED (1 << 1) /* gone past body end mark */
#define MDOC_EOS (1 << 2) /* at sentence boundary */
#define MDOC_LINE (1 << 3) /* first macro/text on line */
#define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting */
-#define MDOC_ENDED (1 << 5) /* rendering has been ended */
+#define MDOC_BROKEN (1 << 5) /* must validate parent when ending */
#define MDOC_DELIMO (1 << 6)
#define MDOC_DELIMC (1 << 7)
enum mdoc_type type; /* AST node type */
enum mdoc_sec sec; /* current named section */
union mdoc_data *norm; /* normalised args */
- const void *prev_font; /* before entering this node */
+ int prev_font; /* before entering this node */
/* FIXME: these can be union'd to shave a few bytes. */
struct mdoc_arg *args; /* BLOCK/ELEM */
- struct mdoc_node *pending; /* BLOCK */
struct mdoc_node *head; /* BLOCK */
- struct mdoc_node *body; /* BLOCK */
+ struct mdoc_node *body; /* BLOCK/ENDBODY */
struct mdoc_node *tail; /* BLOCK */
char *string; /* TEXT */
const struct tbl_span *span; /* TBL */
diff --git a/mdoc_argv.c b/mdoc_argv.c
index 3e7fabd2ae1c..a53389bf99cc 100644
--- a/mdoc_argv.c
+++ b/mdoc_argv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD$ */
+/* $Id: mdoc_argv.c,v 1.100 2015/02/04 18:59:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -339,7 +339,7 @@ mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
/* Parse the arguments of the flag. */
tmpv.line = line;
- tmpv.pos = ipos;
+ tmpv.pos = *pos;
tmpv.sz = 0;
tmpv.value = NULL;
diff --git a/mdoc_html.c b/mdoc_html.c
index ca51049eec53..09104f8f142a 100644
--- a/mdoc_html.c
+++ b/mdoc_html.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_html.c,v 1.216 2014/12/02 10:08:06 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.225 2015/02/12 12:24:33 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -35,7 +35,7 @@
#define INDENT 5
#define MDOC_ARGS const struct mdoc_meta *meta, \
- const struct mdoc_node *n, \
+ struct mdoc_node *n, \
struct html *h
#ifndef MIN
@@ -81,6 +81,8 @@ static int mdoc_fl_pre(MDOC_ARGS);
static int mdoc_fn_pre(MDOC_ARGS);
static int mdoc_ft_pre(MDOC_ARGS);
static int mdoc_em_pre(MDOC_ARGS);
+static void mdoc_eo_post(MDOC_ARGS);
+static int mdoc_eo_pre(MDOC_ARGS);
static int mdoc_er_pre(MDOC_ARGS);
static int mdoc_ev_pre(MDOC_ARGS);
static int mdoc_ex_pre(MDOC_ARGS);
@@ -189,7 +191,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{NULL, NULL}, /* Ec */ /* FIXME: no space */
{NULL, NULL}, /* Ef */
{mdoc_em_pre, NULL}, /* Em */
- {mdoc_quote_pre, mdoc_quote_post}, /* Eo */
+ {mdoc_eo_pre, mdoc_eo_post}, /* Eo */
{mdoc_xx_pre, NULL}, /* Fx */
{mdoc_ms_pre, NULL}, /* Ms */
{mdoc_no_pre, NULL}, /* No */
@@ -265,7 +267,7 @@ void
html_mdoc(void *arg, const struct mdoc *mdoc)
{
- print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc),
+ print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc)->child,
(struct html *)arg);
putchar('\n');
}
@@ -279,10 +281,11 @@ static void
a2width(const char *p, struct roffsu *su)
{
- if ( ! a2roffsu(p, su, SCALE_MAX)) {
+ if (a2roffsu(p, su, SCALE_MAX) < 2) {
su->unit = SCALE_EN;
su->scale = html_strlen(p);
- }
+ } else if (su->scale < 0.0)
+ su->scale = 0.0;
}
/*
@@ -370,9 +373,10 @@ static void
print_mdoc_nodelist(MDOC_ARGS)
{
- print_mdoc_node(meta, n, h);
- if (n->next)
- print_mdoc_nodelist(meta, n->next, h);
+ while (n != NULL) {
+ print_mdoc_node(meta, n, h);
+ n = n->next;
+ }
}
static void
@@ -383,6 +387,7 @@ print_mdoc_node(MDOC_ARGS)
child = 1;
t = h->tags.head;
+ n->flags &= ~MDOC_ENDED;
switch (n->type) {
case MDOC_ROOT:
@@ -432,12 +437,9 @@ print_mdoc_node(MDOC_ARGS)
break;
}
- if (HTML_KEEP & h->flags) {
- if (n->prev ? (n->prev->lastline != n->line) :
- (n->parent && n->parent->line != n->line)) {
- h->flags &= ~HTML_KEEP;
- h->flags |= HTML_PREKEEP;
- }
+ if (h->flags & HTML_KEEP && n->flags & MDOC_LINE) {
+ h->flags &= ~HTML_KEEP;
+ h->flags |= HTML_PREKEEP;
}
if (child && n->child)
@@ -456,7 +458,7 @@ print_mdoc_node(MDOC_ARGS)
break;
(*mdocs[n->tok].post)(meta, n, h);
if (n->end != ENDBODY_NOT)
- n->pending->flags |= MDOC_ENDED;
+ n->body->flags |= MDOC_ENDED;
if (n->end == ENDBODY_NOSPACE)
h->flags |= HTML_NOSPACE;
break;
@@ -1121,7 +1123,7 @@ mdoc_bd_pre(MDOC_ARGS)
{
struct htmlpair tag[2];
int comp, sv;
- const struct mdoc_node *nn;
+ struct mdoc_node *nn;
struct roffsu su;
if (MDOC_HEAD == n->type)
@@ -1252,9 +1254,6 @@ mdoc_an_pre(MDOC_ARGS)
return(0);
}
- if (n->child == NULL)
- return(0);
-
if (h->flags & HTML_SPLIT)
print_otag(h, TAG_BR, 0, NULL);
@@ -1566,9 +1565,12 @@ mdoc_sp_pre(MDOC_ARGS)
SCALE_VS_INIT(&su, 1);
if (MDOC_sp == n->tok) {
- if (NULL != (n = n->child))
+ if (NULL != (n = n->child)) {
if ( ! a2roffsu(n->string, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(n->string));
+ su.scale = 1.0;
+ else if (su.scale < 0.0)
+ su.scale = 0.0;
+ }
} else
su.scale = 0.0;
@@ -2080,8 +2082,8 @@ mdoc_quote_pre(MDOC_ARGS)
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- print_text(h, n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
+ print_text(h, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
break;
case MDOC_Bro:
/* FALLTHROUGH */
@@ -2107,8 +2109,6 @@ mdoc_quote_pre(MDOC_ARGS)
return(1);
print_text(h, n->norm->Es->child->string);
break;
- case MDOC_Eo:
- break;
case MDOC_Do:
/* FALLTHROUGH */
case MDOC_Dq:
@@ -2150,16 +2150,14 @@ mdoc_quote_post(MDOC_ARGS)
if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
- if ( ! (n->tok == MDOC_En ||
- (n->tok == MDOC_Eo && n->end == ENDBODY_SPACE)))
- h->flags |= HTML_NOSPACE;
+ h->flags |= HTML_NOSPACE;
switch (n->tok) {
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- print_text(h, n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
+ print_text(h, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
break;
case MDOC_Bro:
/* FALLTHROUGH */
@@ -2176,14 +2174,12 @@ mdoc_quote_post(MDOC_ARGS)
print_text(h, "\\(rB");
break;
case MDOC_En:
- if (NULL != n->norm->Es &&
- NULL != n->norm->Es->child &&
- NULL != n->norm->Es->child->next) {
- h->flags |= HTML_NOSPACE;
+ if (n->norm->Es == NULL ||
+ n->norm->Es->child == NULL ||
+ n->norm->Es->child->next == NULL)
+ h->flags &= ~HTML_NOSPACE;
+ else
print_text(h, n->norm->Es->child->next->string);
- }
- break;
- case MDOC_Eo:
break;
case MDOC_Qo:
/* FALLTHROUGH */
@@ -2211,3 +2207,44 @@ mdoc_quote_post(MDOC_ARGS)
/* NOTREACHED */
}
}
+
+static int
+mdoc_eo_pre(MDOC_ARGS)
+{
+
+ if (n->type != MDOC_BODY)
+ return(1);
+
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ print_text(h, "\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL && (n->child != NULL ||
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+ h->flags |= HTML_NOSPACE;
+ return(1);
+}
+
+static void
+mdoc_eo_post(MDOC_ARGS)
+{
+ int body, tail;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->end != ENDBODY_NOT) {
+ h->flags &= ~HTML_NOSPACE;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+ if (body && tail)
+ h->flags |= HTML_NOSPACE;
+ else if ( ! tail)
+ h->flags &= ~HTML_NOSPACE;
+}
diff --git a/mdoc_macro.c b/mdoc_macro.c
index b354e540a1bf..efb48d023f83 100644
--- a/mdoc_macro.c
+++ b/mdoc_macro.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_macro.c,v 1.157 2014/12/13 13:14:39 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.183 2015/02/12 12:24:33 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -31,15 +31,6 @@
#include "libmdoc.h"
#include "libmandoc.h"
-enum rew { /* see rew_dohalt() */
- REWIND_NONE,
- REWIND_THIS,
- REWIND_MORE,
- REWIND_FORCE,
- REWIND_LATER,
- REWIND_ERROR
-};
-
static void blk_full(MACRO_PROT_ARGS);
static void blk_exp_close(MACRO_PROT_ARGS);
static void blk_part_exp(MACRO_PROT_ARGS);
@@ -56,17 +47,12 @@ static void append_delims(struct mdoc *, int, int *, char *);
static enum mdoct lookup(struct mdoc *, enum mdoct,
int, int, const char *);
static int macro_or_word(MACRO_PROT_ARGS, int);
-static int make_pending(struct mdoc_node *, enum mdoct,
- struct mdoc *, int, int);
static int parse_rest(struct mdoc *, enum mdoct,
int, int *, char *);
static enum mdoct rew_alt(enum mdoct);
-static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
- const struct mdoc_node *);
static void rew_elem(struct mdoc *, enum mdoct);
static void rew_last(struct mdoc *, const struct mdoc_node *);
-static void rew_sub(enum mdoc_type, struct mdoc *,
- enum mdoct, int, int);
+static void rew_pending(struct mdoc *, const struct mdoc_node *);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
@@ -263,6 +249,9 @@ lookup(struct mdoc *mdoc, enum mdoct from, int line, int ppos, const char *p)
return(MDOC_MAX);
}
+/*
+ * Rewind up to and including a specific node.
+ */
static void
rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
{
@@ -288,6 +277,44 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
}
/*
+ * Rewind up to a specific block, including all blocks that broke it.
+ */
+static void
+rew_pending(struct mdoc *mdoc, const struct mdoc_node *n)
+{
+
+ for (;;) {
+ rew_last(mdoc, n);
+
+ switch (n->type) {
+ case MDOC_HEAD:
+ mdoc_body_alloc(mdoc, n->line, n->pos, n->tok);
+ return;
+ case MDOC_BLOCK:
+ break;
+ default:
+ return;
+ }
+
+ if ( ! (n->flags & MDOC_BROKEN))
+ return;
+
+ for (;;) {
+ if ((n = n->parent) == NULL)
+ return;
+
+ if (n->type == MDOC_BLOCK ||
+ n->type == MDOC_HEAD) {
+ if (n->flags & MDOC_ENDED)
+ break;
+ else
+ return;
+ }
+ }
+ }
+}
+
+/*
* For a block closing macro, return the corresponding opening one.
* Otherwise, return the macro itself.
*/
@@ -333,119 +360,6 @@ rew_alt(enum mdoct tok)
/* NOTREACHED */
}
-/*
- * Rewinding to tok, how do we have to handle *p?
- * REWIND_NONE: *p would delimit tok, but no tok scope is open
- * inside *p, so there is no need to rewind anything at all.
- * REWIND_THIS: *p matches tok, so rewind *p and nothing else.
- * REWIND_MORE: *p is implicit, rewind it and keep searching for tok.
- * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p.
- * REWIND_LATER: *p is explicit and still open, postpone rewinding.
- * REWIND_ERROR: No tok block is open at all.
- */
-static enum rew
-rew_dohalt(enum mdoct tok, enum mdoc_type type,
- const struct mdoc_node *p)
-{
-
- /*
- * No matching token, no delimiting block, no broken block.
- * This can happen when full implicit macros are called for
- * the first time but try to rewind their previous
- * instance anyway.
- */
- if (MDOC_ROOT == p->type)
- return(MDOC_BLOCK == type &&
- MDOC_EXPLICIT & mdoc_macros[tok].flags ?
- REWIND_ERROR : REWIND_NONE);
-
- /*
- * When starting to rewind, skip plain text
- * and nodes that have already been rewound.
- */
- if (MDOC_TEXT == p->type || MDOC_VALID & p->flags)
- return(REWIND_MORE);
-
- /*
- * The easiest case: Found a matching token.
- * This applies to both blocks and elements.
- */
- tok = rew_alt(tok);
- if (tok == p->tok)
- return(p->end ? REWIND_NONE :
- type == p->type ? REWIND_THIS : REWIND_MORE);
-
- /*
- * While elements do require rewinding for themselves,
- * they never affect rewinding of other nodes.
- */
- if (MDOC_ELEM == p->type)
- return(REWIND_MORE);
-
- /*
- * Blocks delimited by our target token get REWIND_MORE.
- * Blocks delimiting our target token get REWIND_NONE.
- */
- switch (tok) {
- case MDOC_Bl:
- if (MDOC_It == p->tok)
- return(REWIND_MORE);
- break;
- case MDOC_It:
- if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
- return(REWIND_NONE);
- break;
- /*
- * XXX Badly nested block handling still fails badly
- * when one block is breaking two blocks of the same type.
- * This is an incomplete and extremely ugly workaround,
- * required to let the OpenBSD tree build.
- */
- case MDOC_Oo:
- if (MDOC_Op == p->tok)
- return(REWIND_MORE);
- break;
- case MDOC_Nm:
- return(REWIND_NONE);
- case MDOC_Nd:
- /* FALLTHROUGH */
- case MDOC_Ss:
- if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
- return(REWIND_NONE);
- /* FALLTHROUGH */
- case MDOC_Sh:
- if (MDOC_ROOT == p->parent->type)
- return(REWIND_THIS);
- if (MDOC_Nd == p->tok || MDOC_Ss == p->tok ||
- MDOC_Sh == p->tok)
- return(REWIND_MORE);
- break;
- default:
- break;
- }
-
- /*
- * Default block rewinding rules.
- * In particular, always skip block end markers,
- * and let all blocks rewind Nm children.
- * Do not warn again when closing a block,
- * since closing the body already warned.
- */
- if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok ||
- MDOC_BLOCK == type || (MDOC_BLOCK == p->type &&
- ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)))
- return(REWIND_MORE);
-
- /*
- * By default, closing out full blocks
- * forces closing of broken explicit blocks,
- * while closing out partial blocks
- * allows delayed rewinding by default.
- */
- return (&blk_full == mdoc_macros[tok].fp ?
- REWIND_FORCE : REWIND_LATER);
-}
-
static void
rew_elem(struct mdoc *mdoc, enum mdoct tok)
{
@@ -460,136 +374,6 @@ rew_elem(struct mdoc *mdoc, enum mdoct tok)
}
/*
- * We are trying to close a block identified by tok,
- * but the child block *broken is still open.
- * Thus, postpone closing the tok block
- * until the rew_sub call closing *broken.
- */
-static int
-make_pending(struct mdoc_node *broken, enum mdoct tok,
- struct mdoc *mdoc, int line, int ppos)
-{
- struct mdoc_node *breaker;
-
- /*
- * Iterate backwards, searching for the block matching tok,
- * that is, the block breaking the *broken block.
- */
- for (breaker = broken->parent; breaker; breaker = breaker->parent) {
-
- /*
- * If the *broken block had already been broken before
- * and we encounter its breaker, make the tok block
- * pending on the inner breaker.
- * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]"
- * becomes "[A broken=[B [C->B B] tok=A] C]"
- * and finally "[A [B->A [C->B B] A] C]".
- */
- if (breaker == broken->pending) {
- broken = breaker;
- continue;
- }
-
- if (REWIND_THIS != rew_dohalt(tok, MDOC_BLOCK, breaker))
- continue;
- if (MDOC_BODY == broken->type)
- broken = broken->parent;
-
- /*
- * Found the breaker.
- * If another, outer breaker is already pending on
- * the *broken block, we must not clobber the link
- * to the outer breaker, but make it pending on the
- * new, now inner breaker.
- * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]"
- * becomes "[A breaker=[B->A broken=[C A] tok=B] C]"
- * and finally "[A [B->A [C->B A] B] C]".
- */
- if (broken->pending) {
- struct mdoc_node *taker;
-
- /*
- * If the breaker had also been broken before,
- * it cannot take on the outer breaker itself,
- * but must hand it on to its own breakers.
- * Graphically, this is the following situation:
- * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]"
- * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]"
- */
- taker = breaker;
- while (taker->pending)
- taker = taker->pending;
- taker->pending = broken->pending;
- }
- broken->pending = breaker;
- mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos,
- "%s breaks %s", mdoc_macronames[tok],
- mdoc_macronames[broken->tok]);
- return(1);
- }
-
- /*
- * Found no matching block for tok.
- * Are you trying to close a block that is not open?
- */
- return(0);
-}
-
-static void
-rew_sub(enum mdoc_type t, struct mdoc *mdoc,
- enum mdoct tok, int line, int ppos)
-{
- struct mdoc_node *n;
-
- n = mdoc->last;
- while (n) {
- switch (rew_dohalt(tok, t, n)) {
- case REWIND_NONE:
- return;
- case REWIND_THIS:
- n->lastline = line -
- (mdoc->flags & MDOC_NEWLINE &&
- ! (mdoc_macros[tok].flags & MDOC_EXPLICIT));
- break;
- case REWIND_FORCE:
- mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse,
- line, ppos, "%s breaks %s",
- mdoc_macronames[tok],
- mdoc_macronames[n->tok]);
- /* FALLTHROUGH */
- case REWIND_MORE:
- n->lastline = line -
- (mdoc->flags & MDOC_NEWLINE ? 1 : 0);
- n = n->parent;
- continue;
- case REWIND_LATER:
- if (make_pending(n, tok, mdoc, line, ppos) ||
- t != MDOC_BLOCK)
- return;
- /* FALLTHROUGH */
- case REWIND_ERROR:
- mandoc_msg(MANDOCERR_BLK_NOTOPEN,
- mdoc->parse, line, ppos,
- mdoc_macronames[tok]);
- return;
- }
- break;
- }
- assert(n);
- rew_last(mdoc, n);
-
- /*
- * The current block extends an enclosing block.
- * Now that the current block ends, close the enclosing block, too.
- */
- while ((n = n->pending) != NULL) {
- rew_last(mdoc, n);
- if (n->type == MDOC_HEAD)
- mdoc_body_alloc(mdoc, n->line, n->pos, n->tok);
- }
-}
-
-/*
* Allocate a word and check whether it's punctuation or not.
* Punctuation consists of those tokens found in mdoc_isdelim().
*/
@@ -699,10 +483,11 @@ blk_exp_close(MACRO_PROT_ARGS)
{
struct mdoc_node *body; /* Our own body. */
struct mdoc_node *endbody; /* Our own end marker. */
+ struct mdoc_node *itblk; /* An It block starting later. */
struct mdoc_node *later; /* A sub-block starting later. */
- struct mdoc_node *n; /* For searching backwards. */
+ struct mdoc_node *n; /* Search back to our block. */
- int j, lastarg, maxargs, flushed, nl;
+ int j, lastarg, maxargs, nl;
enum margserr ac;
enum mdoct atok, ntok;
char *p;
@@ -727,10 +512,13 @@ blk_exp_close(MACRO_PROT_ARGS)
*/
atok = rew_alt(tok);
- body = endbody = later = NULL;
+ body = endbody = itblk = later = NULL;
for (n = mdoc->last; n; n = n->parent) {
- if (n->flags & MDOC_VALID)
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
continue;
+ }
/* Remember the start of our own body. */
@@ -742,6 +530,12 @@ blk_exp_close(MACRO_PROT_ARGS)
if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm)
continue;
+
+ if (n->tok == MDOC_It) {
+ itblk = n;
+ continue;
+ }
+
if (atok == n->tok) {
assert(body);
@@ -751,52 +545,70 @@ blk_exp_close(MACRO_PROT_ARGS)
* just proceed to closing out.
*/
- if (later == NULL)
+ if (later == NULL ||
+ (tok == MDOC_El && itblk == NULL))
break;
/*
- * When there is a pending sub block,
- * postpone closing out the current block
- * until the rew_sub() closing out the sub-block.
- */
-
- make_pending(later, tok, mdoc, line, ppos);
-
- /*
+ * When there is a pending sub block, postpone
+ * closing out the current block until the
+ * rew_pending() closing out the sub-block.
* Mark the place where the formatting - but not
* the scope - of the current block ends.
*/
- mdoc_endbody_alloc(mdoc, line, ppos,
+ mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
+ line, ppos, "%s breaks %s",
+ mdoc_macronames[atok],
+ mdoc_macronames[later->tok]);
+
+ endbody = mdoc_endbody_alloc(mdoc, line, ppos,
atok, body, ENDBODY_SPACE);
+ if (tok == MDOC_El)
+ itblk->flags |= MDOC_ENDED | MDOC_BROKEN;
+
/*
* If a block closing macro taking arguments
* breaks another block, put the arguments
- * into the end marker and remeber the
- * end marker in order to close it out.
+ * into the end marker.
*/
- if (maxargs) {
- endbody = mdoc->last;
+ if (maxargs)
mdoc->next = MDOC_NEXT_CHILD;
- }
break;
}
- /*
- * When finding an open sub block, remember the last
- * open explicit block, or, in case there are only
- * implicit ones, the first open implicit block.
- */
+ /* Explicit blocks close out description lines. */
- if (later &&
- mdoc_macros[later->tok].flags & MDOC_EXPLICIT)
+ if (n->tok == MDOC_Nd) {
+ rew_last(mdoc, n);
continue;
- if (n->tok != MDOC_It)
+ }
+
+ /* Breaking an open sub block. */
+
+ n->flags |= MDOC_BROKEN;
+ if (later == NULL)
later = n;
}
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+
+ if (body == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ if (maxargs && endbody == NULL) {
+ /*
+ * Stray .Ec without previous .Eo:
+ * Break the output line, keep the arguments.
+ */
+ mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
+ rew_elem(mdoc, MDOC_br);
+ }
+ } else if (endbody == NULL) {
+ rew_last(mdoc, body);
+ if (maxargs)
+ mdoc_tail_alloc(mdoc, line, ppos, atok);
+ }
if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
if (buf[*pos] != '\0')
@@ -804,32 +616,19 @@ blk_exp_close(MACRO_PROT_ARGS)
mdoc->parse, line, ppos,
"%s %s", mdoc_macronames[tok],
buf + *pos);
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ if (endbody == NULL && n != NULL)
+ rew_pending(mdoc, n);
return;
}
- if (maxargs && endbody == NULL) {
- if (n == NULL) {
- /*
- * Stray .Ec without previous .Eo:
- * Break the output line, ignore any arguments.
- */
- mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
- rew_elem(mdoc, MDOC_br);
- } else
- mdoc_tail_alloc(mdoc, line, ppos, atok);
- }
-
- flushed = n == NULL;
+ if (endbody != NULL)
+ n = endbody;
for (j = 0; ; j++) {
lastarg = *pos;
- if (j == maxargs && ! flushed) {
- if (endbody == NULL)
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
- else
- rew_last(mdoc, endbody);
- flushed = 1;
+ if (j == maxargs && n != NULL) {
+ rew_pending(mdoc, n);
+ n = NULL;
}
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
@@ -845,24 +644,17 @@ blk_exp_close(MACRO_PROT_ARGS)
continue;
}
- if ( ! flushed) {
- if (endbody == NULL)
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
- else
- rew_last(mdoc, endbody);
- flushed = 1;
+ if (n != NULL) {
+ rew_pending(mdoc, n);
+ n = NULL;
}
mdoc->flags &= ~MDOC_NEWLINE;
mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
break;
}
- if ( ! flushed) {
- if (endbody == NULL)
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
- else
- rew_last(mdoc, endbody);
- }
+ if (n != NULL)
+ rew_pending(mdoc, n);
if (nl)
append_delims(mdoc, line, pos, buf);
}
@@ -932,7 +724,7 @@ in_line(MACRO_PROT_ARGS)
*/
if (ac == ARGS_PUNCT) {
- if (cnt == 0 && nc == 0)
+ if (cnt == 0 && (nc == 0 || tok == MDOC_An))
mdoc->flags |= MDOC_NODELIMC;
break;
}
@@ -1055,22 +847,95 @@ blk_full(MACRO_PROT_ARGS)
{
int la, nl, parsed;
struct mdoc_arg *arg;
- struct mdoc_node *head; /* save of head macro */
- struct mdoc_node *body; /* save of body macro */
+ struct mdoc_node *blk; /* Our own or a broken block. */
+ struct mdoc_node *head; /* Our own head. */
+ struct mdoc_node *body; /* Our own body. */
struct mdoc_node *n;
enum margserr ac, lac;
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
- /* Skip items outside lists. */
+ if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ return;
+ }
- if (tok == MDOC_It) {
- for (n = mdoc->last; n; n = n->parent)
- if (n->tok == MDOC_Bl &&
- ! (n->flags & MDOC_VALID))
+ if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
+
+ /* Here, tok is one of Sh Ss Nm Nd It. */
+
+ blk = NULL;
+ for (n = mdoc->last; n != NULL; n = n->parent) {
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
+ continue;
+ }
+ if (n->type != MDOC_BLOCK)
+ continue;
+
+ if (tok == MDOC_It && n->tok == MDOC_Bl) {
+ if (blk != NULL) {
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN,
+ mdoc->parse, line, ppos,
+ "It breaks %s",
+ mdoc_macronames[blk->tok]);
+ rew_pending(mdoc, blk);
+ }
+ break;
+ }
+
+ if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ switch (tok) {
+ case MDOC_Sh:
+ /* FALLTHROUGH */
+ case MDOC_Ss:
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN,
+ mdoc->parse, line, ppos,
+ "%s breaks %s",
+ mdoc_macronames[tok],
+ mdoc_macronames[n->tok]);
+ rew_pending(mdoc, n);
+ n = mdoc->last;
+ continue;
+ case MDOC_It:
+ /* Delay in case it's astray. */
+ blk = n;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* Here, n is one of Sh Ss Nm Nd It. */
+
+ if (tok != MDOC_Sh && (n->tok == MDOC_Sh ||
+ (tok != MDOC_Ss && (n->tok == MDOC_Ss ||
+ (tok != MDOC_It && n->tok == MDOC_It)))))
break;
- if (n == NULL) {
+
+ /* Item breaking an explicit block. */
+
+ if (blk != NULL) {
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN,
+ mdoc->parse, line, ppos,
+ "It breaks %s",
+ mdoc_macronames[blk->tok]);
+ rew_pending(mdoc, blk);
+ blk = NULL;
+ }
+
+ /* Close out prior implicit scopes. */
+
+ rew_last(mdoc, n);
+ }
+
+ /* Skip items outside lists. */
+
+ if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
line, ppos, "It %s", buf + *pos);
mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
@@ -1079,13 +944,6 @@ blk_full(MACRO_PROT_ARGS)
}
}
- /* Close out prior implicit scope. */
-
- if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
- }
-
/*
* This routine accommodates implicitly- and explicitly-scoped
* macro openings. Implicit ones first close out prior scope
@@ -1096,7 +954,7 @@ blk_full(MACRO_PROT_ARGS)
*/
mdoc_argv(mdoc, line, tok, &arg, pos, buf);
- mdoc_block_alloc(mdoc, line, ppos, tok, arg);
+ blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
head = body = NULL;
/*
@@ -1115,7 +973,7 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_Nd) {
head = mdoc_head_alloc(mdoc, line, ppos, tok);
- rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ rew_last(mdoc, head);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
}
@@ -1127,8 +985,6 @@ blk_full(MACRO_PROT_ARGS)
la = *pos;
lac = ac;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ac == ARGS_PUNCT)
- break;
if (ac == ARGS_EOLN) {
if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE)
break;
@@ -1139,10 +995,24 @@ blk_full(MACRO_PROT_ARGS)
* reopen our scope if the last parse was a
* phrase or partial phrase.
*/
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+ if (body != NULL)
+ rew_last(mdoc, body);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
break;
}
+ if (tok == MDOC_Bd || tok == MDOC_Bk) {
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS,
+ mdoc->parse, line, la, "%s ... %s",
+ mdoc_macronames[tok], buf + la);
+ break;
+ }
+ if (tok == MDOC_Rs) {
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
+ line, la, "Rs %s", buf + la);
+ break;
+ }
+ if (ac == ARGS_PUNCT)
+ break;
/*
* Emit leading punctuation (i.e., punctuation before
@@ -1173,8 +1043,7 @@ blk_full(MACRO_PROT_ARGS)
* head; if we have, rewind that instead.
*/
- rew_sub(body ? MDOC_BODY : MDOC_HEAD,
- mdoc, tok, line, ppos);
+ rew_last(mdoc, body == NULL ? head : body);
body = mdoc_body_alloc(mdoc, line, ppos, tok);
/*
@@ -1196,9 +1065,11 @@ blk_full(MACRO_PROT_ARGS)
break;
}
+ if (blk->flags & MDOC_VALID)
+ return;
if (head == NULL)
head = mdoc_head_alloc(mdoc, line, ppos, tok);
- if (nl)
+ if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
append_delims(mdoc, line, pos, buf);
if (body != NULL)
goto out;
@@ -1206,26 +1077,32 @@ blk_full(MACRO_PROT_ARGS)
/*
* If there is an open (i.e., unvalidated) sub-block requiring
* explicit close-out, postpone switching the current block from
- * head to body until the rew_sub() call closing out that
+ * head to body until the rew_pending() call closing out that
* sub-block.
*/
for (n = mdoc->last; n && n != head; n = n->parent) {
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
+ continue;
+ }
if (n->type == MDOC_BLOCK &&
- mdoc_macros[n->tok].flags & MDOC_EXPLICIT &&
- ! (n->flags & MDOC_VALID)) {
- n->pending = head;
- return;
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ n->flags = MDOC_BROKEN;
+ head->flags = MDOC_ENDED;
}
}
+ if (head->flags & MDOC_ENDED)
+ return;
/* Close out scopes to remain in a consistent state. */
- rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
- mdoc_body_alloc(mdoc, line, ppos, tok);
+ rew_last(mdoc, head);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
out:
if (mdoc->flags & MDOC_FREECOL) {
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ rew_last(mdoc, body);
+ rew_last(mdoc, blk);
mdoc->flags &= ~MDOC_FREECOL;
}
}
@@ -1252,8 +1129,7 @@ blk_part_imp(MACRO_PROT_ARGS)
*/
blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
- mdoc_head_alloc(mdoc, line, ppos, tok);
- rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok));
/*
* Open the body scope "on-demand", that is, after we've
@@ -1284,26 +1160,38 @@ blk_part_imp(MACRO_PROT_ARGS)
/*
* If there is an open sub-block requiring explicit close-out,
- * postpone closing out the current block
- * until the rew_sub() call closing out the sub-block.
+ * postpone closing out the current block until the
+ * rew_pending() call closing out the sub-block.
*/
for (n = mdoc->last; n && n != body && n != blk->parent;
n = n->parent) {
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
+ continue;
+ }
if (n->type == MDOC_BLOCK &&
- mdoc_macros[n->tok].flags & MDOC_EXPLICIT &&
- ! (n->flags & MDOC_VALID)) {
- make_pending(n, tok, mdoc, line, ppos);
- mdoc_endbody_alloc(mdoc, line, ppos,
- tok, body, ENDBODY_NOSPACE);
- return;
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ n->flags |= MDOC_BROKEN;
+ if ( ! (body->flags & MDOC_ENDED)) {
+ mandoc_vmsg(MANDOCERR_BLK_NEST,
+ mdoc->parse, line, ppos,
+ "%s breaks %s", mdoc_macronames[tok],
+ mdoc_macronames[n->tok]);
+ mdoc_endbody_alloc(mdoc, line, ppos,
+ tok, body, ENDBODY_NOSPACE);
+ }
}
}
assert(n == body);
- rew_sub(MDOC_BODY, mdoc, tok, line, ppos);
+ if (body->flags & MDOC_ENDED)
+ return;
+
+ rew_last(mdoc, body);
if (nl)
append_delims(mdoc, line, pos, buf);
- rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos);
+ rew_pending(mdoc, blk);
/* Move trailing .Ns out of scope. */
@@ -1319,7 +1207,6 @@ blk_part_exp(MACRO_PROT_ARGS)
int la, nl;
enum margserr ac;
struct mdoc_node *head; /* keep track of head */
- struct mdoc_node *body; /* keep track of body */
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
@@ -1331,7 +1218,8 @@ blk_part_exp(MACRO_PROT_ARGS)
*/
mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
- for (head = body = NULL; ; ) {
+ head = NULL;
+ for (;;) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
@@ -1341,32 +1229,19 @@ blk_part_exp(MACRO_PROT_ARGS)
if (head == NULL && ac != ARGS_QWORD &&
mdoc_isdelim(p) == DELIM_OPEN) {
- assert(NULL == body);
dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
if (head == NULL) {
- assert(body == NULL);
head = mdoc_head_alloc(mdoc, line, ppos, tok);
- }
-
- /*
- * `Eo' gobbles any data into the head, but most other
- * macros just immediately close out and begin the body.
- */
-
- if (body == NULL) {
- assert(head);
- /* No check whether it's a macro! */
- if (tok == MDOC_Eo)
+ if (tok == MDOC_Eo) /* Not parsed. */
dword(mdoc, line, la, p, DELIM_MAX, 0);
- rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
- body = mdoc_body_alloc(mdoc, line, ppos, tok);
+ rew_last(mdoc, head);
+ mdoc_body_alloc(mdoc, line, ppos, tok);
if (tok == MDOC_Eo)
continue;
}
- assert(head != NULL && body != NULL);
if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
break;
@@ -1374,11 +1249,8 @@ blk_part_exp(MACRO_PROT_ARGS)
/* Clean-up to leave in a consistent state. */
- if (head == NULL)
- mdoc_head_alloc(mdoc, line, ppos, tok);
-
- if (body == NULL) {
- rew_sub(MDOC_HEAD, mdoc, tok, line, ppos);
+ if (head == NULL) {
+ rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok));
mdoc_body_alloc(mdoc, line, ppos, tok);
}
if (nl)
@@ -1388,11 +1260,12 @@ blk_part_exp(MACRO_PROT_ARGS)
static void
in_line_argn(MACRO_PROT_ARGS)
{
- int la, flushed, j, maxargs, nl;
- enum margserr ac;
struct mdoc_arg *arg;
char *p;
+ enum margserr ac;
enum mdoct ntok;
+ int state; /* arg#; -1: not yet open; -2: closed */
+ int la, maxargs, nl;
nl = mdoc->flags & MDOC_NEWLINE;
@@ -1426,62 +1299,76 @@ in_line_argn(MACRO_PROT_ARGS)
mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ state = -1;
p = NULL;
- flushed = j = 0;
for (;;) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
+
+ if (ac == ARGS_WORD && state == -1 &&
+ ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
+ continue;
+ }
+
+ if (state == -1 && tok != MDOC_In &&
+ tok != MDOC_St && tok != MDOC_Xr) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ state = 0;
+ }
+
if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
- if (j < 2 && tok == MDOC_Pf)
+ if (abs(state) < 2 && tok == MDOC_Pf)
mandoc_vmsg(MANDOCERR_PF_SKIP,
mdoc->parse, line, ppos, "Pf %s",
p == NULL ? "at eol" : p);
break;
}
- if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
- ac != ARGS_QWORD && j == 0 &&
- mdoc_isdelim(p) == DELIM_OPEN) {
- dword(mdoc, line, la, p, DELIM_OPEN, 0);
- continue;
- } else if (j == 0)
- mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
-
- if (j == maxargs && ! flushed) {
+ if (state == maxargs) {
rew_elem(mdoc, tok);
- flushed = 1;
+ state = -2;
}
- ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && j == 0)) ?
+ ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ?
MDOC_MAX : lookup(mdoc, tok, line, la, p);
if (ntok != MDOC_MAX) {
- if ( ! flushed)
+ if (state >= 0) {
rew_elem(mdoc, tok);
- flushed = 1;
+ state = -2;
+ }
mdoc_macro(mdoc, ntok, line, la, pos, buf);
- j++;
break;
}
- if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
- ac != ARGS_QWORD && ! flushed &&
- mdoc_isdelim(p) != DELIM_NONE) {
+ if (ac == ARGS_QWORD ||
+ mdoc_macros[tok].flags & MDOC_IGNDELIM ||
+ mdoc_isdelim(p) == DELIM_NONE) {
+ if (state == -1) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ state = 1;
+ } else if (state >= 0)
+ state++;
+ } else if (state >= 0) {
rew_elem(mdoc, tok);
- flushed = 1;
+ state = -2;
}
dword(mdoc, line, la, p, DELIM_MAX,
MDOC_JOIN & mdoc_macros[tok].flags);
- j++;
}
- if (j == 0) {
- mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
- if (ac == ARGS_PUNCT && tok == MDOC_Pf)
- append_delims(mdoc, line, pos, buf);
+ if (state == -1) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ return;
}
- if ( ! flushed)
+
+ if (state == 0 && tok == MDOC_Pf)
+ append_delims(mdoc, line, pos, buf);
+ if (state >= 0)
rew_elem(mdoc, tok);
if (nl)
append_delims(mdoc, line, pos, buf);
@@ -1490,10 +1377,24 @@ in_line_argn(MACRO_PROT_ARGS)
static void
in_line_eoln(MACRO_PROT_ARGS)
{
- struct mdoc_arg *arg;
+ struct mdoc_node *n;
+ struct mdoc_arg *arg;
+
+ if ((tok == MDOC_Pp || tok == MDOC_Lp) &&
+ ! (mdoc->flags & MDOC_SYNOPSIS)) {
+ n = mdoc->last;
+ if (mdoc->next == MDOC_NEXT_SIBLING)
+ n = n->parent;
+ if (n->tok == MDOC_Nm)
+ rew_last(mdoc, mdoc->last->parent);
+ }
- if (tok == MDOC_Pp)
- rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos);
+ if (buf[*pos] == '\0' &&
+ (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ return;
+ }
mdoc_argv(mdoc, line, tok, &arg, pos, buf);
mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
@@ -1543,13 +1444,20 @@ ctx_synopsis(MACRO_PROT_ARGS)
static void
phrase_ta(MACRO_PROT_ARGS)
{
- struct mdoc_node *n;
+ struct mdoc_node *body, *n;
/* Make sure we are in a column list or ignore this macro. */
- n = mdoc->last;
- while (n != NULL && n->tok != MDOC_Bl)
- n = n->parent;
+ body = NULL;
+ for (n = mdoc->last; n != NULL; n = n->parent) {
+ if (n->flags & MDOC_ENDED)
+ continue;
+ if (n->tok == MDOC_It && n->type == MDOC_BODY)
+ body = n;
+ if (n->tok == MDOC_Bl)
+ break;
+ }
+
if (n == NULL || n->norm->Bl.type != LIST_column) {
mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
line, ppos, "Ta");
@@ -1558,7 +1466,7 @@ phrase_ta(MACRO_PROT_ARGS)
/* Advance to the next column. */
- rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos);
+ rew_last(mdoc, body);
mdoc_body_alloc(mdoc, line, ppos, MDOC_It);
parse_rest(mdoc, MDOC_MAX, line, pos, buf);
}
diff --git a/mdoc_man.c b/mdoc_man.c
index 974cfbd46f58..9c086a576c4e 100644
--- a/mdoc_man.c
+++ b/mdoc_man.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_man.c,v 1.77 2014/11/30 05:29:00 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.88 2015/02/17 20:37:17 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -29,8 +29,7 @@
#include "mdoc.h"
#include "main.h"
-#define DECL_ARGS const struct mdoc_meta *meta, \
- const struct mdoc_node *n
+#define DECL_ARGS const struct mdoc_meta *meta, struct mdoc_node *n
struct manact {
int (*cond)(DECL_ARGS); /* DON'T run actions */
@@ -116,8 +115,8 @@ static void print_word(const char *);
static void print_line(const char *, int);
static void print_block(const char *, int);
static void print_offs(const char *, int);
-static void print_width(const char *,
- const struct mdoc_node *, size_t);
+static void print_width(const struct mdoc_bl *,
+ const struct mdoc_node *);
static void print_count(int *);
static void print_node(DECL_ARGS);
@@ -186,8 +185,8 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre_bx, NULL, 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 */
- { cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Dq */
+ { cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
+ { cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Dq */
{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
@@ -265,7 +264,7 @@ static int outflags;
#define BL_STACK_MAX 32
-static size_t Bl_stack[BL_STACK_MAX]; /* offsets [chars] */
+static int Bl_stack[BL_STACK_MAX]; /* offsets [chars] */
static int Bl_stack_post[BL_STACK_MAX]; /* add final .RE */
static int Bl_stack_len; /* number of nested Bl blocks */
static int TPremain; /* characters before tag is full */
@@ -423,7 +422,7 @@ print_offs(const char *v, int keywords)
{
char buf[24];
struct roffsu su;
- size_t sz;
+ int sz;
print_line(".RS", MMAN_Bk_susp);
@@ -434,7 +433,7 @@ print_offs(const char *v, int keywords)
sz = 6;
else if (keywords && !strcmp(v, "indent-two"))
sz = 12;
- else if (a2roffsu(v, &su, SCALE_MAX)) {
+ else if (a2roffsu(v, &su, SCALE_EN) > 1) {
if (SCALE_EN == su.unit)
sz = su.scale;
else {
@@ -459,7 +458,7 @@ print_offs(const char *v, int keywords)
if (Bl_stack_len)
sz += Bl_stack[Bl_stack_len - 1];
- (void)snprintf(buf, sizeof(buf), "%zun", sz);
+ (void)snprintf(buf, sizeof(buf), "%dn", sz);
print_word(buf);
outflags |= MMAN_nl;
}
@@ -468,20 +467,19 @@ print_offs(const char *v, int keywords)
* Set up the indentation for a list item; used from pre_it().
*/
static void
-print_width(const char *v, const struct mdoc_node *child, size_t defsz)
+print_width(const struct mdoc_bl *bl, const struct mdoc_node *child)
{
char buf[24];
struct roffsu su;
- size_t sz, chsz;
- int numeric, remain;
+ int numeric, remain, sz, chsz;
numeric = 1;
remain = 0;
- /* Convert v into a number (of characters). */
- if (NULL == v)
- sz = defsz;
- else if (a2roffsu(v, &su, SCALE_MAX)) {
+ /* Convert the width into a number (of characters). */
+ if (bl->width == NULL)
+ sz = (bl->type == LIST_hang) ? 6 : 0;
+ else if (a2roffsu(bl->width, &su, SCALE_MAX) > 1) {
if (SCALE_EN == su.unit)
sz = su.scale;
else {
@@ -489,11 +487,15 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
numeric = 0;
}
} else
- sz = strlen(v);
+ sz = strlen(bl->width);
/* XXX Rough estimation, might have multiple parts. */
- chsz = (NULL != child && MDOC_TEXT == child->type) ?
- strlen(child->string) : 0;
+ if (bl->type == LIST_enum)
+ chsz = (bl->count > 8) + 1;
+ else if (child != NULL && child->type == MDOC_TEXT)
+ chsz = strlen(child->string);
+ else
+ chsz = 0;
/* Maybe we are inside an enclosing list? */
mid_it();
@@ -505,17 +507,17 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
Bl_stack[Bl_stack_len++] = sz + 2;
/* Set up the current list. */
- if (defsz && chsz > sz)
+ if (chsz > sz && bl->type != LIST_tag)
print_block(".HP", 0);
else {
print_block(".TP", 0);
remain = sz + 2;
}
if (numeric) {
- (void)snprintf(buf, sizeof(buf), "%zun", sz + 2);
+ (void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
print_word(buf);
} else
- print_word(v);
+ print_word(bl->width);
TPremain = remain;
}
@@ -524,7 +526,7 @@ print_count(int *count)
{
char buf[24];
- (void)snprintf(buf, sizeof(buf), "%d.", ++*count);
+ (void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
print_word(buf);
}
@@ -545,10 +547,10 @@ void
man_mdoc(void *arg, const struct mdoc *mdoc)
{
const struct mdoc_meta *meta;
- const struct mdoc_node *n;
+ struct mdoc_node *n;
meta = mdoc_meta(mdoc);
- n = mdoc_node(mdoc);
+ n = mdoc_node(mdoc)->child;
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
meta->title,
@@ -564,15 +566,18 @@ man_mdoc(void *arg, const struct mdoc *mdoc)
fontqueue.head = fontqueue.tail = mandoc_malloc(8);
*fontqueue.tail = 'R';
}
- print_node(meta, n);
+ while (n != NULL) {
+ print_node(meta, n);
+ n = n->next;
+ }
putchar('\n');
}
static void
print_node(DECL_ARGS)
{
- const struct mdoc_node *sub;
const struct manact *act;
+ struct mdoc_node *sub;
int cond, do_sub;
/*
@@ -585,6 +590,7 @@ print_node(DECL_ARGS)
act = NULL;
cond = 0;
do_sub = 1;
+ n->flags &= ~MDOC_ENDED;
if (MDOC_TEXT == n->type) {
/*
@@ -632,7 +638,7 @@ print_node(DECL_ARGS)
(*act->post)(meta, n);
if (ENDBODY_NOT != n->end)
- n->pending->flags |= MDOC_ENDED;
+ n->body->flags |= MDOC_ENDED;
if (ENDBODY_NOSPACE == n->end)
outflags &= ~(MMAN_spc | MMAN_nl);
@@ -876,8 +882,8 @@ static int
pre_aq(DECL_ARGS)
{
- print_word(n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
+ print_word(n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
outflags &= ~MMAN_spc;
return(1);
}
@@ -887,8 +893,8 @@ post_aq(DECL_ARGS)
{
outflags &= ~(MMAN_spc | MMAN_nl);
- print_word(n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
+ print_word(n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
}
static int
@@ -1003,10 +1009,12 @@ pre_bl(DECL_ARGS)
return(1);
}
- print_line(".TS", MMAN_nl);
- for (icol = 0; icol < n->norm->Bl.ncols; icol++)
- print_word("l");
- print_word(".");
+ if (n->nchild) {
+ print_line(".TS", MMAN_nl);
+ for (icol = 0; icol < n->norm->Bl.ncols; icol++)
+ print_word("l");
+ print_word(".");
+ }
outflags |= MMAN_nl;
return(1);
}
@@ -1017,7 +1025,8 @@ post_bl(DECL_ARGS)
switch (n->norm->Bl.type) {
case LIST_column:
- print_line(".TE", 0);
+ if (n->nchild)
+ print_line(".TE", 0);
break;
case LIST_enum:
n->norm->Bl.count = 0;
@@ -1128,16 +1137,37 @@ static int
pre_eo(DECL_ARGS)
{
- outflags &= ~(MMAN_spc | MMAN_nl);
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ print_word("\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL && (n->child != NULL ||
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+ outflags &= ~(MMAN_spc | MMAN_nl);
return(1);
}
static void
post_eo(DECL_ARGS)
{
+ int body, tail;
- if (n->end != ENDBODY_SPACE)
+ if (n->end != ENDBODY_NOT) {
+ outflags |= MMAN_spc;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+ if (body && tail)
outflags &= ~MMAN_spc;
+ else if ( ! (body || tail))
+ print_word("\\&");
+ else if ( ! tail)
+ outflags |= MMAN_spc;
}
static int
@@ -1256,12 +1286,14 @@ pre_fo(DECL_ARGS)
pre_syn(n);
break;
case MDOC_HEAD:
+ if (n->child == NULL)
+ return(0);
if (MDOC_SYNPRETTY & n->flags)
print_block(".HP 4n", MMAN_nl);
font_push('B');
break;
case MDOC_BODY:
- outflags &= ~MMAN_spc;
+ outflags &= ~(MMAN_spc | MMAN_nl);
print_word("(");
outflags &= ~MMAN_spc;
break;
@@ -1277,7 +1309,8 @@ post_fo(DECL_ARGS)
switch (n->type) {
case MDOC_HEAD:
- font_pop();
+ if (n->child != NULL)
+ font_pop();
break;
case MDOC_BODY:
post_fn(meta, n);
@@ -1362,7 +1395,7 @@ pre_it(DECL_ARGS)
case LIST_dash:
/* FALLTHROUGH */
case LIST_hyphen:
- print_width(bln->norm->Bl.width, NULL, 0);
+ print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
font_push('B');
@@ -1374,19 +1407,19 @@ pre_it(DECL_ARGS)
outflags |= MMAN_nl;
return(0);
case LIST_enum:
- print_width(bln->norm->Bl.width, NULL, 0);
+ print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
print_count(&bln->norm->Bl.count);
outflags |= MMAN_nl;
return(0);
case LIST_hang:
- print_width(bln->norm->Bl.width, n->child, 6);
+ print_width(&bln->norm->Bl, n->child);
TPremain = 0;
outflags |= MMAN_nl;
return(1);
case LIST_tag:
- print_width(bln->norm->Bl.width, n->child, 0);
+ print_width(&bln->norm->Bl, n->child);
putchar('\n');
outflags &= ~MMAN_spc;
return(1);
@@ -1418,7 +1451,7 @@ mid_it(void)
/* Restore the indentation of the enclosing list. */
print_line(".RS", MMAN_Bk_susp);
- (void)snprintf(buf, sizeof(buf), "%zun",
+ (void)snprintf(buf, sizeof(buf), "%dn",
Bl_stack[Bl_stack_len - 1]);
print_word(buf);
diff --git a/mdoc_term.c b/mdoc_term.c
index 7f57aed37649..cc44d761248f 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_term.c,v 1.299 2014/12/02 10:08:06 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.311 2015/02/17 20:37:17 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -22,6 +22,7 @@
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,8 +50,7 @@ struct termact {
void (*post)(DECL_ARGS);
};
-static size_t a2width(const struct termp *, const char *);
-static size_t a2height(const struct termp *, const char *);
+static int a2width(const struct termp *, const char *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
@@ -67,6 +67,7 @@ static void termp__t_post(DECL_ARGS);
static void termp_bd_post(DECL_ARGS);
static void termp_bk_post(DECL_ARGS);
static void termp_bl_post(DECL_ARGS);
+static void termp_eo_post(DECL_ARGS);
static void termp_fd_post(DECL_ARGS);
static void termp_fo_post(DECL_ARGS);
static void termp_in_post(DECL_ARGS);
@@ -91,6 +92,7 @@ static int termp_bt_pre(DECL_ARGS);
static int termp_bx_pre(DECL_ARGS);
static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
+static int termp_eo_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
@@ -190,7 +192,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* Ec */ /* FIXME: no space */
{ NULL, NULL }, /* Ef */
{ termp_under_pre, NULL }, /* Em */
- { termp_quote_pre, termp_quote_post }, /* Eo */
+ { termp_eo_pre, termp_eo_post }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
{ termp_li_pre, NULL }, /* No */
@@ -291,9 +293,10 @@ static void
print_mdoc_nodelist(DECL_ARGS)
{
- print_mdoc_node(p, pair, meta, n);
- if (n->next)
- print_mdoc_nodelist(p, pair, meta, n->next);
+ while (n != NULL) {
+ print_mdoc_node(p, pair, meta, n);
+ n = n->next;
+ }
}
static void
@@ -306,7 +309,8 @@ print_mdoc_node(DECL_ARGS)
chld = 1;
offset = p->offset;
rmargin = p->rmargin;
- n->prev_font = term_fontq(p);
+ n->flags &= ~MDOC_ENDED;
+ n->prev_font = p->fonti;
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
@@ -316,12 +320,9 @@ print_mdoc_node(DECL_ARGS)
* invoked in a prior line, revert it to PREKEEP.
*/
- if (TERMP_KEEP & p->flags) {
- if (n->prev ? (n->prev->lastline != n->line) :
- (n->parent && n->parent->line != n->line)) {
- p->flags &= ~TERMP_KEEP;
- p->flags |= TERMP_PREKEEP;
- }
+ if (p->flags & TERMP_KEEP && n->flags & MDOC_LINE) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
}
/*
@@ -361,7 +362,7 @@ print_mdoc_node(DECL_ARGS)
print_mdoc_nodelist(p, &npair, meta, n->child);
term_fontpopq(p,
- (ENDBODY_NOT == n->end ? n : n->pending)->prev_font);
+ (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
switch (n->type) {
case MDOC_TEXT:
@@ -381,7 +382,7 @@ print_mdoc_node(DECL_ARGS)
* that it must not call the post handler again.
*/
if (ENDBODY_NOT != n->end)
- n->pending->flags |= MDOC_ENDED;
+ n->body->flags |= MDOC_ENDED;
/*
* End of line terminating an implicit block
@@ -526,30 +527,15 @@ print_mdoc_head(struct termp *p, const void *arg)
free(volume);
}
-static size_t
-a2height(const struct termp *p, const char *v)
-{
- struct roffsu su;
-
-
- assert(v);
- if ( ! a2roffsu(v, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(v));
-
- return(term_vspan(p, &su));
-}
-
-static size_t
+static int
a2width(const struct termp *p, const char *v)
{
struct roffsu su;
- assert(v);
- if ( ! a2roffsu(v, &su, SCALE_MAX)) {
+ if (a2roffsu(v, &su, SCALE_MAX) < 2) {
SCALE_HS_INIT(&su, term_strlen(p, v));
su.scale /= term_strlen(p, "0");
}
-
return(term_hspan(p, &su));
}
@@ -620,10 +606,10 @@ termp_ll_pre(DECL_ARGS)
static int
termp_it_pre(DECL_ARGS)
{
- const struct mdoc_node *bl, *nn;
char buf[24];
- int i;
- size_t width, offset, ncols, dcol;
+ const struct mdoc_node *bl, *nn;
+ size_t ncols, dcol;
+ int i, offset, width;
enum mdoc_list type;
if (MDOC_BLOCK == n->type) {
@@ -635,15 +621,46 @@ termp_it_pre(DECL_ARGS)
type = bl->norm->Bl.type;
/*
+ * Defaults for specific list types.
+ */
+
+ switch (type) {
+ case LIST_bullet:
+ /* FALLTHROUGH */
+ case LIST_dash:
+ /* FALLTHROUGH */
+ case LIST_hyphen:
+ /* FALLTHROUGH */
+ case LIST_enum:
+ width = term_len(p, 2);
+ break;
+ case LIST_hang:
+ width = term_len(p, 8);
+ break;
+ case LIST_column:
+ /* FALLTHROUGH */
+ case LIST_tag:
+ width = term_len(p, 10);
+ break;
+ default:
+ width = 0;
+ break;
+ }
+ offset = 0;
+
+ /*
* First calculate width and offset. This is pretty easy unless
* we're a -column list, in which case all prior columns must
* be accounted for.
*/
- width = offset = 0;
-
- if (bl->norm->Bl.offs)
+ if (bl->norm->Bl.offs != NULL) {
offset = a2width(p, bl->norm->Bl.offs);
+ if (offset < 0 && (size_t)(-offset) > p->offset)
+ offset = -p->offset;
+ else if (offset > SHRT_MAX)
+ offset = 0;
+ }
switch (type) {
case LIST_column:
@@ -698,39 +715,11 @@ termp_it_pre(DECL_ARGS)
* number for buffering single arguments. See the above
* handling for column for how this changes.
*/
- assert(bl->norm->Bl.width);
width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
- break;
- }
-
- /*
- * List-type can override the width in the case of fixed-head
- * values (bullet, dash/hyphen, enum). Tags need a non-zero
- * offset.
- */
-
- switch (type) {
- case LIST_bullet:
- /* FALLTHROUGH */
- case LIST_dash:
- /* FALLTHROUGH */
- case LIST_hyphen:
- /* FALLTHROUGH */
- case LIST_enum:
- if (width < term_len(p, 2))
- width = term_len(p, 2);
- break;
- case LIST_hang:
- if (0 == width)
- width = term_len(p, 8);
- break;
- case LIST_column:
- /* FALLTHROUGH */
- case LIST_tag:
- if (0 == width)
- width = term_len(p, 10);
- break;
- default:
+ if (width < 0 && (size_t)(-width) > p->offset)
+ width = -p->offset;
+ else if (width > SHRT_MAX)
+ width = 0;
break;
}
@@ -776,16 +765,16 @@ termp_it_pre(DECL_ARGS)
case LIST_enum:
/*
* Weird special case.
- * Very narrow enum lists actually hang.
+ * Some very narrow lists actually hang.
*/
- if (width == term_len(p, 2))
- p->flags |= TERMP_HANG;
/* FALLTHROUGH */
case LIST_bullet:
/* FALLTHROUGH */
case LIST_dash:
/* FALLTHROUGH */
case LIST_hyphen:
+ if (width <= (int)term_len(p, 2))
+ p->flags |= TERMP_HANG;
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
@@ -874,7 +863,6 @@ termp_it_pre(DECL_ARGS)
case LIST_hyphen:
/* FALLTHROUGH */
case LIST_tag:
- assert(width);
if (MDOC_HEAD == n->type)
p->rmargin = p->offset + width;
else
@@ -1104,9 +1092,6 @@ termp_an_pre(DECL_ARGS)
return(0);
}
- if (n->child == NULL)
- return(0);
-
if (p->flags & TERMP_SPLIT)
term_newln(p);
@@ -1554,6 +1539,7 @@ termp_bd_pre(DECL_ARGS)
{
size_t tabwidth, lm, len, rm, rmax;
struct mdoc_node *nn;
+ int offset;
if (MDOC_BLOCK == n->type) {
print_bvspace(p, n, n);
@@ -1570,8 +1556,13 @@ termp_bd_pre(DECL_ARGS)
p->offset += term_len(p, p->defindent + 1);
else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
p->offset += term_len(p, (p->defindent + 1) * 2);
- else
- p->offset += a2width(p, n->norm->Bd.offs);
+ else {
+ offset = a2width(p, n->norm->Bd.offs);
+ if (offset < 0 && (size_t)(-offset) > p->offset)
+ p->offset = 0;
+ else if (offset < SHRT_MAX)
+ p->offset += offset;
+ }
/*
* If -ragged or -filled are specified, the block does nothing
@@ -1816,11 +1807,17 @@ termp_in_post(DECL_ARGS)
static int
termp_sp_pre(DECL_ARGS)
{
+ struct roffsu su;
size_t i, len;
switch (n->tok) {
case MDOC_sp:
- len = n->child ? a2height(p, n->child->string) : 1;
+ if (n->child) {
+ if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
+ su.scale = 1.0;
+ len = term_vspan(p, &su);
+ } else
+ len = 1;
break;
case MDOC_br:
len = 0;
@@ -1856,8 +1853,8 @@ termp_quote_pre(DECL_ARGS)
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- term_word(p, n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? "<" : "\\(la");
+ term_word(p, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
break;
case MDOC_Bro:
/* FALLTHROUGH */
@@ -1876,7 +1873,7 @@ termp_quote_pre(DECL_ARGS)
case MDOC_Do:
/* FALLTHROUGH */
case MDOC_Dq:
- term_word(p, "\\(lq");
+ term_word(p, "\\(Lq");
break;
case MDOC_En:
if (NULL == n->norm->Es ||
@@ -1884,8 +1881,6 @@ termp_quote_pre(DECL_ARGS)
return(1);
term_word(p, n->norm->Es->child->string);
break;
- case MDOC_Eo:
- break;
case MDOC_Po:
/* FALLTHROUGH */
case MDOC_Pq:
@@ -1921,16 +1916,14 @@ termp_quote_post(DECL_ARGS)
if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
- if ( ! (n->tok == MDOC_En ||
- (n->tok == MDOC_Eo && n->end == ENDBODY_SPACE)))
- p->flags |= TERMP_NOSPACE;
+ p->flags |= TERMP_NOSPACE;
switch (n->tok) {
case MDOC_Ao:
/* FALLTHROUGH */
case MDOC_Aq:
- term_word(p, n->parent->prev != NULL &&
- n->parent->prev->tok == MDOC_An ? ">" : "\\(ra");
+ term_word(p, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
break;
case MDOC_Bro:
/* FALLTHROUGH */
@@ -1949,17 +1942,15 @@ termp_quote_post(DECL_ARGS)
case MDOC_Do:
/* FALLTHROUGH */
case MDOC_Dq:
- term_word(p, "\\(rq");
+ term_word(p, "\\(Rq");
break;
case MDOC_En:
- if (NULL != n->norm->Es &&
- NULL != n->norm->Es->child &&
- NULL != n->norm->Es->child->next) {
- p->flags |= TERMP_NOSPACE;
+ if (n->norm->Es == NULL ||
+ n->norm->Es->child == NULL ||
+ n->norm->Es->child->next == NULL)
+ p->flags &= ~TERMP_NOSPACE;
+ else
term_word(p, n->norm->Es->child->next->string);
- }
- break;
- case MDOC_Eo:
break;
case MDOC_Po:
/* FALLTHROUGH */
@@ -1987,6 +1978,50 @@ termp_quote_post(DECL_ARGS)
}
static int
+termp_eo_pre(DECL_ARGS)
+{
+
+ if (n->type != MDOC_BODY)
+ return(1);
+
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ term_word(p, "\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL && (n->child != NULL ||
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+ p->flags |= TERMP_NOSPACE;
+
+ return(1);
+}
+
+static void
+termp_eo_post(DECL_ARGS)
+{
+ int body, tail;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->end != ENDBODY_NOT) {
+ p->flags &= ~TERMP_NOSPACE;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+ if (body && tail)
+ p->flags |= TERMP_NOSPACE;
+ else if ( ! (body || tail))
+ term_word(p, "\\&");
+ else if ( ! tail)
+ p->flags &= ~TERMP_NOSPACE;
+}
+
+static int
termp_fo_pre(DECL_ARGS)
{
size_t rmargin = 0;
diff --git a/mdoc_validate.c b/mdoc_validate.c
index 7990ffe93853..eb531e828987 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_validate.c,v 1.263 2014/11/30 05:29:00 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.283 2015/02/23 13:55:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -48,11 +48,6 @@ enum check_ineq {
CHECK_EQ
};
-enum check_lvl {
- CHECK_WARN,
- CHECK_ERROR,
-};
-
typedef void (*v_pre)(PRE_ARGS);
typedef void (*v_post)(POST_ARGS);
@@ -61,8 +56,6 @@ struct valids {
v_post post;
};
-static void check_count(struct mdoc *, enum mdoc_type,
- enum check_lvl, enum check_ineq, int);
static void check_text(struct mdoc *, int, int, char *);
static void check_argv(struct mdoc *,
struct mdoc_node *, struct mdoc_argv *);
@@ -72,11 +65,6 @@ static enum mdoc_sec a2sec(const char *);
static size_t macro2len(enum mdoct);
static void rewrite_macro2len(char **);
-static void bwarn_ge1(POST_ARGS);
-static void ewarn_eq1(POST_ARGS);
-static void ewarn_ge1(POST_ARGS);
-static void hwarn_eq0(POST_ARGS);
-
static void post_an(POST_ARGS);
static void post_at(POST_ARGS);
static void post_bf(POST_ARGS);
@@ -99,7 +87,6 @@ static void post_fn(POST_ARGS);
static void post_fname(POST_ARGS);
static void post_fo(POST_ARGS);
static void post_hyph(POST_ARGS);
-static void post_hyphtext(POST_ARGS);
static void post_ignpar(POST_ARGS);
static void post_it(POST_ARGS);
static void post_lb(POST_ARGS);
@@ -157,12 +144,12 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Ev */
{ pre_std, post_ex }, /* Ex */
{ NULL, post_fa }, /* Fa */
- { NULL, ewarn_ge1 }, /* Fd */
+ { NULL, NULL }, /* Fd */
{ NULL, NULL }, /* Fl */
{ NULL, post_fn }, /* Fn */
{ NULL, NULL }, /* Ft */
{ NULL, NULL }, /* Ic */
- { NULL, ewarn_eq1 }, /* In */
+ { NULL, NULL }, /* In */
{ NULL, post_defaults }, /* Li */
{ NULL, post_nd }, /* Nd */
{ NULL, post_nm }, /* Nm */
@@ -173,18 +160,18 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, post_st }, /* St */
{ NULL, NULL }, /* Va */
{ NULL, post_vt }, /* Vt */
- { NULL, ewarn_ge1 }, /* Xr */
- { NULL, ewarn_ge1 }, /* %A */
- { NULL, post_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
- { NULL, ewarn_ge1 }, /* %D */
- { NULL, ewarn_ge1 }, /* %I */
- { NULL, ewarn_ge1 }, /* %J */
- { NULL, post_hyphtext }, /* %N */
- { NULL, post_hyphtext }, /* %O */
- { NULL, ewarn_ge1 }, /* %P */
- { NULL, post_hyphtext }, /* %R */
- { NULL, post_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
- { NULL, ewarn_ge1 }, /* %V */
+ { NULL, NULL }, /* Xr */
+ { NULL, NULL }, /* %A */
+ { NULL, post_hyph }, /* %B */ /* FIXME: can be used outside Rs/Re. */
+ { NULL, NULL }, /* %D */
+ { NULL, NULL }, /* %I */
+ { NULL, NULL }, /* %J */
+ { NULL, post_hyph }, /* %N */
+ { NULL, post_hyph }, /* %O */
+ { NULL, NULL }, /* %P */
+ { NULL, post_hyph }, /* %R */
+ { NULL, post_hyph }, /* %T */ /* FIXME: can be used outside Rs/Re. */
+ { NULL, NULL }, /* %V */
{ NULL, NULL }, /* Ac */
{ NULL, NULL }, /* Ao */
{ NULL, NULL }, /* Aq */
@@ -246,14 +233,14 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Brq */
{ NULL, NULL }, /* Bro */
{ NULL, NULL }, /* Brc */
- { NULL, ewarn_ge1 }, /* %C */
+ { NULL, NULL }, /* %C */
{ pre_obsolete, post_es }, /* Es */
{ pre_obsolete, post_en }, /* En */
{ NULL, NULL }, /* Dx */
- { NULL, ewarn_ge1 }, /* %Q */
+ { NULL, NULL }, /* %Q */
{ NULL, post_par }, /* br */
{ NULL, post_par }, /* sp */
- { NULL, ewarn_eq1 }, /* %U */
+ { NULL, NULL }, /* %U */
{ NULL, NULL }, /* Ta */
{ NULL, NULL }, /* ll */
};
@@ -311,7 +298,8 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
switch (n->type) {
case MDOC_TEXT:
- check_text(mdoc, n->line, n->pos, n->string);
+ if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
+ check_text(mdoc, n->line, n->pos, n->string);
/* FALLTHROUGH */
case MDOC_TBL:
/* FALLTHROUGH */
@@ -338,7 +326,7 @@ mdoc_valid_post(struct mdoc *mdoc)
n = mdoc->last;
if (n->flags & MDOC_VALID)
return;
- n->flags |= MDOC_VALID;
+ n->flags |= MDOC_VALID | MDOC_ENDED;
switch (n->type) {
case MDOC_TEXT:
@@ -373,67 +361,6 @@ mdoc_valid_post(struct mdoc *mdoc)
}
static void
-check_count(struct mdoc *mdoc, enum mdoc_type type,
- enum check_lvl lvl, enum check_ineq ineq, int val)
-{
- const char *p;
- enum mandocerr t;
-
- if (mdoc->last->type != type)
- return;
-
- switch (ineq) {
- case CHECK_LT:
- p = "less than ";
- if (mdoc->last->nchild < val)
- return;
- break;
- case CHECK_GT:
- p = "more than ";
- if (mdoc->last->nchild > val)
- return;
- break;
- case CHECK_EQ:
- p = "";
- if (val == mdoc->last->nchild)
- return;
- break;
- default:
- abort();
- /* NOTREACHED */
- }
-
- t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
- mandoc_vmsg(t, mdoc->parse, mdoc->last->line,
- mdoc->last->pos, "want %s%d children (have %d)",
- p, val, mdoc->last->nchild);
-}
-
-static void
-bwarn_ge1(POST_ARGS)
-{
- check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
-}
-
-static void
-ewarn_eq1(POST_ARGS)
-{
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
-}
-
-static void
-ewarn_ge1(POST_ARGS)
-{
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
-}
-
-static void
-hwarn_eq0(POST_ARGS)
-{
- check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
-}
-
-static void
check_args(struct mdoc *mdoc, struct mdoc_node *n)
{
int i;
@@ -490,24 +417,13 @@ pre_display(PRE_ARGS)
static void
pre_bl(PRE_ARGS)
{
- struct mdoc_node *np;
struct mdoc_argv *argv, *wa;
int i;
enum mdocargt mdoclt;
enum mdoc_list lt;
- if (MDOC_BLOCK != n->type) {
- if (ENDBODY_NOT != n->end) {
- assert(n->pending);
- np = n->pending->parent;
- } else
- np = n->parent;
-
- assert(np);
- assert(MDOC_BLOCK == np->type);
- assert(MDOC_Bl == np->tok);
+ if (n->type != MDOC_BLOCK)
return;
- }
/*
* First figure out which kind of list to use: bind ourselves to
@@ -683,25 +599,14 @@ pre_bl(PRE_ARGS)
static void
pre_bd(PRE_ARGS)
{
- struct mdoc_node *np;
struct mdoc_argv *argv;
int i;
enum mdoc_disp dt;
pre_literal(mdoc, n);
- if (MDOC_BLOCK != n->type) {
- if (ENDBODY_NOT != n->end) {
- assert(n->pending);
- np = n->pending->parent;
- } else
- np = n->parent;
-
- assert(np);
- assert(MDOC_BLOCK == np->type);
- assert(MDOC_Bd == np->tok);
+ if (n->type != MDOC_BLOCK)
return;
- }
for (i = 0; n->args && i < (int)n->args->argc; i++) {
argv = n->args->argv + i;
@@ -871,22 +776,10 @@ post_bf(POST_ARGS)
* element, which contains the goods.
*/
- if (MDOC_HEAD != mdoc->last->type) {
- if (ENDBODY_NOT != mdoc->last->end) {
- assert(mdoc->last->pending);
- np = mdoc->last->pending->parent->head;
- } else if (MDOC_BLOCK != mdoc->last->type) {
- np = mdoc->last->parent->head;
- } else
- np = mdoc->last->head;
-
- assert(np);
- assert(MDOC_HEAD == np->type);
- assert(MDOC_Bf == np->tok);
+ np = mdoc->last;
+ if (MDOC_HEAD != np->type)
return;
- }
- np = mdoc->last;
assert(MDOC_BLOCK == np->parent->type);
assert(MDOC_Bf == np->parent->tok);
@@ -941,13 +834,12 @@ post_lb(POST_ARGS)
const char *stdlibname;
char *libname;
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
n = mdoc->last->child;
assert(MDOC_TEXT == n->type);
if (NULL == (stdlibname = mdoc_a2lib(n->string)))
mandoc_asprintf(&libname,
- "library \\(lq%s\\(rq", n->string);
+ "library \\(Lq%s\\(Rq", n->string);
else
libname = mandoc_strdup(stdlibname);
@@ -994,11 +886,27 @@ post_fn(POST_ARGS)
static void
post_fo(POST_ARGS)
{
+ const struct mdoc_node *n;
- check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1);
- bwarn_ge1(mdoc);
- if (mdoc->last->type == MDOC_HEAD && mdoc->last->nchild)
- post_fname(mdoc);
+ n = mdoc->last;
+
+ if (n->type != MDOC_HEAD)
+ return;
+
+ if (n->child == NULL) {
+ mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
+ n->line, n->pos, "Fo");
+ return;
+ }
+ if (n->child != n->last) {
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ n->child->next->line, n->child->next->pos,
+ "Fo ... %s", n->child->next->string);
+ while (n->child != n->last)
+ mdoc_node_delete(mdoc, n->last);
+ }
+
+ post_fname(mdoc);
}
static void
@@ -1047,50 +955,79 @@ post_vt(POST_ARGS)
static void
post_nm(POST_ARGS)
{
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->last != NULL &&
+ (n->last->tok == MDOC_Pp ||
+ n->last->tok == MDOC_Lp))
+ mdoc_node_relink(mdoc, n->last);
if (NULL != mdoc->meta.name)
return;
- mdoc_deroff(&mdoc->meta.name, mdoc->last);
+ mdoc_deroff(&mdoc->meta.name, n);
if (NULL == mdoc->meta.name)
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
- mdoc->last->line, mdoc->last->pos, "Nm");
+ n->line, n->pos, "Nm");
}
static void
post_nd(POST_ARGS)
{
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->child == NULL)
+ mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
+ n->line, n->pos, "Nd");
- check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0);
post_hyph(mdoc);
}
static void
post_d1(POST_ARGS)
{
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->child == NULL)
+ mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ n->line, n->pos, "D1");
- bwarn_ge1(mdoc);
post_hyph(mdoc);
}
static void
post_literal(POST_ARGS)
{
+ struct mdoc_node *n;
- if (mdoc->last->tok == MDOC_Bd)
- hwarn_eq0(mdoc);
- bwarn_ge1(mdoc);
+ n = mdoc->last;
- /*
- * The `Dl' (note "el" not "one") and `Bd' macros unset the
- * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
- * this in literal mode, but it doesn't hurt to just switch it
- * off in general since displays can't be nested.
- */
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->child == NULL)
+ mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
- if (MDOC_BODY == mdoc->last->type)
- mdoc->flags &= ~MDOC_LITERAL;
+ if (n->tok == MDOC_Bd &&
+ n->norm->Bd.type != DISP_literal &&
+ n->norm->Bd.type != DISP_unfilled)
+ return;
+
+ mdoc->flags &= ~MDOC_LITERAL;
}
static void
@@ -1164,14 +1101,17 @@ post_at(POST_ARGS)
static void
post_an(POST_ARGS)
{
- struct mdoc_node *np;
+ struct mdoc_node *np, *nch;
np = mdoc->last;
- if (AUTH__NONE == np->norm->An.auth) {
- if (0 == np->child)
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
- } else if (np->child)
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
+ nch = np->child;
+ if (np->norm->An.auth == AUTH__NONE) {
+ if (nch == NULL)
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ np->line, np->pos, "An");
+ } else if (nch != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nch->line, nch->pos, "An ... %s", nch->string);
}
static void
@@ -1197,7 +1137,7 @@ post_it(POST_ARGS)
struct mdoc_node *nbl, *nit, *nch;
nit = mdoc->last;
- if (MDOC_BLOCK != nit->type)
+ if (nit->type != MDOC_BLOCK)
return;
nbl = nit->parent->parent;
@@ -1213,7 +1153,7 @@ post_it(POST_ARGS)
case LIST_inset:
/* FALLTHROUGH */
case LIST_diag:
- if (NULL == nit->head->child)
+ if (nit->head->child == NULL)
mandoc_vmsg(MANDOCERR_IT_NOHEAD,
mdoc->parse, nit->line, nit->pos,
"Bl -%s It",
@@ -1226,14 +1166,14 @@ post_it(POST_ARGS)
case LIST_enum:
/* FALLTHROUGH */
case LIST_hyphen:
- if (NULL == nit->body->child)
+ if (nit->body == NULL || nit->body->child == NULL)
mandoc_vmsg(MANDOCERR_IT_NOBODY,
mdoc->parse, nit->line, nit->pos,
"Bl -%s It",
mdoc_argnames[nbl->args->argv[0].arg]);
/* FALLTHROUGH */
case LIST_item:
- if (NULL != nit->head->child)
+ if (nit->head->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP,
mdoc->parse, nit->line, nit->pos,
"It %s", nit->head->child->string);
@@ -1241,16 +1181,16 @@ post_it(POST_ARGS)
case LIST_column:
cols = (int)nbl->norm->Bl.ncols;
- assert(NULL == nit->head->child);
+ assert(nit->head->child == NULL);
for (i = 0, nch = nit->child; nch; nch = nch->next)
- if (MDOC_BODY == nch->type)
+ if (nch->type == MDOC_BODY)
i++;
if (i < cols || i > cols + 1)
- mandoc_vmsg(MANDOCERR_ARGCOUNT,
+ mandoc_vmsg(MANDOCERR_BL_COL,
mdoc->parse, nit->line, nit->pos,
- "columns == %d (have %d)", cols, i);
+ "%d columns, %d cells", cols, i);
break;
default:
abort();
@@ -1404,13 +1344,21 @@ post_bl_block_tag(POST_ARGS)
static void
post_bl_head(POST_ARGS)
{
- struct mdoc_node *np, *nn, *nnp;
+ struct mdoc_node *nbl, *nh, *nch, *nnext;
struct mdoc_argv *argv;
int i, j;
- if (LIST_column != mdoc->last->norm->Bl.type) {
- /* FIXME: this should be ERROR class... */
- hwarn_eq0(mdoc);
+ nh = mdoc->last;
+
+ if (nh->norm->Bl.type != LIST_column) {
+ if ((nch = nh->child) == NULL)
+ return;
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nch->line, nch->pos, "Bl ... %s", nch->string);
+ while (nch != NULL) {
+ mdoc_node_delete(mdoc, nch);
+ nch = nh->child;
+ }
return;
}
@@ -1420,17 +1368,15 @@ post_bl_head(POST_ARGS)
* lists where they're argument values following -column.
*/
- if (mdoc->last->child == NULL)
+ if (nh->child == NULL)
return;
- np = mdoc->last->parent;
- assert(np->args);
-
- for (j = 0; j < (int)np->args->argc; j++)
- if (MDOC_Column == np->args->argv[j].arg)
+ nbl = nh->parent;
+ for (j = 0; j < (int)nbl->args->argc; j++)
+ if (nbl->args->argv[j].arg == MDOC_Column)
break;
- assert(j < (int)np->args->argc);
+ assert(j < (int)nbl->args->argc);
/*
* Accommodate for new-style groff column syntax. Shuffle the
@@ -1438,25 +1384,23 @@ post_bl_head(POST_ARGS)
* column field. Then, delete the head children.
*/
- argv = np->args->argv + j;
+ argv = nbl->args->argv + j;
i = argv->sz;
- argv->sz += mdoc->last->nchild;
+ argv->sz += nh->nchild;
argv->value = mandoc_reallocarray(argv->value,
argv->sz, sizeof(char *));
- mdoc->last->norm->Bl.ncols = argv->sz;
- mdoc->last->norm->Bl.cols = (void *)argv->value;
+ nh->norm->Bl.ncols = argv->sz;
+ nh->norm->Bl.cols = (void *)argv->value;
- for (nn = mdoc->last->child; nn; i++) {
- argv->value[i] = nn->string;
- nn->string = NULL;
- nnp = nn;
- nn = nn->next;
- mdoc_node_delete(NULL, nnp);
+ for (nch = nh->child; nch != NULL; nch = nnext) {
+ argv->value[i++] = nch->string;
+ nch->string = NULL;
+ nnext = nch->next;
+ mdoc_node_delete(NULL, nch);
}
-
- mdoc->last->nchild = 0;
- mdoc->last->child = NULL;
+ nh->nchild = 0;
+ nh->child = NULL;
}
static void
@@ -1480,11 +1424,17 @@ post_bl(POST_ARGS)
return;
}
- bwarn_ge1(mdoc);
-
nchild = nbody->child;
- while (NULL != nchild) {
- if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
+ if (nchild == NULL) {
+ mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ nbody->line, nbody->pos, "Bl");
+ return;
+ }
+ while (nchild != NULL) {
+ if (nchild->tok == MDOC_It ||
+ (nchild->tok == MDOC_Sm &&
+ nchild->next != NULL &&
+ nchild->next->tok == MDOC_It)) {
nchild = nchild->next;
continue;
}
@@ -1539,9 +1489,15 @@ post_bl(POST_ARGS)
static void
post_bk(POST_ARGS)
{
+ struct mdoc_node *n;
- hwarn_eq0(mdoc);
- bwarn_ge1(mdoc);
+ n = mdoc->last;
+
+ if (n->type == MDOC_BLOCK && n->body->child == NULL) {
+ mandoc_msg(MANDOCERR_BLK_EMPTY,
+ mdoc->parse, n->line, n->pos, "Bk");
+ mdoc_node_delete(mdoc, n);
+ }
}
static void
@@ -1623,13 +1579,6 @@ post_st(POST_ARGS)
n = mdoc->last;
nch = n->child;
- if (NULL == nch) {
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
- n->line, n->pos, mdoc_macronames[n->tok]);
- mdoc_node_delete(mdoc, n);
- return;
- }
-
assert(MDOC_TEXT == nch->type);
if (NULL == (p = mdoc_a2st(nch->string))) {
@@ -1645,19 +1594,17 @@ post_st(POST_ARGS)
static void
post_rs(POST_ARGS)
{
- struct mdoc_node *nn, *next, *prev;
+ struct mdoc_node *np, *nch, *next, *prev;
int i, j;
- switch (mdoc->last->type) {
- case MDOC_HEAD:
- check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
- return;
- case MDOC_BODY:
- if (mdoc->last->child)
- break;
- check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
+ np = mdoc->last;
+
+ if (np->type != MDOC_BODY)
return;
- default:
+
+ if (np->child == NULL) {
+ mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
+ np->line, np->pos, "Rs");
return;
}
@@ -1668,38 +1615,38 @@ post_rs(POST_ARGS)
*/
next = NULL;
- for (nn = mdoc->last->child->next; nn; nn = next) {
- /* Determine order of `nn'. */
+ for (nch = np->child->next; nch != NULL; nch = next) {
+ /* Determine order number of this child. */
for (i = 0; i < RSORD_MAX; i++)
- if (rsord[i] == nn->tok)
+ if (rsord[i] == nch->tok)
break;
if (i == RSORD_MAX) {
mandoc_msg(MANDOCERR_RS_BAD,
- mdoc->parse, nn->line, nn->pos,
- mdoc_macronames[nn->tok]);
+ mdoc->parse, nch->line, nch->pos,
+ mdoc_macronames[nch->tok]);
i = -1;
- } else if (MDOC__J == nn->tok || MDOC__B == nn->tok)
- mdoc->last->norm->Rs.quote_T++;
+ } else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
+ np->norm->Rs.quote_T++;
/*
- * Remove `nn' from the chain. This somewhat
+ * Remove this child from the chain. This somewhat
* repeats mdoc_node_unlink(), but since we're
* just re-ordering, there's no need for the
* full unlink process.
*/
- if (NULL != (next = nn->next))
- next->prev = nn->prev;
+ if ((next = nch->next) != NULL)
+ next->prev = nch->prev;
- if (NULL != (prev = nn->prev))
- prev->next = nn->next;
+ if ((prev = nch->prev) != NULL)
+ prev->next = nch->next;
- nn->prev = nn->next = NULL;
+ nch->prev = nch->next = NULL;
/*
* Scan back until we reach a node that's
- * ordered before `nn'.
+ * to be ordered before this child.
*/
for ( ; prev ; prev = prev->prev) {
@@ -1715,21 +1662,21 @@ post_rs(POST_ARGS)
}
/*
- * Set `nn' back into its correct place in front
- * of the `prev' node.
+ * Set this child back into its correct place
+ * in front of the `prev' node.
*/
- nn->prev = prev;
+ nch->prev = prev;
- if (prev) {
- if (prev->next)
- prev->next->prev = nn;
- nn->next = prev->next;
- prev->next = nn;
+ if (prev == NULL) {
+ np->child->prev = nch;
+ nch->next = np->child;
+ np->child = nch;
} else {
- mdoc->last->child->prev = nn;
- nn->next = mdoc->last->child;
- mdoc->last->child = nn;
+ if (prev->next)
+ prev->next->prev = nch;
+ nch->next = prev->next;
+ prev->next = nch;
}
}
}
@@ -1741,33 +1688,17 @@ post_rs(POST_ARGS)
static void
post_hyph(POST_ARGS)
{
- struct mdoc_node *n, *nch;
+ struct mdoc_node *nch;
char *cp;
- n = mdoc->last;
- switch (n->type) {
- case MDOC_HEAD:
- if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
- break;
- return;
- case MDOC_BODY:
- if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
- break;
- return;
- case MDOC_ELEM:
- break;
- default:
- return;
- }
-
- for (nch = n->child; nch; nch = nch->next) {
- if (MDOC_TEXT != nch->type)
+ for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
+ if (nch->type != MDOC_TEXT)
continue;
cp = nch->string;
- if ('\0' == *cp)
+ if (*cp == '\0')
continue;
- while ('\0' != *(++cp))
- if ('-' == *cp &&
+ while (*(++cp) != '\0')
+ if (*cp == '-' &&
isalpha((unsigned char)cp[-1]) &&
isalpha((unsigned char)cp[1]))
*cp = ASCII_HYPH;
@@ -1775,14 +1706,6 @@ post_hyph(POST_ARGS)
}
static void
-post_hyphtext(POST_ARGS)
-{
-
- ewarn_ge1(mdoc);
- post_hyph(mdoc);
-}
-
-static void
post_ns(POST_ARGS)
{
@@ -1825,41 +1748,45 @@ static void
post_sh_name(POST_ARGS)
{
struct mdoc_node *n;
+ int hasnm, hasnd;
- /*
- * Warn if the NAME section doesn't contain the `Nm' and `Nd'
- * macros (can have multiple `Nm' and one `Nd'). Note that the
- * children of the BODY declaration can also be "text".
- */
-
- if (NULL == (n = mdoc->last->child)) {
- mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
- mdoc->last->line, mdoc->last->pos, "empty");
- return;
- }
+ hasnm = hasnd = 0;
- for ( ; n && n->next; n = n->next) {
- if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
- continue;
- if (MDOC_TEXT == n->type)
- continue;
- mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
- n->line, n->pos, mdoc_macronames[n->tok]);
+ for (n = mdoc->last->child; n != NULL; n = n->next) {
+ switch (n->tok) {
+ case MDOC_Nm:
+ hasnm = 1;
+ break;
+ case MDOC_Nd:
+ hasnd = 1;
+ if (n->next != NULL)
+ mandoc_msg(MANDOCERR_NAMESEC_ND,
+ mdoc->parse, n->line, n->pos, NULL);
+ break;
+ case MDOC_MAX:
+ if (hasnm)
+ break;
+ /* FALLTHROUGH */
+ default:
+ mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
+ break;
+ }
}
- assert(n);
- if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
- return;
-
- mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
- n->line, n->pos, mdoc_macronames[n->tok]);
+ if ( ! hasnm)
+ mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
+ if ( ! hasnd)
+ mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
}
static void
post_sh_see_also(POST_ARGS)
{
const struct mdoc_node *n;
- const char *name, *sec;
+ const char *name, *sec;
const char *lastname, *lastsec, *lastpunct;
int cmp;
@@ -2061,11 +1988,15 @@ post_ignpar(POST_ARGS)
{
struct mdoc_node *np;
- check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0);
- post_hyph(mdoc);
-
- if (MDOC_BODY != mdoc->last->type)
+ switch (mdoc->last->type) {
+ case MDOC_HEAD:
+ post_hyph(mdoc);
return;
+ case MDOC_BODY:
+ break;
+ default:
+ return;
+ }
if (NULL != (np = mdoc->last->child))
if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
@@ -2123,14 +2054,17 @@ post_par(POST_ARGS)
{
struct mdoc_node *np;
- if (mdoc->last->tok == MDOC_sp)
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
- else
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
+ np = mdoc->last;
- if (MDOC_ELEM != mdoc->last->type &&
- MDOC_BLOCK != mdoc->last->type)
- return;
+ if (np->tok == MDOC_sp) {
+ if (np->nchild > 1)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ np->child->next->line, np->child->next->pos,
+ "sp ... %s", np->child->next->string);
+ } else if (np->child != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, np->line, np->pos, "%s %s",
+ mdoc_macronames[np->tok], np->child->string);
if (NULL == (np = mdoc->last->prev)) {
np = mdoc->last->parent;
@@ -2226,70 +2160,68 @@ post_dt(POST_ARGS)
mdoc->meta.vol = NULL;
mdoc->meta.arch = NULL;
- /* First check that all characters are uppercase. */
+ /* Mandatory first argument: title. */
- if (NULL != (nn = n->child))
- for (p = nn->string; *p; p++) {
- if (toupper((unsigned char)*p) == *p)
- continue;
- mandoc_vmsg(MANDOCERR_TITLE_CASE,
- mdoc->parse, nn->line,
- nn->pos + (p - nn->string),
- "Dt %s", nn->string);
- break;
- }
-
- /* No argument: msec and arch remain NULL. */
-
- if (NULL == (nn = n->child)) {
+ nn = n->child;
+ if (nn == NULL || *nn->string == '\0') {
mandoc_msg(MANDOCERR_DT_NOTITLE,
mdoc->parse, n->line, n->pos, "Dt");
mdoc->meta.title = mandoc_strdup("UNTITLED");
- mdoc->meta.vol = mandoc_strdup("LOCAL");
- goto out;
+ } else {
+ mdoc->meta.title = mandoc_strdup(nn->string);
+
+ /* Check that all characters are uppercase. */
+
+ for (p = nn->string; *p != '\0'; p++)
+ if (islower((unsigned char)*p)) {
+ mandoc_vmsg(MANDOCERR_TITLE_CASE,
+ mdoc->parse, nn->line,
+ nn->pos + (p - nn->string),
+ "Dt %s", nn->string);
+ break;
+ }
}
- /* One argument: msec and arch remain NULL. */
+ /* Mandatory second argument: section. */
- mdoc->meta.title = mandoc_strdup(
- '\0' == nn->string[0] ? "UNTITLED" : nn->string);
+ if (nn != NULL)
+ nn = nn->next;
- if (NULL == (nn = nn->next)) {
+ if (nn == NULL) {
mandoc_vmsg(MANDOCERR_MSEC_MISSING,
mdoc->parse, n->line, n->pos,
"Dt %s", mdoc->meta.title);
mdoc->meta.vol = mandoc_strdup("LOCAL");
- goto out;
+ goto out; /* msec and arch remain NULL. */
}
- /* Handles: `.Dt TITLE SEC'
- * title = TITLE,
- * volume = SEC is msec ? format(msec) : SEC,
- * msec = SEC is msec ? atoi(msec) : 0,
- * arch = NULL
- */
+ mdoc->meta.msec = mandoc_strdup(nn->string);
+
+ /* Infer volume title from section number. */
cp = mandoc_a2msec(nn->string);
- if (cp) {
- mdoc->meta.vol = mandoc_strdup(cp);
- mdoc->meta.msec = mandoc_strdup(nn->string);
- } else {
+ if (cp == NULL) {
mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
nn->line, nn->pos, "Dt ... %s", nn->string);
mdoc->meta.vol = mandoc_strdup(nn->string);
- mdoc->meta.msec = mandoc_strdup(nn->string);
- }
+ } else
+ mdoc->meta.vol = mandoc_strdup(cp);
- /* Handle an optional architecture */
+ /* Optional third argument: architecture. */
- if ((nn = nn->next) != NULL) {
- for (p = nn->string; *p; p++)
- *p = tolower((unsigned char)*p);
- mdoc->meta.arch = mandoc_strdup(nn->string);
- }
+ if ((nn = nn->next) == NULL)
+ goto out;
+
+ for (p = nn->string; *p != '\0'; p++)
+ *p = tolower((unsigned char)*p);
+ mdoc->meta.arch = mandoc_strdup(nn->string);
+
+ /* Ignore fourth and later arguments. */
+
+ if ((nn = nn->next) != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nn->line, nn->pos, "Dt ... %s", nn->string);
- /* Ignore any subsequent parameters... */
- /* FIXME: warn about subsequent parameters. */
out:
mdoc_node_delete(mdoc, n);
}
diff --git a/msec.c b/msec.c
index ffe5024ff1e3..d49d2975b6b1 100644
--- a/msec.c
+++ b/msec.c
@@ -1,4 +1,4 @@
-/* $Id: msec.c,v 1.13 2014/12/01 08:05:52 schwarze Exp $ */
+/* $Id: msec.c,v 1.14 2014/12/21 14:14:35 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -20,6 +20,7 @@
#include <string.h>
+#include "mandoc.h"
#include "libmandoc.h"
#define LINE(x, y) \
diff --git a/out.c b/out.c
index 7a61b39969c3..53b93fbe00cc 100644
--- a/out.c
+++ b/out.c
@@ -1,7 +1,7 @@
-/* $Id: out.c,v 1.54 2014/12/04 02:05:42 schwarze Exp $ */
+/* $Id: out.c,v 1.59 2015/01/30 04:11:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,8 +20,6 @@
#include <sys/types.h>
#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -39,97 +37,64 @@ static void tblcalc_number(struct rofftbl *, struct roffcol *,
/*
- * Convert a `scaling unit' to a consistent form, or fail. Scaling
- * units are documented in groff.7, mdoc.7, man.7.
+ * Parse the *src string and store a scaling unit into *dst.
+ * If the string doesn't specify the unit, use the default.
+ * If no default is specified, fail.
+ * Return 2 on complete success, 1 when a conversion was done,
+ * but there was trailing garbage, and 0 on total failure.
*/
int
a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
{
- char buf[BUFSIZ], hasd;
- int i;
- enum roffscale unit;
+ char *endptr;
- if ('\0' == *src)
+ dst->unit = def == SCALE_MAX ? SCALE_BU : def;
+ dst->scale = strtod(src, &endptr);
+ if (endptr == src)
return(0);
- i = hasd = 0;
-
- switch (*src) {
- case '+':
- src++;
+ switch (*endptr++) {
+ case 'c':
+ dst->unit = SCALE_CM;
break;
- case '-':
- buf[i++] = *src++;
+ case 'i':
+ dst->unit = SCALE_IN;
break;
- default:
+ case 'f':
+ dst->unit = SCALE_FS;
break;
- }
-
- if ('\0' == *src)
- return(0);
-
- while (i < BUFSIZ) {
- if ( ! isdigit((unsigned char)*src)) {
- if ('.' != *src)
- break;
- else if (hasd)
- break;
- else
- hasd = 1;
- }
- buf[i++] = *src++;
- }
-
- if (BUFSIZ == i || (*src && *(src + 1)))
- return(0);
-
- buf[i] = '\0';
-
- switch (*src) {
- case 'c':
- unit = SCALE_CM;
+ case 'M':
+ dst->unit = SCALE_MM;
break;
- case 'i':
- unit = SCALE_IN;
+ case 'm':
+ dst->unit = SCALE_EM;
+ break;
+ case 'n':
+ dst->unit = SCALE_EN;
break;
case 'P':
- unit = SCALE_PC;
+ dst->unit = SCALE_PC;
break;
case 'p':
- unit = SCALE_PT;
+ dst->unit = SCALE_PT;
break;
- case 'f':
- unit = SCALE_FS;
+ case 'u':
+ dst->unit = SCALE_BU;
break;
case 'v':
- unit = SCALE_VS;
- break;
- case 'm':
- unit = SCALE_EM;
+ dst->unit = SCALE_VS;
break;
case '\0':
+ endptr--;
+ /* FALLTHROUGH */
+ default:
if (SCALE_MAX == def)
return(0);
- unit = def;
- break;
- case 'u':
- unit = SCALE_BU;
- break;
- case 'M':
- unit = SCALE_MM;
- break;
- case 'n':
- unit = SCALE_EN;
+ dst->unit = def;
break;
- default:
- return(0);
}
- /* FIXME: do this in the caller. */
- if ((dst->scale = atof(buf)) < 0.0)
- dst->scale = 0.0;
- dst->unit = unit;
- return(1);
+ return(*endptr == '\0' ? 2 : 1);
}
/*
@@ -142,11 +107,12 @@ void
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
size_t totalwidth)
{
+ const struct tbl_opts *opts;
const struct tbl_dat *dp;
struct roffcol *col;
size_t ewidth, xwidth;
int spans;
- int icol, maxcol, necol, nxcol;
+ int icol, maxcol, necol, nxcol, quirkcol;
/*
* Allocate the master column specifiers. These will hold the
@@ -157,6 +123,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
assert(NULL == tbl->cols);
tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
sizeof(struct roffcol));
+ opts = sp->opts;
for (maxcol = -1; sp; sp = sp->next) {
if (TBL_SPAN_DATA != sp->pos)
@@ -173,14 +140,14 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
spans = dp->spans;
if (1 < spans)
continue;
- icol = dp->layout->head->ident;
+ icol = dp->layout->col;
if (maxcol < icol)
maxcol = icol;
col = tbl->cols + icol;
col->flags |= dp->layout->flags;
if (dp->layout->flags & TBL_CELL_WIGN)
continue;
- tblcalc_data(tbl, col, sp->opts, dp);
+ tblcalc_data(tbl, col, opts, dp);
}
}
@@ -230,13 +197,35 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
*/
if (nxcol && totalwidth) {
- xwidth = totalwidth - 3*maxcol - xwidth;
+ xwidth = totalwidth - xwidth - 3*maxcol -
+ (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
+ 2 : !!opts->lvert + !!opts->rvert);
+
+ /*
+ * Emulate a bug in GNU tbl width calculation that
+ * manifests itself for large numbers of x-columns.
+ * Emulating it for 5 x-columns gives identical
+ * behaviour for up to 6 x-columns.
+ */
+
+ if (nxcol == 5) {
+ quirkcol = xwidth % nxcol + 2;
+ if (quirkcol != 3 && quirkcol != 4)
+ quirkcol = -1;
+ } else
+ quirkcol = -1;
+
+ necol = 0;
+ ewidth = 0;
for (icol = 0; icol <= maxcol; icol++) {
col = tbl->cols + icol;
if ( ! (col->flags & TBL_CELL_WMAX))
continue;
- col->width = xwidth / nxcol--;
- xwidth -= col->width;
+ col->width = (double)xwidth * ++necol / nxcol
+ - ewidth + 0.4995;
+ if (necol == quirkcol)
+ col->width--;
+ ewidth += col->width;
}
}
}
diff --git a/preconv.c b/preconv.c
index 0c6076ecb425..a2bbe9ca6065 100644
--- a/preconv.c
+++ b/preconv.c
@@ -1,4 +1,4 @@
-/* $Id: preconv.c,v 1.12 2014/11/14 04:24:04 schwarze Exp $ */
+/* $Id: preconv.c,v 1.13 2014/12/19 04:58:35 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "mandoc.h"
@@ -28,88 +29,70 @@ int
preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
int *filenc)
{
- size_t i;
- int state;
+ unsigned char *cu;
+ int nby;
unsigned int accum;
- unsigned char cu;
+
+ cu = ib->buf + *ii;
+ assert(*cu & 0x80);
if ( ! (*filenc & MPARSE_UTF8))
goto latin;
- state = 0;
- accum = 0U;
-
- for (i = *ii; i < ib->sz; i++) {
- cu = ib->buf[i];
- if (state) {
- if ( ! (cu & 128) || (cu & 64)) {
- /* Bad sequence header. */
- break;
- }
-
- /* Accept only legitimate bit patterns. */
-
- if (cu > 191 || cu < 128) {
- /* Bad in-sequence bits. */
- break;
- }
-
- accum |= (cu & 63) << --state * 6;
-
- if (state)
- continue;
-
- if (accum < 0x80)
- ob->buf[(*oi)++] = accum;
- else
- *oi += snprintf(ob->buf + *oi,
- 11, "\\[u%.4X]", accum);
- *ii = i + 1;
- *filenc &= ~MPARSE_LATIN1;
- return(1);
- } else {
- /*
- * Entering a UTF-8 state: if we encounter a
- * UTF-8 bitmask, calculate the expected UTF-8
- * state from it.
- */
- for (state = 0; state < 7; state++)
- if ( ! (cu & (1 << (7 - state))))
- break;
-
- /* Accept only legitimate bit patterns. */
-
- switch (state--) {
- case (4):
- if (cu <= 244 && cu >= 240) {
- accum = (cu & 7) << 18;
- continue;
- }
- /* Bad 4-sequence start bits. */
- break;
- case (3):
- if (cu <= 239 && cu >= 224) {
- accum = (cu & 15) << 12;
- continue;
- }
- /* Bad 3-sequence start bits. */
- break;
- case (2):
- if (cu <= 223 && cu >= 194) {
- accum = (cu & 31) << 6;
- continue;
- }
- /* Bad 2-sequence start bits. */
- break;
- default:
- /* Bad sequence bit mask. */
- break;
- }
- break;
- }
+ nby = 1;
+ while (nby < 5 && *cu & (1 << (7 - nby)))
+ nby++;
+
+ switch (nby) {
+ case 2:
+ accum = *cu & 0x1f;
+ if (accum < 0x02) /* Obfuscated ASCII. */
+ goto latin;
+ break;
+ case 3:
+ accum = *cu & 0x0f;
+ break;
+ case 4:
+ accum = *cu & 0x07;
+ if (accum > 0x04) /* Beyond Unicode. */
+ goto latin;
+ break;
+ default: /* Bad sequence header. */
+ goto latin;
+ }
+
+ cu++;
+ switch (nby) {
+ case 3:
+ if ((accum == 0x00 && ! (*cu & 0x20)) || /* Use 2-byte. */
+ (accum == 0x0d && *cu & 0x20)) /* Surrogates. */
+ goto latin;
+ break;
+ case 4:
+ if ((accum == 0x00 && ! (*cu & 0x30)) || /* Use 3-byte. */
+ (accum == 0x04 && *cu & 0x30)) /* Beyond Unicode. */
+ goto latin;
+ break;
+ default:
+ break;
+ }
+
+ while (--nby) {
+ if ((*cu & 0xc0) != 0x80) /* Invalid continuation. */
+ goto latin;
+ accum <<= 6;
+ accum += *cu & 0x3f;
+ cu++;
}
- /* FALLTHROUGH: Invalid or incomplete UTF-8 sequence. */
+ assert(accum > 0x7f);
+ assert(accum < 0x110000);
+ assert(accum < 0xd800 || accum > 0xdfff);
+
+ *oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
+ *ii = (char *)cu - ib->buf;
+ *filenc &= ~MPARSE_LATIN1;
+ return(1);
latin:
if ( ! (*filenc & MPARSE_LATIN1))
diff --git a/read.c b/read.c
index 8d6cb1038bec..0b4caa05a9c0 100644
--- a/read.c
+++ b/read.c
@@ -1,7 +1,7 @@
-/* $Id: read.c,v 1.104 2014/12/01 04:14:14 schwarze Exp $ */
+/* $Id: read.c,v 1.129 2015/03/02 14:50:17 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -80,7 +80,7 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
MANDOCERR_WARNING,
MANDOCERR_WARNING,
MANDOCERR_ERROR,
- MANDOCERR_FATAL,
+ MANDOCERR_UNSUPP,
MANDOCERR_MAX,
MANDOCERR_MAX
};
@@ -109,7 +109,11 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"no document body",
"content before first section header",
"first section is not \"NAME\"",
- "bad NAME section contents",
+ "NAME section without name",
+ "NAME section without description",
+ "description not at the end of NAME",
+ "bad NAME section content",
+ "missing description line, using \"\"",
"sections out of conventional order",
"duplicate section title",
"unexpected section",
@@ -135,18 +139,22 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"skipping empty request",
"conditional request controls empty scope",
"skipping empty macro",
+ "empty block",
"empty argument, using 0n",
- "argument count wrong",
"missing display type, using -ragged",
"list type is not the first argument",
"missing -width in -tag list, using 8n",
"missing utility name, using \"\"",
+ "missing function name, using \"\"",
"empty head in list item",
"empty list item",
"missing font type, using \\fR",
"unknown font type, using \\fR",
"nothing follows prefix",
+ "empty reference block",
"missing -std argument, adding it",
+ "missing option string, using \"\"",
+ "missing resource identifier, using \"\"",
"missing eqn box, using \"\"",
/* related to bad macro arguments */
@@ -156,12 +164,14 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"skipping duplicate display type",
"skipping duplicate list type",
"skipping -width argument",
+ "wrong number of cells",
"unknown AT&T UNIX version",
"comma in function argument",
"parenthesis in function name",
"invalid content in Rs block",
"invalid Boolean argument",
"unknown font, skipping request",
+ "odd number of characters in request",
/* related to plain text */
"blank line in fill mode, using .sp",
@@ -171,64 +181,60 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"invalid escape sequence",
"undefined string, using \"\"",
- "generic error",
+ /* related to tables */
+ "tbl line starts with span",
+ "tbl column starts with span",
+ "skipping vertical bar in tbl layout",
- /* related to equations */
- "unexpected equation scope closure",
- "equation scope open on exit",
- "overlapping equation scopes",
- "unexpected end of equation",
+ "generic error",
/* related to tables */
- "bad table syntax",
- "bad table option",
- "bad table layout",
- "no table layout cells specified",
- "no table data cells specified",
- "ignore data in cell",
- "data block still open",
- "ignoring extra data cells",
+ "non-alphabetic character in tbl options",
+ "skipping unknown tbl option",
+ "missing tbl option argument",
+ "wrong tbl option argument size",
+ "empty tbl layout",
+ "invalid character in tbl layout",
+ "unmatched parenthesis in tbl layout",
+ "tbl without any data cells",
+ "ignoring data in spanned tbl cell",
+ "ignoring extra tbl data cells",
+ "data block open at end of tbl",
/* related to document structure and macros */
+ NULL,
"input stack limit exceeded, infinite loop?",
"skipping bad character",
"skipping unknown macro",
+ "skipping insecure request",
"skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
+ "fewer RS blocks open, skipping",
"inserting missing end of block",
"appending missing end of block",
/* related to request and macro arguments */
"escaped character not allowed in a name",
- "argument count wrong",
"NOT IMPLEMENTED: Bd -file",
"missing list type, using -item",
"missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN",
"unknown standard specifier",
"skipping request without numeric argument",
+ "NOT IMPLEMENTED: .so with absolute path or \"..\"",
+ ".so request failed",
"skipping all arguments",
"skipping excess arguments",
"divide by zero",
- "generic fatal error",
-
+ "unsupported feature",
"input too large",
- "NOT IMPLEMENTED: .so with absolute path or \"..\"",
- ".so request failed",
-
- /* system errors */
- "cannot dup file descriptor",
- "cannot exec",
- "gunzip failed with code",
- "cannot fork",
- NULL,
- "cannot open pipe",
- "cannot read file",
- "gunzip died from signal",
- "cannot stat file",
- "wait failed",
+ "unsupported control character",
+ "unsupported roff request",
+ "eqn delim option in tbl",
+ "unsupported tbl layout modifier",
+ "ignoring macro in table",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
@@ -236,7 +242,7 @@ static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"RESERVED",
"WARNING",
"ERROR",
- "FATAL",
+ "UNSUPP",
"BADARG",
"SYSERR"
};
@@ -297,7 +303,8 @@ choose_parser(struct mparse *curp)
/* Fall back to man(7) as a last resort. */
if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp,
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pman);
curp->man = curp->pman;
@@ -315,10 +322,14 @@ 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;
size_t pos; /* byte number in the ln buffer */
enum rofferr rr;
int of;
int lnn; /* line number in the real file */
+ int fd;
+ pid_t save_child;
unsigned char c;
memset(&ln, 0, sizeof(ln));
@@ -373,9 +384,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
if (c & 0x80) {
if ( ! (curp->filenc && preconv_encode(
&blk, &i, &ln, &pos, &curp->filenc))) {
- mandoc_vmsg(MANDOCERR_BADCHAR,
- curp, curp->line, pos,
- "0x%x", c);
+ mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
+ curp->line, pos, "0x%x", c);
ln.buf[pos++] = '?';
i++;
}
@@ -387,10 +397,13 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
*/
if (c == 0x7f || (c < 0x20 && c != 0x09)) {
- mandoc_vmsg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, "0x%x", c);
+ mandoc_vmsg(c == 0x00 || c == 0x04 ||
+ c > 0x0a ? MANDOCERR_CHAR_BAD :
+ MANDOCERR_CHAR_UNSUPP,
+ curp, curp->line, pos, "0x%x", c);
i++;
- ln.buf[pos++] = '?';
+ if (c != '\r')
+ ln.buf[pos++] = '?';
continue;
}
@@ -444,7 +457,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
if ( ! (isascii(c) &&
(isgraph(c) || isblank(c)))) {
- mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
curp->line, pos, "0x%x", c);
i += 2;
ln.buf[pos++] = '?';
@@ -513,9 +526,6 @@ rerun:
case ROFF_IGN:
pos = 0;
continue;
- case ROFF_ERR:
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- break;
case ROFF_SO:
if ( ! (curp->options & MPARSE_SO) &&
(i >= blk.sz || blk.buf[i] == '\0')) {
@@ -530,13 +540,26 @@ rerun:
*/
if (curp->secondary)
curp->secondary->sz -= pos + 1;
- mparse_readfd(curp, -1, ln.buf + of);
- if (MANDOCLEVEL_FATAL <= curp->file_status) {
+ save_file = curp->file;
+ save_child = curp->child;
+ if (mparse_open(curp, &fd, ln.buf + of) ==
+ MANDOCLEVEL_OK) {
+ mparse_readfd(curp, fd, ln.buf + of);
+ curp->file = save_file;
+ } else {
+ curp->file = save_file;
mandoc_vmsg(MANDOCERR_SO_FAIL,
curp, curp->line, pos,
".so %s", ln.buf + of);
- break;
+ ln.sz = mandoc_asprintf(&cp,
+ ".sp\nSee the file %s.\n.sp",
+ ln.buf + of);
+ free(ln.buf);
+ ln.buf = cp;
+ of = 0;
+ mparse_buf_r(curp, ln, of, 0);
}
+ curp->child = save_child;
pos = 0;
continue;
default:
@@ -544,14 +567,6 @@ rerun:
}
/*
- * If we encounter errors in the recursive parse, make
- * sure we don't continue parsing.
- */
-
- if (MANDOCLEVEL_FATAL <= curp->file_status)
- break;
-
- /*
* If input parsers have not been allocated, do so now.
* We keep these instanced between parsers, but set them
* locally per parse routine since we can use different
@@ -609,11 +624,8 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
#if HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_SYSSTAT, curp->file_status,
- file, 0, 0, strerror(errno));
- return(0);
+ perror(file);
+ exit((int)MANDOCLEVEL_SYSERR);
}
/*
@@ -625,10 +637,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
if (S_ISREG(st.st_mode)) {
if (st.st_size >= (1U << 31)) {
- curp->file_status = MANDOCLEVEL_FATAL;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_TOOLARGE,
- curp->file_status, file, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
return(0);
}
*with_mmap = 1;
@@ -651,11 +660,8 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
- curp->file_status = MANDOCLEVEL_FATAL;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_TOOLARGE,
- curp->file_status,
- file, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_TOOLARGE, curp,
+ 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
@@ -666,12 +672,8 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
return(1);
}
if (ssz == -1) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_SYSREAD,
- curp->file_status, file, 0, 0,
- strerror(errno));
- break;
+ perror(file);
+ exit((int)MANDOCLEVEL_SYSERR);
}
off += (size_t)ssz;
}
@@ -685,9 +687,6 @@ static void
mparse_end(struct mparse *curp)
{
- if (MANDOCLEVEL_FATAL <= curp->file_status)
- return;
-
if (curp->mdoc == NULL &&
curp->man == NULL &&
curp->sodest == NULL) {
@@ -695,22 +694,16 @@ mparse_end(struct mparse *curp)
curp->mdoc = curp->pmdoc;
else {
if (curp->pman == NULL)
- curp->pman = man_alloc(curp->roff, curp,
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
curp->man = curp->pman;
}
}
-
- if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- return;
- }
-
- if (curp->man && ! man_endparse(curp->man)) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- return;
- }
-
+ if (curp->mdoc)
+ mdoc_endparse(curp->mdoc);
+ if (curp->man)
+ man_endparse(curp->man);
roff_endparse(curp->roff);
}
@@ -747,7 +740,7 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
mparse_buf_r(curp, blk, offset, 1);
- if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
+ if (--recursion_depth == 0)
mparse_end(curp);
curp->primary = svprimary;
@@ -768,8 +761,6 @@ mparse_readmem(struct mparse *curp, void *buf, size_t len,
}
/*
- * If a file descriptor is given, use it and assume it points
- * to the named file. Otherwise, open the named file.
* Read the whole file into memory and call the parsers.
* Called recursively when an .so request is encountered.
*/
@@ -779,13 +770,6 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
struct buf blk;
int with_mmap;
int save_filenc;
- pid_t save_child;
-
- save_child = curp->child;
- if (fd != -1)
- curp->child = 0;
- else if (mparse_open(curp, &fd, file) >= MANDOCLEVEL_SYSERR)
- goto out;
if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
save_filenc = curp->filenc;
@@ -805,8 +789,6 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
perror(file);
mparse_wait(curp);
-out:
- curp->child = save_child;
return(curp->file_status);
}
@@ -816,9 +798,7 @@ mparse_open(struct mparse *curp, int *fd, const char *file)
int pfd[2];
int save_errno;
char *cp;
- enum mandocerr err;
- pfd[1] = -1;
curp->file = file;
/* Unless zipped, try to just open the file. */
@@ -842,50 +822,38 @@ mparse_open(struct mparse *curp, int *fd, const char *file)
if (access(file, R_OK) == -1) {
if (cp != NULL)
errno = save_errno;
- err = MANDOCERR_SYSOPEN;
- goto out;
+ free(cp);
+ *fd = -1;
+ curp->child = 0;
+ mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
+ return(MANDOCLEVEL_ERROR);
}
/* Run gunzip(1). */
if (pipe(pfd) == -1) {
- err = MANDOCERR_SYSPIPE;
- goto out;
+ perror("pipe");
+ exit((int)MANDOCLEVEL_SYSERR);
}
switch (curp->child = fork()) {
case -1:
- err = MANDOCERR_SYSFORK;
- close(pfd[0]);
- close(pfd[1]);
- pfd[1] = -1;
- break;
+ perror("fork");
+ exit((int)MANDOCLEVEL_SYSERR);
case 0:
close(pfd[0]);
if (dup2(pfd[1], STDOUT_FILENO) == -1) {
- err = MANDOCERR_SYSDUP;
- break;
+ perror("dup");
+ exit((int)MANDOCLEVEL_SYSERR);
}
execlp("gunzip", "gunzip", "-c", file, NULL);
- err = MANDOCERR_SYSEXEC;
- break;
+ perror("exec");
+ exit((int)MANDOCLEVEL_SYSERR);
default:
close(pfd[1]);
*fd = pfd[0];
return(MANDOCLEVEL_OK);
}
-
-out:
- free(cp);
- *fd = -1;
- curp->child = 0;
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(err, curp->file_status, curp->file,
- 0, 0, strerror(errno));
- if (pfd[1] != -1)
- exit(1);
- return(curp->file_status);
}
enum mandoclevel
@@ -897,22 +865,19 @@ mparse_wait(struct mparse *curp)
return(MANDOCLEVEL_OK);
if (waitpid(curp->child, &status, 0) == -1) {
- mandoc_msg(MANDOCERR_SYSWAIT, curp, 0, 0,
- strerror(errno));
- curp->file_status = MANDOCLEVEL_SYSERR;
- return(curp->file_status);
+ perror("wait");
+ exit((int)MANDOCLEVEL_SYSERR);
}
+ curp->child = 0;
if (WIFSIGNALED(status)) {
- mandoc_vmsg(MANDOCERR_SYSSIG, curp, 0, 0,
- "%d", WTERMSIG(status));
- curp->file_status = MANDOCLEVEL_SYSERR;
- return(curp->file_status);
+ mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ "gunzip died from signal %d", WTERMSIG(status));
+ return(MANDOCLEVEL_ERROR);
}
if (WEXITSTATUS(status)) {
- mandoc_vmsg(MANDOCERR_SYSEXIT, curp, 0, 0,
- "%d", WEXITSTATUS(status));
- curp->file_status = MANDOCLEVEL_SYSERR;
- return(curp->file_status);
+ mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ "gunzip failed with code %d", WEXITSTATUS(status));
+ return(MANDOCLEVEL_ERROR);
}
return(MANDOCLEVEL_OK);
}
@@ -923,8 +888,6 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
{
struct mparse *curp;
- assert(wlevel <= MANDOCLEVEL_FATAL);
-
curp = mandoc_calloc(1, sizeof(struct mparse));
curp->options = options;
@@ -939,7 +902,8 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MAN)
- curp->pman = man_alloc(curp->roff, curp,
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
return(curp);
@@ -1020,11 +984,11 @@ mandoc_msg(enum mandocerr er, struct mparse *m,
{
enum mandoclevel level;
- level = MANDOCLEVEL_FATAL;
+ level = MANDOCLEVEL_UNSUPP;
while (er < mandoclimits[level])
level--;
- if (level < m->wlevel)
+ if (level < m->wlevel && er != MANDOCERR_FILE)
return;
if (m->mmsg)
diff --git a/roff.7 b/roff.7
index 6ee29321884d..dc39b69bb56b 100644
--- a/roff.7
+++ b/roff.7
@@ -1,4 +1,4 @@
-.\" $Id: roff.7,v 1.60 2014/12/02 10:08:06 schwarze Exp $
+.\" $Id: roff.7,v 1.70 2015/02/17 17:16:52 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: December 2 2014 $
+.Dd $Mdocdate: February 17 2015 $
.Dt ROFF 7
.Os
.Sh NAME
@@ -395,27 +395,32 @@ The
.Xr mandoc 1
.Nm
parser recognises the following requests.
-Note that the
-.Nm
-language defines many more requests not implemented in
-.Xr mandoc 1 .
+For requests marked as "ignored" or "unsupported", any arguments are
+ignored, and the number of arguments is not checked.
+.Ss \&ab
+Abort processing.
+Currently unsupported.
.Ss \&ad
Set line adjustment mode.
-This line-scoped request is intended to have one argument to select
-normal, left, right, or centre adjustment for subsequent text.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+It takes one argument to select normal, left, right,
+or center adjustment for subsequent text.
+Currently ignored.
+.Ss \&af
+Assign an output format to a number register.
+Currently ignored.
+.Ss \&aln
+Create an alias for a number register.
+Currently unsupported.
+.Ss \&als
+Create an alias for a request, string, macro, or diversion.
+Currently unsupported.
.Ss \&am
Append to a macro definition.
The syntax of this request is the same as that of
.Sx \&de .
-.Ss \&ami
-Append to a macro definition, specifying the macro name indirectly.
-The syntax of this request is the same as that of
-.Sx \&dei .
.Ss \&am1
Append to a macro definition, switching roff compatibility mode off
-during macro execution.
+during macro execution (groff extension).
The syntax of this request is the same as that of
.Sx \&de1 .
Since
@@ -424,14 +429,96 @@ does not implement
.Nm
compatibility mode at all, it handles this request as an alias for
.Sx \&am .
+.Ss \&ami
+Append to a macro definition, specifying the macro name indirectly
+(groff extension).
+The syntax of this request is the same as that of
+.Sx \&dei .
+.Ss \&ami1
+Append to a macro definition, specifying the macro name indirectly
+and switching roff compatibility mode off during macro execution
+(groff extension).
+The syntax of this request is the same as that of
+.Sx \&dei1 .
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&ami .
.Ss \&as
Append to a user-defined string.
The syntax of this request is the same as that of
.Sx \&ds .
If a user-defined string with the specified name does not yet exist,
it is set to the empty string before appending.
+.Ss \&as1
+Append to a user-defined string, switching roff compatibility mode off
+during macro execution (groff extension).
+The syntax of this request is the same as that of
+.Sx \&ds1 .
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&as .
+.Ss \&asciify
+Fully unformat a diversion.
+Currently unsupported.
+.Ss \&backtrace
+Print a backtrace of the input stack.
+This is a groff extension and currently ignored.
+.Ss \&bd
+Artificially embolden by repeated printing with small shifts.
+Currently ignored.
+.Ss \&bleedat
+Set the BleedBox page parameter for PDF generation.
+This is a Heirloom extension and currently ignored.
+.Ss \&blm
+Set a blank line trap.
+Currently unsupported.
+.Ss \&box
+Begin a diversion without including a partially filled line.
+Currently unsupported.
+.Ss \&boxa
+Add to a diversion without including a partially filled line.
+Currently unsupported.
+.Ss \&bp
+Begin new page.
+Currently ignored.
+.Ss \&BP
+Define a frame and place a picture in it.
+This is a Heirloom extension and currently unsupported.
+.Ss \&br
+Break the output line.
+See
+.Xr man 7
+and
+.Xr mdoc 7 .
+.Ss \&break
+Break out of a
+.Sx \&while
+loop.
+Currently unsupported.
+.Ss \&breakchar
+Optional line break characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&brnl
+Break output line after next N input lines.
+This is a Heirloom extension and currently ignored.
+.Ss \&brp
+Break and spread output line.
+Currently, this is implemented as an alias for
+.Sx \&br .
+.Ss \&brpnl
+Break and spread output line after next N input lines.
+This is a Heirloom extension and currently ignored.
+.Ss \&c2
+Change the no-break control character.
+Currently unsupported.
.Ss \&cc
-Changes the control character.
+Change the control character.
Its syntax is as follows:
.Bd -literal -offset indent
.Pf . Cm \&cc Op Ar c
@@ -444,10 +531,63 @@ is not specified, the control character is reset to
Trailing characters are ignored.
.Ss \&ce
Center some lines.
-This line-scoped request is intended to take one integer argument,
-specifying how many lines to center.
-Currently, it is ignored including its arguments, and the number
-of arguments is not checked.
+It takes one integer argument, specifying how many lines to center.
+Currently ignored.
+.Ss \&cf
+Output the contents of a file.
+Ignored because insecure.
+.Ss \&cflags
+Set character flags.
+This is a groff extension and currently ignored.
+.Ss \&ch
+Change a trap location.
+Currently ignored.
+.Ss \&char
+Define a new glyph.
+Currently unsupported.
+.Ss \&chop
+Remove the last character from a macro, string, or diversion.
+Currently unsupported.
+.Ss \&class
+Define a character class.
+This is a groff extension and currently ignored.
+.Ss \&close
+Close an open file.
+Ignored because insecure.
+.Ss \&CL
+Print text in color.
+This is a Heirloom extension and currently unsupported.
+.Ss \&color
+Activate or deactivate colors.
+This is a groff extension and currently ignored.
+.Ss \&composite
+Define a name component for composite glyph names.
+This is a groff extension and currently unsupported.
+.Ss \&continue
+Immediately start the next iteration of a
+.Sx \&while
+loop.
+Currently unsupported.
+.Ss \&cp
+Switch
+.Nm
+compatibility mode on or off.
+Currently ignored.
+.Ss \&cropat
+Set the CropBox page parameter for PDF generation.
+This is a Heirloom extension and currently ignored.
+.Ss \&cs
+Constant character spacing mode.
+Currently ignored.
+.Ss \&cu
+Underline including whitespace.
+Currently ignored.
+.Ss \&da
+Append to a diversion.
+Currently unsupported.
+.Ss \&dch
+Change a trap location in the current diversion.
+This is a Heirloom extension and currently unsupported.
.Ss \&de
Define a
.Nm
@@ -543,12 +683,30 @@ one explicit newline character.
In order to prevent endless recursion, both groff and
.Xr mandoc 1
limit the stack depth for expanding macros and strings
-to a large, but finite number.
-Do not rely on the exact value of this limit.
+to a large, but finite number, and
+.Xr mandoc 1
+also limits the length of the expanded input line.
+Do not rely on the exact values of these limits.
+.Ss \&de1
+Define a
+.Nm
+macro that will be executed with
+.Nm
+compatibility mode switched off during macro execution.
+This is a groff extension.
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&de .
+.Ss \&defcolor
+Define a color name.
+This is a groff extension and currently ignored.
.Ss \&dei
Define a
.Nm
-macro, specifying the macro name indirectly.
+macro, specifying the macro name indirectly (groff extension).
The syntax of this request is the same as that of
.Sx \&de .
The request
@@ -558,21 +716,33 @@ The request
has the same effect as:
.Pp
.D1 Pf . Cm \&de No \e* Ns Bo Ar name Bc Op \e* Ns Bq Ar end
-.Ss \&de1
+.Ss \&dei1
Define a
.Nm
macro that will be executed with
.Nm
-compatibility mode switched off during macro execution.
-This is a GNU extension not available in traditional
-.Nm
-implementations and not even in older versions of groff.
+compatibility mode switched off during macro execution,
+specifying the macro name indirectly (groff extension).
Since
.Xr mandoc 1
does not implement
.Nm
compatibility mode at all, it handles this request as an alias for
-.Sx \&de .
+.Sx \&dei .
+.Ss \&device
+This request only makes sense with the groff-specific intermediate
+output format and is unsupported.
+.Ss \&devicem
+This request only makes sense with the groff-specific intermediate
+output format and is unsupported.
+.Ss \&di
+Begin a diversion.
+Currently unsupported.
+.Ss \&do
+Execute
+.Nm
+request or macro line with compatibility mode disabled.
+Currently unsupported.
.Ss \&ds
Define a user-defined string.
Its syntax is as follows:
@@ -631,6 +801,32 @@ macro when used in a
.Xr man 7
document.
Such abuse is of course strongly discouraged.
+.Ss \&ds1
+Define a user-defined string that will be expanded with
+.Nm
+compatibility mode switched off during string expansion.
+This is a groff extension.
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&ds .
+.Ss \&dwh
+Set a location trap in the current diversion.
+This is a Heirloom extension and currently unsupported.
+.Ss \&dt
+Set a trap within a diversion.
+Currently unsupported.
+.Ss \&ec
+Change the escape character.
+Currently unsupported.
+.Ss \&ecs
+Restore the escape character.
+Currently unsupported.
+.Ss \&ecr
+Save the escape character.
+Currently unsupported.
.Ss \&el
The
.Qq else
@@ -645,21 +841,89 @@ then false is assumed.
The syntax of this request is similar to
.Sx \&if
except that the conditional is missing.
+.Ss \&em
+Set a trap at the end of input.
+Currently unsupported.
.Ss \&EN
End an equation block.
See
.Sx \&EQ .
+.Ss \&eo
+Disable the escape mechanism completely.
+Currently unsupported.
+.Ss \&EP
+End a picture started by
+.Sx \&BP .
+This is a Heirloom extension and currently unsupported.
.Ss \&EQ
Begin an equation block.
See
.Xr eqn 7
for a description of the equation language.
+.Ss \&errprint
+Print a string like an error message.
+This is a Heirloom extension and currently ignored.
+.Ss \&ev
+Switch to another environment.
+Currently unsupported.
+.Ss \&evc
+Copy an environment into the current environment.
+Currently unsupported.
+.Ss \&ex
+Abort processing and exit.
+Currently unsupported.
+.Ss \&fallback
+Select the fallback sequence for a font.
+This is a Heirloom extension and currently ignored.
.Ss \&fam
Change the font family.
-This line-scoped request is intended to have one argument specifying
-the font family to be selected.
-It is a groff extension, and currently, it is ignored including its
-arguments, and the number of arguments is not checked.
+Takes one argument specifying the font family to be selected.
+It is a groff extension and currently ignored.
+.Ss \&fc
+Define a delimiting and a padding character for fields.
+Currently unsupported.
+.Ss \&fchar
+Define a fallback glyph.
+Currently unsupported.
+.Ss \&fcolor
+Set the fill color for \eD objects.
+This is a groff extension and currently ignored.
+.Ss \&fdeferlig
+Defer ligature building.
+This is a Heirloom extension and currently ignored.
+.Ss \&feature
+Enable or disable an OpenType feature.
+This is a Heirloom extension and currently ignored.
+.Ss \&fi
+Switch to fill mode.
+See
+.Xr man 7 .
+Ignored in
+.Xr mdoc 7 .
+.Ss \&fkern
+Control the use of kerning tables for a font.
+This is a Heirloom extension and currently ignored.
+.Ss \&fl
+Flush output.
+Currently ignored.
+.Ss \&flig
+Define ligatures.
+This is a Heirloom extension and currently ignored.
+.Ss \&fp
+Assign font position.
+Currently ignored.
+.Ss \&fps
+Mount a font with a special character map.
+This is a Heirloom extension and currently ignored.
+.Ss \&fschar
+Define a font-specific fallback glyph.
+This is a groff extension and currently unsupported.
+.Ss \&fspacewidth
+Set a font-specific width for the space character.
+This is a Heirloom extension and currently ignored.
+.Ss \&fspecial
+Conditionally define a special font.
+This is a groff extension and currently ignored.
.Ss \&ft
Change the font.
Its syntax is as follows:
@@ -688,12 +952,60 @@ This request takes effect only locally, may be overridden by macros
and escape sequences, and is only supported in
.Xr man 7
for now.
+.Ss \&ftr
+Translate font name.
+This is a groff extension and currently ignored.
+.Ss \&fzoom
+Zoom font size.
+Currently ignored.
+.Ss \&gcolor
+Set glyph color.
+This is a groff extension and currently ignored.
+.Ss \&hc
+Set the hyphenation character.
+Currently ignored.
+.Ss \&hcode
+Set hyphenation codes of characters.
+Currently ignored.
+.Ss \&hidechar
+Hide characters in a font.
+This is a Heirloom extension and currently ignored.
+.Ss \&hla
+Set hyphenation language.
+This is a groff extension and currently ignored.
+.Ss \&hlm
+Set maximum number of consecutive hyphenated lines.
+Currently ignored.
+.Ss \&hpf
+Load hyphenation pattern file.
+This is a groff extension and currently ignored.
+.Ss \&hpfa
+Load hyphenation pattern file, appending to the current patterns.
+This is a groff extension and currently ignored.
+.Ss \&hpfcode
+Define mapping values for character codes in hyphenation patterns.
+This is a groff extension and currently ignored.
.Ss \&hw
Specify hyphenation points in words.
-This line-scoped request is currently ignored.
+Currently ignored.
.Ss \&hy
Set automatic hyphenation mode.
-This line-scoped request is currently ignored.
+Currently ignored.
+.Ss \&hylang
+Set hyphenation language.
+This is a Heirloom extension and currently ignored.
+.Ss \&hylen
+Minimum word length for hyphenation.
+This is a Heirloom extension and currently ignored.
+.Ss \&hym
+Set hyphenation margin.
+This is a groff extension and currently ignored.
+.Ss \&hypp
+Define hyphenation penalties.
+This is a Heirloom extension and currently ignored.
+.Ss \&hys
+Set hyphenation space.
+This is a groff extension and currently ignored.
.Ss \&ie
The
.Qq if
@@ -871,6 +1183,82 @@ Otherwise, it only terminates the
and arguments following it or the
.Sq \&..
request are discarded.
+.Ss \&in
+Change indentation.
+See
+.Xr man 7 .
+Ignored in
+.Xr mdoc 7 .
+.Ss \&index
+Find a substring in a string.
+This is a Heirloom extension and currently unsupported.
+.Ss \&it
+Set an input line trap.
+Its syntax is as follows:
+.Pp
+.D1 Pf . Cm it Ar expression macro
+.Pp
+The named
+.Ar macro
+will be invoked after processing the number of input text lines
+specified by the numerical
+.Ar expression .
+While evaluating the
+.Ar expression ,
+the unit suffixes described below
+.Sx Scaling Widths
+are ignored.
+.Ss \&itc
+Set an input line trap, not counting lines ending with \ec.
+Currently unsupported.
+.Ss \&IX
+To support the generation of a table of contents,
+.Xr pod2man 1
+emits this user-defined macro, usually without defining it.
+To avoid reporting large numbers of spurious errors,
+.Xr mandoc 1
+ignores it.
+.Ss \&kern
+Switch kerning on or off.
+Currently ignored.
+.Ss \&kernafter
+Increase kerning after some characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&kernbefore
+Increase kerning before some characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&kernpair
+Add a kerning pair to the kerning table.
+This is a Heirloom extension and currently ignored.
+.Ss \&lc
+Define a leader repetition character.
+Currently unsupported.
+.Ss \&lc_ctype
+Set the
+.Dv LC_CTYPE
+locale.
+This is a Heirloom extension and currently unsupported.
+.Ss \&lds
+Define a local string.
+This is a Heirloom extension and currently unsupported.
+.Ss \&length
+Count the number of input characters in a user-defined string.
+Currently unsupported.
+.Ss \&letadj
+Dynamic letter spacing and reshaping.
+This is a Heirloom extension and currently ignored.
+.Ss \&lf
+Change the line number for error messages.
+Ignored because insecure.
+.Ss \&lg
+Switch the ligature mechanism on or off.
+Currently ignored.
+.Ss \&lhang
+Hang characters at left margin.
+This is a Heirloom extension and currently ignored.
+.Ss \&linetabs
+Enable or disable line-tabs mode.
+This is a groff extension and currently unsupported.
.Ss \&ll
Change the output line length.
Its syntax is as follows:
@@ -888,13 +1276,69 @@ among others because it overrides the
.Xr mandoc 1
.Fl O Cm width
command line option.
+.Ss \&lnr
+Set local number register.
+This is a Heirloom extension and currently unsupported.
+.Ss \&lnrf
+Set local floating-point register.
+This is a Heirloom extension and currently unsupported.
+.Ss \&lpfx
+Set a line prefix.
+This is a Heirloom extension and currently unsupported.
+.Ss \&ls
+Set line spacing.
+It takes one integer argument specifying the vertical distance of
+subsequent output text lines measured in v units.
+Currently ignored.
+.Ss \&lsm
+Set a leading spaces trap.
+This is a groff extension and currently unsupported.
+.Ss \&lt
+Set title line length.
+Currently ignored.
+.Ss \&mc
+Print margin character in the right margin.
+Currently ignored.
+.Ss \&mediasize
+Set the device media size.
+This is a Heirloom extension and currently ignored.
+.Ss \&minss
+Set minimum word space.
+This is a Heirloom extension and currently ignored.
+.Ss \&mk
+Mark vertical position.
+Currently ignored.
+.Ss \&mso
+Load a macro file.
+Ignored because insecure.
+.Ss \&na
+Disable adjusting without changing the adjustment mode.
+Currently ignored.
.Ss \&ne
Declare the need for the specified minimum vertical space
before the next trap or the bottom of the page.
-This line-scoped request is currently ignored.
+Currently ignored.
+.Ss \&nf
+Switch to no-fill mode.
+See
+.Xr man 7 .
+Ignored by
+.Xr mdoc 7 .
.Ss \&nh
Turn off automatic hyphenation mode.
-This line-scoped request is currently ignored.
+Currently ignored.
+.Ss \&nhychar
+Define hyphenation-inhibiting characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&nm
+Print line numbers.
+Currently unsupported.
+.Ss \&nn
+Temporarily turn off line numbering.
+Currently unsupported.
+.Ss \&nop
+Exexute the rest of the input line as a request or macro line.
+Currently unsupported.
.Ss \&nr
Define or change a register.
A register is an arbitrary string value that defines some sort of state,
@@ -932,31 +1376,142 @@ section with the
.Cm \&Sh
macro will reset this register.
.El
+.Ss \&nrf
+Define or change a floating-point register.
+This is a Heirloom extension and currently unsupported.
+.Ss \&nroff
+Force nroff mode.
+This is a groff extension and currently ignored.
.Ss \&ns
Turn on no-space mode.
-This line-scoped request is intended to take no arguments.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Currently ignored.
+.Ss \&nx
+Abort processing of the current input file and process another one.
+Ignored because insecure.
+.Ss \&open
+Open a file for writing.
+Ignored because insecure.
+.Ss \&opena
+Open a file for appending.
+Ignored because insecure.
+.Ss \&os
+Output saved vertical space.
+Currently ignored.
+.Ss \&output
+Output directly to intermediate output.
+Not supported.
+.Ss \&padj
+Globally control paragraph-at-once adjustment.
+This is a Heirloom extension and currently ignored.
+.Ss \&papersize
+Set the paper size.
+This is a Heirloom extension and currently ignored.
+.Ss \&pc
+Change the page number character.
+Currently ignored.
+.Ss \&pev
+Print environments.
+This is a groff extension and currently ignored.
+.Ss \&pi
+Pipe output to a shell command.
+Ignored because insecure.
+.Ss \&PI
+Low-level request used by
+.Sx \&BP .
+This is a Heirloom extension and currently unsupported.
.Ss \&pl
Change page length.
-This line-scoped request is intended to take one height argument.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Takes one height argument.
+Currently ignored.
+.Ss \&pm
+Print names and sizes of macros, strings, and diversions.
+Currently ignored.
+.Ss \&pn
+Change page number of the next page.
+Currently ignored.
+.Ss \&pnr
+Print all number registers.
+Currently ignored.
+.Ss \&po
+Set horizontal page offset.
+Currently ignored.
.Ss \&ps
Change point size.
-This line-scoped request is intended to take one numerical argument.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Takes one numerical argument.
+Currently ignored.
+.Ss \&psbb
+Retrieve the bounding box of a PostScript file.
+Currently unsupported.
+.Ss \&pshape
+Set a special shape for the current paragraph.
+This is a Heirloom extension and currently unsupported.
+.Ss \&pso
+Include output of a shell command.
+Ignored because insecure.
+.Ss \&ptr
+Print the names and positions of all traps.
+This is a groff extension and currently ignored.
+.Ss \&pvs
+Change post-vertical spacing.
+This is a groff extension and currently ignored.
+.Ss \&rchar
+Remove glyph definitions.
+Currently unsupported.
+.Ss \&rd
+Read from standard input.
+Currently ignored.
+.Ss \&recursionlimit
+Set the maximum stack depth for recursive macros.
+This is a Heirloom extension and currently ignored.
+.Ss \&return
+Exit a macro and return to the caller.
+Currently unsupported.
+.Ss \&rfschar
+Remove font-specific fallback glyph definitions.
+Currently unsupported.
+.Ss \&rhang
+Hang characters at right margin.
+This is a Heirloom extension and currently ignored.
+.Ss \&rj
+Justify unfilled text to the right margin.
+Currently ignored.
.Ss \&rm
Remove a request, macro or string.
Its syntax is as follows:
.Pp
.D1 Pf \. Cm \&rm Ar name
+.Ss \&rn
+Rename a request, macro, diversion, or string.
+Currently unsupported.
+.Ss \&rnn
+Rename a number register.
+Currently unsupported.
.Ss \&rr
Remove a register.
Its syntax is as follows:
.Pp
.D1 Pf \. Cm \&rr Ar name
+.Ss \&rs
+End no-space mode.
+Currently ignored.
+.Ss \&rt
+Return to marked vertical position.
+Currently ignored.
+.Ss \&schar
+Define global fallback glyph.
+This is a groff extension and currently unsupported.
+.Ss \&sentchar
+Define sentence-ending characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&shc
+Change the soft hyphen character.
+Currently ignored.
+.Ss \&shift
+Shift macro arguments.
+Currently unsupported.
+.Ss \&sizes
+Define permissible point sizes.
+This is a groff extension and currently ignored.
.Ss \&so
Include a source file.
Its syntax is as follows:
@@ -990,10 +1545,64 @@ is discouraged.
Use
.Xr ln 1
instead.
+.Ss \&spacewidth
+Set the space width from the font metrics file.
+This is a Heirloom extension and currently ignored.
+.Ss \&special
+Define a special font.
+This is a groff extension and currently ignored.
+.Ss \&spreadwarn
+Warn about wide spacing between words.
+Currently ignored.
+.Ss \&ss
+Set space character size.
+Currently ignored.
+.Ss \&sty
+Associate style with a font position.
+This is a groff extension and currently ignored.
+.Ss \&substring
+Replace a user-defined string with a substring.
+Currently unsupported.
+.Ss \&sv
+Save vertical space.
+Currently ignored.
+.Ss \&sy
+Execute shell command.
+Ignored because insecure.
+.Ss \&T&
+Re-start a table layout, retaining the options of the prior table
+invocation.
+See
+.Sx \&TS .
.Ss \&ta
Set tab stops.
-This line-scoped request can take an arbitrary number of arguments.
-Currently, it is ignored including its arguments.
+Takes an arbitrary number of arguments.
+Currently unsupported.
+.Ss \&tc
+Change tab repetion character.
+Currently unsupported.
+.Ss \&TE
+End a table context.
+See
+.Sx \&TS .
+.Ss \&ti
+Temporary indent.
+Currently unsupported.
+.Ss \&tkf
+Enable track kerning for a font.
+Currently ignored.
+.Ss \&tl
+Print a title line.
+Currently unsupported.
+.Ss \&tm
+Print to standard error output.
+Currently ignored.
+.Ss \&tm1
+Print to standard error output, allowing leading blanks.
+This is a groff extension and currently ignored.
+.Ss \&tmc
+Print to standard error output without a trailing newline.
+This is a groff extension and currently ignored.
.Ss \&tr
Output character translation.
Its syntax is as follows:
@@ -1011,20 +1620,88 @@ Replacement (or origin) characters may also be character escapes; thus,
.Dl tr \e(xx\e(yy
.Pp
replaces all invocations of \e(xx with \e(yy.
-.Ss \&T&
-Re-start a table layout, retaining the options of the prior table
-invocation.
-See
-.Sx \&TS .
-.Ss \&TE
-End a table context.
-See
-.Sx \&TS .
+.Ss \&track
+Static letter space tracking.
+This is a Heirloom extension and currently ignored.
+.Ss \&transchar
+Define transparent characters for sentence-ending.
+This is a Heirloom extension and currently ignored.
+.Ss \&trf
+Output the contents of a file, disallowing invalid characters.
+This is a groff extension and ignored because insecure.
+.Ss \&trimat
+Set the TrimBox page parameter for PDF generation.
+This is a Heirloom extension and currently ignored.
+.Ss \&trin
+Output character translation, ignored by
+.Cm \&asciify .
+Currently unsupported.
+.Ss \&trnt
+Output character translation, ignored by \e!.
+Currently unsupported.
+.Ss \&troff
+Force troff mode.
+This is a groff extension and currently ignored.
.Ss \&TS
Begin a table, which formats input in aligned rows and columns.
See
.Xr tbl 7
for a description of the tbl language.
+.Ss \&uf
+Globally set the underline font.
+Currently ignored.
+.Ss \&ul
+Underline.
+Currently ignored.
+.Ss \&unformat
+Unformat spaces and tabs in a diversion.
+Currently unsupported.
+.Ss \&unwatch
+Disable notification for string or macro.
+This is a Heirloom extension and currently ignored.
+.Ss \&unwatchn
+Disable notification for register.
+This is a Heirloom extension and currently ignored.
+.Ss \&vpt
+Enable or disable vertical position traps.
+This is a groff extension and currently ignored.
+.Ss \&vs
+Change vertical spacing.
+Currently ignored.
+.Ss \&warn
+Set warning level.
+Currently ignored.
+.Ss \&warnscale
+Set the scaling indicator used in warnings.
+This is a groff extension and currently ignored.
+.Ss \&watch
+Notify on change of string or macro.
+This is a Heirloom extension and currently ignored.
+.Ss \&watchlength
+On change, report the contents of macros and strings
+up to the sepcified length.
+This is a Heirloom extension and currently ignored.
+.Ss \&watchn
+Notify on change of register.
+This is a Heirloom extension and currently ignored.
+.Ss \&wh
+Set a page location trap.
+Currently unsupported.
+.Ss \&while
+Repeated execution while a condition is true.
+Currently unsupported.
+.Ss \&write
+Write to an open file.
+Ignored because insecure.
+.Ss \&writec
+Write to an open file without appending a newline.
+Ignored because insecure.
+.Ss \&writem
+Write macro or string to an open file.
+Ignored because insecure.
+.Ss \&xflag
+Set the extension level.
+This is a Heirloom extension and currently ignored.
.Ss Numerical expressions
The
.Sx \&nr ,
@@ -1043,6 +1720,14 @@ prefixed by an optional sign
.Sq +
or
.Sq - .
+Each number may be followed by one optional scaling unit described below
+.Sx Scaling Widths .
+The following equations hold:
+.Bd -literal -offset indent
+1i = 6v = 6P = 10m = 10n = 72p = 1000M = 240u = 240
+254c = 100i = 24000u = 24000
+1f = 65536u = 65536
+.Ed
.Pp
The following binary operators are implemented.
Unless otherwise stated, they behave as in the C language:
@@ -1276,10 +1961,11 @@ For short names, there are variants
and
.No \en( Ns Ar cc .
.Ss \eo\(aq Ns Ar string Ns \(aq
-Overstrike
-.Ar string ;
-ignored by
-.Xr mandoc 1 .
+Overstrike, writing all the characters contained in the
+.Ar string
+to the same output position.
+In terminal and HTML output modes,
+only the last one of the characters is visible.
.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq
Set number register; ignored by
.Xr mandoc 1 .
@@ -1347,50 +2033,66 @@ approximated in
.Xr mandoc 1
by simply skipping the next character.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other
+The
+.Xr mandoc 1
+implementation of the
.Nm
-implementations, at this time limited to GNU troff
-.Pq Qq groff .
-The term
-.Qq historic groff
-refers to groff version 1.15.
+language is intentionally incomplete.
+Unimplemented features include:
.Pp
.Bl -dash -compact
.It
+For security reasons,
+.Xr mandoc 1
+never reads or writes external files except via
+.Sx \&so
+requests with safe relative paths.
+.It
+There is no automatic hyphenation, no adjustment to the right margin,
+and no centering; the output is always set flush-left.
+.It
+Support for setting tabulator positions
+and tabulator and leader characters is missing,
+and support for manually changing indentation is limited.
+.It
The
.Sq u
scaling unit is the default terminal unit.
-In traditional troff systems, this unit would change depending on the
+In traditional troff systems, this unit changes depending on the
output media.
.It
-In mandoc, the
-.Sx \&EQ ,
-.Sx \&TE ,
-.Sx \&TS ,
-and
-.Sx \&T& ,
-macros are considered regular macros.
-In all other
-.Nm
-implementations, these are special macros that must be specified without
-spacing between the control character (which must be a period) and the
-macro name.
+Width measurements are implemented in a crude way
+and often yield wrong results.
+Explicit movement requests and escapes are ignored.
.It
-The
-.Cm nS
-register is only compatible with OpenBSD's groff-1.15.
+There is no concept of output pages, no support for floats,
+graphics drawing, and picture inclusion;
+terminal output is always continuous.
.It
-Historic groff did not accept white-space before a custom
-.Ar end
-macro for the
-.Sx \&ig
-request.
+Requests regarding color, font families, and glyph manipulation
+are ignored.
+Font support is very limited.
+Kerning is not implemented, and no ligatures are produced.
.It
The
-.Sx \&if
-and family would print funny white-spaces with historic groff when
-using the next-line syntax.
+.Qq \(aq
+macro control character does not suppress output line breaks.
+.It
+Diversions are not implemented,
+and support for traps is very incomplete.
+.It
+While recursion is supported,
+.Sx \&while
+loops are not.
.El
+.Pp
+The special semantics of the
+.Cm nS
+number register is an idiosyncracy of
+.Ox
+manuals and not supported by other
+.Xr mdoc 7
+implementations.
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr eqn 7 ,
diff --git a/roff.c b/roff.c
index f44f01f1b033..5f894e89e251 100644
--- a/roff.c
+++ b/roff.c
@@ -1,7 +1,7 @@
-/* $Id: roff.c,v 1.239 2014/11/19 01:20:25 schwarze Exp $ */
+/* $Id: roff.c,v 1.263 2015/02/21 14:46:58 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,6 +21,7 @@
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -37,43 +38,247 @@
#define EXPAND_LIMIT 1000
enum rofft {
+ ROFF_ab,
ROFF_ad,
+ ROFF_af,
+ ROFF_aln,
+ ROFF_als,
ROFF_am,
- ROFF_ami,
ROFF_am1,
+ ROFF_ami,
+ ROFF_ami1,
ROFF_as,
+ ROFF_as1,
+ ROFF_asciify,
+ ROFF_backtrace,
+ ROFF_bd,
+ ROFF_bleedat,
+ ROFF_blm,
+ ROFF_box,
+ ROFF_boxa,
+ ROFF_bp,
+ ROFF_BP,
+ /* MAN_br, MDOC_br */
+ ROFF_break,
+ ROFF_breakchar,
+ ROFF_brnl,
+ ROFF_brp,
+ ROFF_brpnl,
+ ROFF_c2,
ROFF_cc,
ROFF_ce,
+ ROFF_cf,
+ ROFF_cflags,
+ ROFF_ch,
+ ROFF_char,
+ ROFF_chop,
+ ROFF_class,
+ ROFF_close,
+ ROFF_CL,
+ ROFF_color,
+ ROFF_composite,
+ ROFF_continue,
+ ROFF_cp,
+ ROFF_cropat,
+ ROFF_cs,
+ ROFF_cu,
+ ROFF_da,
+ ROFF_dch,
+ ROFF_Dd,
ROFF_de,
- ROFF_dei,
ROFF_de1,
+ ROFF_defcolor,
+ ROFF_dei,
+ ROFF_dei1,
+ ROFF_device,
+ ROFF_devicem,
+ ROFF_di,
+ ROFF_do,
ROFF_ds,
+ ROFF_ds1,
+ ROFF_dwh,
+ ROFF_dt,
+ ROFF_ec,
+ ROFF_ecr,
+ ROFF_ecs,
ROFF_el,
+ ROFF_em,
+ ROFF_EN,
+ ROFF_eo,
+ ROFF_EP,
+ ROFF_EQ,
+ ROFF_errprint,
+ ROFF_ev,
+ ROFF_evc,
+ ROFF_ex,
+ ROFF_fallback,
ROFF_fam,
+ ROFF_fc,
+ ROFF_fchar,
+ ROFF_fcolor,
+ ROFF_fdeferlig,
+ ROFF_feature,
+ /* MAN_fi; ignored in mdoc(7) */
+ ROFF_fkern,
+ ROFF_fl,
+ ROFF_flig,
+ ROFF_fp,
+ ROFF_fps,
+ ROFF_fschar,
+ ROFF_fspacewidth,
+ ROFF_fspecial,
+ /* MAN_ft; ignored in mdoc(7) */
+ ROFF_ftr,
+ ROFF_fzoom,
+ ROFF_gcolor,
+ ROFF_hc,
+ ROFF_hcode,
+ ROFF_hidechar,
+ ROFF_hla,
+ ROFF_hlm,
+ ROFF_hpf,
+ ROFF_hpfa,
+ ROFF_hpfcode,
ROFF_hw,
ROFF_hy,
+ ROFF_hylang,
+ ROFF_hylen,
+ ROFF_hym,
+ ROFF_hypp,
+ ROFF_hys,
ROFF_ie,
ROFF_if,
ROFF_ig,
+ /* MAN_in; ignored in mdoc(7) */
+ ROFF_index,
ROFF_it,
+ ROFF_itc,
+ ROFF_IX,
+ ROFF_kern,
+ ROFF_kernafter,
+ ROFF_kernbefore,
+ ROFF_kernpair,
+ ROFF_lc,
+ ROFF_lc_ctype,
+ ROFF_lds,
+ ROFF_length,
+ ROFF_letadj,
+ ROFF_lf,
+ ROFF_lg,
+ ROFF_lhang,
+ ROFF_linetabs,
+ /* MAN_ll, MDOC_ll */
+ ROFF_lnr,
+ ROFF_lnrf,
+ ROFF_lpfx,
+ ROFF_ls,
+ ROFF_lsm,
+ ROFF_lt,
+ ROFF_mc,
+ ROFF_mediasize,
+ ROFF_minss,
+ ROFF_mk,
+ ROFF_mso,
+ ROFF_na,
ROFF_ne,
+ /* MAN_nf; ignored in mdoc(7) */
ROFF_nh,
+ ROFF_nhychar,
+ ROFF_nm,
+ ROFF_nn,
+ ROFF_nop,
ROFF_nr,
+ ROFF_nrf,
+ ROFF_nroff,
ROFF_ns,
+ ROFF_nx,
+ ROFF_open,
+ ROFF_opena,
+ ROFF_os,
+ ROFF_output,
+ ROFF_padj,
+ ROFF_papersize,
+ ROFF_pc,
+ ROFF_pev,
+ ROFF_pi,
+ ROFF_PI,
ROFF_pl,
+ ROFF_pm,
+ ROFF_pn,
+ ROFF_pnr,
+ ROFF_po,
ROFF_ps,
+ ROFF_psbb,
+ ROFF_pshape,
+ ROFF_pso,
+ ROFF_ptr,
+ ROFF_pvs,
+ ROFF_rchar,
+ ROFF_rd,
+ ROFF_recursionlimit,
+ ROFF_return,
+ ROFF_rfschar,
+ ROFF_rhang,
+ ROFF_rj,
ROFF_rm,
+ ROFF_rn,
+ ROFF_rnn,
ROFF_rr,
+ ROFF_rs,
+ ROFF_rt,
+ ROFF_schar,
+ ROFF_sentchar,
+ ROFF_shc,
+ ROFF_shift,
+ ROFF_sizes,
ROFF_so,
+ /* MAN_sp, MDOC_sp */
+ ROFF_spacewidth,
+ ROFF_special,
+ ROFF_spreadwarn,
+ ROFF_ss,
+ ROFF_sty,
+ ROFF_substring,
+ ROFF_sv,
+ ROFF_sy,
+ ROFF_T_,
ROFF_ta,
- ROFF_tr,
- ROFF_Dd,
+ ROFF_tc,
+ ROFF_TE,
ROFF_TH,
+ ROFF_ti,
+ ROFF_tkf,
+ ROFF_tl,
+ ROFF_tm,
+ ROFF_tm1,
+ ROFF_tmc,
+ ROFF_tr,
+ ROFF_track,
+ ROFF_transchar,
+ ROFF_trf,
+ ROFF_trimat,
+ ROFF_trin,
+ ROFF_trnt,
+ ROFF_troff,
ROFF_TS,
- ROFF_TE,
- ROFF_T_,
- ROFF_EQ,
- ROFF_EN,
+ ROFF_uf,
+ ROFF_ul,
+ ROFF_unformat,
+ ROFF_unwatch,
+ ROFF_unwatchn,
+ ROFF_vpt,
+ ROFF_vs,
+ ROFF_warn,
+ ROFF_warnscale,
+ ROFF_watch,
+ ROFF_watchlength,
+ ROFF_watchn,
+ ROFF_wh,
+ ROFF_while,
+ ROFF_write,
+ ROFF_writec,
+ ROFF_writem,
+ ROFF_xflag,
ROFF_cblock,
ROFF_USERDEF,
ROFF_MAX
@@ -177,6 +382,7 @@ static void roffnode_push(struct roff *, enum rofft,
static enum rofferr roff_block(ROFF_ARGS);
static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
+static enum rofferr roff_brp(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_cc(ROFF_ARGS);
static void roff_ccond(struct roff *, int, int);
@@ -190,19 +396,20 @@ static int roff_evalcond(struct roff *r, int,
static int roff_evalnum(struct roff *, int,
const char *, int *, int *, int);
static int roff_evalpar(struct roff *, int,
- const char *, int *, int *);
+ const char *, int *, int *, int);
static int roff_evalstrcond(const char *, int *);
static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
static size_t roff_getname(struct roff *, char **, int, int);
-static int roff_getnum(const char *, int *, int *);
+static int roff_getnum(const char *, int *, int *, int);
static int roff_getop(const char *, int *, char *);
static int roff_getregn(const struct roff *,
const char *, size_t);
static int roff_getregro(const char *name);
static const char *roff_getstrn(const struct roff *,
const char *, size_t);
+static enum rofferr roff_insec(ROFF_ARGS);
static enum rofferr roff_it(ROFF_ARGS);
static enum rofferr roff_line_ignore(ROFF_ARGS);
static enum rofferr roff_nr(ROFF_ARGS);
@@ -211,6 +418,7 @@ static enum rofft roff_parse(struct roff *, char *, int *,
static enum rofferr roff_parsetext(struct buf *, int, int *);
static enum rofferr roff_res(struct roff *, struct buf *, int, int);
static enum rofferr roff_rm(ROFF_ARGS);
+static enum rofferr roff_rn(ROFF_ARGS);
static enum rofferr roff_rr(ROFF_ARGS);
static void roff_setstr(struct roff *,
const char *, const char *, int);
@@ -225,6 +433,7 @@ static enum rofferr roff_TS(ROFF_ARGS);
static enum rofferr roff_EQ(ROFF_ARGS);
static enum rofferr roff_EN(ROFF_ARGS);
static enum rofferr roff_T_(ROFF_ARGS);
+static enum rofferr roff_unsupp(ROFF_ARGS);
static enum rofferr roff_userdef(ROFF_ARGS);
/* See roffhash_find() */
@@ -233,46 +442,246 @@ static enum rofferr roff_userdef(ROFF_ARGS);
#define ASCII_LO 33
#define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
+#define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */
+#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */
+
static struct roffmac *hash[HASHWIDTH];
static struct roffmac roffs[ROFF_MAX] = {
+ { "ab", roff_unsupp, NULL, NULL, 0, NULL },
{ "ad", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "af", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "aln", roff_unsupp, NULL, NULL, 0, NULL },
+ { "als", roff_unsupp, NULL, NULL, 0, NULL },
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
- { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "ami1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "as", roff_ds, NULL, NULL, 0, NULL },
+ { "as1", roff_ds, NULL, NULL, 0, NULL },
+ { "asciify", roff_unsupp, NULL, NULL, 0, NULL },
+ { "backtrace", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "bd", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "bleedat", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "blm", roff_unsupp, NULL, NULL, 0, NULL },
+ { "box", roff_unsupp, NULL, NULL, 0, NULL },
+ { "boxa", roff_unsupp, NULL, NULL, 0, NULL },
+ { "bp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "BP", roff_unsupp, NULL, NULL, 0, NULL },
+ { "break", roff_unsupp, NULL, NULL, 0, NULL },
+ { "breakchar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "brnl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "brp", roff_brp, NULL, NULL, 0, NULL },
+ { "brpnl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "c2", roff_unsupp, NULL, NULL, 0, NULL },
{ "cc", roff_cc, NULL, NULL, 0, NULL },
{ "ce", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cf", roff_insec, NULL, NULL, 0, NULL },
+ { "cflags", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ch", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "char", roff_unsupp, NULL, NULL, 0, NULL },
+ { "chop", roff_unsupp, NULL, NULL, 0, NULL },
+ { "class", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "close", roff_insec, NULL, NULL, 0, NULL },
+ { "CL", roff_unsupp, NULL, NULL, 0, NULL },
+ { "color", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "composite", roff_unsupp, NULL, NULL, 0, NULL },
+ { "continue", roff_unsupp, NULL, NULL, 0, NULL },
+ { "cp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cropat", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cu", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "da", roff_unsupp, NULL, NULL, 0, NULL },
+ { "dch", roff_unsupp, NULL, NULL, 0, NULL },
+ { "Dd", roff_Dd, NULL, NULL, 0, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
- { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "defcolor", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "dei1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "device", roff_unsupp, NULL, NULL, 0, NULL },
+ { "devicem", roff_unsupp, NULL, NULL, 0, NULL },
+ { "di", roff_unsupp, NULL, NULL, 0, NULL },
+ { "do", roff_unsupp, NULL, NULL, 0, NULL },
{ "ds", roff_ds, NULL, NULL, 0, NULL },
+ { "ds1", roff_ds, NULL, NULL, 0, NULL },
+ { "dwh", roff_unsupp, NULL, NULL, 0, NULL },
+ { "dt", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ec", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ecr", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ecs", roff_unsupp, NULL, NULL, 0, NULL },
{ "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+ { "em", roff_unsupp, NULL, NULL, 0, NULL },
+ { "EN", roff_EN, NULL, NULL, 0, NULL },
+ { "eo", roff_unsupp, NULL, NULL, 0, NULL },
+ { "EP", roff_unsupp, NULL, NULL, 0, NULL },
+ { "EQ", roff_EQ, NULL, NULL, 0, NULL },
+ { "errprint", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ev", roff_unsupp, NULL, NULL, 0, NULL },
+ { "evc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ex", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fallback", roff_line_ignore, NULL, NULL, 0, NULL },
{ "fam", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fchar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fcolor", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fdeferlig", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "feature", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fkern", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "flig", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fps", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fschar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fspacewidth", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fspecial", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ftr", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fzoom", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "gcolor", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hcode", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hidechar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hla", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hlm", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hpf", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hpfa", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hpfcode", roff_line_ignore, NULL, NULL, 0, NULL },
{ "hw", roff_line_ignore, NULL, NULL, 0, NULL },
{ "hy", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hylang", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hylen", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hym", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hypp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hys", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "index", roff_unsupp, NULL, NULL, 0, NULL },
{ "it", roff_it, NULL, NULL, 0, NULL },
+ { "itc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "IX", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kern", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kernafter", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kernbefore", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kernpair", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lc_ctype", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lds", roff_unsupp, NULL, NULL, 0, NULL },
+ { "length", roff_unsupp, NULL, NULL, 0, NULL },
+ { "letadj", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lf", roff_insec, NULL, NULL, 0, NULL },
+ { "lg", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lhang", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "linetabs", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lnr", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lnrf", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lpfx", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ls", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lsm", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lt", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mediasize", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "minss", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mk", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mso", roff_insec, NULL, NULL, 0, NULL },
+ { "na", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ne", roff_line_ignore, NULL, NULL, 0, NULL },
{ "nh", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "nhychar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "nm", roff_unsupp, NULL, NULL, 0, NULL },
+ { "nn", roff_unsupp, NULL, NULL, 0, NULL },
+ { "nop", roff_unsupp, NULL, NULL, 0, NULL },
{ "nr", roff_nr, NULL, NULL, 0, NULL },
+ { "nrf", roff_unsupp, NULL, NULL, 0, NULL },
+ { "nroff", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ns", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "nx", roff_insec, NULL, NULL, 0, NULL },
+ { "open", roff_insec, NULL, NULL, 0, NULL },
+ { "opena", roff_insec, NULL, NULL, 0, NULL },
+ { "os", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "output", roff_unsupp, NULL, NULL, 0, NULL },
+ { "padj", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "papersize", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pev", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pi", roff_insec, NULL, NULL, 0, NULL },
+ { "PI", roff_unsupp, NULL, NULL, 0, NULL },
{ "pl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pm", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pnr", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "po", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ps", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "psbb", roff_unsupp, NULL, NULL, 0, NULL },
+ { "pshape", roff_unsupp, NULL, NULL, 0, NULL },
+ { "pso", roff_insec, NULL, NULL, 0, NULL },
+ { "ptr", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pvs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "rchar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rd", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "recursionlimit", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "return", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rfschar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rhang", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "rj", roff_line_ignore, NULL, NULL, 0, NULL },
{ "rm", roff_rm, NULL, NULL, 0, NULL },
+ { "rn", roff_rn, NULL, NULL, 0, NULL },
+ { "rnn", roff_unsupp, NULL, NULL, 0, NULL },
{ "rr", roff_rr, NULL, NULL, 0, NULL },
+ { "rs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "rt", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "schar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "sentchar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "shc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "shift", roff_unsupp, NULL, NULL, 0, NULL },
+ { "sizes", roff_line_ignore, NULL, NULL, 0, NULL },
{ "so", roff_so, NULL, NULL, 0, NULL },
- { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
- { "tr", roff_tr, NULL, NULL, 0, NULL },
- { "Dd", roff_Dd, NULL, NULL, 0, NULL },
+ { "spacewidth", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "special", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "spreadwarn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ss", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "sty", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "substring", roff_unsupp, NULL, NULL, 0, NULL },
+ { "sv", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "sy", roff_insec, NULL, NULL, 0, NULL },
+ { "T&", roff_T_, NULL, NULL, 0, NULL },
+ { "ta", roff_unsupp, NULL, NULL, 0, NULL },
+ { "tc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "TE", roff_TE, NULL, NULL, 0, NULL },
{ "TH", roff_TH, NULL, NULL, 0, NULL },
+ { "ti", roff_unsupp, NULL, NULL, 0, NULL },
+ { "tkf", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tl", roff_unsupp, NULL, NULL, 0, NULL },
+ { "tm", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tm1", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tmc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tr", roff_tr, NULL, NULL, 0, NULL },
+ { "track", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "transchar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "trf", roff_insec, NULL, NULL, 0, NULL },
+ { "trimat", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "trin", roff_unsupp, NULL, NULL, 0, NULL },
+ { "trnt", roff_unsupp, NULL, NULL, 0, NULL },
+ { "troff", roff_line_ignore, NULL, NULL, 0, NULL },
{ "TS", roff_TS, NULL, NULL, 0, NULL },
- { "TE", roff_TE, NULL, NULL, 0, NULL },
- { "T&", roff_T_, NULL, NULL, 0, NULL },
- { "EQ", roff_EQ, NULL, NULL, 0, NULL },
- { "EN", roff_EN, NULL, NULL, 0, NULL },
+ { "uf", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ul", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "unformat", roff_unsupp, NULL, NULL, 0, NULL },
+ { "unwatch", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "unwatchn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "vpt", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "vs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "warn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "warnscale", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "watch", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "watchlength", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "watchn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "wh", roff_unsupp, NULL, NULL, 0, NULL },
+ { "while", roff_unsupp, NULL, NULL, 0, NULL },
+ { "write", roff_insec, NULL, NULL, 0, NULL },
+ { "writec", roff_insec, NULL, NULL, 0, NULL },
+ { "writem", roff_insec, NULL, NULL, 0, NULL },
+ { "xflag", roff_line_ignore, NULL, NULL, 0, NULL },
{ ".", roff_cblock, NULL, NULL, 0, NULL },
{ NULL, roff_userdef, NULL, NULL, 0, NULL },
};
@@ -600,8 +1009,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
/* Advance to the end of the name. */
+ naml = 0;
arg_complete = 1;
- for (naml = 0; maxl == 0 || naml < maxl; naml++, cp++) {
+ while (maxl == 0 || naml < maxl) {
if (*cp == '\0') {
mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
ln, (int)(stesc - buf->buf), stesc);
@@ -612,6 +1022,23 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
cp++;
break;
}
+ if (*cp++ != '\\' || stesc[1] != 'w') {
+ naml++;
+ continue;
+ }
+ switch (mandoc_escape(&cp, NULL, NULL)) {
+ case ESCAPE_SPECIAL:
+ /* FALLTHROUGH */
+ case ESCAPE_UNICODE:
+ /* FALLTHROUGH */
+ case ESCAPE_NUMBERED:
+ /* FALLTHROUGH */
+ case ESCAPE_OVERSTRIKE:
+ naml++;
+ break;
+ default:
+ break;
+ }
}
/*
@@ -627,7 +1054,8 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
case 'B':
npos = 0;
ubuf[0] = arg_complete &&
- roff_evalnum(r, ln, stnam, &npos, NULL, 0) &&
+ roff_evalnum(r, ln, stnam, &npos,
+ NULL, ROFFNUM_SCALE) &&
stnam + npos + 1 == cp ? '1' : '0';
ubuf[1] = '\0';
break;
@@ -650,6 +1078,10 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
r->parse, ln, (int)(stesc - buf->buf),
"%.*s", (int)naml, stnam);
res = "";
+ } else if (buf->sz + strlen(res) > SHRT_MAX) {
+ mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+ ln, (int)(stesc - buf->buf), NULL);
+ return(ROFF_IGN);
}
/* Replace the escape sequence by the string. */
@@ -730,6 +1162,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
enum rofft t;
enum rofferr e;
int pos; /* parse point */
+ int spos; /* saved parse point for messages */
int ppos; /* original offset in buf->buf */
int ctl; /* macro line (boolean) */
@@ -757,13 +1190,13 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
/*
* First, if a scope is open and we're not a macro, pass the
- * text through the macro's filter. If a scope isn't open and
- * we're not a macro, just let it through.
- * Finally, if there's an equation scope open, divert it into it
- * no matter our state.
+ * text through the macro's filter.
+ * Equations process all content themselves.
+ * Tables process almost all content themselves, but we want
+ * to warn about macros before passing it there.
*/
- if (r->last && ! ctl) {
+ if (r->last != NULL && ! ctl) {
t = r->last->tok;
assert(roffs[t].text);
e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
@@ -771,13 +1204,12 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
if (e != ROFF_CONT)
return(e);
}
- if (r->eqn)
+ if (r->eqn != NULL)
return(eqn_read(&r->eqn, ln, buf->buf, ppos, offs));
- if ( ! ctl) {
- if (r->tbl)
- return(tbl_read(r->tbl, ln, buf->buf, pos));
+ if (r->tbl != NULL && ( ! ctl || buf->buf[pos] == '\0'))
+ return(tbl_read(r->tbl, ln, buf->buf, ppos));
+ if ( ! ctl)
return(roff_parsetext(buf, pos, offs));
- }
/* Skip empty request lines. */
@@ -800,15 +1232,35 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
return((*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs));
}
+ /* No scope is open. This is a new request or macro. */
+
+ spos = pos;
+ t = roff_parse(r, buf->buf, &pos, ln, ppos);
+
+ /* Tables ignore most macros. */
+
+ if (r->tbl != NULL && (t == ROFF_MAX || t == ROFF_TS)) {
+ mandoc_msg(MANDOCERR_TBLMACRO, r->parse,
+ ln, pos, buf->buf + spos);
+ if (t == ROFF_TS)
+ return(ROFF_IGN);
+ while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
+ pos++;
+ while (buf->buf[pos] != '\0' && buf->buf[pos] == ' ')
+ pos++;
+ return(tbl_read(r->tbl, ln, buf->buf, pos));
+ }
+
/*
- * Lastly, as we've no scope open, try to look up and execute
- * the new macro. If no macro is found, simply return and let
- * the compilers handle it.
+ * This is neither a roff request nor a user-defined macro.
+ * Let the standard macro set parsers handle it.
*/
- if ((t = roff_parse(r, buf->buf, &pos, ln, ppos)) == ROFF_MAX)
+ if (t == ROFF_MAX)
return(ROFF_CONT);
+ /* Execute a roff request or a user defined macro. */
+
assert(roffs[t].proc);
return((*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs));
}
@@ -964,8 +1416,12 @@ roff_block(ROFF_ARGS)
if (tok == ROFF_de1)
tok = ROFF_de;
+ else if (tok == ROFF_dei1)
+ tok = ROFF_dei;
else if (tok == ROFF_am1)
tok = ROFF_am;
+ else if (tok == ROFF_ami1)
+ tok = ROFF_ami;
/* Parse the macro name argument. */
@@ -1143,7 +1599,8 @@ roff_cond_sub(ROFF_ARGS)
*ep = '&';
roff_ccond(r, ln, ep - buf->buf - 1);
}
- ++ep;
+ if (*ep != '\0')
+ ++ep;
}
return(rr ? ROFF_CONT : ROFF_IGN);
}
@@ -1163,7 +1620,8 @@ roff_cond_text(ROFF_ARGS)
*ep = '&';
roff_ccond(r, ln, ep - buf->buf - 1);
}
- ++ep;
+ if (*ep != '\0')
+ ++ep;
}
return(rr ? ROFF_CONT : ROFF_IGN);
}
@@ -1175,18 +1633,22 @@ roff_cond_text(ROFF_ARGS)
* Ignore overflows, treat them just like the C language.
*/
static int
-roff_getnum(const char *v, int *pos, int *res)
+roff_getnum(const char *v, int *pos, int *res, int flags)
{
- int myres, n, p;
+ int myres, scaled, n, p;
if (NULL == res)
res = &myres;
p = *pos;
n = v[p] == '-';
- if (n)
+ if (n || v[p] == '+')
p++;
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[p]))
+ p++;
+
for (*res = 0; isdigit((unsigned char)v[p]); p++)
*res = 10 * *res + v[p] - '0';
if (p == *pos + n)
@@ -1195,8 +1657,47 @@ roff_getnum(const char *v, int *pos, int *res)
if (n)
*res = -*res;
- *pos = p;
- return 1;
+ /* Each number may be followed by one optional scaling unit. */
+
+ switch (v[p]) {
+ case 'f':
+ scaled = *res * 65536;
+ break;
+ case 'i':
+ scaled = *res * 240;
+ break;
+ case 'c':
+ scaled = *res * 240 / 2.54;
+ break;
+ case 'v':
+ /* FALLTROUGH */
+ case 'P':
+ scaled = *res * 40;
+ break;
+ case 'm':
+ /* FALLTROUGH */
+ case 'n':
+ scaled = *res * 24;
+ break;
+ case 'p':
+ scaled = *res * 10 / 3;
+ break;
+ case 'u':
+ scaled = *res;
+ break;
+ case 'M':
+ scaled = *res * 6 / 25;
+ break;
+ default:
+ scaled = *res;
+ p--;
+ break;
+ }
+ if (flags & ROFFNUM_SCALE)
+ *res = scaled;
+
+ *pos = p + 1;
+ return(1);
}
/*
@@ -1236,7 +1737,7 @@ roff_evalstrcond(const char *v, int *pos)
out:
if (NULL == s3)
s3 = strchr(s2, '\0');
- else
+ else if (*s3 != '\0')
s3++;
*pos = s3 - v;
return(match);
@@ -1249,7 +1750,7 @@ out:
static int
roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
{
- int wanttrue, number;
+ int number, savepos, wanttrue;
if ('!' == v[*pos]) {
wanttrue = 0;
@@ -1258,6 +1759,8 @@ roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
wanttrue = 1;
switch (v[*pos]) {
+ case '\0':
+ return(0);
case 'n':
/* FALLTHROUGH */
case 'o':
@@ -1280,10 +1783,13 @@ roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
break;
}
- if (roff_evalnum(r, ln, v, pos, &number, 0))
+ savepos = *pos;
+ if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
return((number > 0) == wanttrue);
- else
+ else if (*pos == savepos)
return(roff_evalstrcond(v, pos) == wanttrue);
+ else
+ return (0);
}
static enum rofferr
@@ -1294,6 +1800,24 @@ roff_line_ignore(ROFF_ARGS)
}
static enum rofferr
+roff_insec(ROFF_ARGS)
+{
+
+ mandoc_msg(MANDOCERR_REQ_INSEC, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
+}
+
+static enum rofferr
+roff_unsupp(ROFF_ARGS)
+{
+
+ mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
+}
+
+static enum rofferr
roff_cond(ROFF_ARGS)
{
@@ -1376,6 +1900,13 @@ roff_ds(ROFF_ARGS)
const char *name;
size_t namesz;
+ /* Ignore groff compatibility mode for now. */
+
+ if (tok == ROFF_ds1)
+ tok = ROFF_ds;
+ else if (tok == ROFF_as1)
+ tok = ROFF_as;
+
/*
* The first word is the name of the string.
* If it is empty or terminated by an escape sequence,
@@ -1476,14 +2007,14 @@ roff_getop(const char *v, int *pos, char *res)
*/
static int
roff_evalpar(struct roff *r, int ln,
- const char *v, int *pos, int *res)
+ const char *v, int *pos, int *res, int flags)
{
if ('(' != v[*pos])
- return(roff_getnum(v, pos, res));
+ return(roff_getnum(v, pos, res, flags));
(*pos)++;
- if ( ! roff_evalnum(r, ln, v, pos, res, 1))
+ if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
return(0);
/*
@@ -1506,7 +2037,7 @@ roff_evalpar(struct roff *r, int ln,
*/
static int
roff_evalnum(struct roff *r, int ln, const char *v,
- int *pos, int *res, int skipwhite)
+ int *pos, int *res, int flags)
{
int mypos, operand2;
char operator;
@@ -1516,29 +2047,29 @@ roff_evalnum(struct roff *r, int ln, const char *v,
pos = &mypos;
}
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
- if ( ! roff_evalpar(r, ln, v, pos, res))
+ if ( ! roff_evalpar(r, ln, v, pos, res, flags))
return(0);
while (1) {
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
if ( ! roff_getop(v, pos, &operator))
break;
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
- if ( ! roff_evalpar(r, ln, v, pos, &operand2))
+ if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
return(0);
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
@@ -1556,7 +2087,7 @@ roff_evalnum(struct roff *r, int ln, const char *v,
*res *= operand2;
break;
case '/':
- if (0 == operand2) {
+ if (operand2 == 0) {
mandoc_msg(MANDOCERR_DIVZERO,
r->parse, ln, *pos, v);
*res = 0;
@@ -1565,6 +2096,12 @@ roff_evalnum(struct roff *r, int ln, const char *v,
*res /= operand2;
break;
case '%':
+ if (operand2 == 0) {
+ mandoc_msg(MANDOCERR_DIVZERO,
+ r->parse, ln, *pos, v);
+ *res = 0;
+ break;
+ }
*res %= operand2;
break;
case '<':
@@ -1736,7 +2273,7 @@ roff_nr(ROFF_ARGS)
if (sign == '+' || sign == '-')
val++;
- if (roff_evalnum(r, ln, val, NULL, &iv, 0))
+ if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
roff_setreg(r, key, iv, sign);
return(ROFF_IGN);
@@ -1789,26 +2326,60 @@ roff_rm(ROFF_ARGS)
}
static enum rofferr
+roff_rn(ROFF_ARGS)
+{
+ struct roffkv *n;
+ char *newname;
+ const char *name;
+ size_t namesz;
+
+ name = newname = buf->buf + pos;
+ if (*name == '\0')
+ return(ROFF_IGN);
+
+ namesz = roff_getname(r, &newname, ln, pos);
+ if (name[namesz] == '\\')
+ return(ROFF_IGN);
+
+
+ for (n = r->strtab; n; n = n->next)
+ if (0 == strncmp(name, n->key.p, namesz) &&
+ '\0' == n->key.p[(int)namesz]) {
+ free(n->key.p);
+ fprintf(stderr, "From %s to %s\n", n->key.p, newname);
+ n->key.p = mandoc_strdup(newname);
+ n->key.sz = strlen(n->key.p);
+ }
+
+ return(ROFF_IGN);
+}
+
+static enum rofferr
roff_it(ROFF_ARGS)
{
- char *cp;
- size_t len;
int iv;
/* Parse the number of lines. */
- cp = buf->buf + pos;
- len = strcspn(cp, " \t");
- cp[len] = '\0';
- if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
+
+ if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
ln, ppos, buf->buf + 1);
return(ROFF_IGN);
}
- cp += len + 1;
- /* Arm the input line trap. */
+ while (isspace((unsigned char)buf->buf[pos]))
+ pos++;
+
+ /*
+ * Arm the input line trap.
+ * Special-casing "an-trap" is an ugly workaround to cope
+ * with DocBook stupidly fiddling with man(7) internals.
+ */
+
roffit_lines = iv;
- roffit_macro = mandoc_strdup(cp);
+ roffit_macro = mandoc_strdup(iv != 1 ||
+ strcmp(buf->buf + pos, "an-trap") ?
+ buf->buf + pos : "br");
return(ROFF_IGN);
}
@@ -1849,9 +2420,12 @@ roff_TE(ROFF_ARGS)
if (NULL == r->tbl)
mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
ln, ppos, "TE");
- else
- tbl_end(&r->tbl);
-
+ else if ( ! tbl_end(&r->tbl)) {
+ free(buf->buf);
+ buf->buf = mandoc_strdup(".sp");
+ buf->sz = 4;
+ return(ROFF_REPARSE);
+ }
return(ROFF_IGN);
}
@@ -1990,6 +2564,14 @@ roff_TS(ROFF_ARGS)
}
static enum rofferr
+roff_brp(ROFF_ARGS)
+{
+
+ buf->buf[pos - 1] = '\0';
+ return(ROFF_CONT);
+}
+
+static enum rofferr
roff_cc(ROFF_ARGS)
{
const char *p;
@@ -2000,7 +2582,8 @@ roff_cc(ROFF_ARGS)
r->control = 0;
if (*p != '\0')
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ ln, p - buf->buf, "cc ... %s", p);
return(ROFF_IGN);
}
@@ -2015,7 +2598,7 @@ roff_tr(ROFF_ARGS)
p = buf->buf + pos;
if (*p == '\0') {
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr");
return(ROFF_IGN);
}
@@ -2043,8 +2626,8 @@ roff_tr(ROFF_ARGS)
}
ssz = (size_t)(p - second);
} else if (*second == '\0') {
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
- ln, (int)(p - buf->buf), NULL);
+ mandoc_vmsg(MANDOCERR_TR_ODD, r->parse,
+ ln, first - buf->buf, "tr %s", first);
second = " ";
p--;
}
@@ -2070,7 +2653,7 @@ roff_tr(ROFF_ARGS)
static enum rofferr
roff_so(ROFF_ARGS)
{
- char *name;
+ char *name, *cp;
name = buf->buf + pos;
mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
@@ -2085,7 +2668,12 @@ roff_so(ROFF_ARGS)
if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
".so %s", name);
- return(ROFF_ERR);
+ buf->sz = mandoc_asprintf(&cp,
+ ".sp\nSee the file %s.\n.sp", name) + 1;
+ free(buf->buf);
+ buf->buf = cp;
+ *offs = 0;
+ return(ROFF_REPARSE);
}
*offs = pos;
@@ -2095,14 +2683,16 @@ roff_so(ROFF_ARGS)
static enum rofferr
roff_userdef(ROFF_ARGS)
{
- const char *arg[9];
+ const char *arg[9], *ap;
char *cp, *n1, *n2;
int i;
+ size_t asz, rsz;
/*
* Collect pointers to macro argument strings
* and NUL-terminate them.
*/
+
cp = buf->buf + pos;
for (i = 0; i < 9; i++)
arg[i] = *cp == '\0' ? "" :
@@ -2111,31 +2701,90 @@ roff_userdef(ROFF_ARGS)
/*
* Expand macro arguments.
*/
- buf->sz = 0;
- n1 = cp = mandoc_strdup(r->current_string);
- while ((cp = strstr(cp, "\\$")) != NULL) {
- i = cp[2] - '1';
- if (0 > i || 8 < i) {
- /* Not an argument invocation. */
- cp += 2;
+
+ buf->sz = strlen(r->current_string) + 1;
+ n1 = cp = mandoc_malloc(buf->sz);
+ memcpy(n1, r->current_string, buf->sz);
+ while (*cp != '\0') {
+
+ /* Scan ahead for the next argument invocation. */
+
+ if (*cp++ != '\\')
+ continue;
+ if (*cp++ != '$')
continue;
+ i = *cp - '1';
+ if (0 > i || 8 < i)
+ continue;
+ cp -= 2;
+
+ /*
+ * Determine the size of the expanded argument,
+ * taking escaping of quotes into account.
+ */
+
+ asz = 0;
+ for (ap = arg[i]; *ap != '\0'; ap++) {
+ asz++;
+ if (*ap == '"')
+ asz += 3;
+ }
+ if (asz != 3) {
+
+ /*
+ * Determine the size of the rest of the
+ * unexpanded macro, including the NUL.
+ */
+
+ rsz = buf->sz - (cp - n1) - 3;
+
+ /*
+ * When shrinking, move before
+ * releasing the storage.
+ */
+
+ if (asz < 3)
+ memmove(cp + asz, cp + 3, rsz);
+
+ /*
+ * Resize the storage for the macro
+ * and readjust the parse pointer.
+ */
+
+ buf->sz += asz - 3;
+ n2 = mandoc_realloc(n1, buf->sz);
+ cp = n2 + (cp - n1);
+ n1 = n2;
+
+ /*
+ * When growing, make room
+ * for the expanded argument.
+ */
+
+ if (asz > 3)
+ memmove(cp + asz, cp + 3, rsz);
+ }
+
+ /* Copy the expanded argument, escaping quotes. */
+
+ n2 = cp;
+ for (ap = arg[i]; *ap != '\0'; ap++) {
+ if (*ap == '"') {
+ memcpy(n2, "\\(dq", 4);
+ n2 += 4;
+ } else
+ *n2++ = *ap;
}
- *cp = '\0';
- buf->sz = mandoc_asprintf(&n2, "%s%s%s",
- n1, arg[i], cp + 3) + 1;
- cp = n2 + (cp - n1);
- free(n1);
- n1 = n2;
}
/*
* Replace the macro invocation
* by the expanded macro.
*/
+
free(buf->buf);
buf->buf = n1;
- if (buf->sz == 0)
- buf->sz = strlen(buf->buf) + 1;
+ *offs = 0;
return(buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
ROFF_REPARSE : ROFF_APPEND);
diff --git a/st.in b/st.in
index 5d2f129e3f42..e70680f3ab27 100644
--- a/st.in
+++ b/st.in
@@ -1,4 +1,4 @@
-/* $Id: st.in,v 1.27 2014/11/30 21:56:18 schwarze Exp $ */
+/* $Id: st.in,v 1.28 2015/02/17 20:37:17 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -28,50 +28,50 @@
* REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
*/
-LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
-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)")
-LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
-LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
-LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
-LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
-LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
-LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
-LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
-LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
-LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
-LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
-LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
-LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
-LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
-LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
-LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
-LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
-LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
-LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
+LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(LqPOSIX.1\\(Rq)")
+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)")
+LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(LqPOSIX.1c\\(Rq)")
+LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(LqPOSIX.1g\\(Rq)")
+LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(LqPOSIX.1i\\(Rq)")
+LINE("-p1003.2", "IEEE Std 1003.2 (\\(LqPOSIX.2\\(Rq)")
+LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(LqPOSIX.2\\(Rq)")
+LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(LqPOSIX.2\\(Rq)")
+LINE("-isoC", "ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
+LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
+LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(LqISO\\~C90, Amendment 1\\(Rq)")
+LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(LqISO\\~C90, Technical Corrigendum 1\\(Rq)")
+LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(LqISO\\~C90, Technical Corrigendum 2\\(Rq)")
+LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(LqISO\\~C99\\(Rq)")
+LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(LqISO\\~C11\\(Rq)")
+LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(LqPOSIX.1\\(Rq)")
+LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
+LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(LqPOSIX.2\\(Rq)")
+LINE("-ansiC", "ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
+LINE("-ansiC-89", "ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
LINE("-ieee754", "IEEE Std 754-1985")
LINE("-iso8802-3", "ISO 8802-3: 1989")
LINE("-iso8601", "ISO 8601")
-LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
-LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
-LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
-LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
-LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
-LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
-LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
-LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
-LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
-LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
-LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
-LINE("-susv1", "Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
-LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
-LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
-LINE("-susv4", "Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
-LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
+LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(LqOpen Firmware\\(Rq)")
+LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(LqXPG3\\(Rq)")
+LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(LqXPG4\\(Rq)")
+LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(LqXPG4.2\\(Rq)")
+LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(LqXBD5\\(Rq)")
+LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(LqXCU5\\(Rq)")
+LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(LqXSH4.2\\(Rq)")
+LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(LqXSH5\\(Rq)")
+LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(LqXNS5\\(Rq)")
+LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(LqXNS5.2\\(Rq)")
+LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(LqXCURSES4.2\\(Rq)")
+LINE("-susv1", "Version\\~1 of the Single UNIX Specification (\\(LqSUSv1\\(Rq)")
+LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(LqSUSv2\\(Rq)")
+LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(LqSUSv3\\(Rq)")
+LINE("-susv4", "Version\\~4 of the Single UNIX Specification (\\(LqSUSv4\\(Rq)")
+LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(LqSVID4\\(Rq)")
diff --git a/style.css b/style.css
index 83c5acc820da..1328f4d30b45 100644
--- a/style.css
+++ b/style.css
@@ -1,4 +1,4 @@
-/* $Id: style.css,v 1.30 2014/09/27 11:16:24 kristaps Exp $ */
+/* $Id: style.css,v 1.31 2015/02/10 08:05:30 schwarze Exp $ */
/*
* This is an example style-sheet provided for mandoc(1) and the -Thtml
@@ -51,7 +51,7 @@ small { } /* Small: SB, SM. */
i.addr { font-weight: normal; } /* Address (Ad). */
i.arg { font-weight: normal; } /* Command argument (Ar). */
span.author { } /* Author name (An). */
-b.cmd { font-style: normal; } /* Command (Cm). */
+b.cmd { font-style: normal; } /* Command (Cm). */
b.config { font-style: normal; } /* Config statement (Cd). */
span.define { } /* Defines (Dv). */
span.desc { } /* Nd. After em-dash. */
diff --git a/tbl.3 b/tbl.3
index 05e423fe548e..f3db622e33cb 100644
--- a/tbl.3
+++ b/tbl.3
@@ -1,4 +1,4 @@
-.\" $Id: tbl.3,v 1.1 2013/06/01 05:44:39 schwarze Exp $
+.\" $Id: tbl.3,v 1.2 2015/01/30 04:11:50 schwarze Exp $
.\"
.\" Copyright (c) 2013 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: June 1 2013 $
+.Dd $Mdocdate: January 30 2015 $
.Dt TBL 3
.Os
.Sh NAME
@@ -79,12 +79,37 @@ It is defined in
created in
.Fn tbl_alloc ,
and stored in the members
-.Va first_tbl ,
-.Va last_tbl ,
+.Fa first_tbl ,
+.Fa last_tbl ,
and
-.Va tbl
+.Fa tbl
of
.Vt struct roff Bq Pa roff.c .
+.Pp
+The
+.Fa first_span ,
+.Fa current_span ,
+.Fa last_span ,
+and
+.Fa next
+members may be
+.Dv NULL .
+The
+.Fa first_row
+and
+.Fa last_row
+members may be
+.Dv NULL ,
+but if there is a span, the function
+.Fn tbl_layout
+guarantees that these pointers are not
+.Dv NULL .
+The function
+.Fn tbl_alloc
+guarantees that the
+.Fa parse
+member is not
+.Dv NULL .
.It Vt struct tbl_opts
This structure describes the options of one table.
It is used as a substructure of
@@ -92,26 +117,27 @@ It is used as a substructure of
and thus created and deleted together with it.
It is filled in
.Fn tbl_options .
-.It Vt struct tbl_head
-This structure describes one layout column in a table,
-in particular the vertical line to its left.
-It is allocated and filled in
-.Fn cell_alloc Bq Pa tbl_layout.c
-and referenced from the
-.Va first_head
-and
-.Va last_head
-members of
-.Vt struct tbl_node .
.It Vt struct tbl_row
This structure describes one layout line in a table
by maintaining a list of all the cells in that line.
It is allocated and filled in
.Fn row Bq Pa tbl_layout.c
and referenced from the
-.Va layout
+.Fa layout
member of
.Vt struct tbl_node .
+.Pp
+The
+.Fa next
+member may be
+.Dv NULL .
+The function
+.Fn tbl_layout
+guarantees that the
+.Fa first
+and
+.Fa last
+members are not NULL.
.It Vt struct tbl_cell
This structure describes one layout cell in a table,
in particular its alignment, membership in spans, and
@@ -119,11 +145,16 @@ usage for lines.
It is allocated and filled in
.Fn cell_alloc Bq Pa tbl_layout.c
and referenced from the
-.Va first
+.Fa first
and
-.Va last
+.Fa last
members of
.Vt struct tbl_row .
+.Pp
+The
+.Fa next
+member may be
+.Dv NULL .
.It Vt struct tbl_span
This structure describes one data line in a table
by maintaining a list of all data cells in that line
@@ -133,14 +164,14 @@ It is allocated and filled in
which is called from
.Fn tbl_data
and referenced from the
-.Va first_span ,
-.Va current_span ,
+.Fa first_span ,
+.Fa current_span ,
and
-.Va last_span
+.Fa last_span
members of
.Vt struct tbl_node ,
and from the
-.Va span
+.Fa span
members of
.Vt struct man_node
and
@@ -149,18 +180,48 @@ from
.In man.h
and
.In mdoc.h .
+.Pp
+The
+.Fa first ,
+.Fa last ,
+.Fa prev ,
+and
+.Fa next
+members may be
+.Dv NULL .
+The function
+.Fn newspan Bq Pa tbl_data.c
+guarantees that the
+.Fa opts
+and
+.Fa layout
+members are not
+.Dv NULL .
.It Vt struct tbl_dat
This structure describes one data cell in a table by specifying
whether it contains a line or data, whether it spans additional
layout cells, and by storing the data.
It is allocated and filled in
-.Fn data
+.Fn tbl_data
and referenced from the
-.Va first
+.Fa first
and
-.Va last
+.Fa last
members of
.Vt struct tbl_span .
+.Pp
+The
+.Fa string
+and
+.Fa next
+members may be
+.Dv NULL .
+The function
+.Fn getdata
+guarantees that the
+.Fa layout
+member is not
+.Dv NULL .
.El
.Ss Interface functions
The following functions are implemented in
@@ -185,7 +246,7 @@ Called from
.Fn roff_parseln .
.It Fn tbl_restart
Resets the
-.Va part
+.Fa part
member of
.Vt struct tbl_node
to
@@ -210,7 +271,7 @@ and
.It Fn tbl_free
Frees the specified
.Vt struct tbl_node
-and all the tbl_row, tbl_cell, tbl_span, tbl_dat and tbl_head structures
+and all the tbl_row, tbl_cell, tbl_span, and tbl_dat structures
referenced from it.
Called from
.Fn roff_free
@@ -228,10 +289,8 @@ called from
.Fn tbl_read .
.It Ft int Fn tbl_layout "struct tbl_node *tbl" "int ln" "const char *p"
Allocates and fills one
-.Vt struct tbl_head
-for each layout column, one
.Vt struct tbl_row
-for each layout line, and one
+for each layout line and one
.Vt struct tbl_cell
for each layout cell.
Implemented in
@@ -242,8 +301,8 @@ called from
Allocates one
.Vt struct tbl_span
for each data line and calls
-.Fn data
-on that line.
+.Fn getdata
+for each data cell.
Implemented in
.Pa tbl_data.c ,
called from
@@ -255,7 +314,7 @@ When finding
switches back to
.Dv TBL_PART_DATA
mode and calls
-.Fn data
+.Fn getdata
if there are more data cells on the line.
Otherwise, appends the data to the current data cell.
Implemented in
@@ -264,7 +323,7 @@ called from
.Fn tbl_read .
.It Xo
.Ft int
-.Fo data
+.Fo getdata
.Fa "struct tbl_node *tbl"
.Fa "struct tbl_span *dp"
.Fa "int ln"
diff --git a/tbl.7 b/tbl.7
index 04f5b47f8c5d..c8fa8e484499 100644
--- a/tbl.7
+++ b/tbl.7
@@ -1,7 +1,7 @@
-.\" $Id: tbl.7,v 1.21 2014/11/26 17:51:55 schwarze Exp $
+.\" $Id: tbl.7,v 1.26 2015/01/29 00:33:57 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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: November 26 2014 $
+.Dd $Mdocdate: January 29 2015 $
.Dt TBL 7
.Os
.Sh NAME
@@ -50,7 +50,7 @@ macro tags, whose precise syntax is documented in
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 centred in
+For example, the following creates a boxed table with digits centered in
the cells.
.Bd -literal -offset indent
\&.TS
@@ -133,58 +133,59 @@ c c c.
in the case of
.Xr man 7 .
.Ss Options
-The first line of a table consists of space-separated option keys and
-modifiers terminated by a semicolon.
-For GNU compatibility, option keys can also be separated by commas.
+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
.Sx Layout
is processed.
-Some options accept arguments enclosed by parenthesis.
+Some options require arguments enclosed by parentheses.
The following case-insensitive options are available:
.Bl -tag -width Ds
-.It Cm center
-This option is not supported by
-.Xr mandoc 1 .
-This may also be invoked with
-.Cm centre .
-.It Cm delim
-Accepts a two-character argument.
-This option is not supported by
-.Xr mandoc 1 .
-.It Cm expand
-This option is not supported by
-.Xr mandoc 1 .
+.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.
-This may also be invoked with
+For GNU compatibility, this may also be invoked with
.Cm frame .
+.It Cm center
+Center the table instead of left-adjusting it.
+For GNU compatibility, this may also be invoked with
+.Cm centre .
+.It Cm decimalpoint
+Use the single-character argument as the decimal point with the
+.Cm n
+layout key.
+This is a GNU extension.
+.It Cm delim
+Use the two characters of the argument as
+.Xr eqn 7
+delimiters.
+Currently unsupported.
.It Cm doublebox
Draw a double-line box around the table.
-This may also be invoked with
+For GNU compatibility, this may also be invoked with
.Cm doubleframe .
-.It Cm allbox
-This option is not supported by
-.Xr mandoc 1 .
-.It Cm tab
-Accepts a single-character argument.
-This character is used as a delimiter between data cells, which otherwise
-defaults to the tab character.
+.It Cm expand
+Increase the width of the table to the current line length.
+Currently ignored.
.It Cm linesize
-Accepts a natural number (all digits).
-This option is not supported by
-.Xr mandoc 1 .
+Draw lines with the point size given by the unsigned integer argument.
+Currently ignored.
.It Cm nokeep
-This option is not supported by
-.Xr mandoc 1 .
-.It Cm decimalpoint
-Accepts a single-character argument.
-This character will be used as the decimal point with the
-.Cm n
-layout key.
+Allow page breaks within the table.
+This is a GNU extension and currently ignored.
.It Cm nospaces
-This option is not supported by
-.Xr mandoc 1 .
+Ignore leading and trailing spaces in data cells.
+This is a GNU extension and currently ignored.
+.It Cm nowarn
+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.
.El
.Ss Layout
The table layout follows
@@ -199,7 +200,7 @@ Layout lines may also be separated by a comma.
Each layout cell consists of one of the following case-insensitive keys:
.Bl -tag -width 2n
.It Cm c
-Centre a literal string within its column.
+Center a literal string within its column.
.It Cm r
Right-justify a literal string within its column.
.It Cm l
@@ -249,6 +250,9 @@ The following case-insensitive modifier keys are available:
.Bl -tag -width 2n
.It Cm b
Use a bold font for the contents of this column.
+.It Cm d
+Move cell content down to the last cell of a vertical span.
+Currently ignored.
.It Cm e
Make this column wider to match the maximum width
of any other column also having the
@@ -261,6 +265,27 @@ See the
manual for supported one-character font names.
.It Cm i
Use an italic font for the contents of this column.
+.It Cm m
+Specify a cell start macro.
+This is a GNU extension and currently unsupported.
+.It Cm p
+Set the point size to the following unsigned argument,
+or change it by the following signed argument.
+Currently ignored.
+.It Cm v
+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.
+Currently ignored.
+.It Cm u
+Move cell content up by half a table line.
+Currently ignored.
+.It Cm w
+Specify minimum column width.
+Currently ignored.
.It Cm x
After determining the width of all other columns, distribute the
rest of the line length among all columns having the
@@ -270,16 +295,7 @@ modifier.
Do not use this cell for determining the width of this column.
.El
.Pp
-The modifiers
-.Cm d ,
-.Cm t ,
-.Cm u ,
-and
-.Cm w
-are ignored by
-.Xr mandoc 1 .
-.Pp
-For example, the following layout specifies a centre-justified column of
+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:
@@ -312,18 +328,17 @@ It may then be followed by a tab
.Pq or as designated by Cm tab
or an end-of-line to terminate the row.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other
-.Nm
-implementations, at this time limited to GNU tbl.
-.Pp
-.Bl -dash -compact
-.It
-In GNU tbl, comments and macros are disallowed prior to the data block
-of a table.
The
.Xr mandoc 1
-implementation allows them.
-.El
+implementation of
+.Nm
+doesn't support
+.Xr mdoc 7
+and
+.Xr man 7
+macros and
+.Xr eqn 7
+equations inside tables.
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr man 7 ,
diff --git a/tbl.c b/tbl.c
index bfed242b9d9e..00ee4661254b 100644
--- a/tbl.c
+++ b/tbl.c
@@ -1,7 +1,7 @@
-/* $Id: tbl.c,v 1.30 2014/08/10 23:54:41 schwarze Exp $ */
+/* $Id: tbl.c,v 1.39 2015/01/30 17:32:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -32,43 +32,58 @@
enum rofferr
-tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs)
+tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
{
- int len;
const char *cp;
-
- cp = &p[offs];
- len = (int)strlen(cp);
+ int active;
/*
- * If we're in the options section and we don't have a
- * terminating semicolon, assume we've moved directly into the
- * layout section. No need to report a warning: this is,
- * apparently, standard behaviour.
+ * In the options section, proceed to the layout section
+ * after a semicolon, or right away if there is no semicolon.
+ * Ignore semicolons in arguments.
*/
- if (TBL_PART_OPTS == tbl->part && len)
- if (';' != cp[len - 1])
- tbl->part = TBL_PART_LAYOUT;
+ if (tbl->part == TBL_PART_OPTS) {
+ tbl->part = TBL_PART_LAYOUT;
+ active = 1;
+ for (cp = p + pos; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case '(':
+ active = 0;
+ continue;
+ case ')':
+ active = 1;
+ continue;
+ case ';':
+ if (active)
+ break;
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ if (*cp == ';') {
+ tbl_option(tbl, ln, p, &pos);
+ if (p[pos] == '\0')
+ return(ROFF_IGN);
+ }
+ }
- /* Now process each logical section of the table. */
+ /* Process the other section types. */
switch (tbl->part) {
- case TBL_PART_OPTS:
- return(tbl_option(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
case TBL_PART_LAYOUT:
- return(tbl_layout(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
+ tbl_layout(tbl, ln, p, pos);
+ return(ROFF_IGN);
case TBL_PART_CDATA:
- return(tbl_cdata(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
+ return(tbl_cdata(tbl, ln, p, pos) ? ROFF_TBL : ROFF_IGN);
default:
break;
}
- /*
- * This only returns zero if the line is empty, so we ignore it
- * and continue on.
- */
- return(tbl_data(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
+ tbl_data(tbl, ln, p, pos);
+ return(ROFF_TBL);
}
struct tbl_node *
@@ -76,13 +91,12 @@ tbl_alloc(int pos, int line, struct mparse *parse)
{
struct tbl_node *tbl;
- tbl = mandoc_calloc(1, sizeof(struct tbl_node));
+ tbl = mandoc_calloc(1, sizeof(*tbl));
tbl->line = line;
tbl->pos = pos;
tbl->parse = parse;
tbl->part = TBL_PART_OPTS;
tbl->opts.tab = '\t';
- tbl->opts.linesize = 12;
tbl->opts.decimal = '.';
return(tbl);
}
@@ -94,11 +108,10 @@ tbl_free(struct tbl_node *tbl)
struct tbl_cell *cp;
struct tbl_span *sp;
struct tbl_dat *dp;
- struct tbl_head *hp;
- while (NULL != (rp = tbl->first_row)) {
+ while ((rp = tbl->first_row) != NULL) {
tbl->first_row = rp->next;
- while (rp->first) {
+ while (rp->first != NULL) {
cp = rp->first;
rp->first = cp->next;
free(cp);
@@ -106,40 +119,30 @@ tbl_free(struct tbl_node *tbl)
free(rp);
}
- while (NULL != (sp = tbl->first_span)) {
+ while ((sp = tbl->first_span) != NULL) {
tbl->first_span = sp->next;
- while (sp->first) {
+ while (sp->first != NULL) {
dp = sp->first;
sp->first = dp->next;
- if (dp->string)
- free(dp->string);
+ free(dp->string);
free(dp);
}
free(sp);
}
- while (NULL != (hp = tbl->first_head)) {
- tbl->first_head = hp->next;
- free(hp);
- }
-
free(tbl);
}
void
tbl_restart(int line, int pos, struct tbl_node *tbl)
{
- if (TBL_PART_CDATA == tbl->part)
- mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ if (tbl->part == TBL_PART_CDATA)
+ mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
+ line, pos, "T&");
tbl->part = TBL_PART_LAYOUT;
tbl->line = line;
tbl->pos = pos;
-
- if (NULL == tbl->first_span || NULL == tbl->first_span->first)
- mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
- tbl->line, tbl->pos, NULL);
}
const struct tbl_span *
@@ -155,22 +158,26 @@ tbl_span(struct tbl_node *tbl)
return(span);
}
-void
+int
tbl_end(struct tbl_node **tblp)
{
struct tbl_node *tbl;
+ struct tbl_span *sp;
tbl = *tblp;
*tblp = NULL;
- if (NULL == tbl->first_span || NULL == tbl->first_span->first)
- mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
- tbl->line, tbl->pos, NULL);
-
- if (tbl->last_span)
- tbl->last_span->flags |= TBL_SPAN_LAST;
+ if (tbl->part == TBL_PART_CDATA)
+ mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
+ tbl->line, tbl->pos, "TE");
- if (TBL_PART_CDATA == tbl->part)
- mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
+ sp = tbl->first_span;
+ while (sp != NULL && sp->first == NULL)
+ sp = sp->next;
+ if (sp == NULL) {
+ mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse,
tbl->line, tbl->pos, NULL);
+ return(0);
+ }
+ return(1);
}
diff --git a/tbl_data.c b/tbl_data.c
index 43244dabd464..e2be64eb811a 100644
--- a/tbl_data.c
+++ b/tbl_data.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_data.c,v 1.32 2014/08/10 23:54:41 schwarze Exp $ */
+/* $Id: tbl_data.c,v 1.39 2015/01/30 17:32:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -30,32 +30,24 @@
#include "libmandoc.h"
#include "libroff.h"
-static int getdata(struct tbl_node *, struct tbl_span *,
+static void getdata(struct tbl_node *, struct tbl_span *,
int, const char *, int *);
static struct tbl_span *newspan(struct tbl_node *, int,
struct tbl_row *);
-static int
+static void
getdata(struct tbl_node *tbl, struct tbl_span *dp,
int ln, const char *p, int *pos)
{
struct tbl_dat *dat;
struct tbl_cell *cp;
- int sv, spans;
+ int sv;
- cp = NULL;
- if (dp->last && dp->last->layout)
- cp = dp->last->layout->next;
- else if (NULL == dp->last)
- cp = dp->layout->first;
+ /* Advance to the next layout cell, skipping spanners. */
- /*
- * Skip over spanners, since
- * we want to match data with data layout cells in the header.
- */
-
- while (cp && TBL_CELL_SPAN == cp->pos)
+ cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
+ while (cp != NULL && cp->pos == TBL_CELL_SPAN)
cp = cp->next;
/*
@@ -63,34 +55,30 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
* cells. This means that we have extra input.
*/
- if (NULL == cp) {
- mandoc_msg(MANDOCERR_TBLEXTRADAT, tbl->parse,
- ln, *pos, NULL);
+ if (cp == NULL) {
+ mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
+ ln, *pos, p + *pos);
/* Skip to the end... */
while (p[*pos])
(*pos)++;
- return(1);
+ return;
}
- dat = mandoc_calloc(1, sizeof(struct tbl_dat));
+ dat = mandoc_calloc(1, sizeof(*dat));
dat->layout = cp;
dat->pos = TBL_DATA_NONE;
-
- assert(TBL_CELL_SPAN != cp->pos);
-
- for (spans = 0, cp = cp->next; cp; cp = cp->next)
- if (TBL_CELL_SPAN == cp->pos)
- spans++;
+ dat->spans = 0;
+ for (cp = cp->next; cp != NULL; cp = cp->next)
+ if (cp->pos == TBL_CELL_SPAN)
+ dat->spans++;
else
break;
- dat->spans = spans;
-
- if (dp->last) {
+ if (dp->last == NULL)
+ dp->first = dat;
+ else
dp->last->next = dat;
- dp->last = dat;
- } else
- dp->last = dp->first = dat;
+ dp->last = dat;
sv = *pos;
while (p[*pos] && p[*pos] != tbl->opts.tab)
@@ -102,16 +90,12 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
* until a standalone `T}', are included in our cell.
*/
- if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) {
+ if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
tbl->part = TBL_PART_CDATA;
- return(1);
+ return;
}
- assert(*pos - sv >= 0);
-
- dat->string = mandoc_malloc((size_t)(*pos - sv + 1));
- memcpy(dat->string, &p[sv], (size_t)(*pos - sv));
- dat->string[*pos - sv] = '\0';
+ dat->string = mandoc_strndup(p + sv, *pos - sv);
if (p[*pos])
(*pos)++;
@@ -127,24 +111,19 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
else
dat->pos = TBL_DATA_DATA;
- if (TBL_CELL_HORIZ == dat->layout->pos ||
- TBL_CELL_DHORIZ == dat->layout->pos ||
- TBL_CELL_DOWN == dat->layout->pos)
- if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
- mandoc_msg(MANDOCERR_TBLIGNDATA,
- tbl->parse, ln, sv, NULL);
-
- return(1);
+ if ((dat->layout->pos == TBL_CELL_HORIZ ||
+ dat->layout->pos == TBL_CELL_DHORIZ ||
+ dat->layout->pos == TBL_CELL_DOWN) &&
+ dat->pos == TBL_DATA_DATA && *dat->string != '\0')
+ mandoc_msg(MANDOCERR_TBLDATA_SPAN,
+ tbl->parse, ln, sv, dat->string);
}
int
-tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
+tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_dat *dat;
size_t sz;
- int pos;
-
- pos = 0;
dat = tbl->last_span->last;
@@ -153,8 +132,9 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
if (p[pos] == tbl->opts.tab) {
tbl->part = TBL_PART_DATA;
pos++;
- return(getdata(tbl, tbl->last_span, ln, p, &pos));
- } else if ('\0' == p[pos]) {
+ getdata(tbl, tbl->last_span, ln, p, &pos);
+ return(1);
+ } else if (p[pos] == '\0') {
tbl->part = TBL_PART_DATA;
return(1);
}
@@ -164,17 +144,17 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
dat->pos = TBL_DATA_DATA;
- if (dat->string) {
- sz = strlen(p) + strlen(dat->string) + 2;
+ if (dat->string != NULL) {
+ sz = strlen(p + pos) + strlen(dat->string) + 2;
dat->string = mandoc_realloc(dat->string, sz);
(void)strlcat(dat->string, " ", sz);
- (void)strlcat(dat->string, p, sz);
+ (void)strlcat(dat->string, p + pos, sz);
} else
- dat->string = mandoc_strdup(p);
+ dat->string = mandoc_strdup(p + pos);
- if (TBL_CELL_DOWN == dat->layout->pos)
- mandoc_msg(MANDOCERR_TBLIGNDATA, tbl->parse,
- ln, pos, NULL);
+ if (dat->layout->pos == TBL_CELL_DOWN)
+ mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
+ ln, pos, dat->string);
return(0);
}
@@ -184,37 +164,27 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
{
struct tbl_span *dp;
- dp = mandoc_calloc(1, sizeof(struct tbl_span));
+ dp = mandoc_calloc(1, sizeof(*dp));
dp->line = line;
dp->opts = &tbl->opts;
dp->layout = rp;
- dp->head = tbl->first_head;
+ dp->prev = tbl->last_span;
- if (tbl->last_span) {
- tbl->last_span->next = dp;
- tbl->last_span = dp;
- } else {
- tbl->last_span = tbl->first_span = dp;
+ if (dp->prev == NULL) {
+ tbl->first_span = dp;
tbl->current_span = NULL;
- dp->flags |= TBL_SPAN_FIRST;
- }
+ } else
+ dp->prev->next = dp;
+ tbl->last_span = dp;
return(dp);
}
-int
-tbl_data(struct tbl_node *tbl, int ln, const char *p)
+void
+tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_span *dp;
struct tbl_row *rp;
- int pos;
-
- pos = 0;
-
- if ('\0' == p[pos]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, pos, NULL);
- return(0);
- }
/*
* Choose a layout row: take the one following the last parsed
@@ -224,11 +194,11 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
* (it doesn't "consume" the layout).
*/
- if (tbl->last_span) {
- assert(tbl->last_span->layout);
+ if (tbl->last_span != NULL) {
if (tbl->last_span->pos == TBL_SPAN_DATA) {
for (rp = tbl->last_span->layout->next;
- rp && rp->first; rp = rp->next) {
+ rp != NULL && rp->first != NULL;
+ rp = rp->next) {
switch (rp->first->pos) {
case TBL_CELL_HORIZ:
dp = newspan(tbl, ln, rp);
@@ -246,7 +216,7 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
} else
rp = tbl->last_span->layout;
- if (NULL == rp)
+ if (rp == NULL)
rp = tbl->last_span->layout;
} else
rp = tbl->first_row;
@@ -257,19 +227,14 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
if ( ! strcmp(p, "_")) {
dp->pos = TBL_SPAN_HORIZ;
- return(1);
+ return;
} else if ( ! strcmp(p, "=")) {
dp->pos = TBL_SPAN_DHORIZ;
- return(1);
+ return;
}
dp->pos = TBL_SPAN_DATA;
- /* This returns 0 when TBL_PART_CDATA is entered. */
-
- while ('\0' != p[pos])
- if ( ! getdata(tbl, dp, ln, p, &pos))
- return(0);
-
- return(1);
+ while (p[pos] != '\0')
+ getdata(tbl, dp, ln, p, &pos);
}
diff --git a/tbl_html.c b/tbl_html.c
index 1de1bb8bdc9d..e7940381d203 100644
--- a/tbl_html.c
+++ b/tbl_html.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_html.c,v 1.13 2014/10/14 02:16:06 schwarze Exp $ */
+/* $Id: tbl_html.c,v 1.16 2015/01/30 17:32:16 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -49,12 +49,12 @@ html_tbl_strlen(const char *p, void *arg)
static void
html_tblopen(struct html *h, const struct tbl_span *sp)
{
- const struct tbl_head *hp;
struct htmlpair tag;
struct roffsu su;
struct roffcol *col;
+ int ic;
- if (TBL_SPAN_FIRST & sp->flags) {
+ if (h->tbl.cols == NULL) {
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
tblcalc(&h->tbl, sp, 0);
@@ -64,9 +64,9 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
PAIR_CLASS_INIT(&tag, "tbl");
h->tblt = print_otag(h, TAG_TABLE, 1, &tag);
- for (hp = sp->head; hp; hp = hp->next) {
+ for (ic = 0; ic < sp->opts->cols; ic++) {
bufinit(h);
- col = &h->tbl.cols[hp->ident];
+ col = h->tbl.cols + ic;
SCALE_HS_INIT(&su, col->width);
bufcat_su(h, "width", &su);
PAIR_STYLE_INIT(&tag, h);
@@ -88,14 +88,14 @@ print_tblclose(struct html *h)
void
print_tbl(struct html *h, const struct tbl_span *sp)
{
- const struct tbl_head *hp;
const struct tbl_dat *dp;
struct htmlpair tag;
struct tag *tt;
+ int ic;
/* Inhibit printing of spaces: we do padding ourselves. */
- if (NULL == h->tblt)
+ if (h->tblt == NULL)
html_tblopen(h, sp);
assert(h->tblt);
@@ -114,14 +114,14 @@ print_tbl(struct html *h, const struct tbl_span *sp)
break;
default:
dp = sp->first;
- for (hp = sp->head; hp; hp = hp->next) {
+ for (ic = 0; ic < sp->opts->cols; ic++) {
print_stagq(h, tt);
print_otag(h, TAG_TD, 0, NULL);
- if (NULL == dp)
- break;
- if (TBL_CELL_DOWN != dp->layout->pos)
- if (dp->string)
+ if (dp == NULL || dp->layout->col > ic)
+ continue;
+ if (dp->layout->pos != TBL_CELL_DOWN)
+ if (dp->string != NULL)
print_text(h, dp->string);
dp = dp->next;
}
@@ -132,7 +132,7 @@ print_tbl(struct html *h, const struct tbl_span *sp)
h->flags &= ~HTML_NONOSPACE;
- if (TBL_SPAN_LAST & sp->flags) {
+ if (sp->next == NULL) {
assert(h->tbl.cols);
free(h->tbl.cols);
h->tbl.cols = NULL;
diff --git a/tbl_layout.c b/tbl_layout.c
index 033074afbb10..ed9acc9c0a5a 100644
--- a/tbl_layout.c
+++ b/tbl_layout.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_layout.c,v 1.30 2014/11/25 21:41:47 schwarze Exp $ */
+/* $Id: tbl_layout.c,v 1.38 2015/02/10 11:03:13 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -34,15 +34,7 @@ struct tbl_phrase {
enum tbl_cellt key;
};
-/*
- * FIXME: we can make this parse a lot nicer by, when an error is
- * encountered in a layout key, bailing to the next key (i.e. to the
- * next whitespace then continuing).
- */
-
-#define KEYS_MAX 11
-
-static const struct tbl_phrase keys[KEYS_MAX] = {
+static const struct tbl_phrase keys[] = {
{ 'c', TBL_CELL_CENTRE },
{ 'r', TBL_CELL_RIGHT },
{ 'l', TBL_CELL_LEFT },
@@ -55,57 +47,30 @@ static const struct tbl_phrase keys[KEYS_MAX] = {
{ '=', TBL_CELL_DHORIZ }
};
-static int mods(struct tbl_node *, struct tbl_cell *,
+#define KEYS_MAX ((int)(sizeof(keys)/sizeof(keys[0])))
+
+static void mods(struct tbl_node *, struct tbl_cell *,
int, const char *, int *);
-static int cell(struct tbl_node *, struct tbl_row *,
+static void cell(struct tbl_node *, struct tbl_row *,
int, const char *, int *);
static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
- enum tbl_cellt, int vert);
+ enum tbl_cellt);
-static int
+static void
mods(struct tbl_node *tbl, struct tbl_cell *cp,
int ln, const char *p, int *pos)
{
- char buf[5];
- int i;
+ char *endptr;
- /* Not all types accept modifiers. */
+mod:
+ while (p[*pos] == ' ' || p[*pos] == '\t')
+ (*pos)++;
- switch (cp->pos) {
- case TBL_CELL_DOWN:
- /* FALLTHROUGH */
- case TBL_CELL_HORIZ:
- /* FALLTHROUGH */
- case TBL_CELL_DHORIZ:
- return(1);
- default:
- break;
- }
+ /* Row delimiters and cell specifiers end modifier lists. */
-mod:
- /*
- * XXX: since, at least for now, modifiers are non-conflicting
- * (are separable by value, regardless of position), we let
- * modifiers come in any order. The existing tbl doesn't let
- * this happen.
- */
- switch (p[*pos]) {
- case '\0':
- /* FALLTHROUGH */
- case ' ':
- /* FALLTHROUGH */
- case '\t':
- /* FALLTHROUGH */
- case ',':
- /* FALLTHROUGH */
- case '.':
- /* FALLTHROUGH */
- case '|':
- return(1);
- default:
- break;
- }
+ if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL)
+ return;
/* Throw away parenthesised expression. */
@@ -117,123 +82,138 @@ mod:
(*pos)++;
goto mod;
}
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
+ mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse,
ln, *pos, NULL);
- return(0);
+ return;
}
/* Parse numerical spacing from modifier string. */
if (isdigit((unsigned char)p[*pos])) {
- for (i = 0; i < 4; i++) {
- if ( ! isdigit((unsigned char)p[*pos + i]))
- break;
- buf[i] = p[*pos + i];
- }
- buf[i] = '\0';
-
- /* No greater than 4 digits. */
-
- if (4 == i) {
- mandoc_msg(MANDOCERR_TBLLAYOUT,
- tbl->parse, ln, *pos, NULL);
- return(0);
- }
-
- *pos += i;
- cp->spacing = (size_t)atoi(buf);
-
+ cp->spacing = strtoull(p + *pos, &endptr, 10);
+ *pos = endptr - p;
goto mod;
- /* NOTREACHED */
}
- /* TODO: GNU has many more extensions. */
-
switch (tolower((unsigned char)p[(*pos)++])) {
- case 'z':
- cp->flags |= TBL_CELL_WIGN;
+ case 'b':
+ cp->flags |= TBL_CELL_BOLD;
goto mod;
- case 'u':
- cp->flags |= TBL_CELL_UP;
+ case 'd':
+ cp->flags |= TBL_CELL_BALIGN;
goto mod;
case 'e':
cp->flags |= TBL_CELL_EQUAL;
goto mod;
+ case 'f':
+ break;
+ case 'i':
+ cp->flags |= TBL_CELL_ITALIC;
+ goto mod;
+ case 'm':
+ mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse,
+ ln, *pos, "m");
+ goto mod;
+ case 'p':
+ /* FALLTHROUGH */
+ case 'v':
+ if (p[*pos] == '-' || p[*pos] == '+')
+ (*pos)++;
+ while (isdigit((unsigned char)p[*pos]))
+ (*pos)++;
+ goto mod;
case 't':
cp->flags |= TBL_CELL_TALIGN;
goto mod;
- case 'd':
- cp->flags |= TBL_CELL_BALIGN;
+ case 'u':
+ cp->flags |= TBL_CELL_UP;
goto mod;
case 'w': /* XXX for now, ignore minimal column width */
goto mod;
case 'x':
cp->flags |= TBL_CELL_WMAX;
goto mod;
- case 'f':
- break;
- case 'r':
- /* FALLTHROUGH */
- case 'b':
- /* FALLTHROUGH */
- case 'i':
- (*pos)--;
- break;
+ case 'z':
+ cp->flags |= TBL_CELL_WIGN;
+ goto mod;
+ case '|':
+ if (cp->vert < 2)
+ cp->vert++;
+ else
+ mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
+ tbl->parse, ln, *pos - 1, NULL);
+ goto mod;
default:
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
+ mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
+ ln, *pos - 1, "%c", p[*pos - 1]);
+ goto mod;
}
- switch (tolower((unsigned char)p[(*pos)++])) {
+ /* Ignore parenthised font names for now. */
+
+ if (p[*pos] == '(')
+ goto mod;
+
+ /* Support only one-character font-names for now. */
+
+ if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
+ mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
+ ln, *pos, "TS %s", p + *pos - 1);
+ if (p[*pos] != '\0')
+ (*pos)++;
+ if (p[*pos] != '\0')
+ (*pos)++;
+ goto mod;
+ }
+
+ switch (p[(*pos)++]) {
case '3':
/* FALLTHROUGH */
- case 'b':
+ case 'B':
cp->flags |= TBL_CELL_BOLD;
goto mod;
case '2':
/* FALLTHROUGH */
- case 'i':
+ case 'I':
cp->flags |= TBL_CELL_ITALIC;
goto mod;
case '1':
/* FALLTHROUGH */
- case 'r':
+ case 'R':
goto mod;
default:
- break;
- }
- if (isalnum((unsigned char)p[*pos - 1])) {
mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
ln, *pos - 1, "TS f%c", p[*pos - 1]);
goto mod;
}
-
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
}
-static int
+static void
cell(struct tbl_node *tbl, struct tbl_row *rp,
int ln, const char *p, int *pos)
{
- int vert, i;
+ int i;
enum tbl_cellt c;
- /* Handle vertical lines. */
+ /* Handle leading vertical lines */
- for (vert = 0; '|' == p[*pos]; ++*pos)
- vert++;
- while (' ' == p[*pos])
+ while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') {
+ if (p[*pos] == '|') {
+ if (rp->vert < 2)
+ rp->vert++;
+ else
+ mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
+ tbl->parse, ln, *pos, NULL);
+ }
(*pos)++;
+ }
- /* Handle trailing vertical lines */
+again:
+ while (p[*pos] == ' ' || p[*pos] == '\t')
+ (*pos)++;
- if ('.' == p[*pos] || '\0' == p[*pos]) {
- rp->vert = vert;
- return(1);
- }
+ if (p[*pos] == '.' || p[*pos] == '\0')
+ return;
/* Parse the column position (`c', `l', `r', ...). */
@@ -241,77 +221,44 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
if (tolower((unsigned char)p[*pos]) == keys[i].name)
break;
- if (KEYS_MAX == i) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
- return(0);
+ if (i == KEYS_MAX) {
+ mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
+ ln, *pos, "%c", p[*pos]);
+ (*pos)++;
+ goto again;
}
-
c = keys[i].key;
- /*
- * If a span cell is found first, raise a warning and abort the
- * parse. If a span cell is found and the last layout element
- * isn't a "normal" layout, bail.
- *
- * FIXME: recover from this somehow?
- */
-
- if (TBL_CELL_SPAN == c) {
- if (NULL == rp->first) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
- return(0);
- } else if (rp->last)
- switch (rp->last->pos) {
- case TBL_CELL_HORIZ:
- /* FALLTHROUGH */
- case TBL_CELL_DHORIZ:
- mandoc_msg(MANDOCERR_TBLLAYOUT,
- tbl->parse, ln, *pos, NULL);
- return(0);
- default:
- break;
- }
- }
-
- /*
- * If a vertical spanner is found, we may not be in the first
- * row.
- */
+ /* Special cases of spanners. */
- if (TBL_CELL_DOWN == c && rp == tbl->first_row) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos, NULL);
- return(0);
- }
+ if (c == TBL_CELL_SPAN) {
+ if (rp->last == NULL)
+ mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN,
+ tbl->parse, ln, *pos, NULL);
+ else if (rp->last->pos == TBL_CELL_HORIZ ||
+ rp->last->pos == TBL_CELL_DHORIZ)
+ c = rp->last->pos;
+ } else if (c == TBL_CELL_DOWN && rp == tbl->first_row)
+ mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN,
+ tbl->parse, ln, *pos, NULL);
(*pos)++;
- /* Disallow adjacent spacers. */
-
- if (vert > 2) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL);
- return(0);
- }
-
/* Allocate cell then parse its modifiers. */
- return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos));
+ mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos);
}
-int
-tbl_layout(struct tbl_node *tbl, int ln, const char *p)
+void
+tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_row *rp;
- int pos;
- pos = 0;
rp = NULL;
-
for (;;) {
/* Skip whitespace before and after each cell. */
- while (isspace((unsigned char)p[pos]))
+ while (p[pos] == ' ' || p[pos] == '\t')
pos++;
switch (p[pos]) {
@@ -320,74 +267,92 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p)
rp = NULL;
continue;
case '\0': /* Next row on next input line. */
- return(1);
+ return;
case '.': /* End of layout. */
pos++;
tbl->part = TBL_PART_DATA;
- if (tbl->first_row != NULL)
- return(1);
- mandoc_msg(MANDOCERR_TBLNOLAYOUT,
- tbl->parse, ln, pos, NULL);
- rp = mandoc_calloc(1, sizeof(*rp));
- cell_alloc(tbl, rp, TBL_CELL_LEFT, 0);
- tbl->first_row = tbl->last_row = rp;
- return(1);
+
+ /*
+ * When the layout is completely empty,
+ * default to one left-justified column.
+ */
+
+ if (tbl->first_row == NULL) {
+ tbl->first_row = tbl->last_row =
+ mandoc_calloc(1, sizeof(*rp));
+ }
+ if (tbl->first_row->first == NULL) {
+ mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,
+ tbl->parse, ln, pos, NULL);
+ cell_alloc(tbl, tbl->first_row,
+ TBL_CELL_LEFT);
+ return;
+ }
+
+ /*
+ * Search for the widest line
+ * along the left and right margins.
+ */
+
+ for (rp = tbl->first_row; rp; rp = rp->next) {
+ if (tbl->opts.lvert < rp->vert)
+ tbl->opts.lvert = rp->vert;
+ if (rp->last != NULL &&
+ rp->last->col + 1 == tbl->opts.cols &&
+ tbl->opts.rvert < rp->last->vert)
+ tbl->opts.rvert = rp->last->vert;
+
+ /* If the last line is empty, drop it. */
+
+ if (rp->next != NULL &&
+ rp->next->first == NULL) {
+ free(rp->next);
+ rp->next = NULL;
+ }
+ }
+ return;
default: /* Cell. */
break;
}
- if (rp == NULL) { /* First cell on this line. */
- rp = mandoc_calloc(1, sizeof(*rp));
- if (tbl->last_row)
- tbl->last_row->next = rp;
- else
- tbl->first_row = rp;
- tbl->last_row = rp;
+ /*
+ * If the last line had at least one cell,
+ * start a new one; otherwise, continue it.
+ */
+
+ if (rp == NULL) {
+ if (tbl->last_row == NULL ||
+ tbl->last_row->first != NULL) {
+ rp = mandoc_calloc(1, sizeof(*rp));
+ if (tbl->last_row)
+ tbl->last_row->next = rp;
+ else
+ tbl->first_row = rp;
+ tbl->last_row = rp;
+ } else
+ rp = tbl->last_row;
}
- if ( ! cell(tbl, rp, ln, p, &pos))
- return(1);
+ cell(tbl, rp, ln, p, &pos);
}
}
static struct tbl_cell *
-cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos,
- int vert)
+cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
{
struct tbl_cell *p, *pp;
- struct tbl_head *h, *hp;
- p = mandoc_calloc(1, sizeof(struct tbl_cell));
+ p = mandoc_calloc(1, sizeof(*p));
+ p->pos = pos;
- if (NULL != (pp = rp->last)) {
+ if ((pp = rp->last) != NULL) {
pp->next = p;
- h = pp->head->next;
- } else {
+ p->col = pp->col + 1;
+ } else
rp->first = p;
- h = tbl->first_head;
- }
rp->last = p;
- p->pos = pos;
- p->vert = vert;
-
- /* Re-use header. */
-
- if (h) {
- p->head = h;
- return(p);
- }
-
- hp = mandoc_calloc(1, sizeof(struct tbl_head));
- hp->ident = tbl->opts.cols++;
- hp->vert = vert;
-
- if (tbl->last_head) {
- hp->prev = tbl->last_head;
- tbl->last_head->next = hp;
- } else
- tbl->first_head = hp;
- tbl->last_head = hp;
+ if (tbl->opts.cols <= p->col)
+ tbl->opts.cols = p->col + 1;
- p->head = hp;
return(p);
}
diff --git a/tbl_opts.c b/tbl_opts.c
index d5ad42f73e5e..c012a3c88545 100644
--- a/tbl_opts.c
+++ b/tbl_opts.c
@@ -1,6 +1,7 @@
-/* $Id: tbl_opts.c,v 1.15 2014/11/26 17:51:55 schwarze Exp $ */
+/* $Id: tbl_opts.c,v 1.20 2015/01/28 17:32:07 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,245 +28,147 @@
#include "libmandoc.h"
#include "libroff.h"
-enum tbl_ident {
- KEY_CENTRE = 0,
- KEY_DELIM,
- KEY_EXPAND,
- KEY_BOX,
- KEY_DBOX,
- KEY_ALLBOX,
- KEY_TAB,
- KEY_LINESIZE,
- KEY_NOKEEP,
- KEY_DPOINT,
- KEY_NOSPACE,
- KEY_FRAME,
- KEY_DFRAME,
- KEY_MAX
-};
+#define KEY_DPOINT 0
+#define KEY_DELIM 1
+#define KEY_LINESIZE 2
+#define KEY_TAB 3
struct tbl_phrase {
const char *name;
int key;
- enum tbl_ident ident;
};
-/* Handle Commonwealth/American spellings. */
-#define KEY_MAXKEYS 14
-
-/* Maximum length of key name string. */
-#define KEY_MAXNAME 13
-
-/* Maximum length of key number size. */
-#define KEY_MAXNUMSZ 10
-
-static const struct tbl_phrase keys[KEY_MAXKEYS] = {
- { "center", TBL_OPT_CENTRE, KEY_CENTRE},
- { "centre", TBL_OPT_CENTRE, KEY_CENTRE},
- { "delim", 0, KEY_DELIM},
- { "expand", TBL_OPT_EXPAND, KEY_EXPAND},
- { "box", TBL_OPT_BOX, KEY_BOX},
- { "doublebox", TBL_OPT_DBOX, KEY_DBOX},
- { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX},
- { "frame", TBL_OPT_BOX, KEY_FRAME},
- { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME},
- { "tab", 0, KEY_TAB},
- { "linesize", 0, KEY_LINESIZE},
- { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP},
- { "decimalpoint", 0, KEY_DPOINT},
- { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE},
+static const struct tbl_phrase keys[] = {
+ {"decimalpoint", 0},
+ {"delim", 0},
+ {"linesize", 0},
+ {"tab", 0},
+ {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX},
+ {"box", TBL_OPT_BOX},
+ {"frame", TBL_OPT_BOX},
+ {"center", TBL_OPT_CENTRE},
+ {"centre", TBL_OPT_CENTRE},
+ {"doublebox", TBL_OPT_DBOX},
+ {"doubleframe", TBL_OPT_DBOX},
+ {"expand", TBL_OPT_EXPAND},
+ {"nokeep", TBL_OPT_NOKEEP},
+ {"nospaces", TBL_OPT_NOSPACE},
+ {"nowarn", TBL_OPT_NOWARN},
};
-static int arg(struct tbl_node *, int,
- const char *, int *, enum tbl_ident);
-static void opt(struct tbl_node *, int,
- const char *, int *);
+#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
+static void arg(struct tbl_node *, int, const char *, int *, int);
-static int
-arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
+
+static void
+arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
{
- int i;
- char buf[KEY_MAXNUMSZ];
+ int len, want;
- while (isspace((unsigned char)p[*pos]))
+ while (p[*pos] == ' ' || p[*pos] == '\t')
(*pos)++;
- /* Arguments always begin with a parenthesis. */
+ /* Arguments are enclosed in parentheses. */
- if ('(' != p[*pos]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos, NULL);
- return(0);
+ len = 0;
+ if (p[*pos] == '(') {
+ (*pos)++;
+ while (p[*pos + len] != ')')
+ len++;
}
- (*pos)++;
-
- /*
- * The arguments can be ANY value, so we can't just stop at the
- * next close parenthesis (the argument can be a closed
- * parenthesis itself).
- */
-
switch (key) {
case KEY_DELIM:
- if ('\0' == p[(*pos)++]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- }
-
- if ('\0' == p[(*pos)++]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- }
+ mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
+ ln, *pos, "%.*s", len, p + *pos);
+ want = 2;
break;
case KEY_TAB:
- if ('\0' != (tbl->opts.tab = p[(*pos)++]))
- break;
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
+ want = 1;
+ if (len == want)
+ tbl->opts.tab = p[*pos];
+ break;
case KEY_LINESIZE:
- for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {
- buf[i] = p[*pos];
- if ( ! isdigit((unsigned char)buf[i]))
- break;
- }
-
- if (i < KEY_MAXNUMSZ) {
- buf[i] = '\0';
- tbl->opts.linesize = atoi(buf);
- break;
- }
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
- return(0);
+ want = 0;
+ break;
case KEY_DPOINT:
- if ('\0' != (tbl->opts.decimal = p[(*pos)++]))
- break;
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
+ want = 1;
+ if (len == want)
+ tbl->opts.decimal = p[*pos];
+ break;
default:
abort();
/* NOTREACHED */
}
- /* End with a close parenthesis. */
-
- if (')' == p[(*pos)++])
- return(1);
+ if (len == 0)
+ mandoc_msg(MANDOCERR_TBLOPT_NOARG,
+ tbl->parse, ln, *pos, keys[key].name);
+ else if (want && len != want)
+ mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
+ tbl->parse, ln, *pos, "%s want %d have %d",
+ keys[key].name, want, len);
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL);
- return(0);
+ *pos += len;
+ if (p[*pos] == ')')
+ (*pos)++;
}
-static void
-opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
+/*
+ * Parse one line of options up to the semicolon.
+ * Each option can be preceded by blanks and/or commas,
+ * and some options are followed by arguments.
+ */
+void
+tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
{
- int i, sv;
- char buf[KEY_MAXNAME];
+ int i, pos, len;
- /*
- * Parse individual options from the stream as surrounded by
- * this goto. Each pass through the routine parses out a single
- * option and registers it. Option arguments are processed in
- * the arg() function.
- */
+ pos = *offs;
+ for (;;) {
+ while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
+ pos++;
-again: /*
- * EBNF describing this section:
- *
- * options ::= option_list [:space:]* [;][\n]
- * option_list ::= option option_tail
- * option_tail ::= [,:space:]+ option_list |
- * ::= epsilon
- * option ::= [:alpha:]+ args
- * args ::= [:space:]* [(] [:alpha:]+ [)]
- */
-
- while (isspace((unsigned char)p[*pos]))
- (*pos)++;
-
- /* Safe exit point. */
-
- if (';' == p[*pos])
- return;
-
- /* Copy up to first non-alpha character. */
-
- for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) {
- buf[i] = (char)tolower((unsigned char)p[*pos]);
- if ( ! isalpha((unsigned char)buf[i]))
- break;
- }
+ if (p[pos] == ';') {
+ *offs = pos + 1;
+ return;
+ }
- /* Exit if buffer is empty (or overrun). */
+ /* Parse one option name. */
- if (KEY_MAXNAME == i || 0 == i) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
- return;
- }
+ len = 0;
+ while (isalpha((unsigned char)p[pos + len]))
+ len++;
- buf[i] = '\0';
+ if (len == 0) {
+ mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
+ tbl->parse, ln, pos, "%c", p[pos]);
+ pos++;
+ continue;
+ }
- while (isspace((unsigned char)p[*pos]) || p[*pos] == ',')
- (*pos)++;
+ /* Look up the option name. */
- /*
- * Look through all of the available keys to find one that
- * matches the input. FIXME: hashtable this.
- */
+ i = 0;
+ while (i < KEY_MAXKEYS &&
+ (strncasecmp(p + pos, keys[i].name, len) ||
+ keys[i].name[len] != '\0'))
+ i++;
- for (i = 0; i < KEY_MAXKEYS; i++) {
- if (strcmp(buf, keys[i].name))
+ if (i == KEY_MAXKEYS) {
+ mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
+ ln, pos, "%.*s", len, p + pos);
+ pos += len;
continue;
+ }
- /*
- * Note: this is more difficult to recover from, as we
- * can be anywhere in the option sequence and it's
- * harder to jump to the next. Meanwhile, just bail out
- * of the sequence altogether.
- */
+ /* Handle the option. */
+ pos += len;
if (keys[i].key)
tbl->opts.opts |= keys[i].key;
- else if ( ! arg(tbl, ln, p, pos, keys[i].ident))
- return;
-
- break;
+ else
+ arg(tbl, ln, p, &pos, i);
}
-
- /*
- * Allow us to recover from bad options by continuing to another
- * parse sequence.
- */
-
- if (KEY_MAXKEYS == i)
- mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL);
-
- goto again;
- /* NOTREACHED */
-}
-
-int
-tbl_option(struct tbl_node *tbl, int ln, const char *p)
-{
- int pos;
-
- /*
- * Table options are always on just one line, so automatically
- * switch into the next input mode here.
- */
- tbl->part = TBL_PART_LAYOUT;
-
- pos = 0;
- opt(tbl, ln, p, &pos);
-
- /* Always succeed. */
- return(1);
}
diff --git a/tbl_term.c b/tbl_term.c
index 0275b1a2a670..a6354b51c4ea 100644
--- a/tbl_term.c
+++ b/tbl_term.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_term.c,v 1.31 2014/10/14 18:18:05 schwarze Exp $ */
+/* $Id: tbl_term.c,v 1.38 2015/01/31 00:12:41 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -34,15 +34,12 @@ static void tbl_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *,
const struct tbl_dat *,
const struct roffcol *);
-static size_t tbl_rulewidth(struct termp *, const struct tbl_head *);
-static void tbl_hframe(struct termp *, const struct tbl_span *, int);
static void tbl_literal(struct termp *, const struct tbl_dat *,
const struct roffcol *);
static void tbl_number(struct termp *, const struct tbl_opts *,
const struct tbl_dat *,
const struct roffcol *);
-static void tbl_hrule(struct termp *, const struct tbl_span *);
-static void tbl_vrule(struct termp *, const struct tbl_head *);
+static void tbl_hrule(struct termp *, const struct tbl_span *, int);
static void tbl_word(struct termp *, const struct tbl_dat *);
@@ -63,11 +60,11 @@ term_tbl_len(size_t sz, void *arg)
void
term_tbl(struct termp *tp, const struct tbl_span *sp)
{
- const struct tbl_head *hp;
+ const struct tbl_cell *cp;
const struct tbl_dat *dp;
- struct roffcol *col;
- int spans;
- size_t rmargin, maxrmargin;
+ static size_t offset;
+ size_t rmargin, maxrmargin, tsz;
+ int ic, horiz, spans, vert;
rmargin = tp->rmargin;
maxrmargin = tp->maxrmargin;
@@ -84,7 +81,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* calculate the table widths and decimal positions.
*/
- if (TBL_SPAN_FIRST & sp->flags) {
+ if (tp->tbl.cols == NULL) {
term_flushln(tp);
tp->tbl.len = term_tbl_len;
@@ -92,79 +89,99 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tbl.arg = tp;
tblcalc(&tp->tbl, sp, rmargin - tp->offset);
- }
- /* Horizontal frame at the start of boxed tables. */
+ /* Center the table as a whole. */
+
+ offset = tp->offset;
+ 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;
+ if (offset + tsz > rmargin)
+ tsz -= 1;
+ tp->offset = (offset + rmargin > tsz) ?
+ (offset + rmargin - tsz) / 2 : 0;
+ }
+
+ /* Horizontal frame at the start of boxed tables. */
- if (TBL_SPAN_FIRST & sp->flags) {
- if (TBL_OPT_DBOX & sp->opts->opts)
- tbl_hframe(tp, sp, 1);
- if (TBL_OPT_DBOX & sp->opts->opts ||
- TBL_OPT_BOX & sp->opts->opts)
- tbl_hframe(tp, sp, 0);
+ if (sp->opts->opts & TBL_OPT_DBOX)
+ tbl_hrule(tp, sp, 2);
+ if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
+ tbl_hrule(tp, sp, 1);
}
/* Vertical frame at the start of each row. */
- if ((TBL_OPT_BOX | TBL_OPT_DBOX) & sp->opts->opts ||
- (sp->head != NULL && sp->head->vert))
- term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
- TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
+ horiz = sp->pos == TBL_SPAN_HORIZ || sp->pos == TBL_SPAN_DHORIZ;
+
+ 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);
/*
* Now print the actual data itself depending on the span type.
- * Spanner spans get a horizontal rule; data spanners have their
- * data printed by matching data to header.
+ * Match data cells to column numbers.
*/
- switch (sp->pos) {
- case TBL_SPAN_HORIZ:
- /* FALLTHROUGH */
- case TBL_SPAN_DHORIZ:
- tbl_hrule(tp, sp);
- break;
- case TBL_SPAN_DATA:
- /* Iterate over template headers. */
+ if (sp->pos == TBL_SPAN_DATA) {
+ cp = sp->layout->first;
dp = sp->first;
spans = 0;
- for (hp = sp->head; hp; hp = hp->next) {
+ for (ic = 0; ic < sp->opts->cols; ic++) {
/*
- * If the current data header is invoked during
- * a spanner ("spans" > 0), don't emit anything
- * at all.
+ * Remeber whether we need a vertical bar
+ * after this cell.
*/
- if (--spans >= 0)
- continue;
-
- /* Separate columns. */
+ vert = cp == NULL ? 0 : cp->vert;
- if (NULL != hp->prev)
- tbl_vrule(tp, hp);
+ /*
+ * Print the data and advance to the next cell.
+ */
- col = &tp->tbl.cols[hp->ident];
- tbl_data(tp, sp->opts, dp, col);
+ if (spans == 0) {
+ tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic);
+ if (dp != NULL) {
+ spans = dp->spans;
+ dp = dp->next;
+ }
+ } else
+ spans--;
+ if (cp != NULL)
+ cp = cp->next;
/*
- * Go to the next data cell and assign the
- * number of subsequent spans, if applicable.
+ * Separate columns, except in the middle
+ * of spans and after the last cell.
*/
- if (dp) {
- spans = dp->spans;
- dp = dp->next;
- }
+ if (ic + 1 == sp->opts->cols || spans)
+ continue;
+
+ tbl_char(tp, ASCII_NBRSP, 1);
+ if (vert > 0)
+ tbl_char(tp, '|', vert);
+ if (vert < 2)
+ tbl_char(tp, ASCII_NBRSP, 2 - vert);
}
- break;
- }
+ } else if (horiz)
+ tbl_hrule(tp, sp, 0);
/* Vertical frame at the end of each row. */
- if ((TBL_OPT_BOX | TBL_OPT_DBOX) & sp->opts->opts ||
- sp->layout->vert)
- term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
- TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
+ 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);
/*
@@ -172,88 +189,67 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* existing table configuration and set it to NULL.
*/
- if (TBL_SPAN_LAST & sp->flags) {
- if (TBL_OPT_DBOX & sp->opts->opts ||
- TBL_OPT_BOX & sp->opts->opts) {
- tbl_hframe(tp, sp, 0);
+ if (sp->next == NULL) {
+ if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
+ tbl_hrule(tp, sp, 1);
tp->skipvsp = 1;
}
- if (TBL_OPT_DBOX & sp->opts->opts) {
- tbl_hframe(tp, sp, 1);
+ if (sp->opts->opts & TBL_OPT_DBOX) {
+ tbl_hrule(tp, sp, 2);
tp->skipvsp = 2;
}
assert(tp->tbl.cols);
free(tp->tbl.cols);
tp->tbl.cols = NULL;
+ tp->offset = offset;
}
tp->flags &= ~TERMP_NONOSPACE;
tp->rmargin = rmargin;
tp->maxrmargin = maxrmargin;
-
-}
-
-/*
- * Horizontal rules extend across the entire table.
- * Calculate the width by iterating over columns.
- */
-static size_t
-tbl_rulewidth(struct termp *tp, const struct tbl_head *hp)
-{
- size_t width;
-
- width = tp->tbl.cols[hp->ident].width;
-
- /* Account for leading blanks. */
- if (hp->prev)
- width += 2 - hp->vert;
-
- /* Account for trailing blank. */
- width++;
-
- return(width);
}
/*
- * Rules inside the table can be single or double
- * and have crossings with vertical rules marked with pluses.
+ * 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)
*/
static void
-tbl_hrule(struct termp *tp, const struct tbl_span *sp)
+tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
{
- const struct tbl_head *hp;
- char c;
-
- c = '-';
- if (TBL_SPAN_DHORIZ == sp->pos)
- c = '=';
-
- for (hp = sp->head; hp; hp = hp->next) {
- if (hp->prev && hp->vert)
- tbl_char(tp, '+', hp->vert);
- tbl_char(tp, c, tbl_rulewidth(tp, hp));
+ const struct tbl_cell *c1, *c2;
+ int vert;
+ char line, cross;
+
+ line = (kind == 0 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
+ cross = (kind < 2) ? '+' : '-';
+
+ if (kind)
+ term_word(tp, "+");
+ c1 = sp->layout->first;
+ c2 = sp->prev == NULL ? NULL : sp->prev->layout->first;
+ if (c2 == c1)
+ c2 = NULL;
+ for (;;) {
+ tbl_char(tp, line, tp->tbl.cols[c1->col].width + 1);
+ vert = c1->vert;
+ if ((c1 = c1->next) == NULL)
+ break;
+ if (c2 != NULL) {
+ if (vert < c2->vert)
+ vert = c2->vert;
+ c2 = c2->next;
+ }
+ if (vert)
+ tbl_char(tp, cross, vert);
+ if (vert < 2)
+ tbl_char(tp, line, 2 - vert);
}
-}
-
-/*
- * Rules above and below the table are always single
- * and have an additional plus at the beginning and end.
- * For double frames, this function is called twice,
- * and the outer one does not have crossings.
- */
-static void
-tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
-{
- const struct tbl_head *hp;
-
- term_word(tp, "+");
- for (hp = sp->head; hp; hp = hp->next) {
- if (hp->prev && hp->vert)
- tbl_char(tp, (outer ? '-' : '+'), hp->vert);
- tbl_char(tp, '-', tbl_rulewidth(tp, hp));
+ if (kind) {
+ term_word(tp, "+");
+ term_flushln(tp);
}
- term_word(tp, "+");
- term_flushln(tp);
}
static void
@@ -262,11 +258,10 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
const struct roffcol *col)
{
- if (NULL == dp) {
+ if (dp == NULL) {
tbl_char(tp, ASCII_NBRSP, col->width);
return;
}
- assert(dp->layout);
switch (dp->pos) {
case TBL_DATA_NONE:
@@ -315,17 +310,6 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
}
static void
-tbl_vrule(struct termp *tp, const struct tbl_head *hp)
-{
-
- tbl_char(tp, ASCII_NBRSP, 1);
- if (0 < hp->vert)
- tbl_char(tp, '|', hp->vert);
- if (2 > hp->vert)
- tbl_char(tp, ASCII_NBRSP, 2 - hp->vert);
-}
-
-static void
tbl_char(struct termp *tp, char c, size_t len)
{
size_t i, sz;
@@ -344,17 +328,16 @@ static void
tbl_literal(struct termp *tp, const struct tbl_dat *dp,
const struct roffcol *col)
{
- struct tbl_head *hp;
- size_t width, len, padl, padr;
- int spans;
+ size_t len, padl, padr, width;
+ int ic, spans;
assert(dp->string);
len = term_strlen(tp, dp->string);
-
- hp = dp->layout->head->next;
width = col->width;
- for (spans = dp->spans; spans--; hp = hp->next)
- width += tp->tbl.cols[hp->ident].width + 3;
+ ic = dp->layout->col;
+ spans = dp->spans;
+ while (spans--)
+ width += tp->tbl.cols[++ic].width + 3;
padr = width > len ? width - len : 0;
padl = 0;
@@ -407,8 +390,7 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
psz = term_strlen(tp, buf);
- if (NULL != (cp = strrchr(dp->string, opts->decimal))) {
- buf[1] = '\0';
+ if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
buf[0] = dp->string[i];
ssz += term_strlen(tp, buf);
@@ -417,9 +399,13 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
} else
d = sz + psz;
- padl = col->decimal - d;
-
- tbl_char(tp, ASCII_NBRSP, padl);
+ if (col->decimal > d && col->width > sz) {
+ padl = col->decimal - d;
+ if (padl + sz > col->width)
+ padl = col->width - sz;
+ tbl_char(tp, ASCII_NBRSP, padl);
+ } else
+ padl = 0;
tbl_word(tp, dp);
if (col->width > sz + padl)
tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
@@ -428,9 +414,9 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
static void
tbl_word(struct termp *tp, const struct tbl_dat *dp)
{
- const void *prev_font;
+ int prev_font;
- prev_font = term_fontq(tp);
+ prev_font = tp->fonti;
if (dp->layout->flags & TBL_CELL_BOLD)
term_fontpush(tp, TERMFONT_BOLD);
else if (dp->layout->flags & TBL_CELL_ITALIC)
diff --git a/term.c b/term.c
index 33f8f90027ac..75c12f4af21e 100644
--- a/term.c
+++ b/term.c
@@ -1,7 +1,7 @@
-/* $Id: term.c,v 1.237 2014/12/02 10:08:06 schwarze Exp $ */
+/* $Id: term.c,v 1.244 2015/01/31 00:12:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -43,6 +43,7 @@ term_free(struct termp *p)
{
free(p->buf);
+ free(p->fontq);
free(p);
}
@@ -100,7 +101,6 @@ term_flushln(struct termp *p)
size_t j; /* temporary loop index for p->buf */
size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */
- size_t rmargin; /* the rightmost of the two margins */
/*
* First, establish the maximum columns of "visible" content.
@@ -113,8 +113,7 @@ term_flushln(struct termp *p)
* is negative, it gets sign extended. Subtracting that
* very large size_t effectively adds a small number to dv.
*/
- rmargin = p->rmargin > p->offset ? p->rmargin : p->offset;
- dv = p->rmargin - p->offset;
+ dv = p->rmargin > p->offset ? p->rmargin - p->offset : 0;
maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
if (p->flags & TERMP_NOBREAK) {
@@ -192,8 +191,9 @@ term_flushln(struct termp *p)
(*p->endline)(p);
p->viscol = 0;
if (TERMP_BRIND & p->flags) {
- vbl = rmargin;
- vend += rmargin - p->offset;
+ vbl = p->rmargin;
+ vend += p->rmargin;
+ vend -= p->offset;
} else
vbl = p->offset;
@@ -273,7 +273,7 @@ term_flushln(struct termp *p)
}
if (TERMP_HANG & p->flags) {
- p->overstep = (int)(vis - maxvis +
+ p->overstep += (int)(p->offset + vis - p->rmargin +
p->trailspace * (*p->width)(p, ' '));
/*
@@ -329,6 +329,7 @@ term_vspace(struct termp *p)
(*p->endline)(p);
}
+/* Swap current and previous font; for \fP and .ft P */
void
term_fontlast(struct termp *p)
{
@@ -339,6 +340,7 @@ term_fontlast(struct termp *p)
p->fontq[p->fonti] = f;
}
+/* Set font, save current, discard previous; for \f, .ft, .B etc. */
void
term_fontrepl(struct termp *p, enum termfont f)
{
@@ -347,38 +349,31 @@ term_fontrepl(struct termp *p, enum termfont f)
p->fontq[p->fonti] = f;
}
+/* Set font, save previous. */
void
term_fontpush(struct termp *p, enum termfont f)
{
- assert(p->fonti + 1 < 10);
p->fontl = p->fontq[p->fonti];
- p->fontq[++p->fonti] = f;
-}
-
-const void *
-term_fontq(struct termp *p)
-{
-
- return(&p->fontq[p->fonti]);
-}
-
-enum termfont
-term_fonttop(struct termp *p)
-{
-
- return(p->fontq[p->fonti]);
+ if (++p->fonti == p->fontsz) {
+ p->fontsz += 8;
+ p->fontq = mandoc_reallocarray(p->fontq,
+ p->fontsz, sizeof(enum termfont *));
+ }
+ p->fontq[p->fonti] = f;
}
+/* Flush to make the saved pointer current again. */
void
-term_fontpopq(struct termp *p, const void *key)
+term_fontpopq(struct termp *p, int i)
{
- while (p->fonti >= 0 && key < (void *)(p->fontq + p->fonti))
- p->fonti--;
- assert(p->fonti >= 0);
+ assert(i >= 0);
+ if (p->fonti > i)
+ p->fonti = i;
}
+/* Pop one font off the stack. */
void
term_fontpop(struct termp *p)
{
@@ -492,6 +487,17 @@ term_word(struct termp *p, const char *word)
case ESCAPE_SKIPCHAR:
p->flags |= TERMP_SKIPCHAR;
continue;
+ case ESCAPE_OVERSTRIKE:
+ cp = seq + sz;
+ while (seq < cp) {
+ if (*seq == '\\') {
+ mandoc_escape(&seq, NULL, NULL);
+ continue;
+ }
+ encode1(p, *seq++);
+ if (seq < cp)
+ encode(p, "\b", 1);
+ }
default:
continue;
}
@@ -554,7 +560,7 @@ encode1(struct termp *p, int c)
if (p->col + 6 >= p->maxcols)
adjbuf(p, p->col + 6);
- f = term_fonttop(p);
+ f = p->fontq[p->fonti];
if (TERMFONT_UNDER == f || TERMFONT_BI == f) {
p->buf[p->col++] = '_';
@@ -586,7 +592,7 @@ encode(struct termp *p, const char *word, size_t sz)
* character by character.
*/
- if (TERMFONT_NONE == term_fonttop(p)) {
+ if (p->fontq[p->fonti] == TERMFONT_NONE) {
if (p->col + sz >= p->maxcols)
adjbuf(p, p->col + sz);
for (i = 0; i < sz; i++)
@@ -713,6 +719,20 @@ term_strlen(const struct termp *p, const char *cp)
case ESCAPE_SKIPCHAR:
skip = 1;
continue;
+ case ESCAPE_OVERSTRIKE:
+ rsz = 0;
+ rhs = seq + ssz;
+ while (seq < rhs) {
+ if (*seq == '\\') {
+ mandoc_escape(&seq, NULL, NULL);
+ continue;
+ }
+ i = (*p->width)(p, *seq++);
+ if (rsz < i)
+ rsz = i;
+ }
+ sz += rsz;
+ continue;
default:
continue;
}
@@ -766,47 +786,55 @@ term_strlen(const struct termp *p, const char *cp)
return(sz);
}
-size_t
+int
term_vspan(const struct termp *p, const struct roffsu *su)
{
double r;
+ int ri;
switch (su->unit) {
+ case SCALE_BU:
+ r = su->scale / 40.0;
+ break;
case SCALE_CM:
- r = su->scale * 2.0;
+ r = su->scale * 6.0 / 2.54;
+ break;
+ case SCALE_FS:
+ r = su->scale * 65536.0 / 40.0;
break;
case SCALE_IN:
r = su->scale * 6.0;
break;
+ case SCALE_MM:
+ r = su->scale * 0.006;
+ break;
case SCALE_PC:
r = su->scale;
break;
case SCALE_PT:
- r = su->scale / 8.0;
+ r = su->scale / 12.0;
break;
- case SCALE_MM:
- r = su->scale / 1000.0;
+ case SCALE_EN:
+ /* FALLTHROUGH */
+ case SCALE_EM:
+ r = su->scale * 0.6;
break;
case SCALE_VS:
r = su->scale;
break;
default:
- r = su->scale - 1.0;
- break;
+ abort();
+ /* NOTREACHED */
}
-
- if (r < 0.0)
- r = 0.0;
- return((size_t)(r + 0.0005));
+ ri = r > 0.0 ? r + 0.4995 : r - 0.4995;
+ return(ri < 66 ? ri : 1);
}
-size_t
+int
term_hspan(const struct termp *p, const struct roffsu *su)
{
double v;
v = (*p->hspan)(p, su);
- if (v < 0.0)
- v = 0.0;
- return((size_t)(v + 0.0005));
+ return(v > 0.0 ? v + 0.0005 : v - 0.0005);
}
diff --git a/term.h b/term.h
index 62c6ffe8af89..b65524b610c4 100644
--- a/term.h
+++ b/term.h
@@ -1,4 +1,4 @@
-/* $Id: term.h,v 1.108 2014/12/02 10:08:06 schwarze Exp $ */
+/* $Id: term.h,v 1.111 2015/01/31 00:12:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -84,7 +84,8 @@ struct termp {
enum termenc enc; /* Type of encoding. */
const struct mchars *symtab; /* Character table. */
enum termfont fontl; /* Last font set. */
- enum termfont fontq[10]; /* Symmetric fonts. */
+ enum termfont *fontq; /* Symmetric fonts. */
+ int fontsz; /* Allocated size of font stack */
int fonti; /* Index of font stack. */
term_margin headf; /* invoked to print head */
term_margin footf; /* invoked to print foot */
@@ -120,18 +121,14 @@ void term_begin(struct termp *, term_margin,
void term_end(struct termp *);
void term_setwidth(struct termp *, const char *);
-size_t term_hspan(const struct termp *,
- const struct roffsu *);
-size_t term_vspan(const struct termp *,
- const struct roffsu *);
+int term_hspan(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);
-enum termfont term_fonttop(struct termp *);
-const void *term_fontq(struct termp *);
void term_fontpush(struct termp *, enum termfont);
void term_fontpop(struct termp *);
-void term_fontpopq(struct termp *, const void *);
+void term_fontpopq(struct termp *, int);
void term_fontrepl(struct termp *, enum termfont);
void term_fontlast(struct termp *);
diff --git a/term_ascii.c b/term_ascii.c
index 71d8af4c6c79..4ce4b686c4f5 100644
--- a/term_ascii.c
+++ b/term_ascii.c
@@ -1,4 +1,4 @@
-/* $Id: term_ascii.c,v 1.40 2014/11/20 13:56:20 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.43 2015/02/16 14:11:41 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -63,12 +63,17 @@ ascii_init(enum termenc enc, const struct mchars *mchars, char *outopts)
const char *toks[5];
char *v;
struct termp *p;
+ const char *errstr;
+ int num;
p = mandoc_calloc(1, sizeof(struct termp));
p->symtab = mchars;
p->tabwidth = 5;
p->defrmargin = p->lastrmargin = 78;
+ p->fontq = mandoc_reallocarray(NULL,
+ (p->fontsz = 8), sizeof(enum termfont));
+ p->fontq[0] = p->fontl = TERMFONT_NONE;
p->begin = ascii_begin;
p->end = ascii_end;
@@ -106,10 +111,14 @@ ascii_init(enum termenc enc, const struct mchars *mchars, char *outopts)
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
case 0:
- p->defindent = (size_t)atoi(v);
+ num = strtonum(v, 0, 1000, &errstr);
+ if (!errstr)
+ p->defindent = num;
break;
case 1:
- p->defrmargin = (size_t)atoi(v);
+ num = strtonum(v, 0, 1000, &errstr);
+ if (!errstr)
+ p->defrmargin = num;
break;
case 2:
/*
@@ -171,6 +180,20 @@ ascii_setwidth(struct termp *p, int iop, size_t width)
p->rmargin = p->maxrmargin = p->defrmargin;
}
+void
+ascii_sepline(void *arg)
+{
+ struct termp *p;
+ size_t i;
+
+ p = (struct termp *)arg;
+ putchar('\n');
+ for (i = 0; i < p->defrmargin; i++)
+ putchar('-');
+ putchar('\n');
+ putchar('\n');
+}
+
static size_t
ascii_width(const struct termp *p, int c)
{
diff --git a/term_ps.c b/term_ps.c
index e3299d70640b..12ca7d67165c 100644
--- a/term_ps.c
+++ b/term_ps.c
@@ -1,7 +1,7 @@
-/* $Id: term_ps.c,v 1.70 2014/12/01 08:05:52 schwarze Exp $ */
+/* $Id: term_ps.c,v 1.72 2015/01/21 19:40:54 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -60,6 +60,7 @@ struct termp_ps {
#define PS_NEWPAGE (1 << 2) /* new page, no words yet */
#define PS_BACKSP (1 << 3) /* last character was backspace */
size_t pscol; /* visible column (AFM units) */
+ size_t pscolnext; /* used for overstrike */
size_t psrow; /* visible row (AFM units) */
char *psmarg; /* margin buf */
size_t psmargsz; /* margin buf size */
@@ -540,6 +541,9 @@ pspdf_alloc(const struct mchars *mchars, char *outopts)
p = mandoc_calloc(1, sizeof(struct termp));
p->symtab = mchars;
p->enc = TERMENC_ASCII;
+ p->fontq = mandoc_reallocarray(NULL,
+ (p->fontsz = 8), sizeof(enum termfont));
+ p->fontq[0] = p->fontl = TERMFONT_NONE;
p->ps = mandoc_calloc(1, sizeof(struct termp_ps));
p->advance = ps_advance;
@@ -1069,7 +1073,7 @@ ps_fclose(struct termp *p)
static void
ps_letter(struct termp *p, int arg)
{
- size_t savecol;
+ size_t savecol, wx;
char c;
c = arg >= 128 || arg <= 0 ? '?' : arg;
@@ -1141,7 +1145,30 @@ ps_letter(struct termp *p, int arg)
ps_setfont(p, p->ps->nextf);
}
p->ps->nextf = TERMFONT_NONE;
+
+ /*
+ * For an overstrike, if a previous character
+ * was wider, advance to center the new one.
+ */
+
+ if (p->ps->pscolnext) {
+ wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx;
+ if (p->ps->pscol + wx < p->ps->pscolnext)
+ p->ps->pscol = (p->ps->pscol +
+ p->ps->pscolnext - wx) / 2;
+ }
+
ps_pletter(p, p->ps->last);
+
+ /*
+ * For an overstrike, if a previous character
+ * was wider, advance to the end of the old one.
+ */
+
+ if (p->ps->pscol < p->ps->pscolnext) {
+ ps_pclose(p);
+ p->ps->pscol = p->ps->pscolnext;
+ }
}
/*
@@ -1155,13 +1182,19 @@ ps_letter(struct termp *p, int arg)
/*
* For an overstrike, back up to the previous position.
+ * If the previous character is wider than any it overstrikes,
+ * remember the current position, because it might also be
+ * wider than all that will overstrike it.
*/
if (savecol != SIZE_MAX) {
+ if (p->ps->pscolnext < p->ps->pscol)
+ p->ps->pscolnext = p->ps->pscol;
ps_pclose(p);
p->ps->pscol = savecol;
p->ps->flags &= ~PS_BACKSP;
- }
+ } else
+ p->ps->pscolnext = 0;
}
static void
diff --git a/test-strtonum.c b/test-strtonum.c
new file mode 100644
index 000000000000..ce70dd660513
--- /dev/null
+++ b/test-strtonum.c
@@ -0,0 +1,42 @@
+/* $Id: test-strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $ */
+/*
+ * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+int
+main(void)
+{
+ const char *errstr;
+
+ if (strtonum("1", 0, 2, &errstr) != 1)
+ return(1);
+ if (errstr != NULL)
+ return(2);
+ if (strtonum("1x", 0, 2, &errstr) != 0)
+ return(3);
+ if (errstr == NULL)
+ return(4);
+ if (strtonum("2", 0, 1, &errstr) != 0)
+ return(5);
+ if (errstr == NULL)
+ return(6);
+ if (strtonum("0", 1, 2, &errstr) != 0)
+ return(7);
+ if (errstr == NULL)
+ return(8);
+ return(0);
+}
diff --git a/tree.c b/tree.c
index 4753219c8e7f..a5a7f2c7d232 100644
--- a/tree.c
+++ b/tree.c
@@ -1,7 +1,7 @@
-/* $Id: tree.c,v 1.60 2014/11/28 05:51:32 schwarze Exp $ */
+/* $Id: tree.c,v 1.62 2015/02/05 00:14:13 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -40,14 +40,14 @@ void
tree_mdoc(void *arg, const struct mdoc *mdoc)
{
- print_mdoc(mdoc_node(mdoc), 0);
+ print_mdoc(mdoc_node(mdoc)->child, 0);
}
void
tree_man(void *arg, const struct man *man)
{
- print_man(man_node(man), 0);
+ print_man(man_node(man)->child, 0);
}
static void
@@ -58,6 +58,9 @@ print_mdoc(const struct mdoc_node *n, int indent)
size_t argc;
struct mdoc_argv *argv;
+ if (n == NULL)
+ return;
+
argv = NULL;
argc = 0;
t = p = NULL;
@@ -142,7 +145,7 @@ print_mdoc(const struct mdoc_node *n, int indent)
print_span(n->span, indent);
} else {
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
printf("%s (%s)", p, t);
@@ -159,16 +162,14 @@ print_mdoc(const struct mdoc_node *n, int indent)
putchar(' ');
if (MDOC_LINE & n->flags)
putchar('*');
- printf("%d:%d", n->line, n->pos + 1);
- if (n->lastline != n->line)
- printf("-%d", n->lastline);
- putchar('\n');
+ printf("%d:%d\n", n->line, n->pos + 1);
}
if (n->eqn)
- print_box(n->eqn->root->first, indent + 1);
+ print_box(n->eqn->root->first, indent + 4);
if (n->child)
- print_mdoc(n->child, indent + 1);
+ print_mdoc(n->child, indent +
+ (n->type == MDOC_BLOCK ? 2 : 4));
if (n->next)
print_mdoc(n->next, indent);
}
@@ -179,6 +180,9 @@ print_man(const struct man_node *n, int indent)
const char *p, *t;
int i;
+ if (n == NULL)
+ return;
+
t = p = NULL;
switch (n->type) {
@@ -241,7 +245,7 @@ print_man(const struct man_node *n, int indent)
print_span(n->span, indent);
} else {
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
printf("%s (%s) ", p, t);
if (MAN_LINE & n->flags)
putchar('*');
@@ -249,9 +253,10 @@ print_man(const struct man_node *n, int indent)
}
if (n->eqn)
- print_box(n->eqn->root->first, indent + 1);
+ print_box(n->eqn->root->first, indent + 4);
if (n->child)
- print_man(n->child, indent + 1);
+ print_man(n->child, indent +
+ (n->type == MAN_BLOCK ? 2 : 4));
if (n->next)
print_man(n->next, indent);
}
@@ -270,7 +275,7 @@ print_box(const struct eqn_box *ep, int indent)
if (NULL == ep)
return;
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
t = NULL;
switch (ep->type) {
@@ -318,7 +323,7 @@ print_box(const struct eqn_box *ep, int indent)
printf(" args=%zu", ep->args);
putchar('\n');
- print_box(ep->first, indent + 1);
+ print_box(ep->first, indent + 4);
print_box(ep->next, indent);
}
@@ -329,7 +334,7 @@ print_span(const struct tbl_span *sp, int indent)
int i;
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
switch (sp->pos) {
case TBL_SPAN_HORIZ: