Import CVS snapshot of mandoc as of 20150302

This commit is contained in:
bapt 2015-03-02 16:45:41 +00:00
parent e28888b1f6
commit ecbd8af4a3
77 changed files with 5322 additions and 3715 deletions

View File

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

View File

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

View File

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

30
Makefile.local Normal file
View File

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

42
TODO
View File

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

View File

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

36
cgi.c
View File

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

View File

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

View File

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

View File

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

76
compat_strtonum.c Normal file
View File

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

16
configure vendored
View File

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

View File

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

View File

@ -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 @@ pstring(const char *p, int col, int *colp, int list)
end = p - 1;
while (end > start)
if ('.' == *end || ',' == *end ||
if ('.' == *end || ',' == *end ||
'\'' == *end || '"' == *end ||
')' == *end || '!' == *end ||
'?' == *end || ':' == *end ||
@ -199,7 +200,7 @@ pstring(const char *p, int col, int *colp, int list)
/*
* 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);
}
}

11
eqn.7
View File

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

125
eqn.c
View File

@ -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 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
/* 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 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
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 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
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 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
* 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

View File

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

View File

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

22
gmdiff
View File

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

55
html.c
View File

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

View File

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

View File

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

View File

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

View File

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

311
main.c
View File

@ -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;
}
if (mparse_wait(curp.mp) != MANDOCLEVEL_OK)
rc = MANDOCLEVEL_SYSERR;
rctmp = mparse_wait(curp.mp);
if (rc < rctmp)
rc = rctmp;
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,50 +468,44 @@ 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);
return((int)rc);
}
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 @@ passthrough(const char *file, int fd, int synopsis_only)
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);
}

4
main.h
View File

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

View File

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

89
man.1
View File

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

127
man.7
View File

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

134
man.c
View File

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

4
man.h
View File

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

View File

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

View File

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

View File

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

View File

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

549
mandoc.1
View File

@ -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 last node in the NAME section is not an
The NAME section does not contain any
.Ic \&Nm
child macro.
.It Sy "NAME section without description"
.Pq mdoc
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 ,
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
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
.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
.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.

View File

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

View File

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

View File

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

114
mandoc.h
View File

@ -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 */
/* 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 */
MANDOCERR_ERROR, /* ===== start of errors ===== */
/* 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 */
/* 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;
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 *prev;
struct tbl_span *next;
int line; /* parse line */
enum tbl_spant pos;
};
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,

View File

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

View File

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

View File

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

View File

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

View File

@ -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 @@ main(int argc, char *argv[])
/* 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);

View File

@ -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)
@ -730,29 +752,6 @@ exprcomp(const struct mansearch *search, int argc, char *argv[])
return(NULL);
}
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)
{

212
mdoc.7
View File

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

23
mdoc.c
View File

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

12
mdoc.h
View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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) {
@ -634,16 +620,47 @@ termp_it_pre(DECL_ARGS)
bl = n->parent->parent->parent;
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 */
@ -1986,6 +1977,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)
{

File diff suppressed because it is too large Load Diff

3
msec.c
View File

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

151
out.c
View File

@ -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++;
break;
case '-':
buf[i++] = *src++;
break;
default:
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) {
switch (*endptr++) {
case 'c':
unit = SCALE_CM;
dst->unit = SCALE_CM;
break;
case 'i':
unit = SCALE_IN;
break;
case 'P':
unit = SCALE_PC;
break;
case 'p':
unit = SCALE_PT;
dst->unit = SCALE_IN;
break;
case 'f':
unit = SCALE_FS;
break;
case 'v':
unit = SCALE_VS;
break;
case 'm':
unit = SCALE_EM;
break;
case '\0':
if (SCALE_MAX == def)
return(0);
unit = def;
break;
case 'u':
unit = SCALE_BU;
dst->unit = SCALE_FS;
break;
case 'M':
unit = SCALE_MM;
dst->unit = SCALE_MM;
break;
case 'm':
dst->unit = SCALE_EM;
break;
case 'n':
unit = SCALE_EN;
dst->unit = SCALE_EN;
break;
case 'P':
dst->unit = SCALE_PC;
break;
case 'p':
dst->unit = SCALE_PT;
break;
case 'u':
dst->unit = SCALE_BU;
break;
case 'v':
dst->unit = SCALE_VS;
break;
case '\0':
endptr--;
/* FALLTHROUGH */
default:
return(0);
if (SCALE_MAX == def)
return(0);
dst->unit = def;
break;
}
/* 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;
}
}
}

133
preconv.c
View File

@ -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;
nby = 1;
while (nby < 5 && *cu & (1 << (7 - nby)))
nby++;
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;
}
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;
}
/* FALLTHROUGH: Invalid or incomplete UTF-8 sequence. */
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++;
}
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))

264
read.c
View File

@ -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 \"\"",
/* related to tables */
"tbl line starts with span",
"tbl column starts with span",
"skipping vertical bar in tbl layout",
"generic error",
/* related to equations */
"unexpected equation scope closure",
"equation scope open on exit",
"overlapping equation scopes",
"unexpected end of equation",
/* 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 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
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,27 +540,32 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
*/
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:
break;
}
/*
* 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
@ -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)

884
roff.7

File diff suppressed because it is too large Load Diff

845
roff.c

File diff suppressed because it is too large Load Diff

90
st.in
View File

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

View File

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

129
tbl.3
View File

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

143
tbl.7
View File

@ -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 doublebox
Draw a double-line box around the table.
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 linesize
Accepts a natural number (all digits).
This option is not supported by
.Xr mandoc 1 .
.It Cm nokeep
This option is not supported by
.Xr mandoc 1 .
.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
Accepts a single-character argument.
This character will be used as the decimal point with the
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.
For GNU compatibility, this may also be invoked with
.Cm doubleframe .
.It Cm expand
Increase the width of the table to the current line length.
Currently ignored.
.It Cm linesize
Draw lines with the point size given by the unsigned integer argument.
Currently ignored.
.It Cm nokeep
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 ,

115
tbl.c
View File

@ -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->part == TBL_PART_CDATA)
mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
tbl->line, tbl->pos, "TE");
if (tbl->last_span)
tbl->last_span->flags |= TBL_SPAN_LAST;
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);
}

View File

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

View File

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

View File

@ -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;
/* Not all types accept modifiers. */
switch (cp->pos) {
case TBL_CELL_DOWN:
/* FALLTHROUGH */
case TBL_CELL_HORIZ:
/* FALLTHROUGH */
case TBL_CELL_DHORIZ:
return(1);
default:
break;
}
char *endptr;
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;
}
while (p[*pos] == ' ' || p[*pos] == '\t')
(*pos)++;
/* Row delimiters and cell specifiers end modifier lists. */
if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL)
return;
/* Throw away parenthesised expression. */
@ -117,123 +82,138 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
(*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)++;
}
again:
while (p[*pos] == ' ' || p[*pos] == '\t')
(*pos)++;
/* Handle trailing vertical lines */
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?
*/
/* Special cases of spanners. */
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.
*/
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;
if (tbl->opts.cols <= p->col)
tbl->opts.cols = p->col + 1;
/* 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;
p->head = hp;
return(p);
}

View File

@ -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 (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);
if (')' == p[(*pos)++])
return(1);
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:]+ [)]
*/
if (p[pos] == ';') {
*offs = pos + 1;
return;
}
while (isspace((unsigned char)p[*pos]))
(*pos)++;
/* Parse one option name. */
/* Safe exit point. */
len = 0;
while (isalpha((unsigned char)p[pos + len]))
len++;
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;
}
/* Exit if buffer is empty (or overrun). */
if (KEY_MAXNAME == i || 0 == i) {
mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
return;
}
buf[i] = '\0';
while (isspace((unsigned char)p[*pos]) || p[*pos] == ',')
(*pos)++;
/*
* Look through all of the available keys to find one that
* matches the input. FIXME: hashtable this.
*/
for (i = 0; i < KEY_MAXKEYS; i++) {
if (strcmp(buf, keys[i].name))
if (len == 0) {
mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
tbl->parse, ln, pos, "%c", p[pos]);
pos++;
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.
*/
/* Look up the option name. */
i = 0;
while (i < KEY_MAXKEYS &&
(strncasecmp(p + pos, keys[i].name, len) ||
keys[i].name[len] != '\0'))
i++;
if (i == KEY_MAXKEYS) {
mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
ln, pos, "%.*s", len, p + pos);
pos += len;
continue;
}
/* 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);
}

View File

@ -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. */
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);
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 (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)
vert = cp == NULL ? 0 : cp->vert;
/*
* Print the data and advance to the next cell.
*/
if (spans == 0) {
tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic);
if (dp != NULL) {
spans = dp->spans;
dp = dp->next;
}
} else
spans--;
if (cp != NULL)
cp = cp->next;
/*
* Separate columns, except in the middle
* of spans and after the last cell.
*/
if (ic + 1 == sp->opts->cols || spans)
continue;
/* Separate columns. */
if (NULL != hp->prev)
tbl_vrule(tp, hp);
col = &tp->tbl.cols[hp->ident];
tbl_data(tp, sp->opts, dp, col);
/*
* Go to the next data cell and assign the
* number of subsequent spans, if applicable.
*/
if (dp) {
spans = dp->spans;
dp = dp->next;
}
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;
const struct tbl_cell *c1, *c2;
int vert;
char line, cross;
c = '-';
if (TBL_SPAN_DHORIZ == sp->pos)
c = '=';
line = (kind == 0 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
cross = (kind < 2) ? '+' : '-';
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));
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:
@ -314,17 +309,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)
{
@ -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)

118
term.c
View File

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

15
term.h
View File

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

View File

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

View File

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

42
test-strtonum.c Normal file
View File

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

39
tree.c
View File

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