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