From 71840fc752bb2b731194aa9d32165cd967d262b2 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Sat, 21 Feb 2015 14:46:58 +0000 Subject: Escape quotes when expanding macro arguments. This fixes a bug naddy@ found in plan9/rc(1). --- roff.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/roff.c b/roff.c index 01fb2966..3c920137 100644 --- a/roff.c +++ b/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.262 2015/02/17 18:09:14 schwarze Exp $ */ +/* $Id: roff.c,v 1.263 2015/02/21 14:46:58 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015 Ingo Schwarze @@ -2653,14 +2653,16 @@ roff_so(ROFF_ARGS) static enum rofferr roff_userdef(ROFF_ARGS) { - const char *arg[9]; + const char *arg[9], *ap; char *cp, *n1, *n2; int i; + size_t asz, rsz; /* * Collect pointers to macro argument strings * and NUL-terminate them. */ + cp = buf->buf + pos; for (i = 0; i < 9; i++) arg[i] = *cp == '\0' ? "" : @@ -2669,31 +2671,89 @@ roff_userdef(ROFF_ARGS) /* * Expand macro arguments. */ - buf->sz = 0; - n1 = cp = mandoc_strdup(r->current_string); - while ((cp = strstr(cp, "\\$")) != NULL) { - i = cp[2] - '1'; - if (0 > i || 8 < i) { - /* Not an argument invocation. */ - cp += 2; + + buf->sz = strlen(r->current_string) + 1; + n1 = cp = mandoc_malloc(buf->sz); + memcpy(n1, r->current_string, buf->sz); + while (*cp != '\0') { + + /* Scan ahead for the next argument invocation. */ + + if (*cp++ != '\\') + continue; + if (*cp++ != '$') continue; + i = *cp - '1'; + if (0 > i || 8 < i) + continue; + cp -= 2; + + /* + * Determine the size of the expanded argument, + * taking escaping of quotes into account. + */ + + asz = 0; + for (ap = arg[i]; *ap != '\0'; ap++) { + asz++; + if (*ap == '"') + asz += 3; + } + if (asz != 3) { + + /* + * Determine the size of the rest of the + * unexpanded macro, including the NUL. + */ + + rsz = buf->sz - (cp - n1) - 3; + + /* + * When shrinking, move before + * releasing the storage. + */ + + if (asz < 3) + memmove(cp + asz, cp + 3, rsz); + + /* + * Resize the storage for the macro + * and readjust the parse pointer. + */ + + buf->sz += asz - 3; + n2 = mandoc_realloc(n1, buf->sz); + cp = n2 + (cp - n1); + n1 = n2; + + /* + * When growing, make room + * for the expanded argument. + */ + + if (asz > 3) + memmove(cp + asz, cp + 3, rsz); + } + + /* Copy the expanded argument, escaping quotes. */ + + n2 = cp; + for (ap = arg[i]; *ap != '\0'; ap++) { + if (*ap == '"') { + memcpy(n2, "\\(dq", 4); + n2 += 4; + } else + *n2++ = *ap; } - *cp = '\0'; - buf->sz = mandoc_asprintf(&n2, "%s%s%s", - n1, arg[i], cp + 3) + 1; - cp = n2 + (cp - n1); - free(n1); - n1 = n2; } /* * Replace the macro invocation * by the expanded macro. */ + free(buf->buf); buf->buf = n1; - if (buf->sz == 0) - buf->sz = strlen(buf->buf) + 1; *offs = 0; return(buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? -- cgit v1.2.3-56-ge451