diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-11 12:25:33 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-11 12:25:33 +0200 |
commit | 4ef8841b21e27e7c7f58d3c9901c833b4fa5a862 (patch) | |
tree | a71524a521f7a1f0510b8affd1ba827a543fcb2f /editors | |
parent | 3d57a8490738d9febaa4496eba791e4fbfc91826 (diff) |
awk: unbreak "printf('%c') can output NUL" testcase
function old new delta
awk_printf 546 593 +47
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'editors')
-rw-r--r-- | editors/awk.c | 43 |
1 files changed, 26 insertions, 17 deletions
diff --git a/editors/awk.c b/editors/awk.c index 0aa7c0804..e765d3fcf 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -2309,11 +2309,11 @@ static int awk_getline(rstream *rsm, var *v) #if !ENABLE_FEATURE_AWK_GNU_EXTENSIONS # define awk_printf(a, b) awk_printf(a) #endif -static char *awk_printf(node *n, int *len) +static char *awk_printf(node *n, size_t *len) { char *b; char *fmt, *f; - int i; + size_t i; //tmpvar = nvalloc(1); #define TMPVAR (&G.awk_printf__tmpvar) @@ -2333,6 +2333,7 @@ static char *awk_printf(node *n, int *len) char c; char sv; var *arg; + size_t slen; s = f; while (*f && (*f != '%' || *++f == '%')) @@ -2347,6 +2348,7 @@ static char *awk_printf(node *n, int *len) /* Tail of fmt with no percent chars, * or "....%" (percent seen, but no format specifier char found) */ + slen = strlen(s); goto tail; } sv = *++f; @@ -2357,31 +2359,38 @@ static char *awk_printf(node *n, int *len) * printf "%99999s", "BOOM" */ if (c == 'c') { - s = xasprintf(s, is_numeric(arg) ? - (char)getvar_i(arg) : *getvar_s(arg)); - } else if (c == 's') { - s = xasprintf(s, getvar_s(arg)); + c = is_numeric(arg) ? getvar_i(arg) : *getvar_s(arg); + s = xasprintf(s, c); + /* + 1 if c == NUL: handle printf "%c" 0 case + * (and printf "%22c" 0 etc, but still fails for e.g. printf "%-22c" 0) */ + slen = strlen(s) + (c == '\0'); } else { - double d = getvar_i(arg); - if (strchr("diouxX", c)) { -//TODO: make it wider here (%x -> %llx etc)? - s = xasprintf(s, (int)d); - } else if (strchr("eEfFgGaA", c)) { - s = xasprintf(s, d); + if (c == 's') { + s = xasprintf(s, getvar_s(arg)); } else { - syntax_error(EMSG_INV_FMT); + double d = getvar_i(arg); + if (strchr("diouxX", c)) { +//TODO: make it wider here (%x -> %llx etc)? + s = xasprintf(s, (int)d); + } else if (strchr("eEfFgGaA", c)) { + s = xasprintf(s, d); + } else { + syntax_error(EMSG_INV_FMT); + } } + slen = strlen(s); } *f = sv; if (i == 0) { b = s; - i = strlen(b); + i = slen; continue; } tail: - b = xrealloc(b, i + strlen(s) + 1); - i = stpcpy(b + i, s) - b; + b = xrealloc(b, i + slen + 1); + strcpy(b + i, s); + i += slen; if (!c) /* tail? */ break; free(s); @@ -2926,7 +2935,6 @@ static var *evaluate(node *op, var *res) debug_printf_eval("PRINTF\n"); { FILE *F = stdout; - IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) if (op->r.n) { rstream *rsm = newfile(R.s); @@ -2966,6 +2974,7 @@ static var *evaluate(node *op, var *res) } fputs(getvar_s(intvar[ORS]), F); } else { /* PRINTF */ + IF_FEATURE_AWK_GNU_EXTENSIONS(size_t len;) char *s = awk_printf(op1, &len); #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS fwrite(s, len, 1, F); |