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 <[email protected]>
---
 editors/awk.c       | 18 +++++++++++++++---
 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
 }
 
 /* formatted output into an allocated buffer, return ptr to buffer */
-static char *awk_printf(node *n)
+#if !ENABLE_FEATURE_AWK_GNU_EXTENSIONS
+# define awk_printf(a, b) awk_printf(a)
+#endif
+static char *awk_printf(node *n, int *len)
 {
        char *b = NULL;
        char *fmt, *s, *f;
@@ -2209,6 +2212,10 @@ static char *awk_printf(node *n)
        nvfree(v);
        b = xrealloc(b, i + 1);
        b[i] = '\0';
+#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
+       if (len)
+               *len = i;
+#endif
        return b;
 }
 
@@ -2666,6 +2673,7 @@ static var *evaluate(node *op, var *res)
                case XC( OC_PRINT ):
                case XC( OC_PRINTF ): {
                        FILE *F = stdout;
+                       IF_FEATURE_AWK_GNU_EXTENSIONS(int len;)
 
                        if (op->r.n) {
                                rstream *rsm = newfile(R.s);
@@ -2703,8 +2711,12 @@ static var *evaluate(node *op, var *res)
                                fputs(getvar_s(intvar[ORS]), F);
 
                        } else {        /* OC_PRINTF */
-                               char *s = awk_printf(op1);
+                               char *s = awk_printf(op1, &len);
+#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
+                               fwrite(s, len, 1, F);
+#else
                                fputs(s, F);
+#endif
                                free(s);
                        }
                        fflush(F);
@@ -2978,7 +2990,7 @@ static var *evaluate(node *op, var *res)
                        break;
 
                case XC( OC_SPRINTF ):
-                       setvar_p(res, awk_printf(op1));
+                       setvar_p(res, awk_printf(op1, NULL));
                        break;
 
                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" \
        "awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" ""
 SKIP=
 
+optional FEATURE_AWK_GNU_EXTENSIONS
+testing "awk printf('%c') can output NUL" \
+       "awk '{printf(\"hello%c null\n\", 0)}'" "hello\0 null\n" "" "\n"
+SKIP=
+
 # testing "description" "command" "result" "infile" "stdin"
 testing 'awk negative field access' \
        'awk 2>&1 -- '\''{ $(-1) }'\' \
-- 
2.29.2

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to