summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mdoc_term.c14
-rw-r--r--mdoc_validate.c49
-rw-r--r--regress/mdoc/Sh/Makefile6
-rw-r--r--regress/mdoc/Sh/tag.in21
-rw-r--r--regress/mdoc/Sh/tag.out_ascii22
-rw-r--r--regress/mdoc/Sh/tag.out_html9
-rw-r--r--regress/mdoc/Sh/tag.out_markdown27
-rw-r--r--roff.c2
-rw-r--r--roff.h2
-rw-r--r--tree.c7
10 files changed, 141 insertions, 18 deletions
diff --git a/mdoc_term.c b/mdoc_term.c
index 776f1130..35e05809 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -117,7 +117,6 @@ static int termp_pp_pre(DECL_ARGS);
static int termp_ss_pre(DECL_ARGS);
static int termp_sy_pre(DECL_ARGS);
static int termp_tag_pre(DECL_ARGS);
-static int termp_tg_pre(DECL_ARGS);
static int termp_under_pre(DECL_ARGS);
static int termp_vt_pre(DECL_ARGS);
static int termp_xr_pre(DECL_ARGS);
@@ -244,7 +243,7 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, termp____post }, /* %Q */
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
- { termp_tg_pre, NULL }, /* Tg */
+ { termp_skip_pre, NULL }, /* Tg */
};
static int fn_prio = TAG_STRONG;
@@ -341,6 +340,10 @@ print_mdoc_node(DECL_ARGS)
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
+ if (n->flags & NODE_ID)
+ tag_put(n->string == NULL ? n->child->string : n->string,
+ TAG_MANUAL, p->line);
+
/*
* Keeps only work until the end of a line. If a keep was
* invoked in a prior line, revert it to PREKEEP.
@@ -2066,13 +2069,6 @@ termp_tag_pre(DECL_ARGS)
}
static int
-termp_tg_pre(DECL_ARGS)
-{
- tag_put(n->child->string, TAG_MANUAL, p->line);
- return 0;
-}
-
-static int
termp_abort_pre(DECL_ARGS)
{
abort();
diff --git a/mdoc_validate.c b/mdoc_validate.c
index 6ab715d3..c8e261f9 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1094,21 +1094,32 @@ post_st(POST_ARGS)
static void
post_tg(POST_ARGS)
{
- struct roff_node *n, *nch;
+ struct roff_node *n, *nch, *nn;
size_t len;
+ /* Find the next node. */
n = mdoc->last;
+ for (nn = n; nn != NULL; nn = nn->parent) {
+ if (nn->next != NULL) {
+ nn = nn->next;
+ break;
+ }
+ }
+
+ /* Add the default argument, if needed. */
nch = n->child;
- if (nch == NULL && n->next != NULL &&
- n->next->child->type == ROFFT_TEXT) {
+ if (nch == NULL && nn != NULL && nn->child->type == ROFFT_TEXT) {
mdoc->next = ROFF_NEXT_CHILD;
roff_word_alloc(mdoc, n->line, n->pos, n->next->child->string);
nch = mdoc->last;
nch->flags |= NODE_NOSRC;
mdoc->last = n;
}
- if (nch == NULL || *nch->string == '\0') {
+
+ /* Validate the first argument. */
+ if (nch == NULL || *nch->string == '\0')
mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg");
+ if (nch == NULL) {
roff_node_delete(mdoc, n);
return;
}
@@ -1116,14 +1127,42 @@ post_tg(POST_ARGS)
if (nch->string[len] != '\0')
mandoc_msg(MANDOCERR_TG_SPC, nch->line, nch->pos + len + 1,
"Tg %s", nch->string);
+
+ /* Keep only the first argument. */
if (nch->next != NULL) {
mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line,
nch->next->pos, "Tg ... %s", nch->next->string);
while (nch->next != NULL)
roff_node_delete(mdoc, nch->next);
}
- if (nch->string[len] != '\0')
+
+ /* Drop the macro if the first argument is invalid. */
+ if (len == 0 || nch->string[len] != '\0') {
roff_node_delete(mdoc, n);
+ return;
+ }
+
+ /* By default, write a <mark> element. */
+ n->flags |= NODE_ID;
+ if (nn == NULL)
+ return;
+
+ /* Explicit tagging of specific macros. */
+ switch (nn->tok) {
+ case MDOC_Sh:
+ case MDOC_Ss:
+ if (nn->head->flags & NODE_ID || nn->head->child == NULL)
+ break;
+ n->flags |= NODE_NOPRT;
+ nn->head->flags |= NODE_ID | NODE_HREF;
+ assert(nn->head->string == NULL);
+ nn->head->string = mandoc_strdup(nch->string);
+ break;
+ default:
+ break;
+ }
+ if (n->flags & NODE_NOPRT)
+ n->flags &= ~NODE_ID;
}
static void
diff --git a/regress/mdoc/Sh/Makefile b/regress/mdoc/Sh/Makefile
index 213664ec..4b37bb2a 100644
--- a/regress/mdoc/Sh/Makefile
+++ b/regress/mdoc/Sh/Makefile
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile,v 1.12 2020/02/27 01:25:58 schwarze Exp $
+# $OpenBSD: Makefile,v 1.13 2020/02/27 21:38:27 schwarze Exp $
REGRESS_TARGETS = badNAME before empty emptyNAME first nohead order
REGRESS_TARGETS += orderNAME paragraph parbefore parborder punctNAME
-REGRESS_TARGETS += subbefore transp
+REGRESS_TARGETS += subbefore tag transp
LINT_TARGETS = badNAME before empty emptyNAME first nohead order
LINT_TARGETS += orderNAME parbefore parborder punctNAME subbefore
-HTML_TARGETS = paragraph
+HTML_TARGETS = paragraph tag
# groff-1.22.3 defects:
# - .Pp before .Sh NAME causes a blank line before the header line
diff --git a/regress/mdoc/Sh/tag.in b/regress/mdoc/Sh/tag.in
new file mode 100644
index 00000000..c204fc6b
--- /dev/null
+++ b/regress/mdoc/Sh/tag.in
@@ -0,0 +1,21 @@
+.\" $OpenBSD: tag.in,v 1.1 2020/02/27 21:38:27 schwarze Exp $
+.Dd $Mdocdate$
+.Dt SH-TAG 1
+.Os
+.Sh NAME
+.Nm Sh-tag
+.Nd tagging section headers
+.Sh DESCRIPTION
+Text in the description.
+.Ss Subsection
+BEGINTEST
+.Pp
+Text in the subsection.
+.Tg examples
+.Sh EXAMPLES
+Text introducing examples.
+.Tg example
+.Ss Subsection
+Example text.
+.Pp
+ENDTEST
diff --git a/regress/mdoc/Sh/tag.out_ascii b/regress/mdoc/Sh/tag.out_ascii
new file mode 100644
index 00000000..df0ab050
--- /dev/null
+++ b/regress/mdoc/Sh/tag.out_ascii
@@ -0,0 +1,22 @@
+SH-TAG(1) General Commands Manual SH-TAG(1)
+
+NNAAMMEE
+ SShh--ttaagg - tagging section headers
+
+DDEESSCCRRIIPPTTIIOONN
+ Text in the description.
+
+ SSuubbsseeccttiioonn
+ BEGINTEST
+
+ Text in the subsection.
+
+EEXXAAMMPPLLEESS
+ Text introducing examples.
+
+ SSuubbsseeccttiioonn
+ Example text.
+
+ ENDTEST
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Sh/tag.out_html b/regress/mdoc/Sh/tag.out_html
new file mode 100644
index 00000000..9722aa8c
--- /dev/null
+++ b/regress/mdoc/Sh/tag.out_html
@@ -0,0 +1,9 @@
+<p class="Pp">Text in the subsection.</p>
+</section>
+</section>
+<section class="Sh">
+<h1 class="Sh" id="examples"><a class="permalink" href="#examples">EXAMPLES</a></h1>
+<p class="Pp">Text introducing examples.</p>
+<section class="Ss">
+<h2 class="Ss" id="example"><a class="permalink" href="#example">Subsection</a></h2>
+<p class="Pp">Example text.</p>
diff --git a/regress/mdoc/Sh/tag.out_markdown b/regress/mdoc/Sh/tag.out_markdown
new file mode 100644
index 00000000..2813f8f0
--- /dev/null
+++ b/regress/mdoc/Sh/tag.out_markdown
@@ -0,0 +1,27 @@
+SH-TAG(1) - General Commands Manual
+
+# NAME
+
+**Sh-tag** - tagging section headers
+
+# DESCRIPTION
+
+Text in the description.
+
+## Subsection
+
+BEGINTEST
+
+Text in the subsection.
+
+# EXAMPLES
+
+Text introducing examples.
+
+## Subsection
+
+Example text.
+
+ENDTEST
+
+OpenBSD - February 27, 2020
diff --git a/roff.c b/roff.c
index 55172fad..d1f364d4 100644
--- a/roff.c
+++ b/roff.c
@@ -1173,7 +1173,7 @@ deroff(char **dest, const struct roff_node *n)
char *cp;
size_t sz;
- if (n->type != ROFFT_TEXT) {
+ if (n->string == NULL) {
for (n = n->child; n != NULL; n = n->next)
deroff(dest, n);
return;
diff --git a/roff.h b/roff.h
index f9aa35de..37d90b4e 100644
--- a/roff.h
+++ b/roff.h
@@ -522,6 +522,8 @@ struct roff_node {
#define NODE_NOFILL (1 << 8) /* Fill mode switched off. */
#define NODE_NOSRC (1 << 9) /* Generated node, not in input file. */
#define NODE_NOPRT (1 << 10) /* Shall not print anything. */
+#define NODE_ID (1 << 11) /* Target for deep linking. */
+#define NODE_HREF (1 << 12) /* Link to another place in this page. */
int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */
enum roff_tok tok; /* Request or macro ID. */
diff --git a/tree.c b/tree.c
index 1a6d4dd7..5352b868 100644
--- a/tree.c
+++ b/tree.c
@@ -199,6 +199,13 @@ print_mdoc(const struct roff_node *n, int indent)
putchar(')');
if (n->flags & NODE_EOS)
putchar('.');
+ if (n->flags & NODE_ID) {
+ printf(" ID");
+ if (n->string != NULL)
+ printf("=%s", n->string);
+ }
+ if (n->flags & NODE_HREF)
+ printf(" HREF");
if (n->flags & NODE_BROKEN)
printf(" BROKEN");
if (n->flags & NODE_NOFILL)