summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorMichal Nowak <mnowak@startmail.com>2019-05-30 07:50:30 +0200
committerDan McDonald <danmcd@joyent.com>2019-06-21 14:59:14 -0400
commitcec8643b41ebefad6c677010fc784dc4bb0550f3 (patch)
treec4eca564abb29cbe5a704a1a1b182a6d0cb526fc /usr/src/cmd
parent07188943efdbeedd24142a14db7384af1478ba54 (diff)
downloadillumos-joyent-cec8643b41ebefad6c677010fc784dc4bb0550f3.tar.gz
11190 Update mandoc to 1.14.5
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Gergő Doma <domag02@gmail.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/mandoc/Makefile.common4
-rw-r--r--usr/src/cmd/mandoc/THIRDPARTYLICENSE15
-rw-r--r--usr/src/cmd/mandoc/arch.c54
-rw-r--r--usr/src/cmd/mandoc/att.c4
-rw-r--r--usr/src/cmd/mandoc/chars.c37
-rw-r--r--usr/src/cmd/mandoc/config.h2
-rw-r--r--usr/src/cmd/mandoc/dbm.c12
-rw-r--r--usr/src/cmd/mandoc/eqn.c93
-rw-r--r--usr/src/cmd/mandoc/eqn.h72
-rw-r--r--usr/src/cmd/mandoc/eqn_html.c3
-rw-r--r--usr/src/cmd/mandoc/eqn_parse.h48
-rw-r--r--usr/src/cmd/mandoc/eqn_term.c6
-rw-r--r--usr/src/cmd/mandoc/html.c277
-rw-r--r--usr/src/cmd/mandoc/html.h19
-rw-r--r--usr/src/cmd/mandoc/lib.c5
-rw-r--r--usr/src/cmd/mandoc/libman.h22
-rw-r--r--usr/src/cmd/mandoc/libmandoc.h54
-rw-r--r--usr/src/cmd/mandoc/libmdoc.h16
-rw-r--r--usr/src/cmd/mandoc/libroff.h80
-rw-r--r--usr/src/cmd/mandoc/main.c223
-rw-r--r--usr/src/cmd/mandoc/main.h24
-rw-r--r--usr/src/cmd/mandoc/man.c170
-rw-r--r--usr/src/cmd/mandoc/man.h3
-rw-r--r--usr/src/cmd/mandoc/man_html.c465
-rw-r--r--usr/src/cmd/mandoc/man_macro.c214
-rw-r--r--usr/src/cmd/mandoc/man_term.c325
-rw-r--r--usr/src/cmd/mandoc/man_validate.c211
-rw-r--r--usr/src/cmd/mandoc/manconf.h8
-rw-r--r--usr/src/cmd/mandoc/mandoc.c316
-rw-r--r--usr/src/cmd/mandoc/mandoc.h241
-rw-r--r--usr/src/cmd/mandoc/mandoc_msg.c329
-rw-r--r--usr/src/cmd/mandoc/mandoc_parse.h43
-rw-r--r--usr/src/cmd/mandoc/mandocdb.c72
-rw-r--r--usr/src/cmd/mandoc/manpath.c24
-rw-r--r--usr/src/cmd/mandoc/mansearch.c20
-rw-r--r--usr/src/cmd/mandoc/mansearch.h3
-rw-r--r--usr/src/cmd/mandoc/mdoc.c59
-rw-r--r--usr/src/cmd/mandoc/mdoc.h5
-rw-r--r--usr/src/cmd/mandoc/mdoc_argv.c53
-rw-r--r--usr/src/cmd/mandoc/mdoc_html.c437
-rw-r--r--usr/src/cmd/mandoc/mdoc_macro.c272
-rw-r--r--usr/src/cmd/mandoc/mdoc_man.c111
-rw-r--r--usr/src/cmd/mandoc/mdoc_markdown.c66
-rw-r--r--usr/src/cmd/mandoc/mdoc_state.c60
-rw-r--r--usr/src/cmd/mandoc/mdoc_term.c150
-rw-r--r--usr/src/cmd/mandoc/mdoc_validate.c559
-rw-r--r--usr/src/cmd/mandoc/msec.c3
-rw-r--r--usr/src/cmd/mandoc/out.c334
-rw-r--r--usr/src/cmd/mandoc/out.h5
-rw-r--r--usr/src/cmd/mandoc/preconv.c5
-rw-r--r--usr/src/cmd/mandoc/read.c730
-rw-r--r--usr/src/cmd/mandoc/roff.c1299
-rw-r--r--usr/src/cmd/mandoc/roff.h86
-rw-r--r--usr/src/cmd/mandoc/roff_html.c51
-rw-r--r--usr/src/cmd/mandoc/roff_int.h58
-rw-r--r--usr/src/cmd/mandoc/roff_term.c48
-rw-r--r--usr/src/cmd/mandoc/roff_validate.c106
-rw-r--r--usr/src/cmd/mandoc/st.c54
-rw-r--r--usr/src/cmd/mandoc/st.in76
-rw-r--r--usr/src/cmd/mandoc/tag.c45
-rw-r--r--usr/src/cmd/mandoc/tag.h3
-rw-r--r--usr/src/cmd/mandoc/tbl.c76
-rw-r--r--usr/src/cmd/mandoc/tbl.h122
-rw-r--r--usr/src/cmd/mandoc/tbl_data.c113
-rw-r--r--usr/src/cmd/mandoc/tbl_html.c158
-rw-r--r--usr/src/cmd/mandoc/tbl_int.h47
-rw-r--r--usr/src/cmd/mandoc/tbl_layout.c34
-rw-r--r--usr/src/cmd/mandoc/tbl_opts.c22
-rw-r--r--usr/src/cmd/mandoc/tbl_parse.h30
-rw-r--r--usr/src/cmd/mandoc/tbl_term.c665
-rw-r--r--usr/src/cmd/mandoc/term.c491
-rw-r--r--usr/src/cmd/mandoc/term.h6
-rw-r--r--usr/src/cmd/mandoc/term_ascii.c13
-rw-r--r--usr/src/cmd/mandoc/term_tab.c2
-rw-r--r--usr/src/cmd/mandoc/tree.c96
75 files changed, 5927 insertions, 4137 deletions
diff --git a/usr/src/cmd/mandoc/Makefile.common b/usr/src/cmd/mandoc/Makefile.common
index f8834bb4a8..42d73be9f5 100644
--- a/usr/src/cmd/mandoc/Makefile.common
+++ b/usr/src/cmd/mandoc/Makefile.common
@@ -17,7 +17,8 @@
PROG= mandoc
-OBJS= att.o \
+OBJS= arch.o \
+ att.o \
chars.o \
dba.o \
dba_array.o \
@@ -39,6 +40,7 @@ OBJS= att.o \
man_validate.o \
mandoc.o \
mandoc_aux.o \
+ mandoc_msg.o \
mandoc_ohash.o \
mandoc_xr.o \
mandocdb.o \
diff --git a/usr/src/cmd/mandoc/THIRDPARTYLICENSE b/usr/src/cmd/mandoc/THIRDPARTYLICENSE
index 34420d2920..45ac298093 100644
--- a/usr/src/cmd/mandoc/THIRDPARTYLICENSE
+++ b/usr/src/cmd/mandoc/THIRDPARTYLICENSE
@@ -1,24 +1,25 @@
-$Id: LICENSE,v 1.17 2017/06/23 15:58:14 schwarze Exp $
+$Id: LICENSE,v 1.21 2018/11/26 17:11:11 schwarze Exp $
-With the exceptions noted below, all code and documentation
-contained in the mandoc toolkit is protected by the Copyright
-of the following developers:
+With the exceptions noted below, all non-trivial files contained
+in the mandoc toolkit are protected by the Copyright of the following
+developers:
Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
-Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 1999, 2004, 2017 Marc Espie <espie@openbsd.org>
Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
Copyright (c) 2014 Baptiste Daroussin <bapt@freebsd.org>
Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
-Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+Copyright (c) 2017 Anthony Bentley <bentley@openbsd.org>
Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
-See the individual source files for information about who contributed
+See the individual files for information about who contributed
to which file during which years.
diff --git a/usr/src/cmd/mandoc/arch.c b/usr/src/cmd/mandoc/arch.c
new file mode 100644
index 0000000000..56b937ec84
--- /dev/null
+++ b/usr/src/cmd/mandoc/arch.c
@@ -0,0 +1,54 @@
+/* $Id: arch.c,v 1.14 2019/03/04 13:01:57 schwarze Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include <string.h>
+
+#include "roff.h"
+
+int
+arch_valid(const char *arch, enum mandoc_os os)
+{
+ const char *openbsd_arch[] = {
+ "alpha", "amd64", "arm64", "armv7", "hppa", "i386",
+ "landisk", "loongson", "luna88k", "macppc", "mips64",
+ "octeon", "sgi", "socppc", "sparc64", NULL
+ };
+ const char *netbsd_arch[] = {
+ "acorn26", "acorn32", "algor", "alpha", "amiga",
+ "arc", "atari",
+ "bebox", "cats", "cesfic", "cobalt", "dreamcast",
+ "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5",
+ "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa",
+ "i386", "ibmnws", "luna68k",
+ "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc",
+ "netwinder", "news68k", "newsmips", "next68k",
+ "pc532", "playstation2", "pmax", "pmppc", "prep",
+ "sandpoint", "sbmips", "sgimips", "shark",
+ "sparc", "sparc64", "sun2", "sun3",
+ "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL
+ };
+ const char **arches[] = { NULL, netbsd_arch, openbsd_arch };
+ const char **arch_p;
+
+ if ((arch_p = arches[os]) == NULL)
+ return 1;
+ for (; *arch_p != NULL; arch_p++)
+ if (strcmp(*arch_p, arch) == 0)
+ return 1;
+ return 0;
+}
diff --git a/usr/src/cmd/mandoc/att.c b/usr/src/cmd/mandoc/att.c
index dd7f2a0d77..5575bed54a 100644
--- a/usr/src/cmd/mandoc/att.c
+++ b/usr/src/cmd/mandoc/att.c
@@ -1,4 +1,4 @@
-/* $Id: att.c,v 1.16 2017/06/24 14:38:32 schwarze Exp $ */
+/* $Id: att.c,v 1.18 2018/12/13 11:55:46 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -19,9 +19,7 @@
#include <sys/types.h>
#include <string.h>
-#include "mandoc.h"
#include "roff.h"
-#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
diff --git a/usr/src/cmd/mandoc/chars.c b/usr/src/cmd/mandoc/chars.c
index fb9ded8bae..24166dbd9f 100644
--- a/usr/src/cmd/mandoc/chars.c
+++ b/usr/src/cmd/mandoc/chars.c
@@ -1,7 +1,7 @@
-/* $Id: chars.c,v 1.73 2017/08/23 13:01:29 schwarze Exp $ */
+/* $Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +23,7 @@
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -47,20 +48,13 @@ static struct ln lines[] = {
{ " ", ascii_nbrsp, 0x00a0 },
{ "~", ascii_nbrsp, 0x00a0 },
{ "0", " ", 0x2002 },
- { "|", "", 0 },
- { "^", "", 0 },
- { "&", "", 0 },
- { "%", "", 0 },
{ ":", ascii_break, 0 },
- /* XXX The following three do not really belong here. */
- { "t", "", 0 },
- { "c", "", 0 },
- { "}", "", 0 },
/* Lines. */
{ "ba", "|", 0x007c },
{ "br", "|", 0x2502 },
{ "ul", "_", 0x005f },
+ { "_", "_", 0x005f },
{ "ru", "_", 0x005f },
{ "rn", "-", 0x203e },
{ "bb", "|", 0x00a6 },
@@ -82,10 +76,10 @@ static struct ln lines[] = {
{ "sh", "#", 0x0023 },
{ "CR", "<cr>", 0x21b5 },
{ "OK", "\\/", 0x2713 },
- { "CL", "<club>", 0x2663 },
- { "SP", "<spade>", 0x2660 },
- { "HE", "<heart>", 0x2665 },
- { "DI", "<diamond>", 0x2666 },
+ { "CL", "C", 0x2663 },
+ { "SP", "S", 0x2660 },
+ { "HE", "H", 0x2665 },
+ { "DI", "D", 0x2666 },
/* Legal symbols. */
{ "co", "(C)", 0x00a9 },
@@ -240,7 +234,7 @@ static struct ln lines[] = {
{ "Ah", "<Aleph>", 0x2135 },
{ "Im", "<Im>", 0x2111 },
{ "Re", "<Re>", 0x211c },
- { "wp", "P", 0x2118 },
+ { "wp", "p", 0x2118 },
{ "pd", "<del>", 0x2202 },
{ "-h", "/h", 0x210f },
{ "hbar", "/h", 0x210f },
@@ -287,6 +281,7 @@ static struct ln lines[] = {
{ "ho", ",", 0x02db },
{ "ha", "^", 0x005e },
{ "ti", "~", 0x007e },
+ { "u02DC", "~", 0x02dc },
/* Accented letters. */
{ "'A", "'\bA", 0x00c1 },
@@ -294,11 +289,13 @@ static struct ln lines[] = {
{ "'I", "'\bI", 0x00cd },
{ "'O", "'\bO", 0x00d3 },
{ "'U", "'\bU", 0x00da },
+ { "'Y", "'\bY", 0x00dd },
{ "'a", "'\ba", 0x00e1 },
{ "'e", "'\be", 0x00e9 },
{ "'i", "'\bi", 0x00ed },
{ "'o", "'\bo", 0x00f3 },
{ "'u", "'\bu", 0x00fa },
+ { "'y", "'\by", 0x00fd },
{ "`A", "`\bA", 0x00c0 },
{ "`E", "`\bE", 0x00c8 },
{ "`I", "`\bI", 0x00cc },
@@ -359,7 +356,7 @@ static struct ln lines[] = {
{ "Eu", "EUR", 0x20ac },
{ "eu", "EUR", 0x20ac },
{ "Ye", "=\bY", 0x00a5 },
- { "Po", "GBP", 0x00a3 },
+ { "Po", "-\bL", 0x00a3 },
{ "Cs", "o\bx", 0x00a4 },
{ "Fn", ",\bf", 0x0192 },
@@ -460,7 +457,7 @@ mchars_spec2cp(const char *p, size_t sz)
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
- return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1;
+ return ln != NULL ? ln->unicode : -1;
}
int
@@ -490,10 +487,8 @@ mchars_spec2str(const char *p, size_t sz, size_t *rsz)
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
- if (ln == NULL) {
- *rsz = 1;
- return sz == 1 ? p : NULL;
- }
+ if (ln == NULL)
+ return NULL;
*rsz = strlen(ln->ascii);
return ln->ascii;
diff --git a/usr/src/cmd/mandoc/config.h b/usr/src/cmd/mandoc/config.h
index 75f62a9339..3ae0245c08 100644
--- a/usr/src/cmd/mandoc/config.h
+++ b/usr/src/cmd/mandoc/config.h
@@ -40,6 +40,8 @@
#define HAVE_WCHAR 1
#define HAVE_OHASH 0
+#define OSENUM MANDOC_OS_OTHER
+
#define BINM_APROPOS "apropos"
#define BINM_MAKEWHATIS "man -w"
#define BINM_MAN "man"
diff --git a/usr/src/cmd/mandoc/dbm.c b/usr/src/cmd/mandoc/dbm.c
index 4aedf66d13..7637a036a5 100644
--- a/usr/src/cmd/mandoc/dbm.c
+++ b/usr/src/cmd/mandoc/dbm.c
@@ -1,4 +1,4 @@
-/* $Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */
+/* $Id: dbm.c,v 1.6 2018/11/19 19:22:07 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -151,17 +151,17 @@ dbm_page_get(int32_t ip)
assert(ip < npages);
res.name = dbm_get(pages[ip].name);
if (res.name == NULL)
- res.name = "(NULL)";
+ res.name = "(NULL)\0";
res.sect = dbm_get(pages[ip].sect);
if (res.sect == NULL)
- res.sect = "(NULL)";
+ res.sect = "(NULL)\0";
res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
res.desc = dbm_get(pages[ip].desc);
if (res.desc == NULL)
res.desc = "(NULL)";
res.file = dbm_get(pages[ip].file);
if (res.file == NULL)
- res.file = " (NULL)";
+ res.file = " (NULL)\0";
res.addr = dbm_addr(pages + ip);
return &res;
}
@@ -233,7 +233,7 @@ static struct dbm_res
page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match)
{
static const struct dbm_match *match;
- static const char *cp;
+ static const char *cp;
static int32_t ip;
struct dbm_res res = {-1, 0};
@@ -315,7 +315,7 @@ page_byarch(const struct dbm_match *arg_match)
static const struct dbm_match *match;
struct dbm_res res = {-1, 0};
static int32_t ip;
- const char *cp;
+ const char *cp;
/* Initialize for a new iteration. */
diff --git a/usr/src/cmd/mandoc/eqn.c b/usr/src/cmd/mandoc/eqn.c
index 01601a7137..3d63382ab3 100644
--- a/usr/src/cmd/mandoc/eqn.c
+++ b/usr/src/cmd/mandoc/eqn.c
@@ -1,7 +1,7 @@
-/* $Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */
+/* $Id: eqn.c,v 1.83 2018/12/14 06:33:14 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015, 2017, 2018 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,8 +30,9 @@
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
+#include "eqn.h"
#include "libmandoc.h"
-#include "libroff.h"
+#include "eqn_parse.h"
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
#define STRNEQ(p1, sz1, p2, sz2) \
@@ -284,6 +285,13 @@ enum parse_mode {
MODE_TOK
};
+struct eqn_def {
+ char *key;
+ size_t keysz;
+ char *val;
+ size_t valsz;
+};
+
static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
static struct eqn_box *eqn_box_makebinary(struct eqn_node *,
struct eqn_box *);
@@ -295,12 +303,11 @@ static void eqn_undef(struct eqn_node *);
struct eqn_node *
-eqn_alloc(struct mparse *parse)
+eqn_alloc(void)
{
struct eqn_node *ep;
ep = mandoc_calloc(1, sizeof(*ep));
- ep->parse = parse;
ep->gsize = EQN_DEFSIZE;
return ep;
}
@@ -399,7 +406,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
ep->end = strchr(ep->start + 1, *ep->start);
ep->start++; /* Skip opening quote. */
if (ep->end == NULL) {
- mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
+ mandoc_msg(MANDOCERR_ARG_QUOTE,
ep->node->line, ep->node->pos, NULL);
ep->end = strchr(ep->start, '\0');
}
@@ -420,7 +427,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
if ((def = eqn_def_find(ep)) == NULL)
break;
if (++lim > EQN_NEST_MAX) {
- mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
+ mandoc_msg(MANDOCERR_ROFFLOOP,
ep->node->line, ep->node->pos, NULL);
return EQN_TOK_EOF;
}
@@ -468,6 +475,8 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
void
eqn_box_free(struct eqn_box *bp)
{
+ if (bp == NULL)
+ return;
if (bp->first)
eqn_box_free(bp->first);
@@ -482,6 +491,16 @@ eqn_box_free(struct eqn_box *bp)
free(bp);
}
+struct eqn_box *
+eqn_box_new(void)
+{
+ struct eqn_box *bp;
+
+ bp = mandoc_calloc(1, sizeof(*bp));
+ bp->expectargs = UINT_MAX;
+ return bp;
+}
+
/*
* Allocate a box as the last child of the parent node.
*/
@@ -490,10 +509,9 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
{
struct eqn_box *bp;
- bp = mandoc_calloc(1, sizeof(struct eqn_box));
+ bp = eqn_box_new();
bp->parent = parent;
bp->parent->args++;
- bp->expectargs = UINT_MAX;
bp->font = bp->parent->font;
bp->size = ep->gsize;
@@ -542,7 +560,7 @@ static void
eqn_delim(struct eqn_node *ep)
{
if (ep->end[0] == '\0' || ep->end[1] == '\0') {
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "delim");
if (ep->end[0] != '\0')
ep->end++;
@@ -569,7 +587,7 @@ eqn_undef(struct eqn_node *ep)
struct eqn_def *def;
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "undef");
return;
}
@@ -588,7 +606,7 @@ eqn_def(struct eqn_node *ep)
int i;
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "define");
return;
}
@@ -617,7 +635,7 @@ eqn_def(struct eqn_node *ep)
}
if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
- mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "define %s", def->key);
free(def->key);
free(def->val);
@@ -666,7 +684,7 @@ next_tok:
case EQN_TOK_TDEFINE:
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "tdefine");
break;
case EQN_TOK_DELIM:
@@ -674,8 +692,8 @@ next_tok:
break;
case EQN_TOK_GFONT:
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
case EQN_TOK_MARK:
case EQN_TOK_LINEUP:
@@ -690,8 +708,8 @@ next_tok:
case EQN_TOK_DOT:
case EQN_TOK_DOTDOT:
if (parent->last == NULL) {
- mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
cur = eqn_box_alloc(ep, parent);
cur->type = EQN_TEXT;
cur->text = mandoc_strdup("");
@@ -735,8 +753,8 @@ next_tok:
case EQN_TOK_DOWN:
case EQN_TOK_UP:
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
case EQN_TOK_FAT:
case EQN_TOK_ROMAN:
@@ -773,14 +791,14 @@ next_tok:
case EQN_TOK_GSIZE:
/* Accept two values: integral size and a single. */
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
}
size = mandoc_strntoi(ep->start, ep->toksz, 10);
if (-1 == size) {
- mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_IT_NONUM, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
}
if (EQN_TOK_GSIZE == tok) {
@@ -804,8 +822,8 @@ next_tok:
* and keep on reading.
*/
if (parent->last == NULL) {
- mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
cur = eqn_box_alloc(ep, parent);
cur->type = EQN_TEXT;
cur->text = mandoc_strdup("");
@@ -871,8 +889,8 @@ next_tok:
* rebalance and continue reading.
*/
if (parent->last == NULL) {
- mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
cur = eqn_box_alloc(ep, parent);
cur->type = EQN_TEXT;
cur->text = mandoc_strdup("");
@@ -898,16 +916,16 @@ next_tok:
cur->left != NULL))
break;
if (cur == NULL) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
}
parent = cur;
if (EQN_TOK_RIGHT == tok) {
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
mandoc_msg(MANDOCERR_REQ_EMPTY,
- ep->parse, ep->node->line,
- ep->node->pos, eqn_toks[tok]);
+ ep->node->line, ep->node->pos,
+ "%s", eqn_toks[tok]);
break;
}
/* Handling depends on right/left. */
@@ -941,8 +959,8 @@ next_tok:
parent = parent->parent;
if (EQN_TOK_LEFT == tok &&
eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
- mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
}
parent = eqn_box_alloc(ep, parent);
@@ -975,8 +993,8 @@ next_tok:
if (cur->type == EQN_PILE)
break;
if (cur == NULL) {
- mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
- ep->node->line, ep->node->pos, eqn_toks[tok]);
+ mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line,
+ ep->node->pos, "%s", eqn_toks[tok]);
break;
}
parent = eqn_box_alloc(ep, cur);
@@ -1092,6 +1110,9 @@ eqn_free(struct eqn_node *p)
{
int i;
+ if (p == NULL)
+ return;
+
for (i = 0; i < (int)p->defsz; i++) {
free(p->defs[i].key);
free(p->defs[i].val);
diff --git a/usr/src/cmd/mandoc/eqn.h b/usr/src/cmd/mandoc/eqn.h
new file mode 100644
index 0000000000..c7c7aa15a7
--- /dev/null
+++ b/usr/src/cmd/mandoc/eqn.h
@@ -0,0 +1,72 @@
+/* $Id: eqn.h,v 1.1 2018/12/13 05:23:38 schwarze Exp $ */
+/*
+ * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Public data types for eqn(7) syntax trees.
+ */
+
+enum eqn_boxt {
+ EQN_TEXT, /* Text, e.g. number, variable, operator, ... */
+ EQN_SUBEXPR, /* Nested eqn(7) subexpression. */
+ EQN_LIST, /* List, for example in braces. */
+ EQN_PILE, /* Vertical pile. */
+ EQN_MATRIX /* List of columns. */
+};
+
+enum eqn_fontt {
+ EQNFONT_NONE = 0,
+ EQNFONT_ROMAN,
+ EQNFONT_BOLD,
+ EQNFONT_FAT,
+ EQNFONT_ITALIC,
+ EQNFONT__MAX
+};
+
+enum eqn_post {
+ EQNPOS_NONE = 0,
+ EQNPOS_SUP,
+ EQNPOS_SUBSUP,
+ EQNPOS_SUB,
+ EQNPOS_TO,
+ EQNPOS_FROM,
+ EQNPOS_FROMTO,
+ EQNPOS_OVER,
+ EQNPOS_SQRT,
+ EQNPOS__MAX
+};
+
+ /*
+ * A "box" is a parsed mathematical expression as defined by the eqn.7
+ * grammar.
+ */
+struct eqn_box {
+ struct eqn_box *parent;
+ struct eqn_box *prev;
+ struct eqn_box *next;
+ struct eqn_box *first; /* First child node. */
+ struct eqn_box *last; /* Last child node. */
+ char *text; /* Text (or NULL). */
+ char *left; /* Left-hand fence. */
+ char *right; /* Right-hand fence. */
+ char *top; /* Symbol above. */
+ char *bottom; /* Symbol below. */
+ size_t expectargs; /* Maximal number of arguments. */
+ size_t args; /* Actual number of arguments. */
+ int size; /* Font size. */
+#define EQN_DEFSIZE INT_MIN
+ enum eqn_boxt type; /* Type of node. */
+ enum eqn_fontt font; /* Font in this box. */
+ enum eqn_post pos; /* Position of the next box. */
+};
diff --git a/usr/src/cmd/mandoc/eqn_html.c b/usr/src/cmd/mandoc/eqn_html.c
index 51f1442342..1fe41ecbfa 100644
--- a/usr/src/cmd/mandoc/eqn_html.c
+++ b/usr/src/cmd/mandoc/eqn_html.c
@@ -1,4 +1,4 @@
-/* $Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */
+/* $Id: eqn_html.c,v 1.18 2018/12/13 05:23:38 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -26,6 +26,7 @@
#include <string.h>
#include "mandoc.h"
+#include "eqn.h"
#include "out.h"
#include "html.h"
diff --git a/usr/src/cmd/mandoc/eqn_parse.h b/usr/src/cmd/mandoc/eqn_parse.h
new file mode 100644
index 0000000000..a2a4e6fd7d
--- /dev/null
+++ b/usr/src/cmd/mandoc/eqn_parse.h
@@ -0,0 +1,48 @@
+/* $Id: eqn_parse.h,v 1.3 2018/12/14 06:33:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * External interface of the eqn(7) parser.
+ * For use in the roff(7) and eqn(7) parsers only.
+ */
+
+struct roff_node;
+struct eqn_box;
+struct eqn_def;
+
+struct eqn_node {
+ struct roff_node *node; /* Syntax tree of this equation. */
+ struct eqn_def *defs; /* Array of definitions. */
+ char *data; /* Source code of this equation. */
+ char *start; /* First byte of the current token. */
+ char *end; /* First byte of the next token. */
+ size_t defsz; /* Number of definitions. */
+ size_t sz; /* Length of the source code. */
+ size_t toksz; /* Length of the current token. */
+ int gsize; /* Default point size. */
+ int delim; /* In-line delimiters enabled. */
+ char odelim; /* In-line opening delimiter. */
+ char cdelim; /* In-line closing delimiter. */
+};
+
+
+struct eqn_node *eqn_alloc(void);
+struct eqn_box *eqn_box_new(void);
+void eqn_box_free(struct eqn_box *);
+void eqn_free(struct eqn_node *);
+void eqn_parse(struct eqn_node *);
+void eqn_read(struct eqn_node *, const char *);
+void eqn_reset(struct eqn_node *);
diff --git a/usr/src/cmd/mandoc/eqn_term.c b/usr/src/cmd/mandoc/eqn_term.c
index 669c3c56cf..3e27233b30 100644
--- a/usr/src/cmd/mandoc/eqn_term.c
+++ b/usr/src/cmd/mandoc/eqn_term.c
@@ -1,4 +1,4 @@
-/* $Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */
+/* $Id: eqn_term.c,v 1.19 2018/12/13 05:23:38 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -25,7 +25,7 @@
#include <stdlib.h>
#include <string.h>
-#include "mandoc.h"
+#include "eqn.h"
#include "out.h"
#include "term.h"
@@ -106,7 +106,7 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
/* Special box types. */
if (bp->pos == EQNPOS_SQRT) {
- term_word(p, "sqrt");
+ term_word(p, "\\(sr");
if (bp->first != NULL) {
p->flags |= TERMP_NOSPACE;
eqn_box(p, bp->first);
diff --git a/usr/src/cmd/mandoc/html.c b/usr/src/cmd/mandoc/html.c
index 70935dcd57..1302972a4e 100644
--- a/usr/src/cmd/mandoc/html.c
+++ b/usr/src/cmd/mandoc/html.c
@@ -1,7 +1,7 @@
-/* $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */
+/* $Id: html.c,v 1.254 2019/03/03 13:02:11 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017-2019 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
@@ -18,6 +18,7 @@
#include "config.h"
#include <sys/types.h>
+#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
@@ -62,6 +63,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"title", HTML_NLAROUND},
{"div", HTML_NLAROUND},
{"div", 0},
+ {"section", HTML_NLALL},
{"h1", HTML_NLAROUND},
{"h2", HTML_NLAROUND},
{"span", 0},
@@ -77,6 +79,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"dl", HTML_NLALL | HTML_INDENT},
{"dt", HTML_NLAROUND},
{"dd", HTML_NLAROUND | HTML_INDENT},
+ {"p", HTML_NLAROUND | HTML_INDENT},
{"pre", HTML_NLALL | HTML_NOINDENT},
{"var", 0},
{"cite", 0},
@@ -107,6 +110,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
/* Avoid duplicate HTML id= attributes. */
static struct ohash id_unique;
+static void html_reset_internal(struct html *);
static void print_byte(struct html *, char);
static void print_endword(struct html *);
static void print_indent(struct html *);
@@ -116,7 +120,6 @@ static void print_ctag(struct html *, struct tag *);
static int print_escape(struct html *, char);
static int print_encode(struct html *, const char *, const char *, int);
static void print_href(struct html *, const char *, const char *, int);
-static void print_metaf(struct html *, enum mandoc_esc);
void *
@@ -128,31 +131,32 @@ html_alloc(const struct manoutput *outopts)
h->tag = NULL;
h->style = outopts->style;
- h->base_man = outopts->man;
+ if ((h->base_man1 = outopts->man) == NULL)
+ h->base_man2 = NULL;
+ else if ((h->base_man2 = strchr(h->base_man1, ';')) != NULL)
+ *h->base_man2++ = '\0';
h->base_includes = outopts->includes;
if (outopts->fragment)
h->oflags |= HTML_FRAGMENT;
+ if (outopts->toc)
+ h->oflags |= HTML_TOC;
mandoc_ohash_init(&id_unique, 4, 0);
return h;
}
-void
-html_free(void *p)
+static void
+html_reset_internal(struct html *h)
{
struct tag *tag;
- struct html *h;
char *cp;
unsigned int slot;
- h = (struct html *)p;
while ((tag = h->tag) != NULL) {
h->tag = tag->next;
free(tag);
}
- free(h);
-
cp = ohash_first(&id_unique, &slot);
while (cp != NULL) {
free(cp);
@@ -162,6 +166,20 @@ html_free(void *p)
}
void
+html_reset(void *p)
+{
+ html_reset_internal(p);
+ mandoc_ohash_init(&id_unique, 4, 0);
+}
+
+void
+html_free(void *p)
+{
+ html_reset_internal(p);
+ free(p);
+}
+
+void
print_gen_head(struct html *h)
{
struct tag *t;
@@ -204,7 +222,7 @@ print_gen_head(struct html *h)
print_tagq(h, t);
}
-static void
+void
print_metaf(struct html *h, enum mandoc_esc deco)
{
enum htmlfont font;
@@ -222,12 +240,15 @@ print_metaf(struct html *h, enum mandoc_esc deco)
case ESCAPE_FONTBI:
font = HTMLFONT_BI;
break;
+ case ESCAPE_FONTCW:
+ font = HTMLFONT_CW;
+ break;
case ESCAPE_FONT:
case ESCAPE_FONTROMAN:
font = HTMLFONT_NONE;
break;
default:
- abort();
+ return;
}
if (h->metaf) {
@@ -249,11 +270,69 @@ print_metaf(struct html *h, enum mandoc_esc deco)
h->metaf = print_otag(h, TAG_B, "");
print_otag(h, TAG_I, "");
break;
+ case HTMLFONT_CW:
+ h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
+ break;
default:
break;
}
}
+void
+html_close_paragraph(struct html *h)
+{
+ struct tag *t;
+
+ for (t = h->tag; t != NULL && t->closed == 0; t = t->next) {
+ switch(t->tag) {
+ case TAG_P:
+ case TAG_PRE:
+ print_tagq(h, t);
+ break;
+ case TAG_A:
+ print_tagq(h, t);
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+}
+
+/*
+ * ROFF_nf switches to no-fill mode, ROFF_fi to fill mode.
+ * TOKEN_NONE does not switch. The old mode is returned.
+ */
+enum roff_tok
+html_fillmode(struct html *h, enum roff_tok want)
+{
+ struct tag *t;
+ enum roff_tok had;
+
+ for (t = h->tag; t != NULL; t = t->next)
+ if (t->tag == TAG_PRE)
+ break;
+
+ had = t == NULL ? ROFF_fi : ROFF_nf;
+
+ if (want != had) {
+ switch (want) {
+ case ROFF_fi:
+ print_tagq(h, t);
+ break;
+ case ROFF_nf:
+ html_close_paragraph(h);
+ print_otag(h, TAG_PRE, "");
+ break;
+ case TOKEN_NONE:
+ break;
+ default:
+ abort();
+ }
+ }
+ return had;
+}
+
char *
html_make_id(const struct roff_node *n, int unique)
{
@@ -345,7 +424,6 @@ static int
print_encode(struct html *h, const char *p, const char *pend, int norecurse)
{
char numbuf[16];
- struct tag *t;
const char *seq;
size_t sz;
int c, len, breakline, nospace;
@@ -371,9 +449,7 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
if (breakline &&
(p >= pend || *p == ' ' || *p == ASCII_NBRSP)) {
- t = print_otag(h, TAG_DIV, "");
- print_text(h, "\\~");
- print_tagq(h, t);
+ print_otag(h, TAG_BR, "");
breakline = 0;
while (p < pend && (*p == ' ' || *p == ASCII_NBRSP))
p++;
@@ -393,22 +469,25 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
continue;
esc = mandoc_escape(&p, &seq, &len);
- if (ESCAPE_ERROR == esc)
- break;
-
switch (esc) {
case ESCAPE_FONT:
case ESCAPE_FONTPREV:
case ESCAPE_FONTBOLD:
case ESCAPE_FONTITALIC:
case ESCAPE_FONTBI:
+ case ESCAPE_FONTCW:
case ESCAPE_FONTROMAN:
- if (0 == norecurse)
+ if (0 == norecurse) {
+ h->flags |= HTML_NOSPACE;
print_metaf(h, esc);
+ h->flags &= ~HTML_NOSPACE;
+ }
continue;
case ESCAPE_SKIPCHAR:
h->flags |= HTML_SKIPCHAR;
continue;
+ case ESCAPE_ERROR:
+ continue;
default:
break;
}
@@ -433,6 +512,12 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
if (c <= 0)
continue;
break;
+ case ESCAPE_UNDEF:
+ c = *seq;
+ break;
+ case ESCAPE_DEVICE:
+ print_word(h, "html");
+ continue;
case ESCAPE_BREAK:
breakline = 1;
continue;
@@ -464,9 +549,21 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
static void
print_href(struct html *h, const char *name, const char *sec, int man)
{
+ struct stat sb;
const char *p, *pp;
+ char *filename;
+
+ if (man) {
+ pp = h->base_man1;
+ if (h->base_man2 != NULL) {
+ mandoc_asprintf(&filename, "%s.%s", name, sec);
+ if (stat(filename, &sb) == -1)
+ pp = h->base_man2;
+ free(filename);
+ }
+ } else
+ pp = h->base_includes;
- pp = man ? h->base_man : h->base_includes;
while ((p = strchr(pp, '%')) != NULL) {
print_encode(h, pp, p, 1);
if (man && p[1] == 'S') {
@@ -492,7 +589,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
struct tag *t;
const char *attr;
char *arg1, *arg2;
- int tflags;
+ int style_written, tflags;
tflags = htmltags[tag].flags;
@@ -502,6 +599,8 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
t = mandoc_malloc(sizeof(struct tag));
t->tag = tag;
t->next = h->tag;
+ t->refcnt = 0;
+ t->closed = 0;
h->tag = t;
} else
t = NULL;
@@ -532,7 +631,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
va_start(ap, fmt);
- while (*fmt != '\0') {
+ while (*fmt != '\0' && *fmt != 's') {
/* Parse attributes and arguments. */
@@ -548,10 +647,6 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
case 'i':
attr = "id";
break;
- case 's':
- attr = "style";
- arg2 = va_arg(ap, char *);
- break;
case '?':
attr = arg1;
arg1 = va_arg(ap, char *);
@@ -584,26 +679,33 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
print_encode(h, arg1, NULL, 1);
fmt++;
break;
- case 'T':
- print_encode(h, arg1, NULL, 1);
- print_word(h, "\" title=\"");
- print_encode(h, arg1, NULL, 1);
- fmt++;
- break;
default:
- if (arg2 == NULL)
- print_encode(h, arg1, NULL, 1);
- else {
- print_word(h, arg1);
- print_byte(h, ':');
- print_byte(h, ' ');
- print_word(h, arg2);
- print_byte(h, ';');
- }
+ print_encode(h, arg1, NULL, 1);
break;
}
print_byte(h, '"');
}
+
+ style_written = 0;
+ while (*fmt++ == 's') {
+ arg1 = va_arg(ap, char *);
+ arg2 = va_arg(ap, char *);
+ if (arg2 == NULL)
+ continue;
+ print_byte(h, ' ');
+ if (style_written == 0) {
+ print_word(h, "style=\"");
+ style_written = 1;
+ }
+ print_word(h, arg1);
+ print_byte(h, ':');
+ print_byte(h, ' ');
+ print_word(h, arg2);
+ print_byte(h, ';');
+ }
+ if (style_written)
+ print_byte(h, '"');
+
va_end(ap);
/* Accommodate for "well-formed" singleton escaping. */
@@ -631,33 +733,32 @@ print_ctag(struct html *h, struct tag *tag)
{
int tflags;
- /*
- * 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;
-
- tflags = htmltags[tag->tag].flags;
-
- if (tflags & HTML_INDENT)
- h->indent--;
- if (tflags & HTML_NOINDENT)
- h->noindent--;
- if (tflags & HTML_NLEND)
- print_endline(h);
- print_indent(h);
- print_byte(h, '<');
- print_byte(h, '/');
- print_word(h, htmltags[tag->tag].name);
- print_byte(h, '>');
- if (tflags & HTML_NLAFTER)
- print_endline(h);
-
- h->tag = tag->next;
- free(tag);
+ if (tag->closed == 0) {
+ tag->closed = 1;
+ if (tag == h->metaf)
+ h->metaf = NULL;
+ if (tag == h->tblt)
+ h->tblt = NULL;
+
+ tflags = htmltags[tag->tag].flags;
+ if (tflags & HTML_INDENT)
+ h->indent--;
+ if (tflags & HTML_NOINDENT)
+ h->noindent--;
+ if (tflags & HTML_NLEND)
+ print_endline(h);
+ print_indent(h);
+ print_byte(h, '<');
+ print_byte(h, '/');
+ print_word(h, htmltags[tag->tag].name);
+ print_byte(h, '>');
+ if (tflags & HTML_NLAFTER)
+ print_endline(h);
+ }
+ if (tag->refcnt == 0) {
+ h->tag = tag->next;
+ free(tag);
+ }
}
void
@@ -717,6 +818,9 @@ print_text(struct html *h, const char *word)
h->metaf = print_otag(h, TAG_B, "");
print_otag(h, TAG_I, "");
break;
+ case HTMLFONT_CW:
+ h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
+ break;
default:
print_indent(h);
break;
@@ -741,36 +845,33 @@ print_text(struct html *h, const char *word)
void
print_tagq(struct html *h, const struct tag *until)
{
- struct tag *tag;
+ struct tag *this, *next;
- while ((tag = h->tag) != NULL) {
- print_ctag(h, tag);
- if (until && tag == until)
- return;
+ for (this = h->tag; this != NULL; this = next) {
+ next = this == until ? NULL : this->next;
+ print_ctag(h, this);
}
}
+/*
+ * Close out all open elements up to but excluding suntil.
+ * Note that a paragraph just inside stays open together with it
+ * because paragraphs include subsequent phrasing content.
+ */
void
print_stagq(struct html *h, const struct tag *suntil)
{
- struct tag *tag;
+ struct tag *this, *next;
- while ((tag = h->tag) != NULL) {
- if (suntil && tag == suntil)
- return;
- print_ctag(h, tag);
+ for (this = h->tag; this != NULL; this = next) {
+ next = this->next;
+ if (this == suntil || (next == suntil &&
+ (this->tag == TAG_P || this->tag == TAG_PRE)))
+ break;
+ print_ctag(h, this);
}
}
-void
-print_paragraph(struct html *h)
-{
- struct tag *t;
-
- t = print_otag(h, TAG_DIV, "c", "Pp");
- print_tagq(h, t);
-}
-
/***********************************************************************
* Low level output functions.
diff --git a/usr/src/cmd/mandoc/html.h b/usr/src/cmd/mandoc/html.h
index 6d44a47383..a6bf891190 100644
--- a/usr/src/cmd/mandoc/html.h
+++ b/usr/src/cmd/mandoc/html.h
@@ -1,7 +1,7 @@
-/* $Id: html.h,v 1.92 2018/06/25 16:54:59 schwarze Exp $ */
+/* $Id: html.h,v 1.102 2019/03/01 10:57:18 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2018, 2019 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 @@ enum htmltag {
TAG_TITLE,
TAG_DIV,
TAG_IDIV,
+ TAG_SECTION,
TAG_H1,
TAG_H2,
TAG_SPAN,
@@ -39,6 +40,7 @@ enum htmltag {
TAG_DL,
TAG_DT,
TAG_DD,
+ TAG_P,
TAG_PRE,
TAG_VAR,
TAG_CITE,
@@ -72,11 +74,14 @@ enum htmlfont {
HTMLFONT_BOLD,
HTMLFONT_ITALIC,
HTMLFONT_BI,
+ HTMLFONT_CW,
HTMLFONT_MAX
};
struct tag {
struct tag *next;
+ int refcnt;
+ int closed;
enum htmltag tag;
};
@@ -87,12 +92,12 @@ struct html {
#define HTML_KEEP (1 << 2)
#define HTML_PREKEEP (1 << 3)
#define HTML_NONOSPACE (1 << 4) /* never add spaces */
-#define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */
#define HTML_SKIPCHAR (1 << 6) /* skip the next character */
#define HTML_NOSPLIT (1 << 7) /* do not break line before .An */
#define HTML_SPLIT (1 << 8) /* break line before .An */
#define HTML_NONEWLINE (1 << 9) /* No line break in nofill mode. */
#define HTML_BUFFER (1 << 10) /* Collect a word to see if it fits. */
+#define HTML_TOCDONE (1 << 11) /* The TOC was already written. */
size_t indent; /* current output indentation level */
int noindent; /* indent disabled by <pre> */
size_t col; /* current output byte position */
@@ -101,7 +106,8 @@ struct html {
struct tag *tag; /* last open tag */
struct rofftbl tbl; /* current table */
struct tag *tblt; /* current open table scope */
- char *base_man; /* base for manpage href */
+ char *base_man1; /* bases for manpage href */
+ char *base_man2;
char *base_includes; /* base for include href */
char *style; /* style-sheet URI */
struct tag *metaf; /* current open font scope */
@@ -109,6 +115,7 @@ struct html {
enum htmlfont metac; /* current font mode */
int oflags; /* output options */
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
+#define HTML_TOC (1 << 1) /* emit a table of contents */
};
@@ -121,6 +128,7 @@ void roff_html_pre(struct html *, const struct roff_node *);
void print_gen_comment(struct html *, struct roff_node *);
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
+void print_metaf(struct html *, enum mandoc_esc);
struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
@@ -128,7 +136,8 @@ void print_text(struct html *, const char *);
void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
void print_eqn(struct html *, const struct eqn_box *);
-void print_paragraph(struct html *);
void print_endline(struct html *);
+void html_close_paragraph(struct html *);
+enum roff_tok html_fillmode(struct html *, enum roff_tok);
char *html_make_id(const struct roff_node *, int);
diff --git a/usr/src/cmd/mandoc/lib.c b/usr/src/cmd/mandoc/lib.c
index 0474924d73..e377c1bced 100644
--- a/usr/src/cmd/mandoc/lib.c
+++ b/usr/src/cmd/mandoc/lib.c
@@ -1,4 +1,4 @@
-/* $Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */
+/* $Id: lib.c,v 1.15 2018/12/13 11:55:46 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -17,12 +17,9 @@
#include "config.h"
#include <sys/types.h>
-
#include <string.h>
-#include "mandoc.h"
#include "roff.h"
-#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
diff --git a/usr/src/cmd/mandoc/libman.h b/usr/src/cmd/mandoc/libman.h
index 312093dd01..ac960a6858 100644
--- a/usr/src/cmd/mandoc/libman.h
+++ b/usr/src/cmd/mandoc/libman.h
@@ -1,7 +1,7 @@
-/* $Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */
+/* $Id: libman.h,v 1.86 2018/12/31 10:04:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015, 2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,6 +16,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+struct roff_node;
+struct roff_man;
+
#define MACRO_PROT_ARGS struct roff_man *man, \
enum roff_tok tok, \
int line, \
@@ -26,15 +29,14 @@
struct man_macro {
void (*fp)(MACRO_PROT_ARGS);
int flags;
-#define MAN_SCOPED (1 << 0) /* Optional next-line scope. */
-#define MAN_NSCOPED (1 << 1) /* Allowed in next-line element scope. */
-#define MAN_BSCOPE (1 << 2) /* Break next-line block scope. */
-#define MAN_JOIN (1 << 3) /* Join arguments together. */
+#define MAN_BSCOPED (1 << 0) /* Optional next-line block scope. */
+#define MAN_ESCOPED (1 << 1) /* Optional next-line element scope. */
+#define MAN_NSCOPED (1 << 2) /* Allowed in next-line element scope. */
+#define MAN_XSCOPE (1 << 3) /* Exit next-line block scope. */
+#define MAN_JOIN (1 << 4) /* Join arguments together. */
};
-extern const struct man_macro *const man_macros;
-
+const struct man_macro *man_macro(enum roff_tok);
-void man_node_validate(struct roff_man *);
-void man_state(struct roff_man *, struct roff_node *);
+void man_descope(struct roff_man *, int, int, char *);
void man_unscope(struct roff_man *, const struct roff_node *);
diff --git a/usr/src/cmd/mandoc/libmandoc.h b/usr/src/cmd/mandoc/libmandoc.h
index 9cc8cce4ec..ff6f4692f0 100644
--- a/usr/src/cmd/mandoc/libmandoc.h
+++ b/usr/src/cmd/mandoc/libmandoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmandoc.h,v 1.71 2018/04/09 22:27:04 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.77 2018/12/21 17:15:18 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,31 +16,38 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-enum rofferr {
- ROFF_CONT, /* continue processing line */
- ROFF_RERUN, /* re-run roff interpreter with offset */
- ROFF_APPEND, /* re-run main parser, appending next line */
- ROFF_REPARSE, /* re-run main parser on the result */
- ROFF_SO, /* include another file */
- ROFF_IGN, /* ignore current line */
-};
+/*
+ * Return codes passed from the roff parser to the main parser.
+ */
+
+/* Main instruction: what to do with the returned line. */
+#define ROFF_IGN 0x000 /* Don't do anything with it. */
+#define ROFF_CONT 0x001 /* Give it to the high-level parser. */
+#define ROFF_RERUN 0x002 /* Re-run the roff parser with an offset. */
+#define ROFF_REPARSE 0x004 /* Recursively run the main parser on it. */
+#define ROFF_SO 0x008 /* Include the named file. */
+#define ROFF_MASK 0x00f /* Only one of these bits should be set. */
+
+/* Options for further parsing, to be OR'ed with the above. */
+#define ROFF_APPEND 0x010 /* Append the next line to this one. */
+#define ROFF_USERCALL 0x020 /* Start execution of a new macro. */
+#define ROFF_USERRET 0x040 /* Abort execution of the current macro. */
+#define ROFF_WHILE 0x100 /* Start a new .while loop. */
+#define ROFF_LOOPCONT 0x200 /* Iterate the current .while loop. */
+#define ROFF_LOOPEXIT 0x400 /* Exit the current .while loop. */
+#define ROFF_LOOPMASK 0xf00
+
struct buf {
- char *buf;
- size_t sz;
+ char *buf;
+ size_t sz;
+ struct buf *next;
};
-struct mparse;
struct roff;
struct roff_man;
-void mandoc_msg(enum mandocerr, struct mparse *,
- int, int, const char *);
-void mandoc_vmsg(enum mandocerr, struct mparse *,
- int, int, const char *, ...)
- __attribute__((__format__ (__printf__, 5, 6)));
-char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct roff_man *, char *, int, int);
int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
@@ -57,17 +64,18 @@ int preconv_encode(const struct buf *, size_t *,
struct buf *, size_t *, int *);
void roff_free(struct roff *);
-struct roff *roff_alloc(struct mparse *, int);
+struct roff *roff_alloc(int);
void roff_reset(struct roff *);
void roff_man_free(struct roff_man *);
-struct roff_man *roff_man_alloc(struct roff *, struct mparse *,
- const char *, int);
+struct roff_man *roff_man_alloc(struct roff *, const char *, int);
void roff_man_reset(struct roff_man *);
-enum rofferr roff_parseln(struct roff *, int, struct buf *, int *);
+int roff_parseln(struct roff *, int, struct buf *, int *);
+void roff_userret(struct roff *);
void roff_endparse(struct roff *);
void roff_setreg(struct roff *, const char *, int, char sign);
int roff_getreg(struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
+char *roff_getarg(struct roff *, char **, int, int *);
int roff_getcontrol(const struct roff *,
const char *, int *);
int roff_getformat(const struct roff *);
diff --git a/usr/src/cmd/mandoc/libmdoc.h b/usr/src/cmd/mandoc/libmdoc.h
index 57dff61b4a..ff29625194 100644
--- a/usr/src/cmd/mandoc/libmdoc.h
+++ b/usr/src/cmd/mandoc/libmdoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */
+/* $Id: libmdoc.h,v 1.117 2018/12/31 04:55:46 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,6 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+struct roff_node;
+struct roff_man;
+struct mdoc_arg;
+
#define MACRO_PROT_ARGS struct roff_man *mdoc, \
enum roff_tok tok, \
int line, \
@@ -38,6 +42,7 @@ enum margserr {
ARGS_ERROR,
ARGS_EOLN, /* end-of-line */
ARGS_WORD, /* normal word */
+ ARGS_ALLOC, /* normal word from roff_getarg() */
ARGS_PUNCT, /* series of punctuation */
ARGS_PHRASE /* Bl -column phrase */
};
@@ -59,10 +64,8 @@ enum mdelim {
DELIM_MAX
};
-extern const struct mdoc_macro *const mdoc_macros;
-
+const struct mdoc_macro *mdoc_macro(enum roff_tok);
-void mdoc_macro(MACRO_PROT_ARGS);
void mdoc_elem_alloc(struct roff_man *, int, int,
enum roff_tok, struct mdoc_arg *);
struct roff_node *mdoc_block_alloc(struct roff_man *, int, int,
@@ -71,10 +74,7 @@ void mdoc_tail_alloc(struct roff_man *, int, int,
enum roff_tok);
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int,
enum roff_tok, struct roff_node *);
-void mdoc_node_relink(struct roff_man *, struct roff_node *);
-void mdoc_node_validate(struct roff_man *);
void mdoc_state(struct roff_man *, struct roff_node *);
-void mdoc_state_reset(struct roff_man *);
const char *mdoc_a2arch(const char *);
const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *);
diff --git a/usr/src/cmd/mandoc/libroff.h b/usr/src/cmd/mandoc/libroff.h
deleted file mode 100644
index b6a026d820..0000000000
--- a/usr/src/cmd/mandoc/libroff.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* $Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */
-/*
- * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-enum tbl_part {
- TBL_PART_OPTS, /* in options (first line) */
- TBL_PART_LAYOUT, /* describing layout */
- TBL_PART_DATA, /* creating data rows */
- TBL_PART_CDATA /* continue previous row */
-};
-
-struct tbl_node {
- struct mparse *parse; /* parse point */
- int pos; /* invocation column */
- int line; /* invocation line */
- enum tbl_part part;
- struct tbl_opts opts;
- struct tbl_row *first_row;
- struct tbl_row *last_row;
- struct tbl_span *first_span;
- struct tbl_span *current_span;
- struct tbl_span *last_span;
- struct tbl_node *next;
-};
-
-struct eqn_node {
- struct mparse *parse; /* main parser, for error reporting */
- struct roff_node *node; /* syntax tree of this equation */
- struct eqn_def *defs; /* array of definitions */
- char *data; /* source code of this equation */
- char *start; /* first byte of the current token */
- char *end; /* first byte of the next token */
- size_t defsz; /* number of definitions */
- size_t sz; /* length of the source code */
- size_t toksz; /* length of the current token */
- int gsize; /* default point size */
- int delim; /* in-line delimiters enabled */
- char odelim; /* in-line opening delimiter */
- char cdelim; /* in-line closing delimiter */
-};
-
-struct eqn_def {
- char *key;
- size_t keysz;
- char *val;
- size_t valsz;
-};
-
-
-struct tbl_node *tbl_alloc(int, int, struct mparse *);
-void tbl_restart(int, int, struct tbl_node *);
-void tbl_free(struct tbl_node *);
-void tbl_reset(struct tbl_node *);
-void tbl_read(struct tbl_node *, int, const char *, int);
-void tbl_option(struct tbl_node *, int, const char *, int *);
-void tbl_layout(struct tbl_node *, int, const char *, int);
-void tbl_data(struct tbl_node *, int, const char *, int);
-void tbl_cdata(struct tbl_node *, int, const char *, int);
-const struct tbl_span *tbl_span(struct tbl_node *);
-int tbl_end(struct tbl_node *);
-struct eqn_node *eqn_alloc(struct mparse *);
-void eqn_box_free(struct eqn_box *);
-void eqn_free(struct eqn_node *);
-void eqn_parse(struct eqn_node *);
-void eqn_read(struct eqn_node *, const char *);
-void eqn_reset(struct eqn_node *);
diff --git a/usr/src/cmd/mandoc/main.c b/usr/src/cmd/mandoc/main.c
index 600bc9bb4b..b91c15860a 100644
--- a/usr/src/cmd/mandoc/main.c
+++ b/usr/src/cmd/mandoc/main.c
@@ -1,7 +1,7 @@
-/* $Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
+/* $Id: main.c,v 1.322 2019/03/06 10:18:58 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -21,7 +21,6 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h> /* MACHINE */
-#include <sys/termios.h>
#include <sys/wait.h>
#include <assert.h>
@@ -40,6 +39,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <time.h>
#include <unistd.h>
@@ -49,6 +49,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
+#include "mandoc_parse.h"
#include "tag.h"
#include "main.h"
#include "manconf.h"
@@ -81,7 +82,6 @@ struct curparse {
void *outdata; /* data for output */
char *os_s; /* operating system for display */
int wstop; /* stop after a file with a warning */
- enum mandocerr mmin; /* ignore messages below this */
enum mandoc_os os_e; /* check base system conventions */
enum outt outtype; /* which output to use */
};
@@ -89,7 +89,7 @@ struct curparse {
int mandocdb(int, char *[]);
-static void check_xr(const char *);
+static void check_xr(void);
static int fs_lookup(const struct manpaths *,
size_t ipath, const char *,
const char *, const char *,
@@ -99,8 +99,6 @@ static int fs_search(const struct mansearch *,
struct manpage **, size_t *);
static int koptions(int *, char *);
static void moptions(int *, char *);
-static void mmsg(enum mandocerr, enum mandoclevel,
- const char *, int, int, const char *);
static void outdata_alloc(struct curparse *);
static void parse(struct curparse *, int, const char *);
static void passthrough(const char *, int, int);
@@ -112,8 +110,6 @@ static int woptions(struct curparse *, char *);
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static char help_arg[] = "help";
static char *help_argv[] = {help_arg, NULL};
-static enum mandoclevel rc;
-static FILE *mmsg_stream;
int
@@ -127,7 +123,7 @@ main(int argc, char *argv[])
struct manpage *res, *resp;
const char *progname, *sec, *thisarg;
char *conf_file, *defpaths, *auxpaths;
- char *oarg;
+ char *oarg, *tagarg;
unsigned char *uc;
size_t i, sz;
int prio, best_prio;
@@ -152,6 +148,7 @@ main(int argc, char *argv[])
setprogname(progname);
#endif
+ mandoc_msg_setoutfile(stderr);
if (strncmp(progname, "mandocdb", 8) == 0 ||
strcmp(progname, BINM_MAKEWHATIS) == 0)
return mandocdb(argc, argv);
@@ -191,10 +188,8 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
- curp.mmin = MANDOCERR_MAX;
curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
- mmsg_stream = stderr;
use_pager = 1;
tag_files = NULL;
@@ -314,6 +309,9 @@ main(int argc, char *argv[])
}
}
+ if (curp.outtype != OUTT_TREE || !curp.outopts->noval)
+ options |= MPARSE_VALIDATE;
+
if (outmode == OUTMODE_FLN ||
outmode == OUTMODE_LST ||
!isatty(STDOUT_FILENO))
@@ -371,7 +369,16 @@ main(int argc, char *argv[])
#endif
}
- rc = MANDOCLEVEL_OK;
+ /*
+ * Use the first argument for -O tag in addition to
+ * using it as a search term for man(1) or apropos(1).
+ */
+
+ if (conf.output.tag != NULL && *conf.output.tag == '\0') {
+ tagarg = argc > 0 && search.argmode == ARG_EXPR ?
+ strchr(*argv, '=') : NULL;
+ conf.output.tag = tagarg == NULL ? *argv : tagarg + 1;
+ }
/* man(1), whatis(1), apropos(1) */
@@ -405,7 +412,6 @@ main(int argc, char *argv[])
res[sz].names = NULL;
res[sz].output = NULL;
res[sz].ipath = SIZE_MAX;
- res[sz].bits = 0;
res[sz].sec = 10;
res[sz].form = FORM_SRC;
sz++;
@@ -415,7 +421,7 @@ main(int argc, char *argv[])
if (sz == 0) {
if (search.argmode != ARG_NAME)
warnx("nothing appropriate");
- rc = MANDOCLEVEL_BADARG;
+ mandoc_msg_setrc(MANDOCLEVEL_BADARG);
goto out;
}
@@ -483,19 +489,17 @@ main(int argc, char *argv[])
moptions(&options, auxpaths);
mchars_alloc();
- curp.mp = mparse_alloc(options, curp.mmin, mmsg,
- curp.os_e, curp.os_s);
-
- /*
- * Conditionally start up the lookaside buffer before parsing.
- */
- if (OUTT_MAN == curp.outtype)
- mparse_keep(curp.mp);
+ curp.mp = mparse_alloc(options, curp.os_e, curp.os_s);
if (argc < 1) {
- if (use_pager)
+ if (use_pager) {
tag_files = tag_init();
- parse(&curp, STDIN_FILENO, "<stdin>");
+ tag_files->tagname = conf.output.tag;
+ }
+ thisarg = "<stdin>";
+ mandoc_msg_setinfilename(thisarg);
+ parse(&curp, STDIN_FILENO, thisarg);
+ mandoc_msg_setinfilename(NULL);
}
/*
@@ -519,22 +523,25 @@ main(int argc, char *argv[])
(void)chdir(conf.manpath.paths[resp->ipath]);
else if (startdir != -1)
(void)fchdir(startdir);
- }
+ thisarg = resp->file;
+ } else
+ thisarg = *argv;
- fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
+ fd = mparse_open(curp.mp, thisarg);
if (fd != -1) {
if (use_pager) {
- tag_files = tag_init();
use_pager = 0;
+ tag_files = tag_init();
+ tag_files->tagname = conf.output.tag;
}
- if (resp == NULL)
- parse(&curp, fd, *argv);
- else if (resp->form == FORM_SRC)
- parse(&curp, fd, resp->file);
+ mandoc_msg_setinfilename(thisarg);
+ if (resp == NULL || resp->form == FORM_SRC)
+ parse(&curp, fd, thisarg);
else
passthrough(resp->file, fd,
conf.output.synopsisonly);
+ mandoc_msg_setinfilename(NULL);
if (ferror(stdout)) {
if (tag_files != NULL) {
@@ -543,7 +550,7 @@ main(int argc, char *argv[])
tag_files = NULL;
} else
warn("stdout");
- rc = MANDOCLEVEL_SYSERR;
+ mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
break;
}
@@ -552,10 +559,11 @@ main(int argc, char *argv[])
outdata_alloc(&curp);
terminal_sepline(curp.outdata);
}
- } else if (rc < MANDOCLEVEL_ERROR)
- rc = MANDOCLEVEL_ERROR;
+ } else
+ mandoc_msg(MANDOCERR_FILE, 0, 0,
+ "%s: %s", thisarg, strerror(errno));
- if (MANDOCLEVEL_OK != rc && curp.wstop)
+ if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
break;
if (resp != NULL)
@@ -646,7 +654,7 @@ out:
if (pid == -1) {
warn("wait");
- rc = MANDOCLEVEL_SYSERR;
+ mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
break;
}
if (!WIFSTOPPED(status))
@@ -656,8 +664,7 @@ out:
}
tag_unlink();
}
-
- return (int)rc;
+ return (int)mandoc_msg_getrc();
}
static void
@@ -755,7 +762,6 @@ found:
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;
@@ -790,8 +796,18 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
return 1;
}
if (res != NULL && *ressz == lastsz &&
- strchr(*argv, '/') == NULL)
- warnx("No entry for %s in the manual.", *argv);
+ strchr(*argv, '/') == NULL) {
+ if (cfg->arch != NULL &&
+ arch_valid(cfg->arch, OSENUM) == 0)
+ warnx("Unknown architecture \"%s\".",
+ cfg->arch);
+ else if (cfg->sec == NULL)
+ warnx("No entry for %s in the manual.",
+ *argv);
+ else
+ warnx("No entry for %s in section %s "
+ "of the manual.", *argv, cfg->sec);
+ }
lastsz = *ressz;
argv++;
argc--;
@@ -802,101 +818,92 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
static void
parse(struct curparse *curp, int fd, const char *file)
{
- enum mandoclevel rctmp;
- struct roff_man *man;
+ struct roff_meta *meta;
/* Begin by parsing the file itself. */
assert(file);
assert(fd >= 0);
- rctmp = mparse_readfd(curp->mp, fd, file);
+ mparse_readfd(curp->mp, fd, file);
if (fd != STDIN_FILENO)
close(fd);
- if (rc < rctmp)
- rc = rctmp;
/*
* With -Wstop and warnings or errors of at least the requested
* level, do not produce output.
*/
- if (rctmp != MANDOCLEVEL_OK && curp->wstop)
+ if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
return;
if (curp->outdata == NULL)
outdata_alloc(curp);
+ else if (curp->outtype == OUTT_HTML)
+ html_reset(curp);
- mparse_result(curp->mp, &man, NULL);
+ mandoc_xr_reset();
+ meta = mparse_result(curp->mp);
/* Execute the out device, if it exists. */
- if (man == NULL)
- return;
- mandoc_xr_reset();
- if (man->macroset == MACROSET_MDOC) {
- if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
- mdoc_validate(man);
+ if (meta->macroset == MACROSET_MDOC) {
switch (curp->outtype) {
case OUTT_HTML:
- html_mdoc(curp->outdata, man);
+ html_mdoc(curp->outdata, meta);
break;
case OUTT_TREE:
- tree_mdoc(curp->outdata, man);
+ tree_mdoc(curp->outdata, meta);
break;
case OUTT_MAN:
- man_mdoc(curp->outdata, man);
+ man_mdoc(curp->outdata, meta);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
- terminal_mdoc(curp->outdata, man);
+ terminal_mdoc(curp->outdata, meta);
break;
case OUTT_MARKDOWN:
- markdown_mdoc(curp->outdata, man);
+ markdown_mdoc(curp->outdata, meta);
break;
default:
break;
}
}
- if (man->macroset == MACROSET_MAN) {
- if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
- man_validate(man);
+ if (meta->macroset == MACROSET_MAN) {
switch (curp->outtype) {
case OUTT_HTML:
- html_man(curp->outdata, man);
+ html_man(curp->outdata, meta);
break;
case OUTT_TREE:
- tree_man(curp->outdata, man);
+ tree_man(curp->outdata, meta);
break;
case OUTT_MAN:
- man_man(curp->outdata, man);
+ mparse_copy(curp->mp);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
- terminal_man(curp->outdata, man);
+ terminal_man(curp->outdata, meta);
break;
default:
break;
}
}
- if (curp->mmin < MANDOCERR_STYLE)
- check_xr(file);
- mparse_updaterc(curp->mp, &rc);
+ if (mandoc_msg_getmin() < MANDOCERR_STYLE)
+ check_xr();
}
static void
-check_xr(const char *file)
+check_xr(void)
{
static struct manpaths paths;
struct mansearch search;
struct mandoc_xr *xr;
- char *cp;
size_t sz;
if (paths.sz == 0)
@@ -915,13 +922,12 @@ check_xr(const char *file)
if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz))
continue;
if (xr->count == 1)
- mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec);
+ mandoc_msg(MANDOCERR_XR_BAD, xr->line,
+ xr->pos + 1, "Xr %s %s", xr->name, xr->sec);
else
- mandoc_asprintf(&cp, "Xr %s %s (%d times)",
+ mandoc_msg(MANDOCERR_XR_BAD, xr->line,
+ xr->pos + 1, "Xr %s %s (%d times)",
xr->name, xr->sec, xr->count);
- mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
- file, xr->line, xr->pos + 1, cp);
- free(cp);
}
}
@@ -1020,8 +1026,7 @@ done:
fail:
free(line);
warn("%s: SYSERR: %s", file, syscall);
- if (rc < MANDOCLEVEL_SYSERR)
- rc = MANDOCLEVEL_SYSERR;
+ mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
}
static int
@@ -1063,8 +1068,8 @@ toptions(struct curparse *curp, char *arg)
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
- curp->mmin = MANDOCERR_BASE;
- mmsg_stream = stdout;
+ mandoc_msg_setoutfile(stdout);
+ mandoc_msg_setmin(MANDOCERR_BASE);
} else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man"))
@@ -1115,29 +1120,29 @@ woptions(struct curparse *curp, char *arg)
break;
case 1:
case 2:
- curp->mmin = MANDOCERR_BASE;
+ mandoc_msg_setmin(MANDOCERR_BASE);
break;
case 3:
- curp->mmin = MANDOCERR_STYLE;
+ mandoc_msg_setmin(MANDOCERR_STYLE);
break;
case 4:
- curp->mmin = MANDOCERR_WARNING;
+ mandoc_msg_setmin(MANDOCERR_WARNING);
break;
case 5:
- curp->mmin = MANDOCERR_ERROR;
+ mandoc_msg_setmin(MANDOCERR_ERROR);
break;
case 6:
- curp->mmin = MANDOCERR_UNSUPP;
+ mandoc_msg_setmin(MANDOCERR_UNSUPP);
break;
case 7:
- curp->mmin = MANDOCERR_MAX;
+ mandoc_msg_setmin(MANDOCERR_MAX);
break;
case 8:
- curp->mmin = MANDOCERR_BASE;
+ mandoc_msg_setmin(MANDOCERR_BASE);
curp->os_e = MANDOC_OS_OPENBSD;
break;
case 9:
- curp->mmin = MANDOCERR_BASE;
+ mandoc_msg_setmin(MANDOCERR_BASE);
curp->os_e = MANDOC_OS_NETBSD;
break;
default:
@@ -1148,29 +1153,6 @@ woptions(struct curparse *curp, char *arg)
return 1;
}
-static void
-mmsg(enum mandocerr t, enum mandoclevel lvl,
- const char *file, int line, int col, const char *msg)
-{
- const char *mparse_msg;
-
- fprintf(mmsg_stream, "%s: %s:", getprogname(),
- file == NULL ? "<stdin>" : file);
-
- if (line)
- fprintf(mmsg_stream, "%d:%d:", line, col + 1);
-
- fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
-
- if ((mparse_msg = mparse_strerror(t)) != NULL)
- fprintf(mmsg_stream, ": %s", mparse_msg);
-
- if (msg)
- fprintf(mmsg_stream, ": %s", msg);
-
- fputc('\n', mmsg_stream);
-}
-
static pid_t
spawn_pager(struct tag_files *tag_files)
{
@@ -1179,8 +1161,10 @@ spawn_pager(struct tag_files *tag_files)
char *argv[MAX_PAGER_ARGS];
const char *pager;
char *cp;
+#if HAVE_LESS_T
size_t cmdlen;
- int argc;
+#endif
+ int argc, use_ofn;
pid_t pager_pid;
pager = getenv("MANPAGER");
@@ -1196,7 +1180,7 @@ spawn_pager(struct tag_files *tag_files)
*/
argc = 0;
- while (argc + 4 < MAX_PAGER_ARGS) {
+ while (argc + 5 < MAX_PAGER_ARGS) {
argv[argc++] = cp;
cp = strchr(cp, ' ');
if (cp == NULL)
@@ -1210,14 +1194,23 @@ spawn_pager(struct tag_files *tag_files)
/* For less(1), use the tag file. */
+ use_ofn = 1;
+#if HAVE_LESS_T
if ((cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
if (strcmp(cp, "less") == 0) {
argv[argc++] = mandoc_strdup("-T");
argv[argc++] = tag_files->tfn;
+ if (tag_files->tagname != NULL) {
+ argv[argc++] = mandoc_strdup("-t");
+ argv[argc++] = tag_files->tagname;
+ use_ofn = 0;
+ }
}
}
- argv[argc++] = tag_files->ofn;
+#endif
+ if (use_ofn)
+ argv[argc++] = tag_files->ofn;
argv[argc] = NULL;
switch (pager_pid = fork()) {
diff --git a/usr/src/cmd/mandoc/main.h b/usr/src/cmd/mandoc/main.h
index f9b8f135f8..19a630cde8 100644
--- a/usr/src/cmd/mandoc/main.h
+++ b/usr/src/cmd/mandoc/main.h
@@ -1,7 +1,7 @@
-/* $Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */
+/* $Id: main.h,v 1.30 2019/03/03 13:02:11 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015, 2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-struct roff_man;
+struct roff_meta;
struct manoutput;
/*
@@ -27,15 +27,15 @@ struct manoutput;
*/
void *html_alloc(const struct manoutput *);
-void html_mdoc(void *, const struct roff_man *);
-void html_man(void *, const struct roff_man *);
+void html_mdoc(void *, const struct roff_meta *);
+void html_man(void *, const struct roff_meta *);
+void html_reset(void *);
void html_free(void *);
-void tree_mdoc(void *, const struct roff_man *);
-void tree_man(void *, const struct roff_man *);
+void tree_mdoc(void *, const struct roff_meta *);
+void tree_man(void *, const struct roff_meta *);
-void man_mdoc(void *, const struct roff_man *);
-void man_man(void *, const struct roff_man *);
+void man_mdoc(void *, const struct roff_meta *);
void *locale_alloc(const struct manoutput *);
void *utf8_alloc(const struct manoutput *);
@@ -46,8 +46,8 @@ void *pdf_alloc(const struct manoutput *);
void *ps_alloc(const struct manoutput *);
void pspdf_free(void *);
-void terminal_mdoc(void *, const struct roff_man *);
-void terminal_man(void *, const struct roff_man *);
+void terminal_mdoc(void *, const struct roff_meta *);
+void terminal_man(void *, const struct roff_meta *);
void terminal_sepline(void *);
-void markdown_mdoc(void *, const struct roff_man *);
+void markdown_mdoc(void *, const struct roff_meta *);
diff --git a/usr/src/cmd/mandoc/man.c b/usr/src/cmd/mandoc/man.c
index 7a2bcc9688..f0e4002b2a 100644
--- a/usr/src/cmd/mandoc/man.c
+++ b/usr/src/cmd/mandoc/man.c
@@ -1,7 +1,7 @@
-/* $Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */
+/* $Id: man.c,v 1.187 2019/01/05 00:36:50 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -35,7 +35,7 @@
#include "roff_int.h"
#include "libman.h"
-static void man_descope(struct roff_man *, int, int);
+static char *man_hasc(char *);
static int man_ptext(struct roff_man *, int, char *, int);
static int man_pmacro(struct roff_man *, int, char *, int);
@@ -52,38 +52,62 @@ man_parseln(struct roff_man *man, int ln, char *buf, int offs)
man_ptext(man, ln, buf, offs);
}
-static void
-man_descope(struct roff_man *man, int line, int offs)
+/*
+ * If the string ends with \c, return a pointer to the backslash.
+ * Otherwise, return NULL.
+ */
+static char *
+man_hasc(char *start)
{
+ char *cp, *ep;
+
+ ep = strchr(start, '\0') - 2;
+ if (ep < start || ep[0] != '\\' || ep[1] != 'c')
+ return NULL;
+ for (cp = ep; cp > start; cp--)
+ if (cp[-1] != '\\')
+ break;
+ return (ep - cp) % 2 ? NULL : ep;
+}
+
+void
+man_descope(struct roff_man *man, int line, int offs, char *start)
+{
+ /* Trailing \c keeps next-line scope open. */
+
+ if (start != NULL && man_hasc(start) != NULL)
+ return;
+
/*
* Co-ordinate what happens with having a next-line scope open:
- * first close out the element scope (if applicable), then close
- * out the block scope (also if applicable).
+ * first close out the element scopes (if applicable),
+ * then close out the block scope (also if applicable).
*/
if (man->flags & MAN_ELINE) {
+ while (man->last->parent->type != ROFFT_ROOT &&
+ man_macro(man->last->parent->tok)->flags & MAN_ESCOPED)
+ man_unscope(man, man->last->parent);
man->flags &= ~MAN_ELINE;
- man_unscope(man, man->last->parent);
}
if ( ! (man->flags & MAN_BLINE))
return;
- man->flags &= ~MAN_BLINE;
man_unscope(man, man->last->parent);
roff_body_alloc(man, line, offs, man->last->tok);
+ man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
}
static int
man_ptext(struct roff_man *man, int line, char *buf, int offs)
{
int i;
- const char *cp, *sp;
char *ep;
- /* Literal free-form text whitespace is preserved. */
+ /* In no-fill mode, whitespace is preserved on text lines. */
- if (man->flags & MAN_LITERAL) {
+ if (man->flags & ROFF_NOFILL) {
roff_word_alloc(man, line, offs, buf + offs);
- man_descope(man, line, offs);
+ man_descope(man, line, offs, buf + offs);
return 1;
}
@@ -98,26 +122,15 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
if (buf[i] == '\0') {
if (man->flags & (MAN_ELINE | MAN_BLINE)) {
- mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
- line, 0, NULL);
+ mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL);
return 1;
}
if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
return 1;
- switch (man->last->type) {
- case ROFFT_TEXT:
- sp = man->last->string;
- cp = ep = strchr(sp, '\0') - 2;
- if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
- break;
- while (cp > sp && cp[-1] == '\\')
- cp--;
- if ((ep - cp) % 2)
- break;
+ if (man->last->type == ROFFT_TEXT &&
+ ((ep = man_hasc(man->last->string)) != NULL)) {
*ep = '\0';
return 1;
- default:
- break;
}
roff_elem_alloc(man, line, offs, ROFF_sp);
man->next = ROFF_NEXT_SIBLING;
@@ -134,8 +147,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
if (i > 1 && '\\' != buf[i - 2])
- mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
- line, i - 1, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL);
for (--i; i && ' ' == buf[i]; i--)
/* Spin back to non-space. */ ;
@@ -157,7 +169,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
if (mandoc_eos(buf, (size_t)i))
man->last->flags |= NODE_EOS;
- man_descope(man, line, offs);
+ man_descope(man, line, offs, buf + offs);
return 1;
}
@@ -180,8 +192,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
if (sz > 0 && sz < 4)
tok = roffhash_find(man->manmac, buf + ppos, sz);
if (tok == TOKEN_NONE) {
- mandoc_msg(MANDOCERR_MACRO, man->parse,
- ln, ppos, buf + ppos - 1);
+ mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1);
return 1;
}
@@ -211,8 +222,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
*/
if (buf[offs] == '\0' && buf[offs - 1] == ' ')
- mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
- ln, offs - 1, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
/*
* Some macros break next-line scopes; otherwise, remember
@@ -230,16 +240,12 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
* page, that's very likely what the author intended.
*/
- if (bline) {
- cp = strchr(buf + offs, '\0') - 2;
- if (cp >= buf && cp[0] == '\\' && cp[1] == 'c')
- bline = 0;
- }
+ if (bline && man_hasc(buf + offs))
+ bline = 0;
/* Call to handler... */
- assert(man_macros[tok].fp);
- (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
+ (*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
@@ -256,15 +262,15 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
* unless the next-line scope is allowed to continue.
*/
- if ( ! bline || man->flags & MAN_ELINE ||
- man_macros[tok].flags & MAN_NSCOPED)
+ if (bline == 0 ||
+ (man->flags & MAN_BLINE) == 0 ||
+ man->flags & MAN_ELINE ||
+ man_macro(tok)->flags & MAN_NSCOPED)
return 1;
- assert(man->flags & MAN_BLINE);
- man->flags &= ~MAN_BLINE;
-
man_unscope(man, man->last->parent);
roff_body_alloc(man, ln, ppos, man->last->tok);
+ man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
return 1;
}
@@ -280,17 +286,17 @@ man_breakscope(struct roff_man *man, int tok)
*/
if (man->flags & MAN_ELINE && (tok < MAN_TH ||
- ! (man_macros[tok].flags & MAN_NSCOPED))) {
+ (man_macro(tok)->flags & MAN_NSCOPED) == 0)) {
n = man->last;
if (n->type == ROFFT_TEXT)
n = n->parent;
if (n->tok < MAN_TH ||
- man_macros[n->tok].flags & MAN_NSCOPED)
+ (man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED))
+ == MAN_NSCOPED)
n = n->parent;
- mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
- n->line, n->pos, "%s breaks %s",
- roff_name[tok], roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
+ "%s breaks %s", roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
man->flags &= ~MAN_ELINE;
@@ -302,12 +308,12 @@ man_breakscope(struct roff_man *man, int tok)
*/
if (man->flags & MAN_BLINE &&
- (tok == MAN_nf || tok == MAN_fi) &&
+ (tok == ROFF_nf || tok == ROFF_fi) &&
(man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
n = man->last;
man_unscope(man, n);
roff_body_alloc(man, n->line, n->pos, n->tok);
- man->flags &= ~MAN_BLINE;
+ man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
}
/*
@@ -316,68 +322,24 @@ man_breakscope(struct roff_man *man, int tok)
* Delete the block that is being broken.
*/
- if (man->flags & MAN_BLINE && (tok < MAN_TH ||
- man_macros[tok].flags & MAN_BSCOPE)) {
+ if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi &&
+ (tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) {
n = man->last;
if (n->type == ROFFT_TEXT)
n = n->parent;
if (n->tok < MAN_TH ||
- (man_macros[n->tok].flags & MAN_BSCOPE) == 0)
+ (man_macro(n->tok)->flags & MAN_XSCOPE) == 0)
n = n->parent;
assert(n->type == ROFFT_HEAD);
n = n->parent;
assert(n->type == ROFFT_BLOCK);
- assert(man_macros[n->tok].flags & MAN_SCOPED);
+ assert(man_macro(n->tok)->flags & MAN_BSCOPED);
- mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
- n->line, n->pos, "%s breaks %s",
- roff_name[tok], roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
+ "%s breaks %s", roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
- man->flags &= ~MAN_BLINE;
+ man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
}
}
-
-const struct mparse *
-man_mparse(const struct roff_man *man)
-{
-
- assert(man && man->parse);
- return man->parse;
-}
-
-void
-man_state(struct roff_man *man, struct roff_node *n)
-{
-
- switch(n->tok) {
- case MAN_nf:
- case MAN_EX:
- if (man->flags & MAN_LITERAL && ! (n->flags & NODE_VALID))
- mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
- n->line, n->pos, "nf");
- man->flags |= MAN_LITERAL;
- break;
- case MAN_fi:
- case MAN_EE:
- if ( ! (man->flags & MAN_LITERAL) &&
- ! (n->flags & NODE_VALID))
- mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
- n->line, n->pos, "fi");
- man->flags &= ~MAN_LITERAL;
- break;
- default:
- break;
- }
- man->last->flags |= NODE_VALID;
-}
-
-void
-man_validate(struct roff_man *man)
-{
-
- man->last = man->first;
- man_node_validate(man);
- man->flags &= ~MAN_LITERAL;
-}
diff --git a/usr/src/cmd/mandoc/man.h b/usr/src/cmd/mandoc/man.h
index d671f9a9e4..ed4375c0c0 100644
--- a/usr/src/cmd/mandoc/man.h
+++ b/usr/src/cmd/mandoc/man.h
@@ -1,4 +1,4 @@
-/* $Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */
+/* $Id: man.h,v 1.79 2018/08/23 19:33:27 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -18,5 +18,4 @@
struct roff_man;
-const struct mparse *man_mparse(const struct roff_man *);
void man_validate(struct roff_man *);
diff --git a/usr/src/cmd/mandoc/man_html.c b/usr/src/cmd/mandoc/man_html.c
index ae5dac1ad9..994a208aa0 100644
--- a/usr/src/cmd/mandoc/man_html.c
+++ b/usr/src/cmd/mandoc/man_html.c
@@ -1,7 +1,7 @@
-/* $Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */
+/* $Id: man_html.c,v 1.173 2019/03/02 16:30:53 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2015, 2017-2019 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
@@ -33,26 +33,22 @@
#include "html.h"
#include "main.h"
-/* FIXME: have PD set the default vspace width. */
-
#define MAN_ARGS const struct roff_meta *man, \
const struct roff_node *n, \
struct html *h
-struct htmlman {
+struct man_html_act {
int (*pre)(MAN_ARGS);
int (*post)(MAN_ARGS);
};
-static void print_bvspace(struct html *,
- const struct roff_node *);
static void print_man_head(const struct roff_meta *,
struct html *);
static void print_man_nodelist(MAN_ARGS);
static void print_man_node(MAN_ARGS);
-static int fillmode(struct html *, int);
+static char list_continues(const struct roff_node *,
+ const struct roff_node *);
static int man_B_pre(MAN_ARGS);
-static int man_HP_pre(MAN_ARGS);
static int man_IP_pre(MAN_ARGS);
static int man_I_pre(MAN_ARGS);
static int man_OP_pre(MAN_ARGS);
@@ -60,8 +56,9 @@ static int man_PP_pre(MAN_ARGS);
static int man_RS_pre(MAN_ARGS);
static int man_SH_pre(MAN_ARGS);
static int man_SM_pre(MAN_ARGS);
-static int man_SS_pre(MAN_ARGS);
+static int man_SY_pre(MAN_ARGS);
static int man_UR_pre(MAN_ARGS);
+static int man_abort_pre(MAN_ARGS);
static int man_alt_pre(MAN_ARGS);
static int man_ign_pre(MAN_ARGS);
static int man_in_pre(MAN_ARGS);
@@ -70,16 +67,17 @@ static void man_root_post(const struct roff_meta *,
static void man_root_pre(const struct roff_meta *,
struct html *);
-static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
+static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
{ NULL, NULL }, /* TH */
{ man_SH_pre, NULL }, /* SH */
- { man_SS_pre, NULL }, /* SS */
+ { man_SH_pre, NULL }, /* SS */
{ man_IP_pre, NULL }, /* TP */
- { man_PP_pre, NULL }, /* LP */
+ { man_IP_pre, NULL }, /* TQ */
+ { man_abort_pre, NULL }, /* LP */
{ man_PP_pre, NULL }, /* PP */
- { man_PP_pre, NULL }, /* P */
+ { man_abort_pre, NULL }, /* P */
{ man_IP_pre, NULL }, /* IP */
- { man_HP_pre, NULL }, /* HP */
+ { man_PP_pre, NULL }, /* HP */
{ man_SM_pre, NULL }, /* SM */
{ man_SM_pre, NULL }, /* SB */
{ man_alt_pre, NULL }, /* BI */
@@ -91,8 +89,6 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_I_pre, NULL }, /* I */
{ man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */
- { NULL, NULL }, /* nf */
- { NULL, NULL }, /* fi */
{ NULL, NULL }, /* RE */
{ man_RS_pre, NULL }, /* RS */
{ man_ign_pre, NULL }, /* DT */
@@ -100,6 +96,8 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_ign_pre, NULL }, /* PD */
{ man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */
+ { man_SY_pre, NULL }, /* SY */
+ { NULL, NULL }, /* YS */
{ man_OP_pre, NULL }, /* OP */
{ NULL, NULL }, /* EX */
{ NULL, NULL }, /* EE */
@@ -108,34 +106,10 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_UR_pre, NULL }, /* MT */
{ NULL, NULL }, /* ME */
};
-static const struct htmlman *const mans = __mans - MAN_TH;
-
-
-/*
- * Printing leading vertical space before a block.
- * This is used for the paragraph macros.
- * The rules are pretty simple, since there's very little nesting going
- * on here. Basically, if we're the first within another block (SS/SH),
- * then don't emit vertical space. If we are (RS), then do. If not the
- * first, print it.
- */
-static void
-print_bvspace(struct html *h, const struct roff_node *n)
-{
- if (n->body && n->body->child)
- if (n->body->child->type == ROFFT_TBL)
- return;
-
- if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
- if (NULL == n->prev)
- return;
-
- print_paragraph(h);
-}
void
-html_man(void *arg, const struct roff_man *man)
+html_man(void *arg, const struct roff_meta *man)
{
struct html *h;
struct roff_node *n;
@@ -147,19 +121,19 @@ html_man(void *arg, const struct roff_man *man)
if ((h->oflags & HTML_FRAGMENT) == 0) {
print_gen_decls(h);
print_otag(h, TAG_HTML, "");
- if (n->type == ROFFT_COMMENT)
+ if (n != NULL && n->type == ROFFT_COMMENT)
print_gen_comment(h, n);
t = print_otag(h, TAG_HEAD, "");
- print_man_head(&man->meta, h);
+ print_man_head(man, h);
print_tagq(h, t);
print_otag(h, TAG_BODY, "");
}
- man_root_pre(&man->meta, h);
+ man_root_pre(man, h);
t = print_otag(h, TAG_DIV, "c", "manual-text");
- print_man_nodelist(&man->meta, n, h);
+ print_man_nodelist(man, n, h);
print_tagq(h, t);
- man_root_post(&man->meta, h);
+ man_root_post(man, h);
print_tagq(h, NULL);
}
@@ -178,7 +152,6 @@ print_man_head(const struct roff_meta *man, struct html *h)
static void
print_man_nodelist(MAN_ARGS)
{
-
while (n != NULL) {
print_man_node(man, n, h);
n = n->next;
@@ -188,99 +161,33 @@ print_man_nodelist(MAN_ARGS)
static void
print_man_node(MAN_ARGS)
{
- static int want_fillmode = MAN_fi;
- static int save_fillmode;
-
struct tag *t;
int child;
- /*
- * Handle fill mode switch requests up front,
- * they would just cause trouble in the subsequent code.
- */
-
- switch (n->tok) {
- case MAN_nf:
- case MAN_EX:
- want_fillmode = MAN_nf;
+ if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
return;
- case MAN_fi:
- case MAN_EE:
- want_fillmode = MAN_fi;
- if (fillmode(h, 0) == MAN_fi)
- print_otag(h, TAG_BR, "");
- return;
- default:
- break;
- }
- /* Set up fill mode for the upcoming node. */
-
- switch (n->type) {
- case ROFFT_BLOCK:
- save_fillmode = 0;
- /* Some block macros suspend or cancel .nf. */
- switch (n->tok) {
- case MAN_TP: /* Tagged paragraphs */
- case MAN_IP: /* temporarily disable .nf */
- case MAN_HP: /* for the head. */
- save_fillmode = want_fillmode;
- /* FALLTHROUGH */
- case MAN_SH: /* Section headers */
- case MAN_SS: /* permanently cancel .nf. */
- want_fillmode = MAN_fi;
- /* FALLTHROUGH */
- case MAN_PP: /* These have no head. */
- case MAN_LP: /* They will simply */
- case MAN_P: /* reopen .nf in the body. */
- case MAN_RS:
- case MAN_UR:
- case MAN_MT:
- fillmode(h, MAN_fi);
- break;
- default:
- break;
- }
- break;
- case ROFFT_TBL:
- fillmode(h, MAN_fi);
- break;
- case ROFFT_ELEM:
- /*
- * Some in-line macros produce tags and/or text
- * in the handler, so they require fill mode to be
- * configured up front just like for text nodes.
- * For the others, keep the traditional approach
- * of doing the same, for now.
- */
- fillmode(h, want_fillmode);
- break;
- case ROFFT_TEXT:
- if (fillmode(h, want_fillmode) == MAN_fi &&
- want_fillmode == MAN_fi &&
- n->flags & NODE_LINE && *n->string == ' ' &&
- (h->flags & HTML_NONEWLINE) == 0)
- print_otag(h, TAG_BR, "");
- if (*n->string != '\0')
- break;
- print_paragraph(h);
- return;
- case ROFFT_COMMENT:
- return;
- default:
- break;
- }
-
- /* Produce output for this node. */
+ html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
child = 1;
switch (n->type) {
case ROFFT_TEXT:
+ if (*n->string == '\0') {
+ print_endline(h);
+ return;
+ }
+ if (*n->string == ' ' && n->flags & NODE_LINE &&
+ (h->flags & HTML_NONEWLINE) == 0)
+ print_endline(h);
+ else if (n->flags & NODE_DELIMC)
+ h->flags |= HTML_NOSPACE;
t = h->tag;
+ t->refcnt++;
print_text(h, n->string);
break;
case ROFFT_EQN:
t = h->tag;
+ t->refcnt++;
print_eqn(h, n->eqn);
break;
case ROFFT_TBL:
@@ -306,62 +213,51 @@ print_man_node(MAN_ARGS)
* the "meta" table state. This will be reopened on the
* next table element.
*/
- if (h->tblt)
+ if (h->tblt != NULL)
print_tblclose(h);
-
t = h->tag;
+ t->refcnt++;
if (n->tok < ROFF_MAX) {
roff_html_pre(h, n);
- child = 0;
- break;
+ t->refcnt--;
+ print_stagq(h, t);
+ return;
}
-
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
- if (mans[n->tok].pre)
- child = (*mans[n->tok].pre)(man, n, h);
-
- /* Some block macros resume .nf in the body. */
- if (save_fillmode && n->type == ROFFT_BODY)
- want_fillmode = save_fillmode;
-
+ if (man_html_acts[n->tok - MAN_TH].pre != NULL)
+ child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
+ n, h);
break;
}
- if (child && n->child)
+ if (child && n->child != NULL)
print_man_nodelist(man, n->child, h);
/* This will automatically close out any font scope. */
- print_stagq(h, t);
+ t->refcnt--;
+ if (n->type == ROFFT_BLOCK &&
+ (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
+ t = h->tag;
+ while (t->tag != TAG_DL && t->tag != TAG_UL)
+ t = t->next;
+ /*
+ * Close the list if no further item of the same type
+ * follows; otherwise, close the item only.
+ */
+ if (list_continues(n, n->next) == '\0') {
+ print_tagq(h, t);
+ t = NULL;
+ }
+ }
+ if (t != NULL)
+ print_stagq(h, t);
- if (fillmode(h, 0) == MAN_nf &&
- n->next != NULL && n->next->flags & NODE_LINE)
+ if (n->flags & NODE_NOFILL && n->tok != MAN_YS &&
+ (n->next != NULL && n->next->flags & NODE_LINE)) {
+ /* In .nf = <pre>, print even empty lines. */
+ h->col++;
print_endline(h);
-}
-
-/*
- * MAN_nf switches to no-fill mode, MAN_fi to fill mode.
- * Other arguments do not switch.
- * The old mode is returned.
- */
-static int
-fillmode(struct html *h, int want)
-{
- struct tag *pre;
- int had;
-
- for (pre = h->tag; pre != NULL; pre = pre->next)
- if (pre->tag == TAG_PRE)
- break;
-
- had = pre == NULL ? MAN_fi : MAN_nf;
-
- if (want && want != had) {
- if (want == MAN_nf)
- print_otag(h, TAG_PRE, "");
- else
- print_tagq(h, pre);
}
- return had;
}
static void
@@ -382,7 +278,7 @@ man_root_pre(const struct roff_meta *man, struct html *h)
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "head-vol");
- if (NULL != man->vol)
+ if (man->vol != NULL)
print_text(h, man->vol);
print_stagq(h, tt);
@@ -405,7 +301,7 @@ man_root_post(const struct roff_meta *man, struct html *h)
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "foot-os");
- if (man->os)
+ if (man->os != NULL)
print_text(h, man->os);
print_tagq(h, t);
}
@@ -413,13 +309,32 @@ man_root_post(const struct roff_meta *man, struct html *h)
static int
man_SH_pre(MAN_ARGS)
{
- char *id;
-
- if (n->type == ROFFT_HEAD) {
+ const char *class;
+ char *id;
+ enum htmltag tag;
+
+ if (n->tok == MAN_SH) {
+ tag = TAG_H1;
+ class = "Sh";
+ } else {
+ tag = TAG_H2;
+ class = "Ss";
+ }
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ print_otag(h, TAG_SECTION, "c", class);
+ break;
+ case ROFFT_HEAD:
id = html_make_id(n, 1);
- print_otag(h, TAG_H1, "cTi", "Sh", id);
+ print_otag(h, tag, "ci", class, id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
+ break;
+ case ROFFT_BODY:
+ break;
+ default:
+ abort();
}
return 1;
}
@@ -428,11 +343,11 @@ static int
man_alt_pre(MAN_ARGS)
{
const struct roff_node *nn;
+ struct tag *t;
int i;
enum htmltag fp;
- struct tag *t;
- for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
+ for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
switch (n->tok) {
case MAN_BI:
fp = i % 2 ? TAG_I : TAG_B;
@@ -474,88 +389,135 @@ static int
man_SM_pre(MAN_ARGS)
{
print_otag(h, TAG_SMALL, "");
- if (MAN_SB == n->tok)
+ if (n->tok == MAN_SB)
print_otag(h, TAG_B, "");
return 1;
}
static int
-man_SS_pre(MAN_ARGS)
+man_PP_pre(MAN_ARGS)
{
- char *id;
-
- if (n->type == ROFFT_HEAD) {
- id = html_make_id(n, 1);
- print_otag(h, TAG_H2, "cTi", "Ss", id);
- if (id != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ break;
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
+ if (n->child != NULL &&
+ (n->child->flags & NODE_NOFILL) == 0)
+ print_otag(h, TAG_P, "c",
+ n->tok == MAN_PP ? "Pp" : "Pp HP");
+ break;
+ default:
+ abort();
}
return 1;
}
-static int
-man_PP_pre(MAN_ARGS)
+static char
+list_continues(const struct roff_node *n1, const struct roff_node *n2)
{
-
- if (n->type == ROFFT_HEAD)
- return 0;
- else if (n->type == ROFFT_BLOCK)
- print_bvspace(h, n);
-
- return 1;
+ const char *s1, *s2;
+ char c1, c2;
+
+ if (n1 == NULL || n1->type != ROFFT_BLOCK ||
+ n2 == NULL || n2->type != ROFFT_BLOCK)
+ return '\0';
+ if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
+ (n2->tok == MAN_TP || n2->tok == MAN_TQ))
+ return ' ';
+ if (n1->tok != MAN_IP || n2->tok != MAN_IP)
+ return '\0';
+ n1 = n1->head->child;
+ n2 = n2->head->child;
+ s1 = n1 == NULL ? "" : n1->string;
+ s2 = n2 == NULL ? "" : n2->string;
+ c1 = strcmp(s1, "*") == 0 ? '*' :
+ strcmp(s1, "\\-") == 0 ? '-' :
+ strcmp(s1, "\\(bu") == 0 ? 'b' : ' ';
+ c2 = strcmp(s2, "*") == 0 ? '*' :
+ strcmp(s2, "\\-") == 0 ? '-' :
+ strcmp(s2, "\\(bu") == 0 ? 'b' : ' ';
+ return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
}
static int
man_IP_pre(MAN_ARGS)
{
const struct roff_node *nn;
+ const char *list_class;
+ enum htmltag list_elem, body_elem;
+ char list_type;
+
+ nn = n->type == ROFFT_BLOCK ? n : n->parent;
+ if ((list_type = list_continues(nn->prev, nn)) == '\0') {
+ /* Start a new list. */
+ if ((list_type = list_continues(nn, nn->next)) == '\0')
+ list_type = ' ';
+ switch (list_type) {
+ case ' ':
+ list_class = "Bl-tag";
+ list_elem = TAG_DL;
+ break;
+ case '*':
+ list_class = "Bl-bullet";
+ list_elem = TAG_UL;
+ break;
+ case '-':
+ list_class = "Bl-dash";
+ list_elem = TAG_UL;
+ break;
+ default:
+ abort();
+ }
+ } else {
+ /* Continue a list that was started earlier. */
+ list_class = NULL;
+ list_elem = TAG_MAX;
+ }
+ body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
- if (n->type == ROFFT_BODY) {
- print_otag(h, TAG_DD, "");
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ if (list_elem != TAG_MAX)
+ print_otag(h, list_elem, "c", list_class);
return 1;
- } else if (n->type != ROFFT_HEAD) {
- print_otag(h, TAG_DL, "c", "Bl-tag");
+ case ROFFT_HEAD:
+ if (body_elem == TAG_LI)
+ return 0;
+ print_otag(h, TAG_DT, "");
+ break;
+ case ROFFT_BODY:
+ print_otag(h, body_elem, "");
return 1;
+ default:
+ abort();
}
- /* FIXME: width specification. */
-
- print_otag(h, TAG_DT, "");
-
- /* For IP, only print the first header element. */
-
- if (MAN_IP == n->tok && n->child)
- print_man_node(man, n->child, h);
-
- /* For TP, only print next-line header elements. */
-
- if (MAN_TP == n->tok) {
+ switch(n->tok) {
+ case MAN_IP: /* Only print the first header element. */
+ if (n->child != NULL)
+ print_man_node(man, n->child, h);
+ break;
+ case MAN_TP: /* Only print next-line header elements. */
+ case MAN_TQ:
nn = n->child;
- while (NULL != nn && 0 == (NODE_LINE & nn->flags))
+ while (nn != NULL && (NODE_LINE & nn->flags) == 0)
nn = nn->next;
- while (NULL != nn) {
+ while (nn != NULL) {
print_man_node(man, nn, h);
nn = nn->next;
}
+ break;
+ default:
+ abort();
}
-
return 0;
}
static int
-man_HP_pre(MAN_ARGS)
-{
- if (n->type == ROFFT_HEAD)
- return 0;
-
- if (n->type == ROFFT_BLOCK) {
- print_bvspace(h, n);
- print_otag(h, TAG_DIV, "c", "HP");
- }
- return 1;
-}
-
-static int
man_OP_pre(MAN_ARGS)
{
struct tag *tt;
@@ -564,14 +526,14 @@ man_OP_pre(MAN_ARGS)
h->flags |= HTML_NOSPACE;
tt = print_otag(h, TAG_SPAN, "c", "Op");
- if (NULL != (n = n->child)) {
+ if ((n = n->child) != NULL) {
print_otag(h, TAG_B, "");
print_text(h, n->string);
}
print_stagq(h, tt);
- if (NULL != n && NULL != n->next) {
+ if (n != NULL && n->next != NULL) {
print_otag(h, TAG_I, "");
print_text(h, n->next->string);
}
@@ -606,17 +568,46 @@ man_in_pre(MAN_ARGS)
static int
man_ign_pre(MAN_ARGS)
{
-
return 0;
}
static int
man_RS_pre(MAN_ARGS)
{
- if (n->type == ROFFT_HEAD)
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ break;
+ case ROFFT_HEAD:
return 0;
- if (n->type == ROFFT_BLOCK)
+ case ROFFT_BODY:
print_otag(h, TAG_DIV, "c", "Bd-indent");
+ break;
+ default:
+ abort();
+ }
+ return 1;
+}
+
+static int
+man_SY_pre(MAN_ARGS)
+{
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ print_otag(h, TAG_TABLE, "c", "Nm");
+ print_otag(h, TAG_TR, "");
+ break;
+ case ROFFT_HEAD:
+ print_otag(h, TAG_TD, "");
+ print_otag(h, TAG_CODE, "c", "Nm");
+ break;
+ case ROFFT_BODY:
+ print_otag(h, TAG_TD, "");
+ break;
+ default:
+ abort();
+ }
return 1;
}
@@ -624,16 +615,17 @@ static int
man_UR_pre(MAN_ARGS)
{
char *cp;
+
n = n->child;
assert(n->type == ROFFT_HEAD);
if (n->child != NULL) {
assert(n->child->type == ROFFT_TEXT);
if (n->tok == MAN_MT) {
mandoc_asprintf(&cp, "mailto:%s", n->child->string);
- print_otag(h, TAG_A, "cTh", "Mt", cp);
+ print_otag(h, TAG_A, "ch", "Mt", cp);
free(cp);
} else
- print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
+ print_otag(h, TAG_A, "ch", "Lk", n->child->string);
}
assert(n->next->type == ROFFT_BODY);
@@ -641,6 +633,11 @@ man_UR_pre(MAN_ARGS)
n = n->next;
print_man_nodelist(man, n->child, h);
-
return 0;
}
+
+static int
+man_abort_pre(MAN_ARGS)
+{
+ abort();
+}
diff --git a/usr/src/cmd/mandoc/man_macro.c b/usr/src/cmd/mandoc/man_macro.c
index aa8b200196..d195576dee 100644
--- a/usr/src/cmd/mandoc/man_macro.c
+++ b/usr/src/cmd/mandoc/man_macro.c
@@ -1,7 +1,7 @@
-/* $Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.144 2019/01/05 18:59:46 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012-2015, 2017-2019 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,47 +41,54 @@ static int man_args(struct roff_man *, int,
int *, char *, char **);
static void rew_scope(struct roff_man *, enum roff_tok);
-const struct man_macro __man_macros[MAN_MAX - MAN_TH] = {
- { in_line_eoln, MAN_BSCOPE }, /* TH */
- { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
- { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
- { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */
- { blk_imp, MAN_BSCOPE }, /* LP */
- { blk_imp, MAN_BSCOPE }, /* PP */
- { blk_imp, MAN_BSCOPE }, /* P */
- { blk_imp, MAN_BSCOPE }, /* IP */
- { blk_imp, MAN_BSCOPE }, /* HP */
- { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */
- { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */
+static const struct man_macro man_macros[MAN_MAX - MAN_TH] = {
+ { in_line_eoln, MAN_XSCOPE }, /* TH */
+ { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SH */
+ { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SS */
+ { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TP */
+ { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TQ */
+ { blk_imp, MAN_XSCOPE }, /* LP */
+ { blk_imp, MAN_XSCOPE }, /* PP */
+ { blk_imp, MAN_XSCOPE }, /* P */
+ { blk_imp, MAN_XSCOPE }, /* IP */
+ { blk_imp, MAN_XSCOPE }, /* HP */
+ { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SM */
+ { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SB */
{ in_line_eoln, 0 }, /* BI */
{ in_line_eoln, 0 }, /* IB */
{ in_line_eoln, 0 }, /* BR */
{ in_line_eoln, 0 }, /* RB */
- { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */
- { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */
- { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
+ { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* R */
+ { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* B */
+ { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
- { in_line_eoln, MAN_NSCOPED }, /* nf */
- { in_line_eoln, MAN_NSCOPED }, /* fi */
- { blk_close, MAN_BSCOPE }, /* RE */
- { blk_exp, MAN_BSCOPE }, /* RS */
+ { blk_close, MAN_XSCOPE }, /* RE */
+ { blk_exp, MAN_XSCOPE }, /* RS */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
{ in_line_eoln, MAN_NSCOPED }, /* PD */
{ in_line_eoln, 0 }, /* AT */
{ in_line_eoln, MAN_NSCOPED }, /* in */
+ { blk_imp, MAN_XSCOPE }, /* SY */
+ { blk_close, MAN_XSCOPE }, /* YS */
{ in_line_eoln, 0 }, /* OP */
- { in_line_eoln, MAN_BSCOPE }, /* EX */
- { in_line_eoln, MAN_BSCOPE }, /* EE */
- { blk_exp, MAN_BSCOPE }, /* UR */
- { blk_close, MAN_BSCOPE }, /* UE */
- { blk_exp, MAN_BSCOPE }, /* MT */
- { blk_close, MAN_BSCOPE }, /* ME */
+ { in_line_eoln, MAN_XSCOPE }, /* EX */
+ { in_line_eoln, MAN_XSCOPE }, /* EE */
+ { blk_exp, MAN_XSCOPE }, /* UR */
+ { blk_close, MAN_XSCOPE }, /* UE */
+ { blk_exp, MAN_XSCOPE }, /* MT */
+ { blk_close, MAN_XSCOPE }, /* ME */
};
-const struct man_macro *const man_macros = __man_macros - MAN_TH;
+const struct man_macro *
+man_macro(enum roff_tok tok)
+{
+ assert(tok >= MAN_TH && tok <= MAN_MAX);
+ return man_macros + (tok - MAN_TH);
+}
+
void
man_unscope(struct roff_man *man, const struct roff_node *to)
{
@@ -94,9 +102,10 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
if (to == NULL && ! (n->flags & NODE_VALID)) {
if (man->flags & (MAN_BLINE | MAN_ELINE) &&
- man_macros[n->tok].flags & MAN_SCOPED) {
- mandoc_vmsg(MANDOCERR_BLK_LINE,
- man->parse, n->line, n->pos,
+ man_macro(n->tok)->flags &
+ (MAN_BSCOPED | MAN_NSCOPED)) {
+ mandoc_msg(MANDOCERR_BLK_LINE,
+ n->line, n->pos,
"EOF breaks %s", roff_name[n->tok]);
if (man->flags & MAN_ELINE)
man->flags &= ~MAN_ELINE;
@@ -111,9 +120,9 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
continue;
}
if (n->type == ROFFT_BLOCK &&
- man_macros[n->tok].fp == blk_exp)
+ man_macro(n->tok)->fp == blk_exp)
mandoc_msg(MANDOCERR_BLK_NOEND,
- man->parse, n->line, n->pos,
+ n->line, n->pos, "%s",
roff_name[n->tok]);
}
@@ -175,7 +184,7 @@ rew_scope(struct roff_man *man, enum roff_tok tok)
}
if (tok != MAN_SH && (n->tok == MAN_SH ||
(tok != MAN_SS && (n->tok == MAN_SS ||
- man_macros[n->tok].fp == blk_exp))))
+ man_macro(n->tok)->fp == blk_exp))))
return;
man_unscope(man, n);
n = man->last;
@@ -189,33 +198,39 @@ rew_scope(struct roff_man *man, enum roff_tok tok)
void
blk_close(MACRO_PROT_ARGS)
{
- enum roff_tok ntok;
+ enum roff_tok ctok, ntok;
const struct roff_node *nn;
- char *p;
- int nrew, target;
+ char *p, *ep;
+ int cline, cpos, la, nrew, target;
nrew = 1;
switch (tok) {
case MAN_RE:
ntok = MAN_RS;
+ la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
for (nn = man->last->parent; nn; nn = nn->parent)
if (nn->tok == ntok && nn->type == ROFFT_BLOCK)
nrew++;
- target = strtol(p, &p, 10);
- if (*p != '\0')
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
- line, p - buf, "RE ... %s", p);
+ target = strtol(p, &ep, 10);
+ if (*ep != '\0')
+ mandoc_msg(MANDOCERR_ARG_EXCESS, line,
+ la + (buf[la] == '"') + (int)(ep - p),
+ "RE ... %s", ep);
+ free(p);
if (target == 0)
target = 1;
nrew -= target;
if (nrew < 1) {
- mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
+ mandoc_msg(MANDOCERR_RE_NOTOPEN,
line, ppos, "RE %d", target);
return;
}
break;
+ case MAN_YS:
+ ntok = MAN_SY;
+ break;
case MAN_UE:
ntok = MAN_UR;
break;
@@ -231,25 +246,47 @@ blk_close(MACRO_PROT_ARGS)
break;
if (nn == NULL) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
- line, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN,
+ line, ppos, "%s", roff_name[tok]);
rew_scope(man, MAN_PP);
- } else {
- line = man->last->line;
- ppos = man->last->pos;
- ntok = man->last->tok;
- man_unscope(man, nn);
+ if (tok == MAN_RE) {
+ roff_elem_alloc(man, line, ppos, ROFF_br);
+ man->last->flags |= NODE_LINE |
+ NODE_VALID | NODE_ENDED;
+ man->next = ROFF_NEXT_SIBLING;
+ }
+ return;
+ }
- if (tok == MAN_RE && nn->head->aux > 0)
- roff_setreg(man->roff, "an-margin",
- nn->head->aux, '-');
+ cline = man->last->line;
+ cpos = man->last->pos;
+ ctok = man->last->tok;
+ man_unscope(man, nn);
- /* Move a trailing paragraph behind the block. */
+ if (tok == MAN_RE && nn->head->aux > 0)
+ roff_setreg(man->roff, "an-margin", nn->head->aux, '-');
- if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
- *pos = strlen(buf);
- blk_imp(man, ntok, line, ppos, pos, buf);
- }
+ /* Trailing text. */
+
+ if (buf[*pos] != '\0') {
+ roff_word_alloc(man, line, ppos, buf + *pos);
+ man->last->flags |= NODE_DELIMC;
+ if (mandoc_eos(man->last->string, strlen(man->last->string)))
+ man->last->flags |= NODE_EOS;
+ }
+
+ /* Move a trailing paragraph behind the block. */
+
+ if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) {
+ *pos = strlen(buf);
+ blk_imp(man, ctok, cline, cpos, pos, buf);
+ }
+
+ /* Synopsis blocks need an explicit end marker for spacing. */
+
+ if (tok == MAN_YS && man->last == nn) {
+ roff_elem_alloc(man, line, ppos, tok);
+ man_unscope(man, man->last);
}
}
@@ -260,7 +297,10 @@ blk_exp(MACRO_PROT_ARGS)
char *p;
int la;
- rew_scope(man, tok);
+ if (tok == MAN_RS) {
+ rew_scope(man, tok);
+ man->flags |= ROFF_NONOFILL;
+ }
roff_block_alloc(man, line, ppos, tok);
head = roff_head_alloc(man, line, ppos, tok);
@@ -275,14 +315,16 @@ blk_exp(MACRO_PROT_ARGS)
roff_setreg(man->roff, "an-margin",
head->aux, '+');
}
+ free(p);
}
if (buf[*pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
- *pos, "%s ... %s", roff_name[tok], buf + *pos);
+ mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
+ "%s ... %s", roff_name[tok], buf + *pos);
man_unscope(man, head);
roff_body_alloc(man, line, ppos, tok);
+ man->flags &= ~ROFF_NONOFILL;
}
/*
@@ -299,9 +341,10 @@ blk_imp(MACRO_PROT_ARGS)
struct roff_node *n;
rew_scope(man, tok);
- n = roff_block_alloc(man, line, ppos, tok);
- if (n->tok == MAN_SH || n->tok == MAN_SS)
- man->flags &= ~MAN_LITERAL;
+ man->flags |= ROFF_NONOFILL;
+ if (tok == MAN_SH || tok == MAN_SS)
+ man->flags &= ~ROFF_NOFILL;
+ roff_block_alloc(man, line, ppos, tok);
n = roff_head_alloc(man, line, ppos, tok);
/* Add line arguments. */
@@ -311,16 +354,17 @@ blk_imp(MACRO_PROT_ARGS)
if ( ! man_args(man, line, pos, buf, &p))
break;
roff_word_alloc(man, line, la, p);
+ free(p);
}
/*
* For macros having optional next-line scope,
* keep the head open if there were no arguments.
- * For `TP', always keep the head open.
+ * For `TP' and `TQ', always keep the head open.
*/
- if (man_macros[tok].flags & MAN_SCOPED &&
- (tok == MAN_TP || n == man->last)) {
+ if (man_macro(tok)->flags & MAN_BSCOPED &&
+ (tok == MAN_TP || tok == MAN_TQ || n == man->last)) {
man->flags |= MAN_BLINE;
return;
}
@@ -329,6 +373,7 @@ blk_imp(MACRO_PROT_ARGS)
man_unscope(man, n);
roff_body_alloc(man, line, ppos, tok);
+ man->flags &= ~ROFF_NONOFILL;
}
void
@@ -341,27 +386,26 @@ in_line_eoln(MACRO_PROT_ARGS)
roff_elem_alloc(man, line, ppos, tok);
n = man->last;
+ if (tok == MAN_EX)
+ man->flags |= ROFF_NOFILL;
+ else if (tok == MAN_EE)
+ man->flags &= ~ROFF_NOFILL;
+
for (;;) {
- if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) {
- mandoc_vmsg(MANDOCERR_ARG_SKIP,
- man->parse, line, *pos, "%s %s",
- roff_name[tok], buf + *pos);
- break;
- }
if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) {
- mandoc_vmsg(MANDOCERR_ARG_EXCESS,
- man->parse, line, *pos, "%s ... %s",
- roff_name[tok], buf + *pos);
+ mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
+ "%s ... %s", roff_name[tok], buf + *pos);
break;
}
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
- if (man_macros[tok].flags & MAN_JOIN &&
+ if (man_macro(tok)->flags & MAN_JOIN &&
man->last->type == ROFFT_TEXT)
roff_word_append(man, p);
else
roff_word_alloc(man, line, la, p);
+ free(p);
}
/*
@@ -374,13 +418,12 @@ in_line_eoln(MACRO_PROT_ARGS)
man->last->flags |= NODE_EOS;
/*
- * If no arguments are specified and this is MAN_SCOPED (i.e.,
+ * If no arguments are specified and this is MAN_ESCOPED (i.e.,
* next-line scoped), then set our mode to indicate that we're
* waiting for terms to load into our context.
*/
- if (n == man->last && man_macros[tok].flags & MAN_SCOPED) {
- assert( ! (man_macros[tok].flags & MAN_NSCOPED));
+ if (n == man->last && man_macro(tok)->flags & MAN_ESCOPED) {
man->flags |= MAN_ELINE;
return;
}
@@ -391,18 +434,21 @@ in_line_eoln(MACRO_PROT_ARGS)
/* Rewind our element scope. */
for ( ; man->last; man->last = man->last->parent) {
- man_state(man, man->last);
+ man->last->flags |= NODE_VALID;
if (man->last == n)
break;
}
+
+ /* Rewind next-line scoped ancestors, if any. */
+
+ if (man_macro(tok)->flags & MAN_ESCOPED)
+ man_descope(man, line, ppos, NULL);
}
void
man_endparse(struct roff_man *man)
{
-
- man_unscope(man, man->first);
- man->flags &= ~MAN_LITERAL;
+ man_unscope(man, man->meta.first);
}
static int
@@ -417,6 +463,6 @@ man_args(struct roff_man *man, int line, int *pos, char *buf, char **v)
if ('\0' == *start)
return 0;
- *v = mandoc_getarg(man->parse, v, line, pos);
+ *v = roff_getarg(man->roff, v, line, pos);
return 1;
}
diff --git a/usr/src/cmd/mandoc/man_term.c b/usr/src/cmd/mandoc/man_term.c
index b5723ccf83..4bb3f9da28 100644
--- a/usr/src/cmd/mandoc/man_term.c
+++ b/usr/src/cmd/mandoc/man_term.c
@@ -1,7 +1,7 @@
-/* $Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
+/* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017-2019 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,7 +27,6 @@
#include <string.h>
#include "mandoc_aux.h"
-#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "out.h"
@@ -37,8 +36,6 @@
#define MAXMARGINS 64 /* maximum number of indented scopes */
struct mtermp {
- int fl;
-#define MANT_LITERAL (1 << 0)
int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
@@ -51,7 +48,7 @@ struct mtermp {
struct roff_node *n, \
const struct roff_meta *meta
-struct termact {
+struct man_term_act {
int (*pre)(DECL_ARGS);
void (*post)(DECL_ARGS);
int flags;
@@ -78,8 +75,10 @@ static int pre_PP(DECL_ARGS);
static int pre_RS(DECL_ARGS);
static int pre_SH(DECL_ARGS);
static int pre_SS(DECL_ARGS);
+static int pre_SY(DECL_ARGS);
static int pre_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS);
+static int pre_abort(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
@@ -89,18 +88,19 @@ static void post_IP(DECL_ARGS);
static void post_HP(DECL_ARGS);
static void post_RS(DECL_ARGS);
static void post_SH(DECL_ARGS);
-static void post_SS(DECL_ARGS);
+static void post_SY(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
-static const struct termact __termacts[MAN_MAX - MAN_TH] = {
+static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
- { pre_SS, post_SS, 0 }, /* SS */
+ { pre_SS, post_SH, 0 }, /* SS */
{ pre_TP, post_TP, 0 }, /* TP */
- { pre_PP, NULL, 0 }, /* LP */
+ { pre_TP, post_TP, 0 }, /* TQ */
+ { pre_abort, NULL, 0 }, /* LP */
{ pre_PP, NULL, 0 }, /* PP */
- { pre_PP, NULL, 0 }, /* P */
+ { pre_abort, NULL, 0 }, /* P */
{ pre_IP, post_IP, 0 }, /* IP */
{ pre_HP, post_HP, 0 }, /* HP */
{ NULL, NULL, 0 }, /* SM */
@@ -114,8 +114,6 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
- { pre_literal, NULL, 0 }, /* nf */
- { pre_literal, NULL, 0 }, /* fi */
{ NULL, NULL, 0 }, /* RE */
{ pre_RS, post_RS, 0 }, /* RS */
{ pre_DT, NULL, 0 }, /* DT */
@@ -123,6 +121,8 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
+ { pre_SY, post_SY, 0 }, /* SY */
+ { NULL, NULL, 0 }, /* YS */
{ pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */
@@ -131,15 +131,22 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_UR, post_UR, 0 }, /* MT */
{ NULL, NULL, 0 }, /* ME */
};
-static const struct termact *termacts = __termacts - MAN_TH;
+static const struct man_term_act *man_term_act(enum roff_tok);
+static const struct man_term_act *
+man_term_act(enum roff_tok tok)
+{
+ assert(tok >= MAN_TH && tok <= MAN_MAX);
+ return man_term_acts + (tok - MAN_TH);
+}
+
void
-terminal_man(void *arg, const struct roff_man *man)
+terminal_man(void *arg, const struct roff_meta *man)
{
+ struct mtermp mt;
struct termp *p;
struct roff_node *n;
- struct mtermp mt;
size_t save_defindent;
p = (struct termp *)arg;
@@ -151,7 +158,7 @@ terminal_man(void *arg, const struct roff_man *man)
term_tab_set(p, "T");
term_tab_set(p, ".5i");
- memset(&mt, 0, sizeof(struct mtermp));
+ memset(&mt, 0, sizeof(mt));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
@@ -164,18 +171,17 @@ terminal_man(void *arg, const struct roff_man *man)
!strcmp(n->child->child->string, "SYNOPSIS")) {
if (n->child->next->child != NULL)
print_man_nodelist(p, &mt,
- n->child->next->child,
- &man->meta);
+ n->child->next->child, man);
term_newln(p);
break;
}
n = n->next;
}
} else {
- term_begin(p, print_man_head, print_man_foot, &man->meta);
+ term_begin(p, print_man_head, print_man_foot, man);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
- print_man_nodelist(p, &mt, n, &man->meta);
+ print_man_nodelist(p, &mt, n, man);
term_end(p);
}
p->defindent = save_defindent;
@@ -196,12 +202,12 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
term_newln(p);
- if (n->body && n->body->child)
+ if (n->body != NULL && n->body->child != NULL)
if (n->body->child->type == ROFFT_TBL)
return;
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
- if (NULL == n->prev)
+ if (n->prev == NULL)
return;
for (i = 0; i < pardist; i++)
@@ -210,16 +216,20 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
static int
-pre_ign(DECL_ARGS)
+pre_abort(DECL_ARGS)
{
+ abort();
+}
+static int
+pre_ign(DECL_ARGS)
+{
return 0;
}
static int
pre_I(DECL_ARGS)
{
-
term_fontrepl(p, TERMFONT_UNDER);
return 1;
}
@@ -227,14 +237,8 @@ pre_I(DECL_ARGS)
static int
pre_literal(DECL_ARGS)
{
-
term_newln(p);
- if (n->tok == MAN_nf || n->tok == MAN_EX)
- mt->fl |= MANT_LITERAL;
- else
- mt->fl &= ~MANT_LITERAL;
-
/*
* Unlike .IP and .TP, .HP does not have a HEAD.
* So in case a second call to term_flushln() is needed,
@@ -247,7 +251,6 @@ pre_literal(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
-
return 0;
}
@@ -272,7 +275,7 @@ pre_alternate(DECL_ARGS)
{
enum termfont font[2];
struct roff_node *nn;
- int savelit, i;
+ int i;
switch (n->tok) {
case MAN_RB:
@@ -302,29 +305,21 @@ pre_alternate(DECL_ARGS)
default:
abort();
}
-
- savelit = MANT_LITERAL & mt->fl;
- mt->fl &= ~MANT_LITERAL;
-
- for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
+ for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
term_fontrepl(p, font[i]);
- if (savelit && NULL == nn->next)
- mt->fl |= MANT_LITERAL;
assert(nn->type == ROFFT_TEXT);
term_word(p, nn->string);
if (nn->flags & NODE_EOS)
- p->flags |= TERMP_SENTENCE;
- if (nn->next)
+ p->flags |= TERMP_SENTENCE;
+ if (nn->next != NULL)
p->flags |= TERMP_NOSPACE;
}
-
return 0;
}
static int
pre_B(DECL_ARGS)
{
-
term_fontrepl(p, TERMFONT_BOLD);
return 1;
}
@@ -332,20 +327,19 @@ pre_B(DECL_ARGS)
static int
pre_OP(DECL_ARGS)
{
-
term_word(p, "[");
- p->flags |= TERMP_NOSPACE;
+ p->flags |= TERMP_KEEP | TERMP_NOSPACE;
- if (NULL != (n = n->child)) {
+ if ((n = n->child) != NULL) {
term_fontrepl(p, TERMFONT_BOLD);
term_word(p, n->string);
}
- if (NULL != n && NULL != n->next) {
+ if (n != NULL && n->next != NULL) {
term_fontrepl(p, TERMFONT_UNDER);
term_word(p, n->next->string);
}
-
term_fontrepl(p, TERMFONT_NONE);
+ p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_NOSPACE;
term_word(p, "]");
return 0;
@@ -369,9 +363,9 @@ pre_in(DECL_ARGS)
cp = n->child->string;
less = 0;
- if ('-' == *cp)
+ if (*cp == '-')
less = -1;
- else if ('+' == *cp)
+ else if (*cp == '+')
less = 1;
else
cp--;
@@ -413,13 +407,18 @@ pre_HP(DECL_ARGS)
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
return 1;
+ case ROFFT_HEAD:
+ return 0;
case ROFFT_BODY:
break;
default:
- return 0;
+ abort();
}
- if ( ! (MANT_LITERAL & mt->fl)) {
+ if (n->child == NULL)
+ return 0;
+
+ if ((n->child->flags & NODE_NOFILL) == 0) {
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
}
@@ -445,8 +444,10 @@ pre_HP(DECL_ARGS)
static void
post_HP(DECL_ARGS)
{
-
switch (n->type) {
+ case ROFFT_BLOCK:
+ case ROFFT_HEAD:
+ break;
case ROFFT_BODY:
term_newln(p);
@@ -466,25 +467,27 @@ post_HP(DECL_ARGS)
p->tcol->rmargin = p->maxrmargin;
break;
default:
- break;
+ abort();
}
}
static int
pre_PP(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n, mt->pardist);
break;
- default:
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
p->tcol->offset = mt->offset;
break;
+ default:
+ abort();
}
-
- return n->type != ROFFT_HEAD;
+ return 1;
}
static int
@@ -492,21 +495,21 @@ pre_IP(DECL_ARGS)
{
struct roffsu su;
const struct roff_node *nn;
- int len, savelit;
+ int len;
switch (n->type) {
- case ROFFT_BODY:
- p->flags |= TERMP_NOSPACE;
- break;
+ case ROFFT_BLOCK:
+ print_bvspace(p, n, mt->pardist);
+ return 1;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case ROFFT_BLOCK:
- print_bvspace(p, n, mt->pardist);
- /* FALLTHROUGH */
+ case ROFFT_BODY:
+ p->flags |= TERMP_NOSPACE;
+ break;
default:
- return 1;
+ abort();
}
/* Calculate the offset from the optional second argument. */
@@ -526,33 +529,25 @@ pre_IP(DECL_ARGS)
case ROFFT_HEAD:
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
-
- savelit = MANT_LITERAL & mt->fl;
- mt->fl &= ~MANT_LITERAL;
-
- if (n->child)
+ if (n->child != NULL)
print_man_node(p, mt, n->child, meta);
-
- if (savelit)
- mt->fl |= MANT_LITERAL;
-
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
p->tcol->rmargin = p->maxrmargin;
break;
default:
- break;
+ abort();
}
-
return 1;
}
static void
post_IP(DECL_ARGS)
{
-
switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
@@ -564,7 +559,7 @@ post_IP(DECL_ARGS)
p->tcol->offset = mt->offset;
break;
default:
- break;
+ abort();
}
}
@@ -573,9 +568,13 @@ pre_TP(DECL_ARGS)
{
struct roffsu su;
struct roff_node *nn;
- int len, savelit;
+ int len;
switch (n->type) {
+ case ROFFT_BLOCK:
+ if (n->tok == MAN_TP)
+ print_bvspace(p, n, mt->pardist);
+ return 1;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
p->trailspace = 1;
@@ -583,11 +582,8 @@ pre_TP(DECL_ARGS)
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
- case ROFFT_BLOCK:
- print_bvspace(p, n, mt->pardist);
- /* FALLTHROUGH */
default:
- return 1;
+ abort();
}
/* Calculate offset. */
@@ -609,21 +605,15 @@ pre_TP(DECL_ARGS)
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
- savelit = MANT_LITERAL & mt->fl;
- mt->fl &= ~MANT_LITERAL;
-
/* Don't print same-line elements. */
nn = n->child;
- while (NULL != nn && 0 == (NODE_LINE & nn->flags))
+ while (nn != NULL && (nn->flags & NODE_LINE) == 0)
nn = nn->next;
- while (NULL != nn) {
+ while (nn != NULL) {
print_man_node(p, mt, nn, meta);
nn = nn->next;
}
-
- if (savelit)
- mt->fl |= MANT_LITERAL;
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
@@ -632,17 +622,17 @@ pre_TP(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
default:
- break;
+ abort();
}
-
return 1;
}
static void
post_TP(DECL_ARGS)
{
-
switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
case ROFFT_HEAD:
term_flushln(p);
break;
@@ -651,7 +641,7 @@ post_TP(DECL_ARGS)
p->tcol->offset = mt->offset;
break;
default:
- break;
+ abort();
}
}
@@ -662,7 +652,6 @@ pre_SS(DECL_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
- mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@@ -674,7 +663,7 @@ pre_SS(DECL_ARGS)
do {
n = n->prev;
} while (n != NULL && n->tok >= MAN_TH &&
- termacts[n->tok].flags & MAN_NOTEXT);
+ man_term_act(n->tok)->flags & MAN_NOTEXT);
if (n == NULL || n->type == ROFFT_COMMENT ||
(n->tok == MAN_SS && n->body->child == NULL))
break;
@@ -698,26 +687,9 @@ pre_SS(DECL_ARGS)
default:
break;
}
-
return 1;
}
-static void
-post_SS(DECL_ARGS)
-{
-
- switch (n->type) {
- case ROFFT_HEAD:
- term_newln(p);
- break;
- case ROFFT_BODY:
- term_newln(p);
- break;
- default:
- break;
- }
-}
-
static int
pre_SH(DECL_ARGS)
{
@@ -725,7 +697,6 @@ pre_SH(DECL_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
- mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@@ -737,7 +708,7 @@ pre_SH(DECL_ARGS)
do {
n = n->prev;
} while (n != NULL && n->tok >= MAN_TH &&
- termacts[n->tok].flags & MAN_NOTEXT);
+ man_term_act(n->tok)->flags & MAN_NOTEXT);
if (n == NULL || n->type == ROFFT_COMMENT ||
(n->tok == MAN_SH && n->body->child == NULL))
break;
@@ -759,25 +730,23 @@ pre_SH(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
default:
- break;
+ abort();
}
-
return 1;
}
static void
post_SH(DECL_ARGS)
{
-
switch (n->type) {
- case ROFFT_HEAD:
- term_newln(p);
+ case ROFFT_BLOCK:
break;
+ case ROFFT_HEAD:
case ROFFT_BODY:
term_newln(p);
break;
default:
- break;
+ abort();
}
}
@@ -792,8 +761,10 @@ pre_RS(DECL_ARGS)
return 1;
case ROFFT_HEAD:
return 0;
- default:
+ case ROFFT_BODY:
break;
+ default:
+ abort();
}
n = n->parent->head;
@@ -821,42 +792,99 @@ pre_RS(DECL_ARGS)
static void
post_RS(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
- return;
case ROFFT_HEAD:
return;
- default:
- term_newln(p);
+ case ROFFT_BODY:
break;
+ default:
+ abort();
}
-
+ term_newln(p);
mt->offset -= n->parent->head->aux;
p->tcol->offset = mt->offset;
-
if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
}
static int
-pre_UR(DECL_ARGS)
+pre_SY(DECL_ARGS)
+{
+ const struct roff_node *nn;
+ int len;
+
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ if (n->prev == NULL || n->prev->tok != MAN_SY)
+ print_bvspace(p, n, mt->pardist);
+ return 1;
+ case ROFFT_HEAD:
+ case ROFFT_BODY:
+ break;
+ default:
+ abort();
+ }
+
+ nn = n->parent->head->child;
+ len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
+
+ switch (n->type) {
+ case ROFFT_HEAD:
+ p->tcol->offset = mt->offset;
+ p->tcol->rmargin = mt->offset + len;
+ if (n->next->child == NULL ||
+ (n->next->child->flags & NODE_NOFILL) == 0)
+ p->flags |= TERMP_NOBREAK;
+ term_fontrepl(p, TERMFONT_BOLD);
+ break;
+ case ROFFT_BODY:
+ mt->lmargin[mt->lmargincur] = len;
+ p->tcol->offset = mt->offset + len;
+ p->tcol->rmargin = p->maxrmargin;
+ p->flags |= TERMP_NOSPACE;
+ break;
+ default:
+ abort();
+ }
+ return 1;
+}
+
+static void
+post_SY(DECL_ARGS)
{
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
+ case ROFFT_HEAD:
+ term_flushln(p);
+ p->flags &= ~TERMP_NOBREAK;
+ break;
+ case ROFFT_BODY:
+ term_newln(p);
+ p->tcol->offset = mt->offset;
+ break;
+ default:
+ abort();
+ }
+}
+static int
+pre_UR(DECL_ARGS)
+{
return n->type != ROFFT_HEAD;
}
static void
post_UR(DECL_ARGS)
{
-
if (n->type != ROFFT_BLOCK)
return;
term_word(p, "<");
p->flags |= TERMP_NOSPACE;
- if (NULL != n->child->child)
+ if (n->child->child != NULL)
print_man_node(p, mt, n->child->child, meta);
p->flags |= TERMP_NOSPACE;
@@ -866,7 +894,8 @@ post_UR(DECL_ARGS)
static void
print_man_node(DECL_ARGS)
{
- int c;
+ const struct man_term_act *act;
+ int c;
switch (n->type) {
case ROFFT_TEXT:
@@ -884,6 +913,8 @@ print_man_node(DECL_ARGS)
} else if (*n->string == ' ' && n->flags & NODE_LINE &&
(p->flags & TERMP_NONEWLINE) == 0)
term_newln(p);
+ else if (n->flags & NODE_DELIMC)
+ p->flags |= TERMP_NOSPACE;
term_word(p, n->string);
goto out;
@@ -910,20 +941,20 @@ print_man_node(DECL_ARGS)
return;
}
- assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
- if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
+ act = man_term_act(n->tok);
+ if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
term_fontrepl(p, TERMFONT_NONE);
c = 1;
- if (termacts[n->tok].pre)
- c = (*termacts[n->tok].pre)(p, mt, n, meta);
+ if (act->pre != NULL)
+ c = (*act->pre)(p, mt, n, meta);
- if (c && n->child)
+ if (c && n->child != NULL)
print_man_nodelist(p, mt, n->child, meta);
- if (termacts[n->tok].post)
- (*termacts[n->tok].post)(p, mt, n, meta);
- if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
+ if (act->post != NULL)
+ (*act->post)(p, mt, n, meta);
+ if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
term_fontrepl(p, TERMFONT_NONE);
out:
@@ -934,7 +965,7 @@ out:
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
- if (mt->fl & MANT_LITERAL &&
+ if (n->flags & NODE_NOFILL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
(n->next == NULL || n->next->flags & NODE_LINE)) {
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
@@ -949,15 +980,13 @@ out:
p->tcol->rmargin = p->maxrmargin;
}
}
- if (NODE_EOS & n->flags)
+ if (n->flags & NODE_EOS)
p->flags |= TERMP_SENTENCE;
}
-
static void
print_man_nodelist(DECL_ARGS)
{
-
while (n != NULL) {
print_man_node(p, mt, n, meta);
n = n->next;
@@ -992,7 +1021,7 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
}
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
- } else if (meta->os) {
+ } else if (meta->os != NULL) {
title = mandoc_strdup(meta->os);
} else {
title = mandoc_strdup("");
diff --git a/usr/src/cmd/mandoc/man_validate.c b/usr/src/cmd/mandoc/man_validate.c
index d6c51af525..4bfaf764e6 100644
--- a/usr/src/cmd/mandoc/man_validate.c
+++ b/usr/src/cmd/mandoc/man_validate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD$ */
+/* $Id: man_validate.c,v 1.146 2018/12/31 10:04:39 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -24,6 +24,7 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -40,28 +41,32 @@
typedef void (*v_check)(CHKARGS);
+static void check_abort(CHKARGS);
static void check_par(CHKARGS);
static void check_part(CHKARGS);
static void check_root(CHKARGS);
static void check_text(CHKARGS);
static void post_AT(CHKARGS);
+static void post_EE(CHKARGS);
+static void post_EX(CHKARGS);
static void post_IP(CHKARGS);
static void post_OP(CHKARGS);
+static void post_SH(CHKARGS);
static void post_TH(CHKARGS);
static void post_UC(CHKARGS);
static void post_UR(CHKARGS);
static void post_in(CHKARGS);
-static void post_vs(CHKARGS);
-static const v_check __man_valids[MAN_MAX - MAN_TH] = {
+static const v_check man_valids[MAN_MAX - MAN_TH] = {
post_TH, /* TH */
- NULL, /* SH */
- NULL, /* SS */
+ post_SH, /* SH */
+ post_SH, /* SS */
NULL, /* TP */
- check_par, /* LP */
+ NULL, /* TQ */
+ check_abort,/* LP */
check_par, /* PP */
- check_par, /* P */
+ check_abort,/* P */
post_IP, /* IP */
NULL, /* HP */
NULL, /* SM */
@@ -75,8 +80,6 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
NULL, /* I */
NULL, /* IR */
NULL, /* RI */
- NULL, /* nf */
- NULL, /* fi */
NULL, /* RE */
check_part, /* RS */
NULL, /* DT */
@@ -84,33 +87,56 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
NULL, /* PD */
post_AT, /* AT */
post_in, /* in */
+ NULL, /* SY */
+ NULL, /* YS */
post_OP, /* OP */
- NULL, /* EX */
- NULL, /* EE */
+ post_EX, /* EX */
+ post_EE, /* EE */
post_UR, /* UR */
NULL, /* UE */
post_UR, /* MT */
NULL, /* ME */
};
-static const v_check *man_valids = __man_valids - MAN_TH;
+/* Validate the subtree rooted at man->last. */
void
-man_node_validate(struct roff_man *man)
+man_validate(struct roff_man *man)
{
struct roff_node *n;
const v_check *cp;
+ /*
+ * Translate obsolete macros such that later code
+ * does not need to look for them.
+ */
+
n = man->last;
+ switch (n->tok) {
+ case MAN_LP:
+ case MAN_P:
+ n->tok = MAN_PP;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Iterate over all children, recursing into each one
+ * in turn, depth-first.
+ */
+
man->last = man->last->child;
while (man->last != NULL) {
- man_node_validate(man);
+ man_validate(man);
if (man->last == n)
man->last = man->last->child;
else
man->last = man->last->next;
}
+ /* Finally validate the macro itself. */
+
man->last = n;
man->next = ROFF_NEXT_SIBLING;
switch (n->type) {
@@ -126,23 +152,15 @@ man_node_validate(struct roff_man *man)
break;
default:
if (n->tok < ROFF_MAX) {
- switch (n->tok) {
- case ROFF_br:
- case ROFF_sp:
- post_vs(man, n);
- break;
- default:
- roff_validate(man);
- break;
- }
+ roff_validate(man);
break;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
- cp = man_valids + n->tok;
+ cp = man_valids + (n->tok - MAN_TH);
if (*cp)
(*cp)(man, n);
if (man->last == n)
- man_state(man, n);
+ n->flags |= NODE_VALID;
break;
}
}
@@ -153,14 +171,12 @@ check_root(CHKARGS)
assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
if (n->last == NULL || n->last->type == ROFFT_COMMENT)
- mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
- n->line, n->pos, NULL);
+ mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL);
else
man->meta.hasbody = 1;
if (NULL == man->meta.title) {
- mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
- n->line, n->pos, NULL);
+ mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL);
/*
* If a title hasn't been set, do so now (by
@@ -175,23 +191,43 @@ check_root(CHKARGS)
if (man->meta.os_e &&
(man->meta.rcsids & (1 << man->meta.os_e)) == 0)
- mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0,
+ mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0,
man->meta.os_e == MANDOC_OS_OPENBSD ?
"(OpenBSD)" : "(NetBSD)");
}
static void
+check_abort(CHKARGS)
+{
+ abort();
+}
+
+static void
check_text(CHKARGS)
{
char *cp, *p;
- if (MAN_LITERAL & man->flags)
+ if (n->flags & NODE_NOFILL)
return;
cp = n->string;
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
- mandoc_msg(MANDOCERR_FI_TAB, man->parse,
- n->line, n->pos + (p - cp), NULL);
+ mandoc_msg(MANDOCERR_FI_TAB,
+ n->line, n->pos + (int)(p - cp), NULL);
+}
+
+static void
+post_EE(CHKARGS)
+{
+ if ((n->flags & NODE_NOFILL) == 0)
+ mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "EE");
+}
+
+static void
+post_EX(CHKARGS)
+{
+ if (n->flags & NODE_NOFILL)
+ mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "EX");
}
static void
@@ -199,21 +235,55 @@ post_OP(CHKARGS)
{
if (n->child == NULL)
- mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
- n->line, n->pos, "OP");
+ mandoc_msg(MANDOCERR_OP_EMPTY, n->line, n->pos, "OP");
else if (n->child->next != NULL && n->child->next->next != NULL) {
n = n->child->next->next;
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
n->line, n->pos, "OP ... %s", n->string);
}
}
static void
+post_SH(CHKARGS)
+{
+ struct roff_node *nc;
+
+ if (n->type != ROFFT_BODY || (nc = n->child) == NULL)
+ return;
+
+ if (nc->tok == MAN_PP && nc->body->child != NULL) {
+ while (nc->body->last != NULL) {
+ man->next = ROFF_NEXT_CHILD;
+ roff_node_relink(man, nc->body->last);
+ man->last = n;
+ }
+ }
+
+ if (nc->tok == MAN_PP || nc->tok == ROFF_sp || nc->tok == ROFF_br) {
+ mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos,
+ "%s after %s", roff_name[nc->tok], roff_name[n->tok]);
+ roff_node_delete(man, nc);
+ }
+
+ /*
+ * Trailing PP is empty, so it is deleted by check_par().
+ * Trailing sp is significant.
+ */
+
+ if ((nc = n->last) != NULL && nc->tok == ROFF_br) {
+ mandoc_msg(MANDOCERR_PAR_SKIP,
+ nc->line, nc->pos, "%s at the end of %s",
+ roff_name[nc->tok], roff_name[n->tok]);
+ roff_node_delete(man, nc);
+ }
+}
+
+static void
post_UR(CHKARGS)
{
if (n->type == ROFFT_HEAD && n->child == NULL)
- mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_UR_NOHEAD, n->line, n->pos,
+ "%s", roff_name[n->tok]);
check_part(man, n);
}
@@ -222,8 +292,8 @@ check_part(CHKARGS)
{
if (n->type == ROFFT_BODY && n->child == NULL)
- mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos,
+ "%s", roff_name[n->tok]);
}
static void
@@ -236,15 +306,22 @@ check_par(CHKARGS)
roff_node_delete(man, n);
break;
case ROFFT_BODY:
+ if (n->child != NULL &&
+ (n->child->tok == ROFF_sp || n->child->tok == ROFF_br)) {
+ mandoc_msg(MANDOCERR_PAR_SKIP,
+ n->child->line, n->child->pos,
+ "%s after %s", roff_name[n->child->tok],
+ roff_name[n->tok]);
+ roff_node_delete(man, n->child);
+ }
if (n->child == NULL)
- mandoc_vmsg(MANDOCERR_PAR_SKIP,
- man->parse, n->line, n->pos,
+ mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
"%s empty", roff_name[n->tok]);
break;
case ROFFT_HEAD:
if (n->child != NULL)
- mandoc_vmsg(MANDOCERR_ARG_SKIP,
- man->parse, n->line, n->pos, "%s %s%s",
+ mandoc_msg(MANDOCERR_ARG_SKIP,
+ n->line, n->pos, "%s %s%s",
roff_name[n->tok], n->child->string,
n->child->next != NULL ? " ..." : "");
break;
@@ -264,8 +341,7 @@ post_IP(CHKARGS)
break;
case ROFFT_BODY:
if (n->parent->head->child == NULL && n->child == NULL)
- mandoc_vmsg(MANDOCERR_PAR_SKIP,
- man->parse, n->line, n->pos,
+ mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
"%s empty", roff_name[n->tok]);
break;
default:
@@ -298,9 +374,8 @@ post_TH(CHKARGS)
/* Only warn about this once... */
if (isalpha((unsigned char)*p) &&
! isupper((unsigned char)*p)) {
- mandoc_vmsg(MANDOCERR_TITLE_CASE,
- man->parse, n->line,
- n->pos + (p - n->string),
+ mandoc_msg(MANDOCERR_TITLE_CASE, n->line,
+ n->pos + (int)(p - n->string),
"TH %s", n->string);
break;
}
@@ -308,8 +383,7 @@ post_TH(CHKARGS)
man->meta.title = mandoc_strdup(n->string);
} else {
man->meta.title = mandoc_strdup("");
- mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
- nb->line, nb->pos, "TH");
+ mandoc_msg(MANDOCERR_TH_NOTITLE, nb->line, nb->pos, "TH");
}
/* TITLE ->MSEC<- DATE OS VOL */
@@ -320,7 +394,7 @@ post_TH(CHKARGS)
man->meta.msec = mandoc_strdup(n->string);
else {
man->meta.msec = mandoc_strdup("");
- mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
+ mandoc_msg(MANDOCERR_MSEC_MISSING,
nb->line, nb->pos, "TH %s", man->meta.title);
}
@@ -334,7 +408,7 @@ post_TH(CHKARGS)
mandoc_normdate(man, n->string, n->line, n->pos);
} else {
man->meta.date = mandoc_strdup("");
- mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
+ mandoc_msg(MANDOCERR_DATE_MISSING,
n ? n->line : nb->line,
n ? n->pos : nb->pos, "TH");
}
@@ -362,7 +436,7 @@ post_TH(CHKARGS)
man->meta.vol = mandoc_strdup(p);
if (n != NULL && (n = n->next) != NULL)
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
n->line, n->pos, "TH ... %s", n->string);
/*
@@ -463,32 +537,3 @@ post_in(CHKARGS)
free(n->child->string);
n->child->string = s;
}
-
-static void
-post_vs(CHKARGS)
-{
-
- if (NULL != n->prev)
- return;
-
- switch (n->parent->tok) {
- case MAN_SH:
- case MAN_SS:
- case MAN_PP:
- case MAN_LP:
- case MAN_P:
- mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
- "%s after %s", roff_name[n->tok],
- roff_name[n->parent->tok]);
- /* FALLTHROUGH */
- case TOKEN_NONE:
- /*
- * Don't warn about this because it occurs in pod2man
- * and would cause considerable (unfixable) warnage.
- */
- roff_node_delete(man, n);
- break;
- default:
- break;
- }
-}
diff --git a/usr/src/cmd/mandoc/manconf.h b/usr/src/cmd/mandoc/manconf.h
index b4cd31646c..bb3761998c 100644
--- a/usr/src/cmd/mandoc/manconf.h
+++ b/usr/src/cmd/mandoc/manconf.h
@@ -1,6 +1,6 @@
-/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */
+/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -30,12 +30,14 @@ struct manoutput {
char *man;
char *paper;
char *style;
+ char *tag;
size_t indent;
size_t width;
int fragment;
int mdoc;
- int synopsisonly;
int noval;
+ int synopsisonly;
+ int toc;
};
struct manconf {
diff --git a/usr/src/cmd/mandoc/mandoc.c b/usr/src/cmd/mandoc/mandoc.c
index 1279b52ed5..fb9395a585 100644
--- a/usr/src/cmd/mandoc/mandoc.c
+++ b/usr/src/cmd/mandoc/mandoc.c
@@ -1,4 +1,4 @@
-/* $Id: mandoc.c,v 1.104 2018/07/28 18:34:15 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.114 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -32,16 +32,70 @@
#include "mandoc.h"
#include "roff.h"
#include "libmandoc.h"
+#include "roff_int.h"
static int a2time(time_t *, const char *, const char *);
static char *time2a(time_t);
enum mandoc_esc
+mandoc_font(const char *cp, int sz)
+{
+ switch (sz) {
+ case 0:
+ return ESCAPE_FONTPREV;
+ case 1:
+ switch (cp[0]) {
+ case 'B':
+ case '3':
+ return ESCAPE_FONTBOLD;
+ case 'I':
+ case '2':
+ return ESCAPE_FONTITALIC;
+ case 'P':
+ return ESCAPE_FONTPREV;
+ case 'R':
+ case '1':
+ return ESCAPE_FONTROMAN;
+ case '4':
+ return ESCAPE_FONTBI;
+ default:
+ return ESCAPE_ERROR;
+ }
+ case 2:
+ switch (cp[0]) {
+ case 'B':
+ switch (cp[1]) {
+ case 'I':
+ return ESCAPE_FONTBI;
+ default:
+ return ESCAPE_ERROR;
+ }
+ case 'C':
+ switch (cp[1]) {
+ case 'B':
+ return ESCAPE_FONTBOLD;
+ case 'I':
+ return ESCAPE_FONTITALIC;
+ case 'R':
+ case 'W':
+ return ESCAPE_FONTCW;
+ default:
+ return ESCAPE_ERROR;
+ }
+ default:
+ return ESCAPE_ERROR;
+ }
+ default:
+ return ESCAPE_ERROR;
+ }
+}
+
+enum mandoc_esc
mandoc_escape(const char **end, const char **start, int *sz)
{
const char *local_start;
- int local_sz;
+ int local_sz, c, i;
char term;
enum mandoc_esc gly;
@@ -56,6 +110,14 @@ mandoc_escape(const char **end, const char **start, int *sz)
sz = &local_sz;
/*
+ * Treat "\E" just like "\";
+ * it only makes a difference in copy mode.
+ */
+
+ if (**end == 'E')
+ ++*end;
+
+ /*
* Beyond the backslash, at least one input character
* is part of the escape sequence. With one exception
* (see below), that character won't be returned.
@@ -77,6 +139,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
*sz = 2;
break;
case '[':
+ if (**start == ' ') {
+ ++*end;
+ return ESCAPE_ERROR;
+ }
gly = ESCAPE_SPECIAL;
term = ']';
break;
@@ -91,11 +157,26 @@ mandoc_escape(const char **end, const char **start, int *sz)
/*
* Escapes taking no arguments at all.
*/
- case 'd':
- case 'u':
+ case '!':
+ case '?':
+ return ESCAPE_UNSUPP;
+ case '%':
+ case '&':
+ case ')':
case ',':
case '/':
+ case '^':
+ case 'a':
+ case 'd':
+ case 'r':
+ case 't':
+ case 'u':
+ case '{':
+ case '|':
+ case '}':
return ESCAPE_IGNORE;
+ case 'c':
+ return ESCAPE_NOSPACE;
case 'p':
return ESCAPE_BREAK;
@@ -113,32 +194,57 @@ mandoc_escape(const char **end, const char **start, int *sz)
* 'X' is the trigger. These have opaque sub-strings.
*/
case 'F':
+ case 'f':
case 'g':
case 'k':
case 'M':
case 'm':
case 'n':
+ case 'O':
case 'V':
case 'Y':
- gly = ESCAPE_IGNORE;
- /* FALLTHROUGH */
- case 'f':
- if (ESCAPE_ERROR == gly)
- gly = ESCAPE_FONT;
+ gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE;
switch (**start) {
case '(':
+ if ((*start)[-1] == 'O')
+ gly = ESCAPE_ERROR;
*start = ++*end;
*sz = 2;
break;
case '[':
+ if ((*start)[-1] == 'O')
+ gly = (*start)[1] == '5' ?
+ ESCAPE_UNSUPP : ESCAPE_ERROR;
*start = ++*end;
term = ']';
break;
default:
+ if ((*start)[-1] == 'O') {
+ switch (**start) {
+ case '0':
+ gly = ESCAPE_UNSUPP;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ break;
+ default:
+ gly = ESCAPE_ERROR;
+ break;
+ }
+ }
*sz = 1;
break;
}
break;
+ case '*':
+ if (strncmp(*start, "(.T", 3) != 0)
+ abort();
+ gly = ESCAPE_DEVICE;
+ *start = ++*end;
+ *sz = 2;
+ break;
/*
* These escapes are of the form \X'Y', where 'X' is the trigger
@@ -250,18 +356,29 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
/*
- * Anything else is assumed to be a glyph.
- * In this case, pass back the character after the backslash.
+ * Several special characters can be encoded as
+ * one-byte escape sequences without using \[].
*/
- default:
+ case ' ':
+ case '\'':
+ case '-':
+ case '.':
+ case '0':
+ case ':':
+ case '_':
+ case '`':
+ case 'e':
+ case '~':
gly = ESCAPE_SPECIAL;
+ /* FALLTHROUGH */
+ default:
+ if (gly == ESCAPE_ERROR)
+ gly = ESCAPE_UNDEF;
*start = --*end;
*sz = 1;
break;
}
- assert(ESCAPE_ERROR != gly);
-
/*
* Read up to the terminating character,
* paying attention to nested escapes.
@@ -284,6 +401,15 @@ mandoc_escape(const char **end, const char **start, int *sz)
}
}
*sz = (*end)++ - *start;
+
+ /*
+ * The file chars.c only provides one common list
+ * of character names, but \[-] == \- is the only
+ * one of the characters with one-byte names that
+ * allows enclosing the name in brackets.
+ */
+ if (gly == ESCAPE_SPECIAL && *sz == 1 && **start != '-')
+ return ESCAPE_ERROR;
} else {
assert(*sz > 0);
if ((size_t)*sz > strlen(*start))
@@ -295,43 +421,25 @@ mandoc_escape(const char **end, const char **start, int *sz)
switch (gly) {
case ESCAPE_FONT:
- if (2 == *sz) {
- if ('C' == **start) {
- /*
- * Treat constant-width font modes
- * just like regular font modes.
- */
- (*start)++;
- (*sz)--;
- } else {
- if ('B' == (*start)[0] && 'I' == (*start)[1])
- gly = ESCAPE_FONTBI;
+ gly = mandoc_font(*start, *sz);
+ break;
+ case ESCAPE_SPECIAL:
+ if (**start == 'c') {
+ if (*sz < 6 || *sz > 7 ||
+ strncmp(*start, "char", 4) != 0 ||
+ (int)strspn(*start + 4, "0123456789") + 4 < *sz)
break;
- }
- } else if (1 != *sz)
- break;
-
- switch (**start) {
- case '3':
- case 'B':
- gly = ESCAPE_FONTBOLD;
- break;
- case '2':
- case 'I':
- gly = ESCAPE_FONTITALIC;
- break;
- case 'P':
- gly = ESCAPE_FONTPREV;
- break;
- case '1':
- case 'R':
- gly = ESCAPE_FONTROMAN;
+ c = 0;
+ for (i = 4; i < *sz; i++)
+ c = 10 * c + ((*start)[i] - '0');
+ if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff)
+ break;
+ *start += 4;
+ *sz -= 4;
+ gly = ESCAPE_NUMBERED;
break;
}
- break;
- case ESCAPE_SPECIAL:
- if (1 == *sz && 'c' == **start)
- gly = ESCAPE_NOSPACE;
+
/*
* Unicode escapes are defined in groff as \[u0000]
* to \[u10FFFF], where the contained value must be
@@ -358,101 +466,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
return gly;
}
-/*
- * Parse a quoted or unquoted roff-style request or macro argument.
- * Return a pointer to the parsed argument, which is either the original
- * pointer or advanced by one byte in case the argument is quoted.
- * NUL-terminate the argument in place.
- * Collapse pairs of quotes inside quoted arguments.
- * Advance the argument pointer to the next argument,
- * or to the NUL byte terminating the argument line.
- */
-char *
-mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
-{
- char *start, *cp;
- int quoted, pairs, white;
-
- /* Quoting can only start with a new word. */
- start = *cpp;
- quoted = 0;
- if ('"' == *start) {
- quoted = 1;
- start++;
- }
-
- pairs = 0;
- white = 0;
- for (cp = start; '\0' != *cp; cp++) {
-
- /*
- * Move the following text left
- * after quoted quotes and after "\\" and "\t".
- */
- if (pairs)
- cp[-pairs] = cp[0];
-
- if ('\\' == cp[0]) {
- /*
- * In copy mode, translate double to single
- * backslashes and backslash-t to literal tabs.
- */
- switch (cp[1]) {
- case 't':
- cp[0] = '\t';
- /* FALLTHROUGH */
- case '\\':
- pairs++;
- cp++;
- break;
- case ' ':
- /* Skip escaped blanks. */
- if (0 == quoted)
- cp++;
- break;
- default:
- break;
- }
- } else if (0 == quoted) {
- if (' ' == cp[0]) {
- /* Unescaped blanks end unquoted args. */
- white = 1;
- break;
- }
- } else if ('"' == cp[0]) {
- if ('"' == cp[1]) {
- /* Quoted quotes collapse. */
- pairs++;
- cp++;
- } else {
- /* Unquoted quotes end quoted args. */
- quoted = 2;
- break;
- }
- }
- }
-
- /* Quoted argument without a closing quote. */
- if (1 == quoted)
- mandoc_msg(MANDOCERR_ARG_QUOTE, parse, ln, *pos, NULL);
-
- /* NUL-terminate this argument and move to the next one. */
- if (pairs)
- cp[-pairs] = '\0';
- if ('\0' != *cp) {
- *cp++ = '\0';
- while (' ' == *cp)
- cp++;
- }
- *pos += (int)(cp - start) + (quoted ? 1 : 0);
- *cpp = cp;
-
- if ('\0' == *cp && (white || ' ' == cp[-1]))
- mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL);
-
- return start;
-}
-
static int
a2time(time_t *t, const char *fmt, const char *p)
{
@@ -529,7 +542,7 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
/* No date specified: use today's date. */
if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) {
- mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, ln, pos, NULL);
+ mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL);
return time2a(time(NULL));
}
@@ -539,23 +552,20 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
a2time(&t, "%b %d, %Y", in)) {
cp = time2a(t);
if (t > time(NULL) + 86400)
- mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
- ln, pos, cp);
+ mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", cp);
else if (*in != '$' && strcmp(in, cp) != 0)
- mandoc_msg(MANDOCERR_DATE_NORM, man->parse,
- ln, pos, cp);
+ mandoc_msg(MANDOCERR_DATE_NORM, ln, pos, "%s", cp);
return cp;
}
/* In man(7), do not warn about the legacy format. */
if (a2time(&t, "%Y-%m-%d", in) == 0)
- mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, in);
+ mandoc_msg(MANDOCERR_DATE_BAD, ln, pos, "%s", in);
else if (t > time(NULL) + 86400)
- mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse, ln, pos, in);
- else if (man->macroset == MACROSET_MDOC)
- mandoc_vmsg(MANDOCERR_DATE_LEGACY, man->parse,
- ln, pos, "Dd %s", in);
+ mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", in);
+ else if (man->meta.macroset == MACROSET_MDOC)
+ mandoc_msg(MANDOCERR_DATE_LEGACY, ln, pos, "Dd %s", in);
/* Use any non-mdoc(7) date verbatim. */
diff --git a/usr/src/cmd/mandoc/mandoc.h b/usr/src/cmd/mandoc/mandoc.h
index dbc266cc3b..a44b192e0f 100644
--- a/usr/src/cmd/mandoc/mandoc.h
+++ b/usr/src/cmd/mandoc/mandoc.h
@@ -1,7 +1,7 @@
-/* $Id: mandoc.h,v 1.248 2018/07/28 18:34:15 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.262 2018/12/16 00:17:02 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Error handling, escape sequence, and character utilities.
*/
#define ASCII_NBRSP 31 /* non-breaking space */
@@ -158,6 +160,7 @@ enum mandocerr {
MANDOCERR_LB_BAD, /* unknown library name: Lb ... */
MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
+ MANDOCERR_CHAR_FONT, /* argument contains two font escapes */
MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
@@ -166,6 +169,7 @@ enum mandocerr {
MANDOCERR_FI_TAB, /* tab in filled text */
MANDOCERR_EOS, /* new sentence, new line */
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
+ MANDOCERR_ESC_UNDEF, /* undefined escape, printing literally: char */
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
/* related to tables */
@@ -195,6 +199,7 @@ enum mandocerr {
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
MANDOCERR_CHAR_BAD, /* skipping bad character: number */
MANDOCERR_MACRO, /* skipping unknown macro: macro */
+ MANDOCERR_REQ_NOMAC, /* skipping request outside 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 */
@@ -205,14 +210,18 @@ enum mandocerr {
/* related to request and macro arguments */
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
+ MANDOCERR_ARG_UNDEF, /* using macro argument outside macro */
+ MANDOCERR_ARG_NONUM, /* argument number is not numeric */
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
+ MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */
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_SHIFT, /* excessive shift: ..., but max is ... */
MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
MANDOCERR_SO_FAIL, /* .so request failed */
MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
@@ -223,7 +232,12 @@ enum mandocerr {
MANDOCERR_TOOLARGE, /* input too large */
MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
+ MANDOCERR_ESC_UNSUPP, /* unsupported escape sequence: escape */
MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
+ MANDOCERR_WHILE_NEST, /* nested .while loops */
+ MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */
+ MANDOCERR_WHILE_INTO, /* end of .while loop in inner scope */
+ MANDOCERR_WHILE_FAIL, /* cannot continue this .while loop */
MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
@@ -231,206 +245,22 @@ enum mandocerr {
MANDOCERR_MAX
};
-struct tbl_opts {
- char tab; /* cell-separator */
- char decimal; /* decimal point */
- int opts;
-#define TBL_OPT_CENTRE (1 << 0)
-#define TBL_OPT_EXPAND (1 << 1)
-#define TBL_OPT_BOX (1 << 2)
-#define TBL_OPT_DBOX (1 << 3)
-#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 */
- int lvert; /* width of left vertical line */
- int rvert; /* width of right vertical line */
-};
-
-enum tbl_cellt {
- TBL_CELL_CENTRE, /* c, C */
- TBL_CELL_RIGHT, /* r, R */
- TBL_CELL_LEFT, /* l, L */
- TBL_CELL_NUMBER, /* n, N */
- TBL_CELL_SPAN, /* s, S */
- TBL_CELL_LONG, /* a, A */
- TBL_CELL_DOWN, /* ^ */
- TBL_CELL_HORIZ, /* _, - */
- TBL_CELL_DHORIZ, /* = */
- TBL_CELL_MAX
-};
-
-/*
- * A cell in a layout row.
- */
-struct tbl_cell {
- struct tbl_cell *next;
- char *wstr; /* min width represented as a string */
- size_t width; /* minimum column width */
- size_t spacing; /* to the right of the column */
- int vert; /* width of subsequent vertical line */
- 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 */
-#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */
-#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */
-#define TBL_CELL_EQUAL (1 << 4) /* e, E */
-#define TBL_CELL_UP (1 << 5) /* u, U */
-#define TBL_CELL_WIGN (1 << 6) /* z, Z */
-#define TBL_CELL_WMAX (1 << 7) /* x, X */
- enum tbl_cellt pos;
-};
-
-/*
- * A layout row.
- */
-struct tbl_row {
- struct tbl_row *next;
- struct tbl_cell *first;
- struct tbl_cell *last;
- int vert; /* width of left vertical line */
-};
-
-enum tbl_datt {
- TBL_DATA_NONE, /* has no data */
- TBL_DATA_DATA, /* consists of data/string */
- TBL_DATA_HORIZ, /* horizontal line */
- TBL_DATA_DHORIZ, /* double-horizontal line */
- TBL_DATA_NHORIZ, /* squeezed horizontal line */
- TBL_DATA_NDHORIZ /* squeezed double-horizontal line */
-};
-
-/*
- * A cell within a row of data. The "string" field contains the actual
- * string value that's in the cell. The rest is layout.
- */
-struct tbl_dat {
- struct tbl_cell *layout; /* layout cell */
- struct tbl_dat *next;
- char *string; /* data (NULL if not TBL_DATA_DATA) */
- int spans; /* how many spans follow */
- int block; /* T{ text block T} */
- enum tbl_datt pos;
-};
-
-enum tbl_spant {
- TBL_SPAN_DATA, /* span consists of data */
- TBL_SPAN_HORIZ, /* span is horizontal line */
- TBL_SPAN_DHORIZ /* span is double horizontal line */
-};
-
-/*
- * A row of data in a table.
- */
-struct tbl_span {
- struct tbl_opts *opts;
- struct tbl_row *layout; /* layout row */
- struct tbl_dat *first;
- struct tbl_dat *last;
- struct tbl_span *prev;
- struct tbl_span *next;
- int line; /* parse line */
- enum tbl_spant pos;
-};
-
-enum eqn_boxt {
- EQN_TEXT, /* text (number, variable, whatever) */
- EQN_SUBEXPR, /* nested `eqn' subexpression */
- EQN_LIST, /* list (braces, etc.) */
- EQN_PILE, /* vertical pile */
- EQN_MATRIX /* pile of piles */
-};
-
-enum eqn_fontt {
- EQNFONT_NONE = 0,
- EQNFONT_ROMAN,
- EQNFONT_BOLD,
- EQNFONT_FAT,
- EQNFONT_ITALIC,
- EQNFONT__MAX
-};
-
-enum eqn_post {
- EQNPOS_NONE = 0,
- EQNPOS_SUP,
- EQNPOS_SUBSUP,
- EQNPOS_SUB,
- EQNPOS_TO,
- EQNPOS_FROM,
- EQNPOS_FROMTO,
- EQNPOS_OVER,
- EQNPOS_SQRT,
- EQNPOS__MAX
-};
-
-enum eqn_pilet {
- EQNPILE_NONE = 0,
- EQNPILE_PILE,
- EQNPILE_CPILE,
- EQNPILE_RPILE,
- EQNPILE_LPILE,
- EQNPILE_COL,
- EQNPILE_CCOL,
- EQNPILE_RCOL,
- EQNPILE_LCOL,
- EQNPILE__MAX
-};
-
- /*
- * A "box" is a parsed mathematical expression as defined by the eqn.7
- * grammar.
- */
-struct eqn_box {
- int size; /* font size of expression */
-#define EQN_DEFSIZE INT_MIN
- enum eqn_boxt type; /* type of node */
- struct eqn_box *first; /* first child node */
- struct eqn_box *last; /* last child node */
- struct eqn_box *next; /* node sibling */
- struct eqn_box *prev; /* node sibling */
- struct eqn_box *parent; /* node sibling */
- char *text; /* text (or NULL) */
- char *left; /* fence left-hand */
- char *right; /* fence right-hand */
- char *top; /* expression over-symbol */
- char *bottom; /* expression under-symbol */
- size_t args; /* arguments in parent */
- size_t expectargs; /* max arguments in parent */
- enum eqn_post pos; /* position of next box */
- enum eqn_fontt font; /* font of box */
- enum eqn_pilet pile; /* equation piling */
-};
-
-/*
- * Parse options.
- */
-#define MPARSE_MDOC 1 /* assume -mdoc */
-#define MPARSE_MAN 2 /* assume -man */
-#define MPARSE_SO 4 /* honour .so requests */
-#define MPARSE_QUICK 8 /* abort the parse early */
-#define MPARSE_UTF8 16 /* accept UTF-8 input */
-#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */
-
-enum mandoc_os {
- MANDOC_OS_OTHER = 0,
- MANDOC_OS_NETBSD,
- MANDOC_OS_OPENBSD
-};
-
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
+ ESCAPE_UNSUPP, /* unsupported escape; ignore it */
ESCAPE_IGNORE, /* escape to be ignored */
+ ESCAPE_UNDEF, /* undefined escape; print literal character */
ESCAPE_SPECIAL, /* a regular special character */
ESCAPE_FONT, /* a generic font mode */
ESCAPE_FONTBOLD, /* bold font mode */
ESCAPE_FONTITALIC, /* italic font mode */
ESCAPE_FONTBI, /* bold italic font mode */
ESCAPE_FONTROMAN, /* roman font mode */
+ ESCAPE_FONTCW, /* constant width font mode */
ESCAPE_FONTPREV, /* previous font mode */
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
+ ESCAPE_DEVICE, /* print the output device name */
ESCAPE_BREAK, /* break the output line */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
ESCAPE_HORIZ, /* horizontal movement */
@@ -439,14 +269,18 @@ enum mandoc_esc {
ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
};
-typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
- const char *, int, int, const char *);
-
-
-struct mparse;
-struct roff_man;
+enum mandoc_esc mandoc_font(const char *, int sz);
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
+void mandoc_msg_setoutfile(FILE *);
+const char *mandoc_msg_getinfilename(void);
+void mandoc_msg_setinfilename(const char *);
+enum mandocerr mandoc_msg_getmin(void);
+void mandoc_msg_setmin(enum mandocerr);
+enum mandoclevel mandoc_msg_getrc(void);
+void mandoc_msg_setrc(enum mandoclevel);
+void mandoc_msg(enum mandocerr, int, int, const char *, ...)
+ __attribute__((__format__ (__printf__, 4, 5)));
void mchars_alloc(void);
void mchars_free(void);
int mchars_num2char(const char *, size_t);
@@ -454,18 +288,3 @@ const char *mchars_uc2str(int);
int mchars_num2uc(const char *, size_t);
int mchars_spec2cp(const char *, size_t);
const char *mchars_spec2str(const char *, size_t, size_t *);
-struct mparse *mparse_alloc(int, enum mandocerr, mandocmsg,
- enum mandoc_os, const char *);
-void mparse_free(struct mparse *);
-void mparse_keep(struct mparse *);
-int mparse_open(struct mparse *, const char *);
-enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
-enum mandoclevel mparse_readmem(struct mparse *, void *, size_t,
- const char *);
-void mparse_reset(struct mparse *);
-void mparse_result(struct mparse *,
- struct roff_man **, char **);
-const char *mparse_getkeep(const struct mparse *);
-const char *mparse_strerror(enum mandocerr);
-const char *mparse_strlevel(enum mandoclevel);
-void mparse_updaterc(struct mparse *, enum mandoclevel *);
diff --git a/usr/src/cmd/mandoc/mandoc_msg.c b/usr/src/cmd/mandoc/mandoc_msg.c
new file mode 100644
index 0000000000..ff4d80313c
--- /dev/null
+++ b/usr/src/cmd/mandoc/mandoc_msg.c
@@ -0,0 +1,329 @@
+/* $Id: mandoc_msg.c,v 1.6 2019/03/06 15:55:38 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mandoc.h"
+
+static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
+ MANDOCERR_OK,
+ MANDOCERR_OK,
+ MANDOCERR_WARNING,
+ MANDOCERR_ERROR,
+ MANDOCERR_UNSUPP,
+ MANDOCERR_MAX,
+ MANDOCERR_MAX
+};
+
+static const char *const level_name[MANDOCLEVEL_MAX] = {
+ "SUCCESS",
+ "STYLE",
+ "WARNING",
+ "ERROR",
+ "UNSUPP",
+ "BADARG",
+ "SYSERR"
+};
+
+static const char *const type_message[MANDOCERR_MAX] = {
+ "ok",
+
+ "base system convention",
+
+ "Mdocdate found",
+ "Mdocdate missing",
+ "unknown architecture",
+ "operating system explicitly specified",
+ "RCS id missing",
+ "referenced manual not found",
+
+ "generic style suggestion",
+
+ "legacy man(7) date format",
+ "normalizing date format to",
+ "lower case character in document title",
+ "duplicate RCS id",
+ "possible typo in section name",
+ "unterminated quoted argument",
+ "useless macro",
+ "consider using OS macro",
+ "errnos out of order",
+ "duplicate errno",
+ "trailing delimiter",
+ "no blank before trailing delimiter",
+ "fill mode already enabled, skipping",
+ "fill mode already disabled, skipping",
+ "verbatim \"--\", maybe consider using \\(em",
+ "function name without markup",
+ "whitespace at end of input line",
+ "bad comment style",
+
+ "generic warning",
+
+ /* related to the prologue */
+ "missing manual title, using UNTITLED",
+ "missing manual title, using \"\"",
+ "missing manual section, using \"\"",
+ "unknown manual section",
+ "missing date, using today's date",
+ "cannot parse date, using it verbatim",
+ "date in the future, using it anyway",
+ "missing Os macro, using \"\"",
+ "late prologue macro",
+ "prologue macros out of order",
+
+ /* related to document structure */
+ ".so is fragile, better use ln(1)",
+ "no document body",
+ "content before first section header",
+ "first section is not \"NAME\"",
+ "NAME section without Nm before Nd",
+ "NAME section without description",
+ "description not at the end of NAME",
+ "bad NAME section content",
+ "missing comma before name",
+ "missing description line, using \"\"",
+ "description line outside NAME section",
+ "sections out of conventional order",
+ "duplicate section title",
+ "unexpected section",
+ "cross reference to self",
+ "unusual Xr order",
+ "unusual Xr punctuation",
+ "AUTHORS section without An macro",
+
+ /* related to macros and nesting */
+ "obsolete macro",
+ "macro neither callable nor escaped",
+ "skipping paragraph macro",
+ "moving paragraph macro out of list",
+ "skipping no-space macro",
+ "blocks badly nested",
+ "nested displays are not portable",
+ "moving content out of list",
+ "first macro on line",
+ "line scope broken",
+ "skipping blank line in line scope",
+
+ /* related to missing macro arguments */
+ "skipping empty request",
+ "conditional request controls empty scope",
+ "skipping empty macro",
+ "empty block",
+ "empty argument, using 0n",
+ "missing display type, using -ragged",
+ "list type is not the first argument",
+ "missing -width in -tag list, using 6n",
+ "missing utility name, using \"\"",
+ "missing function name, using \"\"",
+ "empty head in list item",
+ "empty list item",
+ "missing argument, using next line",
+ "missing font type, using \\fR",
+ "unknown font type, using \\fR",
+ "nothing follows prefix",
+ "empty reference block",
+ "missing section argument",
+ "missing -std argument, adding it",
+ "missing option string, using \"\"",
+ "missing resource identifier, using \"\"",
+ "missing eqn box, using \"\"",
+
+ /* related to bad macro arguments */
+ "duplicate argument",
+ "skipping duplicate argument",
+ "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",
+ "unknown library name",
+ "invalid content in Rs block",
+ "invalid Boolean argument",
+ "argument contains two font escapes",
+ "unknown font, skipping request",
+ "odd number of characters in request",
+
+ /* related to plain text */
+ "blank line in fill mode, using .sp",
+ "tab in filled text",
+ "new sentence, new line",
+ "invalid escape sequence",
+ "undefined escape, printing literally",
+ "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 tables */
+ "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,
+ "duplicate prologue macro",
+ "skipping late title macro",
+ "input stack limit exceeded, infinite loop?",
+ "skipping bad character",
+ "skipping unknown macro",
+ "ignoring request outside 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",
+ "using macro argument outside macro",
+ "argument number is not numeric",
+ "NOT IMPLEMENTED: Bd -file",
+ "skipping display without arguments",
+ "missing list type, using -item",
+ "argument is not numeric, using 1",
+ "argument is not a character",
+ "missing manual name, using \"\"",
+ "uname(3) system call failed, using UNKNOWN",
+ "unknown standard specifier",
+ "skipping request without numeric argument",
+ "excessive shift",
+ "NOT IMPLEMENTED: .so with absolute path or \"..\"",
+ ".so request failed",
+ "skipping all arguments",
+ "skipping excess arguments",
+ "divide by zero",
+
+ "unsupported feature",
+ "input too large",
+ "unsupported control character",
+ "unsupported escape sequence",
+ "unsupported roff request",
+ "nested .while loops",
+ "end of scope with open .while loop",
+ "end of .while loop in inner scope",
+ "cannot continue this .while loop",
+ "eqn delim option in tbl",
+ "unsupported tbl layout modifier",
+ "ignoring macro in table",
+};
+
+static FILE *fileptr = NULL;
+static const char *filename = NULL;
+static enum mandocerr min_type = MANDOCERR_MAX;
+static enum mandoclevel rc = MANDOCLEVEL_OK;
+
+
+void
+mandoc_msg_setoutfile(FILE *fp)
+{
+ fileptr = fp;
+}
+
+const char *
+mandoc_msg_getinfilename(void)
+{
+ return filename;
+}
+
+void
+mandoc_msg_setinfilename(const char *fn)
+{
+ filename = fn;
+}
+
+enum mandocerr
+mandoc_msg_getmin(void)
+{
+ return min_type;
+}
+
+void
+mandoc_msg_setmin(enum mandocerr t)
+{
+ min_type = t;
+}
+
+enum mandoclevel
+mandoc_msg_getrc(void)
+{
+ return rc;
+}
+
+void
+mandoc_msg_setrc(enum mandoclevel level)
+{
+ if (rc < level)
+ rc = level;
+}
+
+void
+mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...)
+{
+ va_list ap;
+ enum mandoclevel level;
+
+ if (t < min_type && t != MANDOCERR_FILE)
+ return;
+
+ level = MANDOCLEVEL_UNSUPP;
+ while (t < lowest_type[level])
+ level--;
+ mandoc_msg_setrc(level);
+
+ if (fileptr == NULL)
+ return;
+
+ fprintf(fileptr, "%s:", getprogname());
+ if (filename != NULL)
+ fprintf(fileptr, " %s:", filename);
+
+ if (line > 0)
+ fprintf(fileptr, "%d:%d:", line, col + 1);
+
+ fprintf(fileptr, " %s", level_name[level]);
+ if (type_message[t] != NULL)
+ fprintf(fileptr, ": %s", type_message[t]);
+
+ if (fmt != NULL) {
+ fprintf(fileptr, ": ");
+ va_start(ap, fmt);
+ vfprintf(fileptr, fmt, ap);
+ va_end(ap);
+ }
+ fputc('\n', fileptr);
+}
diff --git a/usr/src/cmd/mandoc/mandoc_parse.h b/usr/src/cmd/mandoc/mandoc_parse.h
new file mode 100644
index 0000000000..61341f0d7f
--- /dev/null
+++ b/usr/src/cmd/mandoc/mandoc_parse.h
@@ -0,0 +1,43 @@
+/* $Id: mandoc_parse.h,v 1.4 2018/12/30 00:49:55 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Top level parser interface. For use in the main program
+ * and in the main parser, but not in formatters.
+ */
+
+/*
+ * Parse options.
+ */
+#define MPARSE_MDOC (1 << 0) /* assume -mdoc */
+#define MPARSE_MAN (1 << 1) /* assume -man */
+#define MPARSE_SO (1 << 2) /* honour .so requests */
+#define MPARSE_QUICK (1 << 3) /* abort the parse early */
+#define MPARSE_UTF8 (1 << 4) /* accept UTF-8 input */
+#define MPARSE_LATIN1 (1 << 5) /* accept ISO-LATIN-1 input */
+#define MPARSE_VALIDATE (1 << 6) /* call validation functions */
+
+
+struct roff_meta;
+struct mparse;
+
+struct mparse *mparse_alloc(int, enum mandoc_os, const char *);
+void mparse_copy(const struct mparse *);
+void mparse_free(struct mparse *);
+int mparse_open(struct mparse *, const char *);
+void mparse_readfd(struct mparse *, int, const char *);
+void mparse_reset(struct mparse *);
+struct roff_meta *mparse_result(struct mparse *);
diff --git a/usr/src/cmd/mandoc/mandocdb.c b/usr/src/cmd/mandoc/mandocdb.c
index 86dbce2d9f..222350c987 100644
--- a/usr/src/cmd/mandoc/mandocdb.c
+++ b/usr/src/cmd/mandoc/mandocdb.c
@@ -1,7 +1,7 @@
-/* $Id: mandocdb.c,v 1.258 2018/02/23 18:25:57 schwarze Exp $ */
+/* $Id: mandocdb.c,v 1.262 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -52,6 +52,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
+#include "mandoc_parse.h"
#include "manconf.h"
#include "mansearch.h"
#include "dba_array.h"
@@ -185,7 +186,7 @@ static struct ohash names; /* table of all names */
static struct ohash strings; /* table of all strings */
static uint64_t name_mask;
-static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
+static const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = {
{ NULL, 0, NODE_NOPRT }, /* Dd */
{ NULL, 0, NODE_NOPRT }, /* Dt */
{ NULL, 0, NODE_NOPRT }, /* Os */
@@ -307,7 +308,6 @@ static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
{ NULL, 0, 0 }, /* %U */
{ NULL, 0, 0 }, /* Ta */
};
-static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
int
@@ -347,6 +347,7 @@ mandocdb(int argc, char *argv[])
goto usage; \
} while (/*CONSTCOND*/0)
+ mparse_options = MPARSE_VALIDATE;
path_arg = NULL;
op = OP_DEFAULT;
@@ -422,8 +423,7 @@ mandocdb(int argc, char *argv[])
exitcode = (int)MANDOCLEVEL_OK;
mchars_alloc();
- mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
- MANDOC_OS_OTHER, NULL);
+ mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL);
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
@@ -1116,8 +1116,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
{
struct mpage *mpage, *mpage_dest;
struct mlink *mlink, *mlink_dest;
- struct roff_man *man;
- char *sodest;
+ struct roff_meta *meta;
char *cp;
int fd;
@@ -1130,8 +1129,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
mandoc_ohash_init(&names, 4, offsetof(struct str, key));
mandoc_ohash_init(&strings, 6, offsetof(struct str, key));
mparse_reset(mp);
- man = NULL;
- sodest = NULL;
+ meta = NULL;
if ((fd = mparse_open(mp, mlink->file)) == -1) {
say(mlink->file, "&open");
@@ -1146,14 +1144,14 @@ mpages_merge(struct dba *dba, struct mparse *mp)
mparse_readfd(mp, fd, mlink->file);
close(fd);
fd = -1;
- mparse_result(mp, &man, &sodest);
+ meta = mparse_result(mp);
}
- if (sodest != NULL) {
+ if (meta != NULL && meta->sodest != NULL) {
mlink_dest = ohash_find(&mlinks,
- ohash_qlookup(&mlinks, sodest));
+ ohash_qlookup(&mlinks, meta->sodest));
if (mlink_dest == NULL) {
- mandoc_asprintf(&cp, "%s.gz", sodest);
+ mandoc_asprintf(&cp, "%s.gz", meta->sodest);
mlink_dest = ohash_find(&mlinks,
ohash_qlookup(&mlinks, cp));
free(cp);
@@ -1190,39 +1188,36 @@ mpages_merge(struct dba *dba, struct mparse *mp)
mpage->mlinks = NULL;
}
goto nextpage;
- } else if (man != NULL && man->macroset == MACROSET_MDOC) {
- mdoc_validate(man);
+ } else if (meta != NULL && meta->macroset == MACROSET_MDOC) {
mpage->form = FORM_SRC;
- mpage->sec = man->meta.msec;
+ mpage->sec = meta->msec;
mpage->sec = mandoc_strdup(
mpage->sec == NULL ? "" : mpage->sec);
- mpage->arch = man->meta.arch;
+ mpage->arch = meta->arch;
mpage->arch = mandoc_strdup(
mpage->arch == NULL ? "" : mpage->arch);
- mpage->title = mandoc_strdup(man->meta.title);
- } else if (man != NULL && man->macroset == MACROSET_MAN) {
- man_validate(man);
- if (*man->meta.msec != '\0' ||
- *man->meta.title != '\0') {
+ mpage->title = mandoc_strdup(meta->title);
+ } else if (meta != NULL && meta->macroset == MACROSET_MAN) {
+ if (*meta->msec != '\0' || *meta->title != '\0') {
mpage->form = FORM_SRC;
- mpage->sec = mandoc_strdup(man->meta.msec);
+ mpage->sec = mandoc_strdup(meta->msec);
mpage->arch = mandoc_strdup(mlink->arch);
- mpage->title = mandoc_strdup(man->meta.title);
+ mpage->title = mandoc_strdup(meta->title);
} else
- man = NULL;
+ meta = NULL;
}
assert(mpage->desc == NULL);
- if (man == NULL) {
+ if (meta == NULL) {
mpage->form = FORM_CAT;
mpage->sec = mandoc_strdup(mlink->dsec);
mpage->arch = mandoc_strdup(mlink->arch);
mpage->title = mandoc_strdup(mlink->name);
parse_cat(mpage, fd);
- } else if (man->macroset == MACROSET_MDOC)
- parse_mdoc(mpage, &man->meta, man->first);
+ } else if (meta->macroset == MACROSET_MDOC)
+ parse_mdoc(mpage, meta, meta->first);
else
- parse_man(mpage, &man->meta, man->first);
+ parse_man(mpage, meta, meta->first);
if (mpage->desc == NULL) {
mpage->desc = mandoc_strdup(mlink->name);
if (warnings)
@@ -1546,25 +1541,28 @@ static void
parse_mdoc(struct mpage *mpage, const struct roff_meta *meta,
const struct roff_node *n)
{
+ const struct mdoc_handler *handler;
for (n = n->child; n != NULL; n = n->next) {
- if (n->tok == TOKEN_NONE ||
- n->tok < ROFF_MAX ||
- n->flags & mdocs[n->tok].taboo)
+ if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
continue;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
+ handler = mdoc_handlers + (n->tok - MDOC_Dd);
+ if (n->flags & handler->taboo)
+ continue;
+
switch (n->type) {
case ROFFT_ELEM:
case ROFFT_BLOCK:
case ROFFT_HEAD:
case ROFFT_BODY:
case ROFFT_TAIL:
- if (mdocs[n->tok].fp != NULL &&
- (*mdocs[n->tok].fp)(mpage, meta, n) == 0)
+ if (handler->fp != NULL &&
+ (*handler->fp)(mpage, meta, n) == 0)
break;
- if (mdocs[n->tok].mask)
+ if (handler->mask)
putmdockey(mpage, n->child,
- mdocs[n->tok].mask, mdocs[n->tok].taboo);
+ handler->mask, handler->taboo);
break;
default:
continue;
diff --git a/usr/src/cmd/mandoc/manpath.c b/usr/src/cmd/mandoc/manpath.c
index 54f7a6b110..74f38a95db 100644
--- a/usr/src/cmd/mandoc/manpath.c
+++ b/usr/src/cmd/mandoc/manpath.c
@@ -1,6 +1,6 @@
-/* $Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */
+/* $Id: manpath.c,v 1.37 2018/11/22 11:30:23 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -232,8 +232,8 @@ int
manconf_output(struct manoutput *conf, const char *cp, int fromfile)
{
const char *const toks[] = {
- "includes", "man", "paper", "style",
- "indent", "width", "fragment", "mdoc", "noval"
+ "includes", "man", "paper", "style", "indent", "width",
+ "tag", "fragment", "mdoc", "noval", "toc"
};
const char *errstr;
@@ -257,7 +257,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
warnx("-O %s=?: Missing argument value", toks[tok]);
return -1;
}
- if ((tok == 6 || tok == 7) && *cp != '\0') {
+ if (tok > 6 && *cp != '\0') {
warnx("-O %s: Does not take a value: %s", toks[tok], cp);
return -1;
}
@@ -312,14 +312,24 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
warnx("-O width=%s is %s", cp, errstr);
return -1;
case 6:
- conf->fragment = 1;
+ if (conf->tag != NULL) {
+ oldval = mandoc_strdup(conf->tag);
+ break;
+ }
+ conf->tag = mandoc_strdup(cp);
return 0;
case 7:
- conf->mdoc = 1;
+ conf->fragment = 1;
return 0;
case 8:
+ conf->mdoc = 1;
+ return 0;
+ case 9:
conf->noval = 1;
return 0;
+ case 10:
+ conf->toc = 1;
+ return 0;
default:
if (fromfile)
warnx("-O %s: Bad argument", cp);
diff --git a/usr/src/cmd/mandoc/mansearch.c b/usr/src/cmd/mandoc/mansearch.c
index 784c17bee7..4e968332e3 100644
--- a/usr/src/cmd/mandoc/mansearch.c
+++ b/usr/src/cmd/mandoc/mansearch.c
@@ -1,7 +1,7 @@
-/* $Id: mansearch.c,v 1.77 2017/08/22 17:50:11 schwarze Exp $ */
+/* $Id: mansearch.c,v 1.80 2018/12/13 11:55:46 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2018 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
@@ -36,7 +36,6 @@
#include <string.h>
#include <unistd.h>
-#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
#include "manconf.h"
@@ -192,7 +191,7 @@ mansearch(const struct mansearch *search,
mpage->file, R_OK) == -1) {
warn("%s", mpage->file);
warnx("outdated mandoc.db contains "
- "bogus %s entry, run makewhatis %s",
+ "bogus %s entry, run makewhatis %s",
page->file + 1, paths->paths[i]);
free(mpage->file);
free(rp);
@@ -201,7 +200,6 @@ mansearch(const struct mansearch *search,
mpage->names = buildnames(page);
mpage->output = buildoutput(outkey, page);
mpage->ipath = i;
- mpage->bits = rp->bits;
mpage->sec = *page->sect - '0';
if (mpage->sec < 0 || mpage->sec > 9)
mpage->sec = 10;
@@ -296,10 +294,8 @@ manmerge_term(struct expr *e, struct ohash *htab)
break;
slot = ohash_lookup_memory(htab,
(char *)&res, sizeof(res.page), res.page);
- if ((rp = ohash_find(htab, slot)) != NULL) {
- rp->bits |= res.bits;
+ if ((rp = ohash_find(htab, slot)) != NULL)
continue;
- }
rp = mandoc_malloc(sizeof(*rp));
*rp = res;
ohash_insert(htab, slot, rp);
@@ -412,8 +408,7 @@ manpage_compare(const void *vp1, const void *vp2)
mp1 = vp1;
mp2 = vp2;
- if ((diff = mp2->bits - mp1->bits) ||
- (diff = mp1->sec - mp2->sec))
+ if ((diff = mp1->sec - mp2->sec))
return diff;
/* Fall back to alphabetic ordering of names. */
@@ -774,8 +769,9 @@ exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
cs = 0;
} else if ((val = strpbrk(argv[*argi], "=~")) == NULL) {
e->bits = TYPE_Nm | TYPE_Nd;
- e->match.type = DBM_SUB;
- e->match.str = argv[*argi];
+ e->match.type = DBM_REGEX;
+ val = argv[*argi];
+ cs = 0;
} else {
if (val == argv[*argi])
e->bits = TYPE_Nm | TYPE_Nd;
diff --git a/usr/src/cmd/mandoc/mansearch.h b/usr/src/cmd/mandoc/mansearch.h
index cc4f364f69..355873f83e 100644
--- a/usr/src/cmd/mandoc/mansearch.h
+++ b/usr/src/cmd/mandoc/mansearch.h
@@ -1,4 +1,4 @@
-/* $Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */
+/* $Id: mansearch.h,v 1.29 2018/11/22 12:01:46 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -93,7 +93,6 @@ struct manpage {
char *names; /* a list of names with sections */
char *output; /* user-defined additional output */
size_t ipath; /* number of the manpath */
- uint64_t bits; /* name type mask */
int sec; /* section number, 10 means invalid */
enum form form;
};
diff --git a/usr/src/cmd/mandoc/mdoc.c b/usr/src/cmd/mandoc/mdoc.c
index 71803531dd..bb3ec58bd0 100644
--- a/usr/src/cmd/mandoc/mdoc.c
+++ b/usr/src/cmd/mandoc/mdoc.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc.c,v 1.268 2017/08/11 16:56:21 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.274 2018/12/31 07:46:07 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2018 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
@@ -80,13 +80,6 @@ mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
}
void
-mdoc_macro(MACRO_PROT_ARGS)
-{
- assert(tok >= MDOC_Dd && tok < MDOC_MAX);
- (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
-}
-
-void
mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok)
{
struct roff_node *p;
@@ -162,15 +155,6 @@ mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
mdoc->next = ROFF_NEXT_CHILD;
}
-void
-mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p)
-{
-
- roff_node_unlink(mdoc, p);
- p->prev = p->next = NULL;
- roff_node_append(mdoc, p);
-}
-
/*
* Parse free-form text, that is, a line that does not begin with the
* control character.
@@ -196,7 +180,8 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
(n->parent != NULL && n->parent->tok == MDOC_Bl &&
n->parent->norm->Bl.type == LIST_column)) {
mdoc->flags |= MDOC_FREECOL;
- mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
+ (*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It,
+ line, offs, &offs, buf);
return 1;
}
@@ -225,7 +210,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
* Strip trailing tabs in literal context only;
* outside, they affect the next line.
*/
- if (MDOC_LITERAL & mdoc->flags)
+ if (mdoc->flags & ROFF_NOFILL)
continue;
break;
case '\\':
@@ -242,8 +227,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
*end = '\0';
if (ws)
- mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
- line, (int)(ws-buf), NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, line, (int)(ws - buf), NULL);
/*
* Blank lines are allowed in no-fill mode
@@ -251,7 +235,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
* but add a single vertical space elsewhere.
*/
- if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
+ if (buf[offs] == '\0' && (mdoc->flags & ROFF_NOFILL) == 0) {
switch (mdoc->last->type) {
case ROFFT_TEXT:
sp = mdoc->last->string;
@@ -267,8 +251,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
default:
break;
}
- mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
- line, (int)(c - buf), NULL);
+ mandoc_msg(MANDOCERR_FI_BLANK, line, (int)(c - buf), NULL);
roff_elem_alloc(mdoc, line, offs, ROFF_sp);
mdoc->last->flags |= NODE_VALID | NODE_ENDED;
mdoc->next = ROFF_NEXT_SIBLING;
@@ -277,7 +260,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
roff_word_alloc(mdoc, line, offs, buf+offs);
- if (mdoc->flags & MDOC_LITERAL)
+ if (mdoc->flags & ROFF_NOFILL)
return 1;
/*
@@ -308,8 +291,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
if (*c == ' ')
c++;
if (isupper((unsigned char)(*c)))
- mandoc_msg(MANDOCERR_EOS, mdoc->parse,
- line, (int)(c - buf), NULL);
+ mandoc_msg(MANDOCERR_EOS, line, (int)(c - buf), NULL);
}
return 1;
@@ -337,8 +319,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
if (sz == 2 || sz == 3)
tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
if (tok == TOKEN_NONE) {
- mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
- ln, sv, buf + sv - 1);
+ mandoc_msg(MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1);
return 1;
}
@@ -368,8 +349,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
*/
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
- mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
- ln, offs - 1, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
/*
* If an initial macro or a list invocation, divert directly
@@ -378,7 +358,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
n = mdoc->last;
if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
- mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
+ (*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
return 1;
}
@@ -394,13 +374,13 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
(n->parent != NULL && n->parent->tok == MDOC_Bl &&
n->parent->norm->Bl.type == LIST_column)) {
mdoc->flags |= MDOC_FREECOL;
- mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
+ (*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, ln, sv, &sv, buf);
return 1;
}
/* Normal processing of a macro. */
- mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
+ (*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
@@ -448,12 +428,3 @@ mdoc_isdelim(const char *p)
return DELIM_NONE;
}
-
-void
-mdoc_validate(struct roff_man *mdoc)
-{
-
- mdoc->last = mdoc->first;
- mdoc_node_validate(mdoc);
- mdoc_state_reset(mdoc);
-}
diff --git a/usr/src/cmd/mandoc/mdoc.h b/usr/src/cmd/mandoc/mdoc.h
index 1628e0c80c..2f32fa4962 100644
--- a/usr/src/cmd/mandoc/mdoc.h
+++ b/usr/src/cmd/mandoc/mdoc.h
@@ -1,4 +1,4 @@
-/* $Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */
+/* $Id: mdoc.h,v 1.146 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -16,6 +16,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+struct roff_node;
+struct roff_man;
+
enum mdocargt {
MDOC_Split, /* -split */
MDOC_Nosplit, /* -nospli */
diff --git a/usr/src/cmd/mandoc/mdoc_argv.c b/usr/src/cmd/mandoc/mdoc_argv.c
index db4c63f0d6..f4ce4a8730 100644
--- a/usr/src/cmd/mandoc/mdoc_argv.c
+++ b/usr/src/cmd/mandoc/mdoc_argv.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_argv.c,v 1.115 2017/05/30 16:22:03 schwarze Exp $ */
+/* $Id: mdoc_argv.c,v 1.119 2018/12/21 17:15:19 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2014-2018 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
@@ -144,7 +144,7 @@ static const enum mdocargt args_Bl[] = {
MDOC_ARG_MAX
};
-static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
+static const struct mdocarg mdocargs[MDOC_MAX - MDOC_Dd] = {
{ ARGSFL_NONE, NULL }, /* Dd */
{ ARGSFL_NONE, NULL }, /* Dt */
{ ARGSFL_NONE, NULL }, /* Os */
@@ -266,7 +266,6 @@ static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
{ ARGSFL_NONE, NULL }, /* %U */
{ ARGSFL_NONE, NULL }, /* Ta */
};
-static const struct mdocarg *const mdocargs = __mdocargs - MDOC_Dd;
/*
@@ -290,7 +289,7 @@ mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok,
/* Which flags does this macro support? */
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
- argtable = mdocargs[tok].argvs;
+ argtable = mdocargs[tok - MDOC_Dd].argvs;
if (argtable == NULL)
return;
@@ -368,7 +367,7 @@ mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok,
/* Prepare for parsing the next flag. */
*pos = ipos;
- argtable = mdocargs[tok].argvs;
+ argtable = mdocargs[tok - MDOC_Dd].argvs;
}
}
@@ -417,12 +416,9 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos,
char *buf, enum roff_tok tok, char **v)
{
struct roff_node *n;
- char *v_local;
enum argsflag fl;
- if (v == NULL)
- v = &v_local;
- fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags;
+ fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok - MDOC_Dd].flags;
/*
* We know that we're in an `It', so it's reasonable to expect
@@ -449,18 +445,20 @@ args(struct roff_man *mdoc, int line, int *pos,
char *buf, enum argsflag fl, char **v)
{
char *p;
+ char *v_local;
int pairs;
if (buf[*pos] == '\0') {
if (mdoc->flags & MDOC_PHRASELIT &&
! (mdoc->flags & MDOC_PHRASE)) {
- mandoc_msg(MANDOCERR_ARG_QUOTE,
- mdoc->parse, line, *pos, NULL);
+ mandoc_msg(MANDOCERR_ARG_QUOTE, line, *pos, NULL);
mdoc->flags &= ~MDOC_PHRASELIT;
}
return ARGS_EOLN;
}
+ if (v == NULL)
+ v = &v_local;
*v = buf + *pos;
if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos))
@@ -506,7 +504,7 @@ args(struct roff_man *mdoc, int line, int *pos,
p = strchr(*v, '\0');
if (p[-1] == ' ')
mandoc_msg(MANDOCERR_SPACE_EOL,
- mdoc->parse, line, *pos, NULL);
+ line, *pos, NULL);
*pos += (int)(p - *v);
}
@@ -527,13 +525,12 @@ args(struct roff_man *mdoc, int line, int *pos,
* Whitespace is NOT involved in literal termination.
*/
- if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') {
- if ( ! (mdoc->flags & MDOC_PHRASELIT))
+ if (mdoc->flags & MDOC_PHRASELIT ||
+ (mdoc->flags & MDOC_PHRASE && buf[*pos] == '\"')) {
+ if ((mdoc->flags & MDOC_PHRASELIT) == 0) {
*v = &buf[++(*pos)];
-
- if (mdoc->flags & MDOC_PHRASE)
mdoc->flags |= MDOC_PHRASELIT;
-
+ }
pairs = 0;
for ( ; buf[*pos]; (*pos)++) {
/* Move following text left after quoted quotes. */
@@ -554,7 +551,7 @@ args(struct roff_man *mdoc, int line, int *pos,
if (buf[*pos] == '\0') {
if ( ! (mdoc->flags & MDOC_PHRASE))
mandoc_msg(MANDOCERR_ARG_QUOTE,
- mdoc->parse, line, *pos, NULL);
+ line, *pos, NULL);
return ARGS_WORD;
}
@@ -568,14 +565,15 @@ args(struct roff_man *mdoc, int line, int *pos,
(*pos)++;
if ('\0' == buf[*pos])
- mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
- line, *pos, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, line, *pos, NULL);
return ARGS_WORD;
}
p = &buf[*pos];
- *v = mandoc_getarg(mdoc->parse, &p, line, pos);
+ *v = roff_getarg(mdoc->roff, &p, line, pos);
+ if (v == &v_local)
+ free(*v);
/*
* After parsing the last word in this phrase,
@@ -586,7 +584,7 @@ args(struct roff_man *mdoc, int line, int *pos,
mdoc->flags &= ~MDOC_PHRASEQL;
mdoc->flags |= MDOC_PHRASEQF;
}
- return ARGS_WORD;
+ return ARGS_ALLOC;
}
/*
@@ -657,7 +655,9 @@ argv_multi(struct roff_man *mdoc, int line,
v->value = mandoc_reallocarray(v->value,
v->sz + MULTI_STEP, sizeof(char *));
- v->value[(int)v->sz] = mandoc_strdup(p);
+ if (ac != ARGS_ALLOC)
+ p = mandoc_strdup(p);
+ v->value[(int)v->sz] = p;
}
}
@@ -672,7 +672,10 @@ argv_single(struct roff_man *mdoc, int line,
if (ac == ARGS_EOLN)
return;
+ if (ac != ARGS_ALLOC)
+ p = mandoc_strdup(p);
+
v->sz = 1;
v->value = mandoc_malloc(sizeof(char *));
- v->value[0] = mandoc_strdup(p);
+ v->value[0] = p;
}
diff --git a/usr/src/cmd/mandoc/mdoc_html.c b/usr/src/cmd/mandoc/mdoc_html.c
index f50de8a77a..87bf42a72b 100644
--- a/usr/src/cmd/mandoc/mdoc_html.c
+++ b/usr/src/cmd/mandoc/mdoc_html.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_html.c,v 1.310 2018/07/27 17:49:31 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.328 2019/03/01 10:57:18 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014-2019 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
@@ -42,7 +42,7 @@
#define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
#endif
-struct htmlmdoc {
+struct mdoc_html_act {
int (*pre)(MDOC_ARGS);
void (*post)(MDOC_ARGS);
};
@@ -62,6 +62,7 @@ static int mdoc_root_pre(const struct roff_meta *,
static void mdoc__x_post(MDOC_ARGS);
static int mdoc__x_pre(MDOC_ARGS);
+static int mdoc_abort_pre(MDOC_ARGS);
static int mdoc_ad_pre(MDOC_ARGS);
static int mdoc_an_pre(MDOC_ARGS);
static int mdoc_ap_pre(MDOC_ARGS);
@@ -119,7 +120,7 @@ static int mdoc_vt_pre(MDOC_ARGS);
static int mdoc_xr_pre(MDOC_ARGS);
static int mdoc_xx_pre(MDOC_ARGS);
-static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
+static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
{NULL, NULL}, /* Dd */
{NULL, NULL}, /* Dt */
{NULL, NULL}, /* Os */
@@ -154,7 +155,7 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
{mdoc_nd_pre, NULL}, /* Nd */
{mdoc_nm_pre, NULL}, /* Nm */
{mdoc_quote_pre, mdoc_quote_post}, /* Op */
- {mdoc_ft_pre, NULL}, /* Ot */
+ {mdoc_abort_pre, NULL}, /* Ot */
{mdoc_pa_pre, NULL}, /* Pa */
{mdoc_ex_pre, NULL}, /* Rv */
{mdoc_st_pre, NULL}, /* St */
@@ -227,7 +228,7 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
{mdoc_em_pre, NULL}, /* Fr */
{NULL, NULL}, /* Ud */
{mdoc_lb_pre, NULL}, /* Lb */
- {mdoc_pp_pre, NULL}, /* Lp */
+ {mdoc_abort_pre, NULL}, /* Lp */
{mdoc_lk_pre, NULL}, /* Lk */
{mdoc_mt_pre, NULL}, /* Mt */
{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
@@ -241,7 +242,6 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
{mdoc__x_pre, mdoc__x_post}, /* %U */
{NULL, NULL}, /* Ta */
};
-static const struct htmlmdoc *const mdocs = __mdocs - MDOC_Dd;
/*
@@ -268,22 +268,21 @@ synopsis_pre(struct html *h, const struct roff_node *n)
case MDOC_Fo:
case MDOC_In:
case MDOC_Vt:
- print_paragraph(h);
break;
case MDOC_Ft:
- if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
- print_paragraph(h);
+ if (n->tok != MDOC_Fn && n->tok != MDOC_Fo)
break;
- }
/* FALLTHROUGH */
default:
print_otag(h, TAG_BR, "");
- break;
+ return;
}
+ html_close_paragraph(h);
+ print_otag(h, TAG_P, "c", "Pp");
}
void
-html_mdoc(void *arg, const struct roff_man *mdoc)
+html_mdoc(void *arg, const struct roff_meta *mdoc)
{
struct html *h;
struct roff_node *n;
@@ -295,19 +294,19 @@ html_mdoc(void *arg, const struct roff_man *mdoc)
if ((h->oflags & HTML_FRAGMENT) == 0) {
print_gen_decls(h);
print_otag(h, TAG_HTML, "");
- if (n->type == ROFFT_COMMENT)
+ if (n != NULL && n->type == ROFFT_COMMENT)
print_gen_comment(h, n);
t = print_otag(h, TAG_HEAD, "");
- print_mdoc_head(&mdoc->meta, h);
+ print_mdoc_head(mdoc, h);
print_tagq(h, t);
print_otag(h, TAG_BODY, "");
}
- mdoc_root_pre(&mdoc->meta, h);
+ mdoc_root_pre(mdoc, h);
t = print_otag(h, TAG_DIV, "c", "manual-text");
- print_mdoc_nodelist(&mdoc->meta, n, h);
+ print_mdoc_nodelist(mdoc, n, h);
print_tagq(h, t);
- mdoc_root_post(&mdoc->meta, h);
+ mdoc_root_post(mdoc, h);
print_tagq(h, NULL);
}
@@ -346,18 +345,21 @@ print_mdoc_nodelist(MDOC_ARGS)
static void
print_mdoc_node(MDOC_ARGS)
{
- int child;
struct tag *t;
+ int child;
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
return;
+ html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
+
child = 1;
- t = h->tag;
n->flags &= ~NODE_ENDED;
-
switch (n->type) {
case ROFFT_TEXT:
+ t = h->tag;
+ t->refcnt++;
+
/* No tables in this mode... */
assert(NULL == h->tblt);
@@ -366,15 +368,18 @@ print_mdoc_node(MDOC_ARGS)
* (i.e., within a <PRE>) don't print the newline.
*/
if (*n->string == ' ' && n->flags & NODE_LINE &&
- (h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0)
+ (h->flags & HTML_NONEWLINE) == 0 &&
+ (n->flags & NODE_NOFILL) == 0)
print_otag(h, TAG_BR, "");
if (NODE_DELIMC & n->flags)
h->flags |= HTML_NOSPACE;
print_text(h, n->string);
if (NODE_DELIMO & n->flags)
h->flags |= HTML_NOSPACE;
- return;
+ break;
case ROFFT_EQN:
+ t = h->tag;
+ t->refcnt++;
print_eqn(h, n->eqn);
break;
case ROFFT_TBL:
@@ -391,20 +396,22 @@ print_mdoc_node(MDOC_ARGS)
* the "meta" table state. This will be reopened on the
* next table element.
*/
- if (h->tblt != NULL) {
+ if (h->tblt != NULL)
print_tblclose(h);
- t = h->tag;
- }
assert(h->tblt == NULL);
+ t = h->tag;
+ t->refcnt++;
if (n->tok < ROFF_MAX) {
roff_html_pre(h, n);
- child = 0;
- break;
+ t->refcnt--;
+ print_stagq(h, t);
+ return;
}
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
- if (mdocs[n->tok].pre != NULL &&
+ if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
- child = (*mdocs[n->tok].pre)(meta, n, h);
+ child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta,
+ n, h);
break;
}
@@ -413,24 +420,31 @@ print_mdoc_node(MDOC_ARGS)
h->flags |= HTML_PREKEEP;
}
- if (child && n->child)
+ if (child && n->child != NULL)
print_mdoc_nodelist(meta, n->child, h);
+ t->refcnt--;
print_stagq(h, t);
switch (n->type) {
+ case ROFFT_TEXT:
case ROFFT_EQN:
break;
default:
- if (n->tok < ROFF_MAX ||
- mdocs[n->tok].post == NULL ||
+ if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL ||
n->flags & NODE_ENDED)
break;
- (*mdocs[n->tok].post)(meta, n, h);
+ (*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h);
if (n->end != ENDBODY_NOT)
n->body->flags |= NODE_ENDED;
break;
}
+
+ if (n->flags & NODE_NOFILL &&
+ (n->next == NULL || n->next->flags & NODE_LINE)) {
+ h->col++;
+ print_endline(h);
+ }
}
static void
@@ -507,12 +521,65 @@ cond_id(const struct roff_node *n)
static int
mdoc_sh_pre(MDOC_ARGS)
{
- char *id;
+ struct roff_node *sn, *subn;
+ struct tag *t, *tsec, *tsub;
+ char *id;
+ int sc;
switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ if ((h->oflags & HTML_TOC) == 0 ||
+ h->flags & HTML_TOCDONE ||
+ n->sec <= SEC_SYNOPSIS) {
+ print_otag(h, TAG_SECTION, "c", "Sh");
+ break;
+ }
+ h->flags |= HTML_TOCDONE;
+ sc = 0;
+ for (sn = n->next; sn != NULL; sn = sn->next)
+ if (sn->sec == SEC_CUSTOM)
+ if (++sc == 2)
+ break;
+ if (sc < 2)
+ break;
+ t = print_otag(h, TAG_H1, "c", "Sh");
+ print_text(h, "TABLE OF CONTENTS");
+ print_tagq(h, t);
+ t = print_otag(h, TAG_UL, "c", "Bl-compact");
+ for (sn = n; sn != NULL; sn = sn->next) {
+ tsec = print_otag(h, TAG_LI, "");
+ id = html_make_id(sn->head, 0);
+ tsub = print_otag(h, TAG_A, "hR", id);
+ free(id);
+ print_mdoc_nodelist(meta, sn->head->child, h);
+ print_tagq(h, tsub);
+ tsub = NULL;
+ for (subn = sn->body->child; subn != NULL;
+ subn = subn->next) {
+ if (subn->tok != MDOC_Ss)
+ continue;
+ id = html_make_id(subn->head, 0);
+ if (id == NULL)
+ continue;
+ if (tsub == NULL)
+ print_otag(h, TAG_UL,
+ "c", "Bl-compact");
+ tsub = print_otag(h, TAG_LI, "");
+ print_otag(h, TAG_A, "hR", id);
+ free(id);
+ print_mdoc_nodelist(meta,
+ subn->head->child, h);
+ print_tagq(h, tsub);
+ }
+ print_tagq(h, tsec);
+ }
+ print_tagq(h, t);
+ print_otag(h, TAG_SECTION, "c", "Sh");
+ break;
case ROFFT_HEAD:
id = html_make_id(n, 1);
- print_otag(h, TAG_H1, "cTi", "Sh", id);
+ print_otag(h, TAG_H1, "ci", "Sh", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
break;
@@ -531,11 +598,21 @@ mdoc_ss_pre(MDOC_ARGS)
{
char *id;
- if (n->type != ROFFT_HEAD)
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ print_otag(h, TAG_SECTION, "c", "Ss");
return 1;
+ case ROFFT_HEAD:
+ break;
+ case ROFFT_BODY:
+ return 1;
+ default:
+ abort();
+ }
id = html_make_id(n, 1);
- print_otag(h, TAG_H2, "cTi", "Ss", id);
+ print_otag(h, TAG_H2, "ci", "Ss", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
return 1;
@@ -548,7 +625,7 @@ mdoc_fl_pre(MDOC_ARGS)
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "cTi", "Fl", id);
+ print_otag(h, TAG_CODE, "ci", "Fl", id);
print_text(h, "\\-");
if (!(n->child == NULL &&
@@ -567,19 +644,27 @@ mdoc_cm_pre(MDOC_ARGS)
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "cTi", "Cm", id);
+ print_otag(h, TAG_CODE, "ci", "Cm", id);
return 1;
}
static int
mdoc_nd_pre(MDOC_ARGS)
{
- if (n->type != ROFFT_BODY)
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
return 1;
-
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
+ break;
+ default:
+ abort();
+ }
print_text(h, "\\(em");
/* Cannot use TAG_SPAN because it may contain blocks. */
- print_otag(h, TAG_DIV, "cT", "Nd");
+ print_otag(h, TAG_DIV, "c", "Nd");
return 1;
}
@@ -587,18 +672,21 @@ static int
mdoc_nm_pre(MDOC_ARGS)
{
switch (n->type) {
+ case ROFFT_BLOCK:
+ break;
case ROFFT_HEAD:
print_otag(h, TAG_TD, "");
/* FALLTHROUGH */
case ROFFT_ELEM:
- print_otag(h, TAG_CODE, "cT", "Nm");
+ print_otag(h, TAG_CODE, "c", "Nm");
return 1;
case ROFFT_BODY:
print_otag(h, TAG_TD, "");
return 1;
default:
- break;
+ abort();
}
+ html_close_paragraph(h);
synopsis_pre(h, n);
print_otag(h, TAG_TABLE, "c", "Nm");
print_otag(h, TAG_TR, "");
@@ -611,12 +699,12 @@ mdoc_xr_pre(MDOC_ARGS)
if (NULL == n->child)
return 0;
- if (h->base_man)
- print_otag(h, TAG_A, "cThM", "Xr",
+ if (h->base_man1)
+ print_otag(h, TAG_A, "chM", "Xr",
n->child->string, n->child->next == NULL ?
NULL : n->child->next->string);
else
- print_otag(h, TAG_A, "cT", "Xr");
+ print_otag(h, TAG_A, "c", "Xr");
n = n->child;
print_text(h, n->string);
@@ -645,7 +733,7 @@ mdoc_ns_pre(MDOC_ARGS)
static int
mdoc_ar_pre(MDOC_ARGS)
{
- print_otag(h, TAG_VAR, "cT", "Ar");
+ print_otag(h, TAG_VAR, "c", "Ar");
return 1;
}
@@ -660,7 +748,6 @@ static int
mdoc_it_pre(MDOC_ARGS)
{
const struct roff_node *bl;
- struct tag *t;
enum mdoc_list type;
bl = n->parent;
@@ -702,17 +789,6 @@ mdoc_it_pre(MDOC_ARGS)
case LIST_tag:
switch (n->type) {
case ROFFT_HEAD:
- if (h->style != NULL && !bl->norm->Bl.comp &&
- (n->parent->prev == NULL ||
- n->parent->prev->body == NULL ||
- n->parent->prev->body->child != NULL)) {
- t = print_otag(h, TAG_DT, "");
- print_text(h, "\\ ");
- print_tagq(h, t);
- t = print_otag(h, TAG_DD, "");
- print_text(h, "\\ ");
- print_tagq(h, t);
- }
print_otag(h, TAG_DT, "");
break;
case ROFFT_BODY:
@@ -746,17 +822,20 @@ mdoc_it_pre(MDOC_ARGS)
static int
mdoc_bl_pre(MDOC_ARGS)
{
- char cattr[28];
+ char cattr[32];
struct mdoc_bl *bl;
enum htmltag elemtype;
switch (n->type) {
- case ROFFT_BODY:
- return 1;
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ break;
case ROFFT_HEAD:
return 0;
+ case ROFFT_BODY:
+ return 1;
default:
- break;
+ abort();
}
bl = &n->norm->Bl;
@@ -826,28 +905,34 @@ mdoc_ex_pre(MDOC_ARGS)
static int
mdoc_st_pre(MDOC_ARGS)
{
- print_otag(h, TAG_SPAN, "cT", "St");
+ print_otag(h, TAG_SPAN, "c", "St");
return 1;
}
static int
mdoc_em_pre(MDOC_ARGS)
{
- print_otag(h, TAG_I, "cT", "Em");
+ print_otag(h, TAG_I, "c", "Em");
return 1;
}
static int
mdoc_d1_pre(MDOC_ARGS)
{
- if (n->type != ROFFT_BLOCK)
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
+ break;
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
return 1;
-
+ default:
+ abort();
+ }
print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
-
if (n->tok == MDOC_Dl)
print_otag(h, TAG_CODE, "c", "Li");
-
return 1;
}
@@ -857,7 +942,7 @@ mdoc_sx_pre(MDOC_ARGS)
char *id;
id = html_make_id(n, 0);
- print_otag(h, TAG_A, "cThR", "Sx", id);
+ print_otag(h, TAG_A, "chR", "Sx", id);
free(id);
return 1;
}
@@ -865,86 +950,51 @@ mdoc_sx_pre(MDOC_ARGS)
static int
mdoc_bd_pre(MDOC_ARGS)
{
- int comp, sv;
+ char buf[16];
struct roff_node *nn;
+ int comp;
- if (n->type == ROFFT_HEAD)
- return 0;
-
- if (n->type == ROFFT_BLOCK) {
- comp = n->norm->Bd.comp;
- for (nn = n; nn && ! comp; nn = nn->parent) {
- if (nn->type != ROFFT_BLOCK)
- continue;
- if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
- comp = 1;
- if (nn->prev)
- break;
- }
- if ( ! comp)
- print_paragraph(h);
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
return 1;
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
+ break;
+ default:
+ abort();
}
- /* Handle the -offset argument. */
-
- if (n->norm->Bd.offs == NULL ||
- ! strcmp(n->norm->Bd.offs, "left"))
- print_otag(h, TAG_DIV, "c", "Bd");
- else
- print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
-
- if (n->norm->Bd.type != DISP_unfilled &&
- n->norm->Bd.type != DISP_literal)
- return 1;
-
- print_otag(h, TAG_PRE, "c", "Li");
+ /* Handle preceding whitespace. */
- /* This can be recursive: save & set our literal state. */
-
- sv = h->flags & HTML_LITERAL;
- h->flags |= HTML_LITERAL;
-
- for (nn = n->child; nn; nn = nn->next) {
- print_mdoc_node(meta, nn, h);
- /*
- * If the printed node flushes its own line, then we
- * needn't do it here as well. This is hacky, but the
- * notion of selective eoln whitespace is pretty dumb
- * anyway, so don't sweat it.
- */
- switch (nn->tok) {
- case ROFF_br:
- case ROFF_sp:
- case MDOC_Sm:
- case MDOC_Bl:
- case MDOC_D1:
- case MDOC_Dl:
- case MDOC_Lp:
- case MDOC_Pp:
+ comp = n->norm->Bd.comp;
+ for (nn = n; nn != NULL && comp == 0; nn = nn->parent) {
+ if (nn->type != ROFFT_BLOCK)
continue;
- default:
+ if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
+ comp = 1;
+ if (nn->prev != NULL)
break;
- }
- if (h->flags & HTML_NONEWLINE ||
- (nn->next && ! (nn->next->flags & NODE_LINE)))
- continue;
- else if (nn->next)
- print_text(h, "\n");
-
- h->flags |= HTML_NOSPACE;
}
+ (void)strlcpy(buf, "Bd", sizeof(buf));
+ if (comp == 0)
+ (void)strlcat(buf, " Pp", sizeof(buf));
- if (0 == sv)
- h->flags &= ~HTML_LITERAL;
+ /* Handle the -offset argument. */
- return 0;
+ if (n->norm->Bd.offs != NULL &&
+ strcmp(n->norm->Bd.offs, "left") != 0)
+ (void)strlcat(buf, " Bd-indent", sizeof(buf));
+
+ print_otag(h, TAG_DIV, "c", buf);
+ return 1;
}
static int
mdoc_pa_pre(MDOC_ARGS)
{
- print_otag(h, TAG_SPAN, "cT", "Pa");
+ print_otag(h, TAG_SPAN, "c", "Pa");
return 1;
}
@@ -975,7 +1025,7 @@ mdoc_an_pre(MDOC_ARGS)
if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
h->flags |= HTML_SPLIT;
- print_otag(h, TAG_SPAN, "cT", "An");
+ print_otag(h, TAG_SPAN, "c", "An");
return 1;
}
@@ -983,7 +1033,7 @@ static int
mdoc_cd_pre(MDOC_ARGS)
{
synopsis_pre(h, n);
- print_otag(h, TAG_CODE, "cT", "Cd");
+ print_otag(h, TAG_CODE, "c", "Cd");
return 1;
}
@@ -994,7 +1044,7 @@ mdoc_dv_pre(MDOC_ARGS)
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "cTi", "Dv", id);
+ print_otag(h, TAG_CODE, "ci", "Dv", id);
return 1;
}
@@ -1005,7 +1055,7 @@ mdoc_ev_pre(MDOC_ARGS)
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "cTi", "Ev", id);
+ print_otag(h, TAG_CODE, "ci", "Ev", id);
return 1;
}
@@ -1022,7 +1072,7 @@ mdoc_er_pre(MDOC_ARGS)
if (id != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "cTi", "Er", id);
+ print_otag(h, TAG_CODE, "ci", "Er", id);
return 1;
}
@@ -1033,12 +1083,12 @@ mdoc_fa_pre(MDOC_ARGS)
struct tag *t;
if (n->parent->tok != MDOC_Fo) {
- print_otag(h, TAG_VAR, "cT", "Fa");
+ print_otag(h, TAG_VAR, "c", "Fa");
return 1;
}
for (nn = n->child; nn; nn = nn->next) {
- t = print_otag(h, TAG_VAR, "cT", "Fa");
+ t = print_otag(h, TAG_VAR, "c", "Fa");
print_text(h, nn->string);
print_tagq(h, t);
if (nn->next) {
@@ -1069,11 +1119,11 @@ mdoc_fd_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
if (strcmp(n->string, "#include")) {
- print_otag(h, TAG_CODE, "cT", "Fd");
+ print_otag(h, TAG_CODE, "c", "Fd");
return 1;
}
- print_otag(h, TAG_CODE, "cT", "In");
+ print_otag(h, TAG_CODE, "c", "In");
print_text(h, n->string);
if (NULL != (n = n->next)) {
@@ -1087,10 +1137,10 @@ mdoc_fd_pre(MDOC_ARGS)
cp = strchr(buf, '\0') - 1;
if (cp >= buf && (*cp == '>' || *cp == '"'))
*cp = '\0';
- t = print_otag(h, TAG_A, "cThI", "In", buf);
+ t = print_otag(h, TAG_A, "chI", "In", buf);
free(buf);
} else
- t = print_otag(h, TAG_A, "cT", "In");
+ t = print_otag(h, TAG_A, "c", "In");
print_text(h, n->string);
print_tagq(h, t);
@@ -1117,7 +1167,7 @@ mdoc_vt_pre(MDOC_ARGS)
} else if (n->type == ROFFT_HEAD)
return 0;
- print_otag(h, TAG_VAR, "cT", "Vt");
+ print_otag(h, TAG_VAR, "c", "Vt");
return 1;
}
@@ -1125,7 +1175,7 @@ static int
mdoc_ft_pre(MDOC_ARGS)
{
synopsis_pre(h, n);
- print_otag(h, TAG_VAR, "cT", "Ft");
+ print_otag(h, TAG_VAR, "c", "Ft");
return 1;
}
@@ -1146,7 +1196,7 @@ mdoc_fn_pre(MDOC_ARGS)
ep = strchr(sp, ' ');
if (NULL != ep) {
- t = print_otag(h, TAG_VAR, "cT", "Ft");
+ t = print_otag(h, TAG_VAR, "c", "Ft");
while (ep) {
sz = MIN((int)(ep - sp), BUFSIZ - 1);
@@ -1159,7 +1209,7 @@ mdoc_fn_pre(MDOC_ARGS)
print_tagq(h, t);
}
- t = print_otag(h, TAG_CODE, "cT", "Fn");
+ t = print_otag(h, TAG_CODE, "c", "Fn");
if (sp)
print_text(h, sp);
@@ -1172,10 +1222,10 @@ mdoc_fn_pre(MDOC_ARGS)
for (n = n->child->next; n; n = n->next) {
if (NODE_SYNPRETTY & n->flags)
- t = print_otag(h, TAG_VAR, "cTs", "Fa",
+ t = print_otag(h, TAG_VAR, "cs", "Fa",
"white-space", "nowrap");
else
- t = print_otag(h, TAG_VAR, "cT", "Fa");
+ t = print_otag(h, TAG_VAR, "c", "Fa");
print_text(h, n->string);
print_tagq(h, t);
if (n->next) {
@@ -1222,8 +1272,10 @@ mdoc_skip_pre(MDOC_ARGS)
static int
mdoc_pp_pre(MDOC_ARGS)
{
-
- print_paragraph(h);
+ if ((n->flags & NODE_NOFILL) == 0) {
+ html_close_paragraph(h);
+ print_otag(h, TAG_P, "c", "Pp");
+ }
return 0;
}
@@ -1246,7 +1298,7 @@ mdoc_lk_pre(MDOC_ARGS)
descr = link->next;
if (descr == punct)
descr = link; /* no text */
- t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
+ t = print_otag(h, TAG_A, "ch", "Lk", link->string);
do {
if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
h->flags |= HTML_NOSPACE;
@@ -1274,7 +1326,7 @@ mdoc_mt_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
mandoc_asprintf(&cp, "mailto:%s", n->string);
- t = print_otag(h, TAG_A, "cTh", "Mt", cp);
+ t = print_otag(h, TAG_A, "ch", "Mt", cp);
print_text(h, n->string);
print_tagq(h, t);
free(cp);
@@ -1302,7 +1354,7 @@ mdoc_fo_pre(MDOC_ARGS)
return 0;
assert(n->child->string);
- t = print_otag(h, TAG_CODE, "cT", "Fn");
+ t = print_otag(h, TAG_CODE, "c", "Fn");
print_text(h, n->child->string);
print_tagq(h, t);
return 0;
@@ -1326,7 +1378,7 @@ mdoc_in_pre(MDOC_ARGS)
struct tag *t;
synopsis_pre(h, n);
- print_otag(h, TAG_CODE, "cT", "In");
+ print_otag(h, TAG_CODE, "c", "In");
/*
* The first argument of the `In' gets special treatment as
@@ -1345,9 +1397,9 @@ mdoc_in_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
if (h->base_includes)
- t = print_otag(h, TAG_A, "cThI", "In", n->string);
+ t = print_otag(h, TAG_A, "chI", "In", n->string);
else
- t = print_otag(h, TAG_A, "cT", "In");
+ t = print_otag(h, TAG_A, "c", "In");
print_text(h, n->string);
print_tagq(h, t);
@@ -1372,14 +1424,14 @@ mdoc_ic_pre(MDOC_ARGS)
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "cTi", "Ic", id);
+ print_otag(h, TAG_CODE, "ci", "Ic", id);
return 1;
}
static int
mdoc_va_pre(MDOC_ARGS)
{
- print_otag(h, TAG_VAR, "cT", "Va");
+ print_otag(h, TAG_VAR, "c", "Va");
return 1;
}
@@ -1398,10 +1450,17 @@ mdoc_bf_pre(MDOC_ARGS)
{
const char *cattr;
- if (n->type == ROFFT_HEAD)
- return 0;
- else if (n->type != ROFFT_BODY)
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ html_close_paragraph(h);
return 1;
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
+ break;
+ default:
+ abort();
+ }
if (FONT_Em == n->norm->Bf.font)
cattr = "Bf Em";
@@ -1424,7 +1483,7 @@ mdoc_ms_pre(MDOC_ARGS)
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_SPAN, "cTi", "Ms", id);
+ print_otag(h, TAG_SPAN, "ci", "Ms", id);
return 1;
}
@@ -1447,13 +1506,21 @@ mdoc_pf_post(MDOC_ARGS)
static int
mdoc_rs_pre(MDOC_ARGS)
{
- if (n->type != ROFFT_BLOCK)
- return 1;
-
- if (n->prev && SEC_SEE_ALSO == n->sec)
- print_paragraph(h);
-
- print_otag(h, TAG_CITE, "cT", "Rs");
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ if (n->sec == SEC_SEE_ALSO)
+ html_close_paragraph(h);
+ break;
+ case ROFFT_HEAD:
+ return 0;
+ case ROFFT_BODY:
+ if (n->sec == SEC_SEE_ALSO)
+ print_otag(h, TAG_P, "c", "Pp");
+ print_otag(h, TAG_CITE, "c", "Rs");
+ break;
+ default:
+ abort();
+ }
return 1;
}
@@ -1482,7 +1549,7 @@ mdoc_li_pre(MDOC_ARGS)
static int
mdoc_sy_pre(MDOC_ARGS)
{
- print_otag(h, TAG_B, "cT", "Sy");
+ print_otag(h, TAG_B, "c", "Sy");
return 1;
}
@@ -1492,7 +1559,7 @@ mdoc_lb_pre(MDOC_ARGS)
if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
print_otag(h, TAG_BR, "");
- print_otag(h, TAG_SPAN, "cT", "Lb");
+ print_otag(h, TAG_SPAN, "c", "Lb");
return 1;
}
@@ -1630,9 +1697,15 @@ mdoc_quote_pre(MDOC_ARGS)
case MDOC_Oo:
case MDOC_Op:
print_text(h, "\\(lB");
- h->flags |= HTML_NOSPACE;
- /* Cannot use TAG_SPAN because it may contain blocks. */
- print_otag(h, TAG_IDIV, "c", "Op");
+ /*
+ * Give up on semantic markup for now.
+ * We cannot use TAG_SPAN because .Oo may contain blocks.
+ * We cannot use TAG_IDIV because we might be in a
+ * phrasing context (like .Dl or .Pp); we cannot
+ * close out a .Pp at this point either because
+ * that would break the line.
+ */
+ /* XXX print_otag(h, TAG_???, "c", "Op"); */
break;
case MDOC_En:
if (NULL == n->norm->Es ||
@@ -1760,3 +1833,9 @@ mdoc_eo_post(MDOC_ARGS)
else if ( ! tail)
h->flags &= ~HTML_NOSPACE;
}
+
+static int
+mdoc_abort_pre(MDOC_ARGS)
+{
+ abort();
+}
diff --git a/usr/src/cmd/mandoc/mdoc_macro.c b/usr/src/cmd/mandoc/mdoc_macro.c
index b463d03e22..3422945814 100644
--- a/usr/src/cmd/mandoc/mdoc_macro.c
+++ b/usr/src/cmd/mandoc/mdoc_macro.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_macro.c,v 1.224 2017/05/30 16:22:03 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.232 2019/01/07 07:26:29 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2019 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
@@ -49,7 +49,7 @@ static void dword(struct roff_man *, int, int, const char *,
static int find_pending(struct roff_man *, enum roff_tok,
int, int, struct roff_node *);
static int lookup(struct roff_man *, int, int, int, const char *);
-static int macro_or_word(MACRO_PROT_ARGS, int);
+static int macro_or_word(MACRO_PROT_ARGS, char *, int);
static void break_intermediate(struct roff_node *,
struct roff_node *);
static int parse_rest(struct roff_man *, enum roff_tok,
@@ -60,7 +60,7 @@ static void rew_last(struct roff_man *, const struct roff_node *);
static void rew_pending(struct roff_man *,
const struct roff_node *);
-const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
+static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = {
{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */
{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
@@ -201,9 +201,15 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
{ in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
};
-const struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd;
+const struct mdoc_macro *
+mdoc_macro(enum roff_tok tok)
+{
+ assert(tok >= MDOC_Dd && tok < MDOC_MAX);
+ return mdoc_macros + (tok - MDOC_Dd);
+}
+
/*
* This is called at the end of parsing. It must traverse up the tree,
* closing out open [implicit] scopes. Obviously, open explicit scopes
@@ -221,14 +227,13 @@ mdoc_endparse(struct roff_man *mdoc)
for ( ; n; n = n->parent)
if (n->type == ROFFT_BLOCK &&
- mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
- mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mdoc_macro(n->tok)->flags & MDOC_EXPLICIT)
+ mandoc_msg(MANDOCERR_BLK_NOEND,
+ n->line, n->pos, "%s", roff_name[n->tok]);
/* Rewind to the first. */
- rew_last(mdoc, mdoc->first);
- mdoc_state_reset(mdoc);
+ rew_last(mdoc, mdoc->meta.first);
}
/*
@@ -244,13 +249,12 @@ lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
mdoc->flags &= ~MDOC_PHRASEQF;
return TOKEN_NONE;
}
- if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
+ if (from == TOKEN_NONE || mdoc_macro(from)->flags & MDOC_PARSED) {
res = roffhash_find(mdoc->mdocmac, p, 0);
if (res != TOKEN_NONE) {
- if (mdoc_macros[res].flags & MDOC_CALLABLE)
+ if (mdoc_macro(res)->flags & MDOC_CALLABLE)
return res;
- mandoc_msg(MANDOCERR_MACRO_CALL,
- mdoc->parse, line, ppos, p);
+ mandoc_msg(MANDOCERR_MACRO_CALL, line, ppos, "%s", p);
}
}
return TOKEN_NONE;
@@ -291,6 +295,8 @@ rew_pending(struct roff_man *mdoc, const struct roff_node *n)
case ROFFT_HEAD:
roff_body_alloc(mdoc, n->line, n->pos,
n->tok);
+ if (n->tok == MDOC_Ss)
+ mdoc->flags &= ~ROFF_NONOFILL;
break;
case ROFFT_BLOCK:
break;
@@ -409,16 +415,15 @@ find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos,
if (n->flags & NODE_ENDED)
continue;
if (n->type == ROFFT_BLOCK &&
- mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) {
irc = 1;
break_intermediate(mdoc->last, target);
if (target->type == ROFFT_HEAD)
target->flags |= NODE_ENDED;
else if ( ! (target->flags & NODE_ENDED)) {
- mandoc_vmsg(MANDOCERR_BLK_NEST,
- mdoc->parse, line, ppos,
- "%s breaks %s", roff_name[tok],
- roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_BLK_NEST,
+ line, ppos, "%s breaks %s",
+ roff_name[tok], roff_name[n->tok]);
mdoc_endbody_alloc(mdoc, line, ppos,
tok, target);
}
@@ -470,14 +475,15 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
{
char *p;
int la;
+ enum margserr ac;
if (buf[*pos] == '\0')
return;
for (;;) {
la = *pos;
- if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) ==
- ARGS_EOLN)
+ ac = mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p);
+ if (ac == ARGS_EOLN)
break;
dword(mdoc, line, la, p, DELIM_MAX, 1);
@@ -495,6 +501,8 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
if (mandoc_eos(p, strlen(p)))
mdoc->last->flags |= NODE_EOS;
+ if (ac == ARGS_ALLOC)
+ free(p);
}
}
@@ -504,27 +512,23 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
* Otherwise, allocate it and return 0.
*/
static int
-macro_or_word(MACRO_PROT_ARGS, int parsed)
+macro_or_word(MACRO_PROT_ARGS, char *p, int parsed)
{
- char *p;
int ntok;
- p = buf + ppos;
- ntok = TOKEN_NONE;
- if (*p == '"')
- p++;
- else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
- ntok = lookup(mdoc, tok, line, ppos, p);
+ ntok = buf[ppos] == '"' || parsed == 0 ||
+ mdoc->flags & MDOC_PHRASELIT ? TOKEN_NONE :
+ lookup(mdoc, tok, line, ppos, p);
if (ntok == TOKEN_NONE) {
dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
- mdoc_macros[tok].flags & MDOC_JOIN);
+ mdoc_macro(tok)->flags & MDOC_JOIN);
return 0;
} else {
if (tok != TOKEN_NONE &&
- mdoc_macros[tok].fp == in_line_eoln)
+ mdoc_macro(tok)->fp == in_line_eoln)
rew_elem(mdoc, tok);
- mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
+ (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, ppos, pos, buf);
if (tok == TOKEN_NONE)
append_delims(mdoc, line, pos, buf);
return 1;
@@ -629,7 +633,7 @@ blk_exp_close(MACRO_PROT_ARGS)
* the scope - of the current block ends.
*/
- mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
+ mandoc_msg(MANDOCERR_BLK_NEST,
line, ppos, "%s breaks %s",
roff_name[atok], roff_name[later->tok]);
@@ -672,8 +676,8 @@ blk_exp_close(MACRO_PROT_ARGS)
}
if (body == NULL) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
- line, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, line, ppos,
+ "%s", roff_name[tok]);
if (maxargs && endbody == NULL) {
/*
* Stray .Ec without previous .Eo:
@@ -688,14 +692,25 @@ blk_exp_close(MACRO_PROT_ARGS)
mdoc_tail_alloc(mdoc, line, ppos, atok);
}
- if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
+ if ((mdoc_macro(tok)->flags & MDOC_PARSED) == 0) {
if (buf[*pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_SKIP,
- mdoc->parse, line, ppos,
- "%s %s", roff_name[tok],
- buf + *pos);
+ mandoc_msg(MANDOCERR_ARG_SKIP, line, ppos,
+ "%s %s", roff_name[tok], buf + *pos);
if (endbody == NULL && n != NULL)
rew_pending(mdoc, n);
+
+ /*
+ * Restore the fill mode that was set before the display.
+ * This needs to be done here rather than during validation
+ * such that subsequent nodes get the right flags.
+ */
+
+ if (tok == MDOC_Ed && body != NULL) {
+ if (body->flags & NODE_NOFILL)
+ mdoc->flags |= ROFF_NOFILL;
+ else
+ mdoc->flags &= ~ROFF_NOFILL;
+ }
return;
}
@@ -717,14 +732,18 @@ blk_exp_close(MACRO_PROT_ARGS)
if (ntok == TOKEN_NONE) {
dword(mdoc, line, lastarg, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags);
+ mdoc_macro(tok)->flags & MDOC_JOIN);
+ if (ac == ARGS_ALLOC)
+ free(p);
continue;
}
+ if (ac == ARGS_ALLOC)
+ free(p);
if (n != NULL)
rew_last(mdoc, n);
mdoc->flags &= ~MDOC_NEWLINE;
- mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
+ (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, lastarg, pos, buf);
break;
}
@@ -828,12 +847,14 @@ in_line(MACRO_PROT_ARGS)
} else if ( ! nc && ! cnt) {
mdoc_argv_free(arg);
mandoc_msg(MANDOCERR_MACRO_EMPTY,
- mdoc->parse, line, ppos,
- roff_name[tok]);
+ line, ppos, "%s", roff_name[tok]);
}
- mdoc_macro(mdoc, ntok, line, la, pos, buf);
+ (*mdoc_macro(ntok)->fp)(mdoc, ntok,
+ line, la, pos, buf);
if (nl)
append_delims(mdoc, line, pos, buf);
+ if (ac == ARGS_ALLOC)
+ free(p);
return;
}
@@ -875,7 +896,10 @@ in_line(MACRO_PROT_ARGS)
}
dword(mdoc, line, la, p, d,
- mdoc_macros[tok].flags & MDOC_JOIN);
+ mdoc_macro(tok)->flags & MDOC_JOIN);
+
+ if (ac == ARGS_ALLOC)
+ free(p);
/*
* If the first argument is a closing delimiter,
@@ -914,8 +938,8 @@ in_line(MACRO_PROT_ARGS)
rew_last(mdoc, mdoc->last);
} else {
mdoc_argv_free(arg);
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
- line, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
+ line, ppos, "%s", roff_name[tok]);
}
}
if (nl)
@@ -927,24 +951,25 @@ in_line(MACRO_PROT_ARGS)
static void
blk_full(MACRO_PROT_ARGS)
{
- int la, nl, parsed;
struct mdoc_arg *arg;
struct roff_node *blk; /* Our own or a broken block. */
struct roff_node *head; /* Our own head. */
struct roff_node *body; /* Our own body. */
struct roff_node *n;
- enum margserr ac, lac;
char *p;
+ size_t iarg;
+ int done, la, nl, parsed;
+ enum margserr ac, lac;
nl = MDOC_NEWLINE & mdoc->flags;
if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
- line, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
+ line, ppos, "%s", roff_name[tok]);
return;
}
- if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
+ if ((mdoc_macro(tok)->flags & MDOC_EXPLICIT) == 0) {
/* Here, tok is one of Sh Ss Nm Nd It. */
@@ -960,21 +985,20 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_It && n->tok == MDOC_Bl) {
if (blk != NULL) {
- mandoc_vmsg(MANDOCERR_BLK_BROKEN,
- mdoc->parse, line, ppos,
- "It breaks %s",
+ mandoc_msg(MANDOCERR_BLK_BROKEN,
+ line, ppos, "It breaks %s",
roff_name[blk->tok]);
rew_pending(mdoc, blk);
}
break;
}
- if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ if (mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) {
switch (tok) {
case MDOC_Sh:
case MDOC_Ss:
- mandoc_vmsg(MANDOCERR_BLK_BROKEN,
- mdoc->parse, line, ppos,
+ mandoc_msg(MANDOCERR_BLK_BROKEN,
+ line, ppos,
"%s breaks %s", roff_name[tok],
roff_name[n->tok]);
rew_pending(mdoc, n);
@@ -1000,8 +1024,7 @@ blk_full(MACRO_PROT_ARGS)
/* Item breaking an explicit block. */
if (blk != NULL) {
- mandoc_vmsg(MANDOCERR_BLK_BROKEN,
- mdoc->parse, line, ppos,
+ mandoc_msg(MANDOCERR_BLK_BROKEN, line, ppos,
"It breaks %s", roff_name[blk->tok]);
rew_pending(mdoc, blk);
blk = NULL;
@@ -1015,7 +1038,7 @@ blk_full(MACRO_PROT_ARGS)
/* Skip items outside lists. */
if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
- mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
+ mandoc_msg(MANDOCERR_IT_STRAY,
line, ppos, "It %s", buf + *pos);
roff_elem_alloc(mdoc, line, ppos, ROFF_br);
rew_elem(mdoc, ROFF_br);
@@ -1032,6 +1055,16 @@ blk_full(MACRO_PROT_ARGS)
* regular child nodes.
*/
+ switch (tok) {
+ case MDOC_Sh:
+ mdoc->flags &= ~ROFF_NOFILL;
+ break;
+ case MDOC_Ss:
+ mdoc->flags |= ROFF_NONOFILL;
+ break;
+ default:
+ break;
+ }
mdoc_argv(mdoc, line, tok, &arg, pos, buf);
blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
head = body = NULL;
@@ -1093,14 +1126,17 @@ blk_full(MACRO_PROT_ARGS)
}
if (tok == MDOC_Bd || tok == MDOC_Bk) {
- mandoc_vmsg(MANDOCERR_ARG_EXCESS,
- mdoc->parse, line, la, "%s ... %s",
- roff_name[tok], buf + la);
+ mandoc_msg(MANDOCERR_ARG_EXCESS, line, la,
+ "%s ... %s", roff_name[tok], buf + la);
+ if (ac == ARGS_ALLOC)
+ free(p);
break;
}
if (tok == MDOC_Rs) {
- mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_SKIP,
line, la, "Rs %s", buf + la);
+ if (ac == ARGS_ALLOC)
+ free(p);
break;
}
if (ac == ARGS_PUNCT)
@@ -1115,6 +1151,8 @@ blk_full(MACRO_PROT_ARGS)
ac != ARGS_PHRASE &&
mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
+ if (ac == ARGS_ALLOC)
+ free(p);
continue;
}
@@ -1146,7 +1184,10 @@ blk_full(MACRO_PROT_ARGS)
continue;
}
- if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
+ done = macro_or_word(mdoc, tok, line, la, pos, buf, p, parsed);
+ if (ac == ARGS_ALLOC)
+ free(p);
+ if (done)
break;
}
@@ -1165,6 +1206,33 @@ blk_full(MACRO_PROT_ARGS)
rew_last(mdoc, head);
body = roff_body_alloc(mdoc, line, ppos, tok);
+ if (tok == MDOC_Ss)
+ mdoc->flags &= ~ROFF_NONOFILL;
+
+ /*
+ * Set up fill mode for display blocks.
+ * This needs to be done here up front rather than during
+ * validation such that child nodes get the right flags.
+ */
+
+ if (tok == MDOC_Bd && arg != NULL) {
+ for (iarg = 0; iarg < arg->argc; iarg++) {
+ switch (arg->argv[iarg].arg) {
+ case MDOC_Unfilled:
+ case MDOC_Literal:
+ mdoc->flags |= ROFF_NOFILL;
+ break;
+ case MDOC_Filled:
+ case MDOC_Ragged:
+ case MDOC_Centred:
+ mdoc->flags &= ~ROFF_NOFILL;
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+ }
out:
if (mdoc->flags & MDOC_FREECOL) {
rew_last(mdoc, body);
@@ -1176,7 +1244,7 @@ out:
static void
blk_part_imp(MACRO_PROT_ARGS)
{
- int la, nl;
+ int done, la, nl;
enum margserr ac;
char *p;
struct roff_node *blk; /* saved block context */
@@ -1211,13 +1279,18 @@ blk_part_imp(MACRO_PROT_ARGS)
if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
+ if (ac == ARGS_ALLOC)
+ free(p);
continue;
}
if (body == NULL)
body = roff_body_alloc(mdoc, line, ppos, tok);
- if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1);
+ if (ac == ARGS_ALLOC)
+ free(p);
+ if (done)
break;
}
if (body == NULL)
@@ -1236,13 +1309,13 @@ blk_part_imp(MACRO_PROT_ARGS)
for (n = body->child; n && n->next; n = n->next)
/* Do nothing. */ ;
if (n && n->tok == MDOC_Ns)
- mdoc_node_relink(mdoc, n);
+ roff_node_relink(mdoc, n);
}
static void
blk_part_exp(MACRO_PROT_ARGS)
{
- int la, nl;
+ int done, la, nl;
enum margserr ac;
struct roff_node *head; /* keep track of head */
char *p;
@@ -1267,6 +1340,8 @@ blk_part_exp(MACRO_PROT_ARGS)
if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
+ if (ac == ARGS_ALLOC)
+ free(p);
continue;
}
@@ -1276,11 +1351,17 @@ blk_part_exp(MACRO_PROT_ARGS)
dword(mdoc, line, la, p, DELIM_MAX, 0);
rew_last(mdoc, head);
roff_body_alloc(mdoc, line, ppos, tok);
- if (tok == MDOC_Eo)
+ if (tok == MDOC_Eo) {
+ if (ac == ARGS_ALLOC)
+ free(p);
continue;
+ }
}
- if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1);
+ if (ac == ARGS_ALLOC)
+ free(p);
+ if (done)
break;
}
@@ -1338,10 +1419,12 @@ in_line_argn(MACRO_PROT_ARGS)
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ac == ARGS_WORD && state == -1 &&
- ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
+ if ((ac == ARGS_WORD || ac == ARGS_ALLOC) && state == -1 &&
+ (mdoc_macro(tok)->flags & MDOC_IGNDELIM) == 0 &&
mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
+ if (ac == ARGS_ALLOC)
+ free(p);
continue;
}
@@ -1353,8 +1436,8 @@ in_line_argn(MACRO_PROT_ARGS)
if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
if (abs(state) < 2 && tok == MDOC_Pf)
- mandoc_vmsg(MANDOCERR_PF_SKIP,
- mdoc->parse, line, ppos, "Pf %s",
+ mandoc_msg(MANDOCERR_PF_SKIP,
+ line, ppos, "Pf %s",
p == NULL ? "at eol" : p);
break;
}
@@ -1372,11 +1455,14 @@ in_line_argn(MACRO_PROT_ARGS)
rew_elem(mdoc, tok);
state = -2;
}
- mdoc_macro(mdoc, ntok, line, la, pos, buf);
+ (*mdoc_macro(ntok)->fp)(mdoc, ntok,
+ line, la, pos, buf);
+ if (ac == ARGS_ALLOC)
+ free(p);
break;
}
- if (mdoc_macros[tok].flags & MDOC_IGNDELIM ||
+ if (mdoc_macro(tok)->flags & MDOC_IGNDELIM ||
mdoc_isdelim(p) == DELIM_NONE) {
if (state == -1) {
mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
@@ -1389,12 +1475,15 @@ in_line_argn(MACRO_PROT_ARGS)
}
dword(mdoc, line, la, p, DELIM_MAX,
- mdoc_macros[tok].flags & MDOC_JOIN);
+ mdoc_macro(tok)->flags & MDOC_JOIN);
+ if (ac == ARGS_ALLOC)
+ free(p);
+ p = mdoc->last->string;
}
if (state == -1) {
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
- line, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
+ line, ppos, "%s", roff_name[tok]);
return;
}
@@ -1423,8 +1512,8 @@ in_line_eoln(MACRO_PROT_ARGS)
if (buf[*pos] == '\0' &&
(tok == MDOC_Fd || *roff_name[tok] == '%')) {
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
- line, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
+ line, ppos, "%s", roff_name[tok]);
return;
}
@@ -1444,13 +1533,19 @@ static int
parse_rest(struct roff_man *mdoc, enum roff_tok tok,
int line, int *pos, char *buf)
{
- int la;
+ char *p;
+ int done, la;
+ enum margserr ac;
for (;;) {
la = *pos;
- if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
+ ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
+ if (ac == ARGS_EOLN)
return 0;
- if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1);
+ if (ac == ARGS_ALLOC)
+ free(p);
+ if (done)
return 1;
}
}
@@ -1492,8 +1587,7 @@ phrase_ta(MACRO_PROT_ARGS)
}
if (n == NULL || n->norm->Bl.type != LIST_column) {
- mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
- line, ppos, "Ta");
+ mandoc_msg(MANDOCERR_TA_STRAY, line, ppos, "Ta");
return;
}
diff --git a/usr/src/cmd/mandoc/mdoc_man.c b/usr/src/cmd/mandoc/mdoc_man.c
index bcf9207f79..2e8f02ae56 100644
--- a/usr/src/cmd/mandoc/mdoc_man.c
+++ b/usr/src/cmd/mandoc/mdoc_man.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_man.c,v 1.126 2018/04/11 17:11:13 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.132 2019/01/04 03:17:36 schwarze Exp $ */
/*
- * Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2019 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
@@ -36,7 +36,7 @@
typedef int (*int_fp)(DECL_ARGS);
typedef void (*void_fp)(DECL_ARGS);
-struct manact {
+struct mdoc_man_act {
int_fp cond; /* DON'T run actions */
int_fp pre; /* pre-node action */
void_fp post; /* post-node action */
@@ -75,6 +75,7 @@ static void post_pf(DECL_ARGS);
static void post_sect(DECL_ARGS);
static void post_vt(DECL_ARGS);
static int pre__t(DECL_ARGS);
+static int pre_abort(DECL_ARGS);
static int pre_an(DECL_ARGS);
static int pre_ap(DECL_ARGS);
static int pre_aq(DECL_ARGS);
@@ -103,6 +104,7 @@ static int pre_lk(DECL_ARGS);
static int pre_li(DECL_ARGS);
static int pre_nm(DECL_ARGS);
static int pre_no(DECL_ARGS);
+static void pre_noarg(DECL_ARGS);
static int pre_ns(DECL_ARGS);
static void pre_onearg(DECL_ARGS);
static int pre_pp(DECL_ARGS);
@@ -124,12 +126,14 @@ static void print_width(const struct mdoc_bl *,
static void print_count(int *);
static void print_node(DECL_ARGS);
-static const void_fp roff_manacts[ROFF_MAX] = {
+static const void_fp roff_man_acts[ROFF_MAX] = {
pre_br, /* br */
pre_onearg, /* ce */
+ pre_noarg, /* fi */
pre_ft, /* ft */
pre_onearg, /* ll */
pre_onearg, /* mc */
+ pre_noarg, /* nf */
pre_onearg, /* po */
pre_onearg, /* rj */
pre_sp, /* sp */
@@ -137,7 +141,7 @@ static const void_fp roff_manacts[ROFF_MAX] = {
pre_onearg, /* ti */
};
-static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
+static const struct mdoc_man_act mdoc_man_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
{ NULL, NULL, NULL, NULL, NULL }, /* Os */
@@ -172,7 +176,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
- { NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
+ { NULL, pre_abort, NULL, NULL, NULL }, /* Ot */
{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
{ NULL, NULL, NULL, NULL, NULL }, /* St */
@@ -245,7 +249,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, pre_em, post_font, NULL, NULL }, /* Fr */
{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
- { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
+ { NULL, pre_abort, NULL, NULL, NULL }, /* Lp */
{ NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
{ NULL, pre_em, post_font, NULL, NULL }, /* Mt */
{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
@@ -259,7 +263,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
};
-static const struct manact *const manacts = __manacts - MDOC_Dd;
+static const struct mdoc_man_act *mdoc_man_act(enum roff_tok);
static int outflags;
#define MMAN_spc (1 << 0) /* blank character before next word */
@@ -290,6 +294,13 @@ static struct {
} fontqueue;
+static const struct mdoc_man_act *
+mdoc_man_act(enum roff_tok tok)
+{
+ assert(tok >= MDOC_Dd && tok <= MDOC_MAX);
+ return mdoc_man_acts + (tok - MDOC_Dd);
+}
+
static int
man_strlen(const char *cp)
{
@@ -317,6 +328,7 @@ man_strlen(const char *cp)
case ESCAPE_UNICODE:
case ESCAPE_NUMBERED:
case ESCAPE_SPECIAL:
+ case ESCAPE_UNDEF:
case ESCAPE_OVERSTRIKE:
if (skip)
skip = 0;
@@ -593,20 +605,7 @@ print_count(int *count)
}
void
-man_man(void *arg, const struct roff_man *man)
-{
-
- /*
- * Dump the keep buffer.
- * We're guaranteed by now that this exists (is non-NULL).
- * Flush stdout afterward, just in case.
- */
- fputs(mparse_getkeep(man_mparse(man)), stdout);
- fflush(stdout);
-}
-
-void
-man_mdoc(void *arg, const struct roff_man *mdoc)
+man_mdoc(void *arg, const struct roff_meta *mdoc)
{
struct roff_node *n;
@@ -619,9 +618,8 @@ man_mdoc(void *arg, const struct roff_man *mdoc)
}
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
- mdoc->meta.title,
- (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
- mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
+ mdoc->title, (mdoc->msec == NULL ? "" : mdoc->msec),
+ mdoc->date, mdoc->os, mdoc->vol);
/* Disable hyphenation and if nroff, disable justification. */
printf(".nh\n.if n .ad l");
@@ -633,16 +631,16 @@ man_mdoc(void *arg, const struct roff_man *mdoc)
*fontqueue.tail = 'R';
}
for (; n != NULL; n = n->next)
- print_node(&mdoc->meta, n);
+ print_node(mdoc, n);
putchar('\n');
}
static void
print_node(DECL_ARGS)
{
- const struct manact *act;
- struct roff_node *sub;
- int cond, do_sub;
+ const struct mdoc_man_act *act;
+ struct roff_node *sub;
+ int cond, do_sub;
if (n->flags & NODE_NOPRT)
return;
@@ -680,15 +678,14 @@ print_node(DECL_ARGS)
else if (outflags & MMAN_Sm)
outflags |= MMAN_spc;
} else if (n->tok < ROFF_MAX) {
- (*roff_manacts[n->tok])(meta, n);
+ (*roff_man_acts[n->tok])(meta, n);
return;
} else {
- assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
/*
* Conditionally run the pre-node action handler for a
* node.
*/
- act = manacts + n->tok;
+ act = mdoc_man_act(n->tok);
cond = act->cond == NULL || (*act->cond)(meta, n);
if (cond && act->pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
@@ -732,11 +729,17 @@ cond_body(DECL_ARGS)
}
static int
+pre_abort(DECL_ARGS)
+{
+ abort();
+}
+
+static int
pre_enc(DECL_ARGS)
{
const char *prefix;
- prefix = manacts[n->tok].prefix;
+ prefix = mdoc_man_act(n->tok)->prefix;
if (NULL == prefix)
return 1;
print_word(prefix);
@@ -749,7 +752,7 @@ post_enc(DECL_ARGS)
{
const char *suffix;
- suffix = manacts[n->tok].suffix;
+ suffix = mdoc_man_act(n->tok)->suffix;
if (NULL == suffix)
return;
outflags &= ~(MMAN_spc | MMAN_nl);
@@ -774,7 +777,7 @@ static void
post_percent(DECL_ARGS)
{
- if (pre_em == manacts[n->tok].pre)
+ if (mdoc_man_act(n->tok)->pre == pre_em)
font_pop();
if (n->next) {
print_word(",");
@@ -820,7 +823,7 @@ pre_sect(DECL_ARGS)
if (n->type == ROFFT_HEAD) {
outflags |= MMAN_sp;
- print_block(manacts[n->tok].prefix, 0);
+ print_block(mdoc_man_act(n->tok)->prefix, 0);
print_word("");
putchar('\"');
outflags &= ~MMAN_spc;
@@ -936,7 +939,6 @@ post_aq(DECL_ARGS)
static int
pre_bd(DECL_ARGS)
{
-
outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
if (DISP_unfilled == n->norm->Bd.type ||
@@ -951,12 +953,27 @@ pre_bd(DECL_ARGS)
static void
post_bd(DECL_ARGS)
{
+ enum roff_tok bef, now;
/* Close out this display. */
print_line(".RE", MMAN_nl);
- if (DISP_unfilled == n->norm->Bd.type ||
- DISP_literal == n->norm->Bd.type)
- print_line(".fi", MMAN_nl);
+ bef = n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi;
+ if (n->last == NULL)
+ now = n->norm->Bd.type == DISP_unfilled ||
+ n->norm->Bd.type == DISP_literal ? ROFF_nf : ROFF_fi;
+ else if (n->last->tok == ROFF_nf)
+ now = ROFF_nf;
+ else if (n->last->tok == ROFF_fi)
+ now = ROFF_fi;
+ else
+ now = n->last->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi;
+ if (bef != now) {
+ outflags |= MMAN_nl;
+ print_word(".");
+ outflags &= ~MMAN_spc;
+ print_word(roff_name[bef]);
+ outflags |= MMAN_nl;
+ }
/* Maybe we are inside an enclosing list? */
if (NULL != n->parent->next)
@@ -1607,7 +1624,6 @@ pre_onearg(DECL_ARGS)
static int
pre_li(DECL_ARGS)
{
-
font_push('R');
return 1;
}
@@ -1640,7 +1656,6 @@ pre_nm(DECL_ARGS)
static void
post_nm(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
outflags &= ~MMAN_Bk;
@@ -1658,15 +1673,23 @@ post_nm(DECL_ARGS)
static int
pre_no(DECL_ARGS)
{
-
outflags |= MMAN_spc_force;
return 1;
}
+static void
+pre_noarg(DECL_ARGS)
+{
+ outflags |= MMAN_nl;
+ print_word(".");
+ outflags &= ~MMAN_spc;
+ print_word(roff_name[n->tok]);
+ outflags |= MMAN_nl;
+}
+
static int
pre_ns(DECL_ARGS)
{
-
outflags &= ~MMAN_spc;
return 0;
}
diff --git a/usr/src/cmd/mandoc/mdoc_markdown.c b/usr/src/cmd/mandoc/mdoc_markdown.c
index e73440a4e5..b73811b76b 100644
--- a/usr/src/cmd/mandoc/mdoc_markdown.c
+++ b/usr/src/cmd/mandoc/mdoc_markdown.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_markdown.c,v 1.24 2018/04/11 17:11:13 schwarze Exp $ */
+/* $Id: mdoc_markdown.c,v 1.30 2018/12/30 00:49:55 schwarze Exp $ */
/*
- * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2018 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
@@ -19,6 +19,7 @@
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "mandoc_aux.h"
@@ -48,6 +49,7 @@ static void md_uri(const char *);
static int md_cond_head(struct roff_node *);
static int md_cond_body(struct roff_node *);
+static int md_pre_abort(struct roff_node *);
static int md_pre_raw(struct roff_node *);
static int md_pre_word(struct roff_node *);
static int md_pre_skip(struct roff_node *);
@@ -103,7 +105,7 @@ static void md_post_Pf(struct roff_node *);
static void md_post_Vt(struct roff_node *);
static void md_post__T(struct roff_node *);
-static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
+static const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
{ NULL, NULL, NULL, NULL, NULL }, /* Os */
@@ -138,7 +140,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
{ md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
{ NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
- { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */
+ { NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */
{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
{ NULL, NULL, NULL, NULL, NULL }, /* Rv */
{ NULL, NULL, NULL, NULL, NULL }, /* St */
@@ -211,7 +213,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
{ NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
- { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */
+ { NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */
{ NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
{ NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
@@ -225,7 +227,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
};
-static const struct md_act *const md_acts = __md_acts - MDOC_Dd;
+static const struct md_act *md_act(enum roff_tok);
static int outflags;
#define MD_spc (1 << 0) /* Blank character before next word. */
@@ -250,22 +252,30 @@ static int escflags; /* Escape in generated markdown code: */
static int code_blocks, quote_blocks, list_blocks;
static int outcount;
+
+static const struct md_act *
+md_act(enum roff_tok tok)
+{
+ assert(tok >= MDOC_Dd && tok <= MDOC_MAX);
+ return md_acts + (tok - MDOC_Dd);
+}
+
void
-markdown_mdoc(void *arg, const struct roff_man *mdoc)
+markdown_mdoc(void *arg, const struct roff_meta *mdoc)
{
outflags = MD_Sm;
- md_word(mdoc->meta.title);
- if (mdoc->meta.msec != NULL) {
+ md_word(mdoc->title);
+ if (mdoc->msec != NULL) {
outflags &= ~MD_spc;
md_word("(");
- md_word(mdoc->meta.msec);
+ md_word(mdoc->msec);
md_word(")");
}
md_word("-");
- md_word(mdoc->meta.vol);
- if (mdoc->meta.arch != NULL) {
+ md_word(mdoc->vol);
+ if (mdoc->arch != NULL) {
md_word("(");
- md_word(mdoc->meta.arch);
+ md_word(mdoc->arch);
md_word(")");
}
outflags |= MD_sp;
@@ -273,9 +283,9 @@ markdown_mdoc(void *arg, const struct roff_man *mdoc)
md_nodelist(mdoc->first->child);
outflags |= MD_sp;
- md_word(mdoc->meta.os);
+ md_word(mdoc->os);
md_word("-");
- md_word(mdoc->meta.date);
+ md_word(mdoc->date);
putchar('\n');
}
@@ -330,8 +340,7 @@ md_node(struct roff_node *n)
break;
}
} else {
- assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
- act = md_acts + n->tok;
+ act = md_act(n->tok);
cond = act->cond == NULL || (*act->cond)(n);
if (cond && act->pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
@@ -580,6 +589,12 @@ md_word(const char *s)
case ESCAPE_SPECIAL:
uc = mchars_spec2cp(seq, sz);
break;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
+ case ESCAPE_DEVICE:
+ md_rawword("markdown");
+ continue;
case ESCAPE_FONTBOLD:
nextfont = "**";
break;
@@ -590,6 +605,7 @@ md_word(const char *s)
nextfont = "***";
break;
case ESCAPE_FONT:
+ case ESCAPE_FONTCW:
case ESCAPE_FONTROMAN:
nextfont = "";
break;
@@ -712,11 +728,17 @@ md_cond_body(struct roff_node *n)
}
static int
+md_pre_abort(struct roff_node *n)
+{
+ abort();
+}
+
+static int
md_pre_raw(struct roff_node *n)
{
const char *prefix;
- if ((prefix = md_acts[n->tok].prefix) != NULL) {
+ if ((prefix = md_act(n->tok)->prefix) != NULL) {
md_rawword(prefix);
outflags &= ~MD_spc;
if (*prefix == '`')
@@ -730,7 +752,7 @@ md_post_raw(struct roff_node *n)
{
const char *suffix;
- if ((suffix = md_acts[n->tok].suffix) != NULL) {
+ if ((suffix = md_act(n->tok)->suffix) != NULL) {
outflags &= ~(MD_spc | MD_nl);
md_rawword(suffix);
if (*suffix == '`')
@@ -743,7 +765,7 @@ md_pre_word(struct roff_node *n)
{
const char *prefix;
- if ((prefix = md_acts[n->tok].prefix) != NULL) {
+ if ((prefix = md_act(n->tok)->prefix) != NULL) {
md_word(prefix);
outflags &= ~MD_spc;
}
@@ -755,7 +777,7 @@ md_post_word(struct roff_node *n)
{
const char *suffix;
- if ((suffix = md_acts[n->tok].suffix) != NULL) {
+ if ((suffix = md_act(n->tok)->suffix) != NULL) {
outflags &= ~(MD_spc | MD_nl);
md_word(suffix);
}
@@ -1268,7 +1290,7 @@ md_post_It(struct roff_node *n)
while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
i++;
- /*
+ /*
* If a width was specified for this column,
* subtract what printed, and
* add the same spacing as in mdoc_term.c.
diff --git a/usr/src/cmd/mandoc/mdoc_state.c b/usr/src/cmd/mandoc/mdoc_state.c
index 2d8563f5bf..f9a585e736 100644
--- a/usr/src/cmd/mandoc/mdoc_state.c
+++ b/usr/src/cmd/mandoc/mdoc_state.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_state.c,v 1.9 2017/11/29 20:05:33 schwarze Exp $ */
+/* $Id: mdoc_state.c,v 1.15 2019/01/01 07:42:04 schwarze Exp $ */
/*
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -17,6 +17,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -24,19 +25,18 @@
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
+#include "roff_int.h"
#include "libmdoc.h"
#define STATE_ARGS struct roff_man *mdoc, struct roff_node *n
typedef void (*state_handler)(STATE_ARGS);
-static void state_bd(STATE_ARGS);
static void state_bl(STATE_ARGS);
-static void state_dl(STATE_ARGS);
static void state_sh(STATE_ARGS);
static void state_sm(STATE_ARGS);
-static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
+static const state_handler state_handlers[MDOC_MAX - MDOC_Dd] = {
NULL, /* Dd */
NULL, /* Dt */
NULL, /* Os */
@@ -44,8 +44,8 @@ static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
NULL, /* Ss */
NULL, /* Pp */
NULL, /* D1 */
- state_dl, /* Dl */
- state_bd, /* Bd */
+ NULL, /* Dl */
+ NULL, /* Bd */
NULL, /* Ed */
state_bl, /* Bl */
NULL, /* El */
@@ -158,7 +158,6 @@ static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
NULL, /* %U */
NULL, /* Ta */
};
-static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
void
@@ -170,41 +169,14 @@ mdoc_state(struct roff_man *mdoc, struct roff_node *n)
return;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
- if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
+ if ((mdoc_macro(n->tok)->flags & MDOC_PROLOGUE) == 0)
mdoc->flags |= MDOC_PBODY;
- handler = state_handlers[n->tok];
+ handler = state_handlers[n->tok - MDOC_Dd];
if (*handler)
(*handler)(mdoc, n);
}
-void
-mdoc_state_reset(struct roff_man *mdoc)
-{
-
- roff_setreg(mdoc->roff, "nS", 0, '=');
- mdoc->flags = 0;
-}
-
-static void
-state_bd(STATE_ARGS)
-{
- enum mdocargt arg;
-
- if (n->type != ROFFT_HEAD &&
- (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
- return;
-
- if (n->parent->args == NULL)
- return;
-
- arg = n->parent->args->argv[0].arg;
- if (arg != MDOC_Literal && arg != MDOC_Unfilled)
- return;
-
- state_dl(mdoc, n);
-}
-
static void
state_bl(STATE_ARGS)
{
@@ -230,22 +202,6 @@ state_bl(STATE_ARGS)
}
static void
-state_dl(STATE_ARGS)
-{
-
- switch (n->type) {
- case ROFFT_HEAD:
- mdoc->flags |= MDOC_LITERAL;
- break;
- case ROFFT_BODY:
- mdoc->flags &= ~MDOC_LITERAL;
- break;
- default:
- break;
- }
-}
-
-static void
state_sh(STATE_ARGS)
{
struct roff_node *nch;
diff --git a/usr/src/cmd/mandoc/mdoc_term.c b/usr/src/cmd/mandoc/mdoc_term.c
index cf3e7ef3dd..c2f265c4e7 100644
--- a/usr/src/cmd/mandoc/mdoc_term.c
+++ b/usr/src/cmd/mandoc/mdoc_term.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_term.c,v 1.367 2018/04/11 17:11:13 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.373 2019/06/03 19:50:33 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -29,7 +29,6 @@
#include <string.h>
#include "mandoc_aux.h"
-#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "out.h"
@@ -47,7 +46,7 @@ struct termpair {
const struct roff_meta *meta, \
struct roff_node *n
-struct termact {
+struct mdoc_term_act {
int (*pre)(DECL_ARGS);
void (*post)(DECL_ARGS);
};
@@ -84,6 +83,7 @@ static void termp_xx_post(DECL_ARGS);
static int termp__a_pre(DECL_ARGS);
static int termp__t_pre(DECL_ARGS);
+static int termp_abort_pre(DECL_ARGS);
static int termp_an_pre(DECL_ARGS);
static int termp_ap_pre(DECL_ARGS);
static int termp_bd_pre(DECL_ARGS);
@@ -124,7 +124,7 @@ static int termp_vt_pre(DECL_ARGS);
static int termp_xr_pre(DECL_ARGS);
static int termp_xx_pre(DECL_ARGS);
-static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
+static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL }, /* Dd */
{ NULL, NULL }, /* Dt */
{ NULL, NULL }, /* Os */
@@ -159,7 +159,7 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
{ termp_nd_pre, NULL }, /* Nd */
{ termp_nm_pre, termp_nm_post }, /* Nm */
{ termp_quote_pre, termp_quote_post }, /* Op */
- { termp_ft_pre, NULL }, /* Ot */
+ { termp_abort_pre, NULL }, /* Ot */
{ termp_under_pre, NULL }, /* Pa */
{ termp_ex_pre, NULL }, /* Rv */
{ NULL, NULL }, /* St */
@@ -232,7 +232,7 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
{ termp_under_pre, NULL }, /* Fr */
{ NULL, NULL }, /* Ud */
{ NULL, termp_lb_post }, /* Lb */
- { termp_pp_pre, NULL }, /* Lp */
+ { termp_abort_pre, NULL }, /* Lp */
{ termp_lk_pre, NULL }, /* Lk */
{ termp_under_pre, NULL }, /* Mt */
{ termp_quote_pre, termp_quote_post }, /* Brq */
@@ -246,13 +246,12 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
};
-static const struct termact *const termacts = __termacts - MDOC_Dd;
static int fn_prio;
void
-terminal_mdoc(void *arg, const struct roff_man *mdoc)
+terminal_mdoc(void *arg, const struct roff_meta *mdoc)
{
struct roff_node *n;
struct termp *p;
@@ -270,8 +269,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
if (n->child->next->child != NULL)
print_mdoc_nodelist(p, NULL,
- &mdoc->meta,
- n->child->next->child);
+ mdoc, n->child->next->child);
term_newln(p);
break;
}
@@ -281,8 +279,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
save_defindent = p->defindent;
if (p->defindent == 0)
p->defindent = 5;
- term_begin(p, print_mdoc_head, print_mdoc_foot,
- &mdoc->meta);
+ term_begin(p, print_mdoc_head, print_mdoc_foot, mdoc);
while (n != NULL &&
(n->type == ROFFT_COMMENT ||
n->flags & NODE_NOPRT))
@@ -290,7 +287,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
if (n != NULL) {
if (n->tok != MDOC_Sh)
term_vspace(p);
- print_mdoc_nodelist(p, NULL, &mdoc->meta, n);
+ print_mdoc_nodelist(p, NULL, mdoc, n);
}
term_end(p);
p->defindent = save_defindent;
@@ -310,9 +307,23 @@ print_mdoc_nodelist(DECL_ARGS)
static void
print_mdoc_node(DECL_ARGS)
{
- int chld;
+ const struct mdoc_term_act *act;
struct termpair npair;
size_t offset, rmargin;
+ int chld;
+
+ /*
+ * In no-fill mode, break the output line at the beginning
+ * of new input lines except after \c, and nowhere else.
+ */
+
+ if (n->flags & NODE_NOFILL) {
+ if (n->flags & NODE_LINE &&
+ (p->flags & TERMP_NONEWLINE) == 0)
+ term_newln(p);
+ p->flags |= TERMP_BRNEVER;
+ } else
+ p->flags &= ~TERMP_BRNEVER;
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
return;
@@ -341,11 +352,25 @@ print_mdoc_node(DECL_ARGS)
* produce output. Note that some pre-handlers do so.
*/
+ act = NULL;
switch (n->type) {
case ROFFT_TEXT:
- if (*n->string == ' ' && n->flags & NODE_LINE &&
- (p->flags & TERMP_NONEWLINE) == 0)
- term_newln(p);
+ if (n->flags & NODE_LINE) {
+ switch (*n->string) {
+ case '\0':
+ if (p->flags & TERMP_NONEWLINE)
+ term_newln(p);
+ else
+ term_vspace(p);
+ return;
+ case ' ':
+ if ((p->flags & TERMP_NONEWLINE) == 0)
+ term_newln(p);
+ break;
+ default:
+ break;
+ }
+ }
if (NODE_DELIMC & n->flags)
p->flags |= TERMP_NOSPACE;
term_word(p, n->string);
@@ -370,10 +395,10 @@ print_mdoc_node(DECL_ARGS)
return;
}
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
- if (termacts[n->tok].pre != NULL &&
+ act = mdoc_term_acts + (n->tok - MDOC_Dd);
+ if (act->pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
- chld = (*termacts[n->tok].pre)
- (p, &npair, meta, n);
+ chld = (*act->pre)(p, &npair, meta, n);
break;
}
@@ -391,9 +416,9 @@ print_mdoc_node(DECL_ARGS)
case ROFFT_EQN:
break;
default:
- if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
+ if (act->post == NULL || n->flags & NODE_ENDED)
break;
- (void)(*termacts[n->tok].post)(p, &npair, meta, n);
+ (void)(*act->post)(p, &npair, meta, n);
/*
* Explicit end tokens not only call the post
@@ -1420,8 +1445,6 @@ termp_fa_pre(DECL_ARGS)
static int
termp_bd_pre(DECL_ARGS)
{
- size_t lm, len;
- struct roff_node *nn;
int offset;
if (n->type == ROFFT_BLOCK) {
@@ -1447,66 +1470,19 @@ termp_bd_pre(DECL_ARGS)
p->tcol->offset += offset;
}
- /*
- * If -ragged or -filled are specified, the block does nothing
- * but change the indentation. If -unfilled or -literal are
- * specified, text is printed exactly as entered in the display:
- * for macro lines, a newline is appended to the line. Blank
- * lines are allowed.
- */
-
- if (n->norm->Bd.type != DISP_literal &&
- n->norm->Bd.type != DISP_unfilled &&
- n->norm->Bd.type != DISP_centered)
- return 1;
-
- if (n->norm->Bd.type == DISP_literal) {
+ switch (n->norm->Bd.type) {
+ case DISP_literal:
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, "8n");
+ break;
+ case DISP_centered:
+ p->flags |= TERMP_CENTER;
+ break;
+ default:
+ break;
}
-
- lm = p->tcol->offset;
- p->flags |= TERMP_BRNEVER;
- for (nn = n->child; nn != NULL; nn = nn->next) {
- if (n->norm->Bd.type == DISP_centered) {
- if (nn->type == ROFFT_TEXT) {
- len = term_strlen(p, nn->string);
- p->tcol->offset = len >= p->tcol->rmargin ?
- 0 : lm + len >= p->tcol->rmargin ?
- p->tcol->rmargin - len :
- (lm + p->tcol->rmargin - len) / 2;
- } else
- p->tcol->offset = lm;
- }
- print_mdoc_node(p, pair, meta, nn);
- /*
- * If the printed node flushes its own line, then we
- * needn't do it here as well. This is hacky, but the
- * notion of selective eoln whitespace is pretty dumb
- * anyway, so don't sweat it.
- */
- if (nn->tok < ROFF_MAX)
- continue;
- switch (nn->tok) {
- case MDOC_Sm:
- case MDOC_Bl:
- case MDOC_D1:
- case MDOC_Dl:
- case MDOC_Lp:
- case MDOC_Pp:
- continue;
- default:
- break;
- }
- if (p->flags & TERMP_NONEWLINE ||
- (nn->next && ! (nn->next->flags & NODE_LINE)))
- continue;
- term_flushln(p);
- p->flags |= TERMP_NOSPACE;
- }
- p->flags &= ~TERMP_BRNEVER;
- return 0;
+ return 1;
}
static void
@@ -1514,12 +1490,14 @@ termp_bd_post(DECL_ARGS)
{
if (n->type != ROFFT_BODY)
return;
- if (DISP_literal == n->norm->Bd.type ||
- DISP_unfilled == n->norm->Bd.type)
+ if (n->norm->Bd.type == DISP_unfilled ||
+ n->norm->Bd.type == DISP_literal)
p->flags |= TERMP_BRNEVER;
p->flags |= TERMP_NOSPACE;
term_newln(p);
p->flags &= ~TERMP_BRNEVER;
+ if (n->norm->Bd.type == DISP_centered)
+ p->flags &= ~TERMP_CENTER;
}
static int
@@ -2098,3 +2076,9 @@ termp_tag_pre(DECL_ARGS)
tag_put(n->child->string, 1, p->line);
return 1;
}
+
+static int
+termp_abort_pre(DECL_ARGS)
+{
+ abort();
+}
diff --git a/usr/src/cmd/mandoc/mdoc_validate.c b/usr/src/cmd/mandoc/mdoc_validate.c
index 52545e3c46..a31310ec45 100644
--- a/usr/src/cmd/mandoc/mdoc_validate.c
+++ b/usr/src/cmd/mandoc/mdoc_validate.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_validate.c,v 1.360 2018/08/01 16:00:58 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.371 2019/03/04 13:01:57 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
* Copyright 2018, Joyent, Inc.
*
@@ -64,6 +64,7 @@ static int child_an(const struct roff_node *);
static size_t macro2len(enum roff_tok);
static void rewrite_macro2len(struct roff_man *, char **);
static int similar(const char *, const char *);
+static void post_abort(POST_ARGS);
static void post_an(POST_ARGS);
static void post_an_norm(POST_ARGS);
@@ -117,7 +118,7 @@ static void post_useless(POST_ARGS);
static void post_xr(POST_ARGS);
static void post_xx(POST_ARGS);
-static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
+static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_dd, /* Dd */
post_dt, /* Dt */
post_os, /* Os */
@@ -152,7 +153,7 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_nd, /* Nd */
post_nm, /* Nm */
post_delim_nb, /* Op */
- post_obsolete, /* Ot */
+ post_abort, /* Ot */
post_defaults, /* Pa */
post_rv, /* Rv */
post_st, /* St */
@@ -225,7 +226,7 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_obsolete, /* Fr */
post_eoln, /* Ud */
post_lb, /* Lb */
- post_par, /* Lp */
+ post_abort, /* Lp */
post_delim_nb, /* Lk */
post_defaults, /* Mt */
post_delim_nb, /* Brq */
@@ -239,7 +240,6 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
NULL, /* %U */
NULL, /* Ta */
};
-static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd;
#define RSORD_MAX 14 /* Number of `Rs' blocks. */
@@ -287,22 +287,48 @@ static const char * const secnames[SEC__MAX] = {
};
+/* Validate the subtree rooted at mdoc->last. */
void
-mdoc_node_validate(struct roff_man *mdoc)
+mdoc_validate(struct roff_man *mdoc)
{
struct roff_node *n, *np;
const v_post *p;
+ /*
+ * Translate obsolete macros to modern macros first
+ * such that later code does not need to look
+ * for the obsolete versions.
+ */
+
n = mdoc->last;
+ switch (n->tok) {
+ case MDOC_Lp:
+ n->tok = MDOC_Pp;
+ break;
+ case MDOC_Ot:
+ post_obsolete(mdoc);
+ n->tok = MDOC_Ft;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Iterate over all children, recursing into each one
+ * in turn, depth-first.
+ */
+
mdoc->last = mdoc->last->child;
while (mdoc->last != NULL) {
- mdoc_node_validate(mdoc);
+ mdoc_validate(mdoc);
if (mdoc->last == n)
mdoc->last = mdoc->last->child;
else
mdoc->last = mdoc->last->next;
}
+ /* Finally validate the macro itself. */
+
mdoc->last = n;
mdoc->next = ROFF_NEXT_SIBLING;
switch (n->type) {
@@ -311,9 +337,7 @@ mdoc_node_validate(struct roff_man *mdoc)
if (n->sec != SEC_SYNOPSIS ||
(np->tok != MDOC_Cd && np->tok != MDOC_Fd))
check_text(mdoc, n->line, n->pos, n->string);
- if (np->tok != MDOC_Ql && np->tok != MDOC_Dl &&
- (np->tok != MDOC_Bd ||
- (mdoc->flags & MDOC_LITERAL) == 0) &&
+ if ((n->flags & NODE_NOFILL) == 0 &&
(np->tok != MDOC_It || np->type != ROFFT_HEAD ||
np->parent->parent->norm->Bl.type != LIST_diag))
check_text_em(mdoc, n->line, n->pos, n->string);
@@ -345,20 +369,12 @@ mdoc_node_validate(struct roff_man *mdoc)
/* Call the macro's postprocessor. */
if (n->tok < ROFF_MAX) {
- switch(n->tok) {
- case ROFF_br:
- case ROFF_sp:
- post_par(mdoc);
- break;
- default:
- roff_validate(mdoc);
- break;
- }
+ roff_validate(mdoc);
break;
}
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
- p = mdoc_valids + n->tok;
+ p = mdoc_valids + (n->tok - MDOC_Dd);
if (*p)
(*p)(mdoc);
if (mdoc->last == n)
@@ -394,12 +410,11 @@ check_text(struct roff_man *mdoc, int ln, int pos, char *p)
{
char *cp;
- if (MDOC_LITERAL & mdoc->flags)
+ if (mdoc->last->flags & NODE_NOFILL)
return;
for (cp = p; NULL != (p = strchr(p, '\t')); p++)
- mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
- ln, pos + (int)(p - cp), NULL);
+ mandoc_msg(MANDOCERR_FI_TAB, ln, pos + (int)(p - cp), NULL);
}
static void
@@ -446,7 +461,7 @@ check_text_em(struct roff_man *mdoc, int ln, int pos, char *p)
nn != NULL &&
nn->type == ROFFT_TEXT &&
isalpha((unsigned char)*nn->string))) {
- mandoc_msg(MANDOCERR_DASHDASH, mdoc->parse,
+ mandoc_msg(MANDOCERR_DASHDASH,
ln, pos + (int)(cp - p) - 1, NULL);
break;
}
@@ -462,17 +477,13 @@ check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p)
return;
if ((cp = strstr(p, "OpenBSD")) != NULL)
- mandoc_msg(MANDOCERR_BX, mdoc->parse,
- ln, pos + (cp - p), "Ox");
+ mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Ox");
if ((cp = strstr(p, "NetBSD")) != NULL)
- mandoc_msg(MANDOCERR_BX, mdoc->parse,
- ln, pos + (cp - p), "Nx");
+ mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Nx");
if ((cp = strstr(p, "FreeBSD")) != NULL)
- mandoc_msg(MANDOCERR_BX, mdoc->parse,
- ln, pos + (cp - p), "Fx");
+ mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Fx");
if ((cp = strstr(p, "DragonFly")) != NULL)
- mandoc_msg(MANDOCERR_BX, mdoc->parse,
- ln, pos + (cp - p), "Dx");
+ mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Dx");
cp = p;
while ((cp = strstr(cp + 1, "()")) != NULL) {
@@ -481,14 +492,19 @@ check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p)
break;
if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) {
cpr++;
- mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse,
- ln, pos + (cpr - p),
+ mandoc_msg(MANDOCERR_FUNC, ln, pos + (int)(cpr - p),
"%.*s()", (int)(cp - cpr), cpr);
}
}
}
static void
+post_abort(POST_ARGS)
+{
+ abort();
+}
+
+static void
post_delim(POST_ARGS)
{
const struct roff_node *nch;
@@ -510,9 +526,8 @@ post_delim(POST_ARGS)
tok == MDOC_Ss || tok == MDOC_Fo))
return;
- mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse,
- nch->line, nch->pos + (lc - nch->string),
- "%s%s %s", roff_name[tok],
+ mandoc_msg(MANDOCERR_DELIM, nch->line,
+ nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok],
nch == mdoc->last->child ? "" : " ...", nch->string);
}
@@ -604,9 +619,8 @@ post_delim_nb(POST_ARGS)
}
}
- mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse,
- nch->line, nch->pos + (lc - nch->string),
- "%s%s %s", roff_name[tok],
+ mandoc_msg(MANDOCERR_DELIM_NB, nch->line,
+ nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok],
nch == mdoc->last->child ? "" : " ...", nch->string);
}
@@ -672,39 +686,34 @@ post_bl_norm(POST_ARGS)
case MDOC_Compact:
if (n->norm->Bl.comp)
mandoc_msg(MANDOCERR_ARG_REP,
- mdoc->parse, argv->line,
- argv->pos, "Bl -compact");
+ argv->line, argv->pos, "Bl -compact");
n->norm->Bl.comp = 1;
break;
case MDOC_Width:
wa = argv;
if (0 == argv->sz) {
mandoc_msg(MANDOCERR_ARG_EMPTY,
- mdoc->parse, argv->line,
- argv->pos, "Bl -width");
+ argv->line, argv->pos, "Bl -width");
n->norm->Bl.width = "0n";
break;
}
if (NULL != n->norm->Bl.width)
- mandoc_vmsg(MANDOCERR_ARG_REP,
- mdoc->parse, argv->line,
- argv->pos, "Bl -width %s",
- argv->value[0]);
+ mandoc_msg(MANDOCERR_ARG_REP,
+ argv->line, argv->pos,
+ "Bl -width %s", argv->value[0]);
rewrite_macro2len(mdoc, argv->value);
n->norm->Bl.width = argv->value[0];
break;
case MDOC_Offset:
if (0 == argv->sz) {
mandoc_msg(MANDOCERR_ARG_EMPTY,
- mdoc->parse, argv->line,
- argv->pos, "Bl -offset");
+ argv->line, argv->pos, "Bl -offset");
break;
}
if (NULL != n->norm->Bl.offs)
- mandoc_vmsg(MANDOCERR_ARG_REP,
- mdoc->parse, argv->line,
- argv->pos, "Bl -offset %s",
- argv->value[0]);
+ mandoc_msg(MANDOCERR_ARG_REP,
+ argv->line, argv->pos,
+ "Bl -offset %s", argv->value[0]);
rewrite_macro2len(mdoc, argv->value);
n->norm->Bl.offs = argv->value[0];
break;
@@ -718,8 +727,7 @@ post_bl_norm(POST_ARGS)
/* Check: multiple list types. */
if (LIST__NONE != n->norm->Bl.type) {
- mandoc_vmsg(MANDOCERR_BL_REP,
- mdoc->parse, n->line, n->pos,
+ mandoc_msg(MANDOCERR_BL_REP, n->line, n->pos,
"Bl -%s", mdoc_argnames[argv->arg]);
continue;
}
@@ -729,8 +737,8 @@ post_bl_norm(POST_ARGS)
if (n->norm->Bl.width ||
n->norm->Bl.offs ||
n->norm->Bl.comp)
- mandoc_vmsg(MANDOCERR_BL_LATETYPE,
- mdoc->parse, n->line, n->pos, "Bl -%s",
+ mandoc_msg(MANDOCERR_BL_LATETYPE,
+ n->line, n->pos, "Bl -%s",
mdoc_argnames[n->args->argv[0].arg]);
n->norm->Bl.type = lt;
@@ -743,8 +751,7 @@ post_bl_norm(POST_ARGS)
/* Allow lists to default to LIST_item. */
if (LIST__NONE == n->norm->Bl.type) {
- mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
- n->line, n->pos, "Bl");
+ mandoc_msg(MANDOCERR_BL_NOTYPE, n->line, n->pos, "Bl");
n->norm->Bl.type = LIST_item;
mdoclt = MDOC_Item;
}
@@ -759,7 +766,7 @@ post_bl_norm(POST_ARGS)
switch (n->norm->Bl.type) {
case LIST_tag:
if (n->norm->Bl.width == NULL)
- mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
+ mandoc_msg(MANDOCERR_BL_NOWIDTH,
n->line, n->pos, "Bl -tag");
break;
case LIST_column:
@@ -768,9 +775,8 @@ post_bl_norm(POST_ARGS)
case LIST_inset:
case LIST_item:
if (n->norm->Bl.width != NULL)
- mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
- wa->line, wa->pos, "Bl -%s",
- mdoc_argnames[mdoclt]);
+ mandoc_msg(MANDOCERR_BL_SKIPW, wa->line, wa->pos,
+ "Bl -%s", mdoc_argnames[mdoclt]);
n->norm->Bl.width = NULL;
break;
case LIST_bullet:
@@ -818,29 +824,25 @@ post_bd(POST_ARGS)
dt = DISP_literal;
break;
case MDOC_File:
- mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
- n->line, n->pos, NULL);
+ mandoc_msg(MANDOCERR_BD_FILE, n->line, n->pos, NULL);
break;
case MDOC_Offset:
if (0 == argv->sz) {
mandoc_msg(MANDOCERR_ARG_EMPTY,
- mdoc->parse, argv->line,
- argv->pos, "Bd -offset");
+ argv->line, argv->pos, "Bd -offset");
break;
}
if (NULL != n->norm->Bd.offs)
- mandoc_vmsg(MANDOCERR_ARG_REP,
- mdoc->parse, argv->line,
- argv->pos, "Bd -offset %s",
- argv->value[0]);
+ mandoc_msg(MANDOCERR_ARG_REP,
+ argv->line, argv->pos,
+ "Bd -offset %s", argv->value[0]);
rewrite_macro2len(mdoc, argv->value);
n->norm->Bd.offs = argv->value[0];
break;
case MDOC_Compact:
if (n->norm->Bd.comp)
mandoc_msg(MANDOCERR_ARG_REP,
- mdoc->parse, argv->line,
- argv->pos, "Bd -compact");
+ argv->line, argv->pos, "Bd -compact");
n->norm->Bd.comp = 1;
break;
default:
@@ -852,14 +854,12 @@ post_bd(POST_ARGS)
if (DISP__NONE == n->norm->Bd.type)
n->norm->Bd.type = dt;
else
- mandoc_vmsg(MANDOCERR_BD_REP,
- mdoc->parse, n->line, n->pos,
+ mandoc_msg(MANDOCERR_BD_REP, n->line, n->pos,
"Bd -%s", mdoc_argnames[argv->arg]);
}
if (DISP__NONE == n->norm->Bd.type) {
- mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
- n->line, n->pos, "Bd");
+ mandoc_msg(MANDOCERR_BD_NOTYPE, n->line, n->pos, "Bd");
n->norm->Bd.type = DISP_ragged;
}
}
@@ -881,8 +881,7 @@ post_an_norm(POST_ARGS)
for (i = 1; i < n->args->argc; i++) {
argv = n->args->argv + i;
- mandoc_vmsg(MANDOCERR_AN_REP,
- mdoc->parse, argv->line, argv->pos,
+ mandoc_msg(MANDOCERR_AN_REP, argv->line, argv->pos,
"An -%s", mdoc_argnames[argv->arg]);
}
@@ -903,7 +902,7 @@ post_eoln(POST_ARGS)
post_useless(mdoc);
n = mdoc->last;
if (n->child != NULL)
- mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line,
+ mandoc_msg(MANDOCERR_ARG_SKIP, n->line,
n->pos, "%s %s", roff_name[n->tok], n->child->string);
while (n->child != NULL)
@@ -925,7 +924,7 @@ build_list(struct roff_man *mdoc, int tok)
for (ic = 1;; ic++) {
roff_elem_alloc(mdoc, n->line, n->pos, tok);
mdoc->last->flags |= NODE_NOSRC;
- mdoc_node_relink(mdoc, n);
+ roff_node_relink(mdoc, n);
n = mdoc->last = mdoc->last->parent;
mdoc->next = ROFF_NEXT_SIBLING;
if (n->next == NULL)
@@ -966,8 +965,7 @@ post_ex(POST_ARGS)
mdoc->next = ROFF_NEXT_SIBLING;
ic = 1;
} else {
- mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
- n->line, n->pos, "Ex");
+ mandoc_msg(MANDOCERR_EX_NONAME, n->line, n->pos, "Ex");
ic = 0;
}
@@ -1000,7 +998,7 @@ post_lb(POST_ARGS)
return;
}
- mandoc_vmsg(MANDOCERR_LB_BAD, mdoc->parse, n->child->line,
+ mandoc_msg(MANDOCERR_LB_BAD, n->child->line,
n->child->pos, "Lb %s", n->child->string);
roff_word_alloc(mdoc, n->line, n->pos, "library");
@@ -1064,8 +1062,8 @@ post_std(POST_ARGS)
if (n->args->argv[0].arg == MDOC_Std)
return;
- mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_ARG_STD, n->line, n->pos,
+ "%s", roff_name[n->tok]);
}
static void
@@ -1079,7 +1077,7 @@ post_st(POST_ARGS)
assert(nch->type == ROFFT_TEXT);
if ((p = mdoc_a2st(nch->string)) == NULL) {
- mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
+ mandoc_msg(MANDOCERR_ST_BAD,
nch->line, nch->pos, "St %s", nch->string);
roff_node_delete(mdoc, n);
return;
@@ -1099,8 +1097,8 @@ post_obsolete(POST_ARGS)
n = mdoc->last;
if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
- mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_MACRO_OBS, n->line, n->pos,
+ "%s", roff_name[n->tok]);
}
static void
@@ -1109,8 +1107,8 @@ post_useless(POST_ARGS)
struct roff_node *n;
n = mdoc->last;
- mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_MACRO_USELESS, n->line, n->pos,
+ "%s", roff_name[n->tok]);
}
/*
@@ -1139,14 +1137,14 @@ post_bf(POST_ARGS)
nch = np->child;
if (np->parent->args == NULL) {
if (nch == NULL) {
- mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
+ mandoc_msg(MANDOCERR_BF_NOFONT,
np->line, np->pos, "Bf");
return;
}
nch = nch->next;
}
if (nch != NULL)
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
nch->line, nch->pos, "Bf ... %s", nch->string);
/* Extract argument into data. */
@@ -1177,9 +1175,8 @@ post_bf(POST_ARGS)
else if ( ! strcmp(np->child->string, "Sy"))
np->norm->Bf.font = FONT_Sy;
else
- mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
- np->child->line, np->child->pos,
- "Bf %s", np->child->string);
+ mandoc_msg(MANDOCERR_BF_BADFONT, np->child->line,
+ np->child->pos, "Bf %s", np->child->string);
}
static void
@@ -1193,8 +1190,8 @@ post_fname(POST_ARGS)
pos = strcspn(n->string, "()");
cp = n->string + pos;
if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
- mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
- n->line, n->pos + pos, n->string);
+ mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos,
+ "%s", n->string);
}
static void
@@ -1216,12 +1213,11 @@ post_fo(POST_ARGS)
return;
if (n->child == NULL) {
- mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
- n->line, n->pos, "Fo");
+ mandoc_msg(MANDOCERR_FO_NOHEAD, n->line, n->pos, "Fo");
return;
}
if (n->child != n->last) {
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
n->child->next->line, n->child->next->pos,
"Fo ... %s", n->child->next->string);
while (n->child != n->last)
@@ -1245,9 +1241,8 @@ post_fa(POST_ARGS)
break;
if (*cp != ',')
continue;
- mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
- n->line, n->pos + (cp - n->string),
- n->string);
+ mandoc_msg(MANDOCERR_FA_COMMA, n->line,
+ n->pos + (int)(cp - n->string), "%s", n->string);
break;
}
}
@@ -1265,18 +1260,15 @@ post_nm(POST_ARGS)
n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL)
mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1);
- if (n->last != NULL &&
- (n->last->tok == MDOC_Pp ||
- n->last->tok == MDOC_Lp))
- mdoc_node_relink(mdoc, n->last);
+ if (n->last != NULL && n->last->tok == MDOC_Pp)
+ roff_node_relink(mdoc, n->last);
if (mdoc->meta.name == NULL)
deroff(&mdoc->meta.name, n);
if (mdoc->meta.name == NULL ||
(mdoc->lastsec == SEC_NAME && n->child == NULL))
- mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
- n->line, n->pos, "Nm");
+ mandoc_msg(MANDOCERR_NM_NONAME, n->line, n->pos, "Nm");
switch (n->type) {
case ROFFT_ELEM:
@@ -1310,12 +1302,10 @@ post_nd(POST_ARGS)
return;
if (n->sec != SEC_NAME)
- mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse,
- n->line, n->pos, "Nd");
+ mandoc_msg(MANDOCERR_ND_LATE, n->line, n->pos, "Nd");
if (n->child == NULL)
- mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
- n->line, n->pos, "Nd");
+ mandoc_msg(MANDOCERR_ND_EMPTY, n->line, n->pos, "Nd");
else
post_delim(mdoc);
@@ -1335,8 +1325,8 @@ post_display(POST_ARGS)
n->body->parent->args == NULL)
roff_node_delete(mdoc, n);
} else if (n->child == NULL)
- mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos,
+ "%s", roff_name[n->tok]);
else if (n->tok == MDOC_D1)
post_hyph(mdoc);
break;
@@ -1344,10 +1334,10 @@ post_display(POST_ARGS)
if (n->tok == MDOC_Bd) {
if (n->args == NULL) {
mandoc_msg(MANDOCERR_BD_NOARG,
- mdoc->parse, n->line, n->pos, "Bd");
+ n->line, n->pos, "Bd");
mdoc->next = ROFF_NEXT_SIBLING;
while (n->body->child != NULL)
- mdoc_node_relink(mdoc,
+ roff_node_relink(mdoc,
n->body->child);
roff_node_delete(mdoc, n);
break;
@@ -1357,9 +1347,8 @@ post_display(POST_ARGS)
}
for (np = n->parent; np != NULL; np = np->parent) {
if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) {
- mandoc_vmsg(MANDOCERR_BD_NEST,
- mdoc->parse, n->line, n->pos,
- "%s in Bd", roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_BD_NEST, n->line,
+ n->pos, "%s in Bd", roff_name[n->tok]);
break;
}
}
@@ -1423,7 +1412,7 @@ post_at(POST_ARGS)
att = NULL;
if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL))
- mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
+ mandoc_msg(MANDOCERR_AT_BAD,
nch->line, nch->pos, "At %s", nch->string);
mdoc->next = ROFF_NEXT_CHILD;
@@ -1447,12 +1436,12 @@ post_an(POST_ARGS)
nch = np->child;
if (np->norm->An.auth == AUTH__NONE) {
if (nch == NULL)
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
np->line, np->pos, "An");
else
post_delim_nb(mdoc);
} else if (nch != NULL)
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
nch->line, nch->pos, "An ... %s", nch->string);
}
@@ -1548,9 +1537,8 @@ post_it(POST_ARGS)
case LIST_inset:
case LIST_diag:
if (nit->head->child == NULL)
- mandoc_vmsg(MANDOCERR_IT_NOHEAD,
- mdoc->parse, nit->line, nit->pos,
- "Bl -%s It",
+ mandoc_msg(MANDOCERR_IT_NOHEAD,
+ nit->line, nit->pos, "Bl -%s It",
mdoc_argnames[nbl->args->argv[0].arg]);
break;
case LIST_bullet:
@@ -1558,14 +1546,13 @@ post_it(POST_ARGS)
case LIST_enum:
case LIST_hyphen:
if (nit->body == NULL || nit->body->child == NULL)
- mandoc_vmsg(MANDOCERR_IT_NOBODY,
- mdoc->parse, nit->line, nit->pos,
- "Bl -%s It",
+ mandoc_msg(MANDOCERR_IT_NOBODY,
+ nit->line, nit->pos, "Bl -%s It",
mdoc_argnames[nbl->args->argv[0].arg]);
/* FALLTHROUGH */
case LIST_item:
if ((nch = nit->head->child) != NULL)
- mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_SKIP,
nit->line, nit->pos, "It %s",
nch->string == NULL ? roff_name[nch->tok] :
nch->string);
@@ -1577,7 +1564,7 @@ post_it(POST_ARGS)
if (nit->head->next->child == NULL &&
nit->head->next->next == NULL) {
- mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
nit->line, nit->pos, "It");
roff_node_delete(mdoc, nit);
break;
@@ -1588,16 +1575,15 @@ post_it(POST_ARGS)
if (nch->type != ROFFT_BODY)
continue;
if (i++ && nch->flags & NODE_LINE)
- mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse,
+ mandoc_msg(MANDOCERR_TA_LINE,
nch->line, nch->pos, "Ta");
}
if (i < cols || i > cols + 1)
- mandoc_vmsg(MANDOCERR_BL_COL,
- mdoc->parse, nit->line, nit->pos,
+ mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos,
"%d columns, %d cells", cols, i);
else if (nit->head->next->child != NULL &&
- nit->head->next->child->line > nit->line)
- mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse,
+ nit->head->next->child->flags & NODE_LINE)
+ mandoc_msg(MANDOCERR_IT_NOARG,
nit->line, nit->pos, "Bl -column It");
break;
default:
@@ -1620,7 +1606,6 @@ post_bl_block(POST_ARGS)
while (nc != NULL) {
switch (nc->tok) {
case MDOC_Pp:
- case MDOC_Lp:
case ROFF_br:
break;
default:
@@ -1628,14 +1613,13 @@ post_bl_block(POST_ARGS)
continue;
}
if (ni->next == NULL) {
- mandoc_msg(MANDOCERR_PAR_MOVE,
- mdoc->parse, nc->line, nc->pos,
- roff_name[nc->tok]);
- mdoc_node_relink(mdoc, nc);
+ mandoc_msg(MANDOCERR_PAR_MOVE, nc->line,
+ nc->pos, "%s", roff_name[nc->tok]);
+ roff_node_relink(mdoc, nc);
} else if (n->norm->Bl.comp == 0 &&
n->norm->Bl.type != LIST_column) {
- mandoc_vmsg(MANDOCERR_PAR_SKIP,
- mdoc->parse, nc->line, nc->pos,
+ mandoc_msg(MANDOCERR_PAR_SKIP,
+ nc->line, nc->pos,
"%s before It", roff_name[nc->tok]);
roff_node_delete(mdoc, nc);
} else
@@ -1681,7 +1665,7 @@ post_bl_head(POST_ARGS)
if (nh->norm->Bl.type != LIST_column) {
if ((nch = nh->child) == NULL)
return;
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
nch->line, nch->pos, "Bl ... %s", nch->string);
while (nch != NULL) {
roff_node_delete(mdoc, nch);
@@ -1758,7 +1742,7 @@ post_bl(POST_ARGS)
nchild = nbody->child;
if (nchild == NULL) {
- mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ mandoc_msg(MANDOCERR_BLK_EMPTY,
nbody->line, nbody->pos, "Bl");
return;
}
@@ -1791,7 +1775,7 @@ post_bl(POST_ARGS)
roff_body_alloc(mdoc, nchild->line,
nchild->pos, MDOC_It);
while (nchild->tok != MDOC_It) {
- mdoc_node_relink(mdoc, nchild);
+ roff_node_relink(mdoc, nchild);
if ((nchild = nnext) == NULL)
break;
nnext = nchild->next;
@@ -1801,8 +1785,8 @@ post_bl(POST_ARGS)
continue;
}
- mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
- nchild->line, nchild->pos, roff_name[nchild->tok]);
+ mandoc_msg(MANDOCERR_BL_MOVE, nchild->line, nchild->pos,
+ "%s", roff_name[nchild->tok]);
/*
* Move the node out of the Bl block.
@@ -1857,13 +1841,13 @@ post_bl(POST_ARGS)
if (prev_Er != NULL) {
order = strcmp(prev_Er, nnext->string);
if (order > 0)
- mandoc_vmsg(MANDOCERR_ER_ORDER,
- mdoc->parse, nnext->line, nnext->pos,
+ mandoc_msg(MANDOCERR_ER_ORDER,
+ nnext->line, nnext->pos,
"Er %s %s (NetBSD)",
prev_Er, nnext->string);
else if (order == 0)
- mandoc_vmsg(MANDOCERR_ER_REP,
- mdoc->parse, nnext->line, nnext->pos,
+ mandoc_msg(MANDOCERR_ER_REP,
+ nnext->line, nnext->pos,
"Er %s (NetBSD)", prev_Er);
}
prev_Er = nnext->string;
@@ -1878,8 +1862,7 @@ post_bk(POST_ARGS)
n = mdoc->last;
if (n->type == ROFFT_BLOCK && n->body->child == NULL) {
- mandoc_msg(MANDOCERR_BLK_EMPTY,
- mdoc->parse, n->line, n->pos, "Bk");
+ mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, "Bk");
roff_node_delete(mdoc, n);
}
}
@@ -1907,39 +1890,16 @@ post_sm(POST_ARGS)
return;
}
- mandoc_vmsg(MANDOCERR_SM_BAD,
- mdoc->parse, nch->line, nch->pos,
+ mandoc_msg(MANDOCERR_SM_BAD, nch->line, nch->pos,
"%s %s", roff_name[mdoc->last->tok], nch->string);
- mdoc_node_relink(mdoc, nch);
+ roff_node_relink(mdoc, nch);
return;
}
static void
post_root(POST_ARGS)
{
- const char *openbsd_arch[] = {
- "alpha", "amd64", "arm64", "armv7", "hppa", "i386",
- "landisk", "loongson", "luna88k", "macppc", "mips64",
- "octeon", "sgi", "socppc", "sparc64", NULL
- };
- const char *netbsd_arch[] = {
- "acorn26", "acorn32", "algor", "alpha", "amiga",
- "arc", "atari",
- "bebox", "cats", "cesfic", "cobalt", "dreamcast",
- "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5",
- "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa",
- "i386", "ibmnws", "luna68k",
- "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc",
- "netwinder", "news68k", "newsmips", "next68k",
- "pc532", "playstation2", "pmax", "pmppc", "prep",
- "sandpoint", "sbmips", "sgimips", "shark",
- "sparc", "sparc64", "sun2", "sun3",
- "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL
- };
- const char **arches[] = { NULL, netbsd_arch, openbsd_arch };
-
struct roff_node *n;
- const char **arch;
/* Add missing prologue data. */
@@ -1948,8 +1908,7 @@ post_root(POST_ARGS)
mandoc_normdate(mdoc, NULL, 0, 0);
if (mdoc->meta.title == NULL) {
- mandoc_msg(MANDOCERR_DT_NOTITLE,
- mdoc->parse, 0, 0, "EOF");
+ mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF");
mdoc->meta.title = mandoc_strdup("UNTITLED");
}
@@ -1957,49 +1916,43 @@ post_root(POST_ARGS)
mdoc->meta.vol = mandoc_strdup("LOCAL");
if (mdoc->meta.os == NULL) {
- mandoc_msg(MANDOCERR_OS_MISSING,
- mdoc->parse, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_OS_MISSING, 0, 0, NULL);
mdoc->meta.os = mandoc_strdup("");
} else if (mdoc->meta.os_e &&
(mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0)
- mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0,
+ mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0,
mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
"(OpenBSD)" : "(NetBSD)");
if (mdoc->meta.arch != NULL &&
- (arch = arches[mdoc->meta.os_e]) != NULL) {
- while (*arch != NULL && strcmp(*arch, mdoc->meta.arch))
- arch++;
- if (*arch == NULL) {
- n = mdoc->first->child;
- while (n->tok != MDOC_Dt ||
- n->child == NULL ||
- n->child->next == NULL ||
- n->child->next->next == NULL)
- n = n->next;
- n = n->child->next->next;
- mandoc_vmsg(MANDOCERR_ARCH_BAD,
- mdoc->parse, n->line, n->pos,
- "Dt ... %s %s", mdoc->meta.arch,
- mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
- "(OpenBSD)" : "(NetBSD)");
- }
+ arch_valid(mdoc->meta.arch, mdoc->meta.os_e) == 0) {
+ n = mdoc->meta.first->child;
+ while (n->tok != MDOC_Dt ||
+ n->child == NULL ||
+ n->child->next == NULL ||
+ n->child->next->next == NULL)
+ n = n->next;
+ n = n->child->next->next;
+ mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos,
+ "Dt ... %s %s", mdoc->meta.arch,
+ mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
+ "(OpenBSD)" : "(NetBSD)");
}
/* Check that we begin with a proper `Sh'. */
- n = mdoc->first->child;
+ n = mdoc->meta.first->child;
while (n != NULL &&
(n->type == ROFFT_COMMENT ||
(n->tok >= MDOC_Dd &&
- mdoc_macros[n->tok].flags & MDOC_PROLOGUE)))
+ mdoc_macro(n->tok)->flags & MDOC_PROLOGUE)))
n = n->next;
if (n == NULL)
- mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_DOC_EMPTY, 0, 0, NULL);
else if (n->tok != MDOC_Sh)
- mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_SEC_BEFORE, n->line, n->pos,
+ "%s", roff_name[n->tok]);
}
static void
@@ -2014,8 +1967,7 @@ post_rs(POST_ARGS)
return;
if (np->child == NULL) {
- mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
- np->line, np->pos, "Rs");
+ mandoc_msg(MANDOCERR_RS_EMPTY, np->line, np->pos, "Rs");
return;
}
@@ -2033,8 +1985,8 @@ post_rs(POST_ARGS)
break;
if (i == RSORD_MAX) {
- mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse,
- nch->line, nch->pos, roff_name[nch->tok]);
+ mandoc_msg(MANDOCERR_RS_BAD, nch->line, nch->pos,
+ "%s", roff_name[nch->tok]);
i = -1;
} else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
np->norm->Rs.quote_T++;
@@ -2123,8 +2075,7 @@ post_ns(POST_ARGS)
n = mdoc->last;
if (n->flags & NODE_LINE ||
(n->next != NULL && n->next->flags & NODE_DELIMC))
- mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
- n->line, n->pos, NULL);
+ mandoc_msg(MANDOCERR_NS_SKIP, n->line, n->pos, NULL);
}
static void
@@ -2176,8 +2127,8 @@ post_sh_name(POST_ARGS)
switch (n->tok) {
case MDOC_Nm:
if (hasnm && n->child != NULL)
- mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT,
- mdoc->parse, n->line, n->pos,
+ mandoc_msg(MANDOCERR_NAMESEC_PUNCT,
+ n->line, n->pos,
"Nm %s", n->child->string);
hasnm = 1;
continue;
@@ -2185,7 +2136,7 @@ post_sh_name(POST_ARGS)
hasnd = 1;
if (n->next != NULL)
mandoc_msg(MANDOCERR_NAMESEC_ND,
- mdoc->parse, n->line, n->pos, NULL);
+ n->line, n->pos, NULL);
break;
case TOKEN_NONE:
if (n->type == ROFFT_TEXT &&
@@ -2196,18 +2147,18 @@ post_sh_name(POST_ARGS)
}
/* FALLTHROUGH */
default:
- mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
- n->line, n->pos, roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_NAMESEC_BAD,
+ n->line, n->pos, "%s", roff_name[n->tok]);
continue;
}
break;
}
if ( ! hasnm)
- mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
+ mandoc_msg(MANDOCERR_NAMESEC_NONM,
mdoc->last->line, mdoc->last->pos, NULL);
if ( ! hasnd)
- mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
+ mandoc_msg(MANDOCERR_NAMESEC_NOND,
mdoc->last->line, mdoc->last->pos, NULL);
}
@@ -2233,21 +2184,18 @@ post_sh_see_also(POST_ARGS)
sec = n->child->next->string;
if (lastsec != NULL) {
if (lastpunct[0] != ',' || lastpunct[1] != '\0')
- mandoc_vmsg(MANDOCERR_XR_PUNCT,
- mdoc->parse, n->line, n->pos,
- "%s before %s(%s)", lastpunct,
- name, sec);
+ mandoc_msg(MANDOCERR_XR_PUNCT, n->line,
+ n->pos, "%s before %s(%s)",
+ lastpunct, name, sec);
cmp = strcmp(lastsec, sec);
if (cmp > 0)
- mandoc_vmsg(MANDOCERR_XR_ORDER,
- mdoc->parse, n->line, n->pos,
- "%s(%s) after %s(%s)", name,
- sec, lastname, lastsec);
+ mandoc_msg(MANDOCERR_XR_ORDER, n->line,
+ n->pos, "%s(%s) after %s(%s)",
+ name, sec, lastname, lastsec);
else if (cmp == 0 &&
strcasecmp(lastname, name) > 0)
- mandoc_vmsg(MANDOCERR_XR_ORDER,
- mdoc->parse, n->line, n->pos,
- "%s after %s", name, lastname);
+ mandoc_msg(MANDOCERR_XR_ORDER, n->line,
+ n->pos, "%s after %s", name, lastname);
}
lastname = name;
lastsec = sec;
@@ -2268,8 +2216,8 @@ post_sh_see_also(POST_ARGS)
return;
lastpunct = n->string;
if (n->next == NULL || n->next->tok == MDOC_Rs)
- mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
- n->line, n->pos, "%s after %s(%s)",
+ mandoc_msg(MANDOCERR_XR_PUNCT, n->line,
+ n->pos, "%s after %s(%s)",
lastpunct, lastname, lastsec);
n = n->next;
}
@@ -2290,7 +2238,7 @@ post_sh_authors(POST_ARGS)
{
if ( ! child_an(mdoc->last))
- mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
+ mandoc_msg(MANDOCERR_AN_MISSING,
mdoc->last->line, mdoc->last->pos, NULL);
}
@@ -2356,7 +2304,7 @@ post_sh_head(POST_ARGS)
/* The NAME should be first. */
if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE)
- mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
+ mandoc_msg(MANDOCERR_NAMESEC_FIRST,
mdoc->last->line, mdoc->last->pos, "Sh %s",
sec != SEC_CUSTOM ? secnames[sec] :
(nch = mdoc->last->child) == NULL ? "" :
@@ -2393,9 +2341,8 @@ post_sh_head(POST_ARGS)
}
}
if (goodsec != NULL)
- mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse,
- nch->line, nch->pos, "Sh %s instead of %s",
- nch->string, goodsec);
+ mandoc_msg(MANDOCERR_SEC_TYPO, nch->line, nch->pos,
+ "Sh %s instead of %s", nch->string, goodsec);
return;
}
@@ -2405,14 +2352,12 @@ post_sh_head(POST_ARGS)
*/
if (sec == mdoc->lastnamed)
- mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
- mdoc->last->line, mdoc->last->pos,
- "Sh %s", secnames[sec]);
+ mandoc_msg(MANDOCERR_SEC_REP, mdoc->last->line,
+ mdoc->last->pos, "Sh %s", secnames[sec]);
if (sec < mdoc->lastnamed)
- mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
- mdoc->last->line, mdoc->last->pos,
- "Sh %s", secnames[sec]);
+ mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->last->line,
+ mdoc->last->pos, "Sh %s", secnames[sec]);
/* Mark the last named section. */
@@ -2446,7 +2391,7 @@ post_sh_head(POST_ARGS)
break;
if (NULL == goodsec)
goodsec = "9";
- mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
+ mandoc_msg(MANDOCERR_SEC_MSEC,
mdoc->last->line, mdoc->last->pos,
"Sh %s for %s only", secnames[sec], goodsec);
break;
@@ -2463,13 +2408,13 @@ post_xr(POST_ARGS)
n = mdoc->last;
nch = n->child;
if (nch->next == NULL) {
- mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse,
+ mandoc_msg(MANDOCERR_XR_NOSEC,
n->line, n->pos, "Xr %s", nch->string);
} else {
assert(nch->next == n->last);
if(mandoc_xr_add(nch->next->string, nch->string,
nch->line, nch->pos))
- mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse,
+ mandoc_msg(MANDOCERR_XR_SELF,
nch->line, nch->pos, "Xr %s %s",
nch->string, nch->next->string);
}
@@ -2496,19 +2441,18 @@ post_ignpar(POST_ARGS)
}
if ((np = mdoc->last->child) != NULL)
- if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
- mandoc_vmsg(MANDOCERR_PAR_SKIP,
- mdoc->parse, np->line, np->pos,
+ if (np->tok == MDOC_Pp ||
+ np->tok == ROFF_br || np->tok == ROFF_sp) {
+ mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
"%s after %s", roff_name[np->tok],
roff_name[mdoc->last->tok]);
roff_node_delete(mdoc, np);
}
if ((np = mdoc->last->last) != NULL)
- if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
- mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
- np->line, np->pos, "%s at the end of %s",
- roff_name[np->tok],
+ if (np->tok == MDOC_Pp || np->tok == ROFF_br) {
+ mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
+ "%s at the end of %s", roff_name[np->tok],
roff_name[mdoc->last->tok]);
roff_node_delete(mdoc, np);
}
@@ -2526,13 +2470,11 @@ post_prevpar(POST_ARGS)
return;
/*
- * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
- * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
+ * Don't allow `Pp' prior to a paragraph-type
+ * block: `Pp' or non-compact `Bd' or `Bl'.
*/
- if (n->prev->tok != MDOC_Pp &&
- n->prev->tok != MDOC_Lp &&
- n->prev->tok != ROFF_br)
+ if (n->prev->tok != MDOC_Pp && n->prev->tok != ROFF_br)
return;
if (n->tok == MDOC_Bl && n->norm->Bl.comp)
return;
@@ -2541,9 +2483,8 @@ post_prevpar(POST_ARGS)
if (n->tok == MDOC_It && n->parent->norm->Bl.comp)
return;
- mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
- n->prev->line, n->prev->pos, "%s before %s",
- roff_name[n->prev->tok], roff_name[n->tok]);
+ mandoc_msg(MANDOCERR_PAR_SKIP, n->prev->line, n->prev->pos,
+ "%s before %s", roff_name[n->prev->tok], roff_name[n->tok]);
roff_node_delete(mdoc, n->prev);
}
@@ -2552,33 +2493,12 @@ post_par(POST_ARGS)
{
struct roff_node *np;
- np = mdoc->last;
- if (np->tok != ROFF_br && np->tok != ROFF_sp)
- post_prevpar(mdoc);
-
- if (np->tok == ROFF_sp) {
- if (np->child != NULL && np->child->next != NULL)
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
- np->child->next->line, np->child->next->pos,
- "sp ... %s", np->child->next->string);
- } else if (np->child != NULL)
- mandoc_vmsg(MANDOCERR_ARG_SKIP,
- mdoc->parse, np->line, np->pos, "%s %s",
- roff_name[np->tok], np->child->string);
-
- if ((np = mdoc->last->prev) == NULL) {
- np = mdoc->last->parent;
- if (np->tok != MDOC_Sh && np->tok != MDOC_Ss)
- return;
- } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp &&
- (mdoc->last->tok != ROFF_br ||
- (np->tok != ROFF_sp && np->tok != ROFF_br)))
- return;
+ post_prevpar(mdoc);
- mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
- mdoc->last->line, mdoc->last->pos, "%s after %s",
- roff_name[mdoc->last->tok], roff_name[np->tok]);
- roff_node_delete(mdoc, mdoc->last);
+ np = mdoc->last;
+ if (np->child != NULL)
+ mandoc_msg(MANDOCERR_ARG_SKIP, np->line, np->pos,
+ "%s %s", roff_name[np->tok], np->child->string);
}
static void
@@ -2591,17 +2511,15 @@ post_dd(POST_ARGS)
n->flags |= NODE_NOPRT;
if (mdoc->meta.date != NULL) {
- mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
- n->line, n->pos, "Dd");
+ mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dd");
free(mdoc->meta.date);
} else if (mdoc->flags & MDOC_PBODY)
- mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
- n->line, n->pos, "Dd");
+ mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Dd");
else if (mdoc->meta.title != NULL)
- mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ mandoc_msg(MANDOCERR_PROLOG_ORDER,
n->line, n->pos, "Dd after Dt");
else if (mdoc->meta.os != NULL)
- mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ mandoc_msg(MANDOCERR_PROLOG_ORDER,
n->line, n->pos, "Dd after Os");
if (n->child == NULL || n->child->string[0] == '\0') {
@@ -2632,16 +2550,14 @@ post_dt(POST_ARGS)
n->flags |= NODE_NOPRT;
if (mdoc->flags & MDOC_PBODY) {
- mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse,
- n->line, n->pos, "Dt");
+ mandoc_msg(MANDOCERR_DT_LATE, n->line, n->pos, "Dt");
return;
}
if (mdoc->meta.title != NULL)
- mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
- n->line, n->pos, "Dt");
+ mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dt");
else if (mdoc->meta.os != NULL)
- mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ mandoc_msg(MANDOCERR_PROLOG_ORDER,
n->line, n->pos, "Dt after Os");
free(mdoc->meta.title);
@@ -2658,8 +2574,7 @@ post_dt(POST_ARGS)
nn = n->child;
if (nn == NULL || *nn->string == '\0') {
- mandoc_msg(MANDOCERR_DT_NOTITLE,
- mdoc->parse, n->line, n->pos, "Dt");
+ mandoc_msg(MANDOCERR_DT_NOTITLE, n->line, n->pos, "Dt");
mdoc->meta.title = mandoc_strdup("UNTITLED");
} else {
mdoc->meta.title = mandoc_strdup(nn->string);
@@ -2668,9 +2583,8 @@ post_dt(POST_ARGS)
for (p = nn->string; *p != '\0'; p++)
if (islower((unsigned char)*p)) {
- mandoc_vmsg(MANDOCERR_TITLE_CASE,
- mdoc->parse, nn->line,
- nn->pos + (p - nn->string),
+ mandoc_msg(MANDOCERR_TITLE_CASE, nn->line,
+ nn->pos + (int)(p - nn->string),
"Dt %s", nn->string);
break;
}
@@ -2682,8 +2596,7 @@ post_dt(POST_ARGS)
nn = nn->next;
if (nn == NULL) {
- mandoc_vmsg(MANDOCERR_MSEC_MISSING,
- mdoc->parse, n->line, n->pos,
+ mandoc_msg(MANDOCERR_MSEC_MISSING, n->line, n->pos,
"Dt %s", mdoc->meta.title);
mdoc->meta.vol = mandoc_strdup("LOCAL");
return; /* msec and arch remain NULL. */
@@ -2695,7 +2608,7 @@ post_dt(POST_ARGS)
cp = mandoc_a2msec(nn->string);
if (cp == NULL) {
- mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
+ mandoc_msg(MANDOCERR_MSEC_BAD,
nn->line, nn->pos, "Dt ... %s", nn->string);
mdoc->meta.vol = mandoc_strdup(nn->string);
} else
@@ -2713,7 +2626,7 @@ post_dt(POST_ARGS)
/* Ignore fourth and later arguments. */
if ((nn = nn->next) != NULL)
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
nn->line, nn->pos, "Dt ... %s", nn->string);
}
@@ -2734,8 +2647,8 @@ post_bx(POST_ARGS)
!strcmp(nch->string, "Free") ? "Fx" :
!strcmp(nch->string, "DragonFly") ? "Dx" : NULL;
if (macro != NULL)
- mandoc_msg(MANDOCERR_BX, mdoc->parse,
- n->line, n->pos, macro);
+ mandoc_msg(MANDOCERR_BX,
+ n->line, n->pos, "%s", macro);
mdoc->last = nch;
nch = nch->next;
mdoc->next = ROFF_NEXT_SIBLING;
@@ -2783,11 +2696,9 @@ post_os(POST_ARGS)
n->flags |= NODE_NOPRT;
if (mdoc->meta.os != NULL)
- mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
- n->line, n->pos, "Os");
+ mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Os");
else if (mdoc->flags & MDOC_PBODY)
- mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
- n->line, n->pos, "Os");
+ mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Os");
post_delim(mdoc);
@@ -2816,8 +2727,7 @@ post_os(POST_ARGS)
#else /*!OSNAME */
if (defbuf == NULL) {
if (uname(&utsname) == -1) {
- mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
- n->line, n->pos, "Os");
+ mandoc_msg(MANDOCERR_OS_UNAME, n->line, n->pos, "Os");
defbuf = mandoc_strdup("UNKNOWN");
} else
mandoc_asprintf(&defbuf, "%s %s",
@@ -2841,8 +2751,7 @@ out:
*/
if (n->child != NULL)
- mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse,
- n->child->line, n->child->pos,
+ mandoc_msg(MANDOCERR_OS_ARG, n->child->line, n->child->pos,
"Os %s (%s)", n->child->string,
mdoc->meta.os_e == MANDOC_OS_OPENBSD ?
"OpenBSD" : "NetBSD");
@@ -2854,14 +2763,12 @@ out:
return;
if (strncmp(n->string, "$" "Mdocdate", 9)) {
if (mdoc->meta.os_e == MANDOC_OS_OPENBSD)
- mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING,
- mdoc->parse, n->line, n->pos,
- "Dd %s (OpenBSD)", n->string);
+ mandoc_msg(MANDOCERR_MDOCDATE_MISSING, n->line,
+ n->pos, "Dd %s (OpenBSD)", n->string);
} else {
if (mdoc->meta.os_e == MANDOC_OS_NETBSD)
- mandoc_vmsg(MANDOCERR_MDOCDATE,
- mdoc->parse, n->line, n->pos,
- "Dd %s (NetBSD)", n->string);
+ mandoc_msg(MANDOCERR_MDOCDATE, n->line,
+ n->pos, "Dd %s (NetBSD)", n->string);
}
}
diff --git a/usr/src/cmd/mandoc/msec.c b/usr/src/cmd/mandoc/msec.c
index 9d41511696..9a52213d95 100644
--- a/usr/src/cmd/mandoc/msec.c
+++ b/usr/src/cmd/mandoc/msec.c
@@ -1,4 +1,4 @@
-/* $Id: msec.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
+/* $Id: msec.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <stdio.h>
#include <string.h>
#include "mandoc.h"
diff --git a/usr/src/cmd/mandoc/out.c b/usr/src/cmd/mandoc/out.c
index b2b643787e..d0b0d0a2ac 100644
--- a/usr/src/cmd/mandoc/out.c
+++ b/usr/src/cmd/mandoc/out.c
@@ -1,7 +1,7 @@
-/* $Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */
+/* $Id: out.c,v 1.78 2019/03/29 21:27:06 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2014,2015,2017,2018 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,21 +20,29 @@
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mandoc_aux.h"
-#include "mandoc.h"
+#include "tbl.h"
#include "out.h"
-static void tblcalc_data(struct rofftbl *, struct roffcol *,
+struct tbl_colgroup {
+ struct tbl_colgroup *next;
+ size_t wanted;
+ int startcol;
+ int endcol;
+};
+
+static size_t tblcalc_data(struct rofftbl *, struct roffcol *,
const struct tbl_opts *, const struct tbl_dat *,
size_t);
-static void tblcalc_literal(struct rofftbl *, struct roffcol *,
+static size_t tblcalc_literal(struct rofftbl *, struct roffcol *,
const struct tbl_dat *, size_t);
-static void tblcalc_number(struct rofftbl *, struct roffcol *,
+static size_t tblcalc_number(struct rofftbl *, struct roffcol *,
const struct tbl_opts *, const struct tbl_dat *);
@@ -103,16 +111,18 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
* used for the actual width calculations.
*/
void
-tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
+tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
size_t offset, size_t rmargin)
{
struct roffsu su;
const struct tbl_opts *opts;
+ const struct tbl_span *sp;
const struct tbl_dat *dp;
struct roffcol *col;
- size_t ewidth, xwidth;
- int spans;
- int icol, maxcol, necol, nxcol, quirkcol;
+ struct tbl_colgroup *first_group, **gp, *g;
+ size_t *colwidth;
+ size_t ewidth, min1, min2, wanted, width, xwidth;
+ int done, icol, maxcol, necol, nxcol, quirkcol;
/*
* Allocate the master column specifiers. These will hold the
@@ -120,33 +130,34 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
* must be freed and nullified by the caller.
*/
- assert(NULL == tbl->cols);
- tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
+ assert(tbl->cols == NULL);
+ tbl->cols = mandoc_calloc((size_t)sp_first->opts->cols,
sizeof(struct roffcol));
- opts = sp->opts;
+ opts = sp_first->opts;
- for (maxcol = -1; sp; sp = sp->next) {
- if (TBL_SPAN_DATA != sp->pos)
+ maxcol = -1;
+ first_group = NULL;
+ for (sp = sp_first; sp != NULL; sp = sp->next) {
+ if (sp->pos != TBL_SPAN_DATA)
continue;
- spans = 1;
+
/*
* Account for the data cells in the layout, matching it
* to data cells in the data section.
*/
- for (dp = sp->first; dp; dp = dp->next) {
- /* Do not used spanned cells in the calculation. */
- if (0 < --spans)
- continue;
- spans = dp->spans;
- if (1 < spans)
- continue;
+
+ gp = &first_group;
+ for (dp = sp->first; dp != NULL; dp = dp->next) {
icol = dp->layout->col;
- while (maxcol < icol)
+ while (maxcol < icol + dp->hspans)
tbl->cols[++maxcol].spacing = SIZE_MAX;
col = tbl->cols + icol;
col->flags |= dp->layout->flags;
if (dp->layout->flags & TBL_CELL_WIGN)
continue;
+
+ /* Handle explicit width specifications. */
+
if (dp->layout->wstr != NULL &&
dp->layout->width == 0 &&
a2roffsu(dp->layout->wstr, &su, SCALE_EN)
@@ -159,15 +170,165 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
(col->spacing == SIZE_MAX ||
col->spacing < dp->layout->spacing))
col->spacing = dp->layout->spacing;
- tblcalc_data(tbl, col, opts, dp,
+
+ /*
+ * Calculate an automatic width.
+ * Except for spanning cells, apply it.
+ */
+
+ width = tblcalc_data(tbl,
+ dp->hspans == 0 ? col : NULL,
+ opts, dp,
dp->block == 0 ? 0 :
dp->layout->width ? dp->layout->width :
rmargin ? (rmargin + sp->opts->cols / 2)
/ (sp->opts->cols + 1) : 0);
+ if (dp->hspans == 0)
+ continue;
+
+ /*
+ * Build an ordered, singly linked list
+ * of all groups of columns joined by spans,
+ * recording the minimum width for each group.
+ */
+
+ while (*gp != NULL && ((*gp)->startcol < icol ||
+ (*gp)->endcol < icol + dp->hspans))
+ gp = &(*gp)->next;
+ if (*gp == NULL || (*gp)->startcol > icol ||
+ (*gp)->endcol > icol + dp->hspans) {
+ g = mandoc_malloc(sizeof(*g));
+ g->next = *gp;
+ g->wanted = width;
+ g->startcol = icol;
+ g->endcol = icol + dp->hspans;
+ *gp = g;
+ } else if ((*gp)->wanted < width)
+ (*gp)->wanted = width;
+ }
+ }
+
+ /*
+ * Column spacings are needed for span width calculations,
+ * so set the default values now.
+ */
+
+ for (icol = 0; icol <= maxcol; icol++)
+ if (tbl->cols[icol].spacing == SIZE_MAX || icol == maxcol)
+ tbl->cols[icol].spacing = 3;
+
+ /*
+ * Replace the minimum widths with the missing widths,
+ * and dismiss groups that are already wide enough.
+ */
+
+ gp = &first_group;
+ while ((g = *gp) != NULL) {
+ done = 0;
+ for (icol = g->startcol; icol <= g->endcol; icol++) {
+ width = tbl->cols[icol].width;
+ if (icol < g->endcol)
+ width += tbl->cols[icol].spacing;
+ if (g->wanted <= width) {
+ done = 1;
+ break;
+ } else
+ (*gp)->wanted -= width;
+ }
+ if (done) {
+ *gp = g->next;
+ free(g);
+ } else
+ gp = &(*gp)->next;
+ }
+
+ colwidth = mandoc_reallocarray(NULL, maxcol + 1, sizeof(*colwidth));
+ while (first_group != NULL) {
+
+ /*
+ * Rebuild the array of the widths of all columns
+ * participating in spans that require expansion.
+ */
+
+ for (icol = 0; icol <= maxcol; icol++)
+ colwidth[icol] = SIZE_MAX;
+ for (g = first_group; g != NULL; g = g->next)
+ for (icol = g->startcol; icol <= g->endcol; icol++)
+ colwidth[icol] = tbl->cols[icol].width;
+
+ /*
+ * Find the smallest and second smallest column width
+ * among the columns which may need expamsion.
+ */
+
+ min1 = min2 = SIZE_MAX;
+ for (icol = 0; icol <= maxcol; icol++) {
+ if (min1 > colwidth[icol]) {
+ min2 = min1;
+ min1 = colwidth[icol];
+ } else if (min1 < colwidth[icol] &&
+ min2 > colwidth[icol])
+ min2 = colwidth[icol];
+ }
+
+ /*
+ * Find the minimum wanted width
+ * for any one of the narrowest columns,
+ * and mark the columns wanting that width.
+ */
+
+ wanted = min2;
+ for (g = first_group; g != NULL; g = g->next) {
+ necol = 0;
+ for (icol = g->startcol; icol <= g->endcol; icol++)
+ if (tbl->cols[icol].width == min1)
+ necol++;
+ if (necol == 0)
+ continue;
+ width = min1 + (g->wanted - 1) / necol + 1;
+ if (width > min2)
+ width = min2;
+ if (wanted > width)
+ wanted = width;
+ for (icol = g->startcol; icol <= g->endcol; icol++)
+ if (colwidth[icol] == min1 ||
+ (colwidth[icol] < min2 &&
+ colwidth[icol] > width))
+ colwidth[icol] = width;
+ }
+
+ /* Record the effect of the widening on the group list. */
+
+ gp = &first_group;
+ while ((g = *gp) != NULL) {
+ done = 0;
+ for (icol = g->startcol; icol <= g->endcol; icol++) {
+ if (colwidth[icol] != wanted ||
+ tbl->cols[icol].width == wanted)
+ continue;
+ if (g->wanted <= wanted - min1) {
+ done = 1;
+ break;
+ }
+ g->wanted -= wanted - min1;
+ }
+ if (done) {
+ *gp = g->next;
+ free(g);
+ } else
+ gp = &(*gp)->next;
}
+
+ /* Record the effect of the widening on the columns. */
+
+ for (icol = 0; icol <= maxcol; icol++)
+ if (colwidth[icol] == wanted)
+ tbl->cols[icol].width = wanted;
}
+ free(colwidth);
/*
+ * Align numbers with text.
* Count columns to equalize and columns to maximize.
* Find maximum width of the columns to equalize.
* Find total width of the columns *not* to maximize.
@@ -177,8 +338,10 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
ewidth = xwidth = 0;
for (icol = 0; icol <= maxcol; icol++) {
col = tbl->cols + icol;
- if (col->spacing == SIZE_MAX || icol == maxcol)
- col->spacing = 3;
+ if (col->width > col->nwidth)
+ col->decimal += (col->width - col->nwidth) / 2;
+ else
+ col->width = col->nwidth;
if (col->flags & TBL_CELL_EQUAL) {
necol++;
if (ewidth < col->width)
@@ -251,7 +414,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
}
}
-static void
+static size_t
tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw)
{
@@ -263,26 +426,24 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
case TBL_CELL_HORIZ:
case TBL_CELL_DHORIZ:
sz = (*tbl->len)(1, tbl->arg);
- if (col->width < sz)
+ if (col != NULL && col->width < sz)
col->width = sz;
- break;
+ return sz;
case TBL_CELL_LONG:
case TBL_CELL_CENTRE:
case TBL_CELL_LEFT:
case TBL_CELL_RIGHT:
- tblcalc_literal(tbl, col, dp, mw);
- break;
+ return tblcalc_literal(tbl, col, dp, mw);
case TBL_CELL_NUMBER:
- tblcalc_number(tbl, col, opts, dp);
- break;
+ return tblcalc_number(tbl, col, opts, dp);
case TBL_CELL_DOWN:
- break;
+ return 0;
default:
abort();
}
}
-static void
+static size_t
tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_dat *dp, size_t mw)
{
@@ -291,11 +452,12 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
char *end; /* End of the current line. */
size_t lsz; /* Length of the current line. */
size_t wsz; /* Length of the current word. */
+ size_t msz; /* Length of the longest line. */
if (dp->string == NULL || *dp->string == '\0')
- return;
+ return 0;
str = mw ? mandoc_strdup(dp->string) : dp->string;
- lsz = 0;
+ msz = lsz = 0;
for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
end = mw ? strchr(beg, ' ') : NULL;
if (end != NULL) {
@@ -308,62 +470,84 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
lsz += 1 + wsz;
else
lsz = wsz;
- if (col->width < lsz)
- col->width = lsz;
+ if (msz < lsz)
+ msz = lsz;
}
if (mw)
free((void *)str);
+ if (col != NULL && col->width < msz)
+ col->width = msz;
+ return msz;
}
-static void
+static size_t
tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_opts *opts, const struct tbl_dat *dp)
{
- int i;
- size_t sz, psz, ssz, d;
- const char *str;
- char *cp;
+ const char *cp, *lastdigit, *lastpoint;
+ size_t intsz, totsz;
char buf[2];
+ if (dp->string == NULL || *dp->string == '\0')
+ return 0;
+
+ totsz = (*tbl->slen)(dp->string, tbl->arg);
+ if (col == NULL)
+ return totsz;
+
/*
- * First calculate number width and decimal place (last + 1 for
- * non-decimal numbers). If the stored decimal is subsequent to
- * ours, make our size longer by that difference
- * (right-"shifting"); similarly, if ours is subsequent the
- * stored, then extend the stored size by the difference.
- * Finally, re-assign the stored values.
+ * Find the last digit and
+ * the last decimal point that is adjacent to a digit.
+ * The alignment indicator "\&" overrides everything.
*/
- str = dp->string ? dp->string : "";
- sz = (*tbl->slen)(str, tbl->arg);
+ lastdigit = lastpoint = NULL;
+ for (cp = dp->string; cp[0] != '\0'; cp++) {
+ if (cp[0] == '\\' && cp[1] == '&') {
+ lastdigit = lastpoint = cp;
+ break;
+ } else if (cp[0] == opts->decimal &&
+ (isdigit((unsigned char)cp[1]) ||
+ (cp > dp->string && isdigit((unsigned char)cp[-1]))))
+ lastpoint = cp;
+ else if (isdigit((unsigned char)cp[0]))
+ lastdigit = cp;
+ }
- /* FIXME: TBL_DATA_HORIZ et al.? */
+ /* Not a number, treat as a literal string. */
- buf[0] = opts->decimal;
- buf[1] = '\0';
+ if (lastdigit == NULL) {
+ if (col != NULL && col->width < totsz)
+ col->width = totsz;
+ return totsz;
+ }
- psz = (*tbl->slen)(buf, tbl->arg);
+ /* Measure the width of the integer part. */
- if (NULL != (cp = strrchr(str, opts->decimal))) {
- buf[1] = '\0';
- for (ssz = 0, i = 0; cp != &str[i]; i++) {
- buf[0] = str[i];
- ssz += (*tbl->slen)(buf, tbl->arg);
- }
- d = ssz + psz;
- } else
- d = sz + psz;
+ if (lastpoint == NULL)
+ lastpoint = lastdigit + 1;
+ intsz = 0;
+ buf[1] = '\0';
+ for (cp = dp->string; cp < lastpoint; cp++) {
+ buf[0] = cp[0];
+ intsz += (*tbl->slen)(buf, tbl->arg);
+ }
- /* Adjust the settings for this column. */
+ /*
+ * If this number has more integer digits than all numbers
+ * seen on earlier lines, shift them all to the right.
+ * If it has fewer, shift this number to the right.
+ */
- if (col->decimal > d) {
- sz += col->decimal - d;
- d = col->decimal;
+ if (intsz > col->decimal) {
+ col->nwidth += intsz - col->decimal;
+ col->decimal = intsz;
} else
- col->width += d - col->decimal;
+ totsz += col->decimal - intsz;
+
+ /* Update the maximum total width seen so far. */
- if (sz > col->width)
- col->width = sz;
- if (d > col->decimal)
- col->decimal = d;
+ if (totsz > col->nwidth)
+ col->nwidth = totsz;
+ return totsz;
}
diff --git a/usr/src/cmd/mandoc/out.h b/usr/src/cmd/mandoc/out.h
index 9f0a541d5d..dec6a8f873 100644
--- a/usr/src/cmd/mandoc/out.h
+++ b/usr/src/cmd/mandoc/out.h
@@ -1,7 +1,7 @@
-/* $Id: out.h,v 1.32 2018/06/25 16:54:59 schwarze Exp $ */
+/* $Id: out.h,v 1.33 2018/08/18 20:18:14 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2017, 2018 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,6 +32,7 @@ enum roffscale {
struct roffcol {
size_t width; /* width of cell */
+ size_t nwidth; /* max. width of number in cell */
size_t decimal; /* decimal position in cell */
size_t spacing; /* spacing after the column */
int flags; /* layout flags, see tbl_cell */
diff --git a/usr/src/cmd/mandoc/preconv.c b/usr/src/cmd/mandoc/preconv.c
index 08f8df86a6..9ed627d446 100644
--- a/usr/src/cmd/mandoc/preconv.c
+++ b/usr/src/cmd/mandoc/preconv.c
@@ -1,4 +1,4 @@
-/* $Id: preconv.c,v 1.16 2017/02/18 13:43:52 schwarze Exp $ */
+/* $Id: preconv.c,v 1.17 2018/12/13 11:55:47 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -22,7 +22,10 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
+
#include "mandoc.h"
+#include "roff.h"
+#include "mandoc_parse.h"
#include "libmandoc.h"
int
diff --git a/usr/src/cmd/mandoc/read.c b/usr/src/cmd/mandoc/read.c
index 0a583445f2..0f25ab967c 100644
--- a/usr/src/cmd/mandoc/read.c
+++ b/usr/src/cmd/mandoc/read.c
@@ -1,7 +1,7 @@
-/* $Id: read.c,v 1.196 2018/07/28 18:34:15 schwarze Exp $ */
+/* $Id: read.c,v 1.213 2019/06/03 19:58:02 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2019 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
@@ -38,21 +38,19 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
+#include "mandoc_parse.h"
#include "libmandoc.h"
+#include "roff_int.h"
#define REPARSE_LIMIT 1000
struct mparse {
struct roff *roff; /* roff parser (!NULL) */
struct roff_man *man; /* man parser */
- char *sodest; /* filename pointed to by .so */
- const char *file; /* filename of current input file */
struct buf *primary; /* buffer currently being parsed */
- struct buf *secondary; /* preprocessed copy of input */
+ struct buf *secondary; /* copy of top level input */
+ struct buf *loop; /* open .while request line */
const char *os_s; /* default operating system */
- mandocmsg mmsg; /* warning/error message handler */
- enum mandoclevel file_status; /* status of current parse */
- enum mandocerr mmin; /* ignore messages below this */
int options; /* parser options */
int gzip; /* current input file is gzipped */
int filenc; /* encoding of the current file */
@@ -61,220 +59,11 @@ struct mparse {
};
static void choose_parser(struct mparse *);
+static void free_buf_list(struct buf *);
static void resize_buf(struct buf *, size_t);
static int mparse_buf_r(struct mparse *, struct buf, size_t, int);
-static int read_whole_file(struct mparse *, const char *, int,
- struct buf *, int *);
+static int read_whole_file(struct mparse *, int, struct buf *, int *);
static void mparse_end(struct mparse *);
-static void mparse_parse_buffer(struct mparse *, struct buf,
- const char *);
-
-static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
- MANDOCERR_OK,
- MANDOCERR_OK,
- MANDOCERR_WARNING,
- MANDOCERR_ERROR,
- MANDOCERR_UNSUPP,
- MANDOCERR_MAX,
- MANDOCERR_MAX
-};
-
-static const char * const mandocerrs[MANDOCERR_MAX] = {
- "ok",
-
- "base system convention",
-
- "Mdocdate found",
- "Mdocdate missing",
- "unknown architecture",
- "operating system explicitly specified",
- "RCS id missing",
- "referenced manual not found",
-
- "generic style suggestion",
-
- "legacy man(7) date format",
- "normalizing date format to",
- "lower case character in document title",
- "duplicate RCS id",
- "possible typo in section name",
- "unterminated quoted argument",
- "useless macro",
- "consider using OS macro",
- "errnos out of order",
- "duplicate errno",
- "trailing delimiter",
- "no blank before trailing delimiter",
- "fill mode already enabled, skipping",
- "fill mode already disabled, skipping",
- "verbatim \"--\", maybe consider using \\(em",
- "function name without markup",
- "whitespace at end of input line",
- "bad comment style",
-
- "generic warning",
-
- /* related to the prologue */
- "missing manual title, using UNTITLED",
- "missing manual title, using \"\"",
- "missing manual section, using \"\"",
- "unknown manual section",
- "missing date, using today's date",
- "cannot parse date, using it verbatim",
- "date in the future, using it anyway",
- "missing Os macro, using \"\"",
- "late prologue macro",
- "prologue macros out of order",
-
- /* related to document structure */
- ".so is fragile, better use ln(1)",
- "no document body",
- "content before first section header",
- "first section is not \"NAME\"",
- "NAME section without Nm before Nd",
- "NAME section without description",
- "description not at the end of NAME",
- "bad NAME section content",
- "missing comma before name",
- "missing description line, using \"\"",
- "description line outside NAME section",
- "sections out of conventional order",
- "duplicate section title",
- "unexpected section",
- "cross reference to self",
- "unusual Xr order",
- "unusual Xr punctuation",
- "AUTHORS section without An macro",
-
- /* related to macros and nesting */
- "obsolete macro",
- "macro neither callable nor escaped",
- "skipping paragraph macro",
- "moving paragraph macro out of list",
- "skipping no-space macro",
- "blocks badly nested",
- "nested displays are not portable",
- "moving content out of list",
- "first macro on line",
- "line scope broken",
- "skipping blank line in line scope",
-
- /* related to missing macro arguments */
- "skipping empty request",
- "conditional request controls empty scope",
- "skipping empty macro",
- "empty block",
- "empty argument, using 0n",
- "missing display type, using -ragged",
- "list type is not the first argument",
- "missing -width in -tag list, using 6n",
- "missing utility name, using \"\"",
- "missing function name, using \"\"",
- "empty head in list item",
- "empty list item",
- "missing argument, using next line",
- "missing font type, using \\fR",
- "unknown font type, using \\fR",
- "nothing follows prefix",
- "empty reference block",
- "missing section argument",
- "missing -std argument, adding it",
- "missing option string, using \"\"",
- "missing resource identifier, using \"\"",
- "missing eqn box, using \"\"",
-
- /* related to bad macro arguments */
- "duplicate argument",
- "skipping duplicate argument",
- "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",
- "unknown library 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",
- "tab in filled text",
- "new sentence, new line",
- "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 tables */
- "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,
- "duplicate prologue macro",
- "skipping late title macro",
- "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",
- "NOT IMPLEMENTED: Bd -file",
- "skipping display without arguments",
- "missing list type, using -item",
- "argument is not numeric, using 1",
- "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",
-
- "unsupported feature",
- "input too large",
- "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] = {
- "SUCCESS",
- "STYLE",
- "WARNING",
- "ERROR",
- "UNSUPP",
- "BADARG",
- "SYSERR"
-};
static void
@@ -286,6 +75,19 @@ resize_buf(struct buf *buf, size_t initial)
}
static void
+free_buf_list(struct buf *buf)
+{
+ struct buf *tmp;
+
+ while (buf != NULL) {
+ tmp = buf;
+ buf = tmp->next;
+ free(tmp->buf);
+ free(tmp);
+ }
+}
+
+static void
choose_parser(struct mparse *curp)
{
char *cp, *ep;
@@ -320,15 +122,15 @@ choose_parser(struct mparse *curp)
}
if (format == MPARSE_MDOC) {
- curp->man->macroset = MACROSET_MDOC;
+ curp->man->meta.macroset = MACROSET_MDOC;
if (curp->man->mdocmac == NULL)
curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
} else {
- curp->man->macroset = MACROSET_MAN;
+ curp->man->meta.macroset = MACROSET_MAN;
if (curp->man->manmac == NULL)
curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
}
- curp->man->first->tok = TOKEN_NONE;
+ curp->man->meta.first->tok = TOKEN_NONE;
}
/*
@@ -342,24 +144,26 @@ static int
mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
struct buf ln;
- const char *save_file;
+ struct buf *firstln, *lastln, *thisln, *loop;
char *cp;
size_t pos; /* byte number in the ln buffer */
- enum rofferr rr;
+ int line_result, result;
int of;
int lnn; /* line number in the real file */
int fd;
+ int inloop; /* Saw .while on this level. */
unsigned char c;
- memset(&ln, 0, sizeof(ln));
-
+ ln.sz = 256;
+ ln.buf = mandoc_malloc(ln.sz);
+ ln.next = NULL;
+ firstln = lastln = loop = NULL;
lnn = curp->line;
pos = 0;
+ inloop = 0;
+ result = ROFF_CONT;
- while (i < blk.sz) {
- if (0 == pos && '\0' == blk.buf[i])
- break;
-
+ while (i < blk.sz && (blk.buf[i] != '\0' || pos != 0)) {
if (start) {
curp->line = lnn;
curp->reparse_count = 0;
@@ -389,10 +193,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
/*
* Make sure we have space for the worst
- * case of 11 bytes: "\\[u10ffff]\0"
+ * case of 12 bytes: "\\[u10ffff]\n\0"
*/
- if (pos + 11 > ln.sz)
+ if (pos + 12 > ln.sz)
resize_buf(&ln, 256);
/*
@@ -403,7 +207,7 @@ 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_CHAR_BAD, curp,
+ mandoc_msg(MANDOCERR_CHAR_BAD,
curp->line, pos, "0x%x", c);
ln.buf[pos++] = '?';
i++;
@@ -416,10 +220,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
*/
if (c == 0x7f || (c < 0x20 && c != 0x09)) {
- mandoc_vmsg(c == 0x00 || c == 0x04 ||
+ mandoc_msg(c == 0x00 || c == 0x04 ||
c > 0x0a ? MANDOCERR_CHAR_BAD :
MANDOCERR_CHAR_UNSUPP,
- curp, curp->line, pos, "0x%x", c);
+ curp->line, pos, "0x%x", c);
i++;
if (c != '\r')
ln.buf[pos++] = '?';
@@ -428,13 +232,32 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
ln.buf[pos++] = blk.buf[i++];
}
+ ln.buf[pos] = '\0';
- if (pos + 1 >= ln.sz)
- resize_buf(&ln, 256);
+ /*
+ * Maintain a lookaside buffer of all lines.
+ * parsed from this input source.
+ */
+
+ thisln = mandoc_malloc(sizeof(*thisln));
+ thisln->buf = mandoc_strdup(ln.buf);
+ thisln->sz = strlen(ln.buf) + 1;
+ thisln->next = NULL;
+ if (firstln == NULL) {
+ firstln = lastln = thisln;
+ if (curp->secondary == NULL)
+ curp->secondary = firstln;
+ } else {
+ lastln->next = thisln;
+ lastln = thisln;
+ }
- if (i == blk.sz || blk.buf[i] == '\0')
+ /* XXX Ugly hack to mark the end of the input. */
+
+ if (i == blk.sz || blk.buf[i] == '\0') {
ln.buf[pos++] = '\n';
- ln.buf[pos] = '\0';
+ ln.buf[pos] = '\0';
+ }
/*
* A significant amount of complexity is contained by
@@ -446,74 +269,112 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
*/
of = 0;
+rerun:
+ line_result = roff_parseln(curp->roff, curp->line, &ln, &of);
- /*
- * Maintain a lookaside buffer of all parsed lines. We
- * only do this if mparse_keep() has been invoked (the
- * buffer may be accessed with mparse_getkeep()).
- */
+ /* Process options. */
+
+ if (line_result & ROFF_APPEND)
+ assert(line_result == (ROFF_IGN | ROFF_APPEND));
- if (curp->secondary) {
- curp->secondary->buf = mandoc_realloc(
- curp->secondary->buf,
- curp->secondary->sz + pos + 2);
- memcpy(curp->secondary->buf +
- curp->secondary->sz,
- ln.buf, pos);
- curp->secondary->sz += pos;
- curp->secondary->buf
- [curp->secondary->sz] = '\n';
- curp->secondary->sz++;
- curp->secondary->buf
- [curp->secondary->sz] = '\0';
+ if (line_result & ROFF_USERCALL)
+ assert((line_result & ROFF_MASK) == ROFF_REPARSE);
+
+ if (line_result & ROFF_USERRET) {
+ assert(line_result == (ROFF_IGN | ROFF_USERRET));
+ if (start == 0) {
+ /* Return from the current macro. */
+ result = ROFF_USERRET;
+ goto out;
+ }
}
-rerun:
- rr = roff_parseln(curp->roff, curp->line, &ln, &of);
- switch (rr) {
- case ROFF_REPARSE:
- if (++curp->reparse_count > REPARSE_LIMIT)
- mandoc_msg(MANDOCERR_ROFFLOOP, curp,
+ switch (line_result & ROFF_LOOPMASK) {
+ case ROFF_IGN:
+ break;
+ case ROFF_WHILE:
+ if (curp->loop != NULL) {
+ if (loop == curp->loop)
+ break;
+ mandoc_msg(MANDOCERR_WHILE_NEST,
curp->line, pos, NULL);
- else if (mparse_buf_r(curp, ln, of, 0) == 1 ||
- start == 1) {
- pos = 0;
- continue;
}
- free(ln.buf);
- return 0;
- case ROFF_APPEND:
- pos = strlen(ln.buf);
- continue;
+ curp->loop = thisln;
+ loop = NULL;
+ inloop = 1;
+ break;
+ case ROFF_LOOPCONT:
+ case ROFF_LOOPEXIT:
+ if (curp->loop == NULL) {
+ mandoc_msg(MANDOCERR_WHILE_FAIL,
+ curp->line, pos, NULL);
+ break;
+ }
+ if (inloop == 0) {
+ mandoc_msg(MANDOCERR_WHILE_INTO,
+ curp->line, pos, NULL);
+ curp->loop = loop = NULL;
+ break;
+ }
+ if (line_result & ROFF_LOOPCONT)
+ loop = curp->loop;
+ else {
+ curp->loop = loop = NULL;
+ inloop = 0;
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Process the main instruction from the roff parser. */
+
+ switch (line_result & ROFF_MASK) {
+ case ROFF_IGN:
+ break;
+ case ROFF_CONT:
+ if (curp->man->meta.macroset == MACROSET_NONE)
+ choose_parser(curp);
+ if ((curp->man->meta.macroset == MACROSET_MDOC ?
+ mdoc_parseln(curp->man, curp->line, ln.buf, of) :
+ man_parseln(curp->man, curp->line, ln.buf, of)
+ ) == 2)
+ goto out;
+ break;
case ROFF_RERUN:
goto rerun;
- case ROFF_IGN:
- pos = 0;
- continue;
+ case ROFF_REPARSE:
+ if (++curp->reparse_count > REPARSE_LIMIT) {
+ /* Abort and return to the top level. */
+ result = ROFF_IGN;
+ mandoc_msg(MANDOCERR_ROFFLOOP,
+ curp->line, pos, NULL);
+ goto out;
+ }
+ result = mparse_buf_r(curp, ln, of, 0);
+ if (line_result & ROFF_USERCALL) {
+ roff_userret(curp->roff);
+ /* Continue normally. */
+ if (result & ROFF_USERRET)
+ result = ROFF_CONT;
+ }
+ if (start == 0 && result != ROFF_CONT)
+ goto out;
+ break;
case ROFF_SO:
if ( ! (curp->options & MPARSE_SO) &&
(i >= blk.sz || blk.buf[i] == '\0')) {
- curp->sodest = mandoc_strdup(ln.buf + of);
- free(ln.buf);
- return 1;
+ curp->man->meta.sodest =
+ mandoc_strdup(ln.buf + of);
+ goto out;
}
- /*
- * We remove `so' clauses from our lookaside
- * buffer because we're going to descend into
- * the file recursively.
- */
- if (curp->secondary)
- curp->secondary->sz -= pos + 1;
- save_file = curp->file;
if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
mparse_readfd(curp, fd, ln.buf + of);
close(fd);
- curp->file = save_file;
} else {
- curp->file = save_file;
- mandoc_vmsg(MANDOCERR_SO_FAIL,
- curp, curp->line, pos,
- ".so %s", ln.buf + of);
+ mandoc_msg(MANDOCERR_SO_FAIL,
+ curp->line, of, ".so %s: %s",
+ ln.buf + of, strerror(errno));
ln.sz = mandoc_asprintf(&cp,
".sp\nSee the file %s.\n.sp",
ln.buf + of);
@@ -522,37 +383,44 @@ rerun:
of = 0;
mparse_buf_r(curp, ln, of, 0);
}
- pos = 0;
- continue;
- default:
break;
+ default:
+ abort();
}
- if (curp->man->macroset == MACROSET_NONE)
- choose_parser(curp);
-
- if ((curp->man->macroset == MACROSET_MDOC ?
- mdoc_parseln(curp->man, curp->line, ln.buf, of) :
- man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
- break;
-
- /* Temporary buffers typically are not full. */
-
- if (0 == start && '\0' == blk.buf[i])
- break;
-
/* Start the next input line. */
- pos = 0;
- }
+ if (loop != NULL &&
+ (line_result & ROFF_LOOPMASK) == ROFF_IGN)
+ loop = loop->next;
+
+ if (loop != NULL) {
+ if ((line_result & ROFF_APPEND) == 0)
+ *ln.buf = '\0';
+ if (ln.sz < loop->sz)
+ resize_buf(&ln, loop->sz);
+ (void)strlcat(ln.buf, loop->buf, ln.sz);
+ of = 0;
+ goto rerun;
+ }
+ pos = (line_result & ROFF_APPEND) ? strlen(ln.buf) : 0;
+ }
+out:
+ if (inloop) {
+ if (result != ROFF_USERRET)
+ mandoc_msg(MANDOCERR_WHILE_OUTOF,
+ curp->line, pos, NULL);
+ curp->loop = NULL;
+ }
free(ln.buf);
- return 1;
+ if (firstln != curp->secondary)
+ free_buf_list(firstln);
+ return result;
}
static int
-read_whole_file(struct mparse *curp, const char *file, int fd,
- struct buf *fb, int *with_mmap)
+read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap)
{
struct stat st;
gzFile gz;
@@ -561,7 +429,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
int gzerrnum, retval;
if (fstat(fd, &st) == -1) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ mandoc_msg(MANDOCERR_FILE, 0, 0,
"fstat: %s", strerror(errno));
return 0;
}
@@ -575,7 +443,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
if (st.st_size > 0x7fffffff) {
- mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
return 0;
}
*with_mmap = 1;
@@ -594,12 +462,12 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
* which this function must not do.
*/
if ((fd = dup(fd)) == -1) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ mandoc_msg(MANDOCERR_FILE, 0, 0,
"dup: %s", strerror(errno));
return 0;
}
if ((gz = gzdopen(fd, "rb")) == NULL) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ mandoc_msg(MANDOCERR_FILE, 0, 0,
"gzdopen: %s", strerror(errno));
close(fd);
return 0;
@@ -620,8 +488,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
- mandoc_msg(MANDOCERR_TOOLARGE, curp,
- 0, 0, NULL);
+ mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
@@ -637,7 +504,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
if (ssz == -1) {
if (curp->gzip)
(void)gzerror(gz, &gzerrnum);
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "read: %s",
+ mandoc_msg(MANDOCERR_FILE, 0, 0, "read: %s",
curp->gzip && gzerrnum != Z_ERRNO ?
zError(gzerrnum) : strerror(errno));
break;
@@ -646,7 +513,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK)
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0, "gzclose: %s",
+ mandoc_msg(MANDOCERR_FILE, 0, 0, "gzclose: %s",
gzerrnum == Z_ERRNO ? strerror(errno) :
zError(gzerrnum));
if (retval == 0) {
@@ -659,35 +526,51 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
static void
mparse_end(struct mparse *curp)
{
- if (curp->man->macroset == MACROSET_NONE)
- curp->man->macroset = MACROSET_MAN;
- if (curp->man->macroset == MACROSET_MDOC)
+ if (curp->man->meta.macroset == MACROSET_NONE)
+ curp->man->meta.macroset = MACROSET_MAN;
+ if (curp->man->meta.macroset == MACROSET_MDOC)
mdoc_endparse(curp->man);
else
man_endparse(curp->man);
roff_endparse(curp->roff);
}
-static void
-mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
+/*
+ * Read the whole file into memory and call the parsers.
+ * Called recursively when an .so request is encountered.
+ */
+void
+mparse_readfd(struct mparse *curp, int fd, const char *filename)
{
- struct buf *svprimary;
- const char *svfile;
- size_t offset;
static int recursion_depth;
- if (64 < recursion_depth) {
- mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
+ struct buf blk;
+ struct buf *save_primary;
+ const char *save_filename;
+ size_t offset;
+ int save_filenc, save_lineno;
+ int with_mmap;
+
+ if (recursion_depth > 64) {
+ mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL);
return;
}
+ if (read_whole_file(curp, fd, &blk, &with_mmap) == 0)
+ return;
+
+ /*
+ * Save some properties of the parent file.
+ */
+
+ save_primary = curp->primary;
+ save_filenc = curp->filenc;
+ save_lineno = curp->line;
+ save_filename = mandoc_msg_getinfilename();
- /* Line number is per-file. */
- svfile = curp->file;
- curp->file = file;
- svprimary = curp->primary;
curp->primary = &blk;
+ curp->filenc = curp->options & (MPARSE_UTF8 | MPARSE_LATIN1);
curp->line = 1;
- recursion_depth++;
+ mandoc_msg_setinfilename(filename);
/* Skip an UTF-8 byte order mark. */
if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
@@ -699,60 +582,33 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
} else
offset = 0;
+ recursion_depth++;
mparse_buf_r(curp, blk, offset, 1);
-
if (--recursion_depth == 0)
mparse_end(curp);
- curp->primary = svprimary;
- curp->file = svfile;
-}
-
-enum mandoclevel
-mparse_readmem(struct mparse *curp, void *buf, size_t len,
- const char *file)
-{
- struct buf blk;
-
- blk.buf = buf;
- blk.sz = len;
+ /*
+ * Clean up and restore saved parent properties.
+ */
- mparse_parse_buffer(curp, blk, file);
- return curp->file_status;
-}
+ if (with_mmap)
+ munmap(blk.buf, blk.sz);
+ else
+ free(blk.buf);
-/*
- * Read the whole file into memory and call the parsers.
- * Called recursively when an .so request is encountered.
- */
-enum mandoclevel
-mparse_readfd(struct mparse *curp, int fd, const char *file)
-{
- struct buf blk;
- int with_mmap;
- int save_filenc;
-
- if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
- save_filenc = curp->filenc;
- curp->filenc = curp->options &
- (MPARSE_UTF8 | MPARSE_LATIN1);
- mparse_parse_buffer(curp, blk, file);
- curp->filenc = save_filenc;
- if (with_mmap)
- munmap(blk.buf, blk.sz);
- else
- free(blk.buf);
- }
- return curp->file_status;
+ curp->primary = save_primary;
+ curp->filenc = save_filenc;
+ curp->line = save_lineno;
+ if (save_filename != NULL)
+ mandoc_msg_setinfilename(save_filename);
}
int
mparse_open(struct mparse *curp, const char *file)
{
char *cp;
- int fd;
+ int fd, save_errno;
- curp->file = file;
cp = strrchr(file, '.');
curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
@@ -767,9 +623,11 @@ mparse_open(struct mparse *curp, const char *file)
*/
if ( ! curp->gzip) {
+ save_errno = errno;
mandoc_asprintf(&cp, "%s.gz", file);
fd = open(cp, O_RDONLY);
free(cp);
+ errno = save_errno;
if (fd != -1) {
curp->gzip = 1;
return fd;
@@ -778,36 +636,32 @@ mparse_open(struct mparse *curp, const char *file)
/* Neither worked, give up. */
- mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
return -1;
}
struct mparse *
-mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg,
- enum mandoc_os os_e, const char *os_s)
+mparse_alloc(int options, enum mandoc_os os_e, const char *os_s)
{
struct mparse *curp;
curp = mandoc_calloc(1, sizeof(struct mparse));
curp->options = options;
- curp->mmin = mmin;
- curp->mmsg = mmsg;
curp->os_s = os_s;
- curp->roff = roff_alloc(curp, options);
- curp->man = roff_man_alloc(curp->roff, curp, curp->os_s,
+ curp->roff = roff_alloc(options);
+ curp->man = roff_man_alloc(curp->roff, curp->os_s,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MDOC) {
- curp->man->macroset = MACROSET_MDOC;
+ curp->man->meta.macroset = MACROSET_MDOC;
if (curp->man->mdocmac == NULL)
curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
} else if (curp->options & MPARSE_MAN) {
- curp->man->macroset = MACROSET_MAN;
+ curp->man->meta.macroset = MACROSET_MAN;
if (curp->man->manmac == NULL)
curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
}
- curp->man->first->tok = TOKEN_NONE;
+ curp->man->meta.first->tok = TOKEN_NONE;
curp->man->meta.os_e = os_e;
return curp;
}
@@ -817,112 +671,40 @@ mparse_reset(struct mparse *curp)
{
roff_reset(curp->roff);
roff_man_reset(curp->man);
-
- free(curp->sodest);
- curp->sodest = NULL;
-
- if (curp->secondary)
- curp->secondary->sz = 0;
-
- curp->file_status = MANDOCLEVEL_OK;
+ free_buf_list(curp->secondary);
+ curp->secondary = NULL;
curp->gzip = 0;
}
void
mparse_free(struct mparse *curp)
{
-
roffhash_free(curp->man->mdocmac);
roffhash_free(curp->man->manmac);
roff_man_free(curp->man);
roff_free(curp->roff);
- if (curp->secondary)
- free(curp->secondary->buf);
-
- free(curp->secondary);
- free(curp->sodest);
+ free_buf_list(curp->secondary);
free(curp);
}
-void
-mparse_result(struct mparse *curp, struct roff_man **man,
- char **sodest)
+struct roff_meta *
+mparse_result(struct mparse *curp)
{
-
- if (sodest && NULL != (*sodest = curp->sodest)) {
- *man = NULL;
- return;
+ roff_state_reset(curp->man);
+ if (curp->options & MPARSE_VALIDATE) {
+ if (curp->man->meta.macroset == MACROSET_MDOC)
+ mdoc_validate(curp->man);
+ else
+ man_validate(curp->man);
}
- if (man)
- *man = curp->man;
+ return &curp->man->meta;
}
void
-mparse_updaterc(struct mparse *curp, enum mandoclevel *rc)
-{
- if (curp->file_status > *rc)
- *rc = curp->file_status;
-}
-
-void
-mandoc_vmsg(enum mandocerr t, struct mparse *m,
- int ln, int pos, const char *fmt, ...)
-{
- char buf[256];
- va_list ap;
-
- va_start(ap, fmt);
- (void)vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-
- mandoc_msg(t, m, ln, pos, buf);
-}
-
-void
-mandoc_msg(enum mandocerr er, struct mparse *m,
- int ln, int col, const char *msg)
-{
- enum mandoclevel level;
-
- if (er < m->mmin && er != MANDOCERR_FILE)
- return;
-
- level = MANDOCLEVEL_UNSUPP;
- while (er < mandoclimits[level])
- level--;
-
- if (m->mmsg)
- (*m->mmsg)(er, level, m->file, ln, col, msg);
-
- if (m->file_status < level)
- m->file_status = level;
-}
-
-const char *
-mparse_strerror(enum mandocerr er)
-{
-
- return mandocerrs[er];
-}
-
-const char *
-mparse_strlevel(enum mandoclevel lvl)
-{
- return mandoclevels[lvl];
-}
-
-void
-mparse_keep(struct mparse *p)
-{
-
- assert(NULL == p->secondary);
- p->secondary = mandoc_calloc(1, sizeof(struct buf));
-}
-
-const char *
-mparse_getkeep(const struct mparse *p)
+mparse_copy(const struct mparse *p)
{
+ struct buf *buf;
- assert(p->secondary);
- return p->secondary->sz ? p->secondary->buf : NULL;
+ for (buf = p->secondary; buf != NULL; buf = buf->next)
+ puts(buf->buf);
}
diff --git a/usr/src/cmd/mandoc/roff.c b/usr/src/cmd/mandoc/roff.c
index 86e145e366..e84295aac3 100644
--- a/usr/src/cmd/mandoc/roff.c
+++ b/usr/src/cmd/mandoc/roff.c
@@ -1,7 +1,7 @@
-/* $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */
+/* $Id: roff.c,v 1.363 2019/02/06 21:11:43 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017-2019 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
@@ -28,13 +28,23 @@
#include <stdlib.h>
#include <string.h>
-#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
+#include "mandoc.h"
#include "roff.h"
+#include "mandoc_parse.h"
#include "libmandoc.h"
#include "roff_int.h"
-#include "libroff.h"
+#include "tbl_parse.h"
+#include "eqn_parse.h"
+
+/*
+ * ASCII_ESC is used to signal from roff_getarg() to roff_expand()
+ * that an escape sequence resulted from copy-in processing and
+ * needs to be checked or interpolated. As it is used nowhere
+ * else, it is defined here rather than in a header file.
+ */
+#define ASCII_ESC 27
/* Maximum number of string expansions per line, to break infinite loops. */
#define EXPAND_LIMIT 1000
@@ -85,10 +95,20 @@ struct roffreq {
char name[];
};
+/*
+ * A macro processing context.
+ * More than one is needed when macro calls are nested.
+ */
+struct mctx {
+ char **argv;
+ int argc;
+ int argsz;
+};
+
struct roff {
- struct mparse *parse; /* parse point */
struct roff_man *man; /* mdoc or man parser */
struct roffnode *last; /* leaf of stack */
+ struct mctx *mstack; /* stack of macro contexts */
int *rstack; /* stack of inverted `ie' values */
struct ohash *reqtab; /* request lookup table */
struct roffreg *regtab; /* number registers */
@@ -104,10 +124,11 @@ struct roff {
struct eqn_node *eqn; /* active equation parser */
int eqn_inline; /* current equation is inline */
int options; /* parse options */
+ int mstacksz; /* current size of mstack */
+ int mstackpos; /* position in mstack */
int rstacksz; /* current size limit of rstack */
int rstackpos; /* position in rstack */
int format; /* current file in mdoc or man format */
- int argc; /* number of args of the last macro */
char control; /* control character */
char escape; /* escape character */
};
@@ -131,7 +152,7 @@ struct roffnode {
int pos, /* current pos in buffer */ \
int *offs /* reset offset of buffer data */
-typedef enum rofferr (*roffproc)(ROFF_ARGS);
+typedef int (*roffproc)(ROFF_ARGS);
struct roffmac {
roffproc proc; /* process new macro */
@@ -151,32 +172,34 @@ struct predef {
/* --- function prototypes ------------------------------------------------ */
-static void roffnode_cleanscope(struct roff *);
-static void roffnode_pop(struct roff *);
+static int roffnode_cleanscope(struct roff *);
+static int roffnode_pop(struct roff *);
static void roffnode_push(struct roff *, enum roff_tok,
const char *, int, int);
-static void roff_addtbl(struct roff_man *, struct tbl_node *);
-static enum rofferr roff_als(ROFF_ARGS);
-static enum rofferr roff_block(ROFF_ARGS);
-static enum rofferr roff_block_text(ROFF_ARGS);
-static enum rofferr roff_block_sub(ROFF_ARGS);
-static enum rofferr roff_br(ROFF_ARGS);
-static enum rofferr roff_cblock(ROFF_ARGS);
-static enum rofferr roff_cc(ROFF_ARGS);
-static void roff_ccond(struct roff *, int, int);
-static enum rofferr roff_cond(ROFF_ARGS);
-static enum rofferr roff_cond_text(ROFF_ARGS);
-static enum rofferr roff_cond_sub(ROFF_ARGS);
-static enum rofferr roff_ds(ROFF_ARGS);
-static enum rofferr roff_ec(ROFF_ARGS);
-static enum rofferr roff_eo(ROFF_ARGS);
-static enum rofferr roff_eqndelim(struct roff *, struct buf *, int);
+static void roff_addtbl(struct roff_man *, int, struct tbl_node *);
+static int roff_als(ROFF_ARGS);
+static int roff_block(ROFF_ARGS);
+static int roff_block_text(ROFF_ARGS);
+static int roff_block_sub(ROFF_ARGS);
+static int roff_cblock(ROFF_ARGS);
+static int roff_cc(ROFF_ARGS);
+static int roff_ccond(struct roff *, int, int);
+static int roff_char(ROFF_ARGS);
+static int roff_cond(ROFF_ARGS);
+static int roff_cond_text(ROFF_ARGS);
+static int roff_cond_sub(ROFF_ARGS);
+static int roff_ds(ROFF_ARGS);
+static int roff_ec(ROFF_ARGS);
+static int roff_eo(ROFF_ARGS);
+static int roff_eqndelim(struct roff *, struct buf *, int);
static int roff_evalcond(struct roff *r, int, char *, int *);
static int roff_evalnum(struct roff *, int,
const char *, int *, int *, int);
static int roff_evalpar(struct roff *, int,
const char *, int *, int *, int);
static int roff_evalstrcond(const char *, int *);
+static int roff_expand(struct roff *, struct buf *,
+ int, int, char);
static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
@@ -191,39 +214,42 @@ static const char *roff_getstrn(struct roff *,
const char *, size_t, int *);
static int roff_hasregn(const struct roff *,
const char *, size_t);
-static enum rofferr roff_insec(ROFF_ARGS);
-static enum rofferr roff_it(ROFF_ARGS);
-static enum rofferr roff_line_ignore(ROFF_ARGS);
+static int roff_insec(ROFF_ARGS);
+static int roff_it(ROFF_ARGS);
+static int roff_line_ignore(ROFF_ARGS);
static void roff_man_alloc1(struct roff_man *);
static void roff_man_free1(struct roff_man *);
-static enum rofferr roff_manyarg(ROFF_ARGS);
-static enum rofferr roff_nr(ROFF_ARGS);
-static enum rofferr roff_onearg(ROFF_ARGS);
+static int roff_manyarg(ROFF_ARGS);
+static int roff_noarg(ROFF_ARGS);
+static int roff_nop(ROFF_ARGS);
+static int roff_nr(ROFF_ARGS);
+static int roff_onearg(ROFF_ARGS);
static enum roff_tok roff_parse(struct roff *, char *, int *,
int, int);
-static enum rofferr roff_parsetext(struct roff *, struct buf *,
+static int roff_parsetext(struct roff *, struct buf *,
int, int *);
-static enum rofferr roff_renamed(ROFF_ARGS);
-static enum rofferr roff_res(struct roff *, struct buf *, int, int);
-static enum rofferr roff_rm(ROFF_ARGS);
-static enum rofferr roff_rn(ROFF_ARGS);
-static enum rofferr roff_rr(ROFF_ARGS);
+static int roff_renamed(ROFF_ARGS);
+static int roff_return(ROFF_ARGS);
+static int roff_rm(ROFF_ARGS);
+static int roff_rn(ROFF_ARGS);
+static int roff_rr(ROFF_ARGS);
static void roff_setregn(struct roff *, const char *,
size_t, int, char, int);
static void roff_setstr(struct roff *,
const char *, const char *, int);
static void roff_setstrn(struct roffkv **, const char *,
size_t, const char *, size_t, int);
-static enum rofferr roff_so(ROFF_ARGS);
-static enum rofferr roff_tr(ROFF_ARGS);
-static enum rofferr roff_Dd(ROFF_ARGS);
-static enum rofferr roff_TE(ROFF_ARGS);
-static enum rofferr roff_TS(ROFF_ARGS);
-static enum rofferr roff_EQ(ROFF_ARGS);
-static enum rofferr roff_EN(ROFF_ARGS);
-static enum rofferr roff_T_(ROFF_ARGS);
-static enum rofferr roff_unsupp(ROFF_ARGS);
-static enum rofferr roff_userdef(ROFF_ARGS);
+static int roff_shift(ROFF_ARGS);
+static int roff_so(ROFF_ARGS);
+static int roff_tr(ROFF_ARGS);
+static int roff_Dd(ROFF_ARGS);
+static int roff_TE(ROFF_ARGS);
+static int roff_TS(ROFF_ARGS);
+static int roff_EQ(ROFF_ARGS);
+static int roff_EN(ROFF_ARGS);
+static int roff_T_(ROFF_ARGS);
+static int roff_unsupp(ROFF_ARGS);
+static int roff_userdef(ROFF_ARGS);
/* --- constant data ------------------------------------------------------ */
@@ -231,8 +257,9 @@ static enum rofferr roff_userdef(ROFF_ARGS);
#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */
const char *__roff_name[MAN_MAX + 1] = {
- "br", "ce", "ft", "ll",
- "mc", "po", "rj", "sp",
+ "br", "ce", "fi", "ft",
+ "ll", "mc", "nf",
+ "po", "rj", "sp",
"ta", "ti", NULL,
"ab", "ad", "af", "aln",
"als", "am", "am1", "ami",
@@ -326,24 +353,27 @@ const char *__roff_name[MAN_MAX + 1] = {
"Dx", "%Q", "%U", "Ta",
NULL,
"TH", "SH", "SS", "TP",
+ "TQ",
"LP", "PP", "P", "IP",
"HP", "SM", "SB", "BI",
"IB", "BR", "RB", "R",
"B", "I", "IR", "RI",
- "nf", "fi",
"RE", "RS", "DT", "UC",
"PD", "AT", "in",
- "OP", "EX", "EE", "UR",
+ "SY", "YS", "OP",
+ "EX", "EE", "UR",
"UE", "MT", "ME", NULL
};
const char *const *roff_name = __roff_name;
static struct roffmac roffs[TOKEN_NONE] = {
- { roff_br, NULL, NULL, 0 }, /* br */
+ { roff_noarg, NULL, NULL, 0 }, /* br */
{ roff_onearg, NULL, NULL, 0 }, /* ce */
+ { roff_noarg, NULL, NULL, 0 }, /* fi */
{ roff_onearg, NULL, NULL, 0 }, /* ft */
{ roff_onearg, NULL, NULL, 0 }, /* ll */
{ roff_onearg, NULL, NULL, 0 }, /* mc */
+ { roff_noarg, NULL, NULL, 0 }, /* nf */
{ roff_onearg, NULL, NULL, 0 }, /* po */
{ roff_onearg, NULL, NULL, 0 }, /* rj */
{ roff_onearg, NULL, NULL, 0 }, /* sp */
@@ -373,14 +403,14 @@ static struct roffmac roffs[TOKEN_NONE] = {
{ roff_unsupp, NULL, NULL, 0 }, /* break */
{ roff_line_ignore, NULL, NULL, 0 }, /* breakchar */
{ roff_line_ignore, NULL, NULL, 0 }, /* brnl */
- { roff_br, NULL, NULL, 0 }, /* brp */
+ { roff_noarg, NULL, NULL, 0 }, /* brp */
{ roff_line_ignore, NULL, NULL, 0 }, /* brpnl */
{ roff_unsupp, NULL, NULL, 0 }, /* c2 */
{ roff_cc, NULL, NULL, 0 }, /* cc */
{ roff_insec, NULL, NULL, 0 }, /* cf */
{ roff_line_ignore, NULL, NULL, 0 }, /* cflags */
{ roff_line_ignore, NULL, NULL, 0 }, /* ch */
- { roff_unsupp, NULL, NULL, 0 }, /* char */
+ { roff_char, NULL, NULL, 0 }, /* char */
{ roff_unsupp, NULL, NULL, 0 }, /* chop */
{ roff_line_ignore, NULL, NULL, 0 }, /* class */
{ roff_insec, NULL, NULL, 0 }, /* close */
@@ -490,7 +520,7 @@ static struct roffmac roffs[TOKEN_NONE] = {
{ roff_line_ignore, NULL, NULL, 0 }, /* nhychar */
{ roff_unsupp, NULL, NULL, 0 }, /* nm */
{ roff_unsupp, NULL, NULL, 0 }, /* nn */
- { roff_unsupp, NULL, NULL, 0 }, /* nop */
+ { roff_nop, NULL, NULL, 0 }, /* nop */
{ roff_nr, NULL, NULL, 0 }, /* nr */
{ roff_unsupp, NULL, NULL, 0 }, /* nrf */
{ roff_line_ignore, NULL, NULL, 0 }, /* nroff */
@@ -519,7 +549,7 @@ static struct roffmac roffs[TOKEN_NONE] = {
{ roff_unsupp, NULL, NULL, 0 }, /* rchar */
{ roff_line_ignore, NULL, NULL, 0 }, /* rd */
{ roff_line_ignore, NULL, NULL, 0 }, /* recursionlimit */
- { roff_unsupp, NULL, NULL, 0 }, /* return */
+ { roff_return, NULL, NULL, 0 }, /* return */
{ roff_unsupp, NULL, NULL, 0 }, /* rfschar */
{ roff_line_ignore, NULL, NULL, 0 }, /* rhang */
{ roff_rm, NULL, NULL, 0 }, /* rm */
@@ -531,7 +561,7 @@ static struct roffmac roffs[TOKEN_NONE] = {
{ roff_unsupp, NULL, NULL, 0 }, /* schar */
{ roff_line_ignore, NULL, NULL, 0 }, /* sentchar */
{ roff_line_ignore, NULL, NULL, 0 }, /* shc */
- { roff_unsupp, NULL, NULL, 0 }, /* shift */
+ { roff_shift, NULL, NULL, 0 }, /* shift */
{ roff_line_ignore, NULL, NULL, 0 }, /* sizes */
{ roff_so, NULL, NULL, 0 }, /* so */
{ roff_line_ignore, NULL, NULL, 0 }, /* spacewidth */
@@ -573,7 +603,7 @@ static struct roffmac roffs[TOKEN_NONE] = {
{ roff_line_ignore, NULL, NULL, 0 }, /* watchlength */
{ roff_line_ignore, NULL, NULL, 0 }, /* watchn */
{ roff_unsupp, NULL, NULL, 0 }, /* wh */
- { roff_unsupp, NULL, NULL, 0 }, /* while */
+ { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /*while*/
{ roff_insec, NULL, NULL, 0 }, /* write */
{ roff_insec, NULL, NULL, 0 }, /* writec */
{ roff_insec, NULL, NULL, 0 }, /* writem */
@@ -657,18 +687,19 @@ roffhash_find(struct ohash *htab, const char *name, size_t sz)
* Pop the current node off of the stack of roff instructions currently
* pending.
*/
-static void
+static int
roffnode_pop(struct roff *r)
{
struct roffnode *p;
+ int inloop;
- assert(r->last);
p = r->last;
-
- r->last = r->last->parent;
+ inloop = p->tok == ROFF_while;
+ r->last = p->parent;
free(p->name);
free(p->end);
free(p);
+ return inloop;
}
/*
@@ -698,19 +729,17 @@ roffnode_push(struct roff *r, enum roff_tok tok, const char *name,
static void
roff_free1(struct roff *r)
{
- struct tbl_node *tbl;
int i;
- while (NULL != (tbl = r->first_tbl)) {
- r->first_tbl = tbl->next;
- tbl_free(tbl);
- }
+ tbl_free(r->first_tbl);
r->first_tbl = r->last_tbl = r->tbl = NULL;
- if (r->last_eqn != NULL)
- eqn_free(r->last_eqn);
+ eqn_free(r->last_eqn);
r->last_eqn = r->eqn = NULL;
+ while (r->mstackpos >= 0)
+ roff_userret(r);
+
while (r->last)
roffnode_pop(r);
@@ -750,21 +779,26 @@ roff_reset(struct roff *r)
void
roff_free(struct roff *r)
{
+ int i;
+
roff_free1(r);
+ for (i = 0; i < r->mstacksz; i++)
+ free(r->mstack[i].argv);
+ free(r->mstack);
roffhash_free(r->reqtab);
free(r);
}
struct roff *
-roff_alloc(struct mparse *parse, int options)
+roff_alloc(int options)
{
struct roff *r;
r = mandoc_calloc(1, sizeof(struct roff));
- r->parse = parse;
r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
r->options = options;
r->format = options & (MPARSE_MDOC | MPARSE_MAN);
+ r->mstackpos = -1;
r->rstackpos = -1;
r->escape = '\\';
return r;
@@ -775,9 +809,8 @@ roff_alloc(struct mparse *parse, int options)
static void
roff_man_free1(struct roff_man *man)
{
-
- if (man->first != NULL)
- roff_node_delete(man, man->first);
+ if (man->meta.first != NULL)
+ roff_node_delete(man, man->meta.first);
free(man->meta.msec);
free(man->meta.vol);
free(man->meta.os);
@@ -785,27 +818,33 @@ roff_man_free1(struct roff_man *man)
free(man->meta.title);
free(man->meta.name);
free(man->meta.date);
+ free(man->meta.sodest);
}
-static void
-roff_man_alloc1(struct roff_man *man)
+void
+roff_state_reset(struct roff_man *man)
{
-
- memset(&man->meta, 0, sizeof(man->meta));
- man->first = mandoc_calloc(1, sizeof(*man->first));
- man->first->type = ROFFT_ROOT;
- man->last = man->first;
+ man->last = man->meta.first;
man->last_es = NULL;
man->flags = 0;
- man->macroset = MACROSET_NONE;
man->lastsec = man->lastnamed = SEC_NONE;
man->next = ROFF_NEXT_CHILD;
+ roff_setreg(man->roff, "nS", 0, '=');
+}
+
+static void
+roff_man_alloc1(struct roff_man *man)
+{
+ memset(&man->meta, 0, sizeof(man->meta));
+ man->meta.first = mandoc_calloc(1, sizeof(*man->meta.first));
+ man->meta.first->type = ROFFT_ROOT;
+ man->meta.macroset = MACROSET_NONE;
+ roff_state_reset(man);
}
void
roff_man_reset(struct roff_man *man)
{
-
roff_man_free1(man);
roff_man_alloc1(man);
}
@@ -813,19 +852,16 @@ roff_man_reset(struct roff_man *man)
void
roff_man_free(struct roff_man *man)
{
-
roff_man_free1(man);
free(man);
}
struct roff_man *
-roff_man_alloc(struct roff *roff, struct mparse *parse,
- const char *os_s, int quick)
+roff_man_alloc(struct roff *roff, const char *os_s, int quick)
{
struct roff_man *man;
man = mandoc_calloc(1, sizeof(*man));
- man->parse = parse;
man->roff = roff;
man->os_s = os_s;
man->quick = quick;
@@ -853,6 +889,10 @@ roff_node_alloc(struct roff_man *man, int line, int pos,
n->flags |= NODE_SYNPRETTY;
else
n->flags &= ~NODE_SYNPRETTY;
+ if ((man->flags & (ROFF_NOFILL | ROFF_NONOFILL)) == ROFF_NOFILL)
+ n->flags |= NODE_NOFILL;
+ else
+ n->flags &= ~NODE_NOFILL;
if (man->flags & MDOC_NEWLINE)
n->flags |= NODE_LINE;
man->flags &= ~MDOC_NEWLINE;
@@ -985,15 +1025,15 @@ roff_body_alloc(struct roff_man *man, int line, int pos, int tok)
}
static void
-roff_addtbl(struct roff_man *man, struct tbl_node *tbl)
+roff_addtbl(struct roff_man *man, int line, struct tbl_node *tbl)
{
struct roff_node *n;
- const struct tbl_span *span;
+ struct tbl_span *span;
- if (man->macroset == MACROSET_MAN)
+ if (man->meta.macroset == MACROSET_MAN)
man_breakscope(man, ROFF_TS);
while ((span = tbl_span(tbl)) != NULL) {
- n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE);
+ n = roff_node_alloc(man, line, 0, ROFFT_TBL, TOKEN_NONE);
n->span = span;
roff_node_append(man, n);
n->flags |= NODE_VALID | NODE_ENDED;
@@ -1034,8 +1074,16 @@ roff_node_unlink(struct roff_man *man, struct roff_node *n)
man->next = ROFF_NEXT_SIBLING;
}
}
- if (man->first == n)
- man->first = NULL;
+ if (man->meta.first == n)
+ man->meta.first = NULL;
+}
+
+void
+roff_node_relink(struct roff_man *man, struct roff_node *n)
+{
+ roff_node_unlink(man, n);
+ n->prev = n->next = NULL;
+ roff_node_append(man, n);
}
void
@@ -1046,8 +1094,7 @@ roff_node_free(struct roff_node *n)
mdoc_argv_free(n->args);
if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM)
free(n->norm);
- if (n->eqn != NULL)
- eqn_box_free(n->eqn);
+ eqn_box_free(n->eqn);
free(n->string);
free(n);
}
@@ -1114,17 +1161,19 @@ deroff(char **dest, const struct roff_node *n)
/* --- main functions of the roff parser ---------------------------------- */
/*
- * In the current line, expand escape sequences that tend to get
- * used in numerical expressions and conditional requests.
- * Also check the syntax of the remaining escape sequences.
+ * In the current line, expand escape sequences that produce parsable
+ * input text. Also check the syntax of the remaining escape sequences,
+ * which typically produce output glyphs or change formatter state.
*/
-static enum rofferr
-roff_res(struct roff *r, struct buf *buf, int ln, int pos)
+static int
+roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char newesc)
{
+ struct mctx *ctx; /* current macro call context */
char ubuf[24]; /* buffer to print the number */
struct roff_node *n; /* used for header comments */
const char *start; /* start of the string to process */
char *stesc; /* start of an escape sequence ('\\') */
+ const char *esct; /* type of esccape sequence */
char *ep; /* end of comment string */
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
@@ -1132,14 +1181,17 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
char *nbuf; /* new buffer to copy buf->buf to */
size_t maxl; /* expected length of the escape name */
size_t naml; /* actual length of the escape name */
- enum mandoc_esc esc; /* type of the escape sequence */
+ size_t asz; /* length of the replacement */
+ size_t rsz; /* length of the rest of the string */
int inaml; /* length returned from mandoc_escape() */
int expand_count; /* to avoid infinite loops */
int npos; /* position in numeric expression */
int arg_complete; /* argument not interrupted by eol */
+ int quote_args; /* true for \\$@, false for \\$* */
int done; /* no more input available */
int deftype; /* type of definition to paste */
int rcsid; /* kind of RCS id seen */
+ enum mandocerr err; /* for escape sequence problems */
char sign; /* increment number register */
char term; /* character terminating the escape */
@@ -1148,7 +1200,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
done = 0;
start = buf->buf + pos;
for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
- if (stesc[0] != r->escape || stesc[1] == '\0')
+ if (stesc[0] != newesc || stesc[1] == '\0')
continue;
stesc++;
if (*stesc != '"' && *stesc != '#')
@@ -1168,8 +1220,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
isalnum((unsigned char)*cp) == 0 &&
strchr(cp, '$') != NULL) {
if (r->man->meta.rcsids & rcsid)
- mandoc_msg(MANDOCERR_RCS_REP, r->parse,
- ln, stesc + 1 - buf->buf, stesc + 1);
+ mandoc_msg(MANDOCERR_RCS_REP, ln,
+ (int)(stesc - buf->buf) + 1,
+ "%s", stesc + 1);
r->man->meta.rcsids |= rcsid;
}
@@ -1181,15 +1234,15 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
ep--;
}
if (*ep == ' ' || *ep == '\t')
- mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
- ln, ep - buf->buf, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL,
+ ln, (int)(ep - buf->buf), NULL);
/*
* Save comments preceding the title macro
* in the syntax tree.
*/
- if (r->format == 0) {
+ if (newesc != ASCII_ESC && r->format == 0) {
while (*ep == ' ' || *ep == '\t')
ep--;
ep[1] = '\0';
@@ -1202,9 +1255,17 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
r->man->next = ROFF_NEXT_SIBLING;
}
- /* Discard comments. */
+ /* Line continuation with comment. */
+
+ if (stesc[1] == '#') {
+ *stesc = '\0';
+ return ROFF_IGN | ROFF_APPEND;
+ }
+
+ /* Discard normal comments. */
- while (stesc > start && stesc[-1] == ' ')
+ while (stesc > start && stesc[-1] == ' ' &&
+ (stesc == start + 1 || stesc[-2] != '\\'))
stesc--;
*stesc = '\0';
break;
@@ -1222,11 +1283,16 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
expand_count = 0;
while (stesc >= start) {
+ if (*stesc != newesc) {
- /* Search backwards for the next backslash. */
+ /*
+ * If we have a non-standard escape character,
+ * escape literal backslashes because all
+ * processing in subsequent functions uses
+ * the standard escaping rules.
+ */
- if (*stesc != r->escape) {
- if (*stesc == '\\') {
+ if (newesc != ASCII_ESC && *stesc == '\\') {
*stesc = '\0';
buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s",
buf->buf, stesc + 1) + 1;
@@ -1235,6 +1301,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
free(buf->buf);
buf->buf = nbuf;
}
+
+ /* Search backwards for the next escape. */
+
stesc--;
continue;
}
@@ -1256,15 +1325,19 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
if (done)
continue;
else
- return ROFF_APPEND;
+ return ROFF_IGN | ROFF_APPEND;
}
/* Decide whether to expand or to check only. */
term = '\0';
cp = stesc + 1;
- switch (*cp) {
+ if (*cp == 'E')
+ cp++;
+ esct = cp;
+ switch (*esct) {
case '*':
+ case '$':
res = NULL;
break;
case 'B':
@@ -1278,19 +1351,33 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
res = ubuf;
break;
default:
- esc = mandoc_escape(&cp, &stnam, &inaml);
- if (esc == ESCAPE_ERROR ||
- (esc == ESCAPE_SPECIAL &&
- mchars_spec2cp(stnam, inaml) < 0))
- mandoc_vmsg(MANDOCERR_ESC_BAD,
- r->parse, ln, (int)(stesc - buf->buf),
+ err = MANDOCERR_OK;
+ switch(mandoc_escape(&cp, &stnam, &inaml)) {
+ case ESCAPE_SPECIAL:
+ if (mchars_spec2cp(stnam, inaml) >= 0)
+ break;
+ /* FALLTHROUGH */
+ case ESCAPE_ERROR:
+ err = MANDOCERR_ESC_BAD;
+ break;
+ case ESCAPE_UNDEF:
+ err = MANDOCERR_ESC_UNDEF;
+ break;
+ case ESCAPE_UNSUPP:
+ err = MANDOCERR_ESC_UNSUPP;
+ break;
+ default:
+ break;
+ }
+ if (err != MANDOCERR_OK)
+ mandoc_msg(err, ln, (int)(stesc - buf->buf),
"%.*s", (int)(cp - stesc), stesc);
stesc--;
continue;
}
if (EXPAND_LIMIT < ++expand_count) {
- mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+ mandoc_msg(MANDOCERR_ROFFLOOP,
ln, (int)(stesc - buf->buf), NULL);
return ROFF_IGN;
}
@@ -1331,8 +1418,8 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
arg_complete = 1;
while (maxl == 0 || naml < maxl) {
if (*cp == '\0') {
- mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
- ln, (int)(stesc - buf->buf), stesc);
+ mandoc_msg(MANDOCERR_ESC_BAD, ln,
+ (int)(stesc - buf->buf), "%s", stesc);
arg_complete = 0;
break;
}
@@ -1340,7 +1427,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
cp++;
break;
}
- if (*cp++ != '\\' || stesc[1] != 'w') {
+ if (*cp++ != '\\' || *esct != 'w') {
naml++;
continue;
}
@@ -1348,6 +1435,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
case ESCAPE_SPECIAL:
case ESCAPE_UNICODE:
case ESCAPE_NUMBERED:
+ case ESCAPE_UNDEF:
case ESCAPE_OVERSTRIKE:
naml++;
break;
@@ -1361,13 +1449,80 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
* undefined, resume searching for escapes.
*/
- switch (stesc[1]) {
+ switch (*esct) {
case '*':
if (arg_complete) {
deftype = ROFFDEF_USER | ROFFDEF_PRE;
res = roff_getstrn(r, stnam, naml, &deftype);
+
+ /*
+ * If not overriden, let \*(.T
+ * through to the formatters.
+ */
+
+ if (res == NULL && naml == 2 &&
+ stnam[0] == '.' && stnam[1] == 'T') {
+ roff_setstrn(&r->strtab,
+ ".T", 2, NULL, 0, 0);
+ stesc--;
+ continue;
+ }
}
break;
+ case '$':
+ if (r->mstackpos < 0) {
+ mandoc_msg(MANDOCERR_ARG_UNDEF, ln,
+ (int)(stesc - buf->buf), "%.3s", stesc);
+ break;
+ }
+ ctx = r->mstack + r->mstackpos;
+ npos = esct[1] - '1';
+ if (npos >= 0 && npos <= 8) {
+ res = npos < ctx->argc ?
+ ctx->argv[npos] : "";
+ break;
+ }
+ if (esct[1] == '*')
+ quote_args = 0;
+ else if (esct[1] == '@')
+ quote_args = 1;
+ else {
+ mandoc_msg(MANDOCERR_ARG_NONUM, ln,
+ (int)(stesc - buf->buf), "%.3s", stesc);
+ break;
+ }
+ asz = 0;
+ for (npos = 0; npos < ctx->argc; npos++) {
+ if (npos)
+ asz++; /* blank */
+ if (quote_args)
+ asz += 2; /* quotes */
+ asz += strlen(ctx->argv[npos]);
+ }
+ if (asz != 3) {
+ rsz = buf->sz - (stesc - buf->buf) - 3;
+ if (asz < 3)
+ memmove(stesc + asz, stesc + 3, rsz);
+ buf->sz += asz - 3;
+ nbuf = mandoc_realloc(buf->buf, buf->sz);
+ start = nbuf + pos;
+ stesc = nbuf + (stesc - buf->buf);
+ buf->buf = nbuf;
+ if (asz > 3)
+ memmove(stesc + asz, stesc + 3, rsz);
+ }
+ for (npos = 0; npos < ctx->argc; npos++) {
+ if (npos)
+ *stesc++ = ' ';
+ if (quote_args)
+ *stesc++ = '"';
+ cp = ctx->argv[npos];
+ while (*cp != '\0')
+ *stesc++ = *cp++;
+ if (quote_args)
+ *stesc++ = '"';
+ }
+ continue;
case 'B':
npos = 0;
ubuf[0] = arg_complete &&
@@ -1391,12 +1546,13 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
}
if (res == NULL) {
- mandoc_vmsg(MANDOCERR_STR_UNDEF,
- r->parse, ln, (int)(stesc - buf->buf),
- "%.*s", (int)naml, stnam);
+ if (*esct == '*')
+ mandoc_msg(MANDOCERR_STR_UNDEF,
+ ln, (int)(stesc - buf->buf),
+ "%.*s", (int)naml, stnam);
res = "";
} else if (buf->sz + strlen(res) > SHRT_MAX) {
- mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+ mandoc_msg(MANDOCERR_ROFFLOOP,
ln, (int)(stesc - buf->buf), NULL);
return ROFF_IGN;
}
@@ -1418,9 +1574,121 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
}
/*
+ * Parse a quoted or unquoted roff-style request or macro argument.
+ * Return a pointer to the parsed argument, which is either the original
+ * pointer or advanced by one byte in case the argument is quoted.
+ * NUL-terminate the argument in place.
+ * Collapse pairs of quotes inside quoted arguments.
+ * Advance the argument pointer to the next argument,
+ * or to the NUL byte terminating the argument line.
+ */
+char *
+roff_getarg(struct roff *r, char **cpp, int ln, int *pos)
+{
+ struct buf buf;
+ char *cp, *start;
+ int newesc, pairs, quoted, white;
+
+ /* Quoting can only start with a new word. */
+ start = *cpp;
+ quoted = 0;
+ if ('"' == *start) {
+ quoted = 1;
+ start++;
+ }
+
+ newesc = pairs = white = 0;
+ for (cp = start; '\0' != *cp; cp++) {
+
+ /*
+ * Move the following text left
+ * after quoted quotes and after "\\" and "\t".
+ */
+ if (pairs)
+ cp[-pairs] = cp[0];
+
+ if ('\\' == cp[0]) {
+ /*
+ * In copy mode, translate double to single
+ * backslashes and backslash-t to literal tabs.
+ */
+ switch (cp[1]) {
+ case 'a':
+ case 't':
+ cp[-pairs] = '\t';
+ pairs++;
+ cp++;
+ break;
+ case '\\':
+ newesc = 1;
+ cp[-pairs] = ASCII_ESC;
+ pairs++;
+ cp++;
+ break;
+ case ' ':
+ /* Skip escaped blanks. */
+ if (0 == quoted)
+ cp++;
+ break;
+ default:
+ break;
+ }
+ } else if (0 == quoted) {
+ if (' ' == cp[0]) {
+ /* Unescaped blanks end unquoted args. */
+ white = 1;
+ break;
+ }
+ } else if ('"' == cp[0]) {
+ if ('"' == cp[1]) {
+ /* Quoted quotes collapse. */
+ pairs++;
+ cp++;
+ } else {
+ /* Unquoted quotes end quoted args. */
+ quoted = 2;
+ break;
+ }
+ }
+ }
+
+ /* Quoted argument without a closing quote. */
+ if (1 == quoted)
+ mandoc_msg(MANDOCERR_ARG_QUOTE, ln, *pos, NULL);
+
+ /* NUL-terminate this argument and move to the next one. */
+ if (pairs)
+ cp[-pairs] = '\0';
+ if ('\0' != *cp) {
+ *cp++ = '\0';
+ while (' ' == *cp)
+ cp++;
+ }
+ *pos += (int)(cp - start) + (quoted ? 1 : 0);
+ *cpp = cp;
+
+ if ('\0' == *cp && (white || ' ' == cp[-1]))
+ mandoc_msg(MANDOCERR_SPACE_EOL, ln, *pos, NULL);
+
+ start = mandoc_strdup(start);
+ if (newesc == 0)
+ return start;
+
+ buf.buf = start;
+ buf.sz = strlen(start) + 1;
+ buf.next = NULL;
+ if (roff_expand(r, &buf, ln, 0, ASCII_ESC) & ROFF_IGN) {
+ free(buf.buf);
+ buf.buf = mandoc_strdup("");
+ }
+ return buf.buf;
+}
+
+
+/*
* Process text streams.
*/
-static enum rofferr
+static int
roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
{
size_t sz;
@@ -1486,11 +1754,11 @@ roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
return ROFF_CONT;
}
-enum rofferr
+int
roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
{
enum roff_tok t;
- enum rofferr e;
+ int e;
int pos; /* parse point */
int spos; /* saved parse point for messages */
int ppos; /* original offset in buf->buf */
@@ -1511,8 +1779,8 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
/* Expand some escape sequences. */
- e = roff_res(r, buf, ln, pos);
- if (e == ROFF_IGN || e == ROFF_APPEND)
+ e = roff_expand(r, buf, ln, pos, r->escape);
+ if ((e & ROFF_MASK) == ROFF_IGN)
return e;
assert(e == ROFF_CONT);
@@ -1529,27 +1797,27 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
if (r->last != NULL && ! ctl) {
t = r->last->tok;
e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
- if (e == ROFF_IGN)
+ if ((e & ROFF_MASK) == ROFF_IGN)
return e;
- assert(e == ROFF_CONT);
- }
+ e &= ~ROFF_MASK;
+ } else
+ e = ROFF_IGN;
if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) {
eqn_read(r->eqn, buf->buf + ppos);
- return ROFF_IGN;
+ return e;
}
if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) {
tbl_read(r->tbl, ln, buf->buf, ppos);
- roff_addtbl(r->man, r->tbl);
- return ROFF_IGN;
+ roff_addtbl(r->man, ln, r->tbl);
+ return e;
}
if ( ! ctl)
- return roff_parsetext(r, buf, pos, offs);
+ return roff_parsetext(r, buf, pos, offs) | e;
/* Skip empty request lines. */
if (buf->buf[pos] == '"') {
- mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse,
- ln, pos, NULL);
+ mandoc_msg(MANDOCERR_COMMENT_BAD, ln, pos, NULL);
return ROFF_IGN;
} else if (buf->buf[pos] == '\0')
return ROFF_IGN;
@@ -1574,8 +1842,8 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS ||
t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) {
- mandoc_msg(MANDOCERR_TBLMACRO, r->parse,
- ln, pos, buf->buf + spos);
+ mandoc_msg(MANDOCERR_TBLMACRO,
+ ln, pos, "%s", buf->buf + spos);
if (t != TOKEN_NONE)
return ROFF_IGN;
while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
@@ -1583,7 +1851,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
while (buf->buf[pos] == ' ')
pos++;
tbl_read(r->tbl, ln, buf->buf, pos);
- roff_addtbl(r->man, r->tbl);
+ roff_addtbl(r->man, ln, r->tbl);
return ROFF_IGN;
}
@@ -1611,25 +1879,41 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs);
}
+/*
+ * Internal interface function to tell the roff parser that execution
+ * of the current macro ended. This is required because macro
+ * definitions usually do not end with a .return request.
+ */
+void
+roff_userret(struct roff *r)
+{
+ struct mctx *ctx;
+ int i;
+
+ assert(r->mstackpos >= 0);
+ ctx = r->mstack + r->mstackpos;
+ for (i = 0; i < ctx->argc; i++)
+ free(ctx->argv[i]);
+ ctx->argc = 0;
+ r->mstackpos--;
+}
+
void
roff_endparse(struct roff *r)
{
if (r->last != NULL)
- mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
- r->last->line, r->last->col,
- roff_name[r->last->tok]);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->last->line,
+ r->last->col, "%s", roff_name[r->last->tok]);
if (r->eqn != NULL) {
- mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ mandoc_msg(MANDOCERR_BLK_NOEND,
r->eqn->node->line, r->eqn->node->pos, "EQ");
eqn_parse(r->eqn);
r->eqn = NULL;
}
if (r->tbl != NULL) {
- mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
- r->tbl->line, r->tbl->pos, "TS");
- tbl_end(r->tbl);
+ tbl_end(r->tbl, 1);
r->tbl = NULL;
}
}
@@ -1680,7 +1964,7 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
/* --- handling of request blocks ----------------------------------------- */
-static enum rofferr
+static int
roff_cblock(ROFF_ARGS)
{
@@ -1690,8 +1974,7 @@ roff_cblock(ROFF_ARGS)
*/
if (r->last == NULL) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "..");
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
return ROFF_IGN;
}
@@ -1705,13 +1988,12 @@ roff_cblock(ROFF_ARGS)
case ROFF_ig:
break;
default:
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "..");
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
return ROFF_IGN;
}
if (buf->buf[pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
".. %s", buf->buf + pos);
roffnode_pop(r);
@@ -1720,50 +2002,48 @@ roff_cblock(ROFF_ARGS)
}
-static void
+static int
roffnode_cleanscope(struct roff *r)
{
+ int inloop;
- while (r->last) {
+ inloop = 0;
+ while (r->last != NULL) {
if (--r->last->endspan != 0)
break;
- roffnode_pop(r);
+ inloop += roffnode_pop(r);
}
+ return inloop;
}
-static void
+static int
roff_ccond(struct roff *r, int ln, int ppos)
{
-
if (NULL == r->last) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "\\}");
- return;
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
+ return 0;
}
switch (r->last->tok) {
case ROFF_el:
case ROFF_ie:
case ROFF_if:
+ case ROFF_while:
break;
default:
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "\\}");
- return;
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
+ return 0;
}
if (r->last->endspan > -1) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "\\}");
- return;
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "\\}");
+ return 0;
}
- roffnode_pop(r);
- roffnode_cleanscope(r);
- return;
+ return roffnode_pop(r) + roffnode_cleanscope(r);
}
-static enum rofferr
+static int
roff_block(ROFF_ARGS)
{
const char *name, *value;
@@ -1800,8 +2080,8 @@ roff_block(ROFF_ARGS)
deftype = ROFFDEF_USER;
name = roff_getstrn(r, iname, namesz, &deftype);
if (name == NULL) {
- mandoc_vmsg(MANDOCERR_STR_UNDEF,
- r->parse, ln, (int)(iname - buf->buf),
+ mandoc_msg(MANDOCERR_STR_UNDEF,
+ ln, (int)(iname - buf->buf),
"%.*s", (int)namesz, iname);
namesz = 0;
} else
@@ -1810,8 +2090,8 @@ roff_block(ROFF_ARGS)
name = iname;
if (namesz == 0 && tok != ROFF_ig) {
- mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
- ln, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
+ ln, ppos, "%s", roff_name[tok]);
return ROFF_IGN;
}
@@ -1869,8 +2149,8 @@ roff_block(ROFF_ARGS)
deftype = ROFFDEF_USER;
name = roff_getstrn(r, iname, namesz, &deftype);
if (name == NULL) {
- mandoc_vmsg(MANDOCERR_STR_UNDEF,
- r->parse, ln, (int)(iname - buf->buf),
+ mandoc_msg(MANDOCERR_STR_UNDEF,
+ ln, (int)(iname - buf->buf),
"%.*s", (int)namesz, iname);
namesz = 0;
} else
@@ -1882,13 +2162,13 @@ roff_block(ROFF_ARGS)
r->last->end = mandoc_strndup(name, namesz);
if (*cp != '\0')
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
ln, pos, ".%s ... %s", roff_name[tok], cp);
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_block_sub(ROFF_ARGS)
{
enum roff_tok t;
@@ -1942,7 +2222,7 @@ roff_block_sub(ROFF_ARGS)
return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
}
-static enum rofferr
+static int
roff_block_text(ROFF_ARGS)
{
@@ -1952,15 +2232,19 @@ roff_block_text(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_cond_sub(ROFF_ARGS)
{
- enum roff_tok t;
char *ep;
- int rr;
+ int endloop, irc, rr;
+ enum roff_tok t;
+ irc = ROFF_IGN;
rr = r->last->rule;
- roffnode_cleanscope(r);
+ endloop = tok != ROFF_while ? ROFF_IGN :
+ rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT;
+ if (roffnode_cleanscope(r))
+ irc |= endloop;
/*
* If `\}' occurs on a macro line without a preceding macro,
@@ -1971,13 +2255,17 @@ roff_cond_sub(ROFF_ARGS)
if (ep[0] == '\\' && ep[1] == '}')
rr = 0;
- /* Always check for the closing delimiter `\}'. */
+ /*
+ * The closing delimiter `\}' rewinds the conditional scope
+ * but is otherwise ignored when interpreting the line.
+ */
while ((ep = strchr(ep, '\\')) != NULL) {
switch (ep[1]) {
case '}':
memmove(ep, ep + 2, strlen(ep + 2) + 1);
- roff_ccond(r, ln, ep - buf->buf);
+ if (roff_ccond(r, ln, ep - buf->buf))
+ irc |= endloop;
break;
case '\0':
++ep;
@@ -1994,30 +2282,57 @@ roff_cond_sub(ROFF_ARGS)
*/
t = roff_parse(r, buf->buf, &pos, ln, ppos);
- return t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT)
- ? (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : rr
- ? ROFF_CONT : ROFF_IGN;
+ irc |= t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) ?
+ (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) :
+ rr ? ROFF_CONT : ROFF_IGN;
+ return irc;
}
-static enum rofferr
+static int
roff_cond_text(ROFF_ARGS)
{
char *ep;
- int rr;
+ int endloop, irc, rr;
+ irc = ROFF_IGN;
rr = r->last->rule;
- roffnode_cleanscope(r);
+ endloop = tok != ROFF_while ? ROFF_IGN :
+ rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT;
+ if (roffnode_cleanscope(r))
+ irc |= endloop;
+
+ /*
+ * If `\}' occurs on a text line with neither preceding
+ * nor following characters, drop the line completely.
+ */
ep = buf->buf + pos;
+ if (strcmp(ep, "\\}") == 0)
+ rr = 0;
+
+ /*
+ * The closing delimiter `\}' rewinds the conditional scope
+ * but is otherwise ignored when interpreting the line.
+ */
+
while ((ep = strchr(ep, '\\')) != NULL) {
- if (*(++ep) == '}') {
- *ep = '&';
- roff_ccond(r, ln, ep - buf->buf - 1);
- }
- if (*ep != '\0')
+ switch (ep[1]) {
+ case '}':
+ memmove(ep, ep + 2, strlen(ep + 2) + 1);
+ if (roff_ccond(r, ln, ep - buf->buf))
+ irc |= endloop;
+ break;
+ case '\0':
++ep;
+ break;
+ default:
+ ep += 2;
+ break;
+ }
}
- return rr ? ROFF_CONT : ROFF_IGN;
+ if (rr)
+ irc |= ROFF_CONT;
+ return irc;
}
/* --- handling of numeric and conditional expressions -------------------- */
@@ -2144,9 +2459,10 @@ out:
static int
roff_evalcond(struct roff *r, int ln, char *v, int *pos)
{
- char *cp, *name;
- size_t sz;
- int deftype, number, savepos, istrue, wanttrue;
+ const char *start, *end;
+ char *cp, *name;
+ size_t sz;
+ int deftype, len, number, savepos, istrue, wanttrue;
if ('!' == v[*pos]) {
wanttrue = 0;
@@ -2161,12 +2477,50 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos)
case 'o':
(*pos)++;
return wanttrue;
- case 'c':
case 'e':
case 't':
case 'v':
(*pos)++;
return !wanttrue;
+ case 'c':
+ do {
+ (*pos)++;
+ } while (v[*pos] == ' ');
+
+ /*
+ * Quirk for groff compatibility:
+ * The horizontal tab is neither available nor unavailable.
+ */
+
+ if (v[*pos] == '\t') {
+ (*pos)++;
+ return 0;
+ }
+
+ /* Printable ASCII characters are available. */
+
+ if (v[*pos] != '\\') {
+ (*pos)++;
+ return wanttrue;
+ }
+
+ end = v + ++*pos;
+ switch (mandoc_escape(&end, &start, &len)) {
+ case ESCAPE_SPECIAL:
+ istrue = mchars_spec2cp(start, len) != -1;
+ break;
+ case ESCAPE_UNICODE:
+ istrue = 1;
+ break;
+ case ESCAPE_NUMBERED:
+ istrue = mchars_num2char(start, len) != -1;
+ break;
+ default:
+ istrue = !wanttrue;
+ break;
+ }
+ *pos = end - v;
+ return istrue == wanttrue;
case 'd':
case 'r':
cp = v + *pos + 1;
@@ -2183,7 +2537,7 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos)
roff_getstrn(r, name, sz, &deftype);
istrue = !!deftype;
}
- *pos = cp - v;
+ *pos = (name + sz) - v;
return istrue == wanttrue;
default:
break;
@@ -2198,34 +2552,33 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos)
return 0;
}
-static enum rofferr
+static int
roff_line_ignore(ROFF_ARGS)
{
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_insec(ROFF_ARGS)
{
- mandoc_msg(MANDOCERR_REQ_INSEC, r->parse,
- ln, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_REQ_INSEC, ln, ppos, "%s", roff_name[tok]);
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_unsupp(ROFF_ARGS)
{
- mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse,
- ln, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_REQ_UNSUPP, ln, ppos, "%s", roff_name[tok]);
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_cond(ROFF_ARGS)
{
+ int irc;
roffnode_push(r, tok, NULL, ln, ppos);
@@ -2264,9 +2617,10 @@ roff_cond(ROFF_ARGS)
* Determine scope.
* If there is nothing on the line after the conditional,
* not even whitespace, use next-line scope.
+ * Except that .while does not support next-line scope.
*/
- if (buf->buf[pos] == '\0') {
+ if (buf->buf[pos] == '\0' && tok != ROFF_while) {
r->last->endspan = 2;
goto out;
}
@@ -2291,17 +2645,20 @@ roff_cond(ROFF_ARGS)
*/
if (buf->buf[pos] == '\0')
- mandoc_msg(MANDOCERR_COND_EMPTY, r->parse,
- ln, ppos, roff_name[tok]);
+ mandoc_msg(MANDOCERR_COND_EMPTY,
+ ln, ppos, "%s", roff_name[tok]);
r->last->endspan = 1;
out:
*offs = pos;
- return ROFF_RERUN;
+ irc = ROFF_RERUN;
+ if (tok == ROFF_while)
+ irc |= ROFF_WHILE;
+ return irc;
}
-static enum rofferr
+static int
roff_ds(ROFF_ARGS)
{
char *string;
@@ -2326,8 +2683,15 @@ roff_ds(ROFF_ARGS)
return ROFF_IGN;
namesz = roff_getname(r, &string, ln, pos);
- if (name[namesz] == '\\')
+ switch (name[namesz]) {
+ case '\\':
return ROFF_IGN;
+ case '\t':
+ string = buf->buf + pos + namesz;
+ break;
+ default:
+ break;
+ }
/* Read past the initial double-quote, if any. */
if (*string == '"')
@@ -2492,7 +2856,7 @@ roff_evalnum(struct roff *r, int ln, const char *v,
case '/':
if (operand2 == 0) {
mandoc_msg(MANDOCERR_DIVZERO,
- r->parse, ln, *pos, v);
+ ln, *pos, "%s", v);
*res = 0;
break;
}
@@ -2501,7 +2865,7 @@ roff_evalnum(struct roff *r, int ln, const char *v,
case '%':
if (operand2 == 0) {
mandoc_msg(MANDOCERR_DIVZERO,
- r->parse, ln, *pos, v);
+ ln, *pos, "%s", v);
*res = 0;
break;
}
@@ -2600,7 +2964,7 @@ roff_getregro(const struct roff *r, const char *name)
switch (*name) {
case '$': /* Number of arguments of the last macro evaluated. */
- return r->argc;
+ return r->mstackpos < 0 ? 0 : r->mstack[r->mstackpos].argc;
case 'A': /* ASCII approximation mode is always off. */
return 0;
case 'g': /* Groff compatibility mode is always on. */
@@ -2690,7 +3054,7 @@ roff_freereg(struct roffreg *reg)
}
}
-static enum rofferr
+static int
roff_nr(ROFF_ARGS)
{
char *key, *val, *step;
@@ -2703,7 +3067,7 @@ roff_nr(ROFF_ARGS)
return ROFF_IGN;
keysz = roff_getname(r, &val, ln, pos);
- if (key[keysz] == '\\')
+ if (key[keysz] == '\\' || key[keysz] == '\t')
return ROFF_IGN;
sign = *val;
@@ -2724,7 +3088,7 @@ roff_nr(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_rr(ROFF_ARGS)
{
struct roffreg *reg, **prev;
@@ -2754,7 +3118,7 @@ roff_rr(ROFF_ARGS)
/* --- handler functions for roff requests -------------------------------- */
-static enum rofferr
+static int
roff_rm(ROFF_ARGS)
{
const char *name;
@@ -2767,13 +3131,13 @@ roff_rm(ROFF_ARGS)
namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0);
- if (name[namesz] == '\\')
+ if (name[namesz] == '\\' || name[namesz] == '\t')
break;
}
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_it(ROFF_ARGS)
{
int iv;
@@ -2781,8 +3145,8 @@ roff_it(ROFF_ARGS)
/* Parse the number of lines. */
if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
- mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
- ln, ppos, buf->buf + 1);
+ mandoc_msg(MANDOCERR_IT_NONUM,
+ ln, ppos, "%s", buf->buf + 1);
return ROFF_IGN;
}
@@ -2802,7 +3166,7 @@ roff_it(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_Dd(ROFF_ARGS)
{
int mask;
@@ -2832,15 +3196,15 @@ roff_Dd(ROFF_ARGS)
return ROFF_CONT;
}
-static enum rofferr
+static int
roff_TE(ROFF_ARGS)
{
+ r->man->flags &= ~ROFF_NONOFILL;
if (r->tbl == NULL) {
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "TE");
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "TE");
return ROFF_IGN;
}
- if (tbl_end(r->tbl) == 0) {
+ if (tbl_end(r->tbl, 0) == 0) {
r->tbl = NULL;
free(buf->buf);
buf->buf = mandoc_strdup(".sp");
@@ -2852,13 +3216,12 @@ roff_TE(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_T_(ROFF_ARGS)
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
- ln, ppos, "T&");
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "T&");
else
tbl_restart(ln, ppos, r->tbl);
@@ -2868,7 +3231,7 @@ roff_T_(ROFF_ARGS)
/*
* Handle in-line equation delimiters.
*/
-static enum rofferr
+static int
roff_eqndelim(struct roff *r, struct buf *buf, int pos)
{
char *cp1, *cp2;
@@ -2931,68 +3294,85 @@ roff_eqndelim(struct roff *r, struct buf *buf, int pos)
return ROFF_REPARSE;
}
-static enum rofferr
+static int
roff_EQ(ROFF_ARGS)
{
struct roff_node *n;
- if (r->man->macroset == MACROSET_MAN)
+ if (r->man->meta.macroset == MACROSET_MAN)
man_breakscope(r->man, ROFF_EQ);
n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE);
if (ln > r->man->last->line)
n->flags |= NODE_LINE;
- n->eqn = mandoc_calloc(1, sizeof(*n->eqn));
- n->eqn->expectargs = UINT_MAX;
+ n->eqn = eqn_box_new();
roff_node_append(r->man, n);
r->man->next = ROFF_NEXT_SIBLING;
assert(r->eqn == NULL);
if (r->last_eqn == NULL)
- r->last_eqn = eqn_alloc(r->parse);
+ r->last_eqn = eqn_alloc();
else
eqn_reset(r->last_eqn);
r->eqn = r->last_eqn;
r->eqn->node = n;
if (buf->buf[pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
".EQ %s", buf->buf + pos);
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_EN(ROFF_ARGS)
{
if (r->eqn != NULL) {
eqn_parse(r->eqn);
r->eqn = NULL;
} else
- mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "EN");
if (buf->buf[pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
"EN %s", buf->buf + pos);
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_TS(ROFF_ARGS)
{
if (r->tbl != NULL) {
- mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
- ln, ppos, "TS breaks TS");
- tbl_end(r->tbl);
+ mandoc_msg(MANDOCERR_BLK_BROKEN, ln, ppos, "TS breaks TS");
+ tbl_end(r->tbl, 0);
}
- r->tbl = tbl_alloc(ppos, ln, r->parse);
- if (r->last_tbl)
- r->last_tbl->next = r->tbl;
- else
+ r->man->flags |= ROFF_NONOFILL;
+ r->tbl = tbl_alloc(ppos, ln, r->last_tbl);
+ if (r->last_tbl == NULL)
r->first_tbl = r->tbl;
r->last_tbl = r->tbl;
return ROFF_IGN;
}
-static enum rofferr
+static int
+roff_noarg(ROFF_ARGS)
+{
+ if (r->man->flags & (MAN_BLINE | MAN_ELINE))
+ man_breakscope(r->man, tok);
+ if (tok == ROFF_brp)
+ tok = ROFF_br;
+ roff_elem_alloc(r->man, ln, ppos, tok);
+ if (buf->buf[pos] != '\0')
+ mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
+ "%s %s", roff_name[tok], buf->buf + pos);
+ if (tok == ROFF_nf)
+ r->man->flags |= ROFF_NOFILL;
+ else if (tok == ROFF_fi)
+ r->man->flags &= ~ROFF_NOFILL;
+ r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
+ r->man->next = ROFF_NEXT_SIBLING;
+ return ROFF_IGN;
+}
+
+static int
roff_onearg(ROFF_ARGS)
{
struct roff_node *n;
@@ -3019,8 +3399,8 @@ roff_onearg(ROFF_ARGS)
while (*cp == ' ')
*cp++ = '\0';
if (*cp != '\0')
- mandoc_vmsg(MANDOCERR_ARG_EXCESS,
- r->parse, ln, cp - buf->buf,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
+ ln, (int)(cp - buf->buf),
"%s ... %s", roff_name[tok], cp);
roff_word_alloc(r->man, ln, pos, buf->buf + pos);
}
@@ -3033,8 +3413,8 @@ roff_onearg(ROFF_ARGS)
npos = 0;
if (roff_evalnum(r, ln, r->man->last->string, &npos,
&roffce_lines, 0) == 0) {
- mandoc_vmsg(MANDOCERR_CE_NONUM,
- r->parse, ln, pos, "ce %s", buf->buf + pos);
+ mandoc_msg(MANDOCERR_CE_NONUM,
+ ln, pos, "ce %s", buf->buf + pos);
roffce_lines = 1;
}
if (roffce_lines < 1) {
@@ -3052,7 +3432,7 @@ roff_onearg(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_manyarg(ROFF_ARGS)
{
struct roff_node *n;
@@ -3075,7 +3455,7 @@ roff_manyarg(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_als(ROFF_ARGS)
{
char *oldn, *newn, *end, *value;
@@ -3086,7 +3466,7 @@ roff_als(ROFF_ARGS)
return ROFF_IGN;
newsz = roff_getname(r, &oldn, ln, pos);
- if (newn[newsz] == '\\' || *oldn == '\0')
+ if (newn[newsz] == '\\' || newn[newsz] == '\t' || *oldn == '\0')
return ROFF_IGN;
end = oldn;
@@ -3094,7 +3474,7 @@ roff_als(ROFF_ARGS)
if (oldsz == 0)
return ROFF_IGN;
- valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n",
+ valsz = mandoc_asprintf(&value, ".%.*s \\$@\\\"\n",
(int)oldsz, oldn);
roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0);
roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
@@ -3102,21 +3482,7 @@ roff_als(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
-roff_br(ROFF_ARGS)
-{
- if (r->man->flags & (MAN_BLINE | MAN_ELINE))
- man_breakscope(r->man, ROFF_br);
- roff_elem_alloc(r->man, ln, ppos, ROFF_br);
- if (buf->buf[pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
- "%s %s", roff_name[tok], buf->buf + pos);
- r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
- r->man->next = ROFF_NEXT_SIBLING;
- return ROFF_IGN;
-}
-
-static enum rofferr
+static int
roff_cc(ROFF_ARGS)
{
const char *p;
@@ -3127,13 +3493,83 @@ roff_cc(ROFF_ARGS)
r->control = '\0';
if (*p != '\0')
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ mandoc_msg(MANDOCERR_ARG_EXCESS,
ln, p - buf->buf, "cc ... %s", p);
return ROFF_IGN;
}
-static enum rofferr
+static int
+roff_char(ROFF_ARGS)
+{
+ const char *p, *kp, *vp;
+ size_t ksz, vsz;
+ int font;
+
+ /* Parse the character to be replaced. */
+
+ kp = buf->buf + pos;
+ p = kp + 1;
+ if (*kp == '\0' || (*kp == '\\' &&
+ mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) ||
+ (*p != ' ' && *p != '\0')) {
+ mandoc_msg(MANDOCERR_CHAR_ARG, ln, pos, "char %s", kp);
+ return ROFF_IGN;
+ }
+ ksz = p - kp;
+ while (*p == ' ')
+ p++;
+
+ /*
+ * If the replacement string contains a font escape sequence,
+ * we have to restore the font at the end.
+ */
+
+ vp = p;
+ vsz = strlen(p);
+ font = 0;
+ while (*p != '\0') {
+ if (*p++ != '\\')
+ continue;
+ switch (mandoc_escape(&p, NULL, NULL)) {
+ case ESCAPE_FONT:
+ case ESCAPE_FONTROMAN:
+ case ESCAPE_FONTITALIC:
+ case ESCAPE_FONTBOLD:
+ case ESCAPE_FONTBI:
+ case ESCAPE_FONTCW:
+ case ESCAPE_FONTPREV:
+ font++;
+ break;
+ default:
+ break;
+ }
+ }
+ if (font > 1)
+ mandoc_msg(MANDOCERR_CHAR_FONT,
+ ln, (int)(vp - buf->buf), "%s", vp);
+
+ /*
+ * Approximate the effect of .char using the .tr tables.
+ * XXX In groff, .char and .tr interact differently.
+ */
+
+ if (ksz == 1) {
+ if (r->xtab == NULL)
+ r->xtab = mandoc_calloc(128, sizeof(*r->xtab));
+ assert((unsigned int)*kp < 128);
+ free(r->xtab[(int)*kp].p);
+ r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p,
+ "%s%s", vp, font ? "\fP" : "");
+ } else {
+ roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0);
+ if (font)
+ roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1);
+ }
+ return ROFF_IGN;
+}
+
+static int
roff_ec(ROFF_ARGS)
{
const char *p;
@@ -3144,23 +3580,32 @@ roff_ec(ROFF_ARGS)
else {
r->escape = *p;
if (*++p != '\0')
- mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
- ln, p - buf->buf, "ec ... %s", p);
+ mandoc_msg(MANDOCERR_ARG_EXCESS, ln,
+ (int)(p - buf->buf), "ec ... %s", p);
}
return ROFF_IGN;
}
-static enum rofferr
+static int
roff_eo(ROFF_ARGS)
{
r->escape = '\0';
if (buf->buf[pos] != '\0')
- mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse,
+ mandoc_msg(MANDOCERR_ARG_SKIP,
ln, pos, "eo %s", buf->buf + pos);
return ROFF_IGN;
}
-static enum rofferr
+static int
+roff_nop(ROFF_ARGS)
+{
+ while (buf->buf[pos] == ' ')
+ pos++;
+ *offs = pos;
+ return ROFF_RERUN;
+}
+
+static int
roff_tr(ROFF_ARGS)
{
const char *p, *first, *second;
@@ -3170,7 +3615,7 @@ roff_tr(ROFF_ARGS)
p = buf->buf + pos;
if (*p == '\0') {
- mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr");
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ln, ppos, "tr");
return ROFF_IGN;
}
@@ -3181,8 +3626,8 @@ roff_tr(ROFF_ARGS)
if (*first == '\\') {
esc = mandoc_escape(&p, NULL, NULL);
if (esc == ESCAPE_ERROR) {
- mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
- ln, (int)(p - buf->buf), first);
+ mandoc_msg(MANDOCERR_ESC_BAD, ln,
+ (int)(p - buf->buf), "%s", first);
return ROFF_IGN;
}
fsz = (size_t)(p - first);
@@ -3192,14 +3637,14 @@ roff_tr(ROFF_ARGS)
if (*second == '\\') {
esc = mandoc_escape(&p, NULL, NULL);
if (esc == ESCAPE_ERROR) {
- mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
- ln, (int)(p - buf->buf), second);
+ mandoc_msg(MANDOCERR_ESC_BAD, ln,
+ (int)(p - buf->buf), "%s", second);
return ROFF_IGN;
}
ssz = (size_t)(p - second);
} else if (*second == '\0') {
- mandoc_vmsg(MANDOCERR_TR_ODD, r->parse,
- ln, first - buf->buf, "tr %s", first);
+ mandoc_msg(MANDOCERR_TR_ODD, ln,
+ (int)(first - buf->buf), "tr %s", first);
second = " ";
p--;
}
@@ -3222,7 +3667,23 @@ roff_tr(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+/*
+ * Implementation of the .return request.
+ * There is no need to call roff_userret() from here.
+ * The read module will call that after rewinding the reader stack
+ * to the place from where the current macro was called.
+ */
+static int
+roff_return(ROFF_ARGS)
+{
+ if (r->mstackpos >= 0)
+ return ROFF_IGN | ROFF_USERRET;
+
+ mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "return");
+ return ROFF_IGN;
+}
+
+static int
roff_rn(ROFF_ARGS)
{
const char *value;
@@ -3235,7 +3696,7 @@ roff_rn(ROFF_ARGS)
return ROFF_IGN;
oldsz = roff_getname(r, &newn, ln, pos);
- if (oldn[oldsz] == '\\' || *newn == '\0')
+ if (oldn[oldsz] == '\\' || oldn[oldsz] == '\t' || *newn == '\0')
return ROFF_IGN;
end = newn;
@@ -3272,13 +3733,46 @@ roff_rn(ROFF_ARGS)
return ROFF_IGN;
}
-static enum rofferr
+static int
+roff_shift(ROFF_ARGS)
+{
+ struct mctx *ctx;
+ int levels, i;
+
+ levels = 1;
+ if (buf->buf[pos] != '\0' &&
+ roff_evalnum(r, ln, buf->buf, &pos, &levels, 0) == 0) {
+ mandoc_msg(MANDOCERR_CE_NONUM,
+ ln, pos, "shift %s", buf->buf + pos);
+ levels = 1;
+ }
+ if (r->mstackpos < 0) {
+ mandoc_msg(MANDOCERR_REQ_NOMAC, ln, ppos, "shift");
+ return ROFF_IGN;
+ }
+ ctx = r->mstack + r->mstackpos;
+ if (levels > ctx->argc) {
+ mandoc_msg(MANDOCERR_SHIFT,
+ ln, pos, "%d, but max is %d", levels, ctx->argc);
+ levels = ctx->argc;
+ }
+ if (levels == 0)
+ return ROFF_IGN;
+ for (i = 0; i < levels; i++)
+ free(ctx->argv[i]);
+ ctx->argc -= levels;
+ for (i = 0; i < ctx->argc; i++)
+ ctx->argv[i] = ctx->argv[i + levels];
+ return ROFF_IGN;
+}
+
+static int
roff_so(ROFF_ARGS)
{
char *name, *cp;
name = buf->buf + pos;
- mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
+ mandoc_msg(MANDOCERR_SO, ln, ppos, "so %s", name);
/*
* Handle `so'. Be EXTREMELY careful, as we shouldn't be
@@ -3288,8 +3782,7 @@ roff_so(ROFF_ARGS)
*/
if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
- mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
- ".so %s", name);
+ mandoc_msg(MANDOCERR_SO_PATH, ln, ppos, ".so %s", name);
buf->sz = mandoc_asprintf(&cp,
".sp\nSee the file %s.\n.sp", name) + 1;
free(buf->buf);
@@ -3304,154 +3797,69 @@ roff_so(ROFF_ARGS)
/* --- user defined strings and macros ------------------------------------ */
-static enum rofferr
+static int
roff_userdef(ROFF_ARGS)
{
- const char *arg[16], *ap;
- char *cp, *n1, *n2;
- int expand_count, i, ib, ie;
- size_t asz, rsz;
+ struct mctx *ctx;
+ char *arg, *ap, *dst, *src;
+ size_t sz;
- /*
- * Collect pointers to macro argument strings
- * and NUL-terminate them.
- */
+ /* Initialize a new macro stack context. */
- r->argc = 0;
- cp = buf->buf + pos;
- for (i = 0; i < 16; i++) {
- if (*cp == '\0')
- arg[i] = "";
- else {
- arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos);
- r->argc = i + 1;
- }
+ if (++r->mstackpos == r->mstacksz) {
+ r->mstack = mandoc_recallocarray(r->mstack,
+ r->mstacksz, r->mstacksz + 8, sizeof(*r->mstack));
+ r->mstacksz += 8;
}
+ ctx = r->mstack + r->mstackpos;
+ ctx->argsz = 0;
+ ctx->argc = 0;
+ ctx->argv = NULL;
/*
- * Expand macro arguments.
+ * Collect pointers to macro argument strings,
+ * NUL-terminating them and escaping quotes.
*/
- buf->sz = strlen(r->current_string) + 1;
- n1 = n2 = cp = mandoc_malloc(buf->sz);
- memcpy(n1, r->current_string, buf->sz);
- expand_count = 0;
- while (*cp != '\0') {
-
- /* Scan ahead for the next argument invocation. */
-
- if (*cp++ != '\\')
- continue;
- if (*cp++ != '$')
- continue;
- if (*cp == '*') { /* \\$* inserts all arguments */
- ib = 0;
- ie = r->argc - 1;
- } else { /* \\$1 .. \\$9 insert one argument */
- ib = ie = *cp - '1';
- if (ib < 0 || ib > 8)
- continue;
- }
- cp -= 2;
-
- /*
- * Prevent infinite recursion.
- */
-
- if (cp >= n2)
- expand_count = 1;
- else if (++expand_count > EXPAND_LIMIT) {
- mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
- ln, (int)(cp - n1), NULL);
- free(buf->buf);
- buf->buf = n1;
- *offs = 0;
- return ROFF_IGN;
- }
-
- /*
- * Determine the size of the expanded argument,
- * taking escaping of quotes into account.
- */
-
- asz = ie > ib ? ie - ib : 0; /* for blanks */
- for (i = ib; i <= ie; i++) {
- for (ap = arg[i]; *ap != '\0'; ap++) {
- asz++;
- if (*ap == '"')
- asz += 3;
- }
- }
- if (asz != 3) {
-
- /*
- * Determine the size of the rest of the
- * unexpanded macro, including the NUL.
- */
-
- rsz = buf->sz - (cp - n1) - 3;
-
- /*
- * When shrinking, move before
- * releasing the storage.
- */
-
- if (asz < 3)
- memmove(cp + asz, cp + 3, rsz);
-
- /*
- * Resize the storage for the macro
- * and readjust the parse pointer.
- */
-
- buf->sz += asz - 3;
- n2 = mandoc_realloc(n1, buf->sz);
- cp = n2 + (cp - n1);
- n1 = n2;
-
- /*
- * When growing, make room
- * for the expanded argument.
- */
-
- if (asz > 3)
- memmove(cp + asz, cp + 3, rsz);
+ src = buf->buf + pos;
+ while (*src != '\0') {
+ if (ctx->argc == ctx->argsz) {
+ ctx->argsz += 8;
+ ctx->argv = mandoc_reallocarray(ctx->argv,
+ ctx->argsz, sizeof(*ctx->argv));
}
-
- /* Copy the expanded argument, escaping quotes. */
-
- n2 = cp;
- for (i = ib; i <= ie; i++) {
- for (ap = arg[i]; *ap != '\0'; ap++) {
- if (*ap == '"') {
- memcpy(n2, "\\(dq", 4);
- n2 += 4;
- } else
- *n2++ = *ap;
- }
- if (i < ie)
- *n2++ = ' ';
+ arg = roff_getarg(r, &src, ln, &pos);
+ sz = 1; /* For the terminating NUL. */
+ for (ap = arg; *ap != '\0'; ap++)
+ sz += *ap == '"' ? 4 : 1;
+ ctx->argv[ctx->argc++] = dst = mandoc_malloc(sz);
+ for (ap = arg; *ap != '\0'; ap++) {
+ if (*ap == '"') {
+ memcpy(dst, "\\(dq", 4);
+ dst += 4;
+ } else
+ *dst++ = *ap;
}
+ *dst = '\0';
+ free(arg);
}
- /*
- * Replace the macro invocation
- * by the expanded macro.
- */
+ /* Replace the macro invocation by the macro definition. */
free(buf->buf);
- buf->buf = n1;
+ buf->buf = mandoc_strdup(r->current_string);
+ buf->sz = strlen(buf->buf) + 1;
*offs = 0;
return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
- ROFF_REPARSE : ROFF_APPEND;
+ ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND;
}
/*
* Calling a high-level macro that was renamed with .rn.
* r->current_string has already been set up by roff_parse().
*/
-static enum rofferr
+static int
roff_renamed(ROFF_ARGS)
{
char *nbuf;
@@ -3464,6 +3872,10 @@ roff_renamed(ROFF_ARGS)
return ROFF_CONT;
}
+/*
+ * Measure the length in bytes of the roff identifier at *cpp
+ * and advance the pointer to the next word.
+ */
static size_t
roff_getname(struct roff *r, char **cpp, int ln, int pos)
{
@@ -3471,31 +3883,34 @@ roff_getname(struct roff *r, char **cpp, int ln, int pos)
size_t namesz;
name = *cpp;
- if ('\0' == *name)
+ if (*name == '\0')
return 0;
- /* Read until end of name and terminate it with NUL. */
+ /* Advance cp to the byte after the end of the name. */
+
for (cp = name; 1; cp++) {
- if ('\0' == *cp || ' ' == *cp) {
- namesz = cp - name;
+ namesz = cp - name;
+ if (*cp == '\0')
+ break;
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
break;
}
- if ('\\' != *cp)
+ if (*cp != '\\')
continue;
- namesz = cp - name;
- if ('{' == cp[1] || '}' == cp[1])
+ if (cp[1] == '{' || cp[1] == '}')
break;
- cp++;
- if ('\\' == *cp)
+ if (*++cp == '\\')
continue;
- mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
+ mandoc_msg(MANDOCERR_NAMESC, ln, pos,
"%.*s", (int)(cp - name + 1), name);
mandoc_escape((const char **)&cp, NULL, NULL);
break;
}
/* Read past spaces. */
- while (' ' == *cp)
+
+ while (*cp == ' ')
cp++;
*cpp = cp;
@@ -3638,7 +4053,7 @@ roff_getstrn(struct roff *r, const char *name, size_t len,
break;
}
}
- if (r->man->macroset != MACROSET_MAN) {
+ if (r->man->meta.macroset != MACROSET_MAN) {
for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
if (strncmp(name, roff_name[tok], len) != 0 ||
roff_name[tok][len] != '\0')
@@ -3652,7 +4067,7 @@ roff_getstrn(struct roff *r, const char *name, size_t len,
}
}
}
- if (r->man->macroset != MACROSET_MDOC) {
+ if (r->man->meta.macroset != MACROSET_MDOC) {
for (tok = MAN_TH; tok < MAN_MAX; tok++) {
if (strncmp(name, roff_name[tok], len) != 0 ||
roff_name[tok][len] != '\0')
@@ -3783,7 +4198,7 @@ roff_strdup(const struct roff *r, const char *p)
/*
* We bail out on bad escapes.
* No need to warn: we already did so when
- * roff_res() was called.
+ * roff_expand() was called.
*/
sz = (int)(p - pp);
res = mandoc_realloc(res, ssz + sz + 1);
diff --git a/usr/src/cmd/mandoc/roff.h b/usr/src/cmd/mandoc/roff.h
index f0da74bd9a..49b0927513 100644
--- a/usr/src/cmd/mandoc/roff.h
+++ b/usr/src/cmd/mandoc/roff.h
@@ -1,7 +1,7 @@
-/* $Id: roff.h,v 1.59 2018/04/11 17:11:13 schwarze Exp $ */
+/* $Id: roff.h,v 1.69 2019/03/04 13:01:57 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,11 +14,15 @@
* 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.
+ *
+ * Common data types for all syntax trees and related functions.
*/
struct ohash;
struct mdoc_arg;
union mdoc_data;
+struct tbl_span;
+struct eqn_box;
enum roff_macroset {
MACROSET_NONE = 0,
@@ -69,9 +73,11 @@ enum roff_type {
enum roff_tok {
ROFF_br = 0,
ROFF_ce,
+ ROFF_fi,
ROFF_ft,
ROFF_ll,
ROFF_mc,
+ ROFF_nf,
ROFF_po,
ROFF_rj,
ROFF_sp,
@@ -156,7 +162,6 @@ enum roff_tok {
ROFF_fcolor,
ROFF_fdeferlig,
ROFF_feature,
- /* MAN_fi; ignored in mdoc(7) */
ROFF_fkern,
ROFF_fl,
ROFF_flig,
@@ -216,7 +221,6 @@ enum roff_tok {
ROFF_mso,
ROFF_na,
ROFF_ne,
- /* MAN_nf; ignored in mdoc(7) */
ROFF_nh,
ROFF_nhychar,
ROFF_nm,
@@ -438,6 +442,7 @@ enum roff_tok {
MAN_SH,
MAN_SS,
MAN_TP,
+ MAN_TQ,
MAN_LP,
MAN_PP,
MAN_P,
@@ -454,8 +459,6 @@ enum roff_tok {
MAN_I,
MAN_IR,
MAN_RI,
- MAN_nf,
- MAN_fi,
MAN_RE,
MAN_RS,
MAN_DT,
@@ -463,6 +466,8 @@ enum roff_tok {
MAN_PD,
MAN_AT,
MAN_in,
+ MAN_SY,
+ MAN_YS,
MAN_OP,
MAN_EX,
MAN_EE,
@@ -473,11 +478,6 @@ enum roff_tok {
MAN_MAX
};
-enum roff_next {
- ROFF_NEXT_SIBLING = 0,
- ROFF_NEXT_CHILD
-};
-
/*
* Indicates that a BODY's formatting has ended, but
* the scope is still open. Used for badly nested blocks.
@@ -487,6 +487,12 @@ enum mdoc_endbody {
ENDBODY_SPACE /* Is broken: append a space. */
};
+enum mandoc_os {
+ MANDOC_OS_OTHER = 0,
+ MANDOC_OS_NETBSD,
+ MANDOC_OS_OPENBSD
+};
+
struct roff_node {
struct roff_node *parent; /* Parent AST node. */
struct roff_node *child; /* First child AST node. */
@@ -499,21 +505,22 @@ struct roff_node {
struct mdoc_arg *args; /* BLOCK/ELEM */
union mdoc_data *norm; /* Normalized arguments. */
char *string; /* TEXT */
- const struct tbl_span *span; /* TBL */
+ struct tbl_span *span; /* TBL */
struct eqn_box *eqn; /* EQN */
int line; /* Input file line number. */
int pos; /* Input file column number. */
int flags;
#define NODE_VALID (1 << 0) /* Has been validated. */
#define NODE_ENDED (1 << 1) /* Gone past body end mark. */
-#define NODE_EOS (1 << 2) /* At sentence boundary. */
+#define NODE_BROKEN (1 << 2) /* Must validate parent when ending. */
#define NODE_LINE (1 << 3) /* First macro/text on line. */
-#define NODE_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting. */
-#define NODE_BROKEN (1 << 5) /* Must validate parent when ending. */
-#define NODE_DELIMO (1 << 6)
-#define NODE_DELIMC (1 << 7)
-#define NODE_NOSRC (1 << 8) /* Generated node, not in input file. */
-#define NODE_NOPRT (1 << 9) /* Shall not print anything. */
+#define NODE_DELIMO (1 << 4)
+#define NODE_DELIMC (1 << 5)
+#define NODE_EOS (1 << 6) /* At sentence boundary. */
+#define NODE_SYNPRETTY (1 << 7) /* SYNOPSIS-style formatting. */
+#define NODE_NOFILL (1 << 8) /* Fill mode switched off. */
+#define NODE_NOSRC (1 << 9) /* Generated node, not in input file. */
+#define NODE_NOPRT (1 << 10) /* Shall not print anything. */
int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */
enum roff_tok tok; /* Request or macro ID. */
@@ -523,6 +530,7 @@ struct roff_node {
};
struct roff_meta {
+ struct roff_node *first; /* The first node parsed. */
char *msec; /* Manual section, usually a digit. */
char *vol; /* Manual volume title. */
char *os; /* Operating system. */
@@ -530,51 +538,15 @@ struct roff_meta {
char *title; /* Manual title, usually CAPS. */
char *name; /* Leading manual name. */
char *date; /* Normalized date. */
+ char *sodest; /* .so target file name or NULL. */
int hasbody; /* Document is not empty. */
int rcsids; /* Bits indexed by enum mandoc_os. */
enum mandoc_os os_e; /* Operating system. */
-};
-
-struct roff_man {
- struct roff_meta meta; /* Document meta-data. */
- struct mparse *parse; /* Parse pointer. */
- struct roff *roff; /* Roff parser state data. */
- struct ohash *mdocmac; /* Mdoc macro lookup table. */
- struct ohash *manmac; /* Man macro lookup table. */
- const char *os_s; /* Default operating system. */
- struct roff_node *first; /* The first node parsed. */
- struct roff_node *last; /* The last node parsed. */
- struct roff_node *last_es; /* The most recent Es node. */
- int quick; /* Abort parse early. */
- int flags; /* Parse flags. */
-#define MDOC_LITERAL (1 << 1) /* In a literal scope. */
-#define MDOC_PBODY (1 << 2) /* In the document body. */
-#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */
-#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */
-#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */
-#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */
-#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */
-#define MDOC_KEEP (1 << 8) /* In a word keep. */
-#define MDOC_SMOFF (1 << 9) /* Spacing is off. */
-#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */
-#define MAN_ELINE (1 << 11) /* Next-line element scope. */
-#define MAN_BLINE (1 << 12) /* Next-line block scope. */
-#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */
-#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */
-#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */
-#define MAN_LITERAL MDOC_LITERAL
-#define MAN_NEWLINE MDOC_NEWLINE
enum roff_macroset macroset; /* Kind of high-level macros used. */
- enum roff_sec lastsec; /* Last section seen. */
- enum roff_sec lastnamed; /* Last standard section seen. */
- enum roff_next next; /* Where to put the next node. */
};
extern const char *const *roff_name;
+int arch_valid(const char *, enum mandoc_os);
void deroff(char **, const struct roff_node *);
-struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok);
-enum roff_tok roffhash_find(struct ohash *, const char *, size_t);
-void roffhash_free(struct ohash *);
-void roff_validate(struct roff_man *);
diff --git a/usr/src/cmd/mandoc/roff_html.c b/usr/src/cmd/mandoc/roff_html.c
index 6a06c0d878..02b8beea3b 100644
--- a/usr/src/cmd/mandoc/roff_html.c
+++ b/usr/src/cmd/mandoc/roff_html.c
@@ -1,7 +1,7 @@
-/* $Id: roff_html.c,v 1.12 2018/06/25 14:53:58 schwarze Exp $ */
+/* $Id: roff_html.c,v 1.19 2019/01/07 07:26:29 schwarze Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2017, 2018, 2019 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
@@ -18,7 +18,8 @@
#include <sys/types.h>
#include <assert.h>
-#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include "mandoc.h"
#include "roff.h"
@@ -31,14 +32,19 @@ typedef void (*roff_html_pre_fp)(ROFF_HTML_ARGS);
static void roff_html_pre_br(ROFF_HTML_ARGS);
static void roff_html_pre_ce(ROFF_HTML_ARGS);
+static void roff_html_pre_fi(ROFF_HTML_ARGS);
+static void roff_html_pre_ft(ROFF_HTML_ARGS);
+static void roff_html_pre_nf(ROFF_HTML_ARGS);
static void roff_html_pre_sp(ROFF_HTML_ARGS);
static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = {
roff_html_pre_br, /* br */
roff_html_pre_ce, /* ce */
- NULL, /* ft */
+ roff_html_pre_fi, /* fi */
+ roff_html_pre_ft, /* ft */
NULL, /* ll */
NULL, /* mc */
+ roff_html_pre_nf, /* nf */
NULL, /* po */
roff_html_pre_ce, /* rj */
roff_html_pre_sp, /* sp */
@@ -58,11 +64,7 @@ roff_html_pre(struct html *h, const struct roff_node *n)
static void
roff_html_pre_br(ROFF_HTML_ARGS)
{
- struct tag *t;
-
- t = print_otag(h, TAG_DIV, "");
- print_text(h, "\\~"); /* So the div isn't empty. */
- print_tagq(h, t);
+ print_otag(h, TAG_BR, "");
}
static void
@@ -80,7 +82,36 @@ roff_html_pre_ce(ROFF_HTML_ARGS)
}
static void
+roff_html_pre_fi(ROFF_HTML_ARGS)
+{
+ if (html_fillmode(h, TOKEN_NONE) == ROFF_fi)
+ print_otag(h, TAG_BR, "");
+}
+
+static void
+roff_html_pre_ft(ROFF_HTML_ARGS)
+{
+ const char *cp;
+
+ cp = n->child->string;
+ print_metaf(h, mandoc_font(cp, (int)strlen(cp)));
+}
+
+static void
+roff_html_pre_nf(ROFF_HTML_ARGS)
+{
+ if (html_fillmode(h, TOKEN_NONE) == ROFF_nf)
+ print_otag(h, TAG_BR, "");
+}
+
+static void
roff_html_pre_sp(ROFF_HTML_ARGS)
{
- print_paragraph(h);
+ if (html_fillmode(h, TOKEN_NONE) == ROFF_nf) {
+ h->col++;
+ print_endline(h);
+ } else {
+ html_close_paragraph(h);
+ print_otag(h, TAG_P, "c", "Pp");
+ }
}
diff --git a/usr/src/cmd/mandoc/roff_int.h b/usr/src/cmd/mandoc/roff_int.h
index 48996dce53..d033f86ace 100644
--- a/usr/src/cmd/mandoc/roff_int.h
+++ b/usr/src/cmd/mandoc/roff_int.h
@@ -1,7 +1,7 @@
-/* $Id: roff_int.h,v 1.9 2017/07/08 17:52:50 schwarze Exp $ */
+/* $Id: roff_int.h,v 1.16 2019/01/05 00:36:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,8 +14,54 @@
* 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.
+ *
+ * Parser internals shared by multiple parsers.
*/
+struct ohash;
+struct roff_node;
+struct roff_meta;
+struct roff;
+struct mdoc_arg;
+
+enum roff_next {
+ ROFF_NEXT_SIBLING = 0,
+ ROFF_NEXT_CHILD
+};
+
+struct roff_man {
+ struct roff_meta meta; /* Public parse results. */
+ struct roff *roff; /* Roff parser state data. */
+ struct ohash *mdocmac; /* Mdoc macro lookup table. */
+ struct ohash *manmac; /* Man macro lookup table. */
+ const char *os_s; /* Default operating system. */
+ struct roff_node *last; /* The last node parsed. */
+ struct roff_node *last_es; /* The most recent Es node. */
+ int quick; /* Abort parse early. */
+ int flags; /* Parse flags. */
+#define ROFF_NOFILL (1 << 1) /* Fill mode switched off. */
+#define MDOC_PBODY (1 << 2) /* In the document body. */
+#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */
+#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */
+#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */
+#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */
+#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */
+#define MDOC_KEEP (1 << 8) /* In a word keep. */
+#define MDOC_SMOFF (1 << 9) /* Spacing is off. */
+#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */
+#define MAN_ELINE (1 << 11) /* Next-line element scope. */
+#define MAN_BLINE (1 << 12) /* Next-line block scope. */
+#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */
+#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */
+#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */
+#define ROFF_NONOFILL (1 << 16) /* Temporarily suspend no-fill mode. */
+#define MAN_NEWLINE MDOC_NEWLINE
+ enum roff_sec lastsec; /* Last section seen. */
+ enum roff_sec lastnamed; /* Last standard section seen. */
+ enum roff_next next; /* Where to put the next node. */
+};
+
+
struct roff_node *roff_node_alloc(struct roff_man *, int, int,
enum roff_type, int);
void roff_node_append(struct roff_man *, struct roff_node *);
@@ -26,9 +72,17 @@ struct roff_node *roff_block_alloc(struct roff_man *, int, int, int);
struct roff_node *roff_head_alloc(struct roff_man *, int, int, int);
struct roff_node *roff_body_alloc(struct roff_man *, int, int, int);
void roff_node_unlink(struct roff_man *, struct roff_node *);
+void roff_node_relink(struct roff_man *, struct roff_node *);
void roff_node_free(struct roff_node *);
void roff_node_delete(struct roff_man *, struct roff_node *);
+struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok);
+enum roff_tok roffhash_find(struct ohash *, const char *, size_t);
+void roffhash_free(struct ohash *);
+
+void roff_state_reset(struct roff_man *);
+void roff_validate(struct roff_man *);
+
/*
* Functions called from roff.c need to be declared here,
* not in libmdoc.h or libman.h, even if they are specific
diff --git a/usr/src/cmd/mandoc/roff_term.c b/usr/src/cmd/mandoc/roff_term.c
index b5ec764963..f10bb61d2c 100644
--- a/usr/src/cmd/mandoc/roff_term.c
+++ b/usr/src/cmd/mandoc/roff_term.c
@@ -1,6 +1,6 @@
-/* $Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
+/* $Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010,2014,2015,2017-2019 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
@@ -17,7 +17,8 @@
#include <sys/types.h>
#include <assert.h>
-#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include "mandoc.h"
#include "roff.h"
@@ -41,9 +42,11 @@ static void roff_term_pre_ti(ROFF_TERM_ARGS);
static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
roff_term_pre_br, /* br */
roff_term_pre_ce, /* ce */
+ roff_term_pre_br, /* fi */
roff_term_pre_ft, /* ft */
roff_term_pre_ll, /* ll */
roff_term_pre_mc, /* mc */
+ roff_term_pre_br, /* nf */
roff_term_pre_po, /* po */
roff_term_pre_ce, /* rj */
roff_term_pre_sp, /* sp */
@@ -66,7 +69,9 @@ roff_term_pre_br(ROFF_TERM_ARGS)
if (p->flags & TERMP_BRIND) {
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
+ p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
+ p->flags |= TERMP_NOSPACE;
}
}
@@ -74,27 +79,16 @@ static void
roff_term_pre_ce(ROFF_TERM_ARGS)
{
const struct roff_node *nc1, *nc2;
- size_t len, lm;
roff_term_pre_br(p, n);
- lm = p->tcol->offset;
+ p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
nc1 = n->child->next;
while (nc1 != NULL) {
nc2 = nc1;
- len = 0;
do {
- if (nc2->type == ROFFT_TEXT) {
- if (len)
- len++;
- len += term_strlen(p, nc2->string);
- }
nc2 = nc2->next;
} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
(nc2->flags & NODE_LINE) == 0));
- p->tcol->offset = len >= p->tcol->rmargin ? 0 :
- lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
- n->tok == ROFF_rj ? p->tcol->rmargin - len :
- (lm + p->tcol->rmargin - len) / 2;
while (nc1 != nc2) {
if (nc1->type == ROFFT_TEXT)
term_word(p, nc1->string);
@@ -105,28 +99,30 @@ roff_term_pre_ce(ROFF_TERM_ARGS)
p->flags |= TERMP_NOSPACE;
term_flushln(p);
}
- p->tcol->offset = lm;
+ p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
}
static void
roff_term_pre_ft(ROFF_TERM_ARGS)
{
- switch (*n->child->string) {
- case '4':
- case '3':
- case 'B':
+ const char *cp;
+
+ cp = n->child->string;
+ switch (mandoc_font(cp, (int)strlen(cp))) {
+ case ESCAPE_FONTBOLD:
term_fontrepl(p, TERMFONT_BOLD);
break;
- case '2':
- case 'I':
+ case ESCAPE_FONTITALIC:
term_fontrepl(p, TERMFONT_UNDER);
break;
- case 'P':
+ case ESCAPE_FONTBI:
+ term_fontrepl(p, TERMFONT_BI);
+ break;
+ case ESCAPE_FONTPREV:
term_fontlast(p);
break;
- case '1':
- case 'C':
- case 'R':
+ case ESCAPE_FONTROMAN:
+ case ESCAPE_FONTCW:
term_fontrepl(p, TERMFONT_NONE);
break;
default:
diff --git a/usr/src/cmd/mandoc/roff_validate.c b/usr/src/cmd/mandoc/roff_validate.c
index 801e931485..9080f28797 100644
--- a/usr/src/cmd/mandoc/roff_validate.c
+++ b/usr/src/cmd/mandoc/roff_validate.c
@@ -1,6 +1,6 @@
-/* $Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */
+/* $Id: roff_validate.c,v 1.18 2018/12/31 09:02:37 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2017, 2018 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
@@ -17,7 +17,8 @@
#include <sys/types.h>
#include <assert.h>
-#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include "mandoc.h"
#include "roff.h"
@@ -28,17 +29,23 @@
typedef void (*roff_valid_fp)(ROFF_VALID_ARGS);
+static void roff_valid_br(ROFF_VALID_ARGS);
+static void roff_valid_fi(ROFF_VALID_ARGS);
static void roff_valid_ft(ROFF_VALID_ARGS);
+static void roff_valid_nf(ROFF_VALID_ARGS);
+static void roff_valid_sp(ROFF_VALID_ARGS);
static const roff_valid_fp roff_valids[ROFF_MAX] = {
- NULL, /* br */
+ roff_valid_br, /* br */
NULL, /* ce */
+ roff_valid_fi, /* fi */
roff_valid_ft, /* ft */
NULL, /* ll */
NULL, /* mc */
+ roff_valid_nf, /* nf */
NULL, /* po */
NULL, /* rj */
- NULL, /* sp */
+ roff_valid_sp, /* sp */
NULL, /* ta */
NULL, /* ti */
};
@@ -56,9 +63,45 @@ roff_validate(struct roff_man *man)
}
static void
+roff_valid_br(ROFF_VALID_ARGS)
+{
+ struct roff_node *np;
+
+ if (n->next != NULL && n->next->type == ROFFT_TEXT &&
+ *n->next->string == ' ') {
+ mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
+ "br before text line with leading blank");
+ roff_node_delete(man, n);
+ return;
+ }
+
+ if ((np = n->prev) == NULL)
+ return;
+
+ switch (np->tok) {
+ case ROFF_br:
+ case ROFF_sp:
+ case MDOC_Pp:
+ mandoc_msg(MANDOCERR_PAR_SKIP,
+ n->line, n->pos, "br after %s", roff_name[np->tok]);
+ roff_node_delete(man, n);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+roff_valid_fi(ROFF_VALID_ARGS)
+{
+ if ((n->flags & NODE_NOFILL) == 0)
+ mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "fi");
+}
+
+static void
roff_valid_ft(ROFF_VALID_ARGS)
{
- char *cp;
+ const char *cp;
if (n->child == NULL) {
man->next = ROFF_NEXT_CHILD;
@@ -68,30 +111,39 @@ roff_valid_ft(ROFF_VALID_ARGS)
}
cp = n->child->string;
- switch (*cp) {
- case '1':
- case '2':
- case '3':
- case '4':
- case 'I':
- case 'P':
- case 'R':
- if (cp[1] == '\0')
- return;
- break;
- case 'B':
- if (cp[1] == '\0' || (cp[1] == 'I' && cp[2] == '\0'))
- return;
+ if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR)
+ return;
+ mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp);
+ roff_node_delete(man, n);
+}
+
+static void
+roff_valid_nf(ROFF_VALID_ARGS)
+{
+ if (n->flags & NODE_NOFILL)
+ mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "nf");
+}
+
+static void
+roff_valid_sp(ROFF_VALID_ARGS)
+{
+ struct roff_node *np;
+
+ if ((np = n->prev) == NULL)
+ return;
+
+ switch (np->tok) {
+ case ROFF_br:
+ mandoc_msg(MANDOCERR_PAR_SKIP,
+ np->line, np->pos, "br before sp");
+ roff_node_delete(man, np);
break;
- case 'C':
- if (cp[1] == 'W' && cp[2] == '\0')
- return;
+ case MDOC_Pp:
+ mandoc_msg(MANDOCERR_PAR_SKIP,
+ n->line, n->pos, "sp after Pp");
+ roff_node_delete(man, n);
break;
default:
break;
}
-
- mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
- n->line, n->pos, "ft %s", cp);
- roff_node_delete(man, n);
}
diff --git a/usr/src/cmd/mandoc/st.c b/usr/src/cmd/mandoc/st.c
index d166566ece..c4d86e33fe 100644
--- a/usr/src/cmd/mandoc/st.c
+++ b/usr/src/cmd/mandoc/st.c
@@ -1,6 +1,6 @@
-/* $Id: st.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
+/* $Id: st.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */
/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,11 +18,11 @@
#include <sys/types.h>
+#include <stdio.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
-#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
@@ -31,8 +31,52 @@
const char *
mdoc_a2st(const char *p)
{
-
-#include "st.in"
+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", "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)")
return NULL;
}
diff --git a/usr/src/cmd/mandoc/st.in b/usr/src/cmd/mandoc/st.in
deleted file mode 100644
index 557a70d10d..0000000000
--- a/usr/src/cmd/mandoc/st.in
+++ /dev/null
@@ -1,76 +0,0 @@
-/* $Id: st.in,v 1.30 2018/04/05 09:17:26 schwarze Exp $ */
-/*
- * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * This file defines the .St macro arguments. If you add a new
- * standard, make sure that the left-and side corresponds to the .St
- * argument (like .St -p1003.1) and the right-hand side corresponds to
- * the formatted output string.
- *
- * Be sure to escape strings.
- * The non-breaking blanks prevent ending an output line right before
- * a number. Groff prevent line breaks at the same places.
- *
- * 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", "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)")
diff --git a/usr/src/cmd/mandoc/tag.c b/usr/src/cmd/mandoc/tag.c
index c0832c4f74..473ea7b6f4 100644
--- a/usr/src/cmd/mandoc/tag.c
+++ b/usr/src/cmd/mandoc/tag.c
@@ -1,6 +1,6 @@
-/* $Id: tag.c,v 1.19 2018/02/23 16:47:10 schwarze Exp $ */
+/* $Id: tag.c,v 1.21 2018/11/22 11:30:23 schwarze Exp $ */
/*
- * Copyright (c) 2015, 2016 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2015, 2016, 2018 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
@@ -18,6 +18,10 @@
#include <sys/types.h>
+#if HAVE_ERR
+#include <err.h>
+#endif
+#include <limits.h>
#include <signal.h>
#include <stddef.h>
#include <stdint.h>
@@ -121,41 +125,57 @@ fail:
/*
* Set the line number where a term is defined,
- * unless it is already defined at a higher priority.
+ * unless it is already defined at a lower priority.
*/
void
tag_put(const char *s, int prio, size_t line)
{
struct tag_entry *entry;
+ const char *se;
size_t len;
unsigned int slot;
- /* Sanity checks. */
-
if (tag_files.tfd <= 0)
return;
+
if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e'))
s += 2;
- if (*s == '\0' || strchr(s, ' ') != NULL)
+
+ /*
+ * Skip whitespace and whatever follows it,
+ * and if there is any, downgrade the priority.
+ */
+
+ len = strcspn(s, " \t");
+ if (len == 0)
return;
- slot = ohash_qlookup(&tag_data, s);
+ se = s + len;
+ if (*se != '\0')
+ prio = INT_MAX;
+
+ slot = ohash_qlookupi(&tag_data, s, &se);
entry = ohash_find(&tag_data, slot);
if (entry == NULL) {
/* Build a new entry. */
- len = strlen(s) + 1;
- entry = mandoc_malloc(sizeof(*entry) + len);
+ entry = mandoc_malloc(sizeof(*entry) + len + 1);
memcpy(entry->s, s, len);
+ entry->s[len] = '\0';
entry->lines = NULL;
entry->maxlines = entry->nlines = 0;
ohash_insert(&tag_data, slot, entry);
} else {
- /* Handle priority 0 entries. */
+ /*
+ * Lower priority numbers take precedence,
+ * but 0 is special.
+ * A tag with priority 0 is only used
+ * if the tag occurs exactly once.
+ */
if (prio == 0) {
if (entry->prio == 0)
@@ -199,6 +219,11 @@ tag_write(void)
if (tag_files.tfd <= 0)
return;
+ if (tag_files.tagname != NULL && ohash_find(&tag_data,
+ ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) {
+ warnx("%s: no such tag", tag_files.tagname);
+ tag_files.tagname = NULL;
+ }
stream = fdopen(tag_files.tfd, "w");
entry = ohash_first(&tag_data, &slot);
while (entry != NULL) {
diff --git a/usr/src/cmd/mandoc/tag.h b/usr/src/cmd/mandoc/tag.h
index ab1388d798..bbd40b737e 100644
--- a/usr/src/cmd/mandoc/tag.h
+++ b/usr/src/cmd/mandoc/tag.h
@@ -1,4 +1,4 @@
-/* $Id: tag.h,v 1.7 2015/11/20 21:59:54 schwarze Exp $ */
+/* $Id: tag.h,v 1.8 2018/11/22 11:30:23 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -18,6 +18,7 @@
struct tag_files {
char ofn[20];
char tfn[20];
+ char *tagname;
int ofd;
int tfd;
pid_t tcpgid;
diff --git a/usr/src/cmd/mandoc/tbl.c b/usr/src/cmd/mandoc/tbl.c
index 3fb8e52a4c..036a117752 100644
--- a/usr/src/cmd/mandoc/tbl.c
+++ b/usr/src/cmd/mandoc/tbl.c
@@ -1,4 +1,4 @@
-/* $Id: tbl.c,v 1.42 2017/07/08 17:52:50 schwarze Exp $ */
+/* $Id: tbl.c,v 1.46 2018/12/14 06:33:14 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -25,10 +25,12 @@
#include <string.h>
#include <time.h>
-#include "mandoc.h"
#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "tbl.h"
#include "libmandoc.h"
-#include "libroff.h"
+#include "tbl_parse.h"
+#include "tbl_int.h"
void
@@ -86,14 +88,15 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
}
struct tbl_node *
-tbl_alloc(int pos, int line, struct mparse *parse)
+tbl_alloc(int pos, int line, struct tbl_node *last_tbl)
{
struct tbl_node *tbl;
tbl = mandoc_calloc(1, sizeof(*tbl));
+ if (last_tbl != NULL)
+ last_tbl->next = tbl;
tbl->line = line;
tbl->pos = pos;
- tbl->parse = parse;
tbl->part = TBL_PART_OPTS;
tbl->opts.tab = '\t';
tbl->opts.decimal = '.';
@@ -103,76 +106,77 @@ tbl_alloc(int pos, int line, struct mparse *parse)
void
tbl_free(struct tbl_node *tbl)
{
+ struct tbl_node *old_tbl;
struct tbl_row *rp;
struct tbl_cell *cp;
struct tbl_span *sp;
struct tbl_dat *dp;
- while ((rp = tbl->first_row) != NULL) {
- tbl->first_row = rp->next;
- while (rp->first != NULL) {
- cp = rp->first;
- rp->first = cp->next;
- free(cp->wstr);
- free(cp);
+ while (tbl != NULL) {
+ while ((rp = tbl->first_row) != NULL) {
+ tbl->first_row = rp->next;
+ while (rp->first != NULL) {
+ cp = rp->first;
+ rp->first = cp->next;
+ free(cp->wstr);
+ free(cp);
+ }
+ free(rp);
}
- free(rp);
- }
-
- while ((sp = tbl->first_span) != NULL) {
- tbl->first_span = sp->next;
- while (sp->first != NULL) {
- dp = sp->first;
- sp->first = dp->next;
- free(dp->string);
- free(dp);
+ while ((sp = tbl->first_span) != NULL) {
+ tbl->first_span = sp->next;
+ while (sp->first != NULL) {
+ dp = sp->first;
+ sp->first = dp->next;
+ free(dp->string);
+ free(dp);
+ }
+ free(sp);
}
- free(sp);
+ old_tbl = tbl;
+ tbl = tbl->next;
+ free(old_tbl);
}
-
- free(tbl);
}
void
tbl_restart(int line, int pos, struct tbl_node *tbl)
{
if (tbl->part == TBL_PART_CDATA)
- mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
- line, pos, "T&");
+ mandoc_msg(MANDOCERR_TBLDATA_BLK, line, pos, "T&");
tbl->part = TBL_PART_LAYOUT;
tbl->line = line;
tbl->pos = pos;
}
-const struct tbl_span *
+struct tbl_span *
tbl_span(struct tbl_node *tbl)
{
struct tbl_span *span;
- assert(tbl);
span = tbl->current_span ? tbl->current_span->next
: tbl->first_span;
- if (span)
+ if (span != NULL)
tbl->current_span = span;
return span;
}
int
-tbl_end(struct tbl_node *tbl)
+tbl_end(struct tbl_node *tbl, int still_open)
{
struct tbl_span *sp;
- if (tbl->part == TBL_PART_CDATA)
- mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
- tbl->line, tbl->pos, "TE");
+ if (still_open)
+ mandoc_msg(MANDOCERR_BLK_NOEND, tbl->line, tbl->pos, "TS");
+ else if (tbl->part == TBL_PART_CDATA)
+ mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->line, tbl->pos, "TE");
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);
+ mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->line, tbl->pos, NULL);
return 0;
}
return 1;
diff --git a/usr/src/cmd/mandoc/tbl.h b/usr/src/cmd/mandoc/tbl.h
new file mode 100644
index 0000000000..365ae929ed
--- /dev/null
+++ b/usr/src/cmd/mandoc/tbl.h
@@ -0,0 +1,122 @@
+/* $Id: tbl.h,v 1.1 2018/12/12 21:54:35 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct tbl_opts {
+ int opts;
+#define TBL_OPT_ALLBOX (1 << 0) /* Option "allbox". */
+#define TBL_OPT_BOX (1 << 1) /* Option "box". */
+#define TBL_OPT_CENTRE (1 << 2) /* Option "center". */
+#define TBL_OPT_DBOX (1 << 3) /* Option "doublebox". */
+#define TBL_OPT_EXPAND (1 << 4) /* Option "expand". */
+#define TBL_OPT_NOKEEP (1 << 5) /* Option "nokeep". */
+#define TBL_OPT_NOSPACE (1 << 6) /* Option "nospaces". */
+#define TBL_OPT_NOWARN (1 << 7) /* Option "nowarn". */
+ int cols; /* Number of columns. */
+ int lvert; /* Width of left vertical line. */
+ int rvert; /* Width of right vertical line. */
+ char tab; /* Option "tab": cell separator. */
+ char decimal; /* Option "decimalpoint". */
+};
+
+enum tbl_cellt {
+ TBL_CELL_CENTRE, /* c, C */
+ TBL_CELL_RIGHT, /* r, R */
+ TBL_CELL_LEFT, /* l, L */
+ TBL_CELL_NUMBER, /* n, N */
+ TBL_CELL_SPAN, /* s, S */
+ TBL_CELL_LONG, /* a, A */
+ TBL_CELL_DOWN, /* ^ */
+ TBL_CELL_HORIZ, /* _, - */
+ TBL_CELL_DHORIZ, /* = */
+ TBL_CELL_MAX
+};
+
+/*
+ * A cell in a layout row.
+ */
+struct tbl_cell {
+ struct tbl_cell *next; /* Layout cell to the right. */
+ char *wstr; /* Min width represented as a string. */
+ size_t width; /* Minimum column width. */
+ size_t spacing; /* To the right of the column. */
+ int vert; /* Width of subsequent vertical line. */
+ int col; /* Column number, starting from 0. */
+ int flags;
+#define TBL_CELL_BOLD (1 << 0) /* b, B, fB */
+#define TBL_CELL_ITALIC (1 << 1) /* i, I, fI */
+#define TBL_CELL_TALIGN (1 << 2) /* t, T */
+#define TBL_CELL_UP (1 << 3) /* u, U */
+#define TBL_CELL_BALIGN (1 << 4) /* d, D */
+#define TBL_CELL_WIGN (1 << 5) /* z, Z */
+#define TBL_CELL_EQUAL (1 << 6) /* e, E */
+#define TBL_CELL_WMAX (1 << 7) /* x, X */
+ enum tbl_cellt pos;
+};
+
+/*
+ * A layout row.
+ */
+struct tbl_row {
+ struct tbl_row *next; /* Layout row below. */
+ struct tbl_cell *first; /* Leftmost layout cell. */
+ struct tbl_cell *last; /* Rightmost layout cell. */
+ int vert; /* Width of left vertical line. */
+};
+
+enum tbl_datt {
+ TBL_DATA_NONE, /* Uninitialized row. */
+ TBL_DATA_DATA, /* Contains data rather than a line. */
+ TBL_DATA_HORIZ, /* _: connecting horizontal line. */
+ TBL_DATA_DHORIZ, /* =: connecting double horizontal line. */
+ TBL_DATA_NHORIZ, /* \_: isolated horizontal line. */
+ TBL_DATA_NDHORIZ /* \=: isolated double horizontal line. */
+};
+
+/*
+ * A cell within a row of data. The "string" field contains the
+ * actual string value that's in the cell. The rest is layout.
+ */
+struct tbl_dat {
+ struct tbl_dat *next; /* Data cell to the right. */
+ struct tbl_cell *layout; /* Associated layout cell. */
+ char *string; /* Data, or NULL if not TBL_DATA_DATA. */
+ int hspans; /* How many horizontal spans follow. */
+ int vspans; /* How many vertical spans follow. */
+ int block; /* T{ text block T} */
+ enum tbl_datt pos;
+};
+
+enum tbl_spant {
+ TBL_SPAN_DATA, /* Contains data rather than a line. */
+ TBL_SPAN_HORIZ, /* _: horizontal line. */
+ TBL_SPAN_DHORIZ /* =: double horizontal line. */
+};
+
+/*
+ * A row of data in a table.
+ */
+struct tbl_span {
+ struct tbl_opts *opts; /* Options for the table as a whole. */
+ struct tbl_span *prev; /* Data row above. */
+ struct tbl_span *next; /* Data row below. */
+ struct tbl_row *layout; /* Associated layout row. */
+ struct tbl_dat *first; /* Leftmost data cell. */
+ struct tbl_dat *last; /* Rightmost data cell. */
+ int line; /* Input file line number. */
+ enum tbl_spant pos;
+};
diff --git a/usr/src/cmd/mandoc/tbl_data.c b/usr/src/cmd/mandoc/tbl_data.c
index ae1906ef73..9a58d32562 100644
--- a/usr/src/cmd/mandoc/tbl_data.c
+++ b/usr/src/cmd/mandoc/tbl_data.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_data.c,v 1.45 2017/07/08 17:52:50 schwarze Exp $ */
+/* $Id: tbl_data.c,v 1.52 2019/02/09 16:00:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2015,2017,2018,2019 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,14 +21,16 @@
#include <assert.h>
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include "mandoc.h"
#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "tbl.h"
#include "libmandoc.h"
-#include "libroff.h"
+#include "tbl_int.h"
static void getdata(struct tbl_node *, struct tbl_span *,
int, const char *, int *);
@@ -40,10 +42,20 @@ static void
getdata(struct tbl_node *tbl, struct tbl_span *dp,
int ln, const char *p, int *pos)
{
- struct tbl_dat *dat;
+ struct tbl_dat *dat, *pdat;
struct tbl_cell *cp;
+ struct tbl_span *pdp;
int sv;
+ /*
+ * Determine the length of the string in the cell
+ * and advance the parse point to the end of the cell.
+ */
+
+ sv = *pos;
+ while (p[*pos] != '\0' && p[*pos] != tbl->opts.tab)
+ (*pos)++;
+
/* Advance to the next layout cell, skipping spanners. */
cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
@@ -65,34 +77,68 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
cp->col = dp->layout->last->col + 1;
dp->layout->last = cp;
} else {
- mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
- ln, *pos, p + *pos);
- while (p[*pos])
+ mandoc_msg(MANDOCERR_TBLDATA_EXTRA,
+ ln, sv, "%s", p + sv);
+ while (p[*pos] != '\0')
(*pos)++;
return;
}
}
- dat = mandoc_calloc(1, sizeof(*dat));
+ dat = mandoc_malloc(sizeof(*dat));
dat->layout = cp;
+ dat->next = NULL;
+ dat->string = NULL;
+ dat->hspans = 0;
+ dat->vspans = 0;
+ dat->block = 0;
dat->pos = TBL_DATA_NONE;
- dat->spans = 0;
+
+ /*
+ * Increment the number of vertical spans in a data cell above,
+ * if this cell vertically extends one or more cells above.
+ * The iteration must be done over data rows,
+ * not over layout rows, because one layout row
+ * can be reused for more than one data row.
+ */
+
+ if (cp->pos == TBL_CELL_DOWN ||
+ (*pos - sv == 2 && p[sv] == '\\' && p[sv + 1] == '^')) {
+ pdp = dp;
+ while ((pdp = pdp->prev) != NULL) {
+ pdat = pdp->first;
+ while (pdat != NULL &&
+ pdat->layout->col < dat->layout->col)
+ pdat = pdat->next;
+ if (pdat == NULL)
+ break;
+ if (pdat->layout->pos != TBL_CELL_DOWN &&
+ strcmp(pdat->string, "\\^") != 0) {
+ pdat->vspans++;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Count the number of horizontal spans to the right of this cell.
+ * This is purely a matter of the layout, independent of the data.
+ */
+
for (cp = cp->next; cp != NULL; cp = cp->next)
if (cp->pos == TBL_CELL_SPAN)
- dat->spans++;
+ dat->hspans++;
else
break;
+ /* Append the new data cell to the data row. */
+
if (dp->last == NULL)
dp->first = dat;
else
dp->last->next = dat;
dp->last = dat;
- sv = *pos;
- while (p[*pos] && p[*pos] != tbl->opts.tab)
- (*pos)++;
-
/*
* Check for a continued-data scope opening. This consists of a
* trailing `T{' at the end of the line. Subsequent lines,
@@ -106,7 +152,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
dat->string = mandoc_strndup(p + sv, *pos - sv);
- if (p[*pos])
+ if (p[*pos] != '\0')
(*pos)++;
if ( ! strcmp(dat->string, "_"))
@@ -125,7 +171,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
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);
+ ln, sv, "%s", dat->string);
}
void
@@ -164,8 +210,8 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
dat->string = mandoc_strdup(p + pos);
if (dat->layout->pos == TBL_CELL_DOWN)
- mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
- ln, pos, dat->string);
+ mandoc_msg(MANDOCERR_TBLDATA_SPAN,
+ ln, pos, "%s", dat->string);
}
static struct tbl_span *
@@ -202,14 +248,27 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
assert(rp != NULL);
- if ( ! strcmp(p, "_")) {
- sp = newspan(tbl, ln, rp);
- sp->pos = TBL_SPAN_HORIZ;
- return;
- } else if ( ! strcmp(p, "=")) {
- sp = newspan(tbl, ln, rp);
- sp->pos = TBL_SPAN_DHORIZ;
- return;
+ if (p[1] == '\0') {
+ switch (p[0]) {
+ case '.':
+ /*
+ * Empty request lines must be handled here
+ * and cannot be discarded in roff_parseln()
+ * because in the layout section, they
+ * are significant and end the layout.
+ */
+ return;
+ case '_':
+ sp = newspan(tbl, ln, rp);
+ sp->pos = TBL_SPAN_HORIZ;
+ return;
+ case '=':
+ sp = newspan(tbl, ln, rp);
+ sp->pos = TBL_SPAN_DHORIZ;
+ return;
+ default:
+ break;
+ }
}
/*
diff --git a/usr/src/cmd/mandoc/tbl_html.c b/usr/src/cmd/mandoc/tbl_html.c
index b87804fda3..4ab6bed10b 100644
--- a/usr/src/cmd/mandoc/tbl_html.c
+++ b/usr/src/cmd/mandoc/tbl_html.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_html.c,v 1.24 2018/06/25 13:45:57 schwarze Exp $ */
+/* $Id: tbl_html.c,v 1.32 2019/01/06 04:55:09 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +25,7 @@
#include <string.h>
#include "mandoc.h"
+#include "tbl.h"
#include "out.h"
#include "html.h"
@@ -79,6 +80,7 @@ html_tbl_sulen(const struct roffsu *su, void *arg)
static void
html_tblopen(struct html *h, const struct tbl_span *sp)
{
+ html_close_paragraph(h);
if (h->tbl.cols == NULL) {
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
@@ -86,7 +88,15 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
tblcalc(&h->tbl, sp, 0, 0);
}
assert(NULL == h->tblt);
- h->tblt = print_otag(h, TAG_TABLE, "c", "tbl");
+ h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl",
+ "border",
+ sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL,
+ "border-style",
+ sp->opts->opts & TBL_OPT_DBOX ? "double" :
+ sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL,
+ "border-top-style",
+ sp->pos == TBL_SPAN_DHORIZ ? "double" :
+ sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL);
}
void
@@ -101,43 +111,138 @@ print_tblclose(struct html *h)
void
print_tbl(struct html *h, const struct tbl_span *sp)
{
- const struct tbl_dat *dp;
- struct tag *tt;
- int ic;
-
- /* Inhibit printing of spaces: we do padding ourselves. */
+ const struct tbl_dat *dp;
+ const struct tbl_cell *cp;
+ const struct tbl_span *psp;
+ struct tag *tt;
+ const char *hspans, *vspans, *halign, *valign;
+ const char *bborder, *lborder, *rborder;
+ char hbuf[4], vbuf[4];
+ int i;
if (h->tblt == NULL)
html_tblopen(h, sp);
- assert(h->tblt);
+ /*
+ * Horizontal lines spanning the whole table
+ * are handled by previous or following table rows.
+ */
+
+ if (sp->pos != TBL_SPAN_DATA)
+ return;
+
+ /* Inhibit printing of spaces: we do padding ourselves. */
h->flags |= HTML_NONOSPACE;
h->flags |= HTML_NOSPACE;
- tt = print_otag(h, TAG_TR, "");
+ /* Draw a vertical line left of this row? */
- switch (sp->pos) {
- case TBL_SPAN_HORIZ:
- case TBL_SPAN_DHORIZ:
- print_otag(h, TAG_TD, "?", "colspan", "0");
+ switch (sp->layout->vert) {
+ case 2:
+ lborder = "double";
+ break;
+ case 1:
+ lborder = "solid";
break;
default:
- dp = sp->first;
- for (ic = 0; ic < sp->opts->cols; ic++) {
- print_stagq(h, tt);
- print_otag(h, TAG_TD, "");
-
- 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;
- }
+ lborder = NULL;
break;
}
+ /* Draw a horizontal line below this row? */
+
+ bborder = NULL;
+ if ((psp = sp->next) != NULL) {
+ switch (psp->pos) {
+ case TBL_SPAN_DHORIZ:
+ bborder = "double";
+ break;
+ case TBL_SPAN_HORIZ:
+ bborder = "solid";
+ break;
+ default:
+ break;
+ }
+ }
+
+ tt = print_otag(h, TAG_TR, "ss",
+ "border-left-style", lborder,
+ "border-bottom-style", bborder);
+
+ for (dp = sp->first; dp != NULL; dp = dp->next) {
+ print_stagq(h, tt);
+
+ /*
+ * Do not generate <td> elements for continuations
+ * of spanned cells. Larger <td> elements covering
+ * this space were already generated earlier.
+ */
+
+ cp = dp->layout;
+ if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN ||
+ (dp->string != NULL && strcmp(dp->string, "\\^") == 0))
+ continue;
+
+ /* Determine the attribute values. */
+
+ if (dp->hspans > 0) {
+ (void)snprintf(hbuf, sizeof(hbuf),
+ "%d", dp->hspans + 1);
+ hspans = hbuf;
+ } else
+ hspans = NULL;
+ if (dp->vspans > 0) {
+ (void)snprintf(vbuf, sizeof(vbuf),
+ "%d", dp->vspans + 1);
+ vspans = vbuf;
+ } else
+ vspans = NULL;
+
+ switch (cp->pos) {
+ case TBL_CELL_CENTRE:
+ halign = "center";
+ break;
+ case TBL_CELL_RIGHT:
+ case TBL_CELL_NUMBER:
+ halign = "right";
+ break;
+ default:
+ halign = NULL;
+ break;
+ }
+ if (cp->flags & TBL_CELL_TALIGN)
+ valign = "top";
+ else if (cp->flags & TBL_CELL_BALIGN)
+ valign = "bottom";
+ else
+ valign = NULL;
+
+ for (i = dp->hspans; i > 0; i--)
+ cp = cp->next;
+ switch (cp->vert) {
+ case 2:
+ rborder = "double";
+ break;
+ case 1:
+ rborder = "solid";
+ break;
+ default:
+ rborder = NULL;
+ break;
+ }
+
+ /* Print the element and the attributes. */
+
+ print_otag(h, TAG_TD, "??sss",
+ "colspan", hspans, "rowspan", vspans,
+ "vertical-align", valign,
+ "text-align", halign,
+ "border-right-style", rborder);
+ if (dp->string != NULL)
+ print_text(h, dp->string);
+ }
+
print_tagq(h, tt);
h->flags &= ~HTML_NONOSPACE;
@@ -148,5 +253,4 @@ print_tbl(struct html *h, const struct tbl_span *sp)
h->tbl.cols = NULL;
print_tblclose(h);
}
-
}
diff --git a/usr/src/cmd/mandoc/tbl_int.h b/usr/src/cmd/mandoc/tbl_int.h
new file mode 100644
index 0000000000..fc32910fc7
--- /dev/null
+++ b/usr/src/cmd/mandoc/tbl_int.h
@@ -0,0 +1,47 @@
+/* $Id: tbl_int.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011,2013,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Internal interfaces of the tbl(7) parser.
+ * For use inside the tbl(7) parser only.
+ */
+
+enum tbl_part {
+ TBL_PART_OPTS, /* In the first line, ends with semicolon. */
+ TBL_PART_LAYOUT, /* In the layout section, ends with full stop. */
+ TBL_PART_DATA, /* In the data section, ends with TE. */
+ TBL_PART_CDATA /* In a T{ block, ends with T} */
+};
+
+struct tbl_node {
+ struct tbl_opts opts; /* Options for the whole table. */
+ struct tbl_node *next; /* Next table. */
+ struct tbl_row *first_row; /* First layout row. */
+ struct tbl_row *last_row; /* Last layout row. */
+ struct tbl_span *first_span; /* First data row. */
+ struct tbl_span *current_span; /* Data row being parsed. */
+ struct tbl_span *last_span; /* Last data row. */
+ int line; /* Line number in input file. */
+ int pos; /* Column number in input file. */
+ enum tbl_part part; /* Table section being parsed. */
+};
+
+
+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);
+void tbl_cdata(struct tbl_node *, int, const char *, int);
+void tbl_reset(struct tbl_node *);
diff --git a/usr/src/cmd/mandoc/tbl_layout.c b/usr/src/cmd/mandoc/tbl_layout.c
index 42fc0e8296..58599705c1 100644
--- a/usr/src/cmd/mandoc/tbl_layout.c
+++ b/usr/src/cmd/mandoc/tbl_layout.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_layout.c,v 1.44 2017/06/27 18:25:02 schwarze Exp $ */
+/* $Id: tbl_layout.c,v 1.48 2018/12/14 05:18:03 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -21,14 +21,16 @@
#include <ctype.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include "mandoc.h"
#include "mandoc_aux.h"
+#include "mandoc.h"
+#include "tbl.h"
#include "libmandoc.h"
-#include "libroff.h"
+#include "tbl_int.h"
struct tbl_phrase {
char name;
@@ -84,8 +86,7 @@ mod:
(*pos)++;
goto mod;
}
- mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse,
- ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, ln, *pos, NULL);
return;
}
@@ -113,8 +114,7 @@ mod:
cp->flags |= TBL_CELL_ITALIC;
goto mod;
case 'm':
- mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse,
- ln, *pos, "m");
+ mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, ln, *pos, "m");
goto mod;
case 'p':
case 'v':
@@ -157,10 +157,10 @@ mod:
cp->vert++;
else
mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
- tbl->parse, ln, *pos - 1, NULL);
+ ln, *pos - 1, NULL);
goto mod;
default:
- mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
+ mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR,
ln, *pos - 1, "%c", p[*pos - 1]);
goto mod;
}
@@ -173,7 +173,7 @@ 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,
+ mandoc_msg(MANDOCERR_FT_BAD,
ln, *pos, "TS %s", p + *pos - 1);
if (p[*pos] != '\0')
(*pos)++;
@@ -195,7 +195,7 @@ mod:
case 'R':
goto mod;
default:
- mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
+ mandoc_msg(MANDOCERR_FT_BAD,
ln, *pos - 1, "TS f%c", p[*pos - 1]);
goto mod;
}
@@ -216,7 +216,7 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
rp->vert++;
else
mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
- tbl->parse, ln, *pos, NULL);
+ ln, *pos, NULL);
}
(*pos)++;
}
@@ -235,7 +235,7 @@ again:
break;
if (i == KEYS_MAX) {
- mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
+ mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR,
ln, *pos, "%c", p[*pos]);
(*pos)++;
goto again;
@@ -246,14 +246,12 @@ again:
if (c == TBL_CELL_SPAN) {
if (rp->last == NULL)
- mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN,
- tbl->parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, 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);
+ mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, ln, *pos, NULL);
(*pos)++;
@@ -296,7 +294,7 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
}
if (tbl->first_row->first == NULL) {
mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,
- tbl->parse, ln, pos, NULL);
+ ln, pos, NULL);
cell_alloc(tbl, tbl->first_row,
TBL_CELL_LEFT);
if (tbl->opts.lvert < tbl->first_row->vert)
diff --git a/usr/src/cmd/mandoc/tbl_opts.c b/usr/src/cmd/mandoc/tbl_opts.c
index f2f5942ae6..e3a8373702 100644
--- a/usr/src/cmd/mandoc/tbl_opts.c
+++ b/usr/src/cmd/mandoc/tbl_opts.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_opts.c,v 1.21 2015/09/26 00:54:04 schwarze Exp $ */
+/* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -25,8 +25,9 @@
#include <string.h>
#include "mandoc.h"
+#include "tbl.h"
#include "libmandoc.h"
-#include "libroff.h"
+#include "tbl_int.h"
#define KEY_DPOINT 0
#define KEY_DELIM 1
@@ -80,7 +81,7 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
switch (key) {
case KEY_DELIM:
- mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
+ mandoc_msg(MANDOCERR_TBLOPT_EQN,
ln, *pos, "%.*s", len, p + *pos);
want = 2;
break;
@@ -102,12 +103,11 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
}
if (len == 0)
- mandoc_msg(MANDOCERR_TBLOPT_NOARG,
- tbl->parse, ln, *pos, keys[key].name);
+ mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos,
+ "%s", keys[key].name);
else if (want && len != want)
- mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
- tbl->parse, ln, *pos, "%s want %d have %d",
- keys[key].name, want, len);
+ mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos,
+ "%s want %d have %d", keys[key].name, want, len);
*pos += len;
if (p[*pos] == ')')
@@ -141,8 +141,8 @@ tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
len++;
if (len == 0) {
- mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
- tbl->parse, ln, pos, "%c", p[pos]);
+ mandoc_msg(MANDOCERR_TBLOPT_ALPHA,
+ ln, pos, "%c", p[pos]);
pos++;
continue;
}
@@ -156,7 +156,7 @@ tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
i++;
if (i == KEY_MAXKEYS) {
- mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
+ mandoc_msg(MANDOCERR_TBLOPT_BAD,
ln, pos, "%.*s", len, p + pos);
pos += len;
continue;
diff --git a/usr/src/cmd/mandoc/tbl_parse.h b/usr/src/cmd/mandoc/tbl_parse.h
new file mode 100644
index 0000000000..bb65536f28
--- /dev/null
+++ b/usr/src/cmd/mandoc/tbl_parse.h
@@ -0,0 +1,30 @@
+/* $Id: tbl_parse.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * External interface of the tbl(7) parser.
+ * For use in the roff(7) and tbl(7) parsers only.
+ */
+
+struct tbl_node;
+struct tbl_span;
+
+struct tbl_node *tbl_alloc(int, int, struct tbl_node *);
+int tbl_end(struct tbl_node *, int);
+void tbl_free(struct tbl_node *);
+void tbl_read(struct tbl_node *, int, const char *, int);
+void tbl_restart(int, int, struct tbl_node *);
+struct tbl_span *tbl_span(struct tbl_node *);
diff --git a/usr/src/cmd/mandoc/tbl_term.c b/usr/src/cmd/mandoc/tbl_term.c
index c154a0e9b9..a411107bd1 100644
--- a/usr/src/cmd/mandoc/tbl_term.c
+++ b/usr/src/cmd/mandoc/tbl_term.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_term.c,v 1.57 2017/07/31 16:14:10 schwarze Exp $ */
+/* $Id: tbl_term.c,v 1.68 2019/02/09 21:02:47 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2019 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,34 +20,121 @@
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
+#include "tbl.h"
#include "out.h"
#include "term.h"
#define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \
(cp)->pos == TBL_CELL_DHORIZ)
+
static size_t term_tbl_len(size_t, void *);
static size_t term_tbl_strlen(const char *, void *);
static size_t term_tbl_sulen(const struct roffsu *, void *);
-static void tbl_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *,
const struct tbl_cell *,
const struct tbl_dat *,
const struct roffcol *);
+static void tbl_direct_border(struct termp *, int, size_t);
+static void tbl_fill_border(struct termp *, int, size_t);
+static void tbl_fill_char(struct termp *, char, size_t);
+static void tbl_fill_string(struct termp *, const char *, size_t);
+static void tbl_hrule(struct termp *, const struct tbl_span *,
+ 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 *, int);
static void tbl_word(struct termp *, const struct tbl_dat *);
+/*
+ * The following border-character tables are indexed
+ * by ternary (3-based) numbers, as opposed to binary or decimal.
+ * Each ternary digit describes the line width in one direction:
+ * 0 means no line, 1 single or light line, 2 double or heavy line.
+ */
+
+/* Positional values of the four directions. */
+#define BRIGHT 1
+#define BDOWN 3
+#define BLEFT (3 * 3)
+#define BUP (3 * 3 * 3)
+#define BHORIZ (BLEFT + BRIGHT)
+
+/* Code points to use for each combination of widths. */
+static const int borders_utf8[81] = {
+ 0x0020, 0x2576, 0x257a, /* 000 right */
+ 0x2577, 0x250c, 0x250d, /* 001 down */
+ 0x257b, 0x250e, 0x250f, /* 002 */
+ 0x2574, 0x2500, 0x257c, /* 010 left */
+ 0x2510, 0x252c, 0x252e, /* 011 left down */
+ 0x2512, 0x2530, 0x2532, /* 012 */
+ 0x2578, 0x257e, 0x2501, /* 020 left */
+ 0x2511, 0x252d, 0x252f, /* 021 left down */
+ 0x2513, 0x2531, 0x2533, /* 022 */
+ 0x2575, 0x2514, 0x2515, /* 100 up */
+ 0x2502, 0x251c, 0x251d, /* 101 up down */
+ 0x257d, 0x251f, 0x2522, /* 102 */
+ 0x2518, 0x2534, 0x2536, /* 110 up left */
+ 0x2524, 0x253c, 0x253e, /* 111 all */
+ 0x2527, 0x2541, 0x2546, /* 112 */
+ 0x2519, 0x2535, 0x2537, /* 120 up left */
+ 0x2525, 0x253d, 0x253f, /* 121 all */
+ 0x252a, 0x2545, 0x2548, /* 122 */
+ 0x2579, 0x2516, 0x2517, /* 200 up */
+ 0x257f, 0x251e, 0x2521, /* 201 up down */
+ 0x2503, 0x2520, 0x2523, /* 202 */
+ 0x251a, 0x2538, 0x253a, /* 210 up left */
+ 0x2526, 0x2540, 0x2544, /* 211 all */
+ 0x2528, 0x2542, 0x254a, /* 212 */
+ 0x251b, 0x2539, 0x253b, /* 220 up left */
+ 0x2529, 0x2543, 0x2547, /* 221 all */
+ 0x252b, 0x2549, 0x254b, /* 222 */
+};
+
+/* ASCII approximations for these code points, compatible with groff. */
+static const int borders_ascii[81] = {
+ ' ', '-', '=', /* 000 right */
+ '|', '+', '+', /* 001 down */
+ '|', '+', '+', /* 002 */
+ '-', '-', '=', /* 010 left */
+ '+', '+', '+', /* 011 left down */
+ '+', '+', '+', /* 012 */
+ '=', '=', '=', /* 020 left */
+ '+', '+', '+', /* 021 left down */
+ '+', '+', '+', /* 022 */
+ '|', '+', '+', /* 100 up */
+ '|', '+', '+', /* 101 up down */
+ '|', '+', '+', /* 102 */
+ '+', '+', '+', /* 110 up left */
+ '+', '+', '+', /* 111 all */
+ '+', '+', '+', /* 112 */
+ '+', '+', '+', /* 120 up left */
+ '+', '+', '+', /* 121 all */
+ '+', '+', '+', /* 122 */
+ '|', '+', '+', /* 200 up */
+ '|', '+', '+', /* 201 up down */
+ '|', '+', '+', /* 202 */
+ '+', '+', '+', /* 210 up left */
+ '+', '+', '+', /* 211 all */
+ '+', '+', '+', /* 212 */
+ '+', '+', '+', /* 220 up left */
+ '+', '+', '+', /* 221 all */
+ '+', '+', '+', /* 222 */
+};
+
+/* Either of the above according to the selected output encoding. */
+static const int *borders_locale;
+
+
static size_t
term_tbl_sulen(const struct roffsu *su, void *arg)
{
@@ -69,19 +156,22 @@ term_tbl_len(size_t sz, void *arg)
return term_len((const struct termp *)arg, sz);
}
+
void
term_tbl(struct termp *tp, const struct tbl_span *sp)
{
- const struct tbl_cell *cp, *cpn, *cpp;
+ const struct tbl_cell *cp, *cpn, *cpp, *cps;
const struct tbl_dat *dp;
static size_t offset;
+ size_t save_offset;
size_t coloff, tsz;
- int ic, horiz, spans, vert, more;
- char fc;
+ int hspans, ic, more;
+ int dvert, fc, horiz, lhori, rhori, uvert;
/* Inhibit printing of spaces: we do padding ourselves. */
tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
+ save_offset = tp->tcol->offset;
/*
* The first time we're invoked for a given table block,
@@ -89,6 +179,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
*/
if (tp->tbl.cols == NULL) {
+ borders_locale = tp->enc == TERMENC_UTF8 ?
+ borders_utf8 : borders_ascii;
+
tp->tbl.len = term_tbl_len;
tp->tbl.slen = term_tbl_strlen;
tp->tbl.sulen = term_tbl_sulen;
@@ -120,21 +213,24 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tsz += tp->tbl.cols[sp->opts->cols - 1].width;
if (offset + tsz > tp->tcol->rmargin)
tsz -= 1;
- tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
+ offset = offset + tp->tcol->rmargin > tsz ?
(offset + tp->tcol->rmargin - tsz) / 2 : 0;
+ tp->tcol->offset = offset;
}
/* Horizontal frame at the start of boxed tables. */
- if (sp->opts->opts & TBL_OPT_DBOX)
- tbl_hrule(tp, sp, 3);
+ if (tp->enc == TERMENC_ASCII &&
+ sp->opts->opts & TBL_OPT_DBOX)
+ tbl_hrule(tp, NULL, sp, TBL_OPT_DBOX);
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
- tbl_hrule(tp, sp, 2);
+ tbl_hrule(tp, NULL, sp, TBL_OPT_BOX);
}
/* Set up the columns. */
tp->flags |= TERMP_MULTICOL;
+ tp->tcol->offset = offset;
horiz = 0;
switch (sp->pos) {
case TBL_SPAN_HORIZ:
@@ -156,9 +252,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Set up the data columns. */
dp = sp->first;
- spans = 0;
+ hspans = 0;
for (ic = 0; ic < sp->opts->cols; ic++) {
- if (spans == 0) {
+ if (hspans == 0) {
tp->tcol++;
tp->tcol->offset = coloff;
}
@@ -166,13 +262,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tcol->rmargin = coloff;
if (ic + 1 < sp->opts->cols)
coloff += tp->tbl.cols[ic].spacing;
- if (spans) {
- spans--;
+ if (hspans) {
+ hspans--;
continue;
}
if (dp == NULL)
continue;
- spans = dp->spans;
+ hspans = dp->hspans;
if (ic || sp->layout->first->pos != TBL_CELL_SPAN)
dp = dp->next;
}
@@ -192,14 +288,14 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tcol = tp->tcols;
cp = cpn = sp->layout->first;
dp = sp->first;
- spans = 0;
+ hspans = 0;
for (ic = 0; ic < sp->opts->cols; ic++) {
if (cpn != NULL) {
cp = cpn;
cpn = cpn->next;
}
- if (spans) {
- spans--;
+ if (hspans) {
+ hspans--;
continue;
}
tp->tcol++;
@@ -207,7 +303,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
if (dp == NULL)
continue;
- spans = dp->spans;
+ hspans = dp->hspans;
if (cp->pos != TBL_CELL_SPAN)
dp = dp->next;
}
@@ -218,37 +314,43 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
/* Print the vertical frame at the start of each row. */
tp->tcol = tp->tcols;
- fc = '\0';
- if (sp->layout->vert ||
- (sp->next != NULL && sp->next->layout->vert &&
- sp->next->pos == TBL_SPAN_DATA) ||
- (sp->prev != NULL && sp->prev->layout->vert &&
- (horiz || (IS_HORIZ(sp->layout->first) &&
- !IS_HORIZ(sp->prev->layout->first)))) ||
- sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
- fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
- else if (horiz && sp->opts->lvert)
- fc = '-';
- if (fc != '\0') {
+ uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 :
+ sp->opts->opts & TBL_OPT_BOX ? 1 : 0;
+ if (sp->pos == TBL_SPAN_DATA && uvert < sp->layout->vert)
+ uvert = dvert = sp->layout->vert;
+ if (sp->next != NULL && sp->next->pos == TBL_SPAN_DATA &&
+ dvert < sp->next->layout->vert)
+ dvert = sp->next->layout->vert;
+ if (sp->prev != NULL && uvert < sp->prev->layout->vert &&
+ (horiz || (IS_HORIZ(sp->layout->first) &&
+ !IS_HORIZ(sp->prev->layout->first))))
+ uvert = sp->prev->layout->vert;
+ rhori = sp->pos == TBL_SPAN_DHORIZ ||
+ (sp->first != NULL && sp->first->pos == TBL_DATA_DHORIZ) ||
+ sp->layout->first->pos == TBL_CELL_DHORIZ ? 2 :
+ sp->pos == TBL_SPAN_HORIZ ||
+ (sp->first != NULL && sp->first->pos == TBL_DATA_HORIZ) ||
+ sp->layout->first->pos == TBL_CELL_HORIZ ? 1 : 0;
+ fc = BUP * uvert + BDOWN * dvert + BRIGHT * rhori;
+ if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) {
(*tp->advance)(tp, tp->tcols->offset);
- (*tp->letter)(tp, fc);
- tp->viscol = tp->tcol->offset + 1;
+ tp->viscol = tp->tcol->offset;
+ tbl_direct_border(tp, fc, 1);
}
/* Print the data cells. */
more = 0;
- if (horiz) {
- tbl_hrule(tp, sp, 0);
- term_flushln(tp);
- } else {
+ if (horiz)
+ tbl_hrule(tp, sp->prev, sp, 0);
+ else {
cp = sp->layout->first;
cpn = sp->next == NULL ? NULL :
sp->next->layout->first;
cpp = sp->prev == NULL ? NULL :
sp->prev->layout->first;
dp = sp->first;
- spans = 0;
+ hspans = 0;
for (ic = 0; ic < sp->opts->cols; ic++) {
/*
@@ -257,25 +359,27 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* and advance to next layout cell.
*/
+ uvert = dvert = fc = 0;
if (cp != NULL) {
- vert = cp->vert;
+ cps = cp;
+ while (cps->next != NULL &&
+ cps->next->pos == TBL_CELL_SPAN)
+ cps = cps->next;
+ if (sp->pos == TBL_SPAN_DATA)
+ uvert = dvert = cps->vert;
switch (cp->pos) {
case TBL_CELL_HORIZ:
- fc = '-';
+ fc = BHORIZ;
break;
case TBL_CELL_DHORIZ:
- fc = '=';
+ fc = BHORIZ * 2;
break;
default:
- fc = ' ';
break;
}
- } else {
- vert = 0;
- fc = ' ';
}
if (cpp != NULL) {
- if (vert == 0 &&
+ if (uvert < cpp->vert &&
cp != NULL &&
((IS_HORIZ(cp) &&
!IS_HORIZ(cpp)) ||
@@ -283,19 +387,31 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
cpp->next != NULL &&
IS_HORIZ(cp->next) &&
!IS_HORIZ(cpp->next))))
- vert = cpp->vert;
+ uvert = cpp->vert;
cpp = cpp->next;
}
- if (vert == 0 &&
- sp->opts->opts & TBL_OPT_ALLBOX)
- vert = 1;
+ if (sp->opts->opts & TBL_OPT_ALLBOX) {
+ if (uvert == 0)
+ uvert = 1;
+ if (dvert == 0)
+ dvert = 1;
+ }
if (cpn != NULL) {
- if (vert == 0)
- vert = cpn->vert;
+ if (dvert == 0 ||
+ (dvert < cpn->vert &&
+ tp->enc == TERMENC_UTF8))
+ dvert = cpn->vert;
cpn = cpn->next;
}
- if (cp != NULL)
- cp = cp->next;
+
+ lhori = (cp != NULL &&
+ cp->pos == TBL_CELL_DHORIZ) ||
+ (dp != NULL &&
+ dp->pos == TBL_DATA_DHORIZ) ? 2 :
+ (cp != NULL &&
+ cp->pos == TBL_CELL_HORIZ) ||
+ (dp != NULL &&
+ dp->pos == TBL_DATA_HORIZ) ? 1 : 0;
/*
* Skip later cells in a span,
@@ -303,12 +419,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* and advance to next data cell.
*/
- if (spans) {
- spans--;
+ if (hspans) {
+ hspans--;
+ cp = cp->next;
continue;
}
if (dp != NULL) {
- spans = dp->spans;
+ hspans = dp->hspans;
if (ic || sp->layout->first->pos
!= TBL_CELL_SPAN)
dp = dp->next;
@@ -330,10 +447,16 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* but not after the last column.
*/
- if (fc == ' ' && ((vert == 0 &&
- (cp == NULL || !IS_HORIZ(cp))) ||
- tp->tcol + 1 == tp->tcols + tp->lasttcol))
+ if (fc == 0 &&
+ ((uvert == 0 && dvert == 0 &&
+ cp != NULL && (cp->next == NULL ||
+ !IS_HORIZ(cp->next))) ||
+ tp->tcol + 1 ==
+ tp->tcols + tp->lasttcol)) {
+ if (cp != NULL)
+ cp = cp->next;
continue;
+ }
if (tp->viscol < tp->tcol->rmargin) {
(*tp->advance)(tp, tp->tcol->rmargin
@@ -341,77 +464,83 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->viscol = tp->tcol->rmargin;
}
while (tp->viscol < tp->tcol->rmargin +
- tp->tbl.cols[ic].spacing / 2) {
- (*tp->letter)(tp, fc);
- tp->viscol++;
- }
+ tp->tbl.cols[ic].spacing / 2)
+ tbl_direct_border(tp,
+ BHORIZ * lhori, 1);
if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
continue;
- if (fc == ' ' && cp != NULL) {
- switch (cp->pos) {
- case TBL_CELL_HORIZ:
- fc = '-';
- break;
- case TBL_CELL_DHORIZ:
- fc = '=';
- break;
- default:
- break;
- }
- }
- if (tp->tbl.cols[ic].spacing) {
- (*tp->letter)(tp, fc == ' ' ? '|' :
- vert ? '+' : fc);
- tp->viscol++;
- }
+ if (cp != NULL)
+ cp = cp->next;
+
+ rhori = (cp != NULL &&
+ cp->pos == TBL_CELL_DHORIZ) ||
+ (dp != NULL &&
+ dp->pos == TBL_DATA_DHORIZ) ? 2 :
+ (cp != NULL &&
+ cp->pos == TBL_CELL_HORIZ) ||
+ (dp != NULL &&
+ dp->pos == TBL_DATA_HORIZ) ? 1 : 0;
+
+ if (tp->tbl.cols[ic].spacing)
+ tbl_direct_border(tp,
+ BLEFT * lhori + BRIGHT * rhori +
+ BUP * uvert + BDOWN * dvert, 1);
+
+ if (tp->enc == TERMENC_UTF8)
+ uvert = dvert = 0;
- if (fc != ' ') {
- if (cp != NULL &&
- cp->pos == TBL_CELL_HORIZ)
- fc = '-';
- else if (cp != NULL &&
- cp->pos == TBL_CELL_DHORIZ)
- fc = '=';
- else
- fc = ' ';
- }
if (tp->tbl.cols[ic].spacing > 2 &&
- (vert > 1 || fc != ' ')) {
- (*tp->letter)(tp, fc == ' ' ? '|' :
- vert > 1 ? '+' : fc);
- tp->viscol++;
- }
+ (uvert > 1 || dvert > 1 || rhori))
+ tbl_direct_border(tp,
+ BHORIZ * rhori +
+ BUP * (uvert > 1) +
+ BDOWN * (dvert > 1), 1);
}
}
/* Print the vertical frame at the end of each row. */
- fc = '\0';
- if ((sp->layout->last->vert &&
- sp->layout->last->col + 1 == sp->opts->cols) ||
- (sp->next != NULL &&
- sp->next->layout->last->vert &&
- sp->next->layout->last->col + 1 == sp->opts->cols) ||
- (sp->prev != NULL &&
- sp->prev->layout->last->vert &&
- sp->prev->layout->last->col + 1 == sp->opts->cols &&
- (horiz || (IS_HORIZ(sp->layout->last) &&
- !IS_HORIZ(sp->prev->layout->last)))) ||
- (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
- fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
- else if (horiz && sp->opts->rvert)
- fc = '-';
- if (fc != '\0') {
+ uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 :
+ sp->opts->opts & TBL_OPT_BOX ? 1 : 0;
+ if (sp->pos == TBL_SPAN_DATA &&
+ uvert < sp->layout->last->vert &&
+ sp->layout->last->col + 1 == sp->opts->cols)
+ uvert = dvert = sp->layout->last->vert;
+ if (sp->next != NULL &&
+ dvert < sp->next->layout->last->vert &&
+ sp->next->layout->last->col + 1 == sp->opts->cols)
+ dvert = sp->next->layout->last->vert;
+ if (sp->prev != NULL &&
+ uvert < sp->prev->layout->last->vert &&
+ sp->prev->layout->last->col + 1 == sp->opts->cols &&
+ (horiz || (IS_HORIZ(sp->layout->last) &&
+ !IS_HORIZ(sp->prev->layout->last))))
+ uvert = sp->prev->layout->last->vert;
+ lhori = sp->pos == TBL_SPAN_DHORIZ ||
+ (sp->last != NULL &&
+ sp->last->pos == TBL_DATA_DHORIZ &&
+ sp->last->layout->col + 1 == sp->opts->cols) ||
+ (sp->layout->last->pos == TBL_CELL_DHORIZ &&
+ sp->layout->last->col + 1 == sp->opts->cols) ? 2 :
+ sp->pos == TBL_SPAN_HORIZ ||
+ (sp->last != NULL &&
+ sp->last->pos == TBL_DATA_HORIZ &&
+ sp->last->layout->col + 1 == sp->opts->cols) ||
+ (sp->layout->last->pos == TBL_CELL_HORIZ &&
+ sp->layout->last->col + 1 == sp->opts->cols) ? 1 : 0;
+ fc = BUP * uvert + BDOWN * dvert + BLEFT * lhori;
+ if (uvert > 0 || dvert > 0 || (horiz && sp->opts->rvert)) {
if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
sp->layout->last->col + 1 < sp->opts->cols)) {
tp->tcol++;
- (*tp->advance)(tp,
- tp->tcol->offset > tp->viscol ?
- tp->tcol->offset - tp->viscol : 1);
+ do {
+ tbl_direct_border(tp,
+ BHORIZ * lhori, 1);
+ } while (tp->viscol < tp->tcol->offset);
}
- (*tp->letter)(tp, fc);
+ tbl_direct_border(tp, fc, 1);
}
(*tp->endline)(tp);
tp->viscol = 0;
@@ -428,80 +557,156 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tcol->rmargin = tp->maxrmargin;
if (sp->next == NULL) {
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
- tbl_hrule(tp, sp, 2);
+ tbl_hrule(tp, sp, NULL, TBL_OPT_BOX);
tp->skipvsp = 1;
}
- if (sp->opts->opts & TBL_OPT_DBOX) {
- tbl_hrule(tp, sp, 3);
+ if (tp->enc == TERMENC_ASCII &&
+ sp->opts->opts & TBL_OPT_DBOX) {
+ tbl_hrule(tp, sp, NULL, TBL_OPT_DBOX);
tp->skipvsp = 2;
}
assert(tp->tbl.cols);
free(tp->tbl.cols);
tp->tbl.cols = NULL;
- tp->tcol->offset = offset;
} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
(sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
sp->next->next != NULL))
- tbl_hrule(tp, sp, 1);
+ tbl_hrule(tp, sp, sp->next, TBL_OPT_ALLBOX);
+ tp->tcol->offset = save_offset;
tp->flags &= ~TERMP_NONOSPACE;
}
-/*
- * Kinds of horizontal rulers:
- * 0: inside the table (single or double line with crossings)
- * 1: inside the table (single or double line with crossings and ends)
- * 2: inner frame (single line with crossings and ends)
- * 3: outer frame (single line without crossings with ends)
- */
static void
-tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
+tbl_hrule(struct termp *tp, const struct tbl_span *spp,
+ const struct tbl_span *spn, int flags)
{
- const struct tbl_cell *cp, *cpn, *cpp;
- const struct roffcol *col;
- int vert;
- char line, cross;
-
- line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
- cross = (kind < 3) ? '+' : '-';
-
- if (kind)
- term_word(tp, "+");
- cp = sp->layout->first;
- cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
- if (cpp == cp)
- cpp = NULL;
- cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
- if (cpn == cp)
- cpn = NULL;
+ const struct tbl_cell *cpp; /* Layout cell above this line. */
+ const struct tbl_cell *cpn; /* Layout cell below this line. */
+ const struct tbl_dat *dpn; /* Data cell below this line. */
+ const struct roffcol *col; /* Contains width and spacing. */
+ int opts; /* For the table as a whole. */
+ int bw; /* Box line width. */
+ int hw; /* Horizontal line width. */
+ int lw, rw; /* Left and right line widths. */
+ int uw, dw; /* Vertical line widths. */
+
+ cpp = spp == NULL ? NULL : spp->layout->first;
+ cpn = spn == NULL ? NULL : spn->layout->first;
+ dpn = NULL;
+ if (spn != NULL) {
+ if (spn->pos == TBL_SPAN_DATA)
+ dpn = spn->first;
+ else if (spn->next != NULL)
+ dpn = spn->next->first;
+ }
+ opts = spn == NULL ? spp->opts->opts : spn->opts->opts;
+ bw = opts & TBL_OPT_DBOX ? (tp->enc == TERMENC_UTF8 ? 2 : 1) :
+ opts & (TBL_OPT_BOX | TBL_OPT_ALLBOX) ? 1 : 0;
+ hw = flags == TBL_OPT_DBOX || flags == TBL_OPT_BOX ? bw :
+ spn->pos == TBL_SPAN_DHORIZ ? 2 : 1;
+
+ /* Print the left end of the line. */
+
+ if (tp->viscol == 0) {
+ (*tp->advance)(tp, tp->tcols->offset);
+ tp->viscol = tp->tcols->offset;
+ }
+ if (flags != 0)
+ tbl_direct_border(tp,
+ (spp == NULL ? 0 : BUP * bw) +
+ (spn == NULL ? 0 : BDOWN * bw) +
+ (spp == NULL || cpn == NULL ||
+ cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1);
+
for (;;) {
- col = tp->tbl.cols + cp->col;
- tbl_char(tp, line, col->width + col->spacing / 2);
- vert = cp->vert;
- if ((cp = cp->next) == NULL)
- break;
+ col = tp->tbl.cols + (cpn == NULL ? cpp->col : cpn->col);
+
+ /* Print the horizontal line inside this column. */
+
+ lw = cpp == NULL || cpn == NULL ||
+ (cpn->pos != TBL_CELL_DOWN &&
+ (dpn == NULL || strcmp(dpn->string, "\\^") != 0))
+ ? hw : 0;
+ tbl_direct_border(tp, BHORIZ * lw,
+ col->width + col->spacing / 2);
+
+ /*
+ * Figure out whether a vertical line is crossing
+ * at the end of this column,
+ * and advance to the next column.
+ */
+
+ uw = dw = 0;
if (cpp != NULL) {
- if (vert < cpp->vert)
- vert = cpp->vert;
+ if (flags != TBL_OPT_DBOX) {
+ uw = cpp->vert;
+ if (uw == 0 && opts & TBL_OPT_ALLBOX)
+ uw = 1;
+ }
cpp = cpp->next;
}
if (cpn != NULL) {
- if (vert < cpn->vert)
- vert = cpn->vert;
+ if (flags != TBL_OPT_DBOX) {
+ dw = cpn->vert;
+ if (dw == 0 && opts & TBL_OPT_ALLBOX)
+ dw = 1;
+ }
cpn = cpn->next;
+ while (dpn != NULL && dpn->layout != cpn)
+ dpn = dpn->next;
}
- if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
- vert = 1;
+ if (cpp == NULL && cpn == NULL)
+ break;
+
+ /* Vertical lines do not cross spanned cells. */
+
+ if (cpp != NULL && cpp->pos == TBL_CELL_SPAN)
+ uw = 0;
+ if (cpn != NULL && cpn->pos == TBL_CELL_SPAN)
+ dw = 0;
+
+ /* The horizontal line inside the next column. */
+
+ rw = cpp == NULL || cpn == NULL ||
+ (cpn->pos != TBL_CELL_DOWN &&
+ (dpn == NULL || strcmp(dpn->string, "\\^") != 0))
+ ? hw : 0;
+
+ /* The line crossing at the end of this column. */
+
if (col->spacing)
- tbl_char(tp, vert ? cross : line, 1);
+ tbl_direct_border(tp, BLEFT * lw +
+ BRIGHT * rw + BUP * uw + BDOWN * dw, 1);
+
+ /*
+ * In ASCII output, a crossing may print two characters.
+ */
+
+ if (tp->enc != TERMENC_ASCII || (uw < 2 && dw < 2))
+ uw = dw = 0;
if (col->spacing > 2)
- tbl_char(tp, vert > 1 ? cross : line, 1);
+ tbl_direct_border(tp,
+ BHORIZ * rw + BUP * uw + BDOWN * dw, 1);
+
+ /* Padding before the start of the next column. */
+
if (col->spacing > 4)
- tbl_char(tp, line, (col->spacing - 3) / 2);
+ tbl_direct_border(tp,
+ BHORIZ * rw, (col->spacing - 3) / 2);
}
- if (kind) {
- term_word(tp, "+");
- term_flushln(tp);
+
+ /* Print the right end of the line. */
+
+ if (flags != 0) {
+ tbl_direct_border(tp,
+ (spp == NULL ? 0 : BUP * bw) +
+ (spn == NULL ? 0 : BDOWN * bw) +
+ (spp == NULL || spn == NULL ||
+ spn->layout->last->pos != TBL_CELL_DOWN ?
+ BLEFT * hw : 0), 1);
+ (*tp->endline)(tp);
+ tp->viscol = 0;
}
}
@@ -512,10 +717,10 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
{
switch (cp->pos) {
case TBL_CELL_HORIZ:
- tbl_char(tp, '-', col->width);
+ tbl_fill_border(tp, BHORIZ, col->width);
return;
case TBL_CELL_DHORIZ:
- tbl_char(tp, '=', col->width);
+ tbl_fill_border(tp, BHORIZ * 2, col->width);
return;
default:
break;
@@ -529,11 +734,11 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
return;
case TBL_DATA_HORIZ:
case TBL_DATA_NHORIZ:
- tbl_char(tp, '-', col->width);
+ tbl_fill_border(tp, BHORIZ, col->width);
return;
case TBL_DATA_NDHORIZ:
case TBL_DATA_DHORIZ:
- tbl_char(tp, '=', col->width);
+ tbl_fill_border(tp, BHORIZ * 2, col->width);
return;
default:
break;
@@ -558,18 +763,48 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
}
static void
-tbl_char(struct termp *tp, char c, size_t len)
+tbl_fill_string(struct termp *tp, const char *cp, size_t len)
{
- size_t i, sz;
- char cp[2];
+ size_t i, sz;
+
+ sz = term_strlen(tp, cp);
+ for (i = 0; i < len; i += sz)
+ term_word(tp, cp);
+}
+
+static void
+tbl_fill_char(struct termp *tp, char c, size_t len)
+{
+ char cp[2];
cp[0] = c;
cp[1] = '\0';
+ tbl_fill_string(tp, cp, len);
+}
- sz = term_strlen(tp, cp);
+static void
+tbl_fill_border(struct termp *tp, int c, size_t len)
+{
+ char buf[12];
- for (i = 0; i < len; i += sz)
- term_word(tp, cp);
+ if ((c = borders_locale[c]) > 127) {
+ (void)snprintf(buf, sizeof(buf), "\\[u%04x]", c);
+ tbl_fill_string(tp, buf, len);
+ } else
+ tbl_fill_char(tp, c, len);
+}
+
+static void
+tbl_direct_border(struct termp *tp, int c, size_t len)
+{
+ size_t i, sz;
+
+ c = borders_locale[c];
+ sz = (*tp->width)(tp, c);
+ for (i = 0; i < len; i += sz) {
+ (*tp->letter)(tp, c);
+ tp->viscol += sz;
+ }
}
static void
@@ -577,14 +812,14 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
const struct roffcol *col)
{
size_t len, padl, padr, width;
- int ic, spans;
+ int ic, hspans;
assert(dp->string);
len = term_strlen(tp, dp->string);
width = col->width;
ic = dp->layout->col;
- spans = dp->spans;
- while (spans--)
+ hspans = dp->hspans;
+ while (hspans--)
width += tp->tbl.cols[++ic].width + 3;
padr = width > len ? width - len : 0;
@@ -609,9 +844,9 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
break;
}
- tbl_char(tp, ASCII_NBRSP, padl);
+ tbl_fill_char(tp, ASCII_NBRSP, padl);
tbl_word(tp, dp);
- tbl_char(tp, ASCII_NBRSP, padr);
+ tbl_fill_char(tp, ASCII_NBRSP, padr);
}
static void
@@ -619,44 +854,66 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
const struct tbl_dat *dp,
const struct roffcol *col)
{
- char *cp;
+ const char *cp, *lastdigit, *lastpoint;
+ size_t intsz, padl, totsz;
char buf[2];
- size_t sz, psz, ssz, d, padl;
- int i;
/*
- * See calc_data_number(). Left-pad by taking the offset of our
- * and the maximum decimal; right-pad by the remaining amount.
+ * Almost the same code as in tblcalc_number():
+ * First find the position of the decimal point.
*/
assert(dp->string);
+ lastdigit = lastpoint = NULL;
+ for (cp = dp->string; cp[0] != '\0'; cp++) {
+ if (cp[0] == '\\' && cp[1] == '&') {
+ lastdigit = lastpoint = cp;
+ break;
+ } else if (cp[0] == opts->decimal &&
+ (isdigit((unsigned char)cp[1]) ||
+ (cp > dp->string && isdigit((unsigned char)cp[-1]))))
+ lastpoint = cp;
+ else if (isdigit((unsigned char)cp[0]))
+ lastdigit = cp;
+ }
- sz = term_strlen(tp, dp->string);
+ /* Then measure both widths. */
- buf[0] = opts->decimal;
- buf[1] = '\0';
+ padl = 0;
+ totsz = term_strlen(tp, dp->string);
+ if (lastdigit != NULL) {
+ if (lastpoint == NULL)
+ lastpoint = lastdigit + 1;
+ intsz = 0;
+ buf[1] = '\0';
+ for (cp = dp->string; cp < lastpoint; cp++) {
+ buf[0] = cp[0];
+ intsz += term_strlen(tp, buf);
+ }
- psz = term_strlen(tp, buf);
+ /*
+ * Pad left to match the decimal position,
+ * but avoid exceeding the total column width.
+ */
- 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);
+ if (col->decimal > intsz && col->width > totsz) {
+ padl = col->decimal - intsz;
+ if (padl + totsz > col->width)
+ padl = col->width - totsz;
}
- d = ssz + psz;
- } else
- d = sz + psz;
- 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;
+ /* If it is not a number, simply center the string. */
+
+ } else if (col->width > totsz)
+ padl = (col->width - totsz) / 2;
+
+ tbl_fill_char(tp, ASCII_NBRSP, padl);
tbl_word(tp, dp);
- if (col->width > sz + padl)
- tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
+
+ /* Pad right to fill the column. */
+
+ if (col->width > padl + totsz)
+ tbl_fill_char(tp, ASCII_NBRSP, col->width - padl - totsz);
}
static void
diff --git a/usr/src/cmd/mandoc/term.c b/usr/src/cmd/mandoc/term.c
index f67fcf9d95..3b9277aaab 100644
--- a/usr/src/cmd/mandoc/term.c
+++ b/usr/src/cmd/mandoc/term.c
@@ -1,7 +1,7 @@
-/* $Id: term.c,v 1.274 2017/07/28 14:25:48 schwarze Exp $ */
+/* $Id: term.c,v 1.281 2019/06/03 20:23:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2019 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -37,6 +38,10 @@ static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int);
static void endline(struct termp *);
+static void term_field(struct termp *, size_t, size_t,
+ size_t, size_t);
+static void term_fill(struct termp *, size_t *, size_t *,
+ size_t);
void
@@ -83,241 +88,327 @@ term_end(struct termp *p)
* Flush a chunk of text. By default, break the output line each time
* the right margin is reached, and continue output on the next line
* at the same offset as the chunk itself. By default, also break the
- * output line at the end of the chunk.
- * The following flags may be specified:
- *
- * - TERMP_NOBREAK: Do not break the output line at the right margin,
- * but only at the max right margin. Also, do not break the output
- * line at the end of the chunk, such that the next call can pad to
- * the next column. However, if less than p->trailspace blanks,
- * which can be 0, 1, or 2, remain to the right margin, the line
- * will be broken.
- * - TERMP_BRTRSP: Consider trailing whitespace significant
- * when deciding whether the chunk fits or not.
- * - TERMP_BRIND: If the chunk does not fit and the output line has
- * to be broken, start the next line at the right margin instead
- * of at the offset. Used together with TERMP_NOBREAK for the tags
- * in various kinds of tagged lists.
- * - TERMP_HANG: Do not break the output line at the right margin,
- * append the next chunk after it even if this one is too long.
- * To be used together with TERMP_NOBREAK.
- * - TERMP_NOPAD: Start writing at the current position,
- * do not pad with blank characters up to the offset.
+ * output line at the end of the chunk. There are many flags modifying
+ * this behaviour, see the comments in the body of the function.
*/
void
term_flushln(struct termp *p)
{
- size_t vis; /* current visual position on output */
- size_t vbl; /* number of blanks to prepend to output */
- size_t vend; /* end of word visual position on output */
- size_t bp; /* visual right border position */
- size_t dv; /* temporary for visual pos calculations */
- size_t j; /* temporary loop index for p->tcol->buf */
- size_t jhy; /* last hyph before overflow w/r/t j */
- size_t maxvis; /* output position of visible boundary */
- int ntab; /* number of tabs to prepend */
- int breakline; /* after this word */
+ size_t vbl; /* Number of blanks to prepend to the output. */
+ size_t vbr; /* Actual visual position of the end of field. */
+ size_t vfield; /* Desired visual field width. */
+ size_t vtarget; /* Desired visual position of the right margin. */
+ size_t ic; /* Character position in the input buffer. */
+ size_t nbr; /* Number of characters to print in this field. */
+
+ /*
+ * Normally, start writing at the left margin, but with the
+ * NOPAD flag, start writing at the current position instead.
+ */
vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
0 : p->tcol->offset - p->viscol;
if (p->minbl && vbl < p->minbl)
vbl = p->minbl;
- maxvis = p->tcol->rmargin > p->viscol + vbl ?
- p->tcol->rmargin - p->viscol - vbl : 0;
- bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
- p->maxrmargin > p->viscol + vbl ?
- p->maxrmargin - p->viscol - vbl : 0;
- vis = vend = 0;
if ((p->flags & TERMP_MULTICOL) == 0)
p->tcol->col = 0;
- while (p->tcol->col < p->tcol->lastcol) {
+
+ /* Loop over output lines. */
+
+ for (;;) {
+ vfield = p->tcol->rmargin > p->viscol + vbl ?
+ p->tcol->rmargin - p->viscol - vbl : 0;
/*
- * Handle literal tab characters: collapse all
- * subsequent tabs into a single huge set of spaces.
+ * Normally, break the line at the the right margin
+ * of the field, but with the NOBREAK flag, only
+ * break it at the max right margin of the screen,
+ * and with the BRNEVER flag, never break it at all.
*/
- ntab = 0;
- while (p->tcol->col < p->tcol->lastcol &&
- p->tcol->buf[p->tcol->col] == '\t') {
- vend = term_tab_next(vis);
- vbl += vend - vis;
- vis = vend;
- ntab++;
- p->tcol->col++;
+ vtarget = p->flags & TERMP_BRNEVER ? SIZE_MAX :
+ (p->flags & TERMP_NOBREAK) == 0 ? vfield :
+ p->maxrmargin > p->viscol + vbl ?
+ p->maxrmargin - p->viscol - vbl : 0;
+
+ /*
+ * Figure out how much text will fit in the field.
+ * If there is whitespace only, print nothing.
+ */
+
+ term_fill(p, &nbr, &vbr, vtarget);
+ if (nbr == 0)
+ break;
+
+ /*
+ * With the CENTER or RIGHT flag, increase the indentation
+ * to center the text between the left and right margins
+ * or to adjust it to the right margin, respectively.
+ */
+
+ if (vbr < vtarget) {
+ if (p->flags & TERMP_CENTER)
+ vbl += (vtarget - vbr) / 2;
+ else if (p->flags & TERMP_RIGHT)
+ vbl += vtarget - vbr;
}
+ /* Finally, print the field content. */
+
+ term_field(p, vbl, nbr, vbr, vtarget);
+
/*
- * Count up visible word characters. Control sequences
- * (starting with the CSI) aren't counted. A space
- * generates a non-printing word, which is valid (the
- * space is printed according to regular spacing rules).
+ * If there is no text left in the field, exit the loop.
+ * If the BRTRSP flag is set, consider trailing
+ * whitespace significant when deciding whether
+ * the field fits or not.
*/
- jhy = 0;
- breakline = 0;
- for (j = p->tcol->col; j < p->tcol->lastcol; j++) {
- if (p->tcol->buf[j] == '\n') {
- if ((p->flags & TERMP_BRIND) == 0)
- breakline = 1;
+ for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) {
+ switch (p->tcol->buf[ic]) {
+ case '\t':
+ if (p->flags & TERMP_BRTRSP)
+ vbr = term_tab_next(vbr);
continue;
- }
- if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
- break;
-
- /* Back over the last printed character. */
- if (p->tcol->buf[j] == '\b') {
- assert(j);
- vend -= (*p->width)(p, p->tcol->buf[j - 1]);
+ case ' ':
+ if (p->flags & TERMP_BRTRSP)
+ vbr += (*p->width)(p, ' ');
continue;
+ case '\n':
+ case ASCII_BREAK:
+ continue;
+ default:
+ break;
}
+ break;
+ }
+ if (ic == p->tcol->lastcol)
+ break;
- /* Regular word. */
- /* Break at the hyphen point if we overrun. */
- if (vend > vis && vend < bp &&
- (p->tcol->buf[j] == ASCII_HYPH||
- p->tcol->buf[j] == ASCII_BREAK))
- jhy = j;
+ /*
+ * At the location of an automtic line break, input
+ * space characters are consumed by the line break.
+ */
- /*
- * Hyphenation now decided, put back a real
- * hyphen such that we get the correct width.
- */
- if (p->tcol->buf[j] == ASCII_HYPH)
- p->tcol->buf[j] = '-';
+ while (p->tcol->col < p->tcol->lastcol &&
+ p->tcol->buf[p->tcol->col] == ' ')
+ p->tcol->col++;
- vend += (*p->width)(p, p->tcol->buf[j]);
- }
+ /*
+ * In multi-column mode, leave the rest of the text
+ * in the buffer to be handled by a subsequent
+ * invocation, such that the other columns of the
+ * table can be handled first.
+ * In single-column mode, simply break the line.
+ */
+
+ if (p->flags & TERMP_MULTICOL)
+ return;
+
+ endline(p);
+ p->viscol = 0;
/*
- * Find out whether we would exceed the right margin.
- * If so, break to the next line.
+ * Normally, start the next line at the same indentation
+ * as this one, but with the BRIND flag, start it at the
+ * right margin instead. This is used together with
+ * NOBREAK for the tags in various kinds of tagged lists.
*/
- if (vend > bp && jhy == 0 && vis > 0 &&
- (p->flags & TERMP_BRNEVER) == 0) {
- if (p->flags & TERMP_MULTICOL)
- return;
+ vbl = p->flags & TERMP_BRIND ?
+ p->tcol->rmargin : p->tcol->offset;
+ }
- endline(p);
- vend -= vis;
+ /* Reset output state in preparation for the next field. */
- /* Use pending tabs on the new line. */
+ p->col = p->tcol->col = p->tcol->lastcol = 0;
+ p->minbl = p->trailspace;
+ p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
- vbl = 0;
- while (ntab--)
- vbl = term_tab_next(vbl);
+ if (p->flags & TERMP_MULTICOL)
+ return;
- /* Re-establish indentation. */
+ /*
+ * The HANG flag means that the next field
+ * always follows on the same line.
+ * The NOBREAK flag means that the next field
+ * follows on the same line unless the field was overrun.
+ * Normally, break the line at the end of each field.
+ */
- if (p->flags & TERMP_BRIND)
- vbl += p->tcol->rmargin;
- else
- vbl += p->tcol->offset;
- maxvis = p->tcol->rmargin > vbl ?
- p->tcol->rmargin - vbl : 0;
- bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
- p->maxrmargin > vbl ? p->maxrmargin - vbl : 0;
- }
+ if ((p->flags & TERMP_HANG) == 0 &&
+ ((p->flags & TERMP_NOBREAK) == 0 ||
+ vbr + term_len(p, p->trailspace) > vfield))
+ endline(p);
+}
- /*
- * Write out the rest of the word.
- */
+/*
+ * Store the number of input characters to print in this field in *nbr
+ * and their total visual width to print in *vbr.
+ * If there is only whitespace in the field, both remain zero.
+ * The desired visual width of the field is provided by vtarget.
+ * If the first word is longer, the field will be overrun.
+ */
+static void
+term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
+{
+ size_t ic; /* Character position in the input buffer. */
+ size_t vis; /* Visual position of the current character. */
+ size_t vn; /* Visual position of the next character. */
+ int breakline; /* Break at the end of this word. */
+ int graph; /* Last character was non-blank. */
+
+ *nbr = *vbr = vis = 0;
+ breakline = graph = 0;
+ for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) {
+ switch (p->tcol->buf[ic]) {
+ case '\b': /* Escape \o (overstrike) or backspace markup. */
+ assert(ic > 0);
+ vis -= (*p->width)(p, p->tcol->buf[ic - 1]);
+ continue;
- for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) {
- if (vend > bp && jhy > 0 && p->tcol->col > jhy)
+ case '\t': /* Normal ASCII whitespace. */
+ case ' ':
+ case ASCII_BREAK: /* Escape \: (breakpoint). */
+ switch (p->tcol->buf[ic]) {
+ case '\t':
+ vn = term_tab_next(vis);
break;
- if (p->tcol->buf[p->tcol->col] == '\n')
- continue;
- if (p->tcol->buf[p->tcol->col] == '\t')
+ case ' ':
+ vn = vis + (*p->width)(p, ' ');
break;
- if (p->tcol->buf[p->tcol->col] == ' ') {
- j = p->tcol->col;
- while (p->tcol->col < p->tcol->lastcol &&
- p->tcol->buf[p->tcol->col] == ' ')
- p->tcol->col++;
- dv = (p->tcol->col - j) * (*p->width)(p, ' ');
- vbl += dv;
- vend += dv;
+ case ASCII_BREAK:
+ vn = vis;
break;
+ default:
+ abort();
}
- if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) {
- vbl += (*p->width)(p, ' ');
- continue;
+ /* Can break at the end of a word. */
+ if (breakline || vn > vtarget)
+ break;
+ if (graph) {
+ *nbr = ic;
+ *vbr = vis;
+ graph = 0;
}
- if (p->tcol->buf[p->tcol->col] == ASCII_BREAK)
- continue;
+ vis = vn;
+ continue;
+ case '\n': /* Escape \p (break at the end of the word). */
+ breakline = 1;
+ continue;
+
+ case ASCII_HYPH: /* Breakable hyphen. */
+ graph = 1;
/*
- * Now we definitely know there will be
- * printable characters to output,
- * so write preceding white space now.
+ * We are about to decide whether to break the
+ * line or not, so we no longer need this hyphen
+ * to be marked as breakable. Put back a real
+ * hyphen such that we get the correct width.
*/
- if (vbl) {
- (*p->advance)(p, vbl);
- p->viscol += vbl;
- vbl = 0;
+ p->tcol->buf[ic] = '-';
+ vis += (*p->width)(p, '-');
+ if (vis > vtarget) {
+ ic++;
+ break;
}
-
- (*p->letter)(p, p->tcol->buf[p->tcol->col]);
- if (p->tcol->buf[p->tcol->col] == '\b')
- p->viscol -= (*p->width)(p,
- p->tcol->buf[p->tcol->col - 1]);
- else
- p->viscol += (*p->width)(p,
- p->tcol->buf[p->tcol->col]);
- }
- vis = vend;
-
- if (breakline == 0)
+ *nbr = ic + 1;
+ *vbr = vis;
continue;
- /* Explicitly requested output line break. */
-
- if (p->flags & TERMP_MULTICOL)
- return;
-
- endline(p);
- breakline = 0;
- vis = vend = 0;
-
- /* Re-establish indentation. */
-
- vbl = p->tcol->offset;
- maxvis = p->tcol->rmargin > vbl ?
- p->tcol->rmargin - vbl : 0;
- bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
- p->maxrmargin > vbl ? p->maxrmargin - vbl : 0;
+ case ASCII_NBRSP: /* Non-breakable space. */
+ p->tcol->buf[ic] = ' ';
+ /* FALLTHROUGH */
+ default: /* Printable character. */
+ graph = 1;
+ vis += (*p->width)(p, p->tcol->buf[ic]);
+ if (vis > vtarget && *nbr > 0)
+ return;
+ continue;
+ }
+ break;
}
/*
- * If there was trailing white space, it was not printed;
- * so reset the cursor position accordingly.
+ * If the last word extends to the end of the field without any
+ * trailing whitespace, the loop could not check yet whether it
+ * can remain on this line. So do the check now.
*/
- if (vis > vbl)
- vis -= vbl;
- else
- vis = 0;
+ if (graph && (vis <= vtarget || *nbr == 0)) {
+ *nbr = ic;
+ *vbr = vis;
+ }
+}
- p->col = p->tcol->col = p->tcol->lastcol = 0;
- p->minbl = p->trailspace;
- p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
+/*
+ * Print the contents of one field
+ * with an indentation of vbl visual columns,
+ * an input string length of nbr characters,
+ * an output width of vbr visual columns,
+ * and a desired field width of vtarget visual columns.
+ */
+static void
+term_field(struct termp *p, size_t vbl, size_t nbr, size_t vbr, size_t vtarget)
+{
+ size_t ic; /* Character position in the input buffer. */
+ size_t vis; /* Visual position of the current character. */
+ size_t dv; /* Visual width of the current character. */
+ size_t vn; /* Visual position of the next character. */
- if (p->flags & TERMP_MULTICOL)
- return;
+ vis = 0;
+ for (ic = p->tcol->col; ic < nbr; ic++) {
+
+ /*
+ * To avoid the printing of trailing whitespace,
+ * do not print whitespace right away, only count it.
+ */
- /* Trailing whitespace is significant in some columns. */
+ switch (p->tcol->buf[ic]) {
+ case '\n':
+ case ASCII_BREAK:
+ continue;
+ case '\t':
+ vn = term_tab_next(vis);
+ vbl += vn - vis;
+ vis = vn;
+ continue;
+ case ' ':
+ case ASCII_NBRSP:
+ dv = (*p->width)(p, ' ');
+ vbl += dv;
+ vis += dv;
+ continue;
+ default:
+ break;
+ }
- if (vis && vbl && (TERMP_BRTRSP & p->flags))
- vis += vbl;
+ /*
+ * We found a non-blank character to print,
+ * so write preceding white space now.
+ */
- /* If the column was overrun, break the line. */
- if ((p->flags & TERMP_NOBREAK) == 0 ||
- ((p->flags & TERMP_HANG) == 0 &&
- vis + p->trailspace * (*p->width)(p, ' ') > maxvis))
- endline(p);
+ if (vbl > 0) {
+ (*p->advance)(p, vbl);
+ p->viscol += vbl;
+ vbl = 0;
+ }
+
+ /* Print the character and adjust the visual position. */
+
+ (*p->letter)(p, p->tcol->buf[ic]);
+ if (p->tcol->buf[ic] == '\b') {
+ dv = (*p->width)(p, p->tcol->buf[ic - 1]);
+ p->viscol -= dv;
+ vis -= dv;
+ } else {
+ dv = (*p->width)(p, p->tcol->buf[ic]);
+ p->viscol += dv;
+ vis += dv;
+ }
+ }
+ p->tcol->col = nbr;
}
static void
@@ -477,9 +568,6 @@ term_word(struct termp *p, const char *word)
word++;
esc = mandoc_escape(&word, &seq, &sz);
- if (ESCAPE_ERROR == esc)
- continue;
-
switch (esc) {
case ESCAPE_UNICODE:
uc = mchars_num2uc(seq + 1, sz - 1);
@@ -500,6 +588,9 @@ term_word(struct termp *p, const char *word)
encode1(p, uc);
}
continue;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
case ESCAPE_FONTBOLD:
term_fontrepl(p, TERMFONT_BOLD);
continue;
@@ -510,6 +601,7 @@ term_word(struct termp *p, const char *word)
term_fontrepl(p, TERMFONT_BI);
continue;
case ESCAPE_FONT:
+ case ESCAPE_FONTCW:
case ESCAPE_FONTROMAN:
term_fontrepl(p, TERMFONT_NONE);
continue;
@@ -525,6 +617,16 @@ term_word(struct termp *p, const char *word)
else if (*word == '\0')
p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
continue;
+ case ESCAPE_DEVICE:
+ if (p->type == TERMTYPE_PDF)
+ encode(p, "pdf", 3);
+ else if (p->type == TERMTYPE_PS)
+ encode(p, "ps", 2);
+ else if (p->enc == TERMENC_ASCII)
+ encode(p, "ascii", 5);
+ else
+ encode(p, "utf8", 4);
+ continue;
case ESCAPE_HORIZ:
if (*seq == '|') {
seq++;
@@ -576,6 +678,9 @@ term_word(struct termp *p, const char *word)
case ESCAPE_SPECIAL:
uc = mchars_spec2cp(cp, sz);
break;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
default:
uc = -1;
break;
@@ -834,12 +939,8 @@ term_strlen(const struct termp *p, const char *cp)
switch (*cp) {
case '\\':
cp++;
- esc = mandoc_escape(&cp, &seq, &ssz);
- if (ESCAPE_ERROR == esc)
- continue;
-
rhs = NULL;
-
+ esc = mandoc_escape(&cp, &seq, &ssz);
switch (esc) {
case ESCAPE_UNICODE:
uc = mchars_num2uc(seq + 1, ssz - 1);
@@ -860,6 +961,24 @@ term_strlen(const struct termp *p, const char *cp)
sz += cond_width(p, uc, &skip);
}
continue;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
+ case ESCAPE_DEVICE:
+ if (p->type == TERMTYPE_PDF) {
+ rhs = "pdf";
+ rsz = 3;
+ } else if (p->type == TERMTYPE_PS) {
+ rhs = "ps";
+ rsz = 2;
+ } else if (p->enc == TERMENC_ASCII) {
+ rhs = "ascii";
+ rsz = 5;
+ } else {
+ rhs = "utf8";
+ rsz = 4;
+ }
+ break;
case ESCAPE_SKIPCHAR:
skip = 1;
continue;
diff --git a/usr/src/cmd/mandoc/term.h b/usr/src/cmd/mandoc/term.h
index 493191d7d3..f0a033a46f 100644
--- a/usr/src/cmd/mandoc/term.h
+++ b/usr/src/cmd/mandoc/term.h
@@ -1,7 +1,7 @@
-/* $Id: term.h,v 1.130 2017/07/08 14:51:05 schwarze Exp $ */
+/* $Id: term.h,v 1.131 2019/01/04 03:21:02 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017, 2019 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
@@ -99,6 +99,8 @@ struct termp {
#define TERMP_NEWMC (1 << 18) /* No .mc printed yet. */
#define TERMP_ENDMC (1 << 19) /* Next break ends .mc mode. */
#define TERMP_MULTICOL (1 << 20) /* Multiple column mode. */
+#define TERMP_CENTER (1 << 21) /* Center output lines. */
+#define TERMP_RIGHT (1 << 22) /* Adjust to the right margin. */
enum termtype type; /* Terminal, PS, or PDF. */
enum termenc enc; /* Type of encoding. */
enum termfont fontl; /* Last font set. */
diff --git a/usr/src/cmd/mandoc/term_ascii.c b/usr/src/cmd/mandoc/term_ascii.c
index f47ffd75d9..368623cac1 100644
--- a/usr/src/cmd/mandoc/term_ascii.c
+++ b/usr/src/cmd/mandoc/term_ascii.c
@@ -1,4 +1,4 @@
-/* $Id: term_ascii.c,v 1.61 2018/05/20 21:37:34 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.64 2018/11/28 14:23:06 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -90,7 +90,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
p->width = ascii_width;
#if HAVE_WCHAR
- if (TERMENC_ASCII != enc) {
+ if (enc != TERMENC_ASCII) {
/*
* Do not change any of this to LC_ALL. It might break
@@ -99,7 +99,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
* worst case, it might even cause buffer overflows.
*/
- v = TERMENC_LOCALE == enc ?
+ v = enc == TERMENC_LOCALE ?
setlocale(LC_CTYPE, "") :
setlocale(LC_CTYPE, UTF8_LOCALE);
@@ -113,7 +113,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
v = setlocale(LC_CTYPE, "C");
if (v != NULL && MB_CUR_MAX > 1) {
- p->enc = enc;
+ p->enc = TERMENC_UTF8;
p->advance = locale_advance;
p->endline = locale_endline;
p->letter = locale_letter;
@@ -196,8 +196,7 @@ terminal_sepline(void *arg)
static size_t
ascii_width(const struct termp *p, int c)
{
-
- return 1;
+ return c != ASCII_BREAK;
}
void
@@ -311,7 +310,7 @@ ascii_uc2str(int uc)
"<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
"<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
"<98>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
- nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<section>",
+ nbrsp, "!", "/\bc", "-\bL", "o\bx", "=\bY", "|", "<section>",
"\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
"<degree>","+-","^2", "^3", "'","<micro>","<paragraph>",".",
",", "^1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
diff --git a/usr/src/cmd/mandoc/term_tab.c b/usr/src/cmd/mandoc/term_tab.c
index 5251a8425a..3343244f3c 100644
--- a/usr/src/cmd/mandoc/term_tab.c
+++ b/usr/src/cmd/mandoc/term_tab.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 schwarze Exp $ */
+/* $Id: term_tab.c,v 1.5 2018/12/16 00:21:05 schwarze Exp $ */
/*
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
*
diff --git a/usr/src/cmd/mandoc/tree.c b/usr/src/cmd/mandoc/tree.c
index b9774e1cd8..649c0804c8 100644
--- a/usr/src/cmd/mandoc/tree.c
+++ b/usr/src/cmd/mandoc/tree.c
@@ -1,7 +1,7 @@
-/* $Id: tree.c,v 1.78 2018/04/11 17:11:13 schwarze Exp $ */
+/* $Id: tree.c,v 1.84 2019/01/01 05:56:34 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2015, 2017-2019 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,6 +29,8 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
+#include "tbl.h"
+#include "eqn.h"
#include "main.h"
static void print_box(const struct eqn_box *, int);
@@ -39,18 +41,18 @@ static void print_span(const struct tbl_span *, int);
void
-tree_mdoc(void *arg, const struct roff_man *mdoc)
+tree_mdoc(void *arg, const struct roff_meta *mdoc)
{
- print_meta(&mdoc->meta);
+ print_meta(mdoc);
putchar('\n');
print_mdoc(mdoc->first->child, 0);
}
void
-tree_man(void *arg, const struct roff_man *man)
+tree_man(void *arg, const struct roff_meta *man)
{
- print_meta(&man->meta);
- if (man->meta.hasbody == 0)
+ print_meta(man);
+ if (man->hasbody == 0)
puts("body = empty");
putchar('\n');
print_man(man->first->child, 0);
@@ -187,20 +189,22 @@ print_mdoc(const struct roff_node *n, int indent)
}
putchar(' ');
- if (NODE_DELIMO & n->flags)
+ if (n->flags & NODE_DELIMO)
putchar('(');
- if (NODE_LINE & n->flags)
+ if (n->flags & NODE_LINE)
putchar('*');
printf("%d:%d", n->line, n->pos + 1);
- if (NODE_DELIMC & n->flags)
+ if (n->flags & NODE_DELIMC)
putchar(')');
- if (NODE_EOS & n->flags)
+ if (n->flags & NODE_EOS)
putchar('.');
- if (NODE_BROKEN & n->flags)
+ if (n->flags & NODE_BROKEN)
printf(" BROKEN");
- if (NODE_NOSRC & n->flags)
+ if (n->flags & NODE_NOFILL)
+ printf(" NOFILL");
+ if (n->flags & NODE_NOSRC)
printf(" NOSRC");
- if (NODE_NOPRT & n->flags)
+ if (n->flags & NODE_NOPRT)
printf(" NOPRT");
putchar('\n');
}
@@ -286,11 +290,15 @@ print_man(const struct roff_node *n, int indent)
for (i = 0; i < indent; i++)
putchar(' ');
printf("%s (%s) ", p, t);
- if (NODE_LINE & n->flags)
+ if (n->flags & NODE_LINE)
putchar('*');
printf("%d:%d", n->line, n->pos + 1);
- if (NODE_EOS & n->flags)
+ if (n->flags & NODE_DELIMC)
+ putchar(')');
+ if (n->flags & NODE_EOS)
putchar('.');
+ if (n->flags & NODE_NOFILL)
+ printf(" NOFILL");
putchar('\n');
}
@@ -377,35 +385,41 @@ print_span(const struct tbl_span *sp, int indent)
switch (sp->pos) {
case TBL_SPAN_HORIZ:
putchar('-');
- return;
+ putchar(' ');
+ break;
case TBL_SPAN_DHORIZ:
putchar('=');
- return;
- default:
+ putchar(' ');
break;
- }
-
- for (dp = sp->first; dp; dp = dp->next) {
- switch (dp->pos) {
- case TBL_DATA_HORIZ:
- case TBL_DATA_NHORIZ:
- putchar('-');
- continue;
- case TBL_DATA_DHORIZ:
- case TBL_DATA_NDHORIZ:
- putchar('=');
- continue;
- default:
- break;
+ default:
+ for (dp = sp->first; dp; dp = dp->next) {
+ switch (dp->pos) {
+ case TBL_DATA_HORIZ:
+ case TBL_DATA_NHORIZ:
+ putchar('-');
+ putchar(' ');
+ continue;
+ case TBL_DATA_DHORIZ:
+ case TBL_DATA_NDHORIZ:
+ putchar('=');
+ putchar(' ');
+ continue;
+ default:
+ break;
+ }
+ printf("[\"%s\"", dp->string ? dp->string : "");
+ if (dp->hspans)
+ printf(">%d", dp->hspans);
+ if (dp->vspans)
+ printf("v%d", dp->vspans);
+ if (dp->layout == NULL)
+ putchar('*');
+ else if (dp->layout->pos == TBL_CELL_DOWN)
+ putchar('^');
+ putchar(']');
+ putchar(' ');
}
- printf("[\"%s\"", dp->string ? dp->string : "");
- if (dp->spans)
- printf("(%d)", dp->spans);
- if (NULL == dp->layout)
- putchar('*');
- putchar(']');
- putchar(' ');
+ break;
}
-
printf("(tbl) %d:1\n", sp->line);
}