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