summaryrefslogtreecommitdiff
path: root/usr.bin/mandoc
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2020-02-27 01:26:00 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2020-02-27 01:26:00 +0000
commit6f8aadfc69810a5c3408b4cae48f85969daf651c (patch)
tree451d059ba46667c14eff8b88012de8605c885723 /usr.bin/mandoc
parentd1bbe4f0575c40545245502a43df4e9910062b65 (diff)
Introduce the concept of nodes that are semantically transparent:
they are skipped when looking for previous or following high-level macros. Examples include roff(7) .ft, .ll, and .ta, mdoc(7) .Sm and .Tg, and man(7) .DT and .PD. Use this concept for a variety of improved decisions in various validators and formatters. While here, * remove a few const qualifiers on struct arguments that caused trouble; * get rid of some more Yoda notation in the vicinity; * and apply some other stylistic improvements in the vicinity. I found this class of issues while considering .Tg patches from kn@.
Diffstat (limited to 'usr.bin/mandoc')
-rw-r--r--usr.bin/mandoc/man_html.c14
-rw-r--r--usr.bin/mandoc/man_term.c39
-rw-r--r--usr.bin/mandoc/mdoc_html.c70
-rw-r--r--usr.bin/mandoc/mdoc_man.c87
-rw-r--r--usr.bin/mandoc/mdoc_markdown.c38
-rw-r--r--usr.bin/mandoc/mdoc_term.c140
-rw-r--r--usr.bin/mandoc/mdoc_validate.c156
-rw-r--r--usr.bin/mandoc/roff.c55
-rw-r--r--usr.bin/mandoc/roff.h10
-rw-r--r--usr.bin/mandoc/roff_validate.c8
10 files changed, 332 insertions, 285 deletions
diff --git a/usr.bin/mandoc/man_html.c b/usr.bin/mandoc/man_html.c
index 4e66abb36de..589b4114138 100644
--- a/usr.bin/mandoc/man_html.c
+++ b/usr.bin/mandoc/man_html.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: man_html.c,v 1.128 2020/02/12 21:14:24 schwarze Exp $ */
+/* $OpenBSD: man_html.c,v 1.129 2020/02/27 01:25:57 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -32,7 +32,7 @@
#include "main.h"
#define MAN_ARGS const struct roff_meta *man, \
- const struct roff_node *n, \
+ struct roff_node *n, \
struct html *h
struct man_html_act {
@@ -242,7 +242,7 @@ print_man_node(MAN_ARGS)
* Close the list if no further item of the same type
* follows; otherwise, close the item only.
*/
- if (list_continues(n, n->next) == '\0') {
+ if (list_continues(n, roff_node_next(n)) == '\0') {
print_tagq(h, t);
t = NULL;
}
@@ -443,15 +443,17 @@ list_continues(const struct roff_node *n1, const struct roff_node *n2)
static int
man_IP_pre(MAN_ARGS)
{
- const struct roff_node *nn;
+ 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') {
+ list_type = list_continues(roff_node_prev(nn), nn);
+ if (list_type == '\0') {
/* Start a new list. */
- if ((list_type = list_continues(nn, nn->next)) == '\0')
+ list_type = list_continues(nn, roff_node_next(nn));
+ if (list_type == '\0')
list_type = ' ';
switch (list_type) {
case ' ':
diff --git a/usr.bin/mandoc/man_term.c b/usr.bin/mandoc/man_term.c
index 0a35597877c..33ae377ffb9 100644
--- a/usr.bin/mandoc/man_term.c
+++ b/usr.bin/mandoc/man_term.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: man_term.c,v 1.186 2020/01/20 10:29:31 schwarze Exp $ */
+/* $OpenBSD: man_term.c,v 1.187 2020/02/27 01:25:57 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -62,7 +62,7 @@ static void print_man_head(struct termp *,
static void print_man_foot(struct termp *,
const struct roff_meta *);
static void print_bvspace(struct termp *,
- const struct roff_node *, int);
+ struct roff_node *, int);
static int pre_B(DECL_ARGS);
static int pre_DT(DECL_ARGS);
@@ -203,19 +203,20 @@ terminal_man(void *arg, const struct roff_meta *man)
* first, print it.
*/
static void
-print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
+print_bvspace(struct termp *p, struct roff_node *n, int pardist)
{
- int i;
+ struct roff_node *nch;
+ int i;
term_newln(p);
- if (n->body != NULL && n->body->child != NULL)
- if (n->body->child->type == ROFFT_TBL)
- return;
+ if (n->body != NULL &&
+ (nch = roff_node_child(n->body)) != NULL &&
+ nch->type == ROFFT_TBL)
+ return;
- if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
- if (n->prev == NULL)
- return;
+ if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL)
+ return;
for (i = 0; i < pardist; i++)
term_vspace(p);
@@ -681,12 +682,8 @@ pre_SS(DECL_ARGS)
* and after an empty subsection.
*/
- do {
- n = n->prev;
- } while (n != NULL && n->tok >= MAN_TH &&
- man_term_act(n->tok)->flags & MAN_NOTEXT);
- if (n == NULL || n->type == ROFFT_COMMENT ||
- (n->tok == MAN_SS && n->body->child == NULL))
+ if ((n = roff_node_prev(n)) == NULL ||
+ (n->tok == MAN_SS && roff_node_child(n->body) == NULL))
break;
for (i = 0; i < mt->pardist; i++)
@@ -726,12 +723,8 @@ pre_SH(DECL_ARGS)
* and after an empty section.
*/
- do {
- n = n->prev;
- } while (n != NULL && n->tok >= MAN_TH &&
- man_term_act(n->tok)->flags & MAN_NOTEXT);
- if (n == NULL || n->type == ROFFT_COMMENT ||
- (n->tok == MAN_SH && n->body->child == NULL))
+ if ((n = roff_node_prev(n)) == NULL ||
+ (n->tok == MAN_SH && roff_node_child(n->body) == NULL))
break;
for (i = 0; i < mt->pardist; i++)
@@ -837,7 +830,7 @@ pre_SY(DECL_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
- if (n->prev == NULL || n->prev->tok != MAN_SY)
+ if ((nn = roff_node_prev(n)) == NULL || nn->tok != MAN_SY)
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
diff --git a/usr.bin/mandoc/mdoc_html.c b/usr.bin/mandoc/mdoc_html.c
index 8a6275f4f5e..cb0c6a82748 100644
--- a/usr.bin/mandoc/mdoc_html.c
+++ b/usr.bin/mandoc/mdoc_html.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mdoc_html.c,v 1.208 2020/01/19 17:59:01 schwarze Exp $ */
+/* $OpenBSD: mdoc_html.c,v 1.209 2020/02/27 01:25:57 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -50,8 +50,7 @@ static void print_mdoc_head(const struct roff_meta *,
struct html *);
static void print_mdoc_node(MDOC_ARGS);
static void print_mdoc_nodelist(MDOC_ARGS);
-static void synopsis_pre(struct html *,
- const struct roff_node *);
+static void synopsis_pre(struct html *, struct roff_node *);
static void mdoc_root_post(const struct roff_meta *,
struct html *);
@@ -248,13 +247,15 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
* See the same function in mdoc_term.c for documentation.
*/
static void
-synopsis_pre(struct html *h, const struct roff_node *n)
+synopsis_pre(struct html *h, struct roff_node *n)
{
+ struct roff_node *np;
- if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
MDOC_Fo != n->tok &&
MDOC_Ft != n->tok &&
MDOC_Fn != n->tok) {
@@ -262,7 +263,7 @@ synopsis_pre(struct html *h, const struct roff_node *n)
return;
}
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -623,17 +624,18 @@ mdoc_ss_pre(MDOC_ARGS)
static int
mdoc_fl_pre(MDOC_ARGS)
{
- char *id;
+ struct roff_node *nn;
+ char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
print_otag(h, TAG_CODE, "ci", "Fl", id);
print_text(h, "\\-");
- if (!(n->child == NULL &&
- (n->next == NULL ||
- n->next->type == ROFFT_TEXT ||
- n->next->flags & NODE_LINE)))
+ if (n->child != NULL ||
+ ((nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT &&
+ (nn->flags & NODE_LINE) == 0))
h->flags |= HTML_NOSPACE;
return 1;
@@ -907,7 +909,7 @@ mdoc_bl_pre(MDOC_ARGS)
static int
mdoc_ex_pre(MDOC_ARGS)
{
- if (n->prev)
+ if (roff_node_prev(n) != NULL)
print_otag(h, TAG_BR, "");
return 1;
}
@@ -984,7 +986,7 @@ mdoc_bd_pre(MDOC_ARGS)
continue;
if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
comp = 1;
- if (nn->prev != NULL)
+ if (roff_node_prev(nn) != NULL)
break;
}
(void)strlcpy(buf, "Bd", sizeof(buf));
@@ -1096,22 +1098,21 @@ mdoc_fa_pre(MDOC_ARGS)
print_otag(h, TAG_VAR, "c", "Fa");
return 1;
}
-
- for (nn = n->child; nn; nn = nn->next) {
+ for (nn = n->child; nn != NULL; nn = nn->next) {
t = print_otag(h, TAG_VAR, "c", "Fa");
print_text(h, nn->string);
print_tagq(h, t);
- if (nn->next) {
+ if (nn->next != NULL) {
h->flags |= HTML_NOSPACE;
print_text(h, ",");
}
}
-
- if (n->child && n->next && n->next->tok == MDOC_Fa) {
+ if (n->child != NULL &&
+ (nn = roff_node_next(n)) != NULL &&
+ nn->tok == MDOC_Fa) {
h->flags |= HTML_NOSPACE;
print_text(h, ",");
}
-
return 0;
}
@@ -1570,7 +1571,9 @@ mdoc_sy_pre(MDOC_ARGS)
static int
mdoc_lb_pre(MDOC_ARGS)
{
- if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
+ if (n->sec == SEC_LIBRARY &&
+ n->flags & NODE_LINE &&
+ roff_node_prev(n) != NULL)
print_otag(h, TAG_BR, "");
print_otag(h, TAG_SPAN, "c", "Lb");
@@ -1580,17 +1583,18 @@ mdoc_lb_pre(MDOC_ARGS)
static int
mdoc__x_pre(MDOC_ARGS)
{
- const char *cattr;
- enum htmltag t;
+ struct roff_node *nn;
+ const char *cattr;
+ enum htmltag t;
t = TAG_SPAN;
switch (n->tok) {
case MDOC__A:
cattr = "RsA";
- if (n->prev && MDOC__A == n->prev->tok)
- if (NULL == n->next || MDOC__A != n->next->tok)
- print_text(h, "and");
+ if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
+ print_text(h, "and");
break;
case MDOC__B:
t = TAG_I;
@@ -1645,19 +1649,21 @@ mdoc__x_pre(MDOC_ARGS)
static void
mdoc__x_post(MDOC_ARGS)
{
+ struct roff_node *nn;
- if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
- if (NULL == n->next->next || MDOC__A != n->next->next->tok)
- if (NULL == n->prev || MDOC__A != n->prev->tok)
- return;
+ if (n->tok == MDOC__A &&
+ (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
+ ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
+ return;
/* TODO: %U */
- if (NULL == n->parent || MDOC_Rs != n->parent->tok)
+ if (n->parent == NULL || n->parent->tok != MDOC_Rs)
return;
h->flags |= HTML_NOSPACE;
- print_text(h, n->next ? "," : ".");
+ print_text(h, roff_node_next(n) ? "," : ".");
}
static int
diff --git a/usr.bin/mandoc/mdoc_man.c b/usr.bin/mandoc/mdoc_man.c
index 7fde52b78cc..25d59a5a01b 100644
--- a/usr.bin/mandoc/mdoc_man.c
+++ b/usr.bin/mandoc/mdoc_man.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mdoc_man.c,v 1.133 2020/02/20 22:55:10 schwarze Exp $ */
+/* $OpenBSD: mdoc_man.c,v 1.134 2020/02/27 01:25:57 schwarze Exp $ */
/*
* Copyright (c) 2011-2020 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -111,7 +111,7 @@ static int pre_sm(DECL_ARGS);
static void pre_sp(DECL_ARGS);
static int pre_sect(DECL_ARGS);
static int pre_sy(DECL_ARGS);
-static void pre_syn(const struct roff_node *);
+static void pre_syn(struct roff_node *);
static void pre_ta(DECL_ARGS);
static int pre_vt(DECL_ARGS);
static int pre_xr(DECL_ARGS);
@@ -648,7 +648,9 @@ print_node(DECL_ARGS)
* Break the line if we were parsed subsequent the current node.
* This makes the page structure be more consistent.
*/
- if (MMAN_spc & outflags && NODE_LINE & n->flags)
+ if (outflags & MMAN_spc &&
+ n->flags & NODE_LINE &&
+ !roff_node_transparent(n))
outflags |= MMAN_nl;
act = NULL;
@@ -775,13 +777,20 @@ post_font(DECL_ARGS)
static void
post_percent(DECL_ARGS)
{
+ struct roff_node *np, *nn, *nnn;
if (mdoc_man_act(n->tok)->pre == pre_em)
font_pop();
- if (n->next) {
- print_word(",");
- if (n->prev && n->prev->tok == n->tok &&
- n->next->tok == n->tok)
+
+ if ((nn = roff_node_next(n)) != NULL) {
+ np = roff_node_prev(n);
+ nnn = nn == NULL ? NULL : roff_node_next(nn);
+ if (nn->tok != n->tok ||
+ (np != NULL && np->tok == n->tok) ||
+ (nnn != NULL && nnn->tok == n->tok))
+ print_word(",");
+ if (nn->tok == n->tok &&
+ (nnn == NULL || nnn->tok != n->tok))
print_word("and");
} else {
print_word(".");
@@ -849,13 +858,15 @@ post_sect(DECL_ARGS)
/* See mdoc_term.c, synopsis_pre() for comments. */
static void
-pre_syn(const struct roff_node *n)
+pre_syn(struct roff_node *n)
{
+ struct roff_node *np;
- if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
MDOC_Ft != n->tok &&
MDOC_Fo != n->tok &&
MDOC_Fn != n->tok) {
@@ -863,7 +874,7 @@ pre_syn(const struct roff_node *n)
return;
}
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -939,11 +950,10 @@ static int
pre_bd(DECL_ARGS)
{
outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
-
- if (DISP_unfilled == n->norm->Bd.type ||
- DISP_literal == n->norm->Bd.type)
+ if (n->norm->Bd.type == DISP_unfilled ||
+ n->norm->Bd.type == DISP_literal)
print_line(".nf", 0);
- if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
+ if (n->norm->Bd.comp == 0 && roff_node_prev(n->parent) != NULL)
outflags |= MMAN_sp;
print_offs(n->norm->Bd.offs, 1);
return 1;
@@ -975,7 +985,7 @@ post_bd(DECL_ARGS)
}
/* Maybe we are inside an enclosing list? */
- if (NULL != n->parent->next)
+ if (roff_node_next(n->parent) != NULL)
mid_it();
}
@@ -1100,16 +1110,15 @@ post_bl(DECL_ARGS)
print_line(".RE", MMAN_nl);
assert(Bl_stack_len);
Bl_stack_len--;
- assert(0 == Bl_stack[Bl_stack_len]);
+ assert(Bl_stack[Bl_stack_len] == 0);
} else {
outflags |= MMAN_PP | MMAN_nl;
outflags &= ~(MMAN_sp | MMAN_br);
}
/* Maybe we are inside an enclosing list? */
- if (NULL != n->parent->next)
+ if (roff_node_next(n->parent) != NULL)
mid_it();
-
}
static void
@@ -1121,7 +1130,6 @@ pre_br(DECL_ARGS)
static int
pre_dl(DECL_ARGS)
{
-
print_offs("6n", 0);
return 1;
}
@@ -1129,11 +1137,10 @@ pre_dl(DECL_ARGS)
static void
post_dl(DECL_ARGS)
{
-
print_line(".RE", MMAN_nl);
/* Maybe we are inside an enclosing list? */
- if (NULL != n->parent->next)
+ if (roff_node_next(n->parent) != NULL)
mid_it();
}
@@ -1234,15 +1241,15 @@ pre_fa(DECL_ARGS)
static void
post_fa(DECL_ARGS)
{
+ struct roff_node *nn;
- if (NULL != n->next && MDOC_Fa == n->next->tok)
+ if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa)
print_word(",");
}
static int
pre_fd(DECL_ARGS)
{
-
pre_syn(n);
font_push('B');
return 1;
@@ -1251,7 +1258,6 @@ pre_fd(DECL_ARGS)
static void
post_fd(DECL_ARGS)
{
-
font_pop();
outflags |= MMAN_br;
}
@@ -1259,7 +1265,6 @@ post_fd(DECL_ARGS)
static int
pre_fl(DECL_ARGS)
{
-
font_push('B');
print_word("\\-");
if (n->child != NULL)
@@ -1270,12 +1275,13 @@ pre_fl(DECL_ARGS)
static void
post_fl(DECL_ARGS)
{
+ struct roff_node *nn;
font_pop();
- if (!(n->child != NULL ||
- n->next == NULL ||
- n->next->type == ROFFT_TEXT ||
- n->next->flags & NODE_LINE))
+ if (n->child == NULL &&
+ ((nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT &&
+ (nn->flags & NODE_LINE) == 0))
outflags &= ~MMAN_spc;
}
@@ -1418,9 +1424,9 @@ pre_it(DECL_ARGS)
case ROFFT_HEAD:
outflags |= MMAN_PP | MMAN_nl;
bln = n->parent->parent;
- if (0 == bln->norm->Bl.comp ||
- (NULL == n->parent->prev &&
- NULL == bln->parent->prev))
+ if (bln->norm->Bl.comp == 0 ||
+ (n->parent->prev == NULL &&
+ roff_node_prev(bln->parent) == NULL))
outflags |= MMAN_sp;
outflags &= ~MMAN_br;
switch (bln->norm->Bl.type) {
@@ -1632,17 +1638,22 @@ pre_nm(DECL_ARGS)
{
char *name;
- if (n->type == ROFFT_BLOCK) {
+ switch (n->type) {
+ case ROFFT_BLOCK:
outflags |= MMAN_Bk;
pre_syn(n);
- }
- if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
return 1;
+ case ROFFT_HEAD:
+ case ROFFT_ELEM:
+ break;
+ default:
+ return 1;
+ }
name = n->child == NULL ? NULL : n->child->string;
- if (NULL == name)
+ if (name == NULL)
return 0;
if (n->type == ROFFT_HEAD) {
- if (NULL == n->parent->prev)
+ if (roff_node_prev(n->parent) == NULL)
outflags |= MMAN_sp;
print_block(".HP", 0);
printf(" %dn", man_strlen(name) + 1);
diff --git a/usr.bin/mandoc/mdoc_markdown.c b/usr.bin/mandoc/mdoc_markdown.c
index 22b46978320..fe87440b5c1 100644
--- a/usr.bin/mandoc/mdoc_markdown.c
+++ b/usr.bin/mandoc/mdoc_markdown.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: mdoc_markdown.c,v 1.33 2020/02/20 00:29:10 schwarze Exp $ */
+/* $OpenBSD: mdoc_markdown.c,v 1.34 2020/02/27 01:25:57 schwarze Exp $ */
/*
- * Copyright (c) 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2018, 2020 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
@@ -310,7 +310,9 @@ md_node(struct roff_node *n)
if (outflags & MD_nonl)
outflags &= ~(MD_nl | MD_sp);
- else if (outflags & MD_spc && n->flags & NODE_LINE)
+ else if (outflags & MD_spc &&
+ n->flags & NODE_LINE &&
+ !roff_node_transparent(n))
outflags |= MD_nl;
act = NULL;
@@ -787,14 +789,17 @@ md_post_word(struct roff_node *n)
static void
md_post_pc(struct roff_node *n)
{
+ struct roff_node *nn;
+
md_post_raw(n);
if (n->parent->tok != MDOC_Rs)
return;
- if (n->next != NULL) {
+
+ if ((nn = roff_node_next(n)) != NULL) {
md_word(",");
- if (n->prev != NULL &&
- n->prev->tok == n->tok &&
- n->next->tok == n->tok)
+ if (nn->tok == n->tok &&
+ (nn = roff_node_prev(n)) != NULL &&
+ nn->tok == n->tok)
md_word("and");
} else {
md_word(".");
@@ -811,10 +816,13 @@ md_pre_skip(struct roff_node *n)
static void
md_pre_syn(struct roff_node *n)
{
- if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY))
+ struct roff_node *np;
+
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
n->tok != MDOC_Ft &&
n->tok != MDOC_Fo &&
n->tok != MDOC_Fn) {
@@ -822,7 +830,7 @@ md_pre_syn(struct roff_node *n)
return;
}
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -1053,7 +1061,9 @@ md_pre_Fa(struct roff_node *n)
static void
md_post_Fa(struct roff_node *n)
{
- if (n->next != NULL && n->next->tok == MDOC_Fa)
+ struct roff_node *nn;
+
+ if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa)
md_word(",");
}
@@ -1075,9 +1085,11 @@ md_post_Fd(struct roff_node *n)
static void
md_post_Fl(struct roff_node *n)
{
+ struct roff_node *nn;
+
md_post_raw(n);
- if (n->child == NULL && n->next != NULL &&
- n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))
+ if (n->child == NULL && (nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT && (nn->flags & NODE_LINE) == 0)
outflags &= ~MD_spc;
}
diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c
index 5e7412e124b..dab449d9da4 100644
--- a/usr.bin/mandoc/mdoc_term.c
+++ b/usr.bin/mandoc/mdoc_term.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mdoc_term.c,v 1.275 2020/01/20 10:29:31 schwarze Exp $ */
+/* $OpenBSD: mdoc_term.c,v 1.276 2020/02/27 01:25:57 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -52,14 +52,12 @@ struct mdoc_term_act {
static int a2width(const struct termp *, const char *);
static void print_bvspace(struct termp *,
- const struct roff_node *,
- const struct roff_node *);
+ struct roff_node *, struct roff_node *);
static void print_mdoc_node(DECL_ARGS);
static void print_mdoc_nodelist(DECL_ARGS);
static void print_mdoc_head(struct termp *, const struct roff_meta *);
static void print_mdoc_foot(struct termp *, const struct roff_meta *);
-static void synopsis_pre(struct termp *,
- const struct roff_node *);
+static void synopsis_pre(struct termp *, struct roff_node *);
static void termp____post(DECL_ARGS);
static void termp__t_post(DECL_ARGS);
@@ -580,29 +578,20 @@ a2width(const struct termp *p, const char *v)
* too.
*/
static void
-print_bvspace(struct termp *p,
- const struct roff_node *bl,
- const struct roff_node *n)
+print_bvspace(struct termp *p, struct roff_node *bl, struct roff_node *n)
{
- const struct roff_node *nn;
-
- assert(n);
+ struct roff_node *nn;
term_newln(p);
- if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
- return;
- if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
+ if ((bl->tok == MDOC_Bd && bl->norm->Bd.comp) ||
+ (bl->tok == MDOC_Bl && bl->norm->Bl.comp))
return;
/* Do not vspace directly after Ss/Sh. */
nn = n;
- while (nn->prev != NULL &&
- (nn->prev->type == ROFFT_COMMENT ||
- nn->prev->flags & NODE_NOPRT))
- nn = nn->prev;
- while (nn->prev == NULL) {
+ while (roff_node_prev(nn) == NULL) {
do {
nn = nn->parent;
if (nn->type == ROFFT_ROOT)
@@ -615,22 +604,18 @@ print_bvspace(struct termp *p,
break;
}
- /* A `-column' does not assert vspace within the list. */
-
- if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
- if (n->prev && MDOC_It == n->prev->tok)
- return;
-
- /* A `-diag' without body does not vspace. */
-
- if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
- if (n->prev && MDOC_It == n->prev->tok) {
- assert(n->prev->body);
- if (NULL == n->prev->body->child)
- return;
- }
+ /*
+ * No vertical space after:
+ * items in .Bl -column
+ * items without a body in .Bl -diag
+ */
- term_vspace(p);
+ if (bl->tok != MDOC_Bl ||
+ n->prev == NULL || n->prev->tok != MDOC_It ||
+ (bl->norm->Bl.type != LIST_column &&
+ (bl->norm->Bl.type != LIST_diag ||
+ n->prev->body->child != NULL)))
+ term_vspace(p);
}
@@ -1041,15 +1026,16 @@ termp_nm_post(DECL_ARGS)
static int
termp_fl_pre(DECL_ARGS)
{
+ struct roff_node *nn;
termp_tag_pre(p, pair, meta, n);
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\-");
- if (!(n->child == NULL &&
- (n->next == NULL ||
- n->next->type == ROFFT_TEXT ||
- n->next->flags & NODE_LINE)))
+ if (n->child != NULL ||
+ ((nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT &&
+ (nn->flags & NODE_LINE) == 0))
p->flags |= TERMP_NOSPACE;
return 1;
@@ -1058,10 +1044,11 @@ termp_fl_pre(DECL_ARGS)
static int
termp__a_pre(DECL_ARGS)
{
+ struct roff_node *nn;
- if (n->prev && MDOC__A == n->prev->tok)
- if (NULL == n->next || MDOC__A != n->next->tok)
- term_word(p, "and");
+ if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
+ term_word(p, "and");
return 1;
}
@@ -1102,10 +1089,9 @@ termp_ns_pre(DECL_ARGS)
static int
termp_rs_pre(DECL_ARGS)
{
-
if (SEC_SEE_ALSO != n->sec)
return 1;
- if (n->type == ROFFT_BLOCK && n->prev != NULL)
+ if (n->type == ROFFT_BLOCK && roff_node_prev(n) != NULL)
term_vspace(p);
return 1;
}
@@ -1179,13 +1165,12 @@ termp_xr_pre(DECL_ARGS)
* macro combos).
*/
static void
-synopsis_pre(struct termp *p, const struct roff_node *n)
+synopsis_pre(struct termp *p, struct roff_node *n)
{
- /*
- * Obviously, if we're not in a SYNOPSIS or no prior macros
- * exist, do nothing.
- */
- if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
+ struct roff_node *np;
+
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
/*
@@ -1193,7 +1178,7 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
* newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
* case we soldier on.
*/
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
MDOC_Ft != n->tok &&
MDOC_Fo != n->tok &&
MDOC_Fn != n->tok) {
@@ -1206,7 +1191,7 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
* another (or Fn/Fo, which we've let slip through) then assert
* vertical space, else only newline and move on.
*/
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -1215,7 +1200,7 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
term_vspace(p);
break;
case MDOC_Ft:
- if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
+ if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
term_vspace(p);
break;
}
@@ -1269,6 +1254,7 @@ termp_fd_post(DECL_ARGS)
static int
termp_sh_pre(DECL_ARGS)
{
+ struct roff_node *np;
switch (n->type) {
case ROFFT_BLOCK:
@@ -1276,10 +1262,9 @@ termp_sh_pre(DECL_ARGS)
* Vertical space before sections, except
* when the previous section was empty.
*/
- if (n->prev == NULL ||
- n->prev->tok != MDOC_Sh ||
- (n->prev->body != NULL &&
- n->prev->body->child != NULL))
+ if ((np = roff_node_prev(n)) == NULL ||
+ np->tok != MDOC_Sh ||
+ (np->body != NULL && np->body->child != NULL))
term_vspace(p);
break;
case ROFFT_HEAD:
@@ -1430,19 +1415,22 @@ termp_fa_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_UNDER);
return 1;
}
-
- for (nn = n->child; nn; nn = nn->next) {
+ for (nn = n->child; nn != NULL; nn = nn->next) {
term_fontpush(p, TERMFONT_UNDER);
p->flags |= TERMP_NBRWORD;
term_word(p, nn->string);
term_fontpop(p);
-
- if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
+ if (nn->next != NULL) {
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
}
-
+ if (n->child != NULL &&
+ (nn = roff_node_next(n)) != NULL &&
+ nn->tok == MDOC_Fa) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, ",");
+ }
return 0;
}
@@ -1522,24 +1510,18 @@ termp_xx_post(DECL_ARGS)
static void
termp_pf_post(DECL_ARGS)
{
-
- if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
+ if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
p->flags |= TERMP_NOSPACE;
}
static int
termp_ss_pre(DECL_ARGS)
{
- struct roff_node *nn;
-
switch (n->type) {
case ROFFT_BLOCK:
- term_newln(p);
- for (nn = n->prev; nn != NULL; nn = nn->prev)
- if (nn->type != ROFFT_COMMENT &&
- (nn->flags & NODE_NOPRT) == 0)
- break;
- if (nn != NULL)
+ if (roff_node_prev(n) == NULL)
+ term_newln(p);
+ else
term_vspace(p);
break;
case ROFFT_HEAD:
@@ -1555,14 +1537,12 @@ termp_ss_pre(DECL_ARGS)
default:
break;
}
-
return 1;
}
static void
termp_ss_post(DECL_ARGS)
{
-
if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
term_newln(p);
}
@@ -1890,24 +1870,26 @@ termp_ap_pre(DECL_ARGS)
static void
termp____post(DECL_ARGS)
{
+ struct roff_node *nn;
/*
* Handle lists of authors. In general, print each followed by
* a comma. Don't print the comma if there are only two
* authors.
*/
- if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
- if (NULL == n->next->next || MDOC__A != n->next->next->tok)
- if (NULL == n->prev || MDOC__A != n->prev->tok)
- return;
+ if (n->tok == MDOC__A &&
+ (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
+ ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
+ return;
/* TODO: %U. */
- if (NULL == n->parent || MDOC_Rs != n->parent->tok)
+ if (n->parent == NULL || n->parent->tok != MDOC_Rs)
return;
p->flags |= TERMP_NOSPACE;
- if (NULL == n->next) {
+ if (roff_node_next(n) == NULL) {
term_word(p, ".");
p->flags |= TERMP_SENTENCE;
} else
diff --git a/usr.bin/mandoc/mdoc_validate.c b/usr.bin/mandoc/mdoc_validate.c
index b7ae573a127..902294e8d79 100644
--- a/usr.bin/mandoc/mdoc_validate.c
+++ b/usr.bin/mandoc/mdoc_validate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mdoc_validate.c,v 1.292 2020/01/19 17:59:01 schwarze Exp $ */
+/* $OpenBSD: mdoc_validate.c,v 1.293 2020/02/27 01:25:58 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -1745,8 +1745,7 @@ post_bl_head(POST_ARGS)
static void
post_bl(POST_ARGS)
{
- struct roff_node *nparent, *nprev; /* of the Bl block */
- struct roff_node *nblock, *nbody; /* of the Bl */
+ struct roff_node *nbody; /* of the Bl */
struct roff_node *nchild, *nnext; /* of the Bl body */
const char *prev_Er;
int order;
@@ -1767,88 +1766,73 @@ post_bl(POST_ARGS)
if (nbody->end != ENDBODY_NOT)
return;
- nchild = nbody->child;
- if (nchild == NULL) {
- mandoc_msg(MANDOCERR_BLK_EMPTY,
- nbody->line, nbody->pos, "Bl");
- return;
+ /*
+ * Up to the first item, move nodes before the list,
+ * but leave transparent nodes where they are
+ * if they precede an item.
+ * The next non-transparent node is kept in nchild.
+ * It only needs to be updated after a non-transparent
+ * node was moved out, and at the very beginning
+ * when no node at all was moved yet.
+ */
+
+ nchild = mdoc->last;
+ for (;;) {
+ if (nchild == mdoc->last)
+ nchild = roff_node_child(nbody);
+ if (nchild == NULL) {
+ mdoc->last = nbody;
+ mandoc_msg(MANDOCERR_BLK_EMPTY,
+ nbody->line, nbody->pos, "Bl");
+ return;
+ }
+ if (nchild->tok == MDOC_It) {
+ mdoc->last = nbody;
+ break;
+ }
+ mandoc_msg(MANDOCERR_BL_MOVE, nbody->child->line,
+ nbody->child->pos, "%s", roff_name[nbody->child->tok]);
+ if (nbody->parent->prev == NULL) {
+ mdoc->last = nbody->parent->parent;
+ mdoc->next = ROFF_NEXT_CHILD;
+ } else {
+ mdoc->last = nbody->parent->prev;
+ mdoc->next = ROFF_NEXT_SIBLING;
+ }
+ roff_node_relink(mdoc, nbody->child);
}
+
+ /*
+ * We have reached the first item,
+ * so moving nodes out is no longer possible.
+ * But in .Bl -column, the first rows may be implicit,
+ * that is, they may not start with .It macros.
+ * Such rows may be followed by nodes generated on the
+ * roff level, for example .TS.
+ * Wrap such roff nodes into an implicit row.
+ */
+
while (nchild != NULL) {
- nnext = nchild->next;
- if (nchild->tok == MDOC_It ||
- ((nchild->tok == MDOC_Sm || nchild->tok == MDOC_Tg) &&
- nnext != NULL && nnext->tok == MDOC_It)) {
- nchild = nnext;
+ if (nchild->tok == MDOC_It) {
+ nchild = roff_node_next(nchild);
continue;
}
-
- /*
- * In .Bl -column, the first rows may be implicit,
- * that is, they may not start with .It macros.
- * Such rows may be followed by nodes generated on the
- * roff level, for example .TS, which cannot be moved
- * out of the list. In that case, wrap such roff nodes
- * into an implicit row.
- */
-
- if (nchild->prev != NULL) {
- mdoc->last = nchild;
- mdoc->next = ROFF_NEXT_SIBLING;
- roff_block_alloc(mdoc, nchild->line,
- nchild->pos, MDOC_It);
- roff_head_alloc(mdoc, nchild->line,
- nchild->pos, MDOC_It);
+ nnext = nchild->next;
+ mdoc->last = nchild->prev;
+ mdoc->next = ROFF_NEXT_SIBLING;
+ roff_block_alloc(mdoc, nchild->line, nchild->pos, MDOC_It);
+ roff_head_alloc(mdoc, nchild->line, nchild->pos, MDOC_It);
+ mdoc->next = ROFF_NEXT_SIBLING;
+ roff_body_alloc(mdoc, nchild->line, nchild->pos, MDOC_It);
+ while (nchild->tok != MDOC_It) {
+ roff_node_relink(mdoc, nchild);
+ if (nnext == NULL)
+ break;
+ nchild = nnext;
+ nnext = nchild->next;
mdoc->next = ROFF_NEXT_SIBLING;
- roff_body_alloc(mdoc, nchild->line,
- nchild->pos, MDOC_It);
- while (nchild->tok != MDOC_It) {
- roff_node_relink(mdoc, nchild);
- if ((nchild = nnext) == NULL)
- break;
- nnext = nchild->next;
- mdoc->next = ROFF_NEXT_SIBLING;
- }
- mdoc->last = nbody;
- continue;
}
-
- mandoc_msg(MANDOCERR_BL_MOVE, nchild->line, nchild->pos,
- "%s", roff_name[nchild->tok]);
-
- /*
- * Move the node out of the Bl block.
- * First, collect all required node pointers.
- */
-
- nblock = nbody->parent;
- nprev = nblock->prev;
- nparent = nblock->parent;
-
- /*
- * Unlink this child.
- */
-
- nbody->child = nnext;
- if (nnext == NULL)
- nbody->last = NULL;
- else
- nnext->prev = NULL;
-
- /*
- * Relink this child.
- */
-
- nchild->parent = nparent;
- nchild->prev = nprev;
- nchild->next = nblock;
-
- nblock->prev = nchild;
- if (nprev == NULL)
- nparent->child = nchild;
- else
- nprev->next = nchild;
-
- nchild = nnext;
+ mdoc->last = nbody;
}
if (mdoc->meta.os_e != MANDOC_OS_NETBSD)
@@ -2485,20 +2469,20 @@ post_ignpar(POST_ARGS)
static void
post_prevpar(POST_ARGS)
{
- struct roff_node *n;
+ struct roff_node *n, *np;
n = mdoc->last;
- if (NULL == n->prev)
- return;
if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK)
return;
+ if ((np = roff_node_prev(n)) == NULL)
+ return;
/*
* 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 != ROFF_br)
+ if (np->tok != MDOC_Pp && np->tok != ROFF_br)
return;
if (n->tok == MDOC_Bl && n->norm->Bl.comp)
return;
@@ -2507,9 +2491,9 @@ post_prevpar(POST_ARGS)
if (n->tok == MDOC_It && n->parent->norm->Bl.comp)
return;
- 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);
+ mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
+ "%s before %s", roff_name[np->tok], roff_name[n->tok]);
+ roff_node_delete(mdoc, np);
}
static void
diff --git a/usr.bin/mandoc/roff.c b/usr.bin/mandoc/roff.c
index 35eec08824c..9a8e77a9893 100644
--- a/usr.bin/mandoc/roff.c
+++ b/usr.bin/mandoc/roff.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: roff.c,v 1.241 2020/01/19 17:59:01 schwarze Exp $ */
+/* $OpenBSD: roff.c,v 1.242 2020/02/27 01:25:58 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -1112,6 +1112,59 @@ roff_node_delete(struct roff_man *man, struct roff_node *n)
roff_node_free(n);
}
+int
+roff_node_transparent(struct roff_node *n)
+{
+ if (n == NULL)
+ return 0;
+ if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
+ return 1;
+ switch (n->tok) {
+ case ROFF_ft:
+ case ROFF_ll:
+ case ROFF_mc:
+ case ROFF_po:
+ case ROFF_ta:
+ case MDOC_Db:
+ case MDOC_Es:
+ case MDOC_Sm:
+ case MDOC_Tg:
+ case MAN_DT:
+ case MAN_UC:
+ case MAN_PD:
+ case MAN_AT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+struct roff_node *
+roff_node_child(struct roff_node *n)
+{
+ for (n = n->child; roff_node_transparent(n); n = n->next)
+ continue;
+ return n;
+}
+
+struct roff_node *
+roff_node_prev(struct roff_node *n)
+{
+ do {
+ n = n->prev;
+ } while (roff_node_transparent(n));
+ return n;
+}
+
+struct roff_node *
+roff_node_next(struct roff_node *n)
+{
+ do {
+ n = n->next;
+ } while (roff_node_transparent(n));
+ return n;
+}
+
void
deroff(char **dest, const struct roff_node *n)
{
diff --git a/usr.bin/mandoc/roff.h b/usr.bin/mandoc/roff.h
index 1479a12688f..24c0e39bc1f 100644
--- a/usr.bin/mandoc/roff.h
+++ b/usr.bin/mandoc/roff.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: roff.h,v 1.52 2020/01/19 17:59:01 schwarze Exp $ */
+/* $OpenBSD: roff.h,v 1.53 2020/02/27 01:25:58 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -549,5 +549,9 @@ struct roff_meta {
extern const char *const *roff_name;
-int arch_valid(const char *, enum mandoc_os);
-void deroff(char **, const struct roff_node *);
+int arch_valid(const char *, enum mandoc_os);
+void deroff(char **, const struct roff_node *);
+struct roff_node *roff_node_child(struct roff_node *);
+struct roff_node *roff_node_next(struct roff_node *);
+struct roff_node *roff_node_prev(struct roff_node *);
+int roff_node_transparent(struct roff_node *);
diff --git a/usr.bin/mandoc/roff_validate.c b/usr.bin/mandoc/roff_validate.c
index 5b6686c2d4c..6fa4f334456 100644
--- a/usr.bin/mandoc/roff_validate.c
+++ b/usr.bin/mandoc/roff_validate.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: roff_validate.c,v 1.18 2018/12/31 09:02:30 schwarze Exp $ */
+/* $OpenBSD: roff_validate.c,v 1.19 2020/02/27 01:25:58 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2017, 2018, 2020 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
@@ -75,7 +75,7 @@ roff_valid_br(ROFF_VALID_ARGS)
return;
}
- if ((np = n->prev) == NULL)
+ if ((np = roff_node_prev(n)) == NULL)
return;
switch (np->tok) {
@@ -129,7 +129,7 @@ roff_valid_sp(ROFF_VALID_ARGS)
{
struct roff_node *np;
- if ((np = n->prev) == NULL)
+ if ((np = roff_node_prev(n)) == NULL)
return;
switch (np->tok) {