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
63echo 'a b c
64s p q r
65x y' > $TEMP0
66echo 'a
67s p
68x' > $TEMP1
69$AWK '{ NF -= 2; $1 = $1; print }' < $TEMP0 > $TEMP2
70diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad field self-assignment"
71
72echo '1
731' > $TEMP1
74$AWK 'BEGIN {x = 1; print x; x = x; print x}' > $TEMP2
75diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad self-assignment"
76
77echo 573109312 | $AWK '{print $1*4}' > $TEMP1
78echo 2292437248 > $TEMP2
79diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad overflow"
80
81# note that there are 8-bit characters in the echo
82# some shells will probably screw this up.
83echo '#
84code € 1
85code € 2' |
86$AWK '/^#/' > $TEMP1
87echo '#' > $TEMP2
88diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad match of 8-bit char"
89
90echo hello |
91$AWK 'BEGIN	{ FILENAME = "/etc/passwd" }
92	{ print $0 }' >/dev/null
93if [[ $? -eq 139 ]]; then fail "BAD: T.misc /etc/passwd dropped core"; fi
94
95echo '2
9610' |
97$AWK '{ x[NR] = $0 }	# test whether $0 is NUM as well as STR
98END { if (x[1] > x[2]) print "BAD: T.misc: $0 is not NUM" }'
99
100
101$AWK 'BEGIN {
102	npad = substr("alexander" "           ",1,15)
103	print npad
104	}' > $TEMP0
105grep '\\' $TEMP0 && fail "BAD: T.misc alexander fails"
106
107# This should give an error about function arguments
108$AWK '
109function foo(x) { print "x is" x }
110BEGIN { foo(foo) }
111' 2> $TEMP0
112grep "can't use function foo" $TEMP0 >/dev/null || fail "BAD: T.misc fcn args"
113
114
115# gawk defref test; should give error about undefined function
116$AWK 'BEGIN { foo() }' 2> $TEMP0
117grep "calling undefined function foo" $TEMP0 >/dev/null || fail "BAD: T.misc undefined function"
118
119
120# gawk arrayparm test; should give error about function
121$AWK '
122BEGIN {
123    foo[1]=1;
124    foo[2]=2;
125    bug1(foo);
126}
127function bug1(i) {
128    for (i in foo) {
129	bug2(i);
130	delete foo[i];
131	print i,1,bot[1];
132    }
133}
134function bug2(arg) {
135    bot[arg]=arg;
136}
137' 2> $TEMP0
138grep "can.t assign to foo" $TEMP0 >/dev/null || fail "BAD: T.misc foo bug"
139
140
141# This should print bbb
142$AWK '
143BEGIN { up[1] = "a"
144	for (i in up) gsub("a", "A", x)
145	print x x "bbb"
146	exit
147      }
148' > $TEMP0
149grep bbb $TEMP0 >/dev/null || fail "BAD: T.misc gsub failed"
150
151echo yes |
152$AWK '
153BEGIN {
154	printf "push return" >"/dev/null"
155	getline ans <"/dev/null"
156} '
157if [[ $? -eq 139 ]]; then fail "BAD: T.misc getline ans dropped core"; fi
158
159$AWK 'BEGIN { unireghf() }
160function unireghf(hfeed) { hfeed[1] = 0 }'
161if [[ $? -eq 139 ]]; then fail "BAD: T.misc unireghf dropped core"; fi
162
163echo x | $AWK '/[/]/' 2> $TEMP0
164grep 'nonterminated character class' $TEMP0 >/dev/null || error 'BAD: T.misc nonterminated fails'
165if [[ $? -eq 139 ]]; then fail "BAD: T.misc nonterminated dropped core"; fi
166
167$AWK '
168function f() { return 12345 }
169BEGIN { printf "<%s>\n", f() }
170' > $TEMP0
171grep '<12345>' $TEMP0 >/dev/null || fail 'BAD: T.misc <12345> fails'
172
173echo 'abc
174def
175
176ghi
177jkl' > $TEMP0
178$AWK '
179BEGIN {	RS = ""
180	while (getline <"'$TEMP0'")
181		print
182}' > $TEMP1
183$AWK 'END {print NR}' $TEMP1 | grep 4 >/dev/null || fail 'BAD: T.misc abcdef fails'
184
185
186# The following should not produce a warning about changing a constant
187# nor about a curdled tempcell list
188$AWK 'function f(x) { x = 2 }
189BEGIN { f(1) }' > $TEMP0
190grep '^' $TEMP0 && fail 'BAD: test constant change fails'
191
192# The following should not produce a warning about a curdled tempcell list
193$AWK 'function f(x) { x }
194BEGIN { f(1) }' > $TEMP0
195grep '^' $TEMP0 && fail 'BAD: test tempcell list fails'
196
197$AWK 'BEGIN { print 9, a=10, 11; print a; exit }' > $TEMP1
198echo '9 10 11
19910' > $TEMP2
200diff $TEMP1 $TEMP2 || fail 'BAD: T.misc (embedded expression)'
201
202echo "abc defgh ijkl" | $AWK '
203  { $1 = ""; line = $0; print line; print $0; $0 = line; print $0 }' > $TEMP1
204echo " defgh ijkl
205 defgh ijkl
206 defgh ijkl" > $TEMP2
207diff $TEMP1 $TEMP2 || fail 'BAD: T.misc (assignment to $0)'
208
209$AWK '
210function min(a, b)
211{
212	if (a < b)
213		return a
214	else
215		return b
216}
217BEGIN { exit }
218'
219if [[ $? -eq 139 ]]; then fail "BAD: T.misc function min dropped core"; fi
220
221# The following should not give a syntax error message:
222$AWK '
223function expand(chart) {
224	getline chart < "CHAR.ticks"
225}
226' > $TEMP0
227grep '^' $TEMP0 >/dev/null && fail 'BAD: T.misc expand error'
228
229$AWK 'BEGIN { print 1e40 }' >/dev/null
230if [[ $? -eq 139 ]]; then fail "BAD: T.misc 1E40 dropped core"; fi
231
232# The following syntax error should not dump core:
233$AWK '
234$NF==3	{first=1}
235$NF==2 && first==0 && (abs($1-o1)>120||abs($2-o2)>120)	{print $0}
236$NF==2	{o1=%1; o2=$2; first=0}
237' 2>/dev/null
238if [[ $? -eq 139 ]]; then fail "BAD: T.misc first/abs dropped core"; fi
239
240# The following syntax error should not dump core:
241$AWK '{ n = split($1, address, !); print address[1] }' 2> $TEMP0
242grep 'illegal statement' $TEMP0 >/dev/null || fail 'BAD: T.misc split error'
243if [[ $? -eq 139 ]]; then fail "BAD: T.misc split! dropped core"; fi
244
245# The following should cause a syntax error message
246$AWK 'BEGIN {"hello"}' 2> $TEMP0
247grep 'illegal statement' $TEMP0 >/dev/null || fail 'BAD: T.misc hello error'
248
249# The following should give a syntax error message:
250$AWK '
251function pile(c,     r) {
252	r = ++pile[c]
253}
254
255{ pile($1) }
256' 2> $TEMP0
257grep 'context is' $TEMP0 >/dev/null || fail 'BAD: T.misc pile error'
258
259# This should complain about missing atan2 argument:
260$AWK 'BEGIN { atan2(1) }' 2> $TEMP0
261grep 'requires two arg' $TEMP0 >/dev/null || fail 'BAD: T.misc atan2 error'
262
263# This should not core dump:
264$AWK 'BEGIN { f() }
265function f(A) { delete A[1] }
266'
267if [[ $? -eq 139 ]]; then fail "BAD: T.misc delete dropped core"; fi
268
269# nasty one:  should not be able to overwrite constants
270$AWK 'BEGIN { gsub(/ana/,"anda","banana")
271		printf "the monkey ate a %s\n", "banana" }
272' >/dev/null 2> $TEMP0
273grep 'syntax error' $TEMP0 >/dev/null || fail 'BAD: T.misc gsub banana error'
274
275# nasty one:  should not be able to overwrite constants
276$AWK 'BEGIN { sub(/ana/,"anda","banana")
277		printf "the monkey ate a %s\n", "banana" }
278' >/dev/null 2> $TEMP0
279grep 'syntax error' $TEMP0 >/dev/null || fail 'BAD: T.misc sub banana error'
280
281# line numbers used to double-count comments
282$AWK '#
283#
284#
285/x
286' >/dev/null 2> $TEMP0
287grep 'line [45]' $TEMP0 >/dev/null || fail 'BAD: T.misc lineno'
288
289echo 'x
290\y' > $TEMP1
291$AWK 'BEGIN { print "x\f\r\b\v\a\\y" }' > $TEMP2
292cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc weird chars'
293
294echo 0 > $TEMP1
295$AWK '	BEGIN { exit }
296	{ print }
297	END { print NR }' > $TEMP2
298cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc BEGIN exit'
299
300echo 1 > $TEMP1
301$AWK '	{ exit }
302	END { print NR }' /etc/passwd > $TEMP2
303cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit'
304
305echo 1 > $TEMP1
306$AWK '	{i = 1; while (i <= NF) {if (i == NF) exit; i++ } }
307	END { print NR }' /etc/passwd > $TEMP2
308cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 2'
309
310echo 1 > $TEMP1
311$AWK '	function f() {
312		i = 1; while (i <= NF) {if (i == NF) return NR; i++ }
313	}
314	{ if (f() == 1) exit }
315	END { print NR }' /etc/passwd > $TEMP2
316cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc while return'
317
318echo 1 > $TEMP1
319$AWK '	function f() {
320		split("a b c", arr)
321		for (i in arr) {if (i == 3) return NR; i++ }
322	}
323	{ if (f() == 1) exit }
324	END { print NR }' /etc/passwd > $TEMP2
325cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc while return'
326
327echo 1 > $TEMP1
328$AWK '	{i = 1; do { if (i == NF) exit; i++ } while (i <= NF) }
329	END { print NR }' /etc/passwd > $TEMP2
330cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 3'
331
332echo 1 > $TEMP1
333$AWK '	function f() {
334		i = 1; do { if (i == NF) return NR; i++ } while (i <= NF)
335	}
336	{ if (f() == 1) exit }
337	END { print NR }' /etc/passwd > $TEMP2
338cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc do return'
339
340echo 1 > $TEMP1
341$AWK '	{i = 1; do { if (i == NF) break; i++ } while (i <= NF); exit }
342	END { print NR }' /etc/passwd > $TEMP2
343cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 4'
344
345echo 1 > $TEMP1
346$AWK '	{ n = split($0, x)
347	  for (i in x) {
348	 	if (i == 1)
349			exit } }
350	END { print NR }' /etc/passwd > $TEMP2
351cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 5'
352
353echo XXXXXXXX > $TEMP1
354$AWK 'BEGIN { s = "ab\fc\rd\be"
355	t = s; 	gsub("[" s "]", "X", t); print t }' > $TEMP2
356cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc weird escapes in char class'
357
358$AWK '{}' /etc/passwd glop/glop > $TEMP0 2> $TEMP2
359grep "can't open.*glop" $TEMP2 >/dev/null || fail "BAD: T.misc can't open"
360
361echo '
362
363
364a
365aa
366
367b
368
369
370c
371
372' > $TEMP0
373echo 3 > $TEMP1
374$AWK 'BEGIN { RS = "" }; END { print NR }' $TEMP0 > $TEMP2
375cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc RS botch'
376
377$AWK 'BEGIN \
378	{
379		print "hello, world"
380	}
381}}}' > $TEMP1 2> $TEMP2
382grep 'source line 5' $TEMP2 >/dev/null 2>&1 || fail 'BAD: T.misc continuation line number'
383
384
385echo 111 222 333 > $TEMP0
386$AWK '{ f[1]=1; f[2]=2; print $f[1], $f[1]++, $f[2], f[1], f[2] }' $TEMP0 > $TEMP2
387echo 111 111 222 2 2 > $TEMP1
388cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc $f[1]++'
389
390
391# These should be syntax errors
392$AWK . 2> $TEMP0
393grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error . fails"
394
395$AWK .. 2> $TEMP0
396grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .. fails"
397
398$AWK .E. 2> $TEMP0
399grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .E. fails"
400
401$AWK .++. 2> $TEMP0
402grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .++. fails"
403
404
405# next several were infinite loops, found by brian tsang.
406# this is his example:
407
408$AWK 'BEGIN {
409    switch (substr("x",1,1)) {
410    case /ask.com/:
411	break
412    case "google":
413	break
414    }
415}' > $TEMP0 2>&1
416grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 1"
417
418$AWK 'BEGIN { s { c /./ } }' > $TEMP0 2>&1
419grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 2"
420
421$AWK 'BEGIN { s { c /../ } }' > $TEMP0 2>&1
422grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 3"
423
424echo '' > $TEMP0
425$AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1
426awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2
427cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0'
428
429exit $RESULT
430