aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/roff.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2018-08-20 17:25:09 +0000
committerIngo Schwarze <schwarze@openbsd.org>2018-08-20 17:25:09 +0000
commite0b77e5e8f276f44afbb5520fbcaab68991655b2 (patch)
tree43ee0421756c3a11616baa1fc9a6d38982f77c6d /roff.c
parentd3cd8071fec1187df23e51c90476a5a42e9c54c3 (diff)
downloadmandoc-e0b77e5e8f276f44afbb5520fbcaab68991655b2.tar.gz
mandoc-e0b77e5e8f276f44afbb5520fbcaab68991655b2.tar.zst
mandoc-e0b77e5e8f276f44afbb5520fbcaab68991655b2.zip
Expand \n(.$ (the number of macro arguments) right in roff_userdef(),
before even reparsing the expanded macro. That is the least dirty way to fix the bug that \(.$ remained set after execution of the user-defined macro ended. Any other way to fix it would probably require changes to read.c, which really shouldn't be bothered with such roff(7) internals.
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c43
1 files changed, 35 insertions, 8 deletions
diff --git a/roff.c b/roff.c
index 9b3002ca..4dd18e3e 100644
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/* $Id: roff.c,v 1.336 2018/08/19 17:46:14 schwarze Exp $ */
+/* $Id: roff.c,v 1.337 2018/08/20 17:25:09 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -107,7 +107,6 @@ struct roff {
int rstacksz; /* current size limit of rstack */
int rstackpos; /* position in rstack */
int format; /* current file in mdoc or man format */
- int argc; /* number of args of the last macro */
char control; /* control character */
char escape; /* escape character */
};
@@ -2663,7 +2662,7 @@ roff_getregro(const struct roff *r, const char *name)
switch (*name) {
case '$': /* Number of arguments of the last macro evaluated. */
- return r->argc;
+ return 0;
case 'A': /* ASCII approximation mode is always off. */
return 0;
case 'g': /* Groff compatibility mode is always on. */
@@ -3381,22 +3380,22 @@ roff_userdef(ROFF_ARGS)
{
const char *arg[16], *ap;
char *cp, *n1, *n2;
- int expand_count, i, ib, ie;
- size_t asz, rsz;
+ int argc, expand_count, i, ib, ie;
+ size_t asz, esz, rsz;
/*
* Collect pointers to macro argument strings
* and NUL-terminate them.
*/
- r->argc = 0;
+ argc = 0;
cp = buf->buf + pos;
for (i = 0; i < 16; i++) {
if (*cp == '\0')
arg[i] = "";
else {
arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos);
- r->argc = i + 1;
+ argc = i + 1;
}
}
@@ -3418,7 +3417,7 @@ roff_userdef(ROFF_ARGS)
continue;
if (*cp == '*') { /* \\$* inserts all arguments */
ib = 0;
- ie = r->argc - 1;
+ ie = argc - 1;
} else { /* \\$1 .. \\$9 insert one argument */
ib = ie = *cp - '1';
if (ib < 0 || ib > 8)
@@ -3507,6 +3506,34 @@ roff_userdef(ROFF_ARGS)
}
/*
+ * Expand the number of arguments, if it is used.
+ * This never makes the expanded macro longer.
+ */
+
+ for (cp = n1; *cp != '\0'; cp++) {
+ if (cp[0] != '\\')
+ continue;
+ if (cp[1] == '\\') {
+ cp++;
+ continue;
+ }
+ if (strncmp(cp + 1, "n(.$", 4) == 0)
+ esz = 5;
+ else if (strncmp(cp + 1, "n[.$]", 5) == 0)
+ esz = 6;
+ else
+ continue;
+ asz = snprintf(cp, esz, "%d", argc);
+ assert(asz < esz);
+ rsz = buf->sz - (cp - n1) - esz;
+ memmove(cp + asz, cp + esz, rsz);
+ buf->sz -= esz - asz;
+ n2 = mandoc_realloc(n1, buf->sz);
+ cp = n2 + (cp - n1) + asz;
+ n1 = n2;
+ }
+
+ /*
* Replace the macro invocation
* by the expanded macro.
*/