Implement the man(7) .MR macro, a 2023 GNU extension.
authorschwarze <schwarze@openbsd.org>
Tue, 24 Oct 2023 20:30:49 +0000 (20:30 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 24 Oct 2023 20:30:49 +0000 (20:30 +0000)
The syntax and semantics is almost identical to mdoc(7) .Xr.

This will be needed for reading the groff manual pages once our port
will be updated to 1.23, and the Linux Manual Pages Project is also
determined to start using it sooner or later.  I did not advocate for
this new macro, but since we want to remain able to read all manual
pages found in the wild, there is little choice but to support it.
At least it is easy to do, they basically copied .Xr.

12 files changed:
regress/usr.bin/mandoc/man/MR/Makefile [new file with mode: 0644]
regress/usr.bin/mandoc/man/MR/basic.in [new file with mode: 0644]
regress/usr.bin/mandoc/man/MR/basic.out_ascii [new file with mode: 0644]
regress/usr.bin/mandoc/man/MR/basic.out_lint [new file with mode: 0644]
regress/usr.bin/mandoc/man/Makefile
usr.bin/mandoc/man_html.c
usr.bin/mandoc/man_macro.c
usr.bin/mandoc/man_term.c
usr.bin/mandoc/man_validate.c
usr.bin/mandoc/mandoc.1
usr.bin/mandoc/roff.c
usr.bin/mandoc/roff.h

diff --git a/regress/usr.bin/mandoc/man/MR/Makefile b/regress/usr.bin/mandoc/man/MR/Makefile
new file mode 100644 (file)
index 0000000..3237d45
--- /dev/null
@@ -0,0 +1,10 @@
+# $OpenBSD: Makefile,v 1.1 2023/10/24 20:30:49 schwarze Exp $
+
+REGRESS_TARGETS         = basic
+LINT_TARGETS    = basic
+
+.include <bsd.regress.mk>
+
+# temporary hack while working towards an update of the groff port
+MANDOC = mandoc -O indent=5
+GROFF = /co/groff/build/test-groff ${GOPTS} -d MF=R ${MOPTS} -Wall -P-c
diff --git a/regress/usr.bin/mandoc/man/MR/basic.in b/regress/usr.bin/mandoc/man/MR/basic.in
new file mode 100644 (file)
index 0000000..adb531a
--- /dev/null
@@ -0,0 +1,46 @@
+.\" $OpenBSD: basic.in,v 1.1 2023/10/24 20:30:49 schwarze Exp $
+.TH MR-BASIC 1 "October 24, 2023" OpenBSD
+.SH NAME
+MR-basic \- manual page cross references
+.SH DESCRIPTION
+empty:
+.MR
+prints empty name and parentheses
+.PP
+single argument:
+.MR name
+prints empty parentheses
+.PP
+two arguments:
+.MR test 1
+normal use
+.PP
+three arguments:
+.MR test 1 suffix
+with suffix
+.PP
+four arguments:
+.MR test 1 suffix excess
+warning
+.PP
+five arguments:
+.MR test 1 suffix too many
+warning
+.PP
+after setting
+.ft B
+bold
+font:
+.MR test 1 suffix
+not bold
+.PP
+in bold next-line scope:
+.B
+.MR test 1 suffix
+not bold
+.TP 5n
+first tag
+first body
+.TP
+.MR test 1 tag
+test body
diff --git a/regress/usr.bin/mandoc/man/MR/basic.out_ascii b/regress/usr.bin/mandoc/man/MR/basic.out_ascii
new file mode 100644 (file)
index 0000000..d386ba0
--- /dev/null
@@ -0,0 +1,29 @@
+MR-BASIC(1)                 General Commands Manual                MR-BASIC(1)
+
+N\bNA\bAM\bME\bE
+     MR-basic - manual page cross references
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     empty: () prints empty name and parentheses
+
+     single argument: name() prints empty parentheses
+
+     two arguments: test(1) normal use
+
+     three arguments: test(1)suffix with suffix
+
+     four arguments: test(1)suffix warning
+
+     five arguments: test(1)suffix warning
+
+     after setting b\bbo\bol\bld\bd f\bfo\bon\bnt\bt:\b: test(1)suffix not bold
+
+     in bold next-line scope: test(1)suffix not bold
+
+     first tag
+          first body
+
+     test(1)tag
+          test body
+
+OpenBSD                        October 24, 2023                    MR-BASIC(1)
diff --git a/regress/usr.bin/mandoc/man/MR/basic.out_lint b/regress/usr.bin/mandoc/man/MR/basic.out_lint
new file mode 100644 (file)
index 0000000..d4803bc
--- /dev/null
@@ -0,0 +1,5 @@
+mandoc: basic.in:38:2: WARNING: line scope broken: MR breaks B
+mandoc: basic.in:7:2: ERROR: missing manual name, using "": MR
+mandoc: basic.in:11:2: WARNING: missing section argument: MR name
+mandoc: basic.in:23:19: ERROR: skipping excess arguments: MR ... excess
+mandoc: basic.in:27:19: ERROR: skipping excess arguments: MR ... too
index 17a939b..306411d 100644 (file)
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.20 2022/04/27 17:04:15 schwarze Exp $
+# $OpenBSD: Makefile,v 1.21 2023/10/24 20:30:49 schwarze Exp $
 
-SUBDIR = AT B BI DT EX HP IP MT OP PD PP RS SH SS SY TH TP TS UC UR nf blank
+SUBDIR = AT B BI DT EX HP IP MR MT OP PD PP RS SH SS SY TH TP TS UC UR nf blank
 
 .include "../Makefile.sub"
 .include <bsd.subdir.mk>
index 581f837..918330d 100644 (file)
@@ -1,6 +1,6 @@
-/* $OpenBSD: man_html.c,v 1.139 2023/10/18 16:11:29 schwarze Exp $ */
+/* $OpenBSD: man_html.c,v 1.140 2023/10/24 20:30:49 schwarze Exp $ */
 /*
- * Copyright (c) 2013-2015,2017-2020,2022 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-15,2017-20,2022-23 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -51,6 +51,7 @@ static        char              list_continues(const struct roff_node *,
 static int               man_B_pre(MAN_ARGS);
 static int               man_IP_pre(MAN_ARGS);
 static int               man_I_pre(MAN_ARGS);
+static int               man_MR_pre(MAN_ARGS);
 static int               man_OP_pre(MAN_ARGS);
 static int               man_PP_pre(MAN_ARGS);
 static int               man_RS_pre(MAN_ARGS);
@@ -104,6 +105,7 @@ static      const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
        { NULL, NULL }, /* UE */
        { man_UR_pre, NULL }, /* MT */
        { NULL, NULL }, /* ME */
+       { man_MR_pre, NULL }, /* MR */
 };
 
 
@@ -516,6 +518,52 @@ man_IP_pre(MAN_ARGS)
        return 0;
 }
 
+static int
+man_MR_pre(MAN_ARGS)
+{
+       struct tag      *t;
+       const char      *name, *section, *suffix;
+       char            *label;
+
+       html_setfont(h, ESCAPE_FONTROMAN);
+       name = section = suffix = label = NULL;
+       if (n->child != NULL) {
+               name = n->child->string;
+               if (n->child->next != NULL) {
+                       section = n->child->next->string;
+                       mandoc_asprintf(&label,
+                           "%s, section %s", name, section);
+                       if (n->child->next->next != NULL)
+                               suffix = n->child->next->next->string;
+               }
+       }
+
+       if (name != NULL && section != NULL && h->base_man1 != NULL)
+               t = print_otag(h, TAG_A, "chM?", "Xr",
+                   name, section, "aria-label", label);
+       else
+               t = print_otag(h, TAG_A, "c?", "Xr", "aria-label", label);
+
+       free(label);
+       if (name != NULL) {
+               print_text(h, name);
+               h->flags |= HTML_NOSPACE;
+       }
+       print_text(h, "(");
+       h->flags |= HTML_NOSPACE;
+       if (section != NULL) {
+               print_text(h, section);
+               h->flags |= HTML_NOSPACE;
+       }
+       print_text(h, ")");
+       print_tagq(h, t);
+       if (suffix != NULL) {
+               h->flags |= HTML_NOSPACE;
+               print_text(h, suffix);
+       }
+       return 0;
+}
+
 static int
 man_OP_pre(MAN_ARGS)
 {
index 10f0776..f73ad97 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: man_macro.c,v 1.109 2022/04/27 17:04:15 schwarze Exp $ */
+/* $OpenBSD: man_macro.c,v 1.110 2023/10/24 20:30:49 schwarze Exp $ */
 /*
  * Copyright (c) 2012-2015,2017-2020,2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -77,6 +77,7 @@ static const struct man_macro man_macros[MAN_MAX - MAN_TH] = {
        { blk_close, MAN_XSCOPE }, /* UE */
        { blk_exp, MAN_XSCOPE }, /* MT */
        { blk_close, MAN_XSCOPE }, /* ME */
+       { in_line_eoln, 0 }, /* MR */
 };
 
 
index 75b2744..5fa9bc1 100644 (file)
@@ -1,6 +1,6 @@
-/* $OpenBSD: man_term.c,v 1.195 2023/04/28 20:14:19 schwarze Exp $ */
+/* $OpenBSD: man_term.c,v 1.196 2023/10/24 20:30:49 schwarze Exp $ */
 /*
- * Copyright (c) 2010-2015,2017-2020,2022 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-15,2017-20,2022-23 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -72,6 +72,7 @@ static        int               pre_DT(DECL_ARGS);
 static int               pre_HP(DECL_ARGS);
 static int               pre_I(DECL_ARGS);
 static int               pre_IP(DECL_ARGS);
+static int               pre_MR(DECL_ARGS);
 static int               pre_OP(DECL_ARGS);
 static int               pre_PD(DECL_ARGS);
 static int               pre_PP(DECL_ARGS);
@@ -132,6 +133,7 @@ static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
        { NULL, NULL, 0 }, /* UE */
        { pre_UR, post_UR, 0 }, /* MT */
        { NULL, NULL, 0 }, /* ME */
+       { pre_MR, NULL, 0 }, /* MR */
 };
 static const struct man_term_act *man_term_act(enum roff_tok);
 
@@ -325,6 +327,29 @@ pre_B(DECL_ARGS)
        return 1;
 }
 
+static int
+pre_MR(DECL_ARGS)
+{
+       term_fontrepl(p, TERMFONT_NONE);
+       n = n->child;
+       if (n != NULL) {
+               term_word(p, n->string);   /* name */
+               p->flags |= TERMP_NOSPACE;
+       }
+       term_word(p, "(");
+       p->flags |= TERMP_NOSPACE;
+       if (n != NULL && (n = n->next) != NULL) {
+               term_word(p, n->string);   /* section */
+               p->flags |= TERMP_NOSPACE;
+       }
+       term_word(p, ")");
+       if (n != NULL && (n = n->next) != NULL) {
+               p->flags |= TERMP_NOSPACE;
+               term_word(p, n->string);   /* suffix */
+       }
+       return 0;
+}
+
 static int
 pre_OP(DECL_ARGS)
 {
index c83e5a2..4a24acd 100644 (file)
@@ -1,6 +1,6 @@
-/* $OpenBSD: man_validate.c,v 1.128 2023/04/28 20:14:19 schwarze Exp $ */
+/* $OpenBSD: man_validate.c,v 1.129 2023/10/24 20:30:49 schwarze Exp $ */
 /*
- * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2020, 2023 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -31,6 +31,7 @@
 
 #include "mandoc_aux.h"
 #include "mandoc.h"
+#include "mandoc_xr.h"
 #include "roff.h"
 #include "man.h"
 #include "libmandoc.h"
@@ -52,6 +53,7 @@ static        void      post_AT(CHKARGS);
 static void      post_EE(CHKARGS);
 static void      post_EX(CHKARGS);
 static void      post_IP(CHKARGS);
+static void      post_MR(CHKARGS);
 static void      post_OP(CHKARGS);
 static void      post_SH(CHKARGS);
 static void      post_TH(CHKARGS);
@@ -98,6 +100,7 @@ static       const v_check man_valids[MAN_MAX - MAN_TH] = {
        NULL,       /* UE */
        post_UR,    /* MT */
        NULL,       /* ME */
+       post_MR,    /* MR */
 };
 
 
@@ -544,6 +547,32 @@ post_TH(CHKARGS)
        roff_node_delete(man, man->last);
 }
 
+static void
+post_MR(CHKARGS)
+{
+       struct roff_node *nch;
+
+       if ((nch = n->child) == NULL) {
+               mandoc_msg(MANDOCERR_NM_NONAME, n->line, n->pos, "MR");
+               return;
+       }
+       if (nch->next == NULL) {
+               mandoc_msg(MANDOCERR_XR_NOSEC,
+                   n->line, n->pos, "MR %s", nch->string);
+               return;
+       }
+       if (mandoc_xr_add(nch->next->string, nch->string, nch->line, nch->pos))
+               mandoc_msg(MANDOCERR_XR_SELF, nch->line, nch->pos,
+                   "MR %s %s", nch->string, nch->next->string);
+       if ((nch = nch->next->next) == NULL || nch->next == NULL)
+               return;
+
+       mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line, nch->next->pos,
+           "MR ... %s", nch->next->string);
+       while (nch->next != NULL)
+               roff_node_delete(man, nch->next);
+}
+
 static void
 post_UC(CHKARGS)
 {
index fd8d4d6..527511c 100644 (file)
@@ -1,6 +1,6 @@
-.\" $OpenBSD: mandoc.1,v 1.191 2023/10/18 14:47:22 schwarze Exp $
+.\" $OpenBSD: mandoc.1,v 1.192 2023/10/24 20:30:49 schwarze Exp $
 .\"
-.\" Copyright (c) 2012, 2014-2022 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2012, 2014-2023 Ingo Schwarze <schwarze@openbsd.org>
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\"
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: October 18 2023 $
+.Dd $Mdocdate: October 24 2023 $
 .Dt MANDOC 1
 .Os
 .Sh NAME
@@ -1295,9 +1295,11 @@ The same standard section title occurs more than once.
 A standard section header occurs in a section of the manual
 where it normally isn't useful.
 .It Sy "cross reference to self"
-.Pq mdoc
+.Pq mdoc , man
 An
 .Ic \&Xr
+or
+.Ic \&MR
 macro refers to a name and section matching the section of the present
 manual page and a name mentioned in an
 .Ic \&Nm
@@ -1616,12 +1618,16 @@ macro is immediately followed by an
 macro on the next input line.
 Such an empty block does not produce any output.
 .It Sy "missing section argument"
-.Pq mdoc
+.Pq mdoc , man
 An
 .Ic \&Xr
+or
+.Ic \&MR
 macro lacks its second, section number argument.
-The first argument, i.e. the name, is printed, but without subsequent
-parentheses.
+The first argument, i.e. the name, is printed, but without a section number.
+In the case of
+.Ic \&Xr ,
+the parentheses are also omitted.
 .It Sy "missing -std argument, adding it"
 .Pq mdoc
 An
@@ -2152,10 +2158,12 @@ request is neither a single ASCII character
 nor a single character escape sequence.
 All arguments are ignored and printing of a margin character is disabled.
 .It Sy "missing manual name, using \(dq\(dq"
-.Pq mdoc
+.Pq mdoc , man
 The first call to
 .Ic \&Nm ,
-or any call in the NAME section, lacks the required argument.
+or any call in the NAME section, lacks the required argument, or
+.Ic \&MR
+is called without any argument.
 .It Sy "uname(3) system call failed, using UNKNOWN"
 .Pq mdoc
 The
@@ -2283,6 +2291,8 @@ or a request of the
 family with more than two arguments
 .It
 .Ic \&Dt
+or
+.Ic \&MR
 with more than three arguments
 .It
 .Ic \&TH
index 7b3df53..651e582 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: roff.c,v 1.271 2023/10/23 20:07:18 schwarze Exp $ */
+/* $OpenBSD: roff.c,v 1.272 2023/10/24 20:30:49 schwarze Exp $ */
 /*
  * Copyright (c) 2010-2015, 2017-2023 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -365,7 +365,8 @@ const char *__roff_name[MAN_MAX + 1] = {
        "PD",           "AT",           "in",
        "SY",           "YS",           "OP",
        "EX",           "EE",           "UR",
-       "UE",           "MT",           "ME",           NULL
+       "UE",           "MT",           "ME",           "MR",
+       NULL
 };
 const  char *const *roff_name = __roff_name;
 
index e04ced7..f6ebfe9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: roff.h,v 1.57 2022/04/30 15:08:56 schwarze Exp $  */
+/* $OpenBSD: roff.h,v 1.58 2023/10/24 20:30:49 schwarze Exp $  */
 /*
  * Copyright (c) 2013-2015,2017-2020,2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -476,6 +476,7 @@ enum        roff_tok {
        MAN_UE,
        MAN_MT,
        MAN_ME,
+       MAN_MR,
        MAN_MAX         /* End of man(7) macros. */
 };