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