From 50f5bf83cff66e2f7baa88e327d78c37143bed97 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Tue, 21 Aug 2018 18:15:22 +0000 Subject: Implement the \\$@ escape sequence (insert all macro arguments, 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. --- roff.7 | 5 +++++ roff.c | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/roff.7 b/roff.7 index 56db5b6e..2fc7638e 100644 --- a/roff.7 +++ b/roff.7 @@ -634,6 +634,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 @@ -1838,6 +1840,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 . diff --git a/roff.c b/roff.c index 96c3c0bf..b13d93f6 100644 --- a/roff.c +++ b/roff.c @@ -3156,7 +3156,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); @@ -3380,7 +3380,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; /* @@ -3415,13 +3415,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; @@ -3447,6 +3455,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 == '"') @@ -3493,6 +3503,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); @@ -3500,6 +3512,8 @@ roff_userdef(ROFF_ARGS) } else *n2++ = *ap; } + if (quote_args) + *n2++ = '"'; if (i < ie) *n2++ = ' '; } -- cgit