Implement the \\$@ escape sequence (insert all macro arguments,
authorschwarze <schwarze@openbsd.org>
Tue, 21 Aug 2018 18:15:16 +0000 (18:15 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 21 Aug 2018 18:15:16 +0000 (18:15 +0000)
quoted) in addition to the already supported \\$* (similar, but
unquoted).  Then use \\$@ to improve the implementation of
the .als request (macro alias).

Needed by groff_hdtbl(7).
Gosh, it feels like the manual pages of the groff package are
exercising every bloody roff(7) feature under the sun.  In the
manual page source code itself, not merely in the implementation
of the used macro packages, that is.

share/man/man7/roff.7
usr.bin/mandoc/roff.c

index 2196575..a48c10f 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.81 2018/08/19 17:43:39 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.82 2018/08/21 18:15:17 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -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: August 19 2018 $
+.Dd $Mdocdate: August 21 2018 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -632,6 +632,8 @@ produces
 in the input stream, and thus in the output: \fI\^XtFree\^\fP.
 Each occurrence of \e\e$* is replaced with all the arguments,
 joined together with single space characters.
+The variant \e\e$@ is similar, except that each argument is
+individually quoted.
 .Pp
 Since macros and user-defined strings share a common string table,
 defining a macro
@@ -1836,6 +1838,9 @@ Discard the rest of the physical input line and continue the logical
 input line on the next physical input line, joining the text on
 both lines together as if it were on a single input line.
 This is a groff extension.
+.Ss \e$ Ns Ar arg
+Macro argument expansion, see
+.Sx de .
 .Ss \e%
 Hyphenation allowed at this point of the word; ignored by
 .Xr mandoc 1 .
index ee9d45c..b673117 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.209 2018/08/20 17:31:44 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.210 2018/08/21 18:15:16 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -3154,7 +3154,7 @@ roff_als(ROFF_ARGS)
        if (oldsz == 0)
                return ROFF_IGN;
 
-       valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n",
+       valsz = mandoc_asprintf(&value, ".%.*s \\$@\\\"\n",
            (int)oldsz, oldn);
        roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0);
        roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
@@ -3378,7 +3378,7 @@ roff_userdef(ROFF_ARGS)
 {
        const char       *arg[16], *ap;
        char             *cp, *n1, *n2;
-       int               argc, expand_count, i, ib, ie;
+       int               argc, expand_count, i, ib, ie, quote_args;
        size_t            asz, esz, rsz;
 
        /*
@@ -3413,13 +3413,21 @@ roff_userdef(ROFF_ARGS)
                        continue;
                if (*cp++ != '$')
                        continue;
-               if (*cp == '*') {  /* \\$* inserts all arguments */
+
+               quote_args = 0;
+               switch (*cp) {
+               case '@':  /* \\$@ inserts all arguments, quoted */
+                       quote_args = 1;
+                       /* FALLTHROUGH */
+               case '*':  /* \\$* inserts all arguments, unquoted */
                        ib = 0;
                        ie = argc - 1;
-               } else {  /* \\$1 .. \\$9 insert one argument */
+                       break;
+               default:  /* \\$1 .. \\$9 insert one argument */
                        ib = ie = *cp - '1';
                        if (ib < 0 || ib > 8)
                                continue;
+                       break;
                }
                cp -= 2;
 
@@ -3445,6 +3453,8 @@ roff_userdef(ROFF_ARGS)
 
                asz = ie > ib ? ie - ib : 0;  /* for blanks */
                for (i = ib; i <= ie; i++) {
+                       if (quote_args)
+                               asz += 2;
                        for (ap = arg[i]; *ap != '\0'; ap++) {
                                asz++;
                                if (*ap == '"')
@@ -3491,6 +3501,8 @@ roff_userdef(ROFF_ARGS)
 
                n2 = cp;
                for (i = ib; i <= ie; i++) {
+                       if (quote_args)
+                               *n2++ = '"';
                        for (ap = arg[i]; *ap != '\0'; ap++) {
                                if (*ap == '"') {
                                        memcpy(n2, "\\(dq", 4);
@@ -3498,6 +3510,8 @@ roff_userdef(ROFF_ARGS)
                                } else
                                        *n2++ = *ap;
                        }
+                       if (quote_args)
+                               *n2++ = '"';
                        if (i < ie)
                                *n2++ = ' ';
                }