1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2012 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                 Eclipse Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#          http://www.eclipse.org/org/documents/epl-v10.html           #
11#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20function err_exit
21{
22	print -u2 -n "\t"
23	print -u2 -r ${Command}[$1]: "${@:2}"
24	let Errors+=1
25}
26alias err_exit='err_exit $LINENO'
27
28Command=${0##*/}
29integer Errors=0
30
31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
32trap "cd /; rm -rf $tmp" EXIT
33
34function checkref
35{
36	nameref foo=$1 bar=$2
37	if	[[ $foo !=  $bar ]]
38	then	err_exit "foo=$foo != bar=$bar"
39	fi
40	foo=hello
41	if	[[ $foo !=  $bar ]]
42	then	err_exit "foo=$foo != bar=$bar"
43	fi
44	foo.child=child
45	if	[[ ${foo.child} !=  ${bar.child} ]]
46	then	err_exit "foo.child=${foo.child} != bar=${bar.child}"
47	fi
48}
49
50name=first
51checkref name name
52name.child=second
53checkref name name
54.foo=top
55.foo.bar=next
56checkref .foo.bar .foo.bar
57if	[[ ${.foo.bar} !=  hello ]]
58then	err_exit ".foo.bar=${.foo.bar} != hello"
59fi
60if	[[ ${.foo.bar.child} !=  child ]]
61then	err_exit ".foo.bar.child=${.foo.bar.child} != child"
62fi
63function func1
64{
65        nameref color=$1
66        func2 color
67}
68
69function func2
70{
71        nameref color=$1
72        set -s -- ${!color[@]}
73	print -r -- "$@"
74}
75
76typeset -A color
77color[apple]=red
78color[grape]=purple
79color[banana]=yellow
80if	[[ $(func1 color) != 'apple banana grape' ]]
81then	err_exit "nameref or nameref not working"
82fi
83nameref x=.foo.bar
84if	[[ ${!x} != .foo.bar ]]
85then	err_exit "${!x} not working"
86fi
87typeset +n x $(typeset +n)
88unset x
89nameref x=.foo.bar
90function x.set
91{
92	[[ ${.sh.value} ]] && print hello
93}
94if	[[ $(.foo.bar.set) != $(x.set) ]]
95then	err_exit "function references  not working"
96fi
97if	[[ $(typeset +n) != x ]]
98then	err_exit "typeset +n doesn't list names of reference variables"
99fi
100if	[[ $(typeset -n) != x=.foo.bar ]]
101then	err_exit "typeset +n doesn't list values of reference variables"
102fi
103file=$tmp/test
104typeset +n foo bar 2> /dev/null
105unset foo bar
106export bar=foo
107nameref foo=bar
108if	[[ $foo != foo ]]
109then	err_exit "value of nameref foo !=  $foo"
110fi
111cat > $file <<\!
112print -r -- $foo
113!
114chmod +x "$file"
115y=$( $file)
116if	[[ $y != '' ]]
117then	err_exit "reference variable not cleared"
118fi
119{
120	command nameref xx=yy
121	command nameref yy=xx
122} 2> /dev/null && err_exit "self reference not detected"
123typeset +n foo bar
124unset foo bar
125set foo
126nameref bar=$1
127foo=hello
128if	[[ $bar !=  hello ]]
129then	err_exit 'nameref of positional paramters outside of function not working'
130fi
131unset foo bar
132bar=123
133function foobar
134{
135	typeset -n foo=bar
136	typeset -n foo=bar
137}
138foobar 2> /dev/null || err_exit 'nameref not unsetting previous reference'
139(
140	nameref short=verylong
141	short=( A=a B=b )
142	if	[[ ${verylong.A} != a ]]
143	then	err_exit 'nameref short to longname compound assignment error'
144	fi
145) 2> /dev/null|| err_exit 'nameref short to longname compound assignment error'
146unset x
147if	[[	$(var1=1 var2=2
148		for i in var1 var2
149		do	nameref x=$i
150			print $x
151		done) != $'1\n2' ]]
152then	err_exit 'for loop nameref optimization error'
153fi
154if	[[	$(typeset -A var1 var2
155		var1[sub1]=1 var2[sub2]=1
156		for i in var1 var2
157		do
158		        typeset -n array=$i
159		        print ${!array[*]}
160		done) != $'sub1\nsub2' ]]
161then 	err_exit 'for loop nameref optimization test2 error'
162fi
163
164unset -n x foo bar
165if	[[ $(nameref x=foo;for x in foo bar;do print ${!x};done) != $'foo\nbar' ]]
166then	err_exit 'for loop optimization with namerefs not working'
167fi
168if	[[ $(
169	p=(x=(r=3) y=(r=4))
170	for i in x y
171	do	nameref x=p.$i
172		print ${x.r}
173	done
174) != $'3\n4' ]]
175then	err_exit 'nameref optimization error'
176fi
177[[ $(
178unset x y var
179var=(foo=bar)
180for i in y var
181do	typeset -n x=$i
182	if	[[ ${!x.@} ]]
183	then	print ok
184	fi
185	typeset +n x
186done) != ok ]] && err_exit 'invalid for loop optimization of name references'
187function setval # name value
188{
189        nameref arg=$1
190	nameref var=arg.bar
191	var=$2
192}
193foo=( integer bar=0)
194setval foo 5
195(( foo.bar == 5)) || err_exit 'nested nameref not working'
196function selfref
197{
198        typeset -n ps=$1
199        print -r -- "${ps}"
200}
201ps=(a=1 b=2)
202[[ $(selfref ps) == *a=1* ]] ||  err_exit 'local nameref cannot reference global variable of the same name'
203function subref
204{
205	typeset -n foo=$1
206	print -r -- ${foo.a}
207}
208[[ $(subref ps) == 1 ]] ||  err_exit 'local nameref cannot reference global variable child'
209
210function local
211{
212	typeset ps=(typeset -i a=3 b=4)
213	[[ $(subref ps) == 3 ]] ||  err_exit 'local nameref cannot reference caller compound variable'
214}
215local
216unset -f local
217function local
218{
219	qs=(integer  a=3; integer b=4)
220}
221local 2> /dev/null || err_exit 'function local has non-zero exit status'
222[[ ${qs.a} == 3 ]] || err_exit 'function cannot set compound global variable'
223unset fun i
224foo=(x=hi)
225function fun
226{
227        nameref i=$1
228        print -r -- "${i.x}"
229}
230i=foo
231[[ $(fun $i) == hi ]] || err_exit 'nameref for compound variable with in function name of caller fails'
232unset -n foo bar
233typeset -A foo
234foo[x.y]=(x=3 y=4)
235nameref bar=foo[x.y]
236[[ ${bar.x} == 3 ]] || err_exit 'nameref to subscript containing . fails'
237[[ ${!bar} == 'foo[x.y]' ]] || err_exit '${!var} not correct for nameref to an array instance'
238typeset +n bar
239nameref bar=foo
240[[ ${!bar} == foo ]] || err_exit '${!var} not correct for nameref to array variable'
241$SHELL -c 'function bar { nameref x=foo[++];};typeset -A foo;bar' 2> /dev/null ||err_exit 'nameref of associative array tries to evaluate subscript'
242i=$($SHELL -c 'nameref foo=bar; bar[2]=(x=3 y=4); nameref x=foo[2].y;print -r -- $x' 2> /dev/null)
243[[ $i == 4 ]] || err_exit 'creating reference from subscripted variable whose name is a reference failed'
244[[ $($SHELL 2> /dev/null <<- '+++EOF'
245	function bar
246	{
247	 	nameref x=$1
248	 	print -r -- "$x"
249	}
250	function foo
251	{
252	 	typeset var=( foo=hello)
253	 	bar var
254	}
255	foo
256+++EOF
257) ==  *foo=hello* ]] || err_exit 'unable to display compound variable from name reference of local variable'
258#set -x
259for c in '=' '[' ']' '\' "'" '"' '<' '=' '('
260do	[[ $($SHELL 2> /dev/null <<- ++EOF++
261	i=\\$c;typeset -A a; a[\$i]=foo;typeset -n x=a[\$i]; print "\$x"
262	++EOF++
263) != foo ]] && err_exit 'nameref x=a[$c] '"not working for c=$c"
264done
265for c in '=' '[' ']' '\' "'" '"' '<' '=' '('
266do      [[ $($SHELL 2> /dev/null <<- ++EOF++
267	i=\\$c;typeset -A a; a[\$i]=foo;b=a[\$i];typeset -n x=\$b; print "\$x"
268	++EOF++
269) != foo ]] && err_exit 'nameref x=$b with b=a[$c] '"not working for c=$c"
270done
271
272unset -n foo x
273unset foo x
274typeset -A foo
275nameref x=foo[xyz]
276foo[xyz]=ok
277[[ $x == ok ]] || err_exit 'nameref to unset subscript not working'
278function function2
279{
280	nameref v=$1
281	v.x=19 v.y=20
282}
283function function1
284{
285	typeset compound_var=()
286	function2 compound_var
287	printf "x=%d, y=%d\n" compound_var.x compound_var.y
288}
289x="$(function1)"
290[[ "$x" != 'x=19, y=20' ]] && err_exit "expected 'x=19, y=20', got '${x}'"
291typeset +n bar
292unset foo bar
293[[ $(function a
294{
295	for i in  foo bar
296	do	typeset -n v=$i
297		print $v
298	done | cat
299}
300foo=1 bar=2;a) == $'1\n2' ]] 2> /dev/null || err_exit 'nameref in pipeline broken'
301function a
302{
303	typeset -n v=vars.data._1
304	print "${v.a} ${v.b}"
305}
306vars=(data=())
307vars.data._1.a=a.1
308vars.data._1.b=b.1
309[[ $(a) == 'a.1 b.1' ]] || err_exit 'nameref choosing wrong scope -- '
310typeset +n bam zip foo
311unset bam zip foo
312typeset -A foo
313foo[2]=bar
314typeset -n bam=foo[2]
315typeset -n zip=bam
316[[ $zip == bar ]] || err_exit 'nameref to another nameref to array element fails'
317[[ -R zip ]] || err_exit '[[ -R zip ]] should detect that zip is a reference'
318[[ -R bam ]] || err_exit '[[ -R bam ]] should detect that bam is a reference'
319[[ -R zip ]] || err_exit '[[ -v zip ]] should detect that zip is set'
320[[ -v bam ]] || err_exit '[[ -v bam ]] should detect that bam is set'
321[[ -R 123 ]] && err_exit '[[ -R 123 ]] should detect that 123 is not a reference'
322[[ -v 123 ]] && err_exit '[[ -v 123 ]] should detect that 123 is not set'
323
324unset ref x
325typeset -n ref
326x=3
327function foobar
328{
329	typeset xxx=3
330	ref=xxx
331	return 0
332}
333foobar 2> /dev/null && err_exit 'invalid reference should cause foobar to fail'
334[[ -v ref ]] && err_exit '$ref should be unset'
335ref=x
336[[ $ref == 3 ]] || err_exit "\$ref is $ref, it should be 3"
337function foobar
338{
339        typeset fvar=()
340        typeset -n ref=fvar.foo
341        ref=ok
342        print -r $ref
343}
344[[ $(foobar) ==  ok ]] 2> /dev/null  || err_exit 'nameref in function not creating variable in proper scope'
345function foobar
346{
347        nameref doc=docs
348        nameref bar=doc.num
349	[[ $bar == 2 ]] || err_exit 'nameref scoping error'
350}
351
352docs=(num=2)
353foobar
354
355typeset +n x y
356unset x y
357typeset -A x
358x[a]=(b=c)
359typeset -n y=x[a]
360[[ ${!y.@} == 'x[a].b' ]] || err_exit 'reference to array element not expanded with ${!y.@}'
361
362typeset +n v
363v=()
364k=a.b.c/d
365command typeset -n n=v.${k//['./']/_} 2> /dev/null || err_exit 'patterns with quotes not handled correctly with name reference assignment'
366
367typeset _n sp
368nameref sp=addrsp
369sp[14]=( size=1 )
370[[ -v sp[19] ]]  && err_exit '[[ -v sp[19] ]] where sp is a nameref should not be set'
371
372function fun2
373{
374	nameref var=$1
375	var.foo=bar
376}
377
378function fun1
379{
380	compound -S container
381	fun2 container
382	[[ $container == *foo=bar* ]] || err_exit 'name references to static compound variables in parent scope not working'
383}
384fun1
385
386function fun2
387{
388	nameref var=$1
389	var.foo=bar
390}
391
392typeset -T container_t=(
393	typeset foo
394)
395
396function fun1
397{
398	container_t -S container
399	fun2 container
400	[[ $container == *foo=bar* ]] || err_exit 'name references to static type variables in parent scope not working'
401}
402fun1
403
404function fun2
405{
406	nameref var=$1
407	nameref node=var.foo
408	node=bar
409}
410function fun3
411{
412       fun2 container #2> /dev/null
413}
414compound container
415fun3
416[[ $container == *foo=bar* ]] || err_exit 'name reference to a name reference variable in a function not working'
417
418typeset -A x=( [a]=1 )
419nameref c=x[h]
420[[ -v x[h] ]] && err_exit 'creating reference to non-existant associative array element causes element to get added'
421
422unset a
423function x
424{
425	nameref a=a
426	(( $# > 0 )) && typeset -A a
427	a[a b]=${1-99}  # this was cauing a syntax on the second call
428}
429x 7
430x 2> /dev/null
431[[ ${a[a b]} == 99 ]] || err_exit 'nameref not handling subscript correctly'
432
433nameref sizes=baz
434typeset -A -i sizes
435sizes[bar]=1
436[[ ${sizes[*]} == 1 ]] || err_exit 'adding -Ai attribute to name referenced variable not working'
437
438$SHELL 2> /dev/null -c 'nameref foo=bar; typeset -A foo; (( (x=foo[a])==0 ))' || err_exit 'references inside arithmetic expressions not working'
439:
440
441unset ar z
442integer -a ar
443nameref z=ar[0]
444(( z[2]=3))
445[[ ${ar[0][2]} == 3 ]] || err_exit "\${ar[0][2]} is '${ar[0][2]}' but should be 3"
446(( ar[0][2] == 3 )) || err_exit "ar[0][2] is '${ar[0][2]}' but should be 3"
447
448unset c x
449typeset +n c x
450compound c=( typeset -a x )
451nameref x=c.x
452x[4]=1
453[[ ${ typeset -p c.x ;} == *-C* ]] && err_exit 'c.x should not have -C attributes'
454
455{ $SHELL 2> /dev/null  <<- \EOF
456	typeset -T xxx_t=(
457		float x=1 y=2
458		typeset name=abc
459	)
460	xxx_t x
461	nameref r=x.y
462	[[ $r == 2 ]] || exit 1
463	unset x
464	[[ ${!r} == .deleted ]] || exit 2
465EOF
466} 2> /dev/null #|| print -u2 bad
467exitval=$?
468if	[[ $(kill -l $exitval) == SEGV ]]
469then	print -u2 'name reference to unset type instance causes segmentation violation'
470else 	if((exitval))
471	then	print -u2 'name reference to unset type instance not redirected to .deleted'
472	fi
473fi
474
475typeset +n nr
476unset c nr
477compound c
478compound -A c.a
479nameref nr=c.a[hello]
480[[ ${!nr} == "c.a[hello]" ]] || err_exit 'name reference nr to unset associative array instance does not expand ${!nr} correctly.'
481
482typeset +n nr
483compound -a c.b
484nameref nr=c.b[2]
485[[ ${!nr} == "c.b[2]" ]] || err_exit 'name reference nr to unset indexed array instance does not expand ${!nr} correctly.'
486
487typeset +n a b
488unset a b
489typeset -n a=ls[0] b=ls[1]
490read line << \!
4913 4
492!
493set -A ls -- $line
494[[ $a == 3 ]] || err_exit 'name reference to ls[0] when ls is not an array fails'
495
496$SHELL  2> /dev/null <<-\EOF || err_exit 'nameref to array element fails'
497	set -o errexit
498	function bf {
499		nameref treename=$1
500		nodepath="treename" ;
501		nameref x="$nodepath"
502		compound -A x.nodes
503		nameref node=treename.nodes[4]
504		node=()
505		typeset +p node.elements
506	}
507	compound c
508	bf c
509EOF
510
511function add_compound
512{
513	nameref arr=$1
514	arr[34]+=( float val=1.1 )
515}
516compound -a rootcpv
517nameref mycpv=rootcpv[4][8][16][32][64]
518compound -a mycpv.myindexedcompoundarray
519add_compound mycpv.myindexedcompoundarray
520(( mycpv.myindexedcompoundarray[34].val == 1.1 )) ||  err_exit 'nameref scoping error'
521
522function add_file_to_tree
523{
524	nameref node=$1
525	compound -A node.elements
526	node.elements[/]=(filepath=foobar)
527}
528function main
529{
530	compound filetree
531	add_file_to_tree filetree
532}
533main 2> /dev/null
534[[ $? == 0 ]] || err_exit 'nameref binding to calling function compound variable failed'
535
536unset l
537typeset -a -C l
538printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4][6]
539exp=$(print -v l)
540unset l
541typeset -a -C l
542nameref l4=l[4]
543printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4[6]
544[[ $(print -v l) == "$exp" ]] || err_exit  'nameref l4=l[4] not working'
545unset l
546typeset -a -C l
547nameref l46=l[4][6]
548printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l46
549[[ $(print -v l) == "$exp" ]] || err_exit  'nameref l46=l[4][6] not working'
550
551exp=$'(\n\t[4]=(\n\t\ttypeset -a ar=(\n\t\t\t1\n\t\t\t2\n\t\t)\n\t\tb=1\n\t)\n)'
552unset l
553typeset +n l4
554typeset -a -C l
555nameref l4=l[4]
556printf "( typeset -a ar=( 1\n2\n) b=1 )\n" | read -C l4
557[[ $(print -v l) == "$exp" ]] || err_exit  'nameref l4=l[4] not working with indexed array read'
558
559unset l
560typeset +n l4
561typeset -A -C l
562nameref l4=l[4]
563printf "( typeset -a ar=( 1\n2\n) b=1 )\n" | read -C l4
564[[ $(print -v l) == "$exp" ]] || err_exit  'nameref l4=l[4] not working with associative array read'
565
566exp=$'(\n\t[9]=(\n\t\tfish=4\n\t)\n)'
567function add_eval
568{
569	nameref pos=$1
570	source /dev/stdin <<<"$2"
571	typeset -m pos=addvar
572}
573function do_local_plain
574{
575	compound -A local_tree
576	add_eval local_tree[9].fish "typeset -i addvar=4"
577	[[ $(print -v local_tree) == "$exp" ]] || err_exit 'do_local_plain failed'
578}
579function do_global_throughnameref
580{
581	nameref tr=global_tree
582	add_eval tr[9].fish "typeset -i addvar=4"
583	[[ $(print -v tr) == "$exp" ]] || err_exit 'do_global_throughnameref failed'
584}
585function do_local_throughnameref
586{
587	compound -A local_tree
588	nameref tr=local_tree
589	add_eval tr[9].fish "typeset -i addvar=4"
590	[[ $(print -v tr) == "$exp" ]] || err_exit 'do_local_throughnameref failed'
591}
592compound -A global_tree
593do_global_throughnameref
594do_local_throughnameref
595do_local_plain
596
597unset ar
598compound -a ar
599function read_c
600{
601	nameref v=$1
602	read -C v
603}
604print "( typeset -i x=36 ) " | read_c ar[5][9][2]
605exp=$'(\n\t[5]=(\n\t\t[9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)'
606[[ $(print -v ar) == "$exp" ]] || err_exit 'read into nameref of global array instance from within a function fails'
607
608function read_c
609{
610	nameref v=$1
611	read -C v
612}
613function main
614{
615	compound -a ar
616	nameref nar=ar
617	print "( typeset -i x=36 ) " | read_c nar[5][9][2]
618	exp=$'(\n\t[5]=(\n\t\t[9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)'
619	[[ $(print -v nar) == "$exp" ]] || err_exit 'read from a nameref variable from calling scope fails'
620}
621main
622
623function rf2
624{
625	nameref val=$1
626	read -C val
627}
628function rf
629{
630	nameref val=$1
631	rf2 val
632}
633function main
634{
635	compound c
636	typeset -A -C c.l
637	nameref l4=c.l[4]
638	printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | rf l4
639	exp=$'(\n\ttypeset -C -A l=(\n\t\t[4]=(\n\t\t\ttypeset -a ar=(\n\t\t\t\t1\n\t\t\t\t2\n\t\t\t\t3\n\t\t\t)\n\t\t\tb=1\n\t\t)\n\t)\n)'
640	[[ $(print -v c) == "$exp" ]] || err_exit 'read -C with nameref to array element fails'
641}
642main
643
644# bug reported by ek
645cfg=( alarms=(type=3))
646function a
647{
648	typeset -n y=$1
649	print -- ${y.type}
650}
651function b
652{
653    a $1
654}
655[[  $(a cfg.alarms) == 3 ]] || err_exit  "nameref scoping error in function"
656[[  $(b cfg.alarms) == 3 ]] || err_exit  "nameref scoping error in nested function"
657
658function yy
659{
660	nameref n=$1
661	n=( z=4 )
662}
663yy foo
664unset foo
665[[ $foo ]] && err_exit 'unset after creating via nameref in function not working'
666
667unset arr
668typeset -a arr=( ( 1 2 3 ) ( 4 5 6 ) ( 7 8 9 ))
669typeset -n ref=arr[1]
670[[ $ref == 4 ]] || err_exit '$ref should be 4'
671[[ ${ref[@]} == '4 5 6' ]] || err_exit '${ref[@]} should be "4 5 6"'
672[[ $ref == "${arr[1]}" ]] || err_exit '$ref shuld be ${arr[1]}'
673[[ ${ref[@]} == "${arr[1][@]}" ]] || err_exit '${ref[@]} should be ${arr[1][@]}'
674
675function fun2
676{
677	nameref var=$1.foo
678	var=$2
679}
680function fun1
681{
682	xxx=$1
683	fun2 $xxx bam
684}
685args=(bar=yes)
686fun1 args
687[[ $args == *foo=bam* ]] || err_exit 'nameref does not bind to correct scope'
688
689typeset +n ref
690unset ref ar
691typeset -a arr=( 1 2 3 )
692typeset -n ref='arr[2]'
693[[ $(typeset -p ref) == *'arr[2]'* ]] || err_exit 'typeset -p ref when ref is a reference to an index array element is wrong'
694
695$SHELL  2> /dev/null -c 'function x { nameref lv=gg ; compound -A lv.c=( [4]=( x=1 )) ; } ; compound gg ; x' || err_exit 'compound array assignment with nameref in a function failed'
696
697exit $((Errors<125?Errors:125))
698