diff options
author | Ron Yorston <rmy@pobox.com> | 2021-01-27 11:19:14 +0000 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-02-02 13:51:14 +0100 |
commit | e8fe9f96356a6b19ec907ea30cffc829c539a7ff (patch) | |
tree | 1c9450cbdc4c32266241652303852acde28c14a0 | |
parent | f3a55b306ed3803133ab028b72b255c65d94197f (diff) | |
download | busybox-w32-e8fe9f96356a6b19ec907ea30cffc829c539a7ff.tar.gz busybox-w32-e8fe9f96356a6b19ec907ea30cffc829c539a7ff.tar.bz2 busybox-w32-e8fe9f96356a6b19ec907ea30cffc829c539a7ff.zip |
awk: allow printf('%c') to output NUL, closes 13486
Treat the output of printf as binary rather than a null-terminated
string so that NUL characters can be output.
This is considered to be a GNU extension, though it's also available
in mawk and FreeBSD's awk.
function old new delta
evaluate 3487 3504 +17
awk_printf 504 519 +15
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 32/0) Total: 32 bytes
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/awk.c | 18 | ||||
-rwxr-xr-x | testsuite/awk.tests | 5 |
2 files changed, 20 insertions, 3 deletions
diff --git a/editors/awk.c b/editors/awk.c index 2c15f9e4e..b4f6a3741 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -2155,7 +2155,10 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i | |||
2155 | } | 2155 | } |
2156 | 2156 | ||
2157 | /* formatted output into an allocated buffer, return ptr to buffer */ | 2157 | /* formatted output into an allocated buffer, return ptr to buffer */ |
2158 | static char *awk_printf(node *n) | 2158 | #if !ENABLE_FEATURE_AWK_GNU_EXTENSIONS |
2159 | # define awk_printf(a, b) awk_printf(a) | ||
2160 | #endif | ||
2161 | static char *awk_printf(node *n, int *len) | ||
2159 | { | 2162 | { |
2160 | char *b = NULL; | 2163 | char *b = NULL; |
2161 | char *fmt, *s, *f; | 2164 | char *fmt, *s, *f; |
@@ -2209,6 +2212,10 @@ static char *awk_printf(node *n) | |||
2209 | nvfree(v); | 2212 | nvfree(v); |
2210 | b = xrealloc(b, i + 1); | 2213 | b = xrealloc(b, i + 1); |
2211 | b[i] = '\0'; | 2214 | b[i] = '\0'; |
2215 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | ||
2216 | if (len) | ||
2217 | *len = i; | ||
2218 | #endif | ||
2212 | return b; | 2219 | return b; |
2213 | } | 2220 | } |
2214 | 2221 | ||
@@ -2666,6 +2673,7 @@ static var *evaluate(node *op, var *res) | |||
2666 | case XC( OC_PRINT ): | 2673 | case XC( OC_PRINT ): |
2667 | case XC( OC_PRINTF ): { | 2674 | case XC( OC_PRINTF ): { |
2668 | FILE *F = stdout; | 2675 | FILE *F = stdout; |
2676 | IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) | ||
2669 | 2677 | ||
2670 | if (op->r.n) { | 2678 | if (op->r.n) { |
2671 | rstream *rsm = newfile(R.s); | 2679 | rstream *rsm = newfile(R.s); |
@@ -2703,8 +2711,12 @@ static var *evaluate(node *op, var *res) | |||
2703 | fputs(getvar_s(intvar[ORS]), F); | 2711 | fputs(getvar_s(intvar[ORS]), F); |
2704 | 2712 | ||
2705 | } else { /* OC_PRINTF */ | 2713 | } else { /* OC_PRINTF */ |
2706 | char *s = awk_printf(op1); | 2714 | char *s = awk_printf(op1, &len); |
2715 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | ||
2716 | fwrite(s, len, 1, F); | ||
2717 | #else | ||
2707 | fputs(s, F); | 2718 | fputs(s, F); |
2719 | #endif | ||
2708 | free(s); | 2720 | free(s); |
2709 | } | 2721 | } |
2710 | fflush(F); | 2722 | fflush(F); |
@@ -2978,7 +2990,7 @@ static var *evaluate(node *op, var *res) | |||
2978 | break; | 2990 | break; |
2979 | 2991 | ||
2980 | case XC( OC_SPRINTF ): | 2992 | case XC( OC_SPRINTF ): |
2981 | setvar_p(res, awk_printf(op1)); | 2993 | setvar_p(res, awk_printf(op1, NULL)); |
2982 | break; | 2994 | break; |
2983 | 2995 | ||
2984 | case XC( OC_UNARY ): { | 2996 | case XC( OC_UNARY ): { |
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 92c83d719..cf9b722dc 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -383,6 +383,11 @@ testing "awk errors on missing delete arg" \ | |||
383 | "awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" "" | 383 | "awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" "" |
384 | SKIP= | 384 | SKIP= |
385 | 385 | ||
386 | optional FEATURE_AWK_GNU_EXTENSIONS | ||
387 | testing "awk printf('%c') can output NUL" \ | ||
388 | "awk '{printf(\"hello%c null\n\", 0)}'" "hello\0 null\n" "" "\n" | ||
389 | SKIP= | ||
390 | |||
386 | # testing "description" "command" "result" "infile" "stdin" | 391 | # testing "description" "command" "result" "infile" "stdin" |
387 | testing 'awk negative field access' \ | 392 | testing 'awk negative field access' \ |
388 | 'awk 2>&1 -- '\''{ $(-1) }'\' \ | 393 | 'awk 2>&1 -- '\''{ $(-1) }'\' \ |