14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * Array processing routines
234887Schin  *
244887Schin  *   David Korn
254887Schin  *   AT&T Labs
264887Schin  *   dgk@research.att.com
274887Schin  *
284887Schin  */
294887Schin 
304887Schin #include	"defs.h"
314887Schin #include	<stak.h>
324887Schin #include	"name.h"
334887Schin 
344887Schin #define NUMSIZE	(4+(ARRAY_MAX>999)+(ARRAY_MAX>9999)+(ARRAY_MAX>99999))
354887Schin #define is_associative(ap)	array_assoc((Namarr_t*)(ap))
36*8462SApril.Chin@Sun.COM #define array_setbit(cp, n, b)	(cp[n] |= (b))
37*8462SApril.Chin@Sun.COM #define array_clrbit(cp, n, b)	(cp[n] &= ~(b))
38*8462SApril.Chin@Sun.COM #define array_isbit(cp, n, b)	(cp[n] & (b))
394887Schin #define NV_CHILD		NV_EXPORT
40*8462SApril.Chin@Sun.COM #define ARRAY_CHILD		1
41*8462SApril.Chin@Sun.COM #define ARRAY_NOFREE		2
424887Schin 
434887Schin struct index_array
444887Schin {
454887Schin         Namarr_t        header;
46*8462SApril.Chin@Sun.COM 	void		*xp;	/* if set, subscripts will be converted */
474887Schin         int		cur;    /* index of current element */
484887Schin         int		maxi;   /* maximum index for array */
494887Schin 	unsigned char	*bits;	/* bit array for child subscripts */
504887Schin         union Value	val[1]; /* array of value holders */
514887Schin };
524887Schin 
534887Schin struct assoc_array
544887Schin {
554887Schin 	Namarr_t	header;
564887Schin 	Namval_t	*pos;
574887Schin 	Namval_t	*nextpos;
584887Schin 	Namval_t	*cur;
594887Schin };
604887Schin 
61*8462SApril.Chin@Sun.COM static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
62*8462SApril.Chin@Sun.COM {
63*8462SApril.Chin@Sun.COM 	Namarr_t *aq;
64*8462SApril.Chin@Sun.COM 	struct index_array *ar;
65*8462SApril.Chin@Sun.COM 	size_t size = ap->hdr.dsize;
66*8462SApril.Chin@Sun.COM 	if(size==0)
67*8462SApril.Chin@Sun.COM 		size = ap->hdr.disc->dsize;
68*8462SApril.Chin@Sun.COM         if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
69*8462SApril.Chin@Sun.COM                 return(0);
70*8462SApril.Chin@Sun.COM         memcpy(aq,ap,size);
71*8462SApril.Chin@Sun.COM 	aq->hdr.nofree &= ~1;
72*8462SApril.Chin@Sun.COM         aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
73*8462SApril.Chin@Sun.COM 	if(is_associative(aq))
74*8462SApril.Chin@Sun.COM 	{
75*8462SApril.Chin@Sun.COM 		aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
76*8462SApril.Chin@Sun.COM 		dtview((Dt_t*)aq->scope,aq->table);
77*8462SApril.Chin@Sun.COM 		aq->table = (Dt_t*)aq->scope;
78*8462SApril.Chin@Sun.COM 		return(aq);
79*8462SApril.Chin@Sun.COM 	}
80*8462SApril.Chin@Sun.COM 	aq->scope = (void*)ap;
81*8462SApril.Chin@Sun.COM 	ar = (struct index_array*)aq;
82*8462SApril.Chin@Sun.COM 	memset(ar->val, 0, ar->maxi*sizeof(char*));
83*8462SApril.Chin@Sun.COM 	return(aq);
84*8462SApril.Chin@Sun.COM }
85*8462SApril.Chin@Sun.COM 
86*8462SApril.Chin@Sun.COM static int array_unscope(Namval_t *np,Namarr_t *ap)
87*8462SApril.Chin@Sun.COM {
88*8462SApril.Chin@Sun.COM 	Namfun_t *fp;
89*8462SApril.Chin@Sun.COM 	if(!ap->scope)
90*8462SApril.Chin@Sun.COM 		return(0);
91*8462SApril.Chin@Sun.COM 	if(is_associative(ap))
92*8462SApril.Chin@Sun.COM 		(*ap->fun)(np, NIL(char*), NV_AFREE);
93*8462SApril.Chin@Sun.COM 	if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
94*8462SApril.Chin@Sun.COM 		free((void*)fp);
95*8462SApril.Chin@Sun.COM 	nv_delete(np,(Dt_t*)0,0);
96*8462SApril.Chin@Sun.COM 	return(1);
97*8462SApril.Chin@Sun.COM }
98*8462SApril.Chin@Sun.COM 
99*8462SApril.Chin@Sun.COM static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
100*8462SApril.Chin@Sun.COM {
101*8462SApril.Chin@Sun.COM 	((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
102*8462SApril.Chin@Sun.COM }
103*8462SApril.Chin@Sun.COM 
104*8462SApril.Chin@Sun.COM static int array_covered(Namval_t *np, struct index_array *ap)
105*8462SApril.Chin@Sun.COM {
106*8462SApril.Chin@Sun.COM 	struct index_array *aq = (struct index_array*)ap->header.scope;
107*8462SApril.Chin@Sun.COM 	if(!ap->header.fun && aq)
108*8462SApril.Chin@Sun.COM 		return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
109*8462SApril.Chin@Sun.COM 	return(0);
110*8462SApril.Chin@Sun.COM }
111*8462SApril.Chin@Sun.COM 
1124887Schin /*
1134887Schin  * replace discipline with new one
1144887Schin  */
1154887Schin static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
1164887Schin {
1174887Schin 	register Namfun_t **fp = &np->nvfun;
1184887Schin 	while(*fp && *fp!= &old->header.hdr)
1194887Schin 		fp = &((*fp)->next);
1204887Schin 	if(*fp)
1214887Schin 	{
1224887Schin 		new->header.hdr.next = (*fp)->next;
1234887Schin 		*fp = &new->header.hdr;
1244887Schin 	}
1254887Schin 	else sfprintf(sfstderr,"discipline not replaced\n");
1264887Schin }
1274887Schin 
1284887Schin /*
1294887Schin  *   Calculate the amount of space to be allocated to hold an
1304887Schin  *   indexed array into which <maxi> is a legal index.  The number of
1314887Schin  *   elements that will actually fit into the array (> <maxi>
1324887Schin  *   but <= ARRAY_MAX) is returned.
1334887Schin  *
1344887Schin  */
135*8462SApril.Chin@Sun.COM static int	arsize(struct index_array *ap, register int maxi)
1364887Schin {
137*8462SApril.Chin@Sun.COM 	if(ap && maxi < 2*ap->maxi)
138*8462SApril.Chin@Sun.COM 		maxi = 2*ap->maxi;
139*8462SApril.Chin@Sun.COM 	maxi = roundof(maxi,ARRAY_INCR);
140*8462SApril.Chin@Sun.COM 	return (maxi>ARRAY_MAX?ARRAY_MAX:maxi);
1414887Schin }
1424887Schin 
1434887Schin static struct index_array *array_grow(Namval_t*, struct index_array*,int);
1444887Schin 
1454887Schin /* return index of highest element of an array */
1464887Schin int array_maxindex(Namval_t *np)
1474887Schin {
1484887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1494887Schin 	register int i = ap->maxi;
1504887Schin 	if(is_associative(ap))
1514887Schin 		return(-1);
1524887Schin 	while(i>0 && ap->val[--i].cp==0);
1534887Schin 	return(i+1);
1544887Schin }
1554887Schin 
156*8462SApril.Chin@Sun.COM static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update)
1574887Schin {
1584887Schin 	register struct index_array *ap = (struct index_array*)arp;
1594887Schin 	register union Value *up;
160*8462SApril.Chin@Sun.COM 	int	nofree;
161*8462SApril.Chin@Sun.COM 	if(!arp)
1624887Schin 		return(&np->nvalue);
1634887Schin 	if(is_associative(ap))
164*8462SApril.Chin@Sun.COM 	{
165*8462SApril.Chin@Sun.COM 		Namval_t	*mp;
166*8462SApril.Chin@Sun.COM 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
167*8462SApril.Chin@Sun.COM 		if(mp)
168*8462SApril.Chin@Sun.COM 		{
169*8462SApril.Chin@Sun.COM 			nofree = nv_isattr(mp,NV_NOFREE);
170*8462SApril.Chin@Sun.COM 			up = &mp->nvalue;
171*8462SApril.Chin@Sun.COM 		}
172*8462SApril.Chin@Sun.COM 		else
173*8462SApril.Chin@Sun.COM 			return((union Value*)((*arp->fun)(np,NIL(char*),0)));
174*8462SApril.Chin@Sun.COM 	}
1754887Schin 	else
1764887Schin 	{
1774887Schin 		if(ap->cur >= ap->maxi)
1784887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
1794887Schin 		up = &(ap->val[ap->cur]);
180*8462SApril.Chin@Sun.COM 		nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
181*8462SApril.Chin@Sun.COM 	}
182*8462SApril.Chin@Sun.COM 	if(update)
183*8462SApril.Chin@Sun.COM 	{
184*8462SApril.Chin@Sun.COM 		if(nofree)
185*8462SApril.Chin@Sun.COM 			nv_onattr(np,NV_NOFREE);
186*8462SApril.Chin@Sun.COM 		else
187*8462SApril.Chin@Sun.COM 			nv_offattr(np,NV_NOFREE);
1884887Schin 	}
1894887Schin 	return(up);
1904887Schin }
1914887Schin 
1924887Schin /*
1934887Schin  * Get the Value pointer for an array.
1944887Schin  * Delete space as necessary if flag is ARRAY_DELETE
1954887Schin  * After the lookup is done the last @ or * subscript is incremented
1964887Schin  */
1974887Schin static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
1984887Schin {
1994887Schin 	register struct index_array *ap = (struct index_array*)arp;
2004887Schin 	register union Value	*up;
2014887Schin 	Namval_t		*mp;
2024887Schin 	int			wasundef;
203*8462SApril.Chin@Sun.COM 	if(flag&ARRAY_LOOKUP)
204*8462SApril.Chin@Sun.COM 		ap->header.nelem &= ~ARRAY_NOSCOPE;
205*8462SApril.Chin@Sun.COM 	else
206*8462SApril.Chin@Sun.COM 		ap->header.nelem |= ARRAY_NOSCOPE;
2074887Schin 	if(wasundef = ap->header.nelem&ARRAY_UNDEF)
2084887Schin 	{
2094887Schin 		ap->header.nelem &= ~ARRAY_UNDEF;
2104887Schin 		/* delete array is the same as delete array[@] */
2114887Schin 		if(flag&ARRAY_DELETE)
2124887Schin 		{
213*8462SApril.Chin@Sun.COM 			nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
2144887Schin 			ap->header.nelem |= ARRAY_SCAN;
2154887Schin 		}
2164887Schin 		else /* same as array[0] */
2174887Schin 		{
2184887Schin 			if(is_associative(ap))
2194887Schin 				(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
2204887Schin 			else
2214887Schin 				ap->cur = 0;
2224887Schin 		}
2234887Schin 	}
2244887Schin 	if(is_associative(ap))
2254887Schin 	{
2264887Schin 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
2274887Schin 		if(!mp)
2284887Schin 			up = (union Value*)&mp;
229*8462SApril.Chin@Sun.COM 		else if(nv_isarray(mp))
2304887Schin 		{
231*8462SApril.Chin@Sun.COM 			if(wasundef)
232*8462SApril.Chin@Sun.COM 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
233*8462SApril.Chin@Sun.COM 			return(mp);
2344887Schin 		}
2354887Schin 		else
236*8462SApril.Chin@Sun.COM 		{
2374887Schin 			up =  &mp->nvalue;
238*8462SApril.Chin@Sun.COM 			if(nv_isvtree(mp))
239*8462SApril.Chin@Sun.COM 			{
240*8462SApril.Chin@Sun.COM 				if(!up->cp && flag==ARRAY_ASSIGN)
241*8462SApril.Chin@Sun.COM 				{
242*8462SApril.Chin@Sun.COM 					nv_arraychild(np,mp,0);
243*8462SApril.Chin@Sun.COM 					ap->header.nelem++;
244*8462SApril.Chin@Sun.COM 				}
245*8462SApril.Chin@Sun.COM 				return(mp);
246*8462SApril.Chin@Sun.COM 			}
247*8462SApril.Chin@Sun.COM 		}
2484887Schin 	}
2494887Schin 	else
2504887Schin 	{
2514887Schin 		if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
2524887Schin 			ap = array_grow(np, ap, (int)ap->cur);
2534887Schin 		if(ap->cur>=ap->maxi)
2544887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
2554887Schin 		up = &(ap->val[ap->cur]);
256*8462SApril.Chin@Sun.COM 		if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
257*8462SApril.Chin@Sun.COM 		{
258*8462SApril.Chin@Sun.COM 			char *cp;
259*8462SApril.Chin@Sun.COM 			if(!ap->header.table)
260*8462SApril.Chin@Sun.COM 				ap->header.table = dtopen(&_Nvdisc,Dtoset);
261*8462SApril.Chin@Sun.COM 			sfprintf(sh.strbuf,"%d",ap->cur);
262*8462SApril.Chin@Sun.COM 			cp = sfstruse(sh.strbuf);
263*8462SApril.Chin@Sun.COM 			mp = nv_search(cp, ap->header.table, NV_ADD);
264*8462SApril.Chin@Sun.COM 			mp->nvenv = (char*)np;
265*8462SApril.Chin@Sun.COM 			nv_arraychild(np,mp,0);
266*8462SApril.Chin@Sun.COM 		}
267*8462SApril.Chin@Sun.COM 		if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
2684887Schin 		{
2694887Schin 			if(wasundef && nv_isarray(up->np))
2704887Schin 				nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
2714887Schin 			return(up->np);
2724887Schin 		}
2734887Schin 	}
2744887Schin 	np->nvalue.cp = up->cp;
2754887Schin 	if(!up->cp)
2764887Schin 	{
2774887Schin 		if(flag!=ARRAY_ASSIGN)
2784887Schin 			return(0);
279*8462SApril.Chin@Sun.COM 		if(!array_covered(np,ap))
280*8462SApril.Chin@Sun.COM 			ap->header.nelem++;
2814887Schin 	}
2824887Schin 	return(np);
2834887Schin }
2844887Schin 
285*8462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
286*8462SApril.Chin@Sun.COM int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
287*8462SApril.Chin@Sun.COM {
288*8462SApril.Chin@Sun.COM 	Namval_t	*nq;
289*8462SApril.Chin@Sun.COM 	char		*av[2];
290*8462SApril.Chin@Sun.COM 	int		rdonly = nv_isattr(np,NV_RDONLY);
291*8462SApril.Chin@Sun.COM 	int		xtrace = sh_isoption(SH_XTRACE);
292*8462SApril.Chin@Sun.COM 	Namarr_t	*ap = nv_arrayptr(np);
293*8462SApril.Chin@Sun.COM 	av[1] = 0;
294*8462SApril.Chin@Sun.COM 	sh.last_table = 0;
295*8462SApril.Chin@Sun.COM 	if(!ap->table)
296*8462SApril.Chin@Sun.COM 		ap->table = dtopen(&_Nvdisc,Dtoset);
297*8462SApril.Chin@Sun.COM 	if(nq = nv_search(sub, ap->table, NV_ADD))
298*8462SApril.Chin@Sun.COM 	{
299*8462SApril.Chin@Sun.COM 		if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
300*8462SApril.Chin@Sun.COM 			_nv_unset(nq,NV_RDONLY);
301*8462SApril.Chin@Sun.COM 		nv_arraychild(np,nq,0);
302*8462SApril.Chin@Sun.COM 		if(!nv_isattr(tp,NV_BINARY))
303*8462SApril.Chin@Sun.COM 		{
304*8462SApril.Chin@Sun.COM 			sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
305*8462SApril.Chin@Sun.COM 			av[0] = strdup(sfstruse(sh.strbuf));
306*8462SApril.Chin@Sun.COM 		}
307*8462SApril.Chin@Sun.COM 		if(!nv_clone(tp,nq,flags|NV_NOFREE))
308*8462SApril.Chin@Sun.COM 			return(0);
309*8462SApril.Chin@Sun.COM 		ap->nelem |= ARRAY_SCAN;
310*8462SApril.Chin@Sun.COM 		if(!rdonly)
311*8462SApril.Chin@Sun.COM 			nv_offattr(nq,NV_RDONLY);
312*8462SApril.Chin@Sun.COM 		if(!nv_isattr(tp,NV_BINARY))
313*8462SApril.Chin@Sun.COM 		{
314*8462SApril.Chin@Sun.COM 			if(xtrace)
315*8462SApril.Chin@Sun.COM 				sh_offoption(SH_XTRACE);
316*8462SApril.Chin@Sun.COM 			ap->nelem &= ~ARRAY_SCAN;
317*8462SApril.Chin@Sun.COM 			sh_eval(sh_sfeval(av),0);
318*8462SApril.Chin@Sun.COM 			ap->nelem |= ARRAY_SCAN;
319*8462SApril.Chin@Sun.COM 			free((void*)av[0]);
320*8462SApril.Chin@Sun.COM 			if(xtrace)
321*8462SApril.Chin@Sun.COM 				sh_onoption(SH_XTRACE);
322*8462SApril.Chin@Sun.COM 		}
323*8462SApril.Chin@Sun.COM 		return(1);
324*8462SApril.Chin@Sun.COM 	}
325*8462SApril.Chin@Sun.COM 	return(0);
326*8462SApril.Chin@Sun.COM }
327*8462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
328*8462SApril.Chin@Sun.COM 
329*8462SApril.Chin@Sun.COM 
3304887Schin static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
3314887Schin {
3324887Schin 	Namarr_t		*ap = (Namarr_t*)fp;
3334887Schin 	Namval_t		*nq, *mq;
3344887Schin 	char			*name, *sub=0;
335*8462SApril.Chin@Sun.COM 	int			nelem, skipped=0;
336*8462SApril.Chin@Sun.COM 	Dt_t			*otable=ap->table;
337*8462SApril.Chin@Sun.COM 	struct index_array	*aq = (struct index_array*)ap, *ar;
338*8462SApril.Chin@Sun.COM 	Shell_t			*shp = sh_getinterp();
339*8462SApril.Chin@Sun.COM 	if(flags&NV_MOVE)
340*8462SApril.Chin@Sun.COM 	{
341*8462SApril.Chin@Sun.COM 		if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
342*8462SApril.Chin@Sun.COM 		{
343*8462SApril.Chin@Sun.COM 			do
344*8462SApril.Chin@Sun.COM 			{
345*8462SApril.Chin@Sun.COM 				if(nq=nv_opensub(np))
346*8462SApril.Chin@Sun.COM 					nq->nvenv = (void*)mp;
347*8462SApril.Chin@Sun.COM 			}
348*8462SApril.Chin@Sun.COM 			while(nv_nextsub(np));
349*8462SApril.Chin@Sun.COM 		}
350*8462SApril.Chin@Sun.COM 		return(fp);
351*8462SApril.Chin@Sun.COM 	}
352*8462SApril.Chin@Sun.COM 	nelem = ap->nelem;
3534887Schin 	if(nelem&ARRAY_NOCLONE)
3544887Schin 		return(0);
355*8462SApril.Chin@Sun.COM 	if((flags&NV_TYPE) && !ap->scope)
356*8462SApril.Chin@Sun.COM 	{
357*8462SApril.Chin@Sun.COM 		ap = array_scope(np,ap,flags);
358*8462SApril.Chin@Sun.COM 		return(&ap->hdr);
359*8462SApril.Chin@Sun.COM 	}
360*8462SApril.Chin@Sun.COM 	ap = (Namarr_t*)nv_clone_disc(fp,0);
361*8462SApril.Chin@Sun.COM 	if(flags&NV_COMVAR)
3624887Schin 	{
363*8462SApril.Chin@Sun.COM 		ap->scope = 0;
364*8462SApril.Chin@Sun.COM 		ap->nelem = 0;
365*8462SApril.Chin@Sun.COM 		sh.prev_table = sh.last_table;
366*8462SApril.Chin@Sun.COM 		sh.prev_root = sh.last_root;
3674887Schin 	}
368*8462SApril.Chin@Sun.COM 	if(ap->table)
369*8462SApril.Chin@Sun.COM 	{
370*8462SApril.Chin@Sun.COM 		ap->table = dtopen(&_Nvdisc,Dtoset);
371*8462SApril.Chin@Sun.COM 		if(ap->scope && !(flags&NV_COMVAR))
372*8462SApril.Chin@Sun.COM 		{
373*8462SApril.Chin@Sun.COM 			ap->scope = ap->table;
374*8462SApril.Chin@Sun.COM 			dtview(ap->table, otable->view);
375*8462SApril.Chin@Sun.COM 		}
376*8462SApril.Chin@Sun.COM 	}
377*8462SApril.Chin@Sun.COM 	mp->nvfun = (Namfun_t*)ap;
378*8462SApril.Chin@Sun.COM 	mp->nvflag &= NV_MINIMAL;
379*8462SApril.Chin@Sun.COM 	mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
3804887Schin 	if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
3814887Schin 		sub = strdup(sub);
3824887Schin 	ar = (struct index_array*)ap;
383*8462SApril.Chin@Sun.COM 	if(!is_associative(ap))
384*8462SApril.Chin@Sun.COM 		ar->bits = (unsigned char*)&ar->val[ar->maxi];
385*8462SApril.Chin@Sun.COM 	if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
386*8462SApril.Chin@Sun.COM 	{
387*8462SApril.Chin@Sun.COM 		if(ap->fun)
388*8462SApril.Chin@Sun.COM 			(*ap->fun)(np,(char*)np,0);
389*8462SApril.Chin@Sun.COM 		skipped=1;
390*8462SApril.Chin@Sun.COM 		goto skip;
391*8462SApril.Chin@Sun.COM 	}
3924887Schin 	do
3934887Schin 	{
394*8462SApril.Chin@Sun.COM 		name = nv_getsub(np);
395*8462SApril.Chin@Sun.COM 		nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
396*8462SApril.Chin@Sun.COM 		mq = 0;
397*8462SApril.Chin@Sun.COM 		if(nq=nv_opensub(np))
398*8462SApril.Chin@Sun.COM 			mq = nv_search(name,ap->table,NV_ADD);
399*8462SApril.Chin@Sun.COM 		if(nq && (flags&NV_COMVAR) && nv_isvtree(nq))
4004887Schin 		{
401*8462SApril.Chin@Sun.COM 			mq->nvalue.cp = 0;
402*8462SApril.Chin@Sun.COM 			if(!is_associative(ap))
403*8462SApril.Chin@Sun.COM 				ar->val[ar->cur].np = mq;
404*8462SApril.Chin@Sun.COM 			nv_clone(nq,mq,flags);
405*8462SApril.Chin@Sun.COM 		}
406*8462SApril.Chin@Sun.COM 		else if(flags&NV_ARRAY)
407*8462SApril.Chin@Sun.COM 		{
408*8462SApril.Chin@Sun.COM 			if((flags&NV_NOFREE) && !is_associative(ap))
409*8462SApril.Chin@Sun.COM 				array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
410*8462SApril.Chin@Sun.COM 			else if(nq && (flags&NV_NOFREE))
4114887Schin 			{
412*8462SApril.Chin@Sun.COM 				mq->nvalue = nq->nvalue;
413*8462SApril.Chin@Sun.COM 				nv_onattr(nq,NV_NOFREE);
4144887Schin 			}
4154887Schin 		}
4164887Schin 		else if(nv_isattr(np,NV_INTEGER))
4174887Schin 		{
4184887Schin 			Sfdouble_t d= nv_getnum(np);
419*8462SApril.Chin@Sun.COM 			if(!is_associative(ap))
420*8462SApril.Chin@Sun.COM 				ar->val[ar->cur].cp = 0;
4214887Schin 			nv_putval(mp,(char*)&d,NV_LDOUBLE);
4224887Schin 		}
4234887Schin 		else
424*8462SApril.Chin@Sun.COM 		{
425*8462SApril.Chin@Sun.COM 			if(!is_associative(ap))
426*8462SApril.Chin@Sun.COM 				ar->val[ar->cur].cp = 0;
4274887Schin 			nv_putval(mp,nv_getval(np),NV_RDONLY);
428*8462SApril.Chin@Sun.COM 		}
429*8462SApril.Chin@Sun.COM 		aq->header.nelem |= ARRAY_NOSCOPE;
4304887Schin 	}
4314887Schin 	while(nv_nextsub(np));
432*8462SApril.Chin@Sun.COM skip:
4334887Schin 	if(sub)
4344887Schin 	{
435*8462SApril.Chin@Sun.COM 		if(!skipped)
436*8462SApril.Chin@Sun.COM 			nv_putsub(np,sub,0L);
4374887Schin 		free((void*)sub);
4384887Schin 	}
439*8462SApril.Chin@Sun.COM 	aq->header.nelem = ap->nelem = nelem;
440*8462SApril.Chin@Sun.COM 	return(&ap->hdr);
4414887Schin }
4424887Schin 
4434887Schin static char *array_getval(Namval_t *np, Namfun_t *disc)
4444887Schin {
445*8462SApril.Chin@Sun.COM 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
4464887Schin 	register Namval_t *mp;
4474887Schin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
448*8462SApril.Chin@Sun.COM 	{
449*8462SApril.Chin@Sun.COM 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
450*8462SApril.Chin@Sun.COM 		{
451*8462SApril.Chin@Sun.COM 			array_syncsub(aq,ap);
452*8462SApril.Chin@Sun.COM 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
453*8462SApril.Chin@Sun.COM 				return(nv_getv(np,&aq->hdr));
454*8462SApril.Chin@Sun.COM 		}
4554887Schin 		return(mp?nv_getval(mp):0);
456*8462SApril.Chin@Sun.COM 	}
4574887Schin 	return(nv_getv(np,&ap->hdr));
4584887Schin }
4594887Schin 
4604887Schin static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
4614887Schin {
462*8462SApril.Chin@Sun.COM 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
4634887Schin 	register Namval_t *mp;
4644887Schin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
465*8462SApril.Chin@Sun.COM 	{
466*8462SApril.Chin@Sun.COM 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
467*8462SApril.Chin@Sun.COM 		{
468*8462SApril.Chin@Sun.COM 			array_syncsub(aq,ap);
469*8462SApril.Chin@Sun.COM 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
470*8462SApril.Chin@Sun.COM 				return(nv_getn(np,&aq->hdr));
471*8462SApril.Chin@Sun.COM 		}
4724887Schin 		return(mp?nv_getnum(mp):0);
473*8462SApril.Chin@Sun.COM 	}
4744887Schin 	return(nv_getn(np,&ap->hdr));
4754887Schin }
4764887Schin 
4774887Schin static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
4784887Schin {
4794887Schin 	register Namarr_t	*ap = (Namarr_t*)dp;
4804887Schin 	register union Value	*up;
4814887Schin 	register Namval_t	*mp;
4824887Schin 	register struct index_array *aq = (struct index_array*)ap;
483*8462SApril.Chin@Sun.COM 	int			scan,nofree = nv_isattr(np,NV_NOFREE);
4844887Schin 	do
4854887Schin 	{
4864887Schin 		mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
487*8462SApril.Chin@Sun.COM 		scan = ap->nelem&ARRAY_SCAN;
4884887Schin 		if(mp && mp!=np)
489*8462SApril.Chin@Sun.COM 		{
490*8462SApril.Chin@Sun.COM 			if(!is_associative(ap) && string && !nv_type(np) && nv_isvtree(mp))
491*8462SApril.Chin@Sun.COM 			{
492*8462SApril.Chin@Sun.COM 				if(!nv_isattr(np,NV_NOFREE))
493*8462SApril.Chin@Sun.COM 					_nv_unset(mp,flags&NV_RDONLY);
494*8462SApril.Chin@Sun.COM 				array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
495*8462SApril.Chin@Sun.COM 				aq->val[aq->cur].cp = 0;
496*8462SApril.Chin@Sun.COM 				if(!nv_isattr(mp,NV_NOFREE))
497*8462SApril.Chin@Sun.COM 					nv_delete(mp,ap->table,0);
498*8462SApril.Chin@Sun.COM 				goto skip;
499*8462SApril.Chin@Sun.COM 			}
5004887Schin 			nv_putval(mp, string, flags);
501*8462SApril.Chin@Sun.COM 			if(string)
502*8462SApril.Chin@Sun.COM 			{
503*8462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
504*8462SApril.Chin@Sun.COM 				if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
505*8462SApril.Chin@Sun.COM 					nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
506*8462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
507*8462SApril.Chin@Sun.COM 				continue;
508*8462SApril.Chin@Sun.COM 			}
509*8462SApril.Chin@Sun.COM 			ap->nelem |= scan;
510*8462SApril.Chin@Sun.COM 		}
5114887Schin 		if(!string)
5124887Schin 		{
5134887Schin 			if(mp)
5144887Schin 			{
515*8462SApril.Chin@Sun.COM 				if(is_associative(ap))
5164887Schin 				{
5174887Schin 					(*ap->fun)(np,NIL(char*),NV_ADELETE);
518*8462SApril.Chin@Sun.COM 					np->nvalue.cp = 0;
519*8462SApril.Chin@Sun.COM 				}
520*8462SApril.Chin@Sun.COM 				else
5214887Schin 				{
522*8462SApril.Chin@Sun.COM 					if(mp!=np)
523*8462SApril.Chin@Sun.COM 					{
524*8462SApril.Chin@Sun.COM 						array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
525*8462SApril.Chin@Sun.COM 						aq->val[aq->cur].cp = 0;
526*8462SApril.Chin@Sun.COM 						nv_delete(mp,ap->table,0);
527*8462SApril.Chin@Sun.COM 					}
528*8462SApril.Chin@Sun.COM 					if(!array_covered(np,(struct index_array*)ap))
529*8462SApril.Chin@Sun.COM 						ap->nelem--;
5304887Schin 				}
5314887Schin 			}
5324887Schin 			if(array_elem(ap)==0 && ((ap->nelem&ARRAY_SCAN) || !is_associative(ap)))
5334887Schin 			{
5344887Schin 				if(is_associative(ap))
5354887Schin 					(*ap->fun)(np, NIL(char*), NV_AFREE);
536*8462SApril.Chin@Sun.COM 				else if(ap->table)
537*8462SApril.Chin@Sun.COM 					dtclose(ap->table);
5384887Schin 				nv_offattr(np,NV_ARRAY);
5394887Schin 			}
540*8462SApril.Chin@Sun.COM 			if(!mp || mp!=np || is_associative(ap))
5414887Schin 				continue;
5424887Schin 		}
543*8462SApril.Chin@Sun.COM 	skip:
5444887Schin 		/* prevent empty string from being deleted */
545*8462SApril.Chin@Sun.COM 		up = array_getup(np,ap,!nofree);
546*8462SApril.Chin@Sun.COM 		if(up->cp ==  Empty)
547*8462SApril.Chin@Sun.COM 			up->cp = 0;
548*8462SApril.Chin@Sun.COM 		if(nv_isarray(np))
549*8462SApril.Chin@Sun.COM 			np->nvalue.up = up;
5504887Schin 		nv_putv(np,string,flags,&ap->hdr);
551*8462SApril.Chin@Sun.COM 		if(!is_associative(ap))
552*8462SApril.Chin@Sun.COM 		{
553*8462SApril.Chin@Sun.COM 			if(string)
554*8462SApril.Chin@Sun.COM 				array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
555*8462SApril.Chin@Sun.COM 			else if(mp==np)
556*8462SApril.Chin@Sun.COM 				aq->val[aq->cur].cp = 0;
557*8462SApril.Chin@Sun.COM 		}
558*8462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
559*8462SApril.Chin@Sun.COM 		if(string && ap->hdr.type && nv_isvtree(np))
560*8462SApril.Chin@Sun.COM 			nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
561*8462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
5624887Schin 	}
5634887Schin 	while(!string && nv_nextsub(np));
564*8462SApril.Chin@Sun.COM 	if(ap)
565*8462SApril.Chin@Sun.COM 		ap->nelem &= ~ARRAY_NOSCOPE;
566*8462SApril.Chin@Sun.COM 	if(nofree)
567*8462SApril.Chin@Sun.COM 		nv_onattr(np,NV_NOFREE);
568*8462SApril.Chin@Sun.COM 	else
569*8462SApril.Chin@Sun.COM 		nv_offattr(np,NV_NOFREE);
5704887Schin 	if(!string && !nv_isattr(np,NV_ARRAY))
5714887Schin 	{
5724887Schin 		Namfun_t *nfp;
573*8462SApril.Chin@Sun.COM 		if(!is_associative(ap) && aq->xp)
574*8462SApril.Chin@Sun.COM 		{
575*8462SApril.Chin@Sun.COM 			_nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
576*8462SApril.Chin@Sun.COM 			free((void*)aq->xp);
577*8462SApril.Chin@Sun.COM 		}
578*8462SApril.Chin@Sun.COM 		if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
5794887Schin 			free((void*)nfp);
580*8462SApril.Chin@Sun.COM 		if(!nv_isnull(np))
581*8462SApril.Chin@Sun.COM 		{
582*8462SApril.Chin@Sun.COM 			nv_onattr(np,NV_NOFREE);
583*8462SApril.Chin@Sun.COM 			_nv_unset(np,flags);
584*8462SApril.Chin@Sun.COM 		}
585*8462SApril.Chin@Sun.COM 		if(np->nvalue.cp==Empty)
586*8462SApril.Chin@Sun.COM 			np->nvalue.cp = 0;
5874887Schin 	}
588*8462SApril.Chin@Sun.COM 	if(!string && (flags&NV_TYPE))
589*8462SApril.Chin@Sun.COM 		array_unscope(np,ap);
5904887Schin }
5914887Schin 
5924887Schin static const Namdisc_t array_disc =
5934887Schin {
5944887Schin 	sizeof(Namarr_t),
5954887Schin 	array_putval,
5964887Schin 	array_getval,
5974887Schin 	array_getnum,
5984887Schin 	0,
5994887Schin 	0,
6004887Schin 	array_clone
6014887Schin };
6024887Schin 
603*8462SApril.Chin@Sun.COM static void array_copytree(Namval_t *np, Namval_t *mp)
604*8462SApril.Chin@Sun.COM {
605*8462SApril.Chin@Sun.COM 	char		*val;
606*8462SApril.Chin@Sun.COM 	Namfun_t	*fp = nv_disc(np,NULL,NV_POP);
607*8462SApril.Chin@Sun.COM 	nv_offattr(np,NV_ARRAY);
608*8462SApril.Chin@Sun.COM 	nv_clone(np,mp,0);
609*8462SApril.Chin@Sun.COM 	np->nvalue.up = &mp->nvalue;
610*8462SApril.Chin@Sun.COM 	val = sfstruse(sh.strbuf);
611*8462SApril.Chin@Sun.COM 	fp->nofree  &= ~1;
612*8462SApril.Chin@Sun.COM 	nv_disc(np,(Namfun_t*)fp, NV_FIRST);
613*8462SApril.Chin@Sun.COM 	fp->nofree |= 1;
614*8462SApril.Chin@Sun.COM 	nv_onattr(np,NV_ARRAY);
615*8462SApril.Chin@Sun.COM 	mp->nvenv = (char*)np;
616*8462SApril.Chin@Sun.COM }
617*8462SApril.Chin@Sun.COM 
6184887Schin /*
6194887Schin  *        Increase the size of the indexed array of elements in <arp>
6204887Schin  *        so that <maxi> is a legal index.  If <arp> is 0, an array
6214887Schin  *        of the required size is allocated.  A pointer to the
6224887Schin  *        allocated Namarr_t structure is returned.
6234887Schin  *        <maxi> becomes the current index of the array.
6244887Schin  */
6254887Schin static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
6264887Schin {
6274887Schin 	register struct index_array *ap;
628*8462SApril.Chin@Sun.COM 	register int i;
629*8462SApril.Chin@Sun.COM 	register int newsize = arsize(arp,maxi+1);
6304887Schin 	if (maxi >= ARRAY_MAX)
6314887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
632*8462SApril.Chin@Sun.COM 	i = (newsize-1)*sizeof(union Value*)+newsize;
633*8462SApril.Chin@Sun.COM 	ap = new_of(struct index_array,i);
634*8462SApril.Chin@Sun.COM 	memset((void*)ap,0,sizeof(*ap)+i);
6354887Schin 	ap->maxi = newsize;
6364887Schin 	ap->cur = maxi;
6374887Schin 	ap->bits =  (unsigned char*)&ap->val[newsize];
638*8462SApril.Chin@Sun.COM 	memset(ap->bits, 0, newsize);
6394887Schin 	if(arp)
6404887Schin 	{
6414887Schin 		ap->header = arp->header;
642*8462SApril.Chin@Sun.COM 		ap->header.hdr.dsize = sizeof(*ap) + i;
643*8462SApril.Chin@Sun.COM 		for(i=0;i < arp->maxi;i++)
6444887Schin 			ap->val[i].cp = arp->val[i].cp;
645*8462SApril.Chin@Sun.COM 		memcpy(ap->bits, arp->bits, arp->maxi);
6464887Schin 		array_setptr(np,arp,ap);
6474887Schin 		free((void*)arp);
6484887Schin 	}
6494887Schin 	else
6504887Schin 	{
651*8462SApril.Chin@Sun.COM 		Namval_t *mp=0;
652*8462SApril.Chin@Sun.COM 		ap->header.hdr.dsize = sizeof(*ap) + i;
653*8462SApril.Chin@Sun.COM 		i = 0;
6544887Schin 		ap->header.fun = 0;
655*8462SApril.Chin@Sun.COM 		if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
6564887Schin 		{
657*8462SApril.Chin@Sun.COM 			i = ARRAY_TREE;
658*8462SApril.Chin@Sun.COM 			nv_offattr(np,NV_NOFREE);
659*8462SApril.Chin@Sun.COM 		}
660*8462SApril.Chin@Sun.COM 		if(np->nvalue.cp==Empty)
661*8462SApril.Chin@Sun.COM 			np->nvalue.cp=0;
662*8462SApril.Chin@Sun.COM 		if(nv_hasdisc(np,&array_disc) || nv_isvtree(np))
663*8462SApril.Chin@Sun.COM 		{
664*8462SApril.Chin@Sun.COM 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
665*8462SApril.Chin@Sun.COM 			mp = nv_search("0", ap->header.table, 0);
666*8462SApril.Chin@Sun.COM 
6674887Schin 			if(mp && nv_isnull(mp))
6684887Schin 			{
669*8462SApril.Chin@Sun.COM 				Namfun_t *fp;
6704887Schin 				ap->val[0].np = mp;
671*8462SApril.Chin@Sun.COM 				array_setbit(ap->bits,0,ARRAY_CHILD);
672*8462SApril.Chin@Sun.COM 				for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
673*8462SApril.Chin@Sun.COM 				if(fp)
674*8462SApril.Chin@Sun.COM 					(*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
675*8462SApril.Chin@Sun.COM 				i++;
6764887Schin 			}
677*8462SApril.Chin@Sun.COM 		}
678*8462SApril.Chin@Sun.COM 		else if((ap->val[0].cp=np->nvalue.cp))
6794887Schin 			i++;
6804887Schin 		else if(nv_isattr(np,NV_INTEGER))
6814887Schin 		{
6824887Schin 			Sfdouble_t d= nv_getnum(np);
6834887Schin 			i++;
6844887Schin 		}
6854887Schin 		ap->header.nelem = i;
6864887Schin 		ap->header.hdr.disc = &array_disc;
687*8462SApril.Chin@Sun.COM 		nv_disc(np,(Namfun_t*)ap, NV_FIRST);
688*8462SApril.Chin@Sun.COM 		nv_onattr(np,NV_ARRAY);
689*8462SApril.Chin@Sun.COM 		if(mp)
690*8462SApril.Chin@Sun.COM 		{
691*8462SApril.Chin@Sun.COM 			array_copytree(np,mp);
692*8462SApril.Chin@Sun.COM 			ap->header.hdr.nofree &= ~1;
693*8462SApril.Chin@Sun.COM 		}
6944887Schin 	}
6954887Schin 	for(;i < newsize;i++)
6964887Schin 		ap->val[i].cp = 0;
6974887Schin 	return(ap);
6984887Schin }
6994887Schin 
700*8462SApril.Chin@Sun.COM int nv_atypeindex(Namval_t *np, const char *tname)
701*8462SApril.Chin@Sun.COM {
702*8462SApril.Chin@Sun.COM 	Namval_t	*tp;
703*8462SApril.Chin@Sun.COM 	int		offset = staktell();
704*8462SApril.Chin@Sun.COM 	int		n = strlen(tname)-1;
705*8462SApril.Chin@Sun.COM 	sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
706*8462SApril.Chin@Sun.COM 	tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
707*8462SApril.Chin@Sun.COM 	stakseek(offset);
708*8462SApril.Chin@Sun.COM 	if(tp)
709*8462SApril.Chin@Sun.COM 	{
710*8462SApril.Chin@Sun.COM 		struct index_array *ap = (struct index_array*)nv_arrayptr(np);
711*8462SApril.Chin@Sun.COM 		if(!nv_hasdisc(tp,&ENUM_disc))
712*8462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
713*8462SApril.Chin@Sun.COM 		if(!ap)
714*8462SApril.Chin@Sun.COM 			ap = array_grow(np,ap,1);
715*8462SApril.Chin@Sun.COM 		ap->xp = calloc(NV_MINSZ,1);
716*8462SApril.Chin@Sun.COM 		np = nv_namptr(ap->xp,0);
717*8462SApril.Chin@Sun.COM 		np->nvname = tp->nvname;
718*8462SApril.Chin@Sun.COM 		nv_onattr(np,NV_MINIMAL);
719*8462SApril.Chin@Sun.COM 		nv_clone(tp,np,NV_NOFREE);
720*8462SApril.Chin@Sun.COM 		nv_offattr(np,NV_RDONLY);
721*8462SApril.Chin@Sun.COM 		return(1);
722*8462SApril.Chin@Sun.COM 	}
723*8462SApril.Chin@Sun.COM 	errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
724*8462SApril.Chin@Sun.COM 	return(0);
725*8462SApril.Chin@Sun.COM }
726*8462SApril.Chin@Sun.COM 
7274887Schin Namarr_t *nv_arrayptr(register Namval_t *np)
7284887Schin {
7294887Schin 	if(nv_isattr(np,NV_ARRAY))
7304887Schin 		return((Namarr_t*)nv_hasdisc(np, &array_disc));
7314887Schin 	return(0);
7324887Schin }
7334887Schin 
7344887Schin /*
7354887Schin  * Verify that argument is an indexed array and convert to associative,
7364887Schin  * freeing relevant storage
7374887Schin  */
7384887Schin static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
7394887Schin {
7404887Schin 	register Namarr_t *ap;
7414887Schin 	char numbuff[NUMSIZE+1];
7424887Schin 	unsigned dot, digit, n;
7434887Schin 	union Value *up;
7444887Schin 	struct index_array *save_ap;
7454887Schin 	register char *string_index=&numbuff[NUMSIZE];
7464887Schin 	numbuff[NUMSIZE]='\0';
7474887Schin 
7484887Schin 	if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
7494887Schin 		return(NIL(Namarr_t*));
7504887Schin 
7514887Schin 	nv_stack(np,&ap->hdr);
7524887Schin 	save_ap = (struct index_array*)nv_stack(np,0);
7534887Schin 	ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
7544887Schin 	ap->nelem = 0;
7554887Schin 	ap->fun = fun;
7564887Schin 	nv_onattr(np,NV_ARRAY);
7574887Schin 
7584887Schin 	for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
7594887Schin 	{
7604887Schin 		if(save_ap->val[dot].cp)
7614887Schin 		{
7624887Schin 			if ((digit = dot)== 0)
7634887Schin 				*--string_index = '0';
7644887Schin 			else while( n = digit )
7654887Schin 			{
7664887Schin 				digit /= 10;
7674887Schin 				*--string_index = '0' + (n-10*digit);
7684887Schin 			}
7694887Schin 			nv_putsub(np, string_index, ARRAY_ADD);
7704887Schin 			up = (union Value*)((*ap->fun)(np,NIL(char*),0));
7714887Schin 			up->cp = save_ap->val[dot].cp;
7724887Schin 			save_ap->val[dot].cp = 0;
7734887Schin 		}
7744887Schin 		string_index = &numbuff[NUMSIZE];
7754887Schin 	}
7764887Schin 	free((void*)save_ap);
7774887Schin 	return(ap);
7784887Schin }
7794887Schin 
7804887Schin /*
7814887Schin  * set the associative array processing method for node <np> to <fun>
7824887Schin  * The array pointer is returned if sucessful.
7834887Schin  */
7844887Schin Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
7854887Schin {
7864887Schin 	register Namarr_t *ap;
787*8462SApril.Chin@Sun.COM 	char		*value=0;
788*8462SApril.Chin@Sun.COM 	Namfun_t	*fp;
789*8462SApril.Chin@Sun.COM 	int		nelem = 0;
7904887Schin 	if(fun && (ap = nv_arrayptr(np)))
7914887Schin 	{
7924887Schin 		/*
7934887Schin 		 * if it's already an indexed array, convert to
7944887Schin 		 * associative structure
7954887Schin 		 */
7964887Schin 		if(!is_associative(ap))
7974887Schin 			ap = nv_changearray(np, fun);
7984887Schin 		return(ap);
7994887Schin 	}
800*8462SApril.Chin@Sun.COM 	if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
801*8462SApril.Chin@Sun.COM 	{
802*8462SApril.Chin@Sun.COM 		nelem = ARRAY_TREE;
803*8462SApril.Chin@Sun.COM 		nv_offattr(np,NV_NOFREE);
804*8462SApril.Chin@Sun.COM 	}
805*8462SApril.Chin@Sun.COM 	if(!(fp=nv_isvtree(np)))
806*8462SApril.Chin@Sun.COM 		value = nv_getval(np);
8074887Schin 	if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
8084887Schin 	{
8094887Schin 		/* check for preexisting initialization and save */
810*8462SApril.Chin@Sun.COM 		ap->nelem = nelem;
8114887Schin 		ap->fun = fun;
8124887Schin 		nv_onattr(np,NV_ARRAY);
813*8462SApril.Chin@Sun.COM 		if(fp || value)
8144887Schin 		{
8154887Schin 			nv_putsub(np, "0", ARRAY_ADD);
816*8462SApril.Chin@Sun.COM 			if(value)
817*8462SApril.Chin@Sun.COM 				nv_putval(np, value, 0);
818*8462SApril.Chin@Sun.COM 			else
819*8462SApril.Chin@Sun.COM 			{
820*8462SApril.Chin@Sun.COM 				Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
821*8462SApril.Chin@Sun.COM 				array_copytree(np,mp);
822*8462SApril.Chin@Sun.COM 			}
8234887Schin 		}
8244887Schin 		return(ap);
8254887Schin 	}
8264887Schin 	return(NIL(Namarr_t*));
8274887Schin }
8284887Schin 
8294887Schin /*
8304887Schin  * move parent subscript into child
8314887Schin  */
8324887Schin Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
8334887Schin {
834*8462SApril.Chin@Sun.COM 	Namfun_t		*fp;
835*8462SApril.Chin@Sun.COM 	register Namarr_t	*ap = nv_arrayptr(np);
836*8462SApril.Chin@Sun.COM 	union Value		*up;
837*8462SApril.Chin@Sun.COM 	Namval_t		*tp;
838*8462SApril.Chin@Sun.COM 	if(!nq)
839*8462SApril.Chin@Sun.COM 		return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
840*8462SApril.Chin@Sun.COM 	if(!ap)
841*8462SApril.Chin@Sun.COM 	{
842*8462SApril.Chin@Sun.COM 		nv_putsub(np, NIL(char*), ARRAY_FILL);
843*8462SApril.Chin@Sun.COM 		ap = nv_arrayptr(np);
844*8462SApril.Chin@Sun.COM 	}
845*8462SApril.Chin@Sun.COM 	if(!(up = array_getup(np,ap,0)))
8464887Schin 		return((Namval_t*)0);
8474887Schin 	np->nvalue.cp = up->cp;
848*8462SApril.Chin@Sun.COM 	if((tp=nv_type(np)) || c)
8494887Schin 	{
850*8462SApril.Chin@Sun.COM 		ap->nelem |= ARRAY_NOCLONE;
851*8462SApril.Chin@Sun.COM 		nq->nvenv = (char*)np;
852*8462SApril.Chin@Sun.COM 		if(c=='t')
853*8462SApril.Chin@Sun.COM 			nv_clone(tp,nq, 0);
854*8462SApril.Chin@Sun.COM 		else
855*8462SApril.Chin@Sun.COM 			nv_clone(np, nq, NV_NODISC);
856*8462SApril.Chin@Sun.COM 		nv_offattr(nq,NV_ARRAY);
857*8462SApril.Chin@Sun.COM 		ap->nelem &= ~ARRAY_NOCLONE;
8584887Schin 	}
859*8462SApril.Chin@Sun.COM 	nq->nvenv = (char*)np;
860*8462SApril.Chin@Sun.COM 	if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
861*8462SApril.Chin@Sun.COM 		free((void*)fp);
862*8462SApril.Chin@Sun.COM 	if(!ap->fun)
8634887Schin 	{
8644887Schin 		struct index_array *aq = (struct index_array*)ap;
865*8462SApril.Chin@Sun.COM 		array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
8664887Schin 		up->np = nq;
8674887Schin 	}
8684887Schin 	if(c=='.')
8694887Schin 		nv_setvtree(nq);
8704887Schin 	return(nq);
8714887Schin }
8724887Schin 
8734887Schin /*
8744887Schin  * This routine sets subscript of <np> to the next element, if any.
8754887Schin  * The return value is zero, if there are no more elements
8764887Schin  * Otherwise, 1 is returned.
8774887Schin  */
8784887Schin int nv_nextsub(Namval_t *np)
8794887Schin {
880*8462SApril.Chin@Sun.COM 	register struct index_array	*ap = (struct index_array*)nv_arrayptr(np);
881*8462SApril.Chin@Sun.COM 	register unsigned		dot;
882*8462SApril.Chin@Sun.COM 	struct index_array		*aq=0, *ar=0;
8834887Schin 	if(!ap || !(ap->header.nelem&ARRAY_SCAN))
8844887Schin 		return(0);
8854887Schin 	if(is_associative(ap))
8864887Schin 	{
887*8462SApril.Chin@Sun.COM 		Namval_t	*nq;
888*8462SApril.Chin@Sun.COM 		if(nq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT))
8894887Schin 		{
890*8462SApril.Chin@Sun.COM 			if(nv_isattr(nq,NV_CHILD))
891*8462SApril.Chin@Sun.COM 				nv_putsub(nq->nvalue.np,NIL(char*),ARRAY_UNDEF);
8924887Schin 			return(1);
8934887Schin 		}
8944887Schin 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
8954887Schin 		return(0);
8964887Schin 	}
897*8462SApril.Chin@Sun.COM 	if(!(ap->header.nelem&ARRAY_NOSCOPE))
898*8462SApril.Chin@Sun.COM 		ar = (struct index_array*)ap->header.scope;
8994887Schin 	for(dot=ap->cur+1; dot <  (unsigned)ap->maxi; dot++)
9004887Schin 	{
901*8462SApril.Chin@Sun.COM 		aq = ap;
902*8462SApril.Chin@Sun.COM 		if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
903*8462SApril.Chin@Sun.COM 		{
904*8462SApril.Chin@Sun.COM 			if(!(aq=ar) || dot>=(unsigned)aq->maxi)
905*8462SApril.Chin@Sun.COM 				continue;
906*8462SApril.Chin@Sun.COM 		}
907*8462SApril.Chin@Sun.COM 		if(aq->val[dot].cp)
9084887Schin 		{
9094887Schin 			ap->cur = dot;
910*8462SApril.Chin@Sun.COM 			if(array_isbit(aq->bits, dot,ARRAY_CHILD))
9114887Schin 			{
912*8462SApril.Chin@Sun.COM 				Namval_t *mp = aq->val[dot].np;
913*8462SApril.Chin@Sun.COM 				if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp))
9144887Schin 					continue;
915*8462SApril.Chin@Sun.COM 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
9164887Schin 			}
9174887Schin 			return(1);
9184887Schin 		}
9194887Schin 	}
9204887Schin 	ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
9214887Schin 	ap->cur = 0;
9224887Schin 	return(0);
9234887Schin }
9244887Schin 
9254887Schin /*
9264887Schin  * Set an array subscript for node <np> given the subscript <sp>
9274887Schin  * An array is created if necessary.
9284887Schin  * <mode> can be a number, plus or more of symbolic constants
9294887Schin  *    ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
9304887Schin  * The node pointer is returned which can be NULL if <np> is
9314887Schin  *    not already array and the ARRAY_ADD bit of <mode> is not set.
9324887Schin  * ARRAY_FILL sets the specified subscript to the empty string when
9334887Schin  *   ARRAY_ADD is specified and there is no value or sets all
9344887Schin  * the elements up to the number specified if ARRAY_ADD is not specified
9354887Schin  */
9364887Schin Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
9374887Schin {
9384887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
9394887Schin 	register int size = (mode&ARRAY_MASK);
9404887Schin 	if(!ap || !ap->header.fun)
9414887Schin 	{
9424887Schin 		if(sp)
943*8462SApril.Chin@Sun.COM 		{
944*8462SApril.Chin@Sun.COM 			if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
945*8462SApril.Chin@Sun.COM 			{
946*8462SApril.Chin@Sun.COM 				Namval_t *mp = nv_namptr(ap->xp,0);
947*8462SApril.Chin@Sun.COM 				nv_putval(mp, sp,0);
948*8462SApril.Chin@Sun.COM 				size = nv_getnum(mp);
949*8462SApril.Chin@Sun.COM 			}
950*8462SApril.Chin@Sun.COM 			else
951*8462SApril.Chin@Sun.COM 				size = (int)sh_arith((char*)sp);
952*8462SApril.Chin@Sun.COM 		}
953*8462SApril.Chin@Sun.COM 		if(size <0 && ap)
954*8462SApril.Chin@Sun.COM 			size += array_maxindex(np);
9554887Schin 		if(size >= ARRAY_MAX || (size < 0))
9564887Schin 		{
9574887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
9584887Schin 			return(NIL(Namval_t*));
9594887Schin 		}
9604887Schin 		if(!ap || size>=ap->maxi)
9614887Schin 		{
9624887Schin 			if(size==0 && !(mode&ARRAY_FILL))
9634887Schin 				return(NIL(Namval_t*));
9644887Schin 			if(sh.subshell)
9654887Schin 				np = sh_assignok(np,1);
9664887Schin 			ap = array_grow(np, ap,size);
9674887Schin 		}
9684887Schin 		ap->header.nelem &= ~ARRAY_UNDEF;
969*8462SApril.Chin@Sun.COM 		ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
970*8462SApril.Chin@Sun.COM #if 0
971*8462SApril.Chin@Sun.COM 		if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
972*8462SApril.Chin@Sun.COM 			mp = ap->val[oldsize].np;
973*8462SApril.Chin@Sun.COM 		if(size != oldsize && mp->nvalue.cp)
974*8462SApril.Chin@Sun.COM 		{
975*8462SApril.Chin@Sun.COM 			Namfun_t *nfp;
976*8462SApril.Chin@Sun.COM 			for(nfp=np->nvfun; nfp; nfp=nfp->next)
977*8462SApril.Chin@Sun.COM 			{
978*8462SApril.Chin@Sun.COM 				if(nfp->disc && nfp->disc->readf)
979*8462SApril.Chin@Sun.COM 				{
980*8462SApril.Chin@Sun.COM 					(*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
981*8462SApril.Chin@Sun.COM 					break;
982*8462SApril.Chin@Sun.COM 				}
983*8462SApril.Chin@Sun.COM 			}
984*8462SApril.Chin@Sun.COM 		}
985*8462SApril.Chin@Sun.COM #endif
9864887Schin 		ap->cur = size;
987*8462SApril.Chin@Sun.COM 		if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
9884887Schin 			np = 0;
989*8462SApril.Chin@Sun.COM 		if(mode&(ARRAY_FILL|ARRAY_ADD))
9904887Schin 		{
9914887Schin 			if(!(mode&ARRAY_ADD))
9924887Schin 			{
9934887Schin 				int n;
994*8462SApril.Chin@Sun.COM 				for(n=0; n <= size; n++)
9954887Schin 				{
9964887Schin 					if(!ap->val[n].cp)
997*8462SApril.Chin@Sun.COM 					{
9984887Schin 						ap->val[n].cp = Empty;
999*8462SApril.Chin@Sun.COM 						if(!array_covered(np,ap))
1000*8462SApril.Chin@Sun.COM 							ap->header.nelem++;
1001*8462SApril.Chin@Sun.COM 					}
10024887Schin 				}
10034887Schin 				if(n=ap->maxi-ap->maxi)
10044887Schin 					memset(&ap->val[size],0,n*sizeof(union Value));
10054887Schin 			}
10064887Schin 			else if(!ap->val[size].cp)
10074887Schin 			{
10084887Schin 				if(sh.subshell)
10094887Schin 					np = sh_assignok(np,1);
10104887Schin 				ap->val[size].cp = Empty;
1011*8462SApril.Chin@Sun.COM 				if(!array_covered(np,ap))
1012*8462SApril.Chin@Sun.COM 					ap->header.nelem++;
10134887Schin 			}
10144887Schin 		}
10154887Schin 		else if(!(mode&ARRAY_SCAN))
10164887Schin 		{
10174887Schin 			ap->header.nelem &= ~ARRAY_SCAN;
1018*8462SApril.Chin@Sun.COM 			if(array_isbit(ap->bits,size,ARRAY_CHILD))
10194887Schin 				nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
1020*8462SApril.Chin@Sun.COM 			if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
1021*8462SApril.Chin@Sun.COM 				np = 0;
10224887Schin 		}
10234887Schin 		return((Namval_t*)np);
10244887Schin 	}
10254887Schin 	ap->header.nelem &= ~ARRAY_UNDEF;
10264887Schin 	if(!(mode&ARRAY_FILL))
10274887Schin 		ap->header.nelem &= ~ARRAY_SCAN;
1028*8462SApril.Chin@Sun.COM 	ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
10294887Schin 	if(sp)
10304887Schin 	{
10314887Schin 		if(mode&ARRAY_SETSUB)
10324887Schin 		{
10334887Schin 			(*ap->header.fun)(np, sp, NV_ASETSUB);
10344887Schin 			return(np);
10354887Schin 		}
1036*8462SApril.Chin@Sun.COM 		(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
1037*8462SApril.Chin@Sun.COM 		if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
1038*8462SApril.Chin@Sun.COM 			np = 0;
10394887Schin 	}
10404887Schin 	else if(mode&ARRAY_SCAN)
10414887Schin 		(*ap->header.fun)(np,(char*)np,0);
10424887Schin 	else if(mode&ARRAY_UNDEF)
10434887Schin 		(*ap->header.fun)(np, "",0);
10444887Schin 	if((mode&ARRAY_SCAN) && !nv_nextsub(np))
10454887Schin 		np = 0;
10464887Schin 	return(np);
10474887Schin }
10484887Schin 
10494887Schin /*
10504887Schin  * process an array subscript for node <np> given the subscript <cp>
10514887Schin  * returns pointer to character after the subscript
10524887Schin  */
10534887Schin char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
10544887Schin {
10554887Schin 	register int count=1, quoted=0, c;
10564887Schin 	register char *sp = cp+1;
10574887Schin 	/* first find matching ']' */
10584887Schin 	while(count>0 && (c= *++cp))
10594887Schin 	{
10604887Schin 		if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
10614887Schin 		{
10624887Schin 			quoted=1;
10634887Schin 			cp++;
10644887Schin 		}
10654887Schin 		else if(c=='[')
10664887Schin 			count++;
10674887Schin 		else if(c==']')
10684887Schin 			count--;
10694887Schin 	}
10704887Schin 	*cp = 0;
10714887Schin 	if(quoted)
10724887Schin 	{
10734887Schin 		/* strip escape characters */
10744887Schin 		count = staktell();
10754887Schin 		stakwrite(sp,1+cp-sp);
10764887Schin 		sh_trim(sp=stakptr(count));
10774887Schin 	}
10784887Schin 	if(mode && np)
1079*8462SApril.Chin@Sun.COM 	{
1080*8462SApril.Chin@Sun.COM 		if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
1081*8462SApril.Chin@Sun.COM 			mode |= NV_ADD;
1082*8462SApril.Chin@Sun.COM 		nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
1083*8462SApril.Chin@Sun.COM 	}
10844887Schin 	if(quoted)
10854887Schin 		stakseek(count);
10864887Schin 	*cp++ = c;
10874887Schin 	return(cp);
10884887Schin }
10894887Schin 
10904887Schin 
10914887Schin Namval_t *nv_opensub(Namval_t* np)
10924887Schin {
10934887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1094*8462SApril.Chin@Sun.COM 	if(ap)
1095*8462SApril.Chin@Sun.COM 	{
1096*8462SApril.Chin@Sun.COM 		if(is_associative(ap))
1097*8462SApril.Chin@Sun.COM 			return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
1098*8462SApril.Chin@Sun.COM 		else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
1099*8462SApril.Chin@Sun.COM 			return(ap->val[ap->cur].np);
1100*8462SApril.Chin@Sun.COM 	}
11014887Schin 	return(NIL(Namval_t*));
11024887Schin }
11034887Schin 
11044887Schin char	*nv_getsub(Namval_t* np)
11054887Schin {
11064887Schin 	static char numbuff[NUMSIZE];
11074887Schin 	register struct index_array *ap;
11084887Schin 	register unsigned dot, n;
11094887Schin 	register char *cp = &numbuff[NUMSIZE];
11104887Schin 	if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
11114887Schin 		return(NIL(char*));
11124887Schin 	if(is_associative(ap))
11134887Schin 		return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
1114*8462SApril.Chin@Sun.COM 	if(ap->xp)
1115*8462SApril.Chin@Sun.COM 	{
1116*8462SApril.Chin@Sun.COM 		np = nv_namptr(ap->xp,0);
1117*8462SApril.Chin@Sun.COM 		np->nvalue.s = ap->cur;
1118*8462SApril.Chin@Sun.COM 		return(nv_getval(np));
1119*8462SApril.Chin@Sun.COM 	}
11204887Schin 	if((dot = ap->cur)==0)
11214887Schin 		*--cp = '0';
11224887Schin 	else while(n=dot)
11234887Schin 	{
11244887Schin 		dot /= 10;
11254887Schin 		*--cp = '0' + (n-10*dot);
11264887Schin 	}
11274887Schin 	return(cp);
11284887Schin }
11294887Schin 
11304887Schin /*
11314887Schin  * If <np> is an indexed array node, the current subscript index
11324887Schin  * returned, otherwise returns -1
11334887Schin  */
11344887Schin int nv_aindex(register Namval_t* np)
11354887Schin {
11364887Schin 	Namarr_t *ap = nv_arrayptr(np);
1137*8462SApril.Chin@Sun.COM 	if(!ap)
1138*8462SApril.Chin@Sun.COM 		return(0);
1139*8462SApril.Chin@Sun.COM 	else if(is_associative(ap))
11404887Schin 		return(-1);
11414887Schin 	return(((struct index_array*)(ap))->cur&ARRAY_MASK);
11424887Schin }
11434887Schin 
1144*8462SApril.Chin@Sun.COM int nv_arraynsub(register Namarr_t* ap)
1145*8462SApril.Chin@Sun.COM {
1146*8462SApril.Chin@Sun.COM 	return(array_elem(ap));
1147*8462SApril.Chin@Sun.COM }
1148*8462SApril.Chin@Sun.COM 
1149*8462SApril.Chin@Sun.COM int nv_aimax(register Namval_t* np)
1150*8462SApril.Chin@Sun.COM {
1151*8462SApril.Chin@Sun.COM 	struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1152*8462SApril.Chin@Sun.COM 	int sub = -1;
1153*8462SApril.Chin@Sun.COM 	if(!ap || is_associative(&ap->header))
1154*8462SApril.Chin@Sun.COM 		return(-1);
1155*8462SApril.Chin@Sun.COM 	sub = ap->maxi;
1156*8462SApril.Chin@Sun.COM 	while(--sub>0 && ap->val[sub].cp==0);
1157*8462SApril.Chin@Sun.COM 	return(sub);
1158*8462SApril.Chin@Sun.COM }
11594887Schin 
11604887Schin /*
1161*8462SApril.Chin@Sun.COM  *  This is the default implementation for associative arrays
11624887Schin  */
11634887Schin void *nv_associative(register Namval_t *np,const char *sp,int mode)
11644887Schin {
11654887Schin 	register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
11664887Schin 	register int type;
11674887Schin 	switch(mode)
11684887Schin 	{
11694887Schin 	    case NV_AINIT:
11704887Schin 		if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
11714887Schin 		{
1172*8462SApril.Chin@Sun.COM 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
11734887Schin 			ap->cur = 0;
11744887Schin 			ap->pos = 0;
11754887Schin 			ap->header.hdr.disc = &array_disc;
1176*8462SApril.Chin@Sun.COM 			nv_disc(np,(Namfun_t*)ap, NV_FIRST);
1177*8462SApril.Chin@Sun.COM 			ap->header.hdr.dsize = sizeof(struct assoc_array);
1178*8462SApril.Chin@Sun.COM 			ap->header.hdr.nofree &= ~1;
11794887Schin 		}
11804887Schin 		return((void*)ap);
11814887Schin 	    case NV_ADELETE:
11824887Schin 		if(ap->cur)
11834887Schin 		{
1184*8462SApril.Chin@Sun.COM 			if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0))
1185*8462SApril.Chin@Sun.COM 				ap->header.nelem--;
1186*8462SApril.Chin@Sun.COM 			_nv_unset(ap->cur,NV_RDONLY);
1187*8462SApril.Chin@Sun.COM 			nv_delete(ap->cur,ap->header.table,0);
1188*8462SApril.Chin@Sun.COM 			ap->cur = 0;
11894887Schin 		}
11904887Schin 		return((void*)ap);
11914887Schin 	    case NV_AFREE:
11924887Schin 		ap->pos = 0;
1193*8462SApril.Chin@Sun.COM 		if(ap->header.scope)
1194*8462SApril.Chin@Sun.COM 		{
1195*8462SApril.Chin@Sun.COM 			ap->header.table = dtview(ap->header.table,(Dt_t*)0);
1196*8462SApril.Chin@Sun.COM 			dtclose(ap->header.scope);
1197*8462SApril.Chin@Sun.COM 			ap->header.scope = 0;
1198*8462SApril.Chin@Sun.COM 		}
1199*8462SApril.Chin@Sun.COM 		else
1200*8462SApril.Chin@Sun.COM 			dtclose(ap->header.table);
12014887Schin 		return((void*)ap);
12024887Schin 	    case NV_ANEXT:
12034887Schin 		if(!ap->pos)
12044887Schin 		{
1205*8462SApril.Chin@Sun.COM 			if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
1206*8462SApril.Chin@Sun.COM 			{
1207*8462SApril.Chin@Sun.COM 				ap->header.scope = dtvnext(ap->header.table);
1208*8462SApril.Chin@Sun.COM 				ap->header.table->view = 0;
1209*8462SApril.Chin@Sun.COM 			}
12104887Schin 			if(!(ap->pos=ap->cur))
1211*8462SApril.Chin@Sun.COM 				ap->pos = (Namval_t*)dtfirst(ap->header.table);
12124887Schin 		}
12134887Schin 		else
12144887Schin 			ap->pos = ap->nextpos;
12154887Schin 		for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
12164887Schin 		{
1217*8462SApril.Chin@Sun.COM 			ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
12184887Schin 			if(ap->cur->nvalue.cp)
12194887Schin 			{
12204887Schin 				if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
12214887Schin 					continue;
12224887Schin 				return((void*)ap);
12234887Schin 			}
12244887Schin 		}
1225*8462SApril.Chin@Sun.COM 		if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
1226*8462SApril.Chin@Sun.COM 		{
1227*8462SApril.Chin@Sun.COM 			ap->header.table->view = (Dt_t*)ap->header.scope;
1228*8462SApril.Chin@Sun.COM 			ap->header.scope = ap->header.table;
1229*8462SApril.Chin@Sun.COM 		}
12304887Schin 		return(NIL(void*));
12314887Schin 	    case NV_ASETSUB:
12324887Schin 		ap->cur = (Namval_t*)sp;
1233*8462SApril.Chin@Sun.COM 		return((void*)ap->cur);
12344887Schin 	    case NV_ACURRENT:
1235*8462SApril.Chin@Sun.COM 		if(ap->cur)
1236*8462SApril.Chin@Sun.COM 			ap->cur->nvenv = (char*)np;
12374887Schin 		return((void*)ap->cur);
12384887Schin 	    case NV_ANAME:
12394887Schin 		if(ap->cur)
1240*8462SApril.Chin@Sun.COM 			return((void*)ap->cur->nvname);
12414887Schin 		return(NIL(void*));
12424887Schin 	    default:
12434887Schin 		if(sp)
12444887Schin 		{
1245*8462SApril.Chin@Sun.COM 			Namval_t *mp=0;
1246*8462SApril.Chin@Sun.COM 			ap->cur = 0;
12474887Schin 			if(sp==(char*)np)
1248*8462SApril.Chin@Sun.COM 				return(0);
1249*8462SApril.Chin@Sun.COM 			type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
1250*8462SApril.Chin@Sun.COM 			if(mode)
1251*8462SApril.Chin@Sun.COM 				mode = NV_ADD|HASH_NOSCOPE;
1252*8462SApril.Chin@Sun.COM 			else if(ap->header.nelem&ARRAY_NOSCOPE)
1253*8462SApril.Chin@Sun.COM 				mode = HASH_NOSCOPE;
1254*8462SApril.Chin@Sun.COM 			if(*sp==0 && (mode&NV_ADD))
1255*8462SApril.Chin@Sun.COM 				sfprintf(sfstderr,"adding empty subscript\n");
1256*8462SApril.Chin@Sun.COM 			if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
1257*8462SApril.Chin@Sun.COM 				ap->cur = mp;
1258*8462SApril.Chin@Sun.COM 			if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
12594887Schin 			{
1260*8462SApril.Chin@Sun.COM 				nv_onattr(mp,type);
1261*8462SApril.Chin@Sun.COM 				mp->nvenv = (char*)np;
1262*8462SApril.Chin@Sun.COM 				if((mode&NV_ADD) && nv_type(np))
1263*8462SApril.Chin@Sun.COM 					nv_arraychild(np,mp,0);
1264*8462SApril.Chin@Sun.COM 				if(sh.subshell)
1265*8462SApril.Chin@Sun.COM 					np = sh_assignok(np,1);
1266*8462SApril.Chin@Sun.COM 				if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
1267*8462SApril.Chin@Sun.COM 					ap->header.nelem++;
1268*8462SApril.Chin@Sun.COM 				if(nv_isnull(mp))
1269*8462SApril.Chin@Sun.COM 				{
1270*8462SApril.Chin@Sun.COM 					if(ap->header.nelem&ARRAY_TREE)
1271*8462SApril.Chin@Sun.COM 						nv_setvtree(mp);
1272*8462SApril.Chin@Sun.COM 					mp->nvalue.cp = Empty;
1273*8462SApril.Chin@Sun.COM 				}
12744887Schin 			}
1275*8462SApril.Chin@Sun.COM 			else if(ap->header.nelem&ARRAY_SCAN)
1276*8462SApril.Chin@Sun.COM 			{
1277*8462SApril.Chin@Sun.COM 				Namval_t fake;
1278*8462SApril.Chin@Sun.COM 				fake.nvname = (char*)sp;
1279*8462SApril.Chin@Sun.COM 				ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
1280*8462SApril.Chin@Sun.COM 				ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
1281*8462SApril.Chin@Sun.COM 			}
1282*8462SApril.Chin@Sun.COM 			np = mp;
1283*8462SApril.Chin@Sun.COM 			if(ap->pos != np && !(ap->header.nelem&ARRAY_SCAN))
12844887Schin 				ap->pos = 0;
12854887Schin 			ap->cur = np;
12864887Schin 		}
12874887Schin 		if(ap->cur)
12884887Schin 			return((void*)(&ap->cur->nvalue));
12894887Schin 		else
12904887Schin 			return((void*)(&ap->cur));
12914887Schin 	}
12924887Schin }
12934887Schin 
12944887Schin /*
12954887Schin  * Assign values to an array
12964887Schin  */
12974887Schin void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
12984887Schin {
12994887Schin 	int arg0=0;
1300*8462SApril.Chin@Sun.COM 	struct index_array *ap=0,*aq;
13014887Schin 	if(nv_isarray(np))
13024887Schin 	{
13034887Schin 		ap = (struct index_array*)nv_arrayptr(np);
13044887Schin 		if(ap && is_associative(ap))
1305*8462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
13064887Schin 	}
13074887Schin 	if(append)
13084887Schin 	{
13094887Schin 		if(ap)
13104887Schin 		{
1311*8462SApril.Chin@Sun.COM 			if(!(aq = (struct index_array*)ap->header.scope))
1312*8462SApril.Chin@Sun.COM 				aq = ap;
13134887Schin 			arg0 = ap->maxi;
1314*8462SApril.Chin@Sun.COM 			while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
13154887Schin 			arg0++;
13164887Schin 		}
13174887Schin 		else if(!nv_isnull(np))
13184887Schin 			arg0=1;
13194887Schin 	}
13204887Schin 	while(--argc >= 0)
13214887Schin 	{
1322*8462SApril.Chin@Sun.COM 		nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
13234887Schin 		nv_putval(np,argv[argc],0);
13244887Schin 	}
13254887Schin }
13264887Schin 
1327