summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2020-02-27 01:43:52 +0000
committerIngo Schwarze <schwarze@openbsd.org>2020-02-27 01:43:52 +0000
commit13c3ceece1e58741fca2635fed585eab72c2c298 (patch)
tree5fef1cb532bff2686cae46fcbf801e02e138f255
parentd0fb47c4e52de4d83cd9b58fbfb7ef94c63ea96d (diff)
downloadmandoc-13c3ceece1e58741fca2635fed585eab72c2c298.tar.gz
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@.
-rw-r--r--man_html.c12
-rw-r--r--man_term.c37
-rw-r--r--mdoc_html.c68
-rw-r--r--mdoc_man.c85
-rw-r--r--mdoc_markdown.c36
-rw-r--r--mdoc_term.c138
-rw-r--r--mdoc_validate.c154
-rw-r--r--regress/man/HP/Makefile4
-rw-r--r--regress/man/HP/vert.in14
-rw-r--r--regress/man/HP/vert.out_ascii21
-rw-r--r--regress/man/IP/Makefile7
-rw-r--r--regress/man/IP/bullet.in22
-rw-r--r--regress/man/IP/bullet.out_ascii28
-rw-r--r--regress/man/IP/bullet.out_html12
-rw-r--r--regress/man/IP/bullet.out_utf828
-rw-r--r--regress/man/IP/vert.in10
-rw-r--r--regress/man/IP/vert.out_ascii16
-rw-r--r--regress/man/PP/Makefile4
-rw-r--r--regress/man/PP/vert.in10
-rw-r--r--regress/man/PP/vert.out_ascii16
-rw-r--r--regress/man/SH/Makefile4
-rw-r--r--regress/man/SH/vert.in10
-rw-r--r--regress/man/SH/vert.out_ascii14
-rw-r--r--regress/man/SS/Makefile4
-rw-r--r--regress/man/SS/vert.in12
-rw-r--r--regress/man/SS/vert.out_ascii17
-rw-r--r--regress/man/TP/Makefile6
-rw-r--r--regress/man/TP/vert.in17
-rw-r--r--regress/man/TP/vert.out_ascii20
-rw-r--r--regress/man/TP/vert.out_html9
-rw-r--r--regress/mdoc/Bd/spacing.in8
-rw-r--r--regress/mdoc/Bd/spacing.out_ascii6
-rw-r--r--regress/mdoc/Bd/spacing.out_markdown8
-rw-r--r--regress/mdoc/Bl/Makefile4
-rw-r--r--regress/mdoc/Bl/noIt.out_lint1
-rw-r--r--regress/mdoc/Bl/vert.in15
-rw-r--r--regress/mdoc/Bl/vert.out_ascii10
-rw-r--r--regress/mdoc/Bl/vert.out_markdown15
-rw-r--r--regress/mdoc/Fl/Makefile4
-rw-r--r--regress/mdoc/Fl/spacing.in42
-rw-r--r--regress/mdoc/Fl/spacing.out_ascii26
-rw-r--r--regress/mdoc/Fl/spacing.out_markdown42
-rw-r--r--regress/mdoc/Fo/Makefile4
-rw-r--r--regress/mdoc/Fo/transp.in23
-rw-r--r--regress/mdoc/Fo/transp.out_ascii13
-rw-r--r--regress/mdoc/Fo/transp.out_markdown19
-rw-r--r--regress/mdoc/Rs/Makefile4
-rw-r--r--regress/mdoc/Rs/transp.in36
-rw-r--r--regress/mdoc/Rs/transp.out_ascii16
-rw-r--r--regress/mdoc/Rs/transp.out_markdown27
-rw-r--r--regress/mdoc/Sh/Makefile5
-rw-r--r--regress/mdoc/Sh/transp.in11
-rw-r--r--regress/mdoc/Sh/transp.out_ascii10
-rw-r--r--regress/mdoc/Sh/transp.out_markdown13
-rw-r--r--regress/mdoc/Sm/badarg.out_markdown3
-rw-r--r--regress/mdoc/Sm/twoarg.out_markdown6
-rw-r--r--regress/mdoc/blank/Makefile6
-rw-r--r--regress/mdoc/blank/transp.in77
-rw-r--r--regress/mdoc/blank/transp.out_ascii48
-rw-r--r--regress/mdoc/blank/transp.out_lint19
-rw-r--r--regress/mdoc/blank/transp.out_markdown44
-rw-r--r--roff.c53
-rw-r--r--roff.h8
-rw-r--r--roff_validate.c6
64 files changed, 1156 insertions, 311 deletions
diff --git a/man_html.c b/man_html.c
index af942837..538ff734 100644
--- a/man_html.c
+++ b/man_html.c
@@ -34,7 +34,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 {
@@ -244,7 +244,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;
}
@@ -445,15 +445,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/man_term.c b/man_term.c
index e25f7c74..2f4c18d8 100644
--- a/man_term.c
+++ b/man_term.c
@@ -64,7 +64,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);
@@ -205,19 +205,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);
@@ -683,12 +684,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++)
@@ -728,12 +725,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++)
@@ -839,7 +832,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/mdoc_html.c b/mdoc_html.c
index e1cd8389..bc50720f 100644
--- a/mdoc_html.c
+++ b/mdoc_html.c
@@ -52,8 +52,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 *);
@@ -250,13 +249,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) {
@@ -264,7 +265,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:
@@ -625,17 +626,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;
@@ -909,7 +911,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;
}
@@ -986,7 +988,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));
@@ -1098,22 +1100,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;
}
@@ -1572,7 +1573,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");
@@ -1582,17 +1585,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;
@@ -1647,19 +1651,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/mdoc_man.c b/mdoc_man.c
index 8daaedfe..7169b184 100644
--- a/mdoc_man.c
+++ b/mdoc_man.c
@@ -113,7 +113,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);
@@ -650,7 +650,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;
@@ -777,13 +779,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(".");
@@ -851,13 +860,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) {
@@ -865,7 +876,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:
@@ -941,11 +952,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;
@@ -977,7 +987,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();
}
@@ -1102,16 +1112,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
@@ -1123,7 +1132,6 @@ pre_br(DECL_ARGS)
static int
pre_dl(DECL_ARGS)
{
-
print_offs("6n", 0);
return 1;
}
@@ -1131,11 +1139,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();
}
@@ -1236,15 +1243,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;
@@ -1253,7 +1260,6 @@ pre_fd(DECL_ARGS)
static void
post_fd(DECL_ARGS)
{
-
font_pop();
outflags |= MMAN_br;
}
@@ -1261,7 +1267,6 @@ post_fd(DECL_ARGS)
static int
pre_fl(DECL_ARGS)
{
-
font_push('B');
print_word("\\-");
if (n->child != NULL)
@@ -1272,12 +1277,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;
}
@@ -1420,9 +1426,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) {
@@ -1634,17 +1640,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/mdoc_markdown.c b/mdoc_markdown.c
index 6d7d3552..1bf48342 100644
--- a/mdoc_markdown.c
+++ b/mdoc_markdown.c
@@ -1,6 +1,6 @@
/* $Id$ */
/*
- * 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/mdoc_term.c b/mdoc_term.c
index c9f11926..776f1130 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -54,14 +54,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);
@@ -582,29 +580,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)
@@ -617,22 +606,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);
}
@@ -1043,15 +1028,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;
@@ -1060,10 +1046,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;
}
@@ -1104,10 +1091,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;
}
@@ -1181,13 +1167,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;
/*
@@ -1195,7 +1180,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) {
@@ -1208,7 +1193,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:
@@ -1217,7 +1202,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;
}
@@ -1271,6 +1256,7 @@ termp_fd_post(DECL_ARGS)
static int
termp_sh_pre(DECL_ARGS)
{
+ struct roff_node *np;
switch (n->type) {
case ROFFT_BLOCK:
@@ -1278,10 +1264,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:
@@ -1432,19 +1417,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;
}
@@ -1524,24 +1512,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:
@@ -1557,14 +1539,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);
}
@@ -1892,24 +1872,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/mdoc_validate.c b/mdoc_validate.c
index 652f9ad6..6ab715d3 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1760,8 +1760,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;
@@ -1782,88 +1781,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)
@@ -2500,20 +2484,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;
@@ -2522,9 +2506,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/regress/man/HP/Makefile b/regress/man/HP/Makefile
index 1e33cfb4..945f5339 100644
--- a/regress/man/HP/Makefile
+++ b/regress/man/HP/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.3 2019/01/06 04:41:15 schwarze Exp $
+# $OpenBSD: Makefile,v 1.4 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = break literal macrotag manyargs spacing
+REGRESS_TARGETS = break literal macrotag manyargs spacing vert
HTML_TARGETS = literal
.include <bsd.regress.mk>
diff --git a/regress/man/HP/vert.in b/regress/man/HP/vert.in
new file mode 100644
index 00000000..b433c7e0
--- /dev/null
+++ b/regress/man/HP/vert.in
@@ -0,0 +1,14 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH HP-VERT 1 "February 19, 2020"
+.SH NAME
+HP-vert \- vertical spacing before hanged lists
+.SH DESCRIPTION
+.PD 2v
+.HP
+Each hanged paragraph gets a sufficient amount of text
+to wrap to the next line.
+.HP
+Each hanged paragraph gets a sufficient amount of text
+to wrap to the next line.
+.LP
+Normal text.
diff --git a/regress/man/HP/vert.out_ascii b/regress/man/HP/vert.out_ascii
new file mode 100644
index 00000000..30fa3dd4
--- /dev/null
+++ b/regress/man/HP/vert.out_ascii
@@ -0,0 +1,21 @@
+HP-VERT(1) General Commands Manual HP-VERT(1)
+
+
+
+NNAAMMEE
+ HP-vert - vertical spacing before hanged lists
+
+DDEESSCCRRIIPPTTIIOONN
+ Each hanged paragraph gets a sufficient amount of text to wrap to the
+ next line.
+
+
+ Each hanged paragraph gets a sufficient amount of text to wrap to the
+ next line.
+
+
+ Normal text.
+
+
+
+OpenBSD February 19, 2020 HP-VERT(1)
diff --git a/regress/man/IP/Makefile b/regress/man/IP/Makefile
index a677b970..70094e5f 100644
--- a/regress/man/IP/Makefile
+++ b/regress/man/IP/Makefile
@@ -1,7 +1,8 @@
-# $OpenBSD: Makefile,v 1.9 2019/01/06 04:41:15 schwarze Exp $
+# $OpenBSD: Makefile,v 1.10 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = empty literal longhead manyargs spacing width
+REGRESS_TARGETS = bullet empty literal longhead manyargs spacing vert width
+UTF8_TARGETS = bullet
LINT_TARGETS = empty
-HTML_TARGETS = literal
+HTML_TARGETS = bullet literal
.include <bsd.regress.mk>
diff --git a/regress/man/IP/bullet.in b/regress/man/IP/bullet.in
new file mode 100644
index 00000000..138a681b
--- /dev/null
+++ b/regress/man/IP/bullet.in
@@ -0,0 +1,22 @@
+.\" $OpenBSD: bullet.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH IP-BULLET 1 "February 20, 2020"
+.SH NAME
+IP-bullet \- bullet lists
+.SH DESCRIPTION
+BEGINTEST
+.IP * 3n
+one
+.IP *
+two
+.IP \(bu
+three
+.IP \(bu
+four
+.IP \-
+five
+.IP \-
+six
+.PP
+ENDTEST
+.br
+end of file
diff --git a/regress/man/IP/bullet.out_ascii b/regress/man/IP/bullet.out_ascii
new file mode 100644
index 00000000..a01f25c2
--- /dev/null
+++ b/regress/man/IP/bullet.out_ascii
@@ -0,0 +1,28 @@
+IP-BULLET(1) General Commands Manual IP-BULLET(1)
+
+
+
+NNAAMMEE
+ IP-bullet - bullet lists
+
+DDEESSCCRRIIPPTTIIOONN
+ BEGINTEST
+
+ * one
+
+ * two
+
+ +o three
+
+ +o four
+
+ - five
+
+ - six
+
+ ENDTEST
+ end of file
+
+
+
+OpenBSD February 20, 2020 IP-BULLET(1)
diff --git a/regress/man/IP/bullet.out_html b/regress/man/IP/bullet.out_html
new file mode 100644
index 00000000..95c452b0
--- /dev/null
+++ b/regress/man/IP/bullet.out_html
@@ -0,0 +1,12 @@
+<ul class="Bl-bullet">
+ <li>one</li>
+ <li>two</li>
+</ul>
+<ul class="Bl-bullet">
+ <li>three</li>
+ <li>four</li>
+</ul>
+<ul class="Bl-dash">
+ <li>five</li>
+ <li>six</li>
+</ul>
diff --git a/regress/man/IP/bullet.out_utf8 b/regress/man/IP/bullet.out_utf8
new file mode 100644
index 00000000..fa021fd5
--- /dev/null
+++ b/regress/man/IP/bullet.out_utf8
@@ -0,0 +1,28 @@
+IP-BULLET(1) General Commands Manual IP-BULLET(1)
+
+
+
+NNAAMMEE
+ IP-bullet - bullet lists
+
+DDEESSCCRRIIPPTTIIOONN
+ BEGINTEST
+
+ * one
+
+ * two
+
+ • three
+
+ • four
+
+ - five
+
+ - six
+
+ ENDTEST
+ end of file
+
+
+
+OpenBSD February 20, 2020 IP-BULLET(1)
diff --git a/regress/man/IP/vert.in b/regress/man/IP/vert.in
new file mode 100644
index 00000000..cc5e2038
--- /dev/null
+++ b/regress/man/IP/vert.in
@@ -0,0 +1,10 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH IP-VERT 1 "February 19, 2020"
+.SH NAME
+IP-vert \- vertical spacing before indented paragraphs
+.SH DESCRIPTION
+.PD 2v
+.IP tag
+text
+.IP tag
+text
diff --git a/regress/man/IP/vert.out_ascii b/regress/man/IP/vert.out_ascii
new file mode 100644
index 00000000..428733be
--- /dev/null
+++ b/regress/man/IP/vert.out_ascii
@@ -0,0 +1,16 @@
+IP-VERT(1) General Commands Manual IP-VERT(1)
+
+
+
+NNAAMMEE
+ IP-vert - vertical spacing before indented paragraphs
+
+DDEESSCCRRIIPPTTIIOONN
+ tag text
+
+
+ tag text
+
+
+
+OpenBSD February 19, 2020 IP-VERT(1)
diff --git a/regress/man/PP/Makefile b/regress/man/PP/Makefile
index 7655d294..a9eb9760 100644
--- a/regress/man/PP/Makefile
+++ b/regress/man/PP/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.4 2014/07/04 16:11:41 schwarze Exp $
+# $OpenBSD: Makefile,v 1.5 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = args empty
+REGRESS_TARGETS = args empty vert
LINT_TARGETS = args empty
.include <bsd.regress.mk>
diff --git a/regress/man/PP/vert.in b/regress/man/PP/vert.in
new file mode 100644
index 00000000..e15148c8
--- /dev/null
+++ b/regress/man/PP/vert.in
@@ -0,0 +1,10 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH PP-VERT 1 "February 19, 2020"
+.SH NAME
+PP-vert \- vertical spacing before an ordinary paragraph
+.SH DESCRIPTION
+.PD 2v
+.PP
+first paragraph
+.PP
+second paragraph
diff --git a/regress/man/PP/vert.out_ascii b/regress/man/PP/vert.out_ascii
new file mode 100644
index 00000000..ac53e071
--- /dev/null
+++ b/regress/man/PP/vert.out_ascii
@@ -0,0 +1,16 @@
+PP-VERT(1) General Commands Manual PP-VERT(1)
+
+
+
+NNAAMMEE
+ PP-vert - vertical spacing before an ordinary paragraph
+
+DDEESSCCRRIIPPTTIIOONN
+ first paragraph
+
+
+ second paragraph
+
+
+
+OpenBSD February 19, 2020 PP-VERT(1)
diff --git a/regress/man/SH/Makefile b/regress/man/SH/Makefile
index 55133efe..f42a85b2 100644
--- a/regress/man/SH/Makefile
+++ b/regress/man/SH/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.6 2019/01/06 04:41:15 schwarze Exp $
+# $OpenBSD: Makefile,v 1.7 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = broken broken_eline empty_before longarg noarg paragraph
+REGRESS_TARGETS = broken broken_eline empty_before longarg noarg paragraph vert
LINT_TARGETS = broken broken_eline empty_before noarg
HTML_TARGETS = paragraph
diff --git a/regress/man/SH/vert.in b/regress/man/SH/vert.in
new file mode 100644
index 00000000..e4154782
--- /dev/null
+++ b/regress/man/SH/vert.in
@@ -0,0 +1,10 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH SH-VERT 1 "February 20, 2020"
+.SH NAME
+SH-vert \- vertical spacing of sections
+.SH DESCRIPTION
+.PD 2v
+.SH EXAMPLES
+.PD 1v
+.PP
+text
diff --git a/regress/man/SH/vert.out_ascii b/regress/man/SH/vert.out_ascii
new file mode 100644
index 00000000..f8afd7e0
--- /dev/null
+++ b/regress/man/SH/vert.out_ascii
@@ -0,0 +1,14 @@
+SH-VERT(1) General Commands Manual SH-VERT(1)
+
+
+
+NNAAMMEE
+ SH-vert - vertical spacing of sections
+
+DDEESSCCRRIIPPTTIIOONN
+EEXXAAMMPPLLEESS
+ text
+
+
+
+OpenBSD February 20, 2020 SH-VERT(1)
diff --git a/regress/man/SS/Makefile b/regress/man/SS/Makefile
index 0ae0fbc5..edbe4c2c 100644
--- a/regress/man/SS/Makefile
+++ b/regress/man/SS/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.4 2019/01/06 04:41:15 schwarze Exp $
+# $OpenBSD: Makefile,v 1.5 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = broken broken_eline longarg noarg paragraph
+REGRESS_TARGETS = broken broken_eline longarg noarg paragraph vert
LINT_TARGETS = broken broken_eline noarg
HTML_TARGETS = paragraph
diff --git a/regress/man/SS/vert.in b/regress/man/SS/vert.in
new file mode 100644
index 00000000..8beb98a6
--- /dev/null
+++ b/regress/man/SS/vert.in
@@ -0,0 +1,12 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH SS-VERT 1 "February 19, 2020"
+.SH NAME
+SS-vert \- vertical spacing of subsections
+.SH DESCRIPTION
+.PD 2v
+.SS First subsection
+.PD 1v
+.SS Second subsection
+first paragraph
+.PP
+second paragraph
diff --git a/regress/man/SS/vert.out_ascii b/regress/man/SS/vert.out_ascii
new file mode 100644
index 00000000..9b5dc152
--- /dev/null
+++ b/regress/man/SS/vert.out_ascii
@@ -0,0 +1,17 @@
+SS-VERT(1) General Commands Manual SS-VERT(1)
+
+
+
+NNAAMMEE
+ SS-vert - vertical spacing of subsections
+
+DDEESSCCRRIIPPTTIIOONN
+ FFiirrsstt ssuubbsseeccttiioonn
+ SSeeccoonndd ssuubbsseeccttiioonn
+ first paragraph
+
+ second paragraph
+
+
+
+OpenBSD February 19, 2020 SS-VERT(1)
diff --git a/regress/man/TP/Makefile b/regress/man/TP/Makefile
index 2fc1074f..ca2475b0 100644
--- a/regress/man/TP/Makefile
+++ b/regress/man/TP/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.15 2019/01/06 04:41:15 schwarze Exp $
+# $OpenBSD: Makefile,v 1.16 2020/02/27 01:25:58 schwarze Exp $
REGRESS_TARGETS = badarg broken double eof fill indent literal longhead
-REGRESS_TARGETS += macrotag manyargs sameline spacing width
+REGRESS_TARGETS += macrotag manyargs sameline spacing vert width
LINT_TARGETS = broken double eof
-HTML_TARGETS = literal
+HTML_TARGETS = literal vert
# groff-1.22.3 defects:
# - If .TP precedes .RE, the latter does not properly reset indentation.
diff --git a/regress/man/TP/vert.in b/regress/man/TP/vert.in
new file mode 100644
index 00000000..086976df
--- /dev/null
+++ b/regress/man/TP/vert.in
@@ -0,0 +1,17 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.TH TP-VERT 1 "February 19, 2020"
+.SH NAME
+TP-vert \- vertical spacing before tagged paragraphs
+BEGINTEST
+.SH DESCRIPTION
+.PD 2v
+.TP
+tag
+text
+.TP
+tag
+text
+.PP
+ENDTEST
+.br
+end of file
diff --git a/regress/man/TP/vert.out_ascii b/regress/man/TP/vert.out_ascii
new file mode 100644
index 00000000..32b26ca9
--- /dev/null
+++ b/regress/man/TP/vert.out_ascii
@@ -0,0 +1,20 @@
+TP-VERT(1) General Commands Manual TP-VERT(1)
+
+
+
+NNAAMMEE
+ TP-vert - vertical spacing before tagged paragraphs BEGINTEST
+
+DDEESSCCRRIIPPTTIIOONN
+ tag text
+
+
+ tag text
+
+
+ ENDTEST
+ end of file
+
+
+
+OpenBSD February 19, 2020 TP-VERT(1)
diff --git a/regress/man/TP/vert.out_html b/regress/man/TP/vert.out_html
new file mode 100644
index 00000000..7301819f
--- /dev/null
+++ b/regress/man/TP/vert.out_html
@@ -0,0 +1,9 @@
+</section>
+<section class="Sh">
+<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
+<dl class="Bl-tag">
+ <dt>tag</dt>
+ <dd>text</dd>
+ <dt>tag</dt>
+ <dd>text</dd>
+</dl>
diff --git a/regress/mdoc/Bd/spacing.in b/regress/mdoc/Bd/spacing.in
index 4b23da75..2346ebd7 100644
--- a/regress/mdoc/Bd/spacing.in
+++ b/regress/mdoc/Bd/spacing.in
@@ -1,4 +1,4 @@
-.\" $OpenBSD: spacing.in,v 1.3 2017/07/04 14:53:24 schwarze Exp $
+.\" $OpenBSD: spacing.in,v 1.4 2020/02/27 01:25:58 schwarze Exp $
.Dd $Mdocdate$
.Dt BD-SPACING 1
.Os
@@ -15,3 +15,9 @@ text between displays
compact display block
.Ed
following text
+.Sh EXAMPLES
+.Tg word
+.Bd -literal -offset indent
+text
+.Ed
+end of file
diff --git a/regress/mdoc/Bd/spacing.out_ascii b/regress/mdoc/Bd/spacing.out_ascii
index 8efa8b30..e965647c 100644
--- a/regress/mdoc/Bd/spacing.out_ascii
+++ b/regress/mdoc/Bd/spacing.out_ascii
@@ -11,4 +11,8 @@ DDEESSCCRRIIPPTTIIOONN
compact display block
following text
-OpenBSD July 4, 2017 OpenBSD
+EEXXAAMMPPLLEESS
+ text
+ end of file
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Bd/spacing.out_markdown b/regress/mdoc/Bd/spacing.out_markdown
index 766dda3b..a03c20ef 100644
--- a/regress/mdoc/Bd/spacing.out_markdown
+++ b/regress/mdoc/Bd/spacing.out_markdown
@@ -16,4 +16,10 @@ text between displays
following text
-OpenBSD - July 4, 2017
+# EXAMPLES
+
+ text
+
+end of file
+
+OpenBSD - February 27, 2020
diff --git a/regress/mdoc/Bl/Makefile b/regress/mdoc/Bl/Makefile
index 8fde5d9e..519c4055 100644
--- a/regress/mdoc/Bl/Makefile
+++ b/regress/mdoc/Bl/Makefile
@@ -1,8 +1,8 @@
-# $OpenBSD: Makefile,v 1.40 2018/12/21 16:58:49 schwarze Exp $
+# $OpenBSD: Makefile,v 1.41 2020/02/27 01:25:58 schwarze Exp $
REGRESS_TARGETS = item inset diag ohang bullet dash enum hang tag
REGRESS_TARGETS += column column_nogroff colNoIt
-REGRESS_TARGETS += esc extend nested offset secstart
+REGRESS_TARGETS += esc extend nested offset secstart vert
REGRESS_TARGETS += notype multitype badargs
REGRESS_TARGETS += empty noIt emptyhead emptytag emptyitem multitag
diff --git a/regress/mdoc/Bl/noIt.out_lint b/regress/mdoc/Bl/noIt.out_lint
index 03a89cc5..7c6803f3 100644
--- a/regress/mdoc/Bl/noIt.out_lint
+++ b/regress/mdoc/Bl/noIt.out_lint
@@ -6,3 +6,4 @@ mandoc: noIt.in:18:2: WARNING: moving content out of list: Em
mandoc: noIt.in:18:10: WARNING: moving content out of list: Sy
mandoc: noIt.in:18:19: WARNING: moving content out of list: Em
mandoc: noIt.in:24:1: WARNING: moving content out of list: text
+mandoc: noIt.in:23:2: WARNING: empty block: Bl
diff --git a/regress/mdoc/Bl/vert.in b/regress/mdoc/Bl/vert.in
new file mode 100644
index 00000000..2ff2c4ba
--- /dev/null
+++ b/regress/mdoc/Bl/vert.in
@@ -0,0 +1,15 @@
+.\" $OpenBSD: vert.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.Dd $Mdocdate$
+.Dt BL-VERT 1
+.Os
+.Sh NAME
+.Nm Bl-vert
+.Nd vertical spacing before lists
+.Sh DESCRIPTION
+.Bl -tag -width 7n
+.Sm off
+.It Fl o Ar file
+.Sm on
+text
+.El
+end of file
diff --git a/regress/mdoc/Bl/vert.out_ascii b/regress/mdoc/Bl/vert.out_ascii
new file mode 100644
index 00000000..24a2c565
--- /dev/null
+++ b/regress/mdoc/Bl/vert.out_ascii
@@ -0,0 +1,10 @@
+BL-VERT(1) General Commands Manual BL-VERT(1)
+
+NNAAMMEE
+ BBll--vveerrtt - vertical spacing before lists
+
+DDEESSCCRRIIPPTTIIOONN
+ --oo_f_i_l_e text
+ end of file
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Bl/vert.out_markdown b/regress/mdoc/Bl/vert.out_markdown
new file mode 100644
index 00000000..ed741b40
--- /dev/null
+++ b/regress/mdoc/Bl/vert.out_markdown
@@ -0,0 +1,15 @@
+BL-VERT(1) - General Commands Manual
+
+# NAME
+
+**Bl-vert** - vertical spacing before lists
+
+# DESCRIPTION
+
+**-o**&zwnj;*file*
+
+> text
+
+end of file
+
+OpenBSD - February 27, 2020
diff --git a/regress/mdoc/Fl/Makefile b/regress/mdoc/Fl/Makefile
index f2b2a9aa..e4e4a6bc 100644
--- a/regress/mdoc/Fl/Makefile
+++ b/regress/mdoc/Fl/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.8 2014/08/21 12:56:24 schwarze Exp $
+# $OpenBSD: Makefile,v 1.13 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = noarg multiarg parsed punct font
+REGRESS_TARGETS = font multiarg noarg parsed punct spacing
LINT_TARGETS = punct
.include <bsd.regress.mk>
diff --git a/regress/mdoc/Fl/spacing.in b/regress/mdoc/Fl/spacing.in
new file mode 100644
index 00000000..8613e6b4
--- /dev/null
+++ b/regress/mdoc/Fl/spacing.in
@@ -0,0 +1,42 @@
+.\" $OpenBSD: spacing.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.Dd $Mdocdate$
+.Dt FL-SPACING 1
+.Os
+.Sh NAME
+.Nm Fl-spacing
+.Nd horizontal spacing after flag macros
+.Sh DESCRIPTION
+with argument:
+.Fl a
+.Pp
+no next node:
+.Xo Fl Xc suffix
+.Pp
+transparent next node only:
+.Xo Fl
+.Tg transparent1
+.Xc suffix
+.Pp
+following text:
+.Fl
+text
+.Pp
+text after transparent node on the same line:
+.Fl Es < >
+text
+.Pp
+following macro on the same line:
+.Fl Em word
+.Pp
+following macro on the next line:
+.Fl
+.Em word
+.Pp
+following macro on the next line after transparent node on the same line:
+.Fl Es < >
+.Em word
+.Pp
+following macro after transparent node on the next line:
+.Fl
+.Tg transparent3
+.Em word
diff --git a/regress/mdoc/Fl/spacing.out_ascii b/regress/mdoc/Fl/spacing.out_ascii
new file mode 100644
index 00000000..c96c3923
--- /dev/null
+++ b/regress/mdoc/Fl/spacing.out_ascii
@@ -0,0 +1,26 @@
+FL-SPACING(1) General Commands Manual FL-SPACING(1)
+
+NNAAMMEE
+ FFll--ssppaacciinngg - horizontal spacing after flag macros
+
+DDEESSCCRRIIPPTTIIOONN
+ with argument: --aa
+
+ no next node: -- suffix
+
+ transparent next node only: -- suffix
+
+ following text: -- text
+
+ text after transparent node on the same line: -- text
+
+ following macro on the same line: --_w_o_r_d
+
+ following macro on the next line: -- _w_o_r_d
+
+ following macro on the next line after transparent node on the same line:
+ -- _w_o_r_d
+
+ following macro after transparent node on the next line: -- _w_o_r_d
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Fl/spacing.out_markdown b/regress/mdoc/Fl/spacing.out_markdown
new file mode 100644
index 00000000..a46a44e3
--- /dev/null
+++ b/regress/mdoc/Fl/spacing.out_markdown
@@ -0,0 +1,42 @@
+FL-SPACING(1) - General Commands Manual
+
+# NAME
+
+**Fl-spacing** - horizontal spacing after flag macros
+
+# DESCRIPTION
+
+with argument:
+**-a**
+
+no next node:
+**-** suffix
+
+transparent next node only:
+**-**
+suffix
+
+following text:
+**-**
+text
+
+text after transparent node on the same line:
+**-**
+text
+
+following macro on the same line:
+**-**&zwnj;*word*
+
+following macro on the next line:
+**-**
+*word*
+
+following macro on the next line after transparent node on the same line:
+**-**
+*word*
+
+following macro after transparent node on the next line:
+**-**
+*word*
+
+OpenBSD - February 27, 2020
diff --git a/regress/mdoc/Fo/Makefile b/regress/mdoc/Fo/Makefile
index 09941a52..7770e9a1 100644
--- a/regress/mdoc/Fo/Makefile
+++ b/regress/mdoc/Fo/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.13 2015/02/16 11:39:34 schwarze Exp $
+# $OpenBSD: Makefile,v 1.17 2020/02/27 01:25:58 schwarze Exp $
REGRESS_TARGETS = basic break eos font noarg nohead
-REGRESS_TARGETS += obsolete punct section warn
+REGRESS_TARGETS += obsolete punct section transp warn
LINT_TARGETS = noarg nohead obsolete punct warn
# groff-1.22.3 defects:
diff --git a/regress/mdoc/Fo/transp.in b/regress/mdoc/Fo/transp.in
new file mode 100644
index 00000000..78c62f6a
--- /dev/null
+++ b/regress/mdoc/Fo/transp.in
@@ -0,0 +1,23 @@
+.\" $OpenBSD: transp.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.Dd $Mdocdate$
+.Dt FO-TRANSP 1
+.Os
+.Sh NAME
+.Nm Fo-transp
+.Nd transparent nodes among function argument macros
+.Sh SYNOPSIS
+.Ft type
+.Fo func
+.Fa one
+.Tg one
+.Fa two
+.Tg two
+.Fc
+.Sh DESCRIPTION
+.Ft type
+.Fo func
+.Fa one
+.Tg one
+.Fa two
+.Tg two
+.Fc
diff --git a/regress/mdoc/Fo/transp.out_ascii b/regress/mdoc/Fo/transp.out_ascii
new file mode 100644
index 00000000..fb0c37fc
--- /dev/null
+++ b/regress/mdoc/Fo/transp.out_ascii
@@ -0,0 +1,13 @@
+FO-TRANSP(1) General Commands Manual FO-TRANSP(1)
+
+NNAAMMEE
+ FFoo--ttrraannsspp - transparent nodes among function argument macros
+
+SSYYNNOOPPSSIISS
+ _t_y_p_e
+ ffuunncc(_o_n_e, _t_w_o);
+
+DDEESSCCRRIIPPTTIIOONN
+ _t_y_p_e ffuunncc(_o_n_e, _t_w_o)
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Fo/transp.out_markdown b/regress/mdoc/Fo/transp.out_markdown
new file mode 100644
index 00000000..237d7819
--- /dev/null
+++ b/regress/mdoc/Fo/transp.out_markdown
@@ -0,0 +1,19 @@
+FO-TRANSP(1) - General Commands Manual
+
+# NAME
+
+**Fo-transp** - transparent nodes among function argument macros
+
+# SYNOPSIS
+
+*type*
+**func**(*one*,
+*two*);
+
+# DESCRIPTION
+
+*type*
+**func**(*one*,
+*two*)
+
+OpenBSD - February 27, 2020
diff --git a/regress/mdoc/Rs/Makefile b/regress/mdoc/Rs/Makefile
index 2881b874..e6e3e1bc 100644
--- a/regress/mdoc/Rs/Makefile
+++ b/regress/mdoc/Rs/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.11 2019/01/07 06:51:37 schwarze Exp $
+# $OpenBSD: Makefile,v 1.12 2020/02/27 01:25:58 schwarze Exp $
-REGRESS_TARGETS = allch args break empty paragraph three_authors
+REGRESS_TARGETS = allch args break empty paragraph three_authors transp
UTF8_TARGETS = allch break empty three_authors
LINT_TARGETS = allch args empty
HTML_TARGETS = paragraph
diff --git a/regress/mdoc/Rs/transp.in b/regress/mdoc/Rs/transp.in
new file mode 100644
index 00000000..6360b8a8
--- /dev/null
+++ b/regress/mdoc/Rs/transp.in
@@ -0,0 +1,36 @@
+.\" $OpenBSD: transp.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.Dd $Mdocdate$
+.Dt RS-TRANSPARENT 1
+.Os
+.Sh NAME
+.Nm Rs-transparent
+.Nd transparent nodes in reference blocks
+.Sh SEE ALSO
+.Tg transparent
+.Rs
+.%T title
+.%A first after title
+.%A last
+.Re
+.Rs
+.%A first
+.%A middle
+.%A last before title
+.%T title
+.Re
+.Rs
+.%T title
+.Tg transparent
+.%A first after title and transparent
+.%A middle before transparent
+.Tg transparent
+.%A last before transparent
+.Tg transparent
+.Re
+.Rs
+.Tg transparent
+.%A first after transparent
+.%A last before transparent and title
+.Tg transparent
+.%T title
+.Re
diff --git a/regress/mdoc/Rs/transp.out_ascii b/regress/mdoc/Rs/transp.out_ascii
new file mode 100644
index 00000000..cc217ed5
--- /dev/null
+++ b/regress/mdoc/Rs/transp.out_ascii
@@ -0,0 +1,16 @@
+RS-TRANSPARENT(1) General Commands Manual RS-TRANSPARENT(1)
+
+NNAAMMEE
+ RRss--ttrraannssppaarreenntt - transparent nodes in reference blocks
+
+SSEEEE AALLSSOO
+ first after title and last, _t_i_t_l_e.
+
+ first, middle, and last before title, _t_i_t_l_e.
+
+ first after title and transparent, middle before transparent, and last
+ before transparent, _t_i_t_l_e.
+
+ first after transparent and last before transparent and title, _t_i_t_l_e.
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Rs/transp.out_markdown b/regress/mdoc/Rs/transp.out_markdown
new file mode 100644
index 00000000..a9896335
--- /dev/null
+++ b/regress/mdoc/Rs/transp.out_markdown
@@ -0,0 +1,27 @@
+RS-TRANSPARENT(1) - General Commands Manual
+
+# NAME
+
+**Rs-transparent** - transparent nodes in reference blocks
+
+# SEE ALSO
+
+first after title,
+last,
+*title*.
+
+first,
+middle, and
+last before title,
+*title*.
+
+first after title and transparent,
+middle before transparent, and
+last before transparent,
+*title*.
+
+first after transparent,
+last before transparent and title,
+*title*.
+
+OpenBSD - February 27, 2020
diff --git a/regress/mdoc/Sh/Makefile b/regress/mdoc/Sh/Makefile
index 1c20f13f..213664ec 100644
--- a/regress/mdoc/Sh/Makefile
+++ b/regress/mdoc/Sh/Makefile
@@ -1,7 +1,8 @@
-# $OpenBSD: Makefile,v 1.11 2019/01/07 06:51:37 schwarze Exp $
+# $OpenBSD: Makefile,v 1.12 2020/02/27 01:25:58 schwarze Exp $
REGRESS_TARGETS = badNAME before empty emptyNAME first nohead order
-REGRESS_TARGETS += orderNAME paragraph parbefore parborder punctNAME subbefore
+REGRESS_TARGETS += orderNAME paragraph parbefore parborder punctNAME
+REGRESS_TARGETS += subbefore transp
LINT_TARGETS = badNAME before empty emptyNAME first nohead order
LINT_TARGETS += orderNAME parbefore parborder punctNAME subbefore
HTML_TARGETS = paragraph
diff --git a/regress/mdoc/Sh/transp.in b/regress/mdoc/Sh/transp.in
new file mode 100644
index 00000000..ef24d380
--- /dev/null
+++ b/regress/mdoc/Sh/transp.in
@@ -0,0 +1,11 @@
+.\" $OpenBSD: transp.in,v 1.1 2020/02/27 01:25:58 schwarze Exp $
+.Dd $Mdocdate$
+.Dt SH-TRANSP 1
+.Os
+.Sh NAME
+.Nm Sh-transp
+.Nd interaction of sections with transparent nodes
+.Sh DESCRIPTION
+.Tg transparent
+.Ss Subsection
+text
diff --git a/regress/mdoc/Sh/transp.out_ascii b/regress/mdoc/Sh/transp.out_ascii
new file mode 100644
index 00000000..e30d327f
--- /dev/null
+++ b/regress/mdoc/Sh/transp.out_ascii
@@ -0,0 +1,10 @@
+SH-TRANSP(1) General Commands Manual SH-TRANSP(1)
+
+NNAAMMEE
+ SShh--ttrraannsspp - interaction of sections with transparent nodes
+
+DDEESSCCRRIIPPTTIIOONN
+ SSuubbsseeccttiioonn
+ text
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Sh/transp.out_markdown b/regress/mdoc/Sh/transp.out_markdown
new file mode 100644
index 00000000..f395ed50
--- /dev/null
+++ b/regress/mdoc/Sh/transp.out_markdown
@@ -0,0 +1,13 @@
+SH-TRANSP(1) - General Commands Manual
+
+# NAME
+
+**Sh-transp** - interaction of sections with transparent nodes
+
+# DESCRIPTION
+
+## Subsection
+
+text
+
+OpenBSD - February 27, 2020
diff --git a/regress/mdoc/Sm/badarg.out_markdown b/regress/mdoc/Sm/badarg.out_markdown
index 903b7f81..92fc66b1 100644
--- a/regress/mdoc/Sm/badarg.out_markdown
+++ b/regress/mdoc/Sm/badarg.out_markdown
@@ -8,7 +8,6 @@ SM-BADARG(1) - General Commands Manual
**-f** *on*
**-f**&zwnj;*off* bad
-**-f** *bad* (on)
-bad**-f**&zwnj;*bad*(off)
+**-f** *bad* (on) bad**-f**&zwnj;*bad*(off)
OpenBSD-July 4, 2017
diff --git a/regress/mdoc/Sm/twoarg.out_markdown b/regress/mdoc/Sm/twoarg.out_markdown
index 5b64aa6e..ce46afb1 100644
--- a/regress/mdoc/Sm/twoarg.out_markdown
+++ b/regress/mdoc/Sm/twoarg.out_markdown
@@ -8,12 +8,10 @@ SM-TWOARG(1) - General Commands Manual
**default**:
**-f** *on*
-**off two**:
-two**-f**&zwnj;*off*
+**off two**: two**-f**&zwnj;*off*
**badtwo**: bad two
**-f** *off*
-**on two**:
-two
+**on two**: two
**-f** *on*
OpenBSD - July 4, 2017
diff --git a/regress/mdoc/blank/Makefile b/regress/mdoc/blank/Makefile
index 7dfd0287..8b61f902 100644
--- a/regress/mdoc/blank/Makefile
+++ b/regress/mdoc/blank/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.5 2014/07/06 19:08:57 schwarze Exp $
+# $OpenBSD: Makefile,v 1.8 2020/02/27 01:25:59 schwarze Exp $
-REGRESS_TARGETS = line comment list
-LINT_TARGETS = line comment list
+REGRESS_TARGETS = line comment list transp
+LINT_TARGETS = line comment list transp
SKIP_TMAN = list
SKIP_MARKDOWN ?= line
diff --git a/regress/mdoc/blank/transp.in b/regress/mdoc/blank/transp.in
new file mode 100644
index 00000000..0e58bf2e
--- /dev/null
+++ b/regress/mdoc/blank/transp.in
@@ -0,0 +1,77 @@
+.\" $OpenBSD: transp.in,v 1.1 2020/02/27 01:25:59 schwarze Exp $
+.Dd $Mdocdate$
+.Dt BLANK-TRANSP 1
+.Os
+.Sh NAME
+.Nm blank-transp
+.Nd transparent nodes between line breaks
+.Sh DESCRIPTION
+Double br:
+.br
+.Tg brbr
+.br
+br Pp:
+.br
+.Tg brPp
+.Pp
+Pp br:
+.Pp
+.Tg Ppbr
+.br
+Double Pp:
+.Pp
+.Tg PpPp
+.Pp
+br sp:
+.br
+.Tg brsp
+.sp
+sp br:
+.sp
+.Tg spbr
+.br
+Pp sp:
+.Pp
+.Tg Ppsp
+.sp
+Pp sp 2v:
+.Pp
+.Tg Ppsp2v
+.sp 2v
+sp Pp:
+.sp
+.Tg spPp
+.Pp
+Double sp:
+.sp
+.Tg spsp
+.sp
+br blank:
+.br
+.Tg brbl
+
+blank br:
+
+.Tg blbr
+.br
+Pp blank:
+.Pp
+.Tg Ppbl
+
+blank Pp:
+
+.Tg blPp
+.Pp
+sp blank:
+.sp
+.Tg spbl
+
+blank sp:
+
+.Tg blsp
+.sp
+Double blank:
+
+.Tg blbl
+
+end of file
diff --git a/regress/mdoc/blank/transp.out_ascii b/regress/mdoc/blank/transp.out_ascii
new file mode 100644
index 00000000..f8bdd6b8
--- /dev/null
+++ b/regress/mdoc/blank/transp.out_ascii
@@ -0,0 +1,48 @@
+BLANK-TRANSP(1) General Commands Manual BLANK-TRANSP(1)
+
+NNAAMMEE
+ bbllaannkk--ttrraannsspp - transparent nodes between line breaks
+
+DDEESSCCRRIIPPTTIIOONN
+ Double br:
+ br Pp:
+
+ Pp br:
+
+ Double Pp:
+
+ br sp:
+
+ sp br:
+
+ Pp sp:
+
+ Pp sp 2v:
+
+ sp Pp:
+
+
+ Double sp:
+
+
+ br blank:
+
+ blank br:
+
+ Pp blank:
+
+ blank Pp:
+
+
+ sp blank:
+
+
+ blank sp:
+
+
+ Double blank:
+
+
+ end of file
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/blank/transp.out_lint b/regress/mdoc/blank/transp.out_lint
new file mode 100644
index 00000000..533ea600
--- /dev/null
+++ b/regress/mdoc/blank/transp.out_lint
@@ -0,0 +1,19 @@
+mandoc: transp.in:52:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:54:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:60:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:62:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:68:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:70:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:74:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:76:1: WARNING: blank line in fill mode, using .sp
+mandoc: transp.in:12:2: WARNING: skipping paragraph macro: br after br
+mandoc: transp.in:14:2: WARNING: skipping paragraph macro: br before Pp
+mandoc: transp.in:20:2: WARNING: skipping paragraph macro: br after Pp
+mandoc: transp.in:22:2: WARNING: skipping paragraph macro: Pp before Pp
+mandoc: transp.in:26:2: WARNING: skipping paragraph macro: br before sp
+mandoc: transp.in:32:2: WARNING: skipping paragraph macro: br after sp
+mandoc: transp.in:36:2: WARNING: skipping paragraph macro: sp after Pp
+mandoc: transp.in:40:2: WARNING: skipping paragraph macro: sp after Pp
+mandoc: transp.in:50:2: WARNING: skipping paragraph macro: br before sp
+mandoc: transp.in:56:2: WARNING: skipping paragraph macro: br after sp
+mandoc: transp.in:60:1: WARNING: skipping paragraph macro: sp after Pp
diff --git a/regress/mdoc/blank/transp.out_markdown b/regress/mdoc/blank/transp.out_markdown
new file mode 100644
index 00000000..9c8ac825
--- /dev/null
+++ b/regress/mdoc/blank/transp.out_markdown
@@ -0,0 +1,44 @@
+BLANK-TRANSP(1) - General Commands Manual
+
+# NAME
+
+**blank-transp** - transparent nodes between line breaks
+
+# DESCRIPTION
+
+Double br:
+br Pp:
+
+Pp br:
+
+Double Pp:
+
+br sp:
+
+sp br:
+
+Pp sp:
+
+Pp sp 2v:
+
+sp Pp:
+
+Double sp:
+
+br blank:
+
+blank br:
+
+Pp blank:
+
+blank Pp:
+
+sp blank:
+
+blank sp:
+
+Double blank:
+
+end of file
+
+OpenBSD - February 27, 2020
diff --git a/roff.c b/roff.c
index d5eb3f90..55172fad 100644
--- a/roff.c
+++ b/roff.c
@@ -1114,6 +1114,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/roff.h b/roff.h
index 6cc113c9..f9aa35de 100644
--- a/roff.h
+++ b/roff.h
@@ -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/roff_validate.c b/roff_validate.c
index 8c0dd237..3d617214 100644
--- a/roff_validate.c
+++ b/roff_validate.c
@@ -1,6 +1,6 @@
/* $Id$ */
/*
- * 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) {