xref: /titanic_41/usr/src/lib/libshell/common/sh/array.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * Array processing routines
23da2e3ebdSchin  *
24da2e3ebdSchin  *   David Korn
25da2e3ebdSchin  *   AT&T Labs
26da2e3ebdSchin  *   dgk@research.att.com
27da2e3ebdSchin  *
28da2e3ebdSchin  */
29da2e3ebdSchin 
30da2e3ebdSchin #include	"defs.h"
31da2e3ebdSchin #include	<stak.h>
32da2e3ebdSchin #include	"name.h"
33da2e3ebdSchin 
34da2e3ebdSchin #define NUMSIZE	(4+(ARRAY_MAX>999)+(ARRAY_MAX>9999)+(ARRAY_MAX>99999))
35da2e3ebdSchin #define is_associative(ap)	array_assoc((Namarr_t*)(ap))
367c2fbfb3SApril Chin #define array_setbit(cp, n, b)	(cp[n] |= (b))
377c2fbfb3SApril Chin #define array_clrbit(cp, n, b)	(cp[n] &= ~(b))
387c2fbfb3SApril Chin #define array_isbit(cp, n, b)	(cp[n] & (b))
39da2e3ebdSchin #define NV_CHILD		NV_EXPORT
407c2fbfb3SApril Chin #define ARRAY_CHILD		1
417c2fbfb3SApril Chin #define ARRAY_NOFREE		2
42da2e3ebdSchin 
43da2e3ebdSchin struct index_array
44da2e3ebdSchin {
45da2e3ebdSchin         Namarr_t        header;
467c2fbfb3SApril Chin 	void		*xp;	/* if set, subscripts will be converted */
47da2e3ebdSchin         int		cur;    /* index of current element */
48da2e3ebdSchin         int		maxi;   /* maximum index for array */
49da2e3ebdSchin 	unsigned char	*bits;	/* bit array for child subscripts */
50da2e3ebdSchin         union Value	val[1]; /* array of value holders */
51da2e3ebdSchin };
52da2e3ebdSchin 
53da2e3ebdSchin struct assoc_array
54da2e3ebdSchin {
55da2e3ebdSchin 	Namarr_t	header;
56da2e3ebdSchin 	Namval_t	*pos;
57da2e3ebdSchin 	Namval_t	*nextpos;
58da2e3ebdSchin 	Namval_t	*cur;
59da2e3ebdSchin };
60da2e3ebdSchin 
array_scope(Namval_t * np,Namarr_t * ap,int flags)617c2fbfb3SApril Chin static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
627c2fbfb3SApril Chin {
637c2fbfb3SApril Chin 	Namarr_t *aq;
647c2fbfb3SApril Chin 	struct index_array *ar;
657c2fbfb3SApril Chin 	size_t size = ap->hdr.dsize;
667c2fbfb3SApril Chin 	if(size==0)
677c2fbfb3SApril Chin 		size = ap->hdr.disc->dsize;
687c2fbfb3SApril Chin         if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
697c2fbfb3SApril Chin                 return(0);
707c2fbfb3SApril Chin         memcpy(aq,ap,size);
717c2fbfb3SApril Chin 	aq->hdr.nofree &= ~1;
727c2fbfb3SApril Chin         aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
737c2fbfb3SApril Chin 	if(is_associative(aq))
747c2fbfb3SApril Chin 	{
757c2fbfb3SApril Chin 		aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
767c2fbfb3SApril Chin 		dtview((Dt_t*)aq->scope,aq->table);
777c2fbfb3SApril Chin 		aq->table = (Dt_t*)aq->scope;
787c2fbfb3SApril Chin 		return(aq);
797c2fbfb3SApril Chin 	}
807c2fbfb3SApril Chin 	aq->scope = (void*)ap;
817c2fbfb3SApril Chin 	ar = (struct index_array*)aq;
827c2fbfb3SApril Chin 	memset(ar->val, 0, ar->maxi*sizeof(char*));
837c2fbfb3SApril Chin 	return(aq);
847c2fbfb3SApril Chin }
857c2fbfb3SApril Chin 
array_unscope(Namval_t * np,Namarr_t * ap)867c2fbfb3SApril Chin static int array_unscope(Namval_t *np,Namarr_t *ap)
877c2fbfb3SApril Chin {
887c2fbfb3SApril Chin 	Namfun_t *fp;
897c2fbfb3SApril Chin 	if(!ap->scope)
907c2fbfb3SApril Chin 		return(0);
917c2fbfb3SApril Chin 	if(is_associative(ap))
927c2fbfb3SApril Chin 		(*ap->fun)(np, NIL(char*), NV_AFREE);
937c2fbfb3SApril Chin 	if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
947c2fbfb3SApril Chin 		free((void*)fp);
957c2fbfb3SApril Chin 	nv_delete(np,(Dt_t*)0,0);
967c2fbfb3SApril Chin 	return(1);
977c2fbfb3SApril Chin }
987c2fbfb3SApril Chin 
array_syncsub(Namarr_t * ap,Namarr_t * aq)997c2fbfb3SApril Chin static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
1007c2fbfb3SApril Chin {
1017c2fbfb3SApril Chin 	((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
1027c2fbfb3SApril Chin }
1037c2fbfb3SApril Chin 
array_covered(Namval_t * np,struct index_array * ap)1047c2fbfb3SApril Chin static int array_covered(Namval_t *np, struct index_array *ap)
1057c2fbfb3SApril Chin {
1067c2fbfb3SApril Chin 	struct index_array *aq = (struct index_array*)ap->header.scope;
1077c2fbfb3SApril Chin 	if(!ap->header.fun && aq)
1087c2fbfb3SApril Chin 		return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
1097c2fbfb3SApril Chin 	return(0);
1107c2fbfb3SApril Chin }
1117c2fbfb3SApril Chin 
112da2e3ebdSchin /*
113da2e3ebdSchin  * replace discipline with new one
114da2e3ebdSchin  */
array_setptr(register Namval_t * np,struct index_array * old,struct index_array * new)115da2e3ebdSchin static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
116da2e3ebdSchin {
117da2e3ebdSchin 	register Namfun_t **fp = &np->nvfun;
118da2e3ebdSchin 	while(*fp && *fp!= &old->header.hdr)
119da2e3ebdSchin 		fp = &((*fp)->next);
120da2e3ebdSchin 	if(*fp)
121da2e3ebdSchin 	{
122da2e3ebdSchin 		new->header.hdr.next = (*fp)->next;
123da2e3ebdSchin 		*fp = &new->header.hdr;
124da2e3ebdSchin 	}
125da2e3ebdSchin 	else sfprintf(sfstderr,"discipline not replaced\n");
126da2e3ebdSchin }
127da2e3ebdSchin 
128da2e3ebdSchin /*
129da2e3ebdSchin  *   Calculate the amount of space to be allocated to hold an
130da2e3ebdSchin  *   indexed array into which <maxi> is a legal index.  The number of
131da2e3ebdSchin  *   elements that will actually fit into the array (> <maxi>
132da2e3ebdSchin  *   but <= ARRAY_MAX) is returned.
133da2e3ebdSchin  *
134da2e3ebdSchin  */
arsize(struct index_array * ap,register int maxi)1357c2fbfb3SApril Chin static int	arsize(struct index_array *ap, register int maxi)
136da2e3ebdSchin {
1377c2fbfb3SApril Chin 	if(ap && maxi < 2*ap->maxi)
1387c2fbfb3SApril Chin 		maxi = 2*ap->maxi;
1397c2fbfb3SApril Chin 	maxi = roundof(maxi,ARRAY_INCR);
1407c2fbfb3SApril Chin 	return (maxi>ARRAY_MAX?ARRAY_MAX:maxi);
141da2e3ebdSchin }
142da2e3ebdSchin 
143da2e3ebdSchin static struct index_array *array_grow(Namval_t*, struct index_array*,int);
144da2e3ebdSchin 
145da2e3ebdSchin /* return index of highest element of an array */
array_maxindex(Namval_t * np)146da2e3ebdSchin int array_maxindex(Namval_t *np)
147da2e3ebdSchin {
148da2e3ebdSchin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
149da2e3ebdSchin 	register int i = ap->maxi;
150da2e3ebdSchin 	if(is_associative(ap))
151da2e3ebdSchin 		return(-1);
152da2e3ebdSchin 	while(i>0 && ap->val[--i].cp==0);
153da2e3ebdSchin 	return(i+1);
154da2e3ebdSchin }
155da2e3ebdSchin 
array_getup(Namval_t * np,Namarr_t * arp,int update)1567c2fbfb3SApril Chin static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update)
157da2e3ebdSchin {
158da2e3ebdSchin 	register struct index_array *ap = (struct index_array*)arp;
159da2e3ebdSchin 	register union Value *up;
1607c2fbfb3SApril Chin 	int	nofree;
1617c2fbfb3SApril Chin 	if(!arp)
162da2e3ebdSchin 		return(&np->nvalue);
163da2e3ebdSchin 	if(is_associative(ap))
1647c2fbfb3SApril Chin 	{
1657c2fbfb3SApril Chin 		Namval_t	*mp;
1667c2fbfb3SApril Chin 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
1677c2fbfb3SApril Chin 		if(mp)
1687c2fbfb3SApril Chin 		{
1697c2fbfb3SApril Chin 			nofree = nv_isattr(mp,NV_NOFREE);
1707c2fbfb3SApril Chin 			up = &mp->nvalue;
1717c2fbfb3SApril Chin 		}
1727c2fbfb3SApril Chin 		else
1737c2fbfb3SApril Chin 			return((union Value*)((*arp->fun)(np,NIL(char*),0)));
1747c2fbfb3SApril Chin 	}
175da2e3ebdSchin 	else
176da2e3ebdSchin 	{
177da2e3ebdSchin 		if(ap->cur >= ap->maxi)
178da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
179da2e3ebdSchin 		up = &(ap->val[ap->cur]);
1807c2fbfb3SApril Chin 		nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
1817c2fbfb3SApril Chin 	}
1827c2fbfb3SApril Chin 	if(update)
1837c2fbfb3SApril Chin 	{
1847c2fbfb3SApril Chin 		if(nofree)
1857c2fbfb3SApril Chin 			nv_onattr(np,NV_NOFREE);
1867c2fbfb3SApril Chin 		else
1877c2fbfb3SApril Chin 			nv_offattr(np,NV_NOFREE);
188da2e3ebdSchin 	}
189da2e3ebdSchin 	return(up);
190da2e3ebdSchin }
191da2e3ebdSchin 
nv_arrayisset(Namval_t * np,Namarr_t * arp)19234f9b3eeSRoland Mainz int nv_arrayisset(Namval_t *np, Namarr_t *arp)
19334f9b3eeSRoland Mainz {
19434f9b3eeSRoland Mainz 	register struct index_array *ap = (struct index_array*)arp;
19534f9b3eeSRoland Mainz 	union Value *up;
19634f9b3eeSRoland Mainz 	if(is_associative(ap))
19734f9b3eeSRoland Mainz 		return((np = nv_opensub(np)) && !nv_isnull(np));
19834f9b3eeSRoland Mainz 	if(ap->cur >= ap->maxi)
19934f9b3eeSRoland Mainz 		return(0);
20034f9b3eeSRoland Mainz 	up = &(ap->val[ap->cur]);
20134f9b3eeSRoland Mainz 	return(up->cp && up->cp!=Empty);
20234f9b3eeSRoland Mainz }
20334f9b3eeSRoland Mainz 
204da2e3ebdSchin /*
205da2e3ebdSchin  * Get the Value pointer for an array.
206da2e3ebdSchin  * Delete space as necessary if flag is ARRAY_DELETE
207da2e3ebdSchin  * After the lookup is done the last @ or * subscript is incremented
208da2e3ebdSchin  */
array_find(Namval_t * np,Namarr_t * arp,int flag)209da2e3ebdSchin static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
210da2e3ebdSchin {
211da2e3ebdSchin 	register struct index_array *ap = (struct index_array*)arp;
212da2e3ebdSchin 	register union Value	*up;
213da2e3ebdSchin 	Namval_t		*mp;
214da2e3ebdSchin 	int			wasundef;
2157c2fbfb3SApril Chin 	if(flag&ARRAY_LOOKUP)
2167c2fbfb3SApril Chin 		ap->header.nelem &= ~ARRAY_NOSCOPE;
2177c2fbfb3SApril Chin 	else
2187c2fbfb3SApril Chin 		ap->header.nelem |= ARRAY_NOSCOPE;
219da2e3ebdSchin 	if(wasundef = ap->header.nelem&ARRAY_UNDEF)
220da2e3ebdSchin 	{
221da2e3ebdSchin 		ap->header.nelem &= ~ARRAY_UNDEF;
222da2e3ebdSchin 		/* delete array is the same as delete array[@] */
223da2e3ebdSchin 		if(flag&ARRAY_DELETE)
224da2e3ebdSchin 		{
2257c2fbfb3SApril Chin 			nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
226da2e3ebdSchin 			ap->header.nelem |= ARRAY_SCAN;
227da2e3ebdSchin 		}
228da2e3ebdSchin 		else /* same as array[0] */
229da2e3ebdSchin 		{
230da2e3ebdSchin 			if(is_associative(ap))
231da2e3ebdSchin 				(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
232da2e3ebdSchin 			else
233da2e3ebdSchin 				ap->cur = 0;
234da2e3ebdSchin 		}
235da2e3ebdSchin 	}
236da2e3ebdSchin 	if(is_associative(ap))
237da2e3ebdSchin 	{
238da2e3ebdSchin 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
239da2e3ebdSchin 		if(!mp)
240da2e3ebdSchin 			up = (union Value*)&mp;
2417c2fbfb3SApril Chin 		else if(nv_isarray(mp))
242da2e3ebdSchin 		{
2437c2fbfb3SApril Chin 			if(wasundef)
2447c2fbfb3SApril Chin 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
2457c2fbfb3SApril Chin 			return(mp);
246da2e3ebdSchin 		}
247da2e3ebdSchin 		else
2487c2fbfb3SApril Chin 		{
249da2e3ebdSchin 			up =  &mp->nvalue;
2507c2fbfb3SApril Chin 			if(nv_isvtree(mp))
2517c2fbfb3SApril Chin 			{
2527c2fbfb3SApril Chin 				if(!up->cp && flag==ARRAY_ASSIGN)
2537c2fbfb3SApril Chin 				{
2547c2fbfb3SApril Chin 					nv_arraychild(np,mp,0);
2557c2fbfb3SApril Chin 					ap->header.nelem++;
2567c2fbfb3SApril Chin 				}
2577c2fbfb3SApril Chin 				return(mp);
2587c2fbfb3SApril Chin 			}
2597c2fbfb3SApril Chin 		}
260da2e3ebdSchin 	}
261da2e3ebdSchin 	else
262da2e3ebdSchin 	{
263da2e3ebdSchin 		if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
264da2e3ebdSchin 			ap = array_grow(np, ap, (int)ap->cur);
265da2e3ebdSchin 		if(ap->cur>=ap->maxi)
266da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
267da2e3ebdSchin 		up = &(ap->val[ap->cur]);
2687c2fbfb3SApril Chin 		if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
2697c2fbfb3SApril Chin 		{
2707c2fbfb3SApril Chin 			char *cp;
2717c2fbfb3SApril Chin 			if(!ap->header.table)
2727c2fbfb3SApril Chin 				ap->header.table = dtopen(&_Nvdisc,Dtoset);
2737c2fbfb3SApril Chin 			sfprintf(sh.strbuf,"%d",ap->cur);
2747c2fbfb3SApril Chin 			cp = sfstruse(sh.strbuf);
2757c2fbfb3SApril Chin 			mp = nv_search(cp, ap->header.table, NV_ADD);
2767c2fbfb3SApril Chin 			mp->nvenv = (char*)np;
2777c2fbfb3SApril Chin 			nv_arraychild(np,mp,0);
2787c2fbfb3SApril Chin 		}
2797c2fbfb3SApril Chin 		if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
280da2e3ebdSchin 		{
281da2e3ebdSchin 			if(wasundef && nv_isarray(up->np))
282da2e3ebdSchin 				nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
283da2e3ebdSchin 			return(up->np);
284da2e3ebdSchin 		}
285da2e3ebdSchin 	}
286da2e3ebdSchin 	np->nvalue.cp = up->cp;
287da2e3ebdSchin 	if(!up->cp)
288da2e3ebdSchin 	{
289*3e14f97fSRoger A. Faulkner 			char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np);
290da2e3ebdSchin 		if(flag!=ARRAY_ASSIGN)
291*3e14f97fSRoger A. Faulkner 			return(xp && xp!=(char*)np?np:0);
2927c2fbfb3SApril Chin 		if(!array_covered(np,ap))
293da2e3ebdSchin 			ap->header.nelem++;
294da2e3ebdSchin 	}
295da2e3ebdSchin 	return(np);
296da2e3ebdSchin }
297da2e3ebdSchin 
2987c2fbfb3SApril Chin #if SHOPT_TYPEDEF
nv_arraysettype(Namval_t * np,Namval_t * tp,const char * sub,int flags)2997c2fbfb3SApril Chin int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
3007c2fbfb3SApril Chin {
3017c2fbfb3SApril Chin 	Namval_t	*nq;
3027c2fbfb3SApril Chin 	char		*av[2];
3037c2fbfb3SApril Chin 	int		rdonly = nv_isattr(np,NV_RDONLY);
3047c2fbfb3SApril Chin 	int		xtrace = sh_isoption(SH_XTRACE);
3057c2fbfb3SApril Chin 	Namarr_t	*ap = nv_arrayptr(np);
3067c2fbfb3SApril Chin 	av[1] = 0;
3077c2fbfb3SApril Chin 	sh.last_table = 0;
3087c2fbfb3SApril Chin 	if(!ap->table)
3097c2fbfb3SApril Chin 		ap->table = dtopen(&_Nvdisc,Dtoset);
3107c2fbfb3SApril Chin 	if(nq = nv_search(sub, ap->table, NV_ADD))
3117c2fbfb3SApril Chin 	{
3127c2fbfb3SApril Chin 		if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
3137c2fbfb3SApril Chin 			_nv_unset(nq,NV_RDONLY);
3147c2fbfb3SApril Chin 		nv_arraychild(np,nq,0);
3157c2fbfb3SApril Chin 		if(!nv_isattr(tp,NV_BINARY))
3167c2fbfb3SApril Chin 		{
3177c2fbfb3SApril Chin 			sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
3187c2fbfb3SApril Chin 			av[0] = strdup(sfstruse(sh.strbuf));
3197c2fbfb3SApril Chin 		}
3207c2fbfb3SApril Chin 		if(!nv_clone(tp,nq,flags|NV_NOFREE))
3217c2fbfb3SApril Chin 			return(0);
3227c2fbfb3SApril Chin 		ap->nelem |= ARRAY_SCAN;
3237c2fbfb3SApril Chin 		if(!rdonly)
3247c2fbfb3SApril Chin 			nv_offattr(nq,NV_RDONLY);
3257c2fbfb3SApril Chin 		if(!nv_isattr(tp,NV_BINARY))
3267c2fbfb3SApril Chin 		{
3277c2fbfb3SApril Chin 			if(xtrace)
3287c2fbfb3SApril Chin 				sh_offoption(SH_XTRACE);
3297c2fbfb3SApril Chin 			ap->nelem &= ~ARRAY_SCAN;
3307c2fbfb3SApril Chin 			sh_eval(sh_sfeval(av),0);
3317c2fbfb3SApril Chin 			ap->nelem |= ARRAY_SCAN;
3327c2fbfb3SApril Chin 			free((void*)av[0]);
3337c2fbfb3SApril Chin 			if(xtrace)
3347c2fbfb3SApril Chin 				sh_onoption(SH_XTRACE);
3357c2fbfb3SApril Chin 		}
3367c2fbfb3SApril Chin 		return(1);
3377c2fbfb3SApril Chin 	}
3387c2fbfb3SApril Chin 	return(0);
3397c2fbfb3SApril Chin }
3407c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
3417c2fbfb3SApril Chin 
3427c2fbfb3SApril Chin 
array_clone(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)343da2e3ebdSchin static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
344da2e3ebdSchin {
345da2e3ebdSchin 	Namarr_t		*ap = (Namarr_t*)fp;
346da2e3ebdSchin 	Namval_t		*nq, *mq;
347da2e3ebdSchin 	char			*name, *sub=0;
3487c2fbfb3SApril Chin 	int			nelem, skipped=0;
3497c2fbfb3SApril Chin 	Dt_t			*otable=ap->table;
3507c2fbfb3SApril Chin 	struct index_array	*aq = (struct index_array*)ap, *ar;
3517c2fbfb3SApril Chin 	Shell_t			*shp = sh_getinterp();
3527c2fbfb3SApril Chin 	if(flags&NV_MOVE)
3537c2fbfb3SApril Chin 	{
3547c2fbfb3SApril Chin 		if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
3557c2fbfb3SApril Chin 		{
3567c2fbfb3SApril Chin 			do
3577c2fbfb3SApril Chin 			{
3587c2fbfb3SApril Chin 				if(nq=nv_opensub(np))
3597c2fbfb3SApril Chin 					nq->nvenv = (void*)mp;
3607c2fbfb3SApril Chin 			}
3617c2fbfb3SApril Chin 			while(nv_nextsub(np));
3627c2fbfb3SApril Chin 		}
3637c2fbfb3SApril Chin 		return(fp);
3647c2fbfb3SApril Chin 	}
3657c2fbfb3SApril Chin 	nelem = ap->nelem;
366da2e3ebdSchin 	if(nelem&ARRAY_NOCLONE)
367da2e3ebdSchin 		return(0);
3687c2fbfb3SApril Chin 	if((flags&NV_TYPE) && !ap->scope)
369da2e3ebdSchin 	{
3707c2fbfb3SApril Chin 		ap = array_scope(np,ap,flags);
3717c2fbfb3SApril Chin 		return(&ap->hdr);
372da2e3ebdSchin 	}
3737c2fbfb3SApril Chin 	ap = (Namarr_t*)nv_clone_disc(fp,0);
3747c2fbfb3SApril Chin 	if(flags&NV_COMVAR)
3757c2fbfb3SApril Chin 	{
3767c2fbfb3SApril Chin 		ap->scope = 0;
3777c2fbfb3SApril Chin 		ap->nelem = 0;
3787c2fbfb3SApril Chin 		sh.prev_table = sh.last_table;
3797c2fbfb3SApril Chin 		sh.prev_root = sh.last_root;
3807c2fbfb3SApril Chin 	}
3817c2fbfb3SApril Chin 	if(ap->table)
3827c2fbfb3SApril Chin 	{
3837c2fbfb3SApril Chin 		ap->table = dtopen(&_Nvdisc,Dtoset);
3847c2fbfb3SApril Chin 		if(ap->scope && !(flags&NV_COMVAR))
3857c2fbfb3SApril Chin 		{
3867c2fbfb3SApril Chin 			ap->scope = ap->table;
3877c2fbfb3SApril Chin 			dtview(ap->table, otable->view);
3887c2fbfb3SApril Chin 		}
3897c2fbfb3SApril Chin 	}
3907c2fbfb3SApril Chin 	mp->nvfun = (Namfun_t*)ap;
3917c2fbfb3SApril Chin 	mp->nvflag &= NV_MINIMAL;
3927c2fbfb3SApril Chin 	mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
393da2e3ebdSchin 	if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
394da2e3ebdSchin 		sub = strdup(sub);
395da2e3ebdSchin 	ar = (struct index_array*)ap;
3967c2fbfb3SApril Chin 	if(!is_associative(ap))
3977c2fbfb3SApril Chin 		ar->bits = (unsigned char*)&ar->val[ar->maxi];
3987c2fbfb3SApril Chin 	if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
3997c2fbfb3SApril Chin 	{
4007c2fbfb3SApril Chin 		if(ap->fun)
4017c2fbfb3SApril Chin 			(*ap->fun)(np,(char*)np,0);
4027c2fbfb3SApril Chin 		skipped=1;
4037c2fbfb3SApril Chin 		goto skip;
4047c2fbfb3SApril Chin 	}
405da2e3ebdSchin 	do
406da2e3ebdSchin 	{
407da2e3ebdSchin 		name = nv_getsub(np);
4087c2fbfb3SApril Chin 		nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
4097c2fbfb3SApril Chin 		mq = 0;
4107c2fbfb3SApril Chin 		if(nq=nv_opensub(np))
4117c2fbfb3SApril Chin 			mq = nv_search(name,ap->table,NV_ADD);
4127c2fbfb3SApril Chin 		if(nq && (flags&NV_COMVAR) && nv_isvtree(nq))
413da2e3ebdSchin 		{
4147c2fbfb3SApril Chin 			mq->nvalue.cp = 0;
4157c2fbfb3SApril Chin 			if(!is_associative(ap))
4167c2fbfb3SApril Chin 				ar->val[ar->cur].np = mq;
4177c2fbfb3SApril Chin 			nv_clone(nq,mq,flags);
418da2e3ebdSchin 		}
4197c2fbfb3SApril Chin 		else if(flags&NV_ARRAY)
420da2e3ebdSchin 		{
4217c2fbfb3SApril Chin 			if((flags&NV_NOFREE) && !is_associative(ap))
4227c2fbfb3SApril Chin 				array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
4237c2fbfb3SApril Chin 			else if(nq && (flags&NV_NOFREE))
4247c2fbfb3SApril Chin 			{
4257c2fbfb3SApril Chin 				mq->nvalue = nq->nvalue;
4267c2fbfb3SApril Chin 				nv_onattr(nq,NV_NOFREE);
427da2e3ebdSchin 			}
428da2e3ebdSchin 		}
429da2e3ebdSchin 		else if(nv_isattr(np,NV_INTEGER))
430da2e3ebdSchin 		{
431da2e3ebdSchin 			Sfdouble_t d= nv_getnum(np);
4327c2fbfb3SApril Chin 			if(!is_associative(ap))
4337c2fbfb3SApril Chin 				ar->val[ar->cur].cp = 0;
434da2e3ebdSchin 			nv_putval(mp,(char*)&d,NV_LDOUBLE);
435da2e3ebdSchin 		}
436da2e3ebdSchin 		else
4377c2fbfb3SApril Chin 		{
4387c2fbfb3SApril Chin 			if(!is_associative(ap))
4397c2fbfb3SApril Chin 				ar->val[ar->cur].cp = 0;
440da2e3ebdSchin 			nv_putval(mp,nv_getval(np),NV_RDONLY);
441da2e3ebdSchin 		}
4427c2fbfb3SApril Chin 		aq->header.nelem |= ARRAY_NOSCOPE;
4437c2fbfb3SApril Chin 	}
444da2e3ebdSchin 	while(nv_nextsub(np));
4457c2fbfb3SApril Chin skip:
446da2e3ebdSchin 	if(sub)
447da2e3ebdSchin 	{
4487c2fbfb3SApril Chin 		if(!skipped)
449da2e3ebdSchin 			nv_putsub(np,sub,0L);
450da2e3ebdSchin 		free((void*)sub);
451da2e3ebdSchin 	}
4527c2fbfb3SApril Chin 	aq->header.nelem = ap->nelem = nelem;
4537c2fbfb3SApril Chin 	return(&ap->hdr);
454da2e3ebdSchin }
455da2e3ebdSchin 
array_getval(Namval_t * np,Namfun_t * disc)456da2e3ebdSchin static char *array_getval(Namval_t *np, Namfun_t *disc)
457da2e3ebdSchin {
4587c2fbfb3SApril Chin 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
459da2e3ebdSchin 	register Namval_t *mp;
460da2e3ebdSchin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
4617c2fbfb3SApril Chin 	{
4627c2fbfb3SApril Chin 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
4637c2fbfb3SApril Chin 		{
4647c2fbfb3SApril Chin 			array_syncsub(aq,ap);
4657c2fbfb3SApril Chin 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
4667c2fbfb3SApril Chin 				return(nv_getv(np,&aq->hdr));
4677c2fbfb3SApril Chin 		}
468da2e3ebdSchin 		return(mp?nv_getval(mp):0);
4697c2fbfb3SApril Chin 	}
470da2e3ebdSchin 	return(nv_getv(np,&ap->hdr));
471da2e3ebdSchin }
472da2e3ebdSchin 
array_getnum(Namval_t * np,Namfun_t * disc)473da2e3ebdSchin static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
474da2e3ebdSchin {
4757c2fbfb3SApril Chin 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
476da2e3ebdSchin 	register Namval_t *mp;
477da2e3ebdSchin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
4787c2fbfb3SApril Chin 	{
4797c2fbfb3SApril Chin 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
4807c2fbfb3SApril Chin 		{
4817c2fbfb3SApril Chin 			array_syncsub(aq,ap);
4827c2fbfb3SApril Chin 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
4837c2fbfb3SApril Chin 				return(nv_getn(np,&aq->hdr));
4847c2fbfb3SApril Chin 		}
485da2e3ebdSchin 		return(mp?nv_getnum(mp):0);
4867c2fbfb3SApril Chin 	}
487da2e3ebdSchin 	return(nv_getn(np,&ap->hdr));
488da2e3ebdSchin }
489da2e3ebdSchin 
array_putval(Namval_t * np,const char * string,int flags,Namfun_t * dp)490da2e3ebdSchin static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
491da2e3ebdSchin {
492da2e3ebdSchin 	register Namarr_t	*ap = (Namarr_t*)dp;
493da2e3ebdSchin 	register union Value	*up;
494da2e3ebdSchin 	register Namval_t	*mp;
495da2e3ebdSchin 	register struct index_array *aq = (struct index_array*)ap;
4967c2fbfb3SApril Chin 	int			scan,nofree = nv_isattr(np,NV_NOFREE);
497da2e3ebdSchin 	do
498da2e3ebdSchin 	{
499da2e3ebdSchin 		mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
5007c2fbfb3SApril Chin 		scan = ap->nelem&ARRAY_SCAN;
501da2e3ebdSchin 		if(mp && mp!=np)
5027c2fbfb3SApril Chin 		{
50334f9b3eeSRoland Mainz 			if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp))
5047c2fbfb3SApril Chin 			{
5057c2fbfb3SApril Chin 				if(!nv_isattr(np,NV_NOFREE))
5067c2fbfb3SApril Chin 					_nv_unset(mp,flags&NV_RDONLY);
5077c2fbfb3SApril Chin 				array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
5087c2fbfb3SApril Chin 				aq->val[aq->cur].cp = 0;
5097c2fbfb3SApril Chin 				if(!nv_isattr(mp,NV_NOFREE))
5107c2fbfb3SApril Chin 					nv_delete(mp,ap->table,0);
5117c2fbfb3SApril Chin 				goto skip;
5127c2fbfb3SApril Chin 			}
513da2e3ebdSchin 			nv_putval(mp, string, flags);
5147c2fbfb3SApril Chin 			if(string)
5157c2fbfb3SApril Chin 			{
5167c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5177c2fbfb3SApril Chin 				if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
5187c2fbfb3SApril Chin 					nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
5197c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
5207c2fbfb3SApril Chin 				continue;
5217c2fbfb3SApril Chin 			}
5227c2fbfb3SApril Chin 			ap->nelem |= scan;
5237c2fbfb3SApril Chin 		}
524da2e3ebdSchin 		if(!string)
525da2e3ebdSchin 		{
526da2e3ebdSchin 			if(mp)
527da2e3ebdSchin 			{
5287c2fbfb3SApril Chin 				if(is_associative(ap))
5297c2fbfb3SApril Chin 				{
5307c2fbfb3SApril Chin 					(*ap->fun)(np,NIL(char*),NV_ADELETE);
5317c2fbfb3SApril Chin 					np->nvalue.cp = 0;
5327c2fbfb3SApril Chin 				}
5337c2fbfb3SApril Chin 				else
5347c2fbfb3SApril Chin 				{
535da2e3ebdSchin 					if(mp!=np)
536da2e3ebdSchin 					{
5377c2fbfb3SApril Chin 						array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
538da2e3ebdSchin 						aq->val[aq->cur].cp = 0;
5397c2fbfb3SApril Chin 						nv_delete(mp,ap->table,0);
540da2e3ebdSchin 					}
5417c2fbfb3SApril Chin 					if(!array_covered(np,(struct index_array*)ap))
542da2e3ebdSchin 						ap->nelem--;
543da2e3ebdSchin 				}
5447c2fbfb3SApril Chin 			}
54534f9b3eeSRoland Mainz 			if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN))
546da2e3ebdSchin 			{
547da2e3ebdSchin 				if(is_associative(ap))
548da2e3ebdSchin 					(*ap->fun)(np, NIL(char*), NV_AFREE);
5497c2fbfb3SApril Chin 				else if(ap->table)
5507c2fbfb3SApril Chin 					dtclose(ap->table);
551da2e3ebdSchin 				nv_offattr(np,NV_ARRAY);
552da2e3ebdSchin 			}
5537c2fbfb3SApril Chin 			if(!mp || mp!=np || is_associative(ap))
554da2e3ebdSchin 				continue;
555da2e3ebdSchin 		}
5567c2fbfb3SApril Chin 	skip:
557da2e3ebdSchin 		/* prevent empty string from being deleted */
5587c2fbfb3SApril Chin 		up = array_getup(np,ap,!nofree);
5597c2fbfb3SApril Chin 		if(up->cp ==  Empty)
5607c2fbfb3SApril Chin 			up->cp = 0;
5617c2fbfb3SApril Chin 		if(nv_isarray(np))
5627c2fbfb3SApril Chin 			np->nvalue.up = up;
563da2e3ebdSchin 		nv_putv(np,string,flags,&ap->hdr);
5647c2fbfb3SApril Chin 		if(!is_associative(ap))
5657c2fbfb3SApril Chin 		{
5667c2fbfb3SApril Chin 			if(string)
5677c2fbfb3SApril Chin 				array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
5687c2fbfb3SApril Chin 			else if(mp==np)
5697c2fbfb3SApril Chin 				aq->val[aq->cur].cp = 0;
5707c2fbfb3SApril Chin 		}
5717c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5727c2fbfb3SApril Chin 		if(string && ap->hdr.type && nv_isvtree(np))
5737c2fbfb3SApril Chin 			nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
5747c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
575da2e3ebdSchin 	}
576da2e3ebdSchin 	while(!string && nv_nextsub(np));
5777c2fbfb3SApril Chin 	if(ap)
5787c2fbfb3SApril Chin 		ap->nelem &= ~ARRAY_NOSCOPE;
5797c2fbfb3SApril Chin 	if(nofree)
5807c2fbfb3SApril Chin 		nv_onattr(np,NV_NOFREE);
5817c2fbfb3SApril Chin 	else
5827c2fbfb3SApril Chin 		nv_offattr(np,NV_NOFREE);
583da2e3ebdSchin 	if(!string && !nv_isattr(np,NV_ARRAY))
584da2e3ebdSchin 	{
585da2e3ebdSchin 		Namfun_t *nfp;
5867c2fbfb3SApril Chin 		if(!is_associative(ap) && aq->xp)
5877c2fbfb3SApril Chin 		{
5887c2fbfb3SApril Chin 			_nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
5897c2fbfb3SApril Chin 			free((void*)aq->xp);
590da2e3ebdSchin 		}
5917c2fbfb3SApril Chin 		if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
5927c2fbfb3SApril Chin 			free((void*)nfp);
5937c2fbfb3SApril Chin 		if(!nv_isnull(np))
5947c2fbfb3SApril Chin 		{
5957c2fbfb3SApril Chin 			nv_onattr(np,NV_NOFREE);
5967c2fbfb3SApril Chin 			_nv_unset(np,flags);
5977c2fbfb3SApril Chin 		}
5987c2fbfb3SApril Chin 		if(np->nvalue.cp==Empty)
5997c2fbfb3SApril Chin 			np->nvalue.cp = 0;
6007c2fbfb3SApril Chin 	}
6017c2fbfb3SApril Chin 	if(!string && (flags&NV_TYPE))
6027c2fbfb3SApril Chin 		array_unscope(np,ap);
603da2e3ebdSchin }
604da2e3ebdSchin 
605da2e3ebdSchin static const Namdisc_t array_disc =
606da2e3ebdSchin {
607da2e3ebdSchin 	sizeof(Namarr_t),
608da2e3ebdSchin 	array_putval,
609da2e3ebdSchin 	array_getval,
610da2e3ebdSchin 	array_getnum,
611da2e3ebdSchin 	0,
612da2e3ebdSchin 	0,
613da2e3ebdSchin 	array_clone
614da2e3ebdSchin };
615da2e3ebdSchin 
array_copytree(Namval_t * np,Namval_t * mp)6167c2fbfb3SApril Chin static void array_copytree(Namval_t *np, Namval_t *mp)
6177c2fbfb3SApril Chin {
6187c2fbfb3SApril Chin 	Namfun_t	*fp = nv_disc(np,NULL,NV_POP);
6197c2fbfb3SApril Chin 	nv_offattr(np,NV_ARRAY);
6207c2fbfb3SApril Chin 	nv_clone(np,mp,0);
62134f9b3eeSRoland Mainz 	if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE))
62234f9b3eeSRoland Mainz 		free((void*)np->nvalue.cp);
62334f9b3eeSRoland Mainz 	np->nvalue.cp = 0;
6247c2fbfb3SApril Chin 	np->nvalue.up = &mp->nvalue;
6257c2fbfb3SApril Chin 	fp->nofree  &= ~1;
6267c2fbfb3SApril Chin 	nv_disc(np,(Namfun_t*)fp, NV_FIRST);
6277c2fbfb3SApril Chin 	fp->nofree |= 1;
6287c2fbfb3SApril Chin 	nv_onattr(np,NV_ARRAY);
6297c2fbfb3SApril Chin 	mp->nvenv = (char*)np;
6307c2fbfb3SApril Chin }
6317c2fbfb3SApril Chin 
632da2e3ebdSchin /*
633da2e3ebdSchin  *        Increase the size of the indexed array of elements in <arp>
634da2e3ebdSchin  *        so that <maxi> is a legal index.  If <arp> is 0, an array
635da2e3ebdSchin  *        of the required size is allocated.  A pointer to the
636da2e3ebdSchin  *        allocated Namarr_t structure is returned.
637da2e3ebdSchin  *        <maxi> becomes the current index of the array.
638da2e3ebdSchin  */
array_grow(Namval_t * np,register struct index_array * arp,int maxi)639da2e3ebdSchin static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
640da2e3ebdSchin {
641da2e3ebdSchin 	register struct index_array *ap;
6427c2fbfb3SApril Chin 	register int i;
6437c2fbfb3SApril Chin 	register int newsize = arsize(arp,maxi+1);
644da2e3ebdSchin 	if (maxi >= ARRAY_MAX)
645da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
6467c2fbfb3SApril Chin 	i = (newsize-1)*sizeof(union Value*)+newsize;
6477c2fbfb3SApril Chin 	ap = new_of(struct index_array,i);
6487c2fbfb3SApril Chin 	memset((void*)ap,0,sizeof(*ap)+i);
649da2e3ebdSchin 	ap->maxi = newsize;
650da2e3ebdSchin 	ap->cur = maxi;
651da2e3ebdSchin 	ap->bits =  (unsigned char*)&ap->val[newsize];
6527c2fbfb3SApril Chin 	memset(ap->bits, 0, newsize);
653da2e3ebdSchin 	if(arp)
654da2e3ebdSchin 	{
655da2e3ebdSchin 		ap->header = arp->header;
6567c2fbfb3SApril Chin 		ap->header.hdr.dsize = sizeof(*ap) + i;
6577c2fbfb3SApril Chin 		for(i=0;i < arp->maxi;i++)
658da2e3ebdSchin 			ap->val[i].cp = arp->val[i].cp;
6597c2fbfb3SApril Chin 		memcpy(ap->bits, arp->bits, arp->maxi);
660da2e3ebdSchin 		array_setptr(np,arp,ap);
661da2e3ebdSchin 		free((void*)arp);
662da2e3ebdSchin 	}
663da2e3ebdSchin 	else
664da2e3ebdSchin 	{
6657c2fbfb3SApril Chin 		Namval_t *mp=0;
6667c2fbfb3SApril Chin 		ap->header.hdr.dsize = sizeof(*ap) + i;
6677c2fbfb3SApril Chin 		i = 0;
668da2e3ebdSchin 		ap->header.fun = 0;
6697c2fbfb3SApril Chin 		if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
670da2e3ebdSchin 		{
6717c2fbfb3SApril Chin 			i = ARRAY_TREE;
6727c2fbfb3SApril Chin 			nv_offattr(np,NV_NOFREE);
6737c2fbfb3SApril Chin 		}
6747c2fbfb3SApril Chin 		if(np->nvalue.cp==Empty)
6757c2fbfb3SApril Chin 			np->nvalue.cp=0;
6767c2fbfb3SApril Chin 		if(nv_hasdisc(np,&array_disc) || nv_isvtree(np))
6777c2fbfb3SApril Chin 		{
6787c2fbfb3SApril Chin 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
67934f9b3eeSRoland Mainz 			mp = nv_search("0", ap->header.table,NV_ADD);
680da2e3ebdSchin 			if(mp && nv_isnull(mp))
681da2e3ebdSchin 			{
6827c2fbfb3SApril Chin 				Namfun_t *fp;
683da2e3ebdSchin 				ap->val[0].np = mp;
6847c2fbfb3SApril Chin 				array_setbit(ap->bits,0,ARRAY_CHILD);
6857c2fbfb3SApril Chin 				for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
68634f9b3eeSRoland Mainz 				if(fp && fp->disc && fp->disc->readf)
6877c2fbfb3SApril Chin 					(*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
688da2e3ebdSchin 				i++;
689da2e3ebdSchin 			}
6907c2fbfb3SApril Chin 		}
6917c2fbfb3SApril Chin 		else if((ap->val[0].cp=np->nvalue.cp))
6927c2fbfb3SApril Chin 			i++;
69334f9b3eeSRoland Mainz 		else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np))
694da2e3ebdSchin 		{
695da2e3ebdSchin 			Sfdouble_t d= nv_getnum(np);
696da2e3ebdSchin 			i++;
697da2e3ebdSchin 		}
698da2e3ebdSchin 		ap->header.nelem = i;
699da2e3ebdSchin 		ap->header.hdr.disc = &array_disc;
7007c2fbfb3SApril Chin 		nv_disc(np,(Namfun_t*)ap, NV_FIRST);
7017c2fbfb3SApril Chin 		nv_onattr(np,NV_ARRAY);
7027c2fbfb3SApril Chin 		if(mp)
7037c2fbfb3SApril Chin 		{
7047c2fbfb3SApril Chin 			array_copytree(np,mp);
7057c2fbfb3SApril Chin 			ap->header.hdr.nofree &= ~1;
7067c2fbfb3SApril Chin 		}
707da2e3ebdSchin 	}
708da2e3ebdSchin 	for(;i < newsize;i++)
709da2e3ebdSchin 		ap->val[i].cp = 0;
710da2e3ebdSchin 	return(ap);
711da2e3ebdSchin }
712da2e3ebdSchin 
nv_atypeindex(Namval_t * np,const char * tname)7137c2fbfb3SApril Chin int nv_atypeindex(Namval_t *np, const char *tname)
7147c2fbfb3SApril Chin {
7157c2fbfb3SApril Chin 	Namval_t	*tp;
7167c2fbfb3SApril Chin 	int		offset = staktell();
7177c2fbfb3SApril Chin 	int		n = strlen(tname)-1;
7187c2fbfb3SApril Chin 	sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
7197c2fbfb3SApril Chin 	tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
7207c2fbfb3SApril Chin 	stakseek(offset);
7217c2fbfb3SApril Chin 	if(tp)
7227c2fbfb3SApril Chin 	{
7237c2fbfb3SApril Chin 		struct index_array *ap = (struct index_array*)nv_arrayptr(np);
7247c2fbfb3SApril Chin 		if(!nv_hasdisc(tp,&ENUM_disc))
7257c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
7267c2fbfb3SApril Chin 		if(!ap)
7277c2fbfb3SApril Chin 			ap = array_grow(np,ap,1);
7287c2fbfb3SApril Chin 		ap->xp = calloc(NV_MINSZ,1);
7297c2fbfb3SApril Chin 		np = nv_namptr(ap->xp,0);
7307c2fbfb3SApril Chin 		np->nvname = tp->nvname;
7317c2fbfb3SApril Chin 		nv_onattr(np,NV_MINIMAL);
7327c2fbfb3SApril Chin 		nv_clone(tp,np,NV_NOFREE);
7337c2fbfb3SApril Chin 		nv_offattr(np,NV_RDONLY);
7347c2fbfb3SApril Chin 		return(1);
7357c2fbfb3SApril Chin 	}
7367c2fbfb3SApril Chin 	errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
7377c2fbfb3SApril Chin 	return(0);
7387c2fbfb3SApril Chin }
7397c2fbfb3SApril Chin 
nv_arrayptr(register Namval_t * np)740da2e3ebdSchin Namarr_t *nv_arrayptr(register Namval_t *np)
741da2e3ebdSchin {
742da2e3ebdSchin 	if(nv_isattr(np,NV_ARRAY))
743da2e3ebdSchin 		return((Namarr_t*)nv_hasdisc(np, &array_disc));
744da2e3ebdSchin 	return(0);
745da2e3ebdSchin }
746da2e3ebdSchin 
747da2e3ebdSchin /*
748da2e3ebdSchin  * Verify that argument is an indexed array and convert to associative,
749da2e3ebdSchin  * freeing relevant storage
750da2e3ebdSchin  */
nv_changearray(Namval_t * np,void * (* fun)(Namval_t *,const char *,int))751da2e3ebdSchin static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
752da2e3ebdSchin {
753da2e3ebdSchin 	register Namarr_t *ap;
754da2e3ebdSchin 	char numbuff[NUMSIZE+1];
755da2e3ebdSchin 	unsigned dot, digit, n;
756da2e3ebdSchin 	union Value *up;
757da2e3ebdSchin 	struct index_array *save_ap;
758da2e3ebdSchin 	register char *string_index=&numbuff[NUMSIZE];
759da2e3ebdSchin 	numbuff[NUMSIZE]='\0';
760da2e3ebdSchin 
761da2e3ebdSchin 	if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
762da2e3ebdSchin 		return(NIL(Namarr_t*));
763da2e3ebdSchin 
764da2e3ebdSchin 	nv_stack(np,&ap->hdr);
765da2e3ebdSchin 	save_ap = (struct index_array*)nv_stack(np,0);
766da2e3ebdSchin 	ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
767da2e3ebdSchin 	ap->nelem = 0;
768da2e3ebdSchin 	ap->fun = fun;
769da2e3ebdSchin 	nv_onattr(np,NV_ARRAY);
770da2e3ebdSchin 
771da2e3ebdSchin 	for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
772da2e3ebdSchin 	{
773da2e3ebdSchin 		if(save_ap->val[dot].cp)
774da2e3ebdSchin 		{
775da2e3ebdSchin 			if ((digit = dot)== 0)
776da2e3ebdSchin 				*--string_index = '0';
777da2e3ebdSchin 			else while( n = digit )
778da2e3ebdSchin 			{
779da2e3ebdSchin 				digit /= 10;
780da2e3ebdSchin 				*--string_index = '0' + (n-10*digit);
781da2e3ebdSchin 			}
782da2e3ebdSchin 			nv_putsub(np, string_index, ARRAY_ADD);
783da2e3ebdSchin 			up = (union Value*)((*ap->fun)(np,NIL(char*),0));
784da2e3ebdSchin 			up->cp = save_ap->val[dot].cp;
785da2e3ebdSchin 			save_ap->val[dot].cp = 0;
786da2e3ebdSchin 		}
787da2e3ebdSchin 		string_index = &numbuff[NUMSIZE];
788da2e3ebdSchin 	}
789da2e3ebdSchin 	free((void*)save_ap);
790da2e3ebdSchin 	return(ap);
791da2e3ebdSchin }
792da2e3ebdSchin 
793da2e3ebdSchin /*
794da2e3ebdSchin  * set the associative array processing method for node <np> to <fun>
795da2e3ebdSchin  * The array pointer is returned if sucessful.
796da2e3ebdSchin  */
nv_setarray(Namval_t * np,void * (* fun)(Namval_t *,const char *,int))797da2e3ebdSchin Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
798da2e3ebdSchin {
799da2e3ebdSchin 	register Namarr_t *ap;
8007c2fbfb3SApril Chin 	char		*value=0;
8017c2fbfb3SApril Chin 	Namfun_t	*fp;
8027c2fbfb3SApril Chin 	int		nelem = 0;
803da2e3ebdSchin 	if(fun && (ap = nv_arrayptr(np)))
804da2e3ebdSchin 	{
805da2e3ebdSchin 		/*
806da2e3ebdSchin 		 * if it's already an indexed array, convert to
807da2e3ebdSchin 		 * associative structure
808da2e3ebdSchin 		 */
809da2e3ebdSchin 		if(!is_associative(ap))
810da2e3ebdSchin 			ap = nv_changearray(np, fun);
811da2e3ebdSchin 		return(ap);
812da2e3ebdSchin 	}
8137c2fbfb3SApril Chin 	if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
8147c2fbfb3SApril Chin 	{
8157c2fbfb3SApril Chin 		nelem = ARRAY_TREE;
8167c2fbfb3SApril Chin 		nv_offattr(np,NV_NOFREE);
8177c2fbfb3SApril Chin 	}
8187c2fbfb3SApril Chin 	if(!(fp=nv_isvtree(np)))
819da2e3ebdSchin 		value = nv_getval(np);
820da2e3ebdSchin 	if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
821da2e3ebdSchin 	{
822da2e3ebdSchin 		/* check for preexisting initialization and save */
8237c2fbfb3SApril Chin 		ap->nelem = nelem;
824da2e3ebdSchin 		ap->fun = fun;
825da2e3ebdSchin 		nv_onattr(np,NV_ARRAY);
8267c2fbfb3SApril Chin 		if(fp || value)
827da2e3ebdSchin 		{
828da2e3ebdSchin 			nv_putsub(np, "0", ARRAY_ADD);
8297c2fbfb3SApril Chin 			if(value)
830da2e3ebdSchin 				nv_putval(np, value, 0);
8317c2fbfb3SApril Chin 			else
8327c2fbfb3SApril Chin 			{
8337c2fbfb3SApril Chin 				Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
8347c2fbfb3SApril Chin 				array_copytree(np,mp);
8357c2fbfb3SApril Chin 			}
836da2e3ebdSchin 		}
837da2e3ebdSchin 		return(ap);
838da2e3ebdSchin 	}
839da2e3ebdSchin 	return(NIL(Namarr_t*));
840da2e3ebdSchin }
841da2e3ebdSchin 
842da2e3ebdSchin /*
843da2e3ebdSchin  * move parent subscript into child
844da2e3ebdSchin  */
nv_arraychild(Namval_t * np,Namval_t * nq,int c)845da2e3ebdSchin Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
846da2e3ebdSchin {
8477c2fbfb3SApril Chin 	Namfun_t		*fp;
848da2e3ebdSchin 	register Namarr_t	*ap = nv_arrayptr(np);
849da2e3ebdSchin 	union Value		*up;
8507c2fbfb3SApril Chin 	Namval_t		*tp;
851da2e3ebdSchin 	if(!nq)
8527c2fbfb3SApril Chin 		return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
8537c2fbfb3SApril Chin 	if(!ap)
8547c2fbfb3SApril Chin 	{
8557c2fbfb3SApril Chin 		nv_putsub(np, NIL(char*), ARRAY_FILL);
8567c2fbfb3SApril Chin 		ap = nv_arrayptr(np);
8577c2fbfb3SApril Chin 	}
8587c2fbfb3SApril Chin 	if(!(up = array_getup(np,ap,0)))
8597c2fbfb3SApril Chin 		return((Namval_t*)0);
860da2e3ebdSchin 	np->nvalue.cp = up->cp;
8617c2fbfb3SApril Chin 	if((tp=nv_type(np)) || c)
8627c2fbfb3SApril Chin 	{
863da2e3ebdSchin 		ap->nelem |= ARRAY_NOCLONE;
8647c2fbfb3SApril Chin 		nq->nvenv = (char*)np;
8657c2fbfb3SApril Chin 		if(c=='t')
8667c2fbfb3SApril Chin 			nv_clone(tp,nq, 0);
8677c2fbfb3SApril Chin 		else
868da2e3ebdSchin 			nv_clone(np, nq, NV_NODISC);
869da2e3ebdSchin 		nv_offattr(nq,NV_ARRAY);
870da2e3ebdSchin 		ap->nelem &= ~ARRAY_NOCLONE;
871da2e3ebdSchin 	}
8727c2fbfb3SApril Chin 	nq->nvenv = (char*)np;
8737c2fbfb3SApril Chin 	if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
8747c2fbfb3SApril Chin 		free((void*)fp);
8757c2fbfb3SApril Chin 	if(!ap->fun)
876da2e3ebdSchin 	{
877da2e3ebdSchin 		struct index_array *aq = (struct index_array*)ap;
8787c2fbfb3SApril Chin 		array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
879da2e3ebdSchin 		up->np = nq;
880da2e3ebdSchin 	}
881da2e3ebdSchin 	if(c=='.')
882da2e3ebdSchin 		nv_setvtree(nq);
883da2e3ebdSchin 	return(nq);
884da2e3ebdSchin }
885da2e3ebdSchin 
886da2e3ebdSchin /*
887da2e3ebdSchin  * This routine sets subscript of <np> to the next element, if any.
888da2e3ebdSchin  * The return value is zero, if there are no more elements
889da2e3ebdSchin  * Otherwise, 1 is returned.
890da2e3ebdSchin  */
nv_nextsub(Namval_t * np)891da2e3ebdSchin int nv_nextsub(Namval_t *np)
892da2e3ebdSchin {
893da2e3ebdSchin 	register struct index_array	*ap = (struct index_array*)nv_arrayptr(np);
894da2e3ebdSchin 	register unsigned		dot;
8957c2fbfb3SApril Chin 	struct index_array		*aq=0, *ar=0;
896da2e3ebdSchin 	if(!ap || !(ap->header.nelem&ARRAY_SCAN))
897da2e3ebdSchin 		return(0);
898da2e3ebdSchin 	if(is_associative(ap))
899da2e3ebdSchin 	{
9007c2fbfb3SApril Chin 		Namval_t	*nq;
9017c2fbfb3SApril Chin 		if(nq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT))
902da2e3ebdSchin 		{
9037c2fbfb3SApril Chin 			if(nv_isattr(nq,NV_CHILD))
9047c2fbfb3SApril Chin 				nv_putsub(nq->nvalue.np,NIL(char*),ARRAY_UNDEF);
905da2e3ebdSchin 			return(1);
906da2e3ebdSchin 		}
907da2e3ebdSchin 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
908da2e3ebdSchin 		return(0);
909da2e3ebdSchin 	}
9107c2fbfb3SApril Chin 	if(!(ap->header.nelem&ARRAY_NOSCOPE))
9117c2fbfb3SApril Chin 		ar = (struct index_array*)ap->header.scope;
912da2e3ebdSchin 	for(dot=ap->cur+1; dot <  (unsigned)ap->maxi; dot++)
913da2e3ebdSchin 	{
9147c2fbfb3SApril Chin 		aq = ap;
9157c2fbfb3SApril Chin 		if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
9167c2fbfb3SApril Chin 		{
9177c2fbfb3SApril Chin 			if(!(aq=ar) || dot>=(unsigned)aq->maxi)
9187c2fbfb3SApril Chin 				continue;
9197c2fbfb3SApril Chin 		}
9207c2fbfb3SApril Chin 		if(aq->val[dot].cp)
921da2e3ebdSchin 		{
922da2e3ebdSchin 			ap->cur = dot;
9237c2fbfb3SApril Chin 			if(array_isbit(aq->bits, dot,ARRAY_CHILD))
924da2e3ebdSchin 			{
9257c2fbfb3SApril Chin 				Namval_t *mp = aq->val[dot].np;
926*3e14f97fSRoger A. Faulkner 				if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize)
927da2e3ebdSchin 					continue;
928*3e14f97fSRoger A. Faulkner 				if(nv_isarray(mp))
9297c2fbfb3SApril Chin 					nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
930da2e3ebdSchin 			}
931da2e3ebdSchin 			return(1);
932da2e3ebdSchin 		}
933da2e3ebdSchin 	}
934da2e3ebdSchin 	ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
935da2e3ebdSchin 	ap->cur = 0;
936da2e3ebdSchin 	return(0);
937da2e3ebdSchin }
938da2e3ebdSchin 
939da2e3ebdSchin /*
940da2e3ebdSchin  * Set an array subscript for node <np> given the subscript <sp>
941da2e3ebdSchin  * An array is created if necessary.
942da2e3ebdSchin  * <mode> can be a number, plus or more of symbolic constants
943da2e3ebdSchin  *    ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
944da2e3ebdSchin  * The node pointer is returned which can be NULL if <np> is
945da2e3ebdSchin  *    not already array and the ARRAY_ADD bit of <mode> is not set.
946da2e3ebdSchin  * ARRAY_FILL sets the specified subscript to the empty string when
947da2e3ebdSchin  *   ARRAY_ADD is specified and there is no value or sets all
948da2e3ebdSchin  * the elements up to the number specified if ARRAY_ADD is not specified
949da2e3ebdSchin  */
nv_putsub(Namval_t * np,register char * sp,register long mode)950da2e3ebdSchin Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
951da2e3ebdSchin {
952da2e3ebdSchin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
953da2e3ebdSchin 	register int size = (mode&ARRAY_MASK);
954da2e3ebdSchin 	if(!ap || !ap->header.fun)
955da2e3ebdSchin 	{
956da2e3ebdSchin 		if(sp)
9577c2fbfb3SApril Chin 		{
9587c2fbfb3SApril Chin 			if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
9597c2fbfb3SApril Chin 			{
9607c2fbfb3SApril Chin 				Namval_t *mp = nv_namptr(ap->xp,0);
9617c2fbfb3SApril Chin 				nv_putval(mp, sp,0);
9627c2fbfb3SApril Chin 				size = nv_getnum(mp);
9637c2fbfb3SApril Chin 			}
9647c2fbfb3SApril Chin 			else
965da2e3ebdSchin 				size = (int)sh_arith((char*)sp);
9667c2fbfb3SApril Chin 		}
9677c2fbfb3SApril Chin 		if(size <0 && ap)
9687c2fbfb3SApril Chin 			size += array_maxindex(np);
969da2e3ebdSchin 		if(size >= ARRAY_MAX || (size < 0))
970da2e3ebdSchin 		{
971da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
972da2e3ebdSchin 			return(NIL(Namval_t*));
973da2e3ebdSchin 		}
974da2e3ebdSchin 		if(!ap || size>=ap->maxi)
975da2e3ebdSchin 		{
976da2e3ebdSchin 			if(size==0 && !(mode&ARRAY_FILL))
977da2e3ebdSchin 				return(NIL(Namval_t*));
978da2e3ebdSchin 			if(sh.subshell)
979da2e3ebdSchin 				np = sh_assignok(np,1);
980da2e3ebdSchin 			ap = array_grow(np, ap,size);
981da2e3ebdSchin 		}
982da2e3ebdSchin 		ap->header.nelem &= ~ARRAY_UNDEF;
9837c2fbfb3SApril Chin 		ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
9847c2fbfb3SApril Chin #if 0
9857c2fbfb3SApril Chin 		if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
9867c2fbfb3SApril Chin 			mp = ap->val[oldsize].np;
9877c2fbfb3SApril Chin 		if(size != oldsize && mp->nvalue.cp)
9887c2fbfb3SApril Chin 		{
9897c2fbfb3SApril Chin 			Namfun_t *nfp;
9907c2fbfb3SApril Chin 			for(nfp=np->nvfun; nfp; nfp=nfp->next)
9917c2fbfb3SApril Chin 			{
9927c2fbfb3SApril Chin 				if(nfp->disc && nfp->disc->readf)
9937c2fbfb3SApril Chin 				{
9947c2fbfb3SApril Chin 					(*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
9957c2fbfb3SApril Chin 					break;
9967c2fbfb3SApril Chin 				}
9977c2fbfb3SApril Chin 			}
9987c2fbfb3SApril Chin 		}
9997c2fbfb3SApril Chin #endif
1000da2e3ebdSchin 		ap->cur = size;
10017c2fbfb3SApril Chin 		if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
1002da2e3ebdSchin 			np = 0;
10037c2fbfb3SApril Chin 		if(mode&(ARRAY_FILL|ARRAY_ADD))
1004da2e3ebdSchin 		{
1005da2e3ebdSchin 			if(!(mode&ARRAY_ADD))
1006da2e3ebdSchin 			{
1007da2e3ebdSchin 				int n;
10087c2fbfb3SApril Chin 				for(n=0; n <= size; n++)
1009da2e3ebdSchin 				{
1010da2e3ebdSchin 					if(!ap->val[n].cp)
10117c2fbfb3SApril Chin 					{
1012da2e3ebdSchin 						ap->val[n].cp = Empty;
10137c2fbfb3SApril Chin 						if(!array_covered(np,ap))
10147c2fbfb3SApril Chin 							ap->header.nelem++;
1015da2e3ebdSchin 					}
10167c2fbfb3SApril Chin 				}
1017da2e3ebdSchin 				if(n=ap->maxi-ap->maxi)
1018da2e3ebdSchin 					memset(&ap->val[size],0,n*sizeof(union Value));
1019da2e3ebdSchin 			}
1020da2e3ebdSchin 			else if(!ap->val[size].cp)
1021da2e3ebdSchin 			{
1022da2e3ebdSchin 				if(sh.subshell)
1023da2e3ebdSchin 					np = sh_assignok(np,1);
1024da2e3ebdSchin 				ap->val[size].cp = Empty;
10257c2fbfb3SApril Chin 				if(!array_covered(np,ap))
1026da2e3ebdSchin 					ap->header.nelem++;
1027da2e3ebdSchin 			}
1028da2e3ebdSchin 		}
1029da2e3ebdSchin 		else if(!(mode&ARRAY_SCAN))
1030da2e3ebdSchin 		{
1031da2e3ebdSchin 			ap->header.nelem &= ~ARRAY_SCAN;
10327c2fbfb3SApril Chin 			if(array_isbit(ap->bits,size,ARRAY_CHILD))
1033da2e3ebdSchin 				nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
10347c2fbfb3SApril Chin 			if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
10357c2fbfb3SApril Chin 				np = 0;
1036da2e3ebdSchin 		}
1037da2e3ebdSchin 		return((Namval_t*)np);
1038da2e3ebdSchin 	}
1039da2e3ebdSchin 	ap->header.nelem &= ~ARRAY_UNDEF;
1040da2e3ebdSchin 	if(!(mode&ARRAY_FILL))
1041da2e3ebdSchin 		ap->header.nelem &= ~ARRAY_SCAN;
10427c2fbfb3SApril Chin 	ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1043da2e3ebdSchin 	if(sp)
1044da2e3ebdSchin 	{
1045da2e3ebdSchin 		if(mode&ARRAY_SETSUB)
1046da2e3ebdSchin 		{
1047da2e3ebdSchin 			(*ap->header.fun)(np, sp, NV_ASETSUB);
1048da2e3ebdSchin 			return(np);
1049da2e3ebdSchin 		}
10507c2fbfb3SApril Chin 		(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
10517c2fbfb3SApril Chin 		if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
10527c2fbfb3SApril Chin 			np = 0;
1053da2e3ebdSchin 	}
1054da2e3ebdSchin 	else if(mode&ARRAY_SCAN)
1055da2e3ebdSchin 		(*ap->header.fun)(np,(char*)np,0);
1056da2e3ebdSchin 	else if(mode&ARRAY_UNDEF)
1057da2e3ebdSchin 		(*ap->header.fun)(np, "",0);
1058da2e3ebdSchin 	if((mode&ARRAY_SCAN) && !nv_nextsub(np))
1059da2e3ebdSchin 		np = 0;
1060da2e3ebdSchin 	return(np);
1061da2e3ebdSchin }
1062da2e3ebdSchin 
1063da2e3ebdSchin /*
1064da2e3ebdSchin  * process an array subscript for node <np> given the subscript <cp>
1065da2e3ebdSchin  * returns pointer to character after the subscript
1066da2e3ebdSchin  */
nv_endsubscript(Namval_t * np,register char * cp,int mode)1067da2e3ebdSchin char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
1068da2e3ebdSchin {
1069da2e3ebdSchin 	register int count=1, quoted=0, c;
1070da2e3ebdSchin 	register char *sp = cp+1;
1071da2e3ebdSchin 	/* first find matching ']' */
1072da2e3ebdSchin 	while(count>0 && (c= *++cp))
1073da2e3ebdSchin 	{
1074da2e3ebdSchin 		if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
1075da2e3ebdSchin 		{
1076da2e3ebdSchin 			quoted=1;
1077da2e3ebdSchin 			cp++;
1078da2e3ebdSchin 		}
1079da2e3ebdSchin 		else if(c=='[')
1080da2e3ebdSchin 			count++;
1081da2e3ebdSchin 		else if(c==']')
1082da2e3ebdSchin 			count--;
1083da2e3ebdSchin 	}
1084da2e3ebdSchin 	*cp = 0;
1085da2e3ebdSchin 	if(quoted)
1086da2e3ebdSchin 	{
1087da2e3ebdSchin 		/* strip escape characters */
1088da2e3ebdSchin 		count = staktell();
1089da2e3ebdSchin 		stakwrite(sp,1+cp-sp);
1090da2e3ebdSchin 		sh_trim(sp=stakptr(count));
1091da2e3ebdSchin 	}
1092da2e3ebdSchin 	if(mode && np)
10937c2fbfb3SApril Chin 	{
109434f9b3eeSRoland Mainz 		Namarr_t *ap = nv_arrayptr(np);
109534f9b3eeSRoland Mainz 		int scan = 0;
109634f9b3eeSRoland Mainz 		if(ap)
109734f9b3eeSRoland Mainz 			scan = ap->nelem&ARRAY_SCAN;
10987c2fbfb3SApril Chin 		if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
10997c2fbfb3SApril Chin 			mode |= NV_ADD;
11007c2fbfb3SApril Chin 		nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
110134f9b3eeSRoland Mainz 		if(scan)
110234f9b3eeSRoland Mainz 			ap->nelem |= scan;
11037c2fbfb3SApril Chin 	}
1104da2e3ebdSchin 	if(quoted)
1105da2e3ebdSchin 		stakseek(count);
1106da2e3ebdSchin 	*cp++ = c;
1107da2e3ebdSchin 	return(cp);
1108da2e3ebdSchin }
1109da2e3ebdSchin 
1110da2e3ebdSchin 
nv_opensub(Namval_t * np)1111da2e3ebdSchin Namval_t *nv_opensub(Namval_t* np)
1112da2e3ebdSchin {
1113da2e3ebdSchin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
11147c2fbfb3SApril Chin 	if(ap)
11157c2fbfb3SApril Chin 	{
11167c2fbfb3SApril Chin 		if(is_associative(ap))
1117da2e3ebdSchin 			return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
11187c2fbfb3SApril Chin 		else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
11197c2fbfb3SApril Chin 			return(ap->val[ap->cur].np);
11207c2fbfb3SApril Chin 	}
1121da2e3ebdSchin 	return(NIL(Namval_t*));
1122da2e3ebdSchin }
1123da2e3ebdSchin 
nv_getsub(Namval_t * np)1124da2e3ebdSchin char	*nv_getsub(Namval_t* np)
1125da2e3ebdSchin {
1126da2e3ebdSchin 	static char numbuff[NUMSIZE];
1127da2e3ebdSchin 	register struct index_array *ap;
1128da2e3ebdSchin 	register unsigned dot, n;
1129da2e3ebdSchin 	register char *cp = &numbuff[NUMSIZE];
1130da2e3ebdSchin 	if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
1131da2e3ebdSchin 		return(NIL(char*));
1132da2e3ebdSchin 	if(is_associative(ap))
1133da2e3ebdSchin 		return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
11347c2fbfb3SApril Chin 	if(ap->xp)
11357c2fbfb3SApril Chin 	{
11367c2fbfb3SApril Chin 		np = nv_namptr(ap->xp,0);
11377c2fbfb3SApril Chin 		np->nvalue.s = ap->cur;
11387c2fbfb3SApril Chin 		return(nv_getval(np));
11397c2fbfb3SApril Chin 	}
1140da2e3ebdSchin 	if((dot = ap->cur)==0)
1141da2e3ebdSchin 		*--cp = '0';
1142da2e3ebdSchin 	else while(n=dot)
1143da2e3ebdSchin 	{
1144da2e3ebdSchin 		dot /= 10;
1145da2e3ebdSchin 		*--cp = '0' + (n-10*dot);
1146da2e3ebdSchin 	}
1147da2e3ebdSchin 	return(cp);
1148da2e3ebdSchin }
1149da2e3ebdSchin 
1150da2e3ebdSchin /*
1151da2e3ebdSchin  * If <np> is an indexed array node, the current subscript index
1152da2e3ebdSchin  * returned, otherwise returns -1
1153da2e3ebdSchin  */
nv_aindex(register Namval_t * np)1154da2e3ebdSchin int nv_aindex(register Namval_t* np)
1155da2e3ebdSchin {
1156da2e3ebdSchin 	Namarr_t *ap = nv_arrayptr(np);
11577c2fbfb3SApril Chin 	if(!ap)
11587c2fbfb3SApril Chin 		return(0);
11597c2fbfb3SApril Chin 	else if(is_associative(ap))
1160da2e3ebdSchin 		return(-1);
1161da2e3ebdSchin 	return(((struct index_array*)(ap))->cur&ARRAY_MASK);
1162da2e3ebdSchin }
1163da2e3ebdSchin 
nv_arraynsub(register Namarr_t * ap)11647c2fbfb3SApril Chin int nv_arraynsub(register Namarr_t* ap)
11657c2fbfb3SApril Chin {
11667c2fbfb3SApril Chin 	return(array_elem(ap));
11677c2fbfb3SApril Chin }
11687c2fbfb3SApril Chin 
nv_aimax(register Namval_t * np)11697c2fbfb3SApril Chin int nv_aimax(register Namval_t* np)
11707c2fbfb3SApril Chin {
11717c2fbfb3SApril Chin 	struct index_array *ap = (struct index_array*)nv_arrayptr(np);
11727c2fbfb3SApril Chin 	int sub = -1;
11737c2fbfb3SApril Chin 	if(!ap || is_associative(&ap->header))
11747c2fbfb3SApril Chin 		return(-1);
11757c2fbfb3SApril Chin 	sub = ap->maxi;
11767c2fbfb3SApril Chin 	while(--sub>0 && ap->val[sub].cp==0);
11777c2fbfb3SApril Chin 	return(sub);
11787c2fbfb3SApril Chin }
1179da2e3ebdSchin 
1180da2e3ebdSchin /*
11817c2fbfb3SApril Chin  *  This is the default implementation for associative arrays
1182da2e3ebdSchin  */
nv_associative(register Namval_t * np,const char * sp,int mode)1183da2e3ebdSchin void *nv_associative(register Namval_t *np,const char *sp,int mode)
1184da2e3ebdSchin {
1185da2e3ebdSchin 	register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
1186da2e3ebdSchin 	register int type;
1187da2e3ebdSchin 	switch(mode)
1188da2e3ebdSchin 	{
1189da2e3ebdSchin 	    case NV_AINIT:
1190da2e3ebdSchin 		if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
1191da2e3ebdSchin 		{
11927c2fbfb3SApril Chin 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
1193da2e3ebdSchin 			ap->cur = 0;
1194da2e3ebdSchin 			ap->pos = 0;
1195da2e3ebdSchin 			ap->header.hdr.disc = &array_disc;
11967c2fbfb3SApril Chin 			nv_disc(np,(Namfun_t*)ap, NV_FIRST);
11977c2fbfb3SApril Chin 			ap->header.hdr.dsize = sizeof(struct assoc_array);
11987c2fbfb3SApril Chin 			ap->header.hdr.nofree &= ~1;
1199da2e3ebdSchin 		}
1200da2e3ebdSchin 		return((void*)ap);
1201da2e3ebdSchin 	    case NV_ADELETE:
1202da2e3ebdSchin 		if(ap->cur)
1203da2e3ebdSchin 		{
12047c2fbfb3SApril Chin 			if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0))
12057c2fbfb3SApril Chin 				ap->header.nelem--;
12067c2fbfb3SApril Chin 			_nv_unset(ap->cur,NV_RDONLY);
12077c2fbfb3SApril Chin 			nv_delete(ap->cur,ap->header.table,0);
1208da2e3ebdSchin 			ap->cur = 0;
1209da2e3ebdSchin 		}
1210da2e3ebdSchin 		return((void*)ap);
1211da2e3ebdSchin 	    case NV_AFREE:
1212da2e3ebdSchin 		ap->pos = 0;
12137c2fbfb3SApril Chin 		if(ap->header.scope)
12147c2fbfb3SApril Chin 		{
12157c2fbfb3SApril Chin 			ap->header.table = dtview(ap->header.table,(Dt_t*)0);
12167c2fbfb3SApril Chin 			dtclose(ap->header.scope);
12177c2fbfb3SApril Chin 			ap->header.scope = 0;
12187c2fbfb3SApril Chin 		}
12197c2fbfb3SApril Chin 		else
12207c2fbfb3SApril Chin 			dtclose(ap->header.table);
1221da2e3ebdSchin 		return((void*)ap);
1222da2e3ebdSchin 	    case NV_ANEXT:
1223da2e3ebdSchin 		if(!ap->pos)
1224da2e3ebdSchin 		{
12257c2fbfb3SApril Chin 			if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
12267c2fbfb3SApril Chin 			{
12277c2fbfb3SApril Chin 				ap->header.scope = dtvnext(ap->header.table);
12287c2fbfb3SApril Chin 				ap->header.table->view = 0;
12297c2fbfb3SApril Chin 			}
1230da2e3ebdSchin 			if(!(ap->pos=ap->cur))
12317c2fbfb3SApril Chin 				ap->pos = (Namval_t*)dtfirst(ap->header.table);
1232da2e3ebdSchin 		}
1233da2e3ebdSchin 		else
1234da2e3ebdSchin 			ap->pos = ap->nextpos;
1235da2e3ebdSchin 		for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
1236da2e3ebdSchin 		{
12377c2fbfb3SApril Chin 			ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
1238da2e3ebdSchin 			if(ap->cur->nvalue.cp)
1239da2e3ebdSchin 			{
1240da2e3ebdSchin 				if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
1241da2e3ebdSchin 					continue;
1242da2e3ebdSchin 				return((void*)ap);
1243da2e3ebdSchin 			}
1244da2e3ebdSchin 		}
12457c2fbfb3SApril Chin 		if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
12467c2fbfb3SApril Chin 		{
12477c2fbfb3SApril Chin 			ap->header.table->view = (Dt_t*)ap->header.scope;
12487c2fbfb3SApril Chin 			ap->header.scope = ap->header.table;
12497c2fbfb3SApril Chin 		}
1250da2e3ebdSchin 		return(NIL(void*));
1251da2e3ebdSchin 	    case NV_ASETSUB:
1252da2e3ebdSchin 		ap->cur = (Namval_t*)sp;
12537c2fbfb3SApril Chin 		return((void*)ap->cur);
1254da2e3ebdSchin 	    case NV_ACURRENT:
12557c2fbfb3SApril Chin 		if(ap->cur)
12567c2fbfb3SApril Chin 			ap->cur->nvenv = (char*)np;
1257da2e3ebdSchin 		return((void*)ap->cur);
1258da2e3ebdSchin 	    case NV_ANAME:
1259da2e3ebdSchin 		if(ap->cur)
1260*3e14f97fSRoger A. Faulkner 		{
1261*3e14f97fSRoger A. Faulkner 			Shell_t *shp = sh_getinterp();
1262*3e14f97fSRoger A. Faulkner 			if(!shp->instance && nv_isnull(ap->cur))
1263*3e14f97fSRoger A. Faulkner 				return(NIL(void*));
12647c2fbfb3SApril Chin 			return((void*)ap->cur->nvname);
1265*3e14f97fSRoger A. Faulkner 		}
1266da2e3ebdSchin 		return(NIL(void*));
1267da2e3ebdSchin 	    default:
1268da2e3ebdSchin 		if(sp)
1269da2e3ebdSchin 		{
12707c2fbfb3SApril Chin 			Namval_t *mp=0;
1271da2e3ebdSchin 			ap->cur = 0;
12727c2fbfb3SApril Chin 			if(sp==(char*)np)
1273da2e3ebdSchin 				return(0);
12747c2fbfb3SApril Chin 			type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
12757c2fbfb3SApril Chin 			if(mode)
12767c2fbfb3SApril Chin 				mode = NV_ADD|HASH_NOSCOPE;
12777c2fbfb3SApril Chin 			else if(ap->header.nelem&ARRAY_NOSCOPE)
12787c2fbfb3SApril Chin 				mode = HASH_NOSCOPE;
1279*3e14f97fSRoger A. Faulkner 			if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD))
128034f9b3eeSRoland Mainz 				errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript");
12817c2fbfb3SApril Chin 			if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
12827c2fbfb3SApril Chin 				ap->cur = mp;
12837c2fbfb3SApril Chin 			if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
12847c2fbfb3SApril Chin 			{
12857c2fbfb3SApril Chin 				nv_onattr(mp,type);
12867c2fbfb3SApril Chin 				mp->nvenv = (char*)np;
12877c2fbfb3SApril Chin 				if((mode&NV_ADD) && nv_type(np))
12887c2fbfb3SApril Chin 					nv_arraychild(np,mp,0);
12897c2fbfb3SApril Chin 				if(sh.subshell)
12907c2fbfb3SApril Chin 					np = sh_assignok(np,1);
12917c2fbfb3SApril Chin 				if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
12927c2fbfb3SApril Chin 					ap->header.nelem++;
12937c2fbfb3SApril Chin 				if(nv_isnull(mp))
12947c2fbfb3SApril Chin 				{
12957c2fbfb3SApril Chin 					if(ap->header.nelem&ARRAY_TREE)
12967c2fbfb3SApril Chin 						nv_setvtree(mp);
12977c2fbfb3SApril Chin 					mp->nvalue.cp = Empty;
1298da2e3ebdSchin 				}
12997c2fbfb3SApril Chin 			}
13007c2fbfb3SApril Chin 			else if(ap->header.nelem&ARRAY_SCAN)
13017c2fbfb3SApril Chin 			{
13027c2fbfb3SApril Chin 				Namval_t fake;
13037c2fbfb3SApril Chin 				fake.nvname = (char*)sp;
13047c2fbfb3SApril Chin 				ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
13057c2fbfb3SApril Chin 				ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
13067c2fbfb3SApril Chin 			}
1307*3e14f97fSRoger A. Faulkner 			else if(!mp && *sp && mode==0)
1308*3e14f97fSRoger A. Faulkner 				mp = nv_search(sp,ap->header.table,NV_ADD);
13097c2fbfb3SApril Chin 			np = mp;
131034f9b3eeSRoland Mainz 			if(ap->pos && ap->pos==np)
131134f9b3eeSRoland Mainz 				ap->header.nelem |= ARRAY_SCAN;
131234f9b3eeSRoland Mainz 			else if(!(ap->header.nelem&ARRAY_SCAN))
1313da2e3ebdSchin 				ap->pos = 0;
1314da2e3ebdSchin 			ap->cur = np;
1315da2e3ebdSchin 		}
1316da2e3ebdSchin 		if(ap->cur)
1317da2e3ebdSchin 			return((void*)(&ap->cur->nvalue));
1318da2e3ebdSchin 		else
1319da2e3ebdSchin 			return((void*)(&ap->cur));
1320da2e3ebdSchin 	}
1321da2e3ebdSchin }
1322da2e3ebdSchin 
1323da2e3ebdSchin /*
1324da2e3ebdSchin  * Assign values to an array
1325da2e3ebdSchin  */
nv_setvec(register Namval_t * np,int append,register int argc,register char * argv[])1326da2e3ebdSchin void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
1327da2e3ebdSchin {
1328da2e3ebdSchin 	int arg0=0;
13297c2fbfb3SApril Chin 	struct index_array *ap=0,*aq;
1330da2e3ebdSchin 	if(nv_isarray(np))
1331da2e3ebdSchin 	{
1332da2e3ebdSchin 		ap = (struct index_array*)nv_arrayptr(np);
1333da2e3ebdSchin 		if(ap && is_associative(ap))
13347c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
1335da2e3ebdSchin 	}
1336da2e3ebdSchin 	if(append)
1337da2e3ebdSchin 	{
1338da2e3ebdSchin 		if(ap)
1339da2e3ebdSchin 		{
13407c2fbfb3SApril Chin 			if(!(aq = (struct index_array*)ap->header.scope))
13417c2fbfb3SApril Chin 				aq = ap;
1342da2e3ebdSchin 			arg0 = ap->maxi;
13437c2fbfb3SApril Chin 			while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
1344da2e3ebdSchin 			arg0++;
1345da2e3ebdSchin 		}
1346da2e3ebdSchin 		else if(!nv_isnull(np))
1347da2e3ebdSchin 			arg0=1;
1348da2e3ebdSchin 	}
1349da2e3ebdSchin 	while(--argc >= 0)
1350da2e3ebdSchin 	{
13517c2fbfb3SApril Chin 		nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
1352da2e3ebdSchin 		nv_putval(np,argv[argc],0);
1353da2e3ebdSchin 	}
1354da2e3ebdSchin }
1355da2e3ebdSchin 
1356