summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main.c5
-rw-r--r--mandoc.h5
-rw-r--r--mdoc.760
-rw-r--r--mdoc_macro.c29
-rw-r--r--mdoc_term.c44
5 files changed, 127 insertions, 16 deletions
diff --git a/main.c b/main.c
index a21f1a38..85baaee1 100644
--- a/main.c
+++ b/main.c
@@ -120,6 +120,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"unknown manual section",
"section not in conventional manual section",
"end of line whitespace",
+ "blocks badly nested",
"scope open on exit",
"generic error",
@@ -143,7 +144,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"bad comment style",
"unknown macro will be lost",
"line scope broken",
- "scope broken",
"argument count wrong",
"request scope close w/none open",
"scope already open",
@@ -162,7 +162,8 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"missing font type",
"displays may not be nested",
"unsupported display type",
- "no scope to rewind: syntax violated",
+ "blocks badly nested",
+ "no such block is open",
"scope broken, syntax violated",
"line scope broken, syntax violated",
"argument count wrong, violates syntax",
diff --git a/mandoc.h b/mandoc.h
index 69a30622..9370d530 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -47,6 +47,7 @@ enum mandocerr {
MANDOCERR_BADMSEC, /* unknown manual section */
MANDOCERR_SECMSEC, /* section not in conventional manual section */
MANDOCERR_EOLNSPACE, /* end of line whitespace */
+ MANDOCERR_SCOPENEST, /* blocks badly nested */
MANDOCERR_SCOPEEXIT, /* scope open on exit */
MANDOCERR_ERROR, /* ===== end of errors ===== */
@@ -70,9 +71,8 @@ enum mandocerr {
MANDOCERR_BADCOMMENT, /* bad comment style */
MANDOCERR_MACRO, /* unknown macro will be lost */
MANDOCERR_LINESCOPE, /* line scope broken */
- MANDOCERR_SCOPE, /* scope broken */
MANDOCERR_ARGCOUNT, /* argument count wrong */
- MANDOCERR_NOSCOPE, /* request scope close w/none open */
+ MANDOCERR_NOSCOPE, /* no such block is open */
MANDOCERR_SCOPEREP, /* scope already open */
/* FIXME: merge following with MANDOCERR_ARGCOUNT */
MANDOCERR_NOARGS, /* macro requires line argument(s) */
@@ -92,6 +92,7 @@ enum mandocerr {
/* FIXME: this should be a MANDOCERR_ERROR */
MANDOCERR_NESTEDDISP, /* displays may not be nested */
MANDOCERR_BADDISP, /* unsupported display type */
+ MANDOCERR_SCOPEFATAL, /* blocks badly nested */
MANDOCERR_SYNTNOSCOPE, /* no scope to rewind: syntax violated */
MANDOCERR_SYNTSCOPE, /* scope broken, syntax violated */
MANDOCERR_SYNTLINESCOPE, /* line scope broken, syntax violated */
diff --git a/mdoc.7 b/mdoc.7
index 38282d1f..5b6788f2 100644
--- a/mdoc.7
+++ b/mdoc.7
@@ -478,6 +478,19 @@ they are separated by a vertical space, unless in the case of
and
.Sx \&Ft ,
which are always separated by vertical space.
+.Pp
+When text and macros following an
+.Sx \&Nm
+macro starting an input line span multiple output lines,
+all output lines but the first will be indented to align
+with the text immediately following the
+.Sx \&Nm
+macro, up to the next
+.Sx \&Nm ,
+.Sx \&Sx ,
+or
+.Sx \&Ss
+macro or the end of an enclosing block, whichever comes first.
.It Em DESCRIPTION
This expands upon the brief, one-line description in
.Em NAME .
@@ -672,9 +685,20 @@ has multiple heads.
.It Em Macro Ta Em Callable Ta Em Parsable Ta Em Scope
.It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El
.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh
+.It Sx \&Nm Ta \&No Ta Yes Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss
.It Sx \&Sh Ta \&No Ta \&No Ta closed by Sx \&Sh
.It Sx \&Ss Ta \&No Ta \&No Ta closed by Sx \&Sh , Sx \&Ss
.El
+.Pp
+Note that the
+.Sx \&Nm
+macro is a
+.Sx Block full-implicit
+macro only when invoked as the first macro
+in a
+.Em SYNOPSIS
+section line, else it is
+.Sx In-line .
.Ss Block partial-explicit
Like block full-explicit, but also with single-line scope.
Each has at least a body and, in limited circumstances, a head
@@ -1958,6 +1982,42 @@ Examples:
.D1 \&.Mt discuss@manpages.bsd.lv
.Ss \&Nd
.Ss \&Nm
+The name of the manual page, or \(em in particular in section 1, 6,
+and 8 pages \(em of an additional command or feature documented in
+the manual page.
+When first invoked, the
+.Sx \&Nm
+macro expects a single argument, the name of the manual page.
+Usually, the first invocation happens in the
+.Em NAME
+section of the page.
+The specified name will be remembered and used whenever the macro is
+called again without arguments later in the page.
+The
+.Sx \&Nm
+macro uses
+.Sx Block full-implicit
+semantics when invoked as the first macro on an input line in the
+.Em SYNOPSIS
+section; otherwise, it uses ordinary
+.Sx In-line
+semantics.
+.Pp
+Examples:
+.Bd -literal -offset indent
+\&.Sh SYNOPSIS
+\&.Nm cat
+\&.Op Fl benstuv
+\&.Op Ar
+.Ed
+.Pp
+In the
+.Em SYNOPSIS
+of section 2, 3 and 9 manual pages, use the
+.Sx \&Fn
+macro rather than
+.Sx \&Nm
+to mark up the name of the manual page.
.Ss \&No
.Ss \&Ns
.Ss \&Nx
diff --git a/mdoc_macro.c b/mdoc_macro.c
index 82cca0c6..99730eee 100644
--- a/mdoc_macro.c
+++ b/mdoc_macro.c
@@ -97,7 +97,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
{ blk_full, 0 }, /* Nd */
- { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
+ { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
{ obsolete, 0 }, /* Ot */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
@@ -392,6 +392,8 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
if (MDOC_Op == p->tok)
return(REWIND_MORE);
break;
+ case (MDOC_Nm):
+ return(REWIND_NONE);
case (MDOC_Nd):
/* FALLTHROUGH */
case (MDOC_Ss):
@@ -409,9 +411,11 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type,
/*
* Default block rewinding rules.
- * In particular, always skip block end markers.
+ * In particular, always skip block end markers,
+ * and let all blocks rewind Nm children.
*/
- if (ENDBODY_NOT != p->end || (MDOC_BLOCK == p->type &&
+ if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok ||
+ (MDOC_BLOCK == p->type &&
! (MDOC_EXPLICIT & mdoc_macros[tok].flags)))
return(REWIND_MORE);
@@ -507,8 +511,9 @@ make_pending(struct mdoc_node *broken, enum mdoct tok,
taker->pending = broken->pending;
}
broken->pending = breaker;
- mdoc_vmsg(m, MANDOCERR_SCOPE, line, ppos, "%s breaks %s",
- mdoc_macronames[tok], mdoc_macronames[broken->tok]);
+ mdoc_vmsg(m, MANDOCERR_SCOPENEST, line, ppos,
+ "%s breaks %s", mdoc_macronames[tok],
+ mdoc_macronames[broken->tok]);
return(1);
}
@@ -542,7 +547,9 @@ rew_sub(enum mdoc_type t, struct mdoc *m,
return(make_pending(n, tok, m, line, ppos));
case (REWIND_ERROR):
/* XXX Make this non-fatal. */
- mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTNOSCOPE);
+ mdoc_vmsg(m, MANDOCERR_SCOPEFATAL, line, ppos,
+ "%s cannot break %s", mdoc_macronames[tok],
+ mdoc_macronames[n->tok]);
return 0;
}
break;
@@ -653,7 +660,7 @@ blk_exp_close(MACRO_PROT_ARGS)
continue;
}
- if (MDOC_BLOCK != n->type)
+ if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok)
continue;
if (atok == n->tok) {
assert(body);
@@ -1290,8 +1297,8 @@ blk_part_imp(MACRO_PROT_ARGS)
* is ugly behaviour nodding its head to OpenBSD's overwhelming
* crufty use of `Op' breakage.
*/
- if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPE, line, ppos,
- "%s broken", mdoc_macronames[tok]))
+ if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPENEST,
+ line, ppos, "%s broken", mdoc_macronames[tok]))
return(0);
if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos))
@@ -1647,7 +1654,9 @@ ctx_synopsis(MACRO_PROT_ARGS)
* up formatting the block scope, then child nodes will inherit
* the formatting. Be careful.
*/
-
+ if (MDOC_Nm == tok)
+ return(blk_full(m, tok, line, ppos, pos, buf));
+ assert(MDOC_Vt == tok);
return(blk_part_imp(m, tok, line, ppos, pos, buf));
}
diff --git a/mdoc_term.c b/mdoc_term.c
index 633394d1..5138a22d 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -85,6 +85,7 @@ static void termp_fo_post(DECL_ARGS);
static void termp_in_post(DECL_ARGS);
static void termp_it_post(DECL_ARGS);
static void termp_lb_post(DECL_ARGS);
+static void termp_nm_post(DECL_ARGS);
static void termp_op_post(DECL_ARGS);
static void termp_pf_post(DECL_ARGS);
static void termp_pq_post(DECL_ARGS);
@@ -170,7 +171,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_in_pre, termp_in_post }, /* In */
{ termp_li_pre, NULL }, /* Li */
{ termp_nd_pre, NULL }, /* Nd */
- { termp_nm_pre, NULL }, /* Nm */
+ { termp_nm_pre, termp_nm_post }, /* Nm */
{ termp_op_pre, termp_op_post }, /* Op */
{ NULL, NULL }, /* Ot */
{ termp_under_pre, NULL }, /* Pa */
@@ -1025,11 +1026,35 @@ static int
termp_nm_pre(DECL_ARGS)
{
- if (NULL == n->child && NULL == m->name)
+ if (MDOC_BLOCK == n->type)
+ return(1);
+
+ if (MDOC_BODY == n->type) {
+ if (NULL == n->child)
+ return(0);
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+ p->offset += term_len(p, 1) +
+ (NULL == n->prev->child ? term_strlen(p, m->name) :
+ MDOC_TEXT == n->prev->child->type ?
+ term_strlen(p, n->prev->child->string) :
+ term_len(p, 5));
return(1);
+ }
+
+ if (NULL == n->child && NULL == m->name)
+ return(0);
synopsis_pre(p, n);
+ if (MDOC_HEAD == n->type && n->next->child) {
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_HANG;
+ p->rmargin = p->offset + term_len(p, 1) +
+ (NULL == n->child ? term_strlen(p, m->name) :
+ MDOC_TEXT == n->child->type ?
+ term_strlen(p, n->child->string) :
+ term_len(p, 5));
+ }
+
term_fontpush(p, TERMFONT_BOLD);
if (NULL == n->child)
term_word(p, m->name);
@@ -1038,6 +1063,21 @@ termp_nm_pre(DECL_ARGS)
/* ARGSUSED */
+static void
+termp_nm_post(DECL_ARGS)
+{
+
+ if (MDOC_HEAD == n->type && n->next->child) {
+ term_flushln(p);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ } else if (MDOC_BODY == n->type && n->child) {
+ term_flushln(p);
+ p->flags &= ~TERMP_NOLPAD;
+ }
+}
+
+
+/* ARGSUSED */
static int
termp_fl_pre(DECL_ARGS)
{