7d06d6e186
A refactor of the awk printf code in
e2e3802987
appears to have broken the printf interpretation of two percent signs,
which normally outputs only one percent sign.
The patch below brings busybox awk printf behavior back into alignment
with the pre-e2e380 behavior, the busybox printf util, and other common
(awk and non-awk) printf implementations.
function old new delta
awk_printf 626 672 +46
Signed-off-by: Daniel Thau <danthau at bedrocklinux.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
473 lines
10 KiB
Bash
Executable File
473 lines
10 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# Copyright 2007 by Denys Vlasenko <vda.linux@googlemail.com>
|
|
# Licensed under GPLv2, see file LICENSE in this source tree.
|
|
|
|
. ./testing.sh
|
|
|
|
# testing "description" "command" "result" "infile" "stdin"
|
|
|
|
testing "awk -F case 0" "awk -F '[#]' '{ print NF }'" "" "" ""
|
|
testing "awk -F case 1" "awk -F '[#]' '{ print NF }'" "0\n" "" "\n"
|
|
testing "awk -F case 2" "awk -F '[#]' '{ print NF }'" "2\n" "" "#\n"
|
|
testing "awk -F case 3" "awk -F '[#]' '{ print NF }'" "3\n" "" "#abc#\n"
|
|
testing "awk -F case 4" "awk -F '[#]' '{ print NF }'" "3\n" "" "#abc#zz\n"
|
|
testing "awk -F case 5" "awk -F '[#]' '{ print NF }'" "4\n" "" "#abc##zz\n"
|
|
testing "awk -F case 6" "awk -F '[#]' '{ print NF }'" "4\n" "" "z#abc##zz\n"
|
|
testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n"
|
|
|
|
# conditions and operators
|
|
testing "awk if operator == " "awk 'BEGIN{if(23==23) print \"foo\"}'" "foo\n" "" ""
|
|
testing "awk if operator != " "awk 'BEGIN{if(23!=23) print \"bar\"}'" "" "" ""
|
|
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\"}'" "" "" ""
|
|
|
|
# 4294967295 = 0xffffffff
|
|
testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4294967295\n" "" "\n"
|
|
|
|
# we were testing for a non-empty body when deciding if a function was
|
|
# defined or not. The testcase below caused:
|
|
# awk: cmd. line:8: Call to undefined function
|
|
prg='
|
|
function empty_fun(count) {
|
|
# empty
|
|
}
|
|
END {
|
|
i=1
|
|
print "L" i "\n"
|
|
empty_fun(i + i + ++i)
|
|
print "L" i "\n"
|
|
}'
|
|
testing "awk handles empty function f(arg){}" \
|
|
"awk '$prg'" \
|
|
"L1\n\nL2\n\n" \
|
|
"" ""
|
|
|
|
prg='
|
|
function empty_fun(){}
|
|
END {empty_fun()
|
|
print "Ok"
|
|
}'
|
|
testing "awk handles empty function f(){}" \
|
|
"awk '$prg'" \
|
|
"Ok\n" \
|
|
"" ""
|
|
|
|
prg='
|
|
function outer_fun() {
|
|
return 1
|
|
}
|
|
END {
|
|
i=1
|
|
print "L" i "\n"
|
|
i += outer_fun()
|
|
print "L" i "\n"
|
|
}'
|
|
testing "awk properly handles function from other scope" \
|
|
"awk '$prg'" \
|
|
"L1\n\nL2\n\n" \
|
|
"" ""
|
|
|
|
prg='
|
|
END {
|
|
i=1
|
|
print "L" i "\n"
|
|
i + trigger_error_fun()
|
|
print "L" i "\n"
|
|
}'
|
|
testing "awk properly handles undefined function" \
|
|
"awk '$prg' 2>&1" \
|
|
"L1\n\nawk: cmd. line:5: Call to undefined function\n" \
|
|
"" ""
|
|
|
|
prg='
|
|
BEGIN {
|
|
v=1
|
|
a=2
|
|
print v (a)
|
|
}'
|
|
testing "awk 'v (a)' is not a function call, it is a concatenation" \
|
|
"awk '$prg' 2>&1" \
|
|
"12\n" \
|
|
"" ""
|
|
|
|
prg='func f(){print"F"};func g(){print"G"};BEGIN{f(g(),g())}'
|
|
testing "awk unused function args are evaluated" \
|
|
"awk '$prg' 2>&1" \
|
|
"G\nG\nF\n" \
|
|
"" ""
|
|
|
|
|
|
optional DESKTOP
|
|
testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4294967295\n" "" "\n"
|
|
testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2147483649\n" "" "\n"
|
|
testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n"
|
|
SKIP=
|
|
|
|
# check that "hex/oct integer" heuristic doesn't kick in on 00NN.NNN
|
|
testing "awk floating const with leading zeroes" \
|
|
"awk '{ printf \"%f %f\n\", \"000.123\", \"009.123\" }'" \
|
|
"0.123000 9.123000\n" \
|
|
"" "\n"
|
|
|
|
# long field seps requiring regex
|
|
testing "awk long field sep" \
|
|
"awk -F-- '{ print NF, length(\$NF), \$NF }'" \
|
|
"2 0 \n3 0 \n4 0 \n5 0 \n" \
|
|
"" \
|
|
"a--\na--b--\na--b--c--\na--b--c--d--"
|
|
|
|
testing "awk -F handles escapes" "awk -F'\\x21' '{print \$1}'" \
|
|
"a\n" \
|
|
"" \
|
|
"a!b\n"
|
|
|
|
# '@(samp|code|file)\{' is an invalid extended regex (unmatched '{'),
|
|
# but gawk 3.1.5 does not bail out on it.
|
|
testing "awk gsub falls back to non-extended-regex" \
|
|
"awk 'gsub(\"@(samp|code|file)\{\",\"\");'; echo \$?" "0\n" "" "Hi\n"
|
|
|
|
optional TAR BUNZIP2 FEATURE_SEAMLESS_BZ2
|
|
test x"$SKIP" != x"1" && tar xjf awk_t1.tar.bz2
|
|
testing "awk 'gcc build bug'" \
|
|
"awk -f awk_t1_opt-functions.awk -f awk_t1_opth-gen.awk <awk_t1_input | md5sum" \
|
|
"f842e256461a5ab1ec60b58d16f1114f -\n" \
|
|
"" ""
|
|
rm -rf awk_t1_* 2>/dev/null
|
|
SKIP=
|
|
|
|
Q='":"'
|
|
|
|
testing "awk NF in BEGIN" \
|
|
"awk 'BEGIN { print ${Q} NF ${Q} \$0 ${Q} \$1 ${Q} \$2 ${Q} }'" \
|
|
":0::::\n" \
|
|
"" ""
|
|
|
|
prg='
|
|
function b(tmp) {
|
|
tmp = 0;
|
|
print "" tmp; #this line causes the bug
|
|
return tmp;
|
|
}
|
|
function c(tmpc) {
|
|
tmpc = b(); return tmpc;
|
|
}
|
|
BEGIN {
|
|
print (c() ? "string" : "number");
|
|
}'
|
|
testing "awk string cast (bug 725)" \
|
|
"awk '$prg'" \
|
|
"0\nnumber\n" \
|
|
"" ""
|
|
|
|
testing "awk handles whitespace before array subscript" \
|
|
"awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" ""
|
|
|
|
# GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2",
|
|
# do we need to emulate that as well?
|
|
testing "awk handles non-existing file correctly" \
|
|
"awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \
|
|
"2\n0\nOk\n" "" ""
|
|
|
|
prg='
|
|
BEGIN {
|
|
u["a"]=1
|
|
u["b"]=1
|
|
u["c"]=1
|
|
v["d"]=1
|
|
v["e"]=1
|
|
v["f"]=1
|
|
for (l in u) {
|
|
print "outer1", l;
|
|
for (l in v) {
|
|
print " inner", l;
|
|
}
|
|
print "outer2", l;
|
|
}
|
|
print "end", l;
|
|
l="a"
|
|
exit;
|
|
}'
|
|
testing "awk nested loops with the same variable" \
|
|
"awk '$prg'" \
|
|
"\
|
|
outer1 a
|
|
inner d
|
|
inner e
|
|
inner f
|
|
outer2 f
|
|
outer1 b
|
|
inner d
|
|
inner e
|
|
inner f
|
|
outer2 f
|
|
outer1 c
|
|
inner d
|
|
inner e
|
|
inner f
|
|
outer2 f
|
|
end f
|
|
" \
|
|
"" ""
|
|
|
|
prg='
|
|
BEGIN {
|
|
u["a"]=1
|
|
u["b"]=1
|
|
u["c"]=1
|
|
v["d"]=1
|
|
v["e"]=1
|
|
v["f"]=1
|
|
for (l in u) {
|
|
print "outer1", l;
|
|
for (l in v) {
|
|
print " inner", l;
|
|
break;
|
|
}
|
|
print "outer2", l;
|
|
}
|
|
print "end", l;
|
|
l="a"
|
|
exit;
|
|
}'
|
|
# It's not just buggy, it enters infinite loop. Thus disabled
|
|
false && test x"$SKIP_KNOWN_BUGS" = x"" && testing "awk nested loops with the same variable and break" \
|
|
"awk '$prg'" \
|
|
"\
|
|
outer1 a
|
|
inner d
|
|
outer2 d
|
|
outer1 b
|
|
inner d
|
|
outer2 d
|
|
outer1 c
|
|
inner d
|
|
outer2 d
|
|
end d
|
|
" \
|
|
"" ""
|
|
|
|
prg='
|
|
function f() {
|
|
for (l in v) {
|
|
print " inner", l;
|
|
return;
|
|
}
|
|
}
|
|
|
|
BEGIN {
|
|
u["a"]=1
|
|
u["b"]=1
|
|
u["c"]=1
|
|
v["d"]=1
|
|
v["e"]=1
|
|
v["f"]=1
|
|
for (l in u) {
|
|
print "outer1", l;
|
|
f();
|
|
print "outer2", l;
|
|
}
|
|
print "end", l;
|
|
l="a"
|
|
exit;
|
|
}'
|
|
# It's not just buggy, it enters infinite loop. Thus disabled
|
|
false && test x"$SKIP_KNOWN_BUGS" = x"" && testing "awk nested loops with the same variable and return" \
|
|
"awk '$prg'" \
|
|
"\
|
|
outer1 a
|
|
inner d
|
|
outer2 d
|
|
outer1 b
|
|
inner d
|
|
outer2 d
|
|
outer1 c
|
|
inner d
|
|
outer2 d
|
|
end d
|
|
" \
|
|
"" ""
|
|
|
|
prg='
|
|
BEGIN{
|
|
cnt = 0
|
|
a[cnt] = "zeroth"
|
|
a[++cnt] = "first"
|
|
delete a[cnt--]
|
|
print cnt
|
|
print "[0]:" a[0]
|
|
print "[1]:" a[1]
|
|
}'
|
|
testing "awk 'delete a[v--]' evaluates v-- once" \
|
|
"awk '$prg'" \
|
|
"\
|
|
0
|
|
[0]:zeroth
|
|
[1]:
|
|
" \
|
|
"" ""
|
|
|
|
testing "awk func arg parsing 1" \
|
|
"awk 'func f(,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
|
|
|
|
testing "awk func arg parsing 2" \
|
|
"awk 'func f(a,,b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
|
|
|
|
testing "awk func arg parsing 3" \
|
|
"awk 'func f(a,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
|
|
|
|
testing "awk func arg parsing 4" \
|
|
"awk 'func f(a b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
|
|
|
|
testing "awk handles empty ()" \
|
|
"awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""
|
|
|
|
testing "awk FS assignment" "awk '{FS=\":\"; print \$1}'" \
|
|
"a:b\ne\n" \
|
|
"" \
|
|
"a:b c:d\ne:f g:h"
|
|
|
|
optional FEATURE_AWK_LIBM
|
|
testing "awk large integer" \
|
|
"awk 'BEGIN{n=(2^31)-1; print n, int(n), n%1, ++n, int(n), n%1}'" \
|
|
"2147483647 2147483647 0 2147483648 2147483648 0\n" \
|
|
"" ""
|
|
SKIP=
|
|
|
|
testing "awk length(array)" \
|
|
"awk 'BEGIN{ A[1]=2; A[\"qwe\"]=\"asd\"; print length(A)}'" \
|
|
"2\n" \
|
|
"" ""
|
|
|
|
testing "awk length()" \
|
|
"awk '{print length; print length(); print length(\"qwe\"); print length(99+9)}'" \
|
|
"3\n3\n3\n3\n" \
|
|
"" "qwe"
|
|
|
|
testing "awk print length, 1" \
|
|
"awk '{ print length, 1 }'" \
|
|
"0 1\n" \
|
|
"" "\n"
|
|
|
|
testing "awk print length 1" \
|
|
"awk '{ print length 1 }'" \
|
|
"01\n" \
|
|
"" "\n"
|
|
|
|
testing "awk length == 0" \
|
|
"awk 'length == 0 { print \"foo\" }'" \
|
|
"foo\n" \
|
|
"" "\n"
|
|
|
|
testing "awk if (length == 0)" \
|
|
"awk '{ if (length == 0) { print \"bar\" } }'" \
|
|
"bar\n" \
|
|
"" "\n"
|
|
|
|
testing "awk -f and ARGC" \
|
|
"awk -f - input" \
|
|
"re\n2\n" \
|
|
"do re mi\n" \
|
|
'{print $2; print ARGC;}' \
|
|
|
|
optional FEATURE_AWK_GNU_EXTENSIONS
|
|
testing "awk -e and ARGC" \
|
|
"awk -e '{print \$2; print ARGC;}' input" \
|
|
"re\n2\n" \
|
|
"do re mi\n" \
|
|
""
|
|
SKIP=
|
|
|
|
testing "awk break" \
|
|
"awk -f - 2>&1; echo \$?" \
|
|
"awk: -:1: 'break' not in a loop\n1\n" \
|
|
"" \
|
|
'BEGIN { if (1) break; else a = 1 }'
|
|
testing "awk continue" \
|
|
"awk -f - 2>&1; echo \$?" \
|
|
"awk: -:1: 'continue' not in a loop\n1\n" \
|
|
"" \
|
|
'BEGIN { if (1) continue; else a = 1 }'
|
|
|
|
optional FEATURE_AWK_GNU_EXTENSIONS
|
|
testing "awk handles invalid for loop" \
|
|
"awk -e '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
|
|
SKIP=
|
|
|
|
optional FEATURE_AWK_GNU_EXTENSIONS
|
|
testing "awk handles colon not preceded by ternary" \
|
|
"awk -e foo:bar: 2>&1" "awk: cmd. line:1: Unexpected token\n" "" ""
|
|
SKIP=
|
|
|
|
optional FEATURE_AWK_GNU_EXTENSIONS
|
|
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=
|
|
|
|
optional FEATURE_AWK_GNU_EXTENSIONS DESKTOP
|
|
testing "awk printf('%-10c') can output NUL" \
|
|
"awk 'BEGIN { printf \"[%-10c]\n\", 0 }' | od -tx1" "\
|
|
0000000 5b 00 20 20 20 20 20 20 20 20 20 5d 0a
|
|
0000015
|
|
" "" ""
|
|
SKIP=
|
|
|
|
# testing "description" "command" "result" "infile" "stdin"
|
|
testing 'awk negative field access' \
|
|
'awk 2>&1 -- '\''{ $(-1) }'\' \
|
|
"awk: cmd. line:1: Access to negative field\n" \
|
|
'' \
|
|
'anything'
|
|
|
|
# was misinterpreted as (("str"++) i) instead of ("str" (++i))
|
|
# (and was executed: "str"++ is "0", thus concatenating "0" and "1"):
|
|
testing 'awk do not allow "str"++' \
|
|
'awk -v i=1 "BEGIN {print \"str\" ++i}"' \
|
|
"str2\n" \
|
|
'' \
|
|
'anything'
|
|
|
|
# gawk compat: FS regex matches only non-empty separators:
|
|
# with -*, the splitting is NOT f o o b a r, but foo bar:
|
|
testing 'awk FS regex which can match empty string' \
|
|
"awk -F '-*' '{print \$1 \"-\" \$2 \"=\" \$3 \"*\" \$4}'" \
|
|
"foo-bar=*\n" \
|
|
'' \
|
|
'foo--bar'
|
|
|
|
# last+1 field should be empty (had a bug where it wasn't)
|
|
testing 'awk $NF is empty' \
|
|
"awk -F '=+' '{print \$NF}'" \
|
|
"\n" \
|
|
'' \
|
|
'a=====123='
|
|
|
|
testing "awk exit N propagates through END's exit" \
|
|
"awk 'BEGIN { exit 42 } END { exit }'; echo \$?" \
|
|
"42\n" \
|
|
'' ''
|
|
|
|
testing "awk print + redirect" \
|
|
"awk 'BEGIN { print \"STDERR %s\" >\"/dev/stderr\" }' 2>&1" \
|
|
"STDERR %s\n" \
|
|
'' ''
|
|
|
|
testing "awk \"cmd\" | getline" \
|
|
"awk 'BEGIN { \"echo HELLO\" | getline; print }'" \
|
|
"HELLO\n" \
|
|
'' ''
|
|
|
|
# printf %% should print one % (had a bug where it didn't)
|
|
testing 'awk printf %% prints one %' \
|
|
"awk 'BEGIN { printf \"%%\n\" }'" \
|
|
"%\n" \
|
|
'' ''
|
|
|
|
exit $FAILCOUNT
|