[PATCH] awk: add '*' as a valid specifier for width and precision in printf
Anubhav Kokane via busybox <[email protected]> Thu, 25 Jun 2026 11:38:59 +0000
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <[email protected]> |
Implemented by replacing '*' with the actual values of width and precision from the argument list of awk printf in a dynamically allocated string. This updated format string is passed to the calls of xasprintf. Signed-off-by: Anubhav Kokane <[email protected]> --- editors/awk.c | 32 ++++++++++++++++++++++++++++++-- testsuite/awk.tests | 22 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index dd8f4ac42..07dff234a 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -2423,6 +2423,7 @@ static char *awk_printf(node *n, size_t *len) char *b; char *fmt, *f; size_t i; + char *allocated; //tmpvar = nvalloc(1); #define TMPVAR (&G.awk_printf__tmpvar) @@ -2437,6 +2438,7 @@ static char *awk_printf(node *n, size_t *len) b = NULL; i = 0; + allocated = NULL; while (1) { /* "print one format spec" loop */ char *s; char c; @@ -2467,8 +2469,33 @@ static char *awk_printf(node *n, size_t *len) while (1) { if (isalpha(c)) break; - if (c == '*') /* gawk supports %*d and %*.*f, we don't... */ - syntax_error("%*x formats are not supported"); + if (c == '*') { + char *temp; + char num_s[12]; + int num; + size_t prefix_len; + size_t suffix_len; + size_t num_len; + + num = (int)getvar_i(evaluate(nextarg(&n), TMPVAR)); + sprintf(num_s, "%d", num); + + num_len = strlen(num_s); + prefix_len = f - s; + suffix_len = strlen(f + 1); + + temp = xmalloc(prefix_len + suffix_len + num_len + 1); + memcpy(temp, s, prefix_len); + memcpy(temp + prefix_len, num_s, num_len); + strcpy(temp + prefix_len + num_len, f + 1); + + if (allocated) + free(allocated); + + s = temp; + allocated = s; + f = s + prefix_len + num_len - 1; + } c = *++f; if (!c) { /* "....%...." and no letter found after % */ /* Example: awk 'BEGIN { printf "^^^%^^^\n"; }' */ @@ -2533,6 +2560,7 @@ static char *awk_printf(node *n, size_t *len) } free(fmt); + free(allocated); //nvfree(tmpvar, 1); #undef TMPVAR diff --git a/testsuite/awk.tests b/testsuite/awk.tests index df1078bdb..76eb0f920 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -24,6 +24,28 @@ testing "awk if operator >= " "awk 'BEGIN{if(23>=23) print \"foo\"}'" "foo\n" " testing "awk if operator < " "awk 'BEGIN{if(2 < 13) print \"foo\"}'" "foo\n" "" "" testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" "" "" +# width and precision +testing "awk only width" \ +"awk 'BEGIN { printf \"%*d\", 10, -42 }'" " -42" "" "" + +testing "awk negative width" \ +"awk 'BEGIN { printf \"%*s\", -10, \"hello\" }'" "hello " "" "" + +testing "awk only precision" \ +"awk 'BEGIN { printf \"%.*f\n\", 2, 3.14159 }'" "3.14\n" "" "" + +testing "awk width and precision" \ +"awk 'BEGIN { printf \"%*.*f\", 10, 2, 3.14159 }'" " 3.14" "" "" + +testing "awk 0 padding with width and precision" \ +"awk 'BEGIN { printf \"%0*.*f\", 10, 2, 3.14 }'" "0000003.14" "" "" + +testing "awk multiple format specifications" \ +"awk 'BEGIN { printf \"%d %*d %d\", 1, 5, 2, 3 }'" "1 2 3" "" "" + +testing "awk width with char" \ +"awk 'BEGIN { printf \"%*c\", 5, 65 }'" " A" "" "" + # 4294967295 = 0xffffffff testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4294967295\n" "" "\n" -- 2.43.0