1#!/bin/bash 2 3if [[ -z "$AWK" || -z "$WORKDIR" ]]; then 4 printf '$AWK and $WORKDIR must be set\n' >&2 5 exit 1 6fi 7 8TEMP0=$WORKDIR/test.temp.0 9TEMP1=$WORKDIR/test.temp.1 10TEMP2=$WORKDIR/test.temp.2 11TEMP3=$WORKDIR/test.temp.3 12 13RESULT=0 14 15fail() { 16 echo "$1" >&2 17 RESULT=1 18} 19 20echo T.misc: miscellaneous buglets now watched for 21 22rm -f core 23 24echo 'The big brown over the lazy doe 25The big brown over the lazy dog 26x 27The big brown over the lazy dog' > $TEMP0 28echo 'failed 29succeeded 30failed 31succeeded' > $TEMP1 32$AWK '{ if (match($0, /^The big brown over the lazy dog/) == 0) { 33 printf("failed\n") 34 } else { 35 printf("succeeded\n") 36 } 37} ' $TEMP0 > $TEMP2 38cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc ghosh RE bug' 39 40echo '123 411234567890 4212345678901' > $TEMP0 43echo '12345678901' > $TEMP1 44$AWK 'length($0) > 10' $TEMP0 > $TEMP2 45cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc last number bug' 46 47# check some \ sequences in strings (ascii) 48echo HIJKL > $TEMP1 49echo $TEMP0 | $AWK '{ print "H\x49\x4a\x4BL" }' > $TEMP2 50cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc hex string cvt' 51 52echo 012x45 > $TEMP1 53$AWK 'BEGIN { print "0\061\62x\0645" }' > $TEMP2 54cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc oct string cvt' 55 56# $i++ means ($i)++ 57echo 3 5 | $AWK '{ i = 1; print $i++ ; print $1, i }' > $TEMP1 58echo '3 594 1' > $TEMP2 60cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc bad field increment' 61 62# makes sure that fields are recomputed even if self-assignment 63# take into account that subtracting from NF now rebuilds the record 64echo 'a b c 65s p q r 66x y z' > $TEMP0 67echo 'a 68s p 69x' > $TEMP1 70$AWK '{ NF -= 2; $1 = $1; print }' < $TEMP0 > $TEMP2 71diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad field self-assignment" 72 73echo '1 741' > $TEMP1 75$AWK 'BEGIN {x = 1; print x; x = x; print x}' > $TEMP2 76diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad self-assignment" 77 78echo 573109312 | $AWK '{print $1*4}' > $TEMP1 79echo 2292437248 > $TEMP2 80diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad overflow" 81 82# note that there are 8-bit characters in the echo 83# some shells will probably screw this up. 84echo '# 85code 1 86code 2' | 87$AWK '/^#/' > $TEMP1 88echo '#' > $TEMP2 89diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad match of 8-bit char" 90 91echo hello | 92$AWK 'BEGIN { FILENAME = "/etc/passwd" } 93 { print $0 }' >/dev/null 94if [[ $? -eq 139 ]]; then fail "BAD: T.misc /etc/passwd dropped core"; fi 95 96echo hello | 97$AWK ' function foo(foo) { 98 foo = 1 99 foo() 100 } 101 { foo(bar) } 102' >/dev/null 2>&1 103if [[ $? -eq 139 ]]; then 104 fail "BAD: T.misc function foo(foo) dropped core" 105 rm -f core 106fi 107 108echo '2 10910' | 110$AWK '{ x[NR] = $0 } # test whether $0 is NUM as well as STR 111END { if (x[1] > x[2]) print "BAD: T.misc: $0 is not NUM" }' 112 113 114$AWK 'BEGIN { 115 npad = substr("alexander" " ",1,15) 116 print npad 117 }' > $TEMP0 118grep '\\' $TEMP0 && fail "BAD: T.misc alexander fails" 119 120# This should give an error about function arguments 121$AWK ' 122function foo(x) { print "x is" x } 123BEGIN { foo(foo) } 124' 2> $TEMP0 125grep "can't use function foo" $TEMP0 >/dev/null || fail "BAD: T.misc fcn args" 126 127 128# gawk defref test; should give error about undefined function 129$AWK 'BEGIN { foo() }' 2> $TEMP0 130grep "calling undefined function foo" $TEMP0 >/dev/null || fail "BAD: T.misc undefined function" 131 132 133# gawk arrayparm test; should give error about function 134$AWK ' 135BEGIN { 136 foo[1]=1; 137 foo[2]=2; 138 bug1(foo); 139} 140function bug1(i) { 141 for (i in foo) { 142 bug2(i); 143 delete foo[i]; 144 print i,1,bot[1]; 145 } 146} 147function bug2(arg) { 148 bot[arg]=arg; 149} 150' 2> $TEMP0 151grep "can.t assign to foo" $TEMP0 >/dev/null || fail "BAD: T.misc foo bug" 152 153 154# This should be a syntax error 155$AWK ' 156!x = y 157' 2> $TEMP0 158grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error !x=y fails" 159 160# This should print bbb 161$AWK ' 162BEGIN { up[1] = "a" 163 for (i in up) gsub("a", "A", x) 164 print x x "bbb" 165 exit 166 } 167' > $TEMP0 168grep bbb $TEMP0 >/dev/null || fail "BAD: T.misc gsub failed" 169 170echo yes | 171$AWK ' 172BEGIN { 173 printf "push return" >"/dev/null" 174 getline ans <"/dev/null" 175} ' 176if [[ $? -eq 139 ]]; then fail "BAD: T.misc getline ans dropped core"; fi 177 178$AWK 'BEGIN { unireghf() } 179function unireghf(hfeed) { hfeed[1] = 0 }' 180if [[ $? -eq 139 ]]; then fail "BAD: T.misc unireghf dropped core"; fi 181 182echo x | $AWK '/[/]/' 2> $TEMP0 183grep 'nonterminated character class' $TEMP0 >/dev/null || error 'BAD: T.misc nonterminated fails' 184if [[ $? -eq 139 ]]; then fail "BAD: T.misc nonterminated dropped core"; fi 185 186$AWK ' 187function f() { return 12345 } 188BEGIN { printf "<%s>\n", f() } 189' > $TEMP0 190grep '<12345>' $TEMP0 >/dev/null || fail 'BAD: T.misc <12345> fails' 191 192echo 'abc 193def 194 195ghi 196jkl' > $TEMP0 197$AWK ' 198BEGIN { RS = "" 199 while (getline <"'$TEMP0'") 200 print 201}' > $TEMP1 202$AWK 'END {print NR}' $TEMP1 | grep 4 >/dev/null || fail 'BAD: T.misc abcdef fails' 203 204 205# The following should not produce a warning about changing a constant 206# nor about a curdled tempcell list 207$AWK 'function f(x) { x = 2 } 208BEGIN { f(1) }' > $TEMP0 209grep '^' $TEMP0 && fail 'BAD: test constant change fails' 210 211# The following should not produce a warning about a curdled tempcell list 212$AWK 'function f(x) { x } 213BEGIN { f(1) }' > $TEMP0 214grep '^' $TEMP0 && fail 'BAD: test tempcell list fails' 215 216$AWK 'BEGIN { print 9, a=10, 11; print a; exit }' > $TEMP1 217echo '9 10 11 21810' > $TEMP2 219diff $TEMP1 $TEMP2 || fail 'BAD: T.misc (embedded expression)' 220 221echo "abc defgh ijkl" | $AWK ' 222 { $1 = ""; line = $0; print line; print $0; $0 = line; print $0 }' > $TEMP1 223echo " defgh ijkl 224 defgh ijkl 225 defgh ijkl" > $TEMP2 226diff $TEMP1 $TEMP2 || fail 'BAD: T.misc (assignment to $0)' 227 228$AWK ' 229function min(a, b) 230{ 231 if (a < b) 232 return a 233 else 234 return b 235} 236BEGIN { exit } 237' 238if [[ $? -eq 139 ]]; then fail "BAD: T.misc function min dropped core"; fi 239 240# The following should not give a syntax error message: 241$AWK ' 242function expand(chart) { 243 getline chart < "CHAR.ticks" 244} 245' > $TEMP0 246grep '^' $TEMP0 >/dev/null && fail 'BAD: T.misc expand error' 247 248$AWK 'BEGIN { print 1e40 }' >/dev/null 249if [[ $? -eq 139 ]]; then fail "BAD: T.misc 1E40 dropped core"; fi 250 251# The following syntax error should not dump core: 252$AWK ' 253$NF==3 {first=1} 254$NF==2 && first==0 && (abs($1-o1)>120||abs($2-o2)>120) {print $0} 255$NF==2 {o1=%1; o2=$2; first=0} 256' 2>/dev/null 257if [[ $? -eq 139 ]]; then fail "BAD: T.misc first/abs dropped core"; fi 258 259# The following syntax error should not dump core: 260$AWK '{ n = split($1, address, !); print address[1] }' 2> $TEMP0 261grep 'illegal statement' $TEMP0 >/dev/null || fail 'BAD: T.misc split error' 262if [[ $? -eq 139 ]]; then fail "BAD: T.misc split! dropped core"; fi 263 264# The following should cause a syntax error message 265$AWK 'BEGIN {"hello"}' 2> $TEMP0 266grep 'illegal statement' $TEMP0 >/dev/null || fail 'BAD: T.misc hello error' 267 268# The following should give a syntax error message: 269$AWK ' 270function pile(c, r) { 271 r = ++pile[c] 272} 273 274{ pile($1) } 275' 2> $TEMP0 276grep 'context is' $TEMP0 >/dev/null || fail 'BAD: T.misc pile error' 277 278# This should complain about missing atan2 argument: 279$AWK 'BEGIN { atan2(1) }' 2> $TEMP0 280grep 'requires two arg' $TEMP0 >/dev/null || fail 'BAD: T.misc atan2 error' 281 282# This should not core dump: 283$AWK 'BEGIN { f() } 284function f(A) { delete A[1] } 285' 286if [[ $? -eq 139 ]]; then fail "BAD: T.misc delete dropped core"; fi 287 288# nasty one: should not be able to overwrite constants 289$AWK 'BEGIN { gsub(/ana/,"anda","banana") 290 printf "the monkey ate a %s\n", "banana" } 291' >/dev/null 2> $TEMP0 292grep 'syntax error' $TEMP0 >/dev/null || fail 'BAD: T.misc gsub banana error' 293 294# nasty one: should not be able to overwrite constants 295$AWK 'BEGIN { sub(/ana/,"anda","banana") 296 printf "the monkey ate a %s\n", "banana" } 297' >/dev/null 2> $TEMP0 298grep 'syntax error' $TEMP0 >/dev/null || fail 'BAD: T.misc sub banana error' 299 300# line numbers used to double-count comments 301$AWK '# 302# 303# 304/x 305' >/dev/null 2> $TEMP0 306grep 'line [45]' $TEMP0 >/dev/null || fail 'BAD: T.misc lineno' 307 308echo 'x 309\y' > $TEMP1 310$AWK 'BEGIN { print "x\f\r\b\v\a\\y" }' > $TEMP2 311cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc weird chars' 312 313echo 0 > $TEMP1 314$AWK ' BEGIN { exit } 315 { print } 316 END { print NR }' > $TEMP2 317cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc BEGIN exit' 318 319echo 1 > $TEMP1 320$AWK ' { exit } 321 END { print NR }' /etc/passwd > $TEMP2 322cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit' 323 324echo 1 > $TEMP1 325$AWK ' {i = 1; while (i <= NF) {if (i == NF) exit; i++ } } 326 END { print NR }' /etc/passwd > $TEMP2 327cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 2' 328 329echo 1 > $TEMP1 330$AWK ' function f() { 331 i = 1; while (i <= NF) {if (i == NF) return NR; i++ } 332 } 333 { if (f() == 1) exit } 334 END { print NR }' /etc/passwd > $TEMP2 335cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc while return' 336 337echo 1 > $TEMP1 338$AWK ' function f() { 339 split("a b c", arr) 340 for (i in arr) {if (i == 3) return NR; i++ } 341 } 342 { if (f() == 1) exit } 343 END { print NR }' /etc/passwd > $TEMP2 344cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc while return' 345 346echo 1 > $TEMP1 347$AWK ' {i = 1; do { if (i == NF) exit; i++ } while (i <= NF) } 348 END { print NR }' /etc/passwd > $TEMP2 349cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 3' 350 351echo 1 > $TEMP1 352$AWK ' function f() { 353 i = 1; do { if (i == NF) return NR; i++ } while (i <= NF) 354 } 355 { if (f() == 1) exit } 356 END { print NR }' /etc/passwd > $TEMP2 357cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc do return' 358 359echo 1 > $TEMP1 360$AWK ' {i = 1; do { if (i == NF) break; i++ } while (i <= NF); exit } 361 END { print NR }' /etc/passwd > $TEMP2 362cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 4' 363 364echo 1 > $TEMP1 365$AWK ' { n = split($0, x) 366 for (i in x) { 367 if (i == 1) 368 exit } } 369 END { print NR }' /etc/passwd > $TEMP2 370cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 5' 371 372echo XXXXXXXX > $TEMP1 373$AWK 'BEGIN { s = "ab\fc\rd\be" 374 t = s; gsub("[" s "]", "X", t); print t }' > $TEMP2 375cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc weird escapes in char class' 376 377$AWK '{}' /etc/passwd glop/glop > $TEMP0 2> $TEMP2 378grep "can't open.*glop" $TEMP2 >/dev/null || fail "BAD: T.misc can't open" 379 380echo ' 381 382 383a 384aa 385 386b 387 388 389c 390 391' > $TEMP0 392echo 3 > $TEMP1 393$AWK 'BEGIN { RS = "" }; END { print NR }' $TEMP0 > $TEMP2 394cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc RS botch' 395 396$AWK 'BEGIN \ 397 { 398 print "hello, world" 399 } 400}}}' > $TEMP1 2> $TEMP2 401grep 'source line 5' $TEMP2 >/dev/null 2>&1 || fail 'BAD: T.misc continuation line number' 402 403 404echo 111 222 333 > $TEMP0 405$AWK '{ f[1]=1; f[2]=2; print $f[1], $f[1]++, $f[2], f[1], f[2] }' $TEMP0 > $TEMP2 406echo 111 111 222 2 2 > $TEMP1 407cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc $f[1]++' 408 409 410# These should be syntax errors 411$AWK . 2> $TEMP0 412grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error . fails" 413 414$AWK .. 2> $TEMP0 415grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .. fails" 416 417$AWK .E. 2> $TEMP0 418grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .E. fails" 419 420$AWK .++. 2> $TEMP0 421grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .++. fails" 422 423 424 425# These should be syntax errors 426$AWK '$' 2> $TEMP0 427grep "unexpected" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error $ fails" 428 429$AWK '{print $' 2> $TEMP0 430grep "unexpected" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error \$2 fails" 431 432$AWK '"' 2> $TEMP0 433grep "non-terminated" $TEMP0 >/dev/null || fail "BAD: T.misc bare quote fails" 434 435 436# %c of 0 is explicit null byte 437 438echo '3' > $TEMP1 439$AWK 'BEGIN {printf("%c%c\n", 0, 0) }' | wc | $AWK '{print $3}' > $TEMP2 440cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc null byte' 441 442# non-terminated RE 443 444$AWK /xyz > $TEMP0 2>&1 445grep "non-terminated" $TEMP0 >/dev/null || fail "BAD: T.misc non-terminated RE" 446 447# next several were infinite loops, found by brian tsang. 448# this is his example: 449 450$AWK 'BEGIN { 451 switch (substr("x",1,1)) { 452 case /ask.com/: 453 break 454 case "google": 455 break 456 } 457}' > $TEMP0 2>&1 458grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 1" 459 460$AWK 'BEGIN { s { c /./ } }' > $TEMP0 2>&1 461grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 2" 462 463$AWK 'BEGIN { s { c /../ } }' > $TEMP0 2>&1 464grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 3" 465 466$AWK 'BEGIN {printf "%2$s %1$s\n", "a", "b"}' >$TEMP0 2>&1 467grep "'$' not permitted in awk formats" $TEMP0 >/dev/null || fail "BAD: T.misc '$' not permitted in formats" 468 469echo 'a 470b c 471de fg hi' > $TEMP0 472$AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1 473awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2 474cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0' 475 476echo 'fg hi' > $TEMP0 477$AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1 478awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2 479cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0' 480 481echo '' > $TEMP0 482$AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1 483awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2 484cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0' 485 486 487LC_NUMERIC=ru_RU.ISO8859-5 $AWK 'BEGIN { 488 "echo 1,200" | getline; 489 if ($1 == 1.2) { 490 printf "good "; 491 } else { 492 printf "bad "; 493 } 494 n = 2.3; 495 print ($1 + 0.1), (n + 0.1); 496}' > $TEMP1 497echo 'good 1,3 2,4' > $TEMP2 498diff $TEMP1 $TEMP2 || fail 'BAD: T.misc LC_NUMERIC should change radix' 499 500$AWK 'function foo(q) { 501 return (q = q); 502} 503BEGIN { print foo("h"); }' > $TEMP1 504echo 'h' > $TEMP2 505diff $TEMP1 $TEMP2 || fail 'BAD: T.misc return tempcell' 506 507$AWK -v RECSIZE=8192 'BEGIN { 508 for (c = 0; c < 3; c++) { 509 a = (RECSIZE % 2 > 0 ? "5" : "55"); 510 while (length(a) < RECSIZE + c) { 511 a = a " 5"; 512 } 513 $0 = a; 514 print $2; 515 } 516}' > $TEMP1 517printf '5\n5\n5\n' > $TEMP2 518diff $TEMP1 $TEMP2 || fail 'BAD: T.misc initial fields overflow' 519 520exit $RESULT 521