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
8TEMP1=$WORKDIR/test.temp.1
9TEMP2=$WORKDIR/test.temp.2
10
11RESULT=0
12
13fail() {
14	echo "$1" >&2
15	RESULT=1
16}
17
18echo T.func: test user-defined functions
19
20echo '10 2
212 10
2210 10
2310 1e1
241e1 9' | $AWK '
25# tests whether function returns sensible type bits
26
27function assert(cond) { # assertion
28    if (cond) print 1; else print 0
29}
30
31function i(x) { return x }
32
33{ m=$1; n=i($2); assert(m>n) }
34' > $TEMP1
35echo '1
360
370
380
391' > $TEMP2
40diff $TEMP1 $TEMP2 || fail 'BAD: T.func (function return type)'
41
42echo 'data: data' > $TEMP1
43$AWK '
44function test1(array) { array["test"] = "data" }
45function test2(array) { return(array["test"]) }
46BEGIN { test1(foo); print "data: " test2(foo) }
47' > $TEMP2
48diff $TEMP1 $TEMP2 || fail 'BAD: T.func (array type)'
49
50$AWK '
51BEGIN	{ code() }
52END	{ codeout("x") }
53function code() { ; }
54function codeout(ex) { print ex }
55' /dev/null > $TEMP1
56echo x > $TEMP2
57diff $TEMP1 $TEMP2 || fail 'BAD: T.func (argument passing)'
58
59$AWK '
60BEGIN { unireghf() }
61
62function unireghf(hfeed) {
63	hfeed[1]=0
64	rcell("foo",hfeed)
65	hfeed[1]=0
66	rcell("bar",hfeed)
67}
68
69function rcell(cellname,hfeed) {
70	print cellname
71}
72' > $TEMP1
73echo "foo
74bar" > $TEMP2
75diff $TEMP1 $TEMP2 || fail 'BAD: T.func (convert arg to array)'
76
77$AWK '
78function f(n) {
79	if (n <= 1)
80		return 1
81	else
82		return n * f(n-1)
83}
84{ print f($1) }
85' > $TEMP2 <<!
860
871
882
893
904
915
926
937
948
959
96!
97cat > $TEMP1 <<!
981
991
1002
1016
10224
103120
104720
1055040
10640320
107362880
108!
109diff $TEMP1 $TEMP2 || fail 'BAD: T.func (factorial)'
110
111$AWK '
112function ack(m,n) {
113	k = k+1
114	if (m == 0) return n+1
115	if (n == 0) return ack(m-1, 1)
116	return ack(m-1, ack(m, n-1))
117}
118{ k = 0; print ack($1,$2), "(" k " calls)" }
119' > $TEMP2 <<!
1200 0
1211 1
1222 2
1233 3
1243 4
1253 5
126!
127cat > $TEMP1 <<!
1281 (1 calls)
1293 (4 calls)
1307 (27 calls)
13161 (2432 calls)
132125 (10307 calls)
133253 (42438 calls)
134!
135diff $TEMP1 $TEMP2 || fail 'BAD: T.func (ackermann)'
136
137$AWK '
138END { print "end" }
139{ print fib($1) }
140function fib(n) {
141	if (n <= 1) return 1
142	else return add(fib(n-1), fib(n-2))
143}
144function add(m,n) { return m+n }
145BEGIN { print "begin" }
146' > $TEMP2 <<!
1471
1483
1495
15010
151!
152cat > $TEMP1 <<!
153begin
1541
1553
1568
15789
158end
159!
160diff $TEMP1 $TEMP2 || fail 'BAD: T.func (fib)'
161
162$AWK '
163function foo() {
164	for (i = 1; i <= 2; i++)
165		return 3
166	print "should not see this"
167}
168BEGIN { foo(); exit }
169' > $TEMP1
170grep 'should not' $TEMP1 && fail 'BAD: T.func (return)'
171
172# this exercises multiple free of temp cells
173echo 'eqn
174eqn2' > $TEMP1
175$AWK 'BEGIN 	{ eprocess("eqn", "x", contig)
176	  process("tbl" )
177	  eprocess("eqn" "2", "x", contig)
178	}
179function eprocess(file, first, contig) {
180	print file
181}
182function process(file) {
183	close(file)
184}' > $TEMP2
185diff $TEMP1 $TEMP2 || fail 'BAD: T.func (eqn)'
186
187echo 1 > $TEMP1
188$AWK 'function f() { n = 1; exit }
189	BEGIN { n = 0; f(); n = 2 }; END { print n}' > $TEMP2
190diff $TEMP1 $TEMP2 || fail 'BAD: T.func (exit in function)'
191
192echo 1 > $TEMP1
193$AWK '
194BEGIN {	n = 10
195	for (i = 1; i <= n; i++)
196	for (j = 1; j <= n; j++)
197		x[i,j] = n * i + j
198	for (i = 1; i <= n; i++)
199	for (j = 1; j <= n; j++)
200		if ((i,j) in x)
201			k++
202	print (k == n^2)
203      }
204' > $TEMP2
205diff $TEMP1 $TEMP2 || fail 'BAD: T.func (multi-dim subscript)'
206
207echo '<> 0' > $TEMP1
208$AWK '
209function foo() { i = 0 }
210        BEGIN { x = foo(); printf "<%s> %d\n", x, x }' > $TEMP2
211diff $TEMP1 $TEMP2 || fail 'BAD: T.func (fall off end)'
212
213exit $RESULT
214