xref: /onnv-gate/usr/src/lib/libshell/common/sh/array.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.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))
368462SApril.Chin@Sun.COM #define array_setbit(cp, n, b)	(cp[n] |= (b))
378462SApril.Chin@Sun.COM #define array_clrbit(cp, n, b)	(cp[n] &= ~(b))
388462SApril.Chin@Sun.COM #define array_isbit(cp, n, b)	(cp[n] & (b))
394887Schin #define NV_CHILD		NV_EXPORT
408462SApril.Chin@Sun.COM #define ARRAY_CHILD		1
418462SApril.Chin@Sun.COM #define ARRAY_NOFREE		2
424887Schin 
434887Schin struct index_array
444887Schin {
454887Schin         Namarr_t        header;
468462SApril.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 
array_scope(Namval_t * np,Namarr_t * ap,int flags)618462SApril.Chin@Sun.COM static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
628462SApril.Chin@Sun.COM {
638462SApril.Chin@Sun.COM 	Namarr_t *aq;
648462SApril.Chin@Sun.COM 	struct index_array *ar;
658462SApril.Chin@Sun.COM 	size_t size = ap->hdr.dsize;
668462SApril.Chin@Sun.COM 	if(size==0)
678462SApril.Chin@Sun.COM 		size = ap->hdr.disc->dsize;
688462SApril.Chin@Sun.COM         if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
698462SApril.Chin@Sun.COM                 return(0);
708462SApril.Chin@Sun.COM         memcpy(aq,ap,size);
718462SApril.Chin@Sun.COM 	aq->hdr.nofree &= ~1;
728462SApril.Chin@Sun.COM         aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
738462SApril.Chin@Sun.COM 	if(is_associative(aq))
748462SApril.Chin@Sun.COM 	{
758462SApril.Chin@Sun.COM 		aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
768462SApril.Chin@Sun.COM 		dtview((Dt_t*)aq->scope,aq->table);
778462SApril.Chin@Sun.COM 		aq->table = (Dt_t*)aq->scope;
788462SApril.Chin@Sun.COM 		return(aq);
798462SApril.Chin@Sun.COM 	}
808462SApril.Chin@Sun.COM 	aq->scope = (void*)ap;
818462SApril.Chin@Sun.COM 	ar = (struct index_array*)aq;
828462SApril.Chin@Sun.COM 	memset(ar->val, 0, ar->maxi*sizeof(char*));
838462SApril.Chin@Sun.COM 	return(aq);
848462SApril.Chin@Sun.COM }
858462SApril.Chin@Sun.COM 
array_unscope(Namval_t * np,Namarr_t * ap)868462SApril.Chin@Sun.COM static int array_unscope(Namval_t *np,Namarr_t *ap)
878462SApril.Chin@Sun.COM {
888462SApril.Chin@Sun.COM 	Namfun_t *fp;
898462SApril.Chin@Sun.COM 	if(!ap->scope)
908462SApril.Chin@Sun.COM 		return(0);
918462SApril.Chin@Sun.COM 	if(is_associative(ap))
928462SApril.Chin@Sun.COM 		(*ap->fun)(np, NIL(char*), NV_AFREE);
938462SApril.Chin@Sun.COM 	if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
948462SApril.Chin@Sun.COM 		free((void*)fp);
958462SApril.Chin@Sun.COM 	nv_delete(np,(Dt_t*)0,0);
968462SApril.Chin@Sun.COM 	return(1);
978462SApril.Chin@Sun.COM }
988462SApril.Chin@Sun.COM 
array_syncsub(Namarr_t * ap,Namarr_t * aq)998462SApril.Chin@Sun.COM static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
1008462SApril.Chin@Sun.COM {
1018462SApril.Chin@Sun.COM 	((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
1028462SApril.Chin@Sun.COM }
1038462SApril.Chin@Sun.COM 
array_covered(Namval_t * np,struct index_array * ap)1048462SApril.Chin@Sun.COM static int array_covered(Namval_t *np, struct index_array *ap)
1058462SApril.Chin@Sun.COM {
1068462SApril.Chin@Sun.COM 	struct index_array *aq = (struct index_array*)ap->header.scope;
1078462SApril.Chin@Sun.COM 	if(!ap->header.fun && aq)
1088462SApril.Chin@Sun.COM 		return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
1098462SApril.Chin@Sun.COM 	return(0);
1108462SApril.Chin@Sun.COM }
1118462SApril.Chin@Sun.COM 
1124887Schin /*
1134887Schin  * replace discipline with new one
1144887Schin  */
array_setptr(register Namval_t * np,struct index_array * old,struct index_array * new)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  */
arsize(struct index_array * ap,register int maxi)1358462SApril.Chin@Sun.COM static int	arsize(struct index_array *ap, register int maxi)
1364887Schin {
1378462SApril.Chin@Sun.COM 	if(ap && maxi < 2*ap->maxi)
1388462SApril.Chin@Sun.COM 		maxi = 2*ap->maxi;
1398462SApril.Chin@Sun.COM 	maxi = roundof(maxi,ARRAY_INCR);
1408462SApril.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 */
array_maxindex(Namval_t * np)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 
array_getup(Namval_t * np,Namarr_t * arp,int update)1568462SApril.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;
1608462SApril.Chin@Sun.COM 	int	nofree;
1618462SApril.Chin@Sun.COM 	if(!arp)
1624887Schin 		return(&np->nvalue);
1634887Schin 	if(is_associative(ap))
1648462SApril.Chin@Sun.COM 	{
1658462SApril.Chin@Sun.COM 		Namval_t	*mp;
1668462SApril.Chin@Sun.COM 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
1678462SApril.Chin@Sun.COM 		if(mp)
1688462SApril.Chin@Sun.COM 		{
1698462SApril.Chin@Sun.COM 			nofree = nv_isattr(mp,NV_NOFREE);
1708462SApril.Chin@Sun.COM 			up = &mp->nvalue;
1718462SApril.Chin@Sun.COM 		}
1728462SApril.Chin@Sun.COM 		else
1738462SApril.Chin@Sun.COM 			return((union Value*)((*arp->fun)(np,NIL(char*),0)));
1748462SApril.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]);
1808462SApril.Chin@Sun.COM 		nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
1818462SApril.Chin@Sun.COM 	}
1828462SApril.Chin@Sun.COM 	if(update)
1838462SApril.Chin@Sun.COM 	{
1848462SApril.Chin@Sun.COM 		if(nofree)
1858462SApril.Chin@Sun.COM 			nv_onattr(np,NV_NOFREE);
1868462SApril.Chin@Sun.COM 		else
1878462SApril.Chin@Sun.COM 			nv_offattr(np,NV_NOFREE);
1884887Schin 	}
1894887Schin 	return(up);
1904887Schin }
1914887Schin 
nv_arrayisset(Namval_t * np,Namarr_t * arp)19210898Sroland.mainz@nrubsig.org int nv_arrayisset(Namval_t *np, Namarr_t *arp)
19310898Sroland.mainz@nrubsig.org {
19410898Sroland.mainz@nrubsig.org 	register struct index_array *ap = (struct index_array*)arp;
19510898Sroland.mainz@nrubsig.org 	union Value *up;
19610898Sroland.mainz@nrubsig.org 	if(is_associative(ap))
19710898Sroland.mainz@nrubsig.org 		return((np = nv_opensub(np)) && !nv_isnull(np));
19810898Sroland.mainz@nrubsig.org 	if(ap->cur >= ap->maxi)
19910898Sroland.mainz@nrubsig.org 		return(0);
20010898Sroland.mainz@nrubsig.org 	up = &(ap->val[ap->cur]);
20110898Sroland.mainz@nrubsig.org 	return(up->cp && up->cp!=Empty);
20210898Sroland.mainz@nrubsig.org }
20310898Sroland.mainz@nrubsig.org 
2044887Schin /*
2054887Schin  * Get the Value pointer for an array.
2064887Schin  * Delete space as necessary if flag is ARRAY_DELETE
2074887Schin  * After the lookup is done the last @ or * subscript is incremented
2084887Schin  */
array_find(Namval_t * np,Namarr_t * arp,int flag)2094887Schin static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
2104887Schin {
2114887Schin 	register struct index_array *ap = (struct index_array*)arp;
2124887Schin 	register union Value	*up;
2134887Schin 	Namval_t		*mp;
2144887Schin 	int			wasundef;
2158462SApril.Chin@Sun.COM 	if(flag&ARRAY_LOOKUP)
2168462SApril.Chin@Sun.COM 		ap->header.nelem &= ~ARRAY_NOSCOPE;
2178462SApril.Chin@Sun.COM 	else
2188462SApril.Chin@Sun.COM 		ap->header.nelem |= ARRAY_NOSCOPE;
2194887Schin 	if(wasundef = ap->header.nelem&ARRAY_UNDEF)
2204887Schin 	{
2214887Schin 		ap->header.nelem &= ~ARRAY_UNDEF;
2224887Schin 		/* delete array is the same as delete array[@] */
2234887Schin 		if(flag&ARRAY_DELETE)
2244887Schin 		{
2258462SApril.Chin@Sun.COM 			nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
2264887Schin 			ap->header.nelem |= ARRAY_SCAN;
2274887Schin 		}
2284887Schin 		else /* same as array[0] */
2294887Schin 		{
2304887Schin 			if(is_associative(ap))
2314887Schin 				(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
2324887Schin 			else
2334887Schin 				ap->cur = 0;
2344887Schin 		}
2354887Schin 	}
2364887Schin 	if(is_associative(ap))
2374887Schin 	{
2384887Schin 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
2394887Schin 		if(!mp)
2404887Schin 			up = (union Value*)&mp;
2418462SApril.Chin@Sun.COM 		else if(nv_isarray(mp))
2424887Schin 		{
2438462SApril.Chin@Sun.COM 			if(wasundef)
2448462SApril.Chin@Sun.COM 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
2458462SApril.Chin@Sun.COM 			return(mp);
2464887Schin 		}
2474887Schin 		else
2488462SApril.Chin@Sun.COM 		{
2494887Schin 			up =  &mp->nvalue;
2508462SApril.Chin@Sun.COM 			if(nv_isvtree(mp))
2518462SApril.Chin@Sun.COM 			{
2528462SApril.Chin@Sun.COM 				if(!up->cp && flag==ARRAY_ASSIGN)
2538462SApril.Chin@Sun.COM 				{
2548462SApril.Chin@Sun.COM 					nv_arraychild(np,mp,0);
2558462SApril.Chin@Sun.COM 					ap->header.nelem++;
2568462SApril.Chin@Sun.COM 				}
2578462SApril.Chin@Sun.COM 				return(mp);
2588462SApril.Chin@Sun.COM 			}
2598462SApril.Chin@Sun.COM 		}
2604887Schin 	}
2614887Schin 	else
2624887Schin 	{
2634887Schin 		if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
2644887Schin 			ap = array_grow(np, ap, (int)ap->cur);
2654887Schin 		if(ap->cur>=ap->maxi)
2664887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
2674887Schin 		up = &(ap->val[ap->cur]);
2688462SApril.Chin@Sun.COM 		if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
2698462SApril.Chin@Sun.COM 		{
2708462SApril.Chin@Sun.COM 			char *cp;
2718462SApril.Chin@Sun.COM 			if(!ap->header.table)
2728462SApril.Chin@Sun.COM 				ap->header.table = dtopen(&_Nvdisc,Dtoset);
2738462SApril.Chin@Sun.COM 			sfprintf(sh.strbuf,"%d",ap->cur);
2748462SApril.Chin@Sun.COM 			cp = sfstruse(sh.strbuf);
2758462SApril.Chin@Sun.COM 			mp = nv_search(cp, ap->header.table, NV_ADD);
2768462SApril.Chin@Sun.COM 			mp->nvenv = (char*)np;
2778462SApril.Chin@Sun.COM 			nv_arraychild(np,mp,0);
2788462SApril.Chin@Sun.COM 		}
2798462SApril.Chin@Sun.COM 		if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
2804887Schin 		{
2814887Schin 			if(wasundef && nv_isarray(up->np))
2824887Schin 				nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
2834887Schin 			return(up->np);
2844887Schin 		}
2854887Schin 	}
2864887Schin 	np->nvalue.cp = up->cp;
2874887Schin 	if(!up->cp)
2884887Schin 	{
289*12068SRoger.Faulkner@Oracle.COM 			char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np);
2904887Schin 		if(flag!=ARRAY_ASSIGN)
291*12068SRoger.Faulkner@Oracle.COM 			return(xp && xp!=(char*)np?np:0);
2928462SApril.Chin@Sun.COM 		if(!array_covered(np,ap))
2938462SApril.Chin@Sun.COM 			ap->header.nelem++;
2944887Schin 	}
2954887Schin 	return(np);
2964887Schin }
2974887Schin 
2988462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
nv_arraysettype(Namval_t * np,Namval_t * tp,const char * sub,int flags)2998462SApril.Chin@Sun.COM int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
3008462SApril.Chin@Sun.COM {
3018462SApril.Chin@Sun.COM 	Namval_t	*nq;
3028462SApril.Chin@Sun.COM 	char		*av[2];
3038462SApril.Chin@Sun.COM 	int		rdonly = nv_isattr(np,NV_RDONLY);
3048462SApril.Chin@Sun.COM 	int		xtrace = sh_isoption(SH_XTRACE);
3058462SApril.Chin@Sun.COM 	Namarr_t	*ap = nv_arrayptr(np);
3068462SApril.Chin@Sun.COM 	av[1] = 0;
3078462SApril.Chin@Sun.COM 	sh.last_table = 0;
3088462SApril.Chin@Sun.COM 	if(!ap->table)
3098462SApril.Chin@Sun.COM 		ap->table = dtopen(&_Nvdisc,Dtoset);
3108462SApril.Chin@Sun.COM 	if(nq = nv_search(sub, ap->table, NV_ADD))
3118462SApril.Chin@Sun.COM 	{
3128462SApril.Chin@Sun.COM 		if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
3138462SApril.Chin@Sun.COM 			_nv_unset(nq,NV_RDONLY);
3148462SApril.Chin@Sun.COM 		nv_arraychild(np,nq,0);
3158462SApril.Chin@Sun.COM 		if(!nv_isattr(tp,NV_BINARY))
3168462SApril.Chin@Sun.COM 		{
3178462SApril.Chin@Sun.COM 			sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
3188462SApril.Chin@Sun.COM 			av[0] = strdup(sfstruse(sh.strbuf));
3198462SApril.Chin@Sun.COM 		}
3208462SApril.Chin@Sun.COM 		if(!nv_clone(tp,nq,flags|NV_NOFREE))
3218462SApril.Chin@Sun.COM 			return(0);
3228462SApril.Chin@Sun.COM 		ap->nelem |= ARRAY_SCAN;
3238462SApril.Chin@Sun.COM 		if(!rdonly)
3248462SApril.Chin@Sun.COM 			nv_offattr(nq,NV_RDONLY);
3258462SApril.Chin@Sun.COM 		if(!nv_isattr(tp,NV_BINARY))
3268462SApril.Chin@Sun.COM 		{
3278462SApril.Chin@Sun.COM 			if(xtrace)
3288462SApril.Chin@Sun.COM 				sh_offoption(SH_XTRACE);
3298462SApril.Chin@Sun.COM 			ap->nelem &= ~ARRAY_SCAN;
3308462SApril.Chin@Sun.COM 			sh_eval(sh_sfeval(av),0);
3318462SApril.Chin@Sun.COM 			ap->nelem |= ARRAY_SCAN;
3328462SApril.Chin@Sun.COM 			free((void*)av[0]);
3338462SApril.Chin@Sun.COM 			if(xtrace)
3348462SApril.Chin@Sun.COM 				sh_onoption(SH_XTRACE);
3358462SApril.Chin@Sun.COM 		}
3368462SApril.Chin@Sun.COM 		return(1);
3378462SApril.Chin@Sun.COM 	}
3388462SApril.Chin@Sun.COM 	return(0);
3398462SApril.Chin@Sun.COM }
3408462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
3418462SApril.Chin@Sun.COM 
3428462SApril.Chin@Sun.COM 
array_clone(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)3434887Schin static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
3444887Schin {
3454887Schin 	Namarr_t		*ap = (Namarr_t*)fp;
3464887Schin 	Namval_t		*nq, *mq;
3474887Schin 	char			*name, *sub=0;
3488462SApril.Chin@Sun.COM 	int			nelem, skipped=0;
3498462SApril.Chin@Sun.COM 	Dt_t			*otable=ap->table;
3508462SApril.Chin@Sun.COM 	struct index_array	*aq = (struct index_array*)ap, *ar;
3518462SApril.Chin@Sun.COM 	Shell_t			*shp = sh_getinterp();
3528462SApril.Chin@Sun.COM 	if(flags&NV_MOVE)
3538462SApril.Chin@Sun.COM 	{
3548462SApril.Chin@Sun.COM 		if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
3558462SApril.Chin@Sun.COM 		{
3568462SApril.Chin@Sun.COM 			do
3578462SApril.Chin@Sun.COM 			{
3588462SApril.Chin@Sun.COM 				if(nq=nv_opensub(np))
3598462SApril.Chin@Sun.COM 					nq->nvenv = (void*)mp;
3608462SApril.Chin@Sun.COM 			}
3618462SApril.Chin@Sun.COM 			while(nv_nextsub(np));
3628462SApril.Chin@Sun.COM 		}
3638462SApril.Chin@Sun.COM 		return(fp);
3648462SApril.Chin@Sun.COM 	}
3658462SApril.Chin@Sun.COM 	nelem = ap->nelem;
3664887Schin 	if(nelem&ARRAY_NOCLONE)
3674887Schin 		return(0);
3688462SApril.Chin@Sun.COM 	if((flags&NV_TYPE) && !ap->scope)
3698462SApril.Chin@Sun.COM 	{
3708462SApril.Chin@Sun.COM 		ap = array_scope(np,ap,flags);
3718462SApril.Chin@Sun.COM 		return(&ap->hdr);
3728462SApril.Chin@Sun.COM 	}
3738462SApril.Chin@Sun.COM 	ap = (Namarr_t*)nv_clone_disc(fp,0);
3748462SApril.Chin@Sun.COM 	if(flags&NV_COMVAR)
3754887Schin 	{
3768462SApril.Chin@Sun.COM 		ap->scope = 0;
3778462SApril.Chin@Sun.COM 		ap->nelem = 0;
3788462SApril.Chin@Sun.COM 		sh.prev_table = sh.last_table;
3798462SApril.Chin@Sun.COM 		sh.prev_root = sh.last_root;
3804887Schin 	}
3818462SApril.Chin@Sun.COM 	if(ap->table)
3828462SApril.Chin@Sun.COM 	{
3838462SApril.Chin@Sun.COM 		ap->table = dtopen(&_Nvdisc,Dtoset);
3848462SApril.Chin@Sun.COM 		if(ap->scope && !(flags&NV_COMVAR))
3858462SApril.Chin@Sun.COM 		{
3868462SApril.Chin@Sun.COM 			ap->scope = ap->table;
3878462SApril.Chin@Sun.COM 			dtview(ap->table, otable->view);
3888462SApril.Chin@Sun.COM 		}
3898462SApril.Chin@Sun.COM 	}
3908462SApril.Chin@Sun.COM 	mp->nvfun = (Namfun_t*)ap;
3918462SApril.Chin@Sun.COM 	mp->nvflag &= NV_MINIMAL;
3928462SApril.Chin@Sun.COM 	mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
3934887Schin 	if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
3944887Schin 		sub = strdup(sub);
3954887Schin 	ar = (struct index_array*)ap;
3968462SApril.Chin@Sun.COM 	if(!is_associative(ap))
3978462SApril.Chin@Sun.COM 		ar->bits = (unsigned char*)&ar->val[ar->maxi];
3988462SApril.Chin@Sun.COM 	if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
3998462SApril.Chin@Sun.COM 	{
4008462SApril.Chin@Sun.COM 		if(ap->fun)
4018462SApril.Chin@Sun.COM 			(*ap->fun)(np,(char*)np,0);
4028462SApril.Chin@Sun.COM 		skipped=1;
4038462SApril.Chin@Sun.COM 		goto skip;
4048462SApril.Chin@Sun.COM 	}
4054887Schin 	do
4064887Schin 	{
4078462SApril.Chin@Sun.COM 		name = nv_getsub(np);
4088462SApril.Chin@Sun.COM 		nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
4098462SApril.Chin@Sun.COM 		mq = 0;
4108462SApril.Chin@Sun.COM 		if(nq=nv_opensub(np))
4118462SApril.Chin@Sun.COM 			mq = nv_search(name,ap->table,NV_ADD);
4128462SApril.Chin@Sun.COM 		if(nq && (flags&NV_COMVAR) && nv_isvtree(nq))
4134887Schin 		{
4148462SApril.Chin@Sun.COM 			mq->nvalue.cp = 0;
4158462SApril.Chin@Sun.COM 			if(!is_associative(ap))
4168462SApril.Chin@Sun.COM 				ar->val[ar->cur].np = mq;
4178462SApril.Chin@Sun.COM 			nv_clone(nq,mq,flags);
4188462SApril.Chin@Sun.COM 		}
4198462SApril.Chin@Sun.COM 		else if(flags&NV_ARRAY)
4208462SApril.Chin@Sun.COM 		{
4218462SApril.Chin@Sun.COM 			if((flags&NV_NOFREE) && !is_associative(ap))
4228462SApril.Chin@Sun.COM 				array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
4238462SApril.Chin@Sun.COM 			else if(nq && (flags&NV_NOFREE))
4244887Schin 			{
4258462SApril.Chin@Sun.COM 				mq->nvalue = nq->nvalue;
4268462SApril.Chin@Sun.COM 				nv_onattr(nq,NV_NOFREE);
4274887Schin 			}
4284887Schin 		}
4294887Schin 		else if(nv_isattr(np,NV_INTEGER))
4304887Schin 		{
4314887Schin 			Sfdouble_t d= nv_getnum(np);
4328462SApril.Chin@Sun.COM 			if(!is_associative(ap))
4338462SApril.Chin@Sun.COM 				ar->val[ar->cur].cp = 0;
4344887Schin 			nv_putval(mp,(char*)&d,NV_LDOUBLE);
4354887Schin 		}
4364887Schin 		else
4378462SApril.Chin@Sun.COM 		{
4388462SApril.Chin@Sun.COM 			if(!is_associative(ap))
4398462SApril.Chin@Sun.COM 				ar->val[ar->cur].cp = 0;
4404887Schin 			nv_putval(mp,nv_getval(np),NV_RDONLY);
4418462SApril.Chin@Sun.COM 		}
4428462SApril.Chin@Sun.COM 		aq->header.nelem |= ARRAY_NOSCOPE;
4434887Schin 	}
4444887Schin 	while(nv_nextsub(np));
4458462SApril.Chin@Sun.COM skip:
4464887Schin 	if(sub)
4474887Schin 	{
4488462SApril.Chin@Sun.COM 		if(!skipped)
4498462SApril.Chin@Sun.COM 			nv_putsub(np,sub,0L);
4504887Schin 		free((void*)sub);
4514887Schin 	}
4528462SApril.Chin@Sun.COM 	aq->header.nelem = ap->nelem = nelem;
4538462SApril.Chin@Sun.COM 	return(&ap->hdr);
4544887Schin }
4554887Schin 
array_getval(Namval_t * np,Namfun_t * disc)4564887Schin static char *array_getval(Namval_t *np, Namfun_t *disc)
4574887Schin {
4588462SApril.Chin@Sun.COM 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
4594887Schin 	register Namval_t *mp;
4604887Schin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
4618462SApril.Chin@Sun.COM 	{
4628462SApril.Chin@Sun.COM 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
4638462SApril.Chin@Sun.COM 		{
4648462SApril.Chin@Sun.COM 			array_syncsub(aq,ap);
4658462SApril.Chin@Sun.COM 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
4668462SApril.Chin@Sun.COM 				return(nv_getv(np,&aq->hdr));
4678462SApril.Chin@Sun.COM 		}
4684887Schin 		return(mp?nv_getval(mp):0);
4698462SApril.Chin@Sun.COM 	}
4704887Schin 	return(nv_getv(np,&ap->hdr));
4714887Schin }
4724887Schin 
array_getnum(Namval_t * np,Namfun_t * disc)4734887Schin static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
4744887Schin {
4758462SApril.Chin@Sun.COM 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
4764887Schin 	register Namval_t *mp;
4774887Schin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
4788462SApril.Chin@Sun.COM 	{
4798462SApril.Chin@Sun.COM 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
4808462SApril.Chin@Sun.COM 		{
4818462SApril.Chin@Sun.COM 			array_syncsub(aq,ap);
4828462SApril.Chin@Sun.COM 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
4838462SApril.Chin@Sun.COM 				return(nv_getn(np,&aq->hdr));
4848462SApril.Chin@Sun.COM 		}
4854887Schin 		return(mp?nv_getnum(mp):0);
4868462SApril.Chin@Sun.COM 	}
4874887Schin 	return(nv_getn(np,&ap->hdr));
4884887Schin }
4894887Schin 
array_putval(Namval_t * np,const char * string,int flags,Namfun_t * dp)4904887Schin static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
4914887Schin {
4924887Schin 	register Namarr_t	*ap = (Namarr_t*)dp;
4934887Schin 	register union Value	*up;
4944887Schin 	register Namval_t	*mp;
4954887Schin 	register struct index_array *aq = (struct index_array*)ap;
4968462SApril.Chin@Sun.COM 	int			scan,nofree = nv_isattr(np,NV_NOFREE);
4974887Schin 	do
4984887Schin 	{
4994887Schin 		mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
5008462SApril.Chin@Sun.COM 		scan = ap->nelem&ARRAY_SCAN;
5014887Schin 		if(mp && mp!=np)
5028462SApril.Chin@Sun.COM 		{
50310898Sroland.mainz@nrubsig.org 			if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp))
5048462SApril.Chin@Sun.COM 			{
5058462SApril.Chin@Sun.COM 				if(!nv_isattr(np,NV_NOFREE))
5068462SApril.Chin@Sun.COM 					_nv_unset(mp,flags&NV_RDONLY);
5078462SApril.Chin@Sun.COM 				array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
5088462SApril.Chin@Sun.COM 				aq->val[aq->cur].cp = 0;
5098462SApril.Chin@Sun.COM 				if(!nv_isattr(mp,NV_NOFREE))
5108462SApril.Chin@Sun.COM 					nv_delete(mp,ap->table,0);
5118462SApril.Chin@Sun.COM 				goto skip;
5128462SApril.Chin@Sun.COM 			}
5134887Schin 			nv_putval(mp, string, flags);
5148462SApril.Chin@Sun.COM 			if(string)
5158462SApril.Chin@Sun.COM 			{
5168462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
5178462SApril.Chin@Sun.COM 				if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
5188462SApril.Chin@Sun.COM 					nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
5198462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
5208462SApril.Chin@Sun.COM 				continue;
5218462SApril.Chin@Sun.COM 			}
5228462SApril.Chin@Sun.COM 			ap->nelem |= scan;
5238462SApril.Chin@Sun.COM 		}
5244887Schin 		if(!string)
5254887Schin 		{
5264887Schin 			if(mp)
5274887Schin 			{
5288462SApril.Chin@Sun.COM 				if(is_associative(ap))
5294887Schin 				{
5304887Schin 					(*ap->fun)(np,NIL(char*),NV_ADELETE);
5318462SApril.Chin@Sun.COM 					np->nvalue.cp = 0;
5328462SApril.Chin@Sun.COM 				}
5338462SApril.Chin@Sun.COM 				else
5344887Schin 				{
5358462SApril.Chin@Sun.COM 					if(mp!=np)
5368462SApril.Chin@Sun.COM 					{
5378462SApril.Chin@Sun.COM 						array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
5388462SApril.Chin@Sun.COM 						aq->val[aq->cur].cp = 0;
5398462SApril.Chin@Sun.COM 						nv_delete(mp,ap->table,0);
5408462SApril.Chin@Sun.COM 					}
5418462SApril.Chin@Sun.COM 					if(!array_covered(np,(struct index_array*)ap))
5428462SApril.Chin@Sun.COM 						ap->nelem--;
5434887Schin 				}
5444887Schin 			}
54510898Sroland.mainz@nrubsig.org 			if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN))
5464887Schin 			{
5474887Schin 				if(is_associative(ap))
5484887Schin 					(*ap->fun)(np, NIL(char*), NV_AFREE);
5498462SApril.Chin@Sun.COM 				else if(ap->table)
5508462SApril.Chin@Sun.COM 					dtclose(ap->table);
5514887Schin 				nv_offattr(np,NV_ARRAY);
5524887Schin 			}
5538462SApril.Chin@Sun.COM 			if(!mp || mp!=np || is_associative(ap))
5544887Schin 				continue;
5554887Schin 		}
5568462SApril.Chin@Sun.COM 	skip:
5574887Schin 		/* prevent empty string from being deleted */
5588462SApril.Chin@Sun.COM 		up = array_getup(np,ap,!nofree);
5598462SApril.Chin@Sun.COM 		if(up->cp ==  Empty)
5608462SApril.Chin@Sun.COM 			up->cp = 0;
5618462SApril.Chin@Sun.COM 		if(nv_isarray(np))
5628462SApril.Chin@Sun.COM 			np->nvalue.up = up;
5634887Schin 		nv_putv(np,string,flags,&ap->hdr);
5648462SApril.Chin@Sun.COM 		if(!is_associative(ap))
5658462SApril.Chin@Sun.COM 		{
5668462SApril.Chin@Sun.COM 			if(string)
5678462SApril.Chin@Sun.COM 				array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
5688462SApril.Chin@Sun.COM 			else if(mp==np)
5698462SApril.Chin@Sun.COM 				aq->val[aq->cur].cp = 0;
5708462SApril.Chin@Sun.COM 		}
5718462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
5728462SApril.Chin@Sun.COM 		if(string && ap->hdr.type && nv_isvtree(np))
5738462SApril.Chin@Sun.COM 			nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
5748462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
5754887Schin 	}
5764887Schin 	while(!string && nv_nextsub(np));
5778462SApril.Chin@Sun.COM 	if(ap)
5788462SApril.Chin@Sun.COM 		ap->nelem &= ~ARRAY_NOSCOPE;
5798462SApril.Chin@Sun.COM 	if(nofree)
5808462SApril.Chin@Sun.COM 		nv_onattr(np,NV_NOFREE);
5818462SApril.Chin@Sun.COM 	else
5828462SApril.Chin@Sun.COM 		nv_offattr(np,NV_NOFREE);
5834887Schin 	if(!string && !nv_isattr(np,NV_ARRAY))
5844887Schin 	{
5854887Schin 		Namfun_t *nfp;
5868462SApril.Chin@Sun.COM 		if(!is_associative(ap) && aq->xp)
5878462SApril.Chin@Sun.COM 		{
5888462SApril.Chin@Sun.COM 			_nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
5898462SApril.Chin@Sun.COM 			free((void*)aq->xp);
5908462SApril.Chin@Sun.COM 		}
5918462SApril.Chin@Sun.COM 		if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
5924887Schin 			free((void*)nfp);
5938462SApril.Chin@Sun.COM 		if(!nv_isnull(np))
5948462SApril.Chin@Sun.COM 		{
5958462SApril.Chin@Sun.COM 			nv_onattr(np,NV_NOFREE);
5968462SApril.Chin@Sun.COM 			_nv_unset(np,flags);
5978462SApril.Chin@Sun.COM 		}
5988462SApril.Chin@Sun.COM 		if(np->nvalue.cp==Empty)
5998462SApril.Chin@Sun.COM 			np->nvalue.cp = 0;
6004887Schin 	}
6018462SApril.Chin@Sun.COM 	if(!string && (flags&NV_TYPE))
6028462SApril.Chin@Sun.COM 		array_unscope(np,ap);
6034887Schin }
6044887Schin 
6054887Schin static const Namdisc_t array_disc =
6064887Schin {
6074887Schin 	sizeof(Namarr_t),
6084887Schin 	array_putval,
6094887Schin 	array_getval,
6104887Schin 	array_getnum,
6114887Schin 	0,
6124887Schin 	0,
6134887Schin 	array_clone
6144887Schin };
6154887Schin 
array_copytree(Namval_t * np,Namval_t * mp)6168462SApril.Chin@Sun.COM static void array_copytree(Namval_t *np, Namval_t *mp)
6178462SApril.Chin@Sun.COM {
6188462SApril.Chin@Sun.COM 	Namfun_t	*fp = nv_disc(np,NULL,NV_POP);
6198462SApril.Chin@Sun.COM 	nv_offattr(np,NV_ARRAY);
6208462SApril.Chin@Sun.COM 	nv_clone(np,mp,0);
62110898Sroland.mainz@nrubsig.org 	if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE))
62210898Sroland.mainz@nrubsig.org 		free((void*)np->nvalue.cp);
62310898Sroland.mainz@nrubsig.org 	np->nvalue.cp = 0;
6248462SApril.Chin@Sun.COM 	np->nvalue.up = &mp->nvalue;
6258462SApril.Chin@Sun.COM 	fp->nofree  &= ~1;
6268462SApril.Chin@Sun.COM 	nv_disc(np,(Namfun_t*)fp, NV_FIRST);
6278462SApril.Chin@Sun.COM 	fp->nofree |= 1;
6288462SApril.Chin@Sun.COM 	nv_onattr(np,NV_ARRAY);
6298462SApril.Chin@Sun.COM 	mp->nvenv = (char*)np;
6308462SApril.Chin@Sun.COM }
6318462SApril.Chin@Sun.COM 
6324887Schin /*
6334887Schin  *        Increase the size of the indexed array of elements in <arp>
6344887Schin  *        so that <maxi> is a legal index.  If <arp> is 0, an array
6354887Schin  *        of the required size is allocated.  A pointer to the
6364887Schin  *        allocated Namarr_t structure is returned.
6374887Schin  *        <maxi> becomes the current index of the array.
6384887Schin  */
array_grow(Namval_t * np,register struct index_array * arp,int maxi)6394887Schin static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
6404887Schin {
6414887Schin 	register struct index_array *ap;
6428462SApril.Chin@Sun.COM 	register int i;
6438462SApril.Chin@Sun.COM 	register int newsize = arsize(arp,maxi+1);
6444887Schin 	if (maxi >= ARRAY_MAX)
6454887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
6468462SApril.Chin@Sun.COM 	i = (newsize-1)*sizeof(union Value*)+newsize;
6478462SApril.Chin@Sun.COM 	ap = new_of(struct index_array,i);
6488462SApril.Chin@Sun.COM 	memset((void*)ap,0,sizeof(*ap)+i);
6494887Schin 	ap->maxi = newsize;
6504887Schin 	ap->cur = maxi;
6514887Schin 	ap->bits =  (unsigned char*)&ap->val[newsize];
6528462SApril.Chin@Sun.COM 	memset(ap->bits, 0, newsize);
6534887Schin 	if(arp)
6544887Schin 	{
6554887Schin 		ap->header = arp->header;
6568462SApril.Chin@Sun.COM 		ap->header.hdr.dsize = sizeof(*ap) + i;
6578462SApril.Chin@Sun.COM 		for(i=0;i < arp->maxi;i++)
6584887Schin 			ap->val[i].cp = arp->val[i].cp;
6598462SApril.Chin@Sun.COM 		memcpy(ap->bits, arp->bits, arp->maxi);
6604887Schin 		array_setptr(np,arp,ap);
6614887Schin 		free((void*)arp);
6624887Schin 	}
6634887Schin 	else
6644887Schin 	{
6658462SApril.Chin@Sun.COM 		Namval_t *mp=0;
6668462SApril.Chin@Sun.COM 		ap->header.hdr.dsize = sizeof(*ap) + i;
6678462SApril.Chin@Sun.COM 		i = 0;
6684887Schin 		ap->header.fun = 0;
6698462SApril.Chin@Sun.COM 		if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
6704887Schin 		{
6718462SApril.Chin@Sun.COM 			i = ARRAY_TREE;
6728462SApril.Chin@Sun.COM 			nv_offattr(np,NV_NOFREE);
6738462SApril.Chin@Sun.COM 		}
6748462SApril.Chin@Sun.COM 		if(np->nvalue.cp==Empty)
6758462SApril.Chin@Sun.COM 			np->nvalue.cp=0;
6768462SApril.Chin@Sun.COM 		if(nv_hasdisc(np,&array_disc) || nv_isvtree(np))
6778462SApril.Chin@Sun.COM 		{
6788462SApril.Chin@Sun.COM 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
67910898Sroland.mainz@nrubsig.org 			mp = nv_search("0", ap->header.table,NV_ADD);
6804887Schin 			if(mp && nv_isnull(mp))
6814887Schin 			{
6828462SApril.Chin@Sun.COM 				Namfun_t *fp;
6834887Schin 				ap->val[0].np = mp;
6848462SApril.Chin@Sun.COM 				array_setbit(ap->bits,0,ARRAY_CHILD);
6858462SApril.Chin@Sun.COM 				for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
68610898Sroland.mainz@nrubsig.org 				if(fp && fp->disc && fp->disc->readf)
6878462SApril.Chin@Sun.COM 					(*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
6888462SApril.Chin@Sun.COM 				i++;
6894887Schin 			}
6908462SApril.Chin@Sun.COM 		}
6918462SApril.Chin@Sun.COM 		else if((ap->val[0].cp=np->nvalue.cp))
6924887Schin 			i++;
69310898Sroland.mainz@nrubsig.org 		else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np))
6944887Schin 		{
6954887Schin 			Sfdouble_t d= nv_getnum(np);
6964887Schin 			i++;
6974887Schin 		}
6984887Schin 		ap->header.nelem = i;
6994887Schin 		ap->header.hdr.disc = &array_disc;
7008462SApril.Chin@Sun.COM 		nv_disc(np,(Namfun_t*)ap, NV_FIRST);
7018462SApril.Chin@Sun.COM 		nv_onattr(np,NV_ARRAY);
7028462SApril.Chin@Sun.COM 		if(mp)
7038462SApril.Chin@Sun.COM 		{
7048462SApril.Chin@Sun.COM 			array_copytree(np,mp);
7058462SApril.Chin@Sun.COM 			ap->header.hdr.nofree &= ~1;
7068462SApril.Chin@Sun.COM 		}
7074887Schin 	}
7084887Schin 	for(;i < newsize;i++)
7094887Schin 		ap->val[i].cp = 0;
7104887Schin 	return(ap);
7114887Schin }
7124887Schin 
nv_atypeindex(Namval_t * np,const char * tname)7138462SApril.Chin@Sun.COM int nv_atypeindex(Namval_t *np, const char *tname)
7148462SApril.Chin@Sun.COM {
7158462SApril.Chin@Sun.COM 	Namval_t	*tp;
7168462SApril.Chin@Sun.COM 	int		offset = staktell();
7178462SApril.Chin@Sun.COM 	int		n = strlen(tname)-1;
7188462SApril.Chin@Sun.COM 	sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
7198462SApril.Chin@Sun.COM 	tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
7208462SApril.Chin@Sun.COM 	stakseek(offset);
7218462SApril.Chin@Sun.COM 	if(tp)
7228462SApril.Chin@Sun.COM 	{
7238462SApril.Chin@Sun.COM 		struct index_array *ap = (struct index_array*)nv_arrayptr(np);
7248462SApril.Chin@Sun.COM 		if(!nv_hasdisc(tp,&ENUM_disc))
7258462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
7268462SApril.Chin@Sun.COM 		if(!ap)
7278462SApril.Chin@Sun.COM 			ap = array_grow(np,ap,1);
7288462SApril.Chin@Sun.COM 		ap->xp = calloc(NV_MINSZ,1);
7298462SApril.Chin@Sun.COM 		np = nv_namptr(ap->xp,0);
7308462SApril.Chin@Sun.COM 		np->nvname = tp->nvname;
7318462SApril.Chin@Sun.COM 		nv_onattr(np,NV_MINIMAL);
7328462SApril.Chin@Sun.COM 		nv_clone(tp,np,NV_NOFREE);
7338462SApril.Chin@Sun.COM 		nv_offattr(np,NV_RDONLY);
7348462SApril.Chin@Sun.COM 		return(1);
7358462SApril.Chin@Sun.COM 	}
7368462SApril.Chin@Sun.COM 	errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
7378462SApril.Chin@Sun.COM 	return(0);
7388462SApril.Chin@Sun.COM }
7398462SApril.Chin@Sun.COM 
nv_arrayptr(register Namval_t * np)7404887Schin Namarr_t *nv_arrayptr(register Namval_t *np)
7414887Schin {
7424887Schin 	if(nv_isattr(np,NV_ARRAY))
7434887Schin 		return((Namarr_t*)nv_hasdisc(np, &array_disc));
7444887Schin 	return(0);
7454887Schin }
7464887Schin 
7474887Schin /*
7484887Schin  * Verify that argument is an indexed array and convert to associative,
7494887Schin  * freeing relevant storage
7504887Schin  */
nv_changearray(Namval_t * np,void * (* fun)(Namval_t *,const char *,int))7514887Schin static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
7524887Schin {
7534887Schin 	register Namarr_t *ap;
7544887Schin 	char numbuff[NUMSIZE+1];
7554887Schin 	unsigned dot, digit, n;
7564887Schin 	union Value *up;
7574887Schin 	struct index_array *save_ap;
7584887Schin 	register char *string_index=&numbuff[NUMSIZE];
7594887Schin 	numbuff[NUMSIZE]='\0';
7604887Schin 
7614887Schin 	if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
7624887Schin 		return(NIL(Namarr_t*));
7634887Schin 
7644887Schin 	nv_stack(np,&ap->hdr);
7654887Schin 	save_ap = (struct index_array*)nv_stack(np,0);
7664887Schin 	ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
7674887Schin 	ap->nelem = 0;
7684887Schin 	ap->fun = fun;
7694887Schin 	nv_onattr(np,NV_ARRAY);
7704887Schin 
7714887Schin 	for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
7724887Schin 	{
7734887Schin 		if(save_ap->val[dot].cp)
7744887Schin 		{
7754887Schin 			if ((digit = dot)== 0)
7764887Schin 				*--string_index = '0';
7774887Schin 			else while( n = digit )
7784887Schin 			{
7794887Schin 				digit /= 10;
7804887Schin 				*--string_index = '0' + (n-10*digit);
7814887Schin 			}
7824887Schin 			nv_putsub(np, string_index, ARRAY_ADD);
7834887Schin 			up = (union Value*)((*ap->fun)(np,NIL(char*),0));
7844887Schin 			up->cp = save_ap->val[dot].cp;
7854887Schin 			save_ap->val[dot].cp = 0;
7864887Schin 		}
7874887Schin 		string_index = &numbuff[NUMSIZE];
7884887Schin 	}
7894887Schin 	free((void*)save_ap);
7904887Schin 	return(ap);
7914887Schin }
7924887Schin 
7934887Schin /*
7944887Schin  * set the associative array processing method for node <np> to <fun>
7954887Schin  * The array pointer is returned if sucessful.
7964887Schin  */
nv_setarray(Namval_t * np,void * (* fun)(Namval_t *,const char *,int))7974887Schin Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
7984887Schin {
7994887Schin 	register Namarr_t *ap;
8008462SApril.Chin@Sun.COM 	char		*value=0;
8018462SApril.Chin@Sun.COM 	Namfun_t	*fp;
8028462SApril.Chin@Sun.COM 	int		nelem = 0;
8034887Schin 	if(fun && (ap = nv_arrayptr(np)))
8044887Schin 	{
8054887Schin 		/*
8064887Schin 		 * if it's already an indexed array, convert to
8074887Schin 		 * associative structure
8084887Schin 		 */
8094887Schin 		if(!is_associative(ap))
8104887Schin 			ap = nv_changearray(np, fun);
8114887Schin 		return(ap);
8124887Schin 	}
8138462SApril.Chin@Sun.COM 	if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
8148462SApril.Chin@Sun.COM 	{
8158462SApril.Chin@Sun.COM 		nelem = ARRAY_TREE;
8168462SApril.Chin@Sun.COM 		nv_offattr(np,NV_NOFREE);
8178462SApril.Chin@Sun.COM 	}
8188462SApril.Chin@Sun.COM 	if(!(fp=nv_isvtree(np)))
8198462SApril.Chin@Sun.COM 		value = nv_getval(np);
8204887Schin 	if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
8214887Schin 	{
8224887Schin 		/* check for preexisting initialization and save */
8238462SApril.Chin@Sun.COM 		ap->nelem = nelem;
8244887Schin 		ap->fun = fun;
8254887Schin 		nv_onattr(np,NV_ARRAY);
8268462SApril.Chin@Sun.COM 		if(fp || value)
8274887Schin 		{
8284887Schin 			nv_putsub(np, "0", ARRAY_ADD);
8298462SApril.Chin@Sun.COM 			if(value)
8308462SApril.Chin@Sun.COM 				nv_putval(np, value, 0);
8318462SApril.Chin@Sun.COM 			else
8328462SApril.Chin@Sun.COM 			{
8338462SApril.Chin@Sun.COM 				Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
8348462SApril.Chin@Sun.COM 				array_copytree(np,mp);
8358462SApril.Chin@Sun.COM 			}
8364887Schin 		}
8374887Schin 		return(ap);
8384887Schin 	}
8394887Schin 	return(NIL(Namarr_t*));
8404887Schin }
8414887Schin 
8424887Schin /*
8434887Schin  * move parent subscript into child
8444887Schin  */
nv_arraychild(Namval_t * np,Namval_t * nq,int c)8454887Schin Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
8464887Schin {
8478462SApril.Chin@Sun.COM 	Namfun_t		*fp;
8488462SApril.Chin@Sun.COM 	register Namarr_t	*ap = nv_arrayptr(np);
8498462SApril.Chin@Sun.COM 	union Value		*up;
8508462SApril.Chin@Sun.COM 	Namval_t		*tp;
8518462SApril.Chin@Sun.COM 	if(!nq)
8528462SApril.Chin@Sun.COM 		return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
8538462SApril.Chin@Sun.COM 	if(!ap)
8548462SApril.Chin@Sun.COM 	{
8558462SApril.Chin@Sun.COM 		nv_putsub(np, NIL(char*), ARRAY_FILL);
8568462SApril.Chin@Sun.COM 		ap = nv_arrayptr(np);
8578462SApril.Chin@Sun.COM 	}
8588462SApril.Chin@Sun.COM 	if(!(up = array_getup(np,ap,0)))
8594887Schin 		return((Namval_t*)0);
8604887Schin 	np->nvalue.cp = up->cp;
8618462SApril.Chin@Sun.COM 	if((tp=nv_type(np)) || c)
8624887Schin 	{
8638462SApril.Chin@Sun.COM 		ap->nelem |= ARRAY_NOCLONE;
8648462SApril.Chin@Sun.COM 		nq->nvenv = (char*)np;
8658462SApril.Chin@Sun.COM 		if(c=='t')
8668462SApril.Chin@Sun.COM 			nv_clone(tp,nq, 0);
8678462SApril.Chin@Sun.COM 		else
8688462SApril.Chin@Sun.COM 			nv_clone(np, nq, NV_NODISC);
8698462SApril.Chin@Sun.COM 		nv_offattr(nq,NV_ARRAY);
8708462SApril.Chin@Sun.COM 		ap->nelem &= ~ARRAY_NOCLONE;
8714887Schin 	}
8728462SApril.Chin@Sun.COM 	nq->nvenv = (char*)np;
8738462SApril.Chin@Sun.COM 	if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
8748462SApril.Chin@Sun.COM 		free((void*)fp);
8758462SApril.Chin@Sun.COM 	if(!ap->fun)
8764887Schin 	{
8774887Schin 		struct index_array *aq = (struct index_array*)ap;
8788462SApril.Chin@Sun.COM 		array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
8794887Schin 		up->np = nq;
8804887Schin 	}
8814887Schin 	if(c=='.')
8824887Schin 		nv_setvtree(nq);
8834887Schin 	return(nq);
8844887Schin }
8854887Schin 
8864887Schin /*
8874887Schin  * This routine sets subscript of <np> to the next element, if any.
8884887Schin  * The return value is zero, if there are no more elements
8894887Schin  * Otherwise, 1 is returned.
8904887Schin  */
nv_nextsub(Namval_t * np)8914887Schin int nv_nextsub(Namval_t *np)
8924887Schin {
8938462SApril.Chin@Sun.COM 	register struct index_array	*ap = (struct index_array*)nv_arrayptr(np);
8948462SApril.Chin@Sun.COM 	register unsigned		dot;
8958462SApril.Chin@Sun.COM 	struct index_array		*aq=0, *ar=0;
8964887Schin 	if(!ap || !(ap->header.nelem&ARRAY_SCAN))
8974887Schin 		return(0);
8984887Schin 	if(is_associative(ap))
8994887Schin 	{
9008462SApril.Chin@Sun.COM 		Namval_t	*nq;
9018462SApril.Chin@Sun.COM 		if(nq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT))
9024887Schin 		{
9038462SApril.Chin@Sun.COM 			if(nv_isattr(nq,NV_CHILD))
9048462SApril.Chin@Sun.COM 				nv_putsub(nq->nvalue.np,NIL(char*),ARRAY_UNDEF);
9054887Schin 			return(1);
9064887Schin 		}
9074887Schin 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
9084887Schin 		return(0);
9094887Schin 	}
9108462SApril.Chin@Sun.COM 	if(!(ap->header.nelem&ARRAY_NOSCOPE))
9118462SApril.Chin@Sun.COM 		ar = (struct index_array*)ap->header.scope;
9124887Schin 	for(dot=ap->cur+1; dot <  (unsigned)ap->maxi; dot++)
9134887Schin 	{
9148462SApril.Chin@Sun.COM 		aq = ap;
9158462SApril.Chin@Sun.COM 		if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
9168462SApril.Chin@Sun.COM 		{
9178462SApril.Chin@Sun.COM 			if(!(aq=ar) || dot>=(unsigned)aq->maxi)
9188462SApril.Chin@Sun.COM 				continue;
9198462SApril.Chin@Sun.COM 		}
9208462SApril.Chin@Sun.COM 		if(aq->val[dot].cp)
9214887Schin 		{
9224887Schin 			ap->cur = dot;
9238462SApril.Chin@Sun.COM 			if(array_isbit(aq->bits, dot,ARRAY_CHILD))
9244887Schin 			{
9258462SApril.Chin@Sun.COM 				Namval_t *mp = aq->val[dot].np;
926*12068SRoger.Faulkner@Oracle.COM 				if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize)
9274887Schin 					continue;
928*12068SRoger.Faulkner@Oracle.COM 				if(nv_isarray(mp))
929*12068SRoger.Faulkner@Oracle.COM 					nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
9304887Schin 			}
9314887Schin 			return(1);
9324887Schin 		}
9334887Schin 	}
9344887Schin 	ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
9354887Schin 	ap->cur = 0;
9364887Schin 	return(0);
9374887Schin }
9384887Schin 
9394887Schin /*
9404887Schin  * Set an array subscript for node <np> given the subscript <sp>
9414887Schin  * An array is created if necessary.
9424887Schin  * <mode> can be a number, plus or more of symbolic constants
9434887Schin  *    ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
9444887Schin  * The node pointer is returned which can be NULL if <np> is
9454887Schin  *    not already array and the ARRAY_ADD bit of <mode> is not set.
9464887Schin  * ARRAY_FILL sets the specified subscript to the empty string when
9474887Schin  *   ARRAY_ADD is specified and there is no value or sets all
9484887Schin  * the elements up to the number specified if ARRAY_ADD is not specified
9494887Schin  */
nv_putsub(Namval_t * np,register char * sp,register long mode)9504887Schin Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
9514887Schin {
9524887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
9534887Schin 	register int size = (mode&ARRAY_MASK);
9544887Schin 	if(!ap || !ap->header.fun)
9554887Schin 	{
9564887Schin 		if(sp)
9578462SApril.Chin@Sun.COM 		{
9588462SApril.Chin@Sun.COM 			if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
9598462SApril.Chin@Sun.COM 			{
9608462SApril.Chin@Sun.COM 				Namval_t *mp = nv_namptr(ap->xp,0);
9618462SApril.Chin@Sun.COM 				nv_putval(mp, sp,0);
9628462SApril.Chin@Sun.COM 				size = nv_getnum(mp);
9638462SApril.Chin@Sun.COM 			}
9648462SApril.Chin@Sun.COM 			else
9658462SApril.Chin@Sun.COM 				size = (int)sh_arith((char*)sp);
9668462SApril.Chin@Sun.COM 		}
9678462SApril.Chin@Sun.COM 		if(size <0 && ap)
9688462SApril.Chin@Sun.COM 			size += array_maxindex(np);
9694887Schin 		if(size >= ARRAY_MAX || (size < 0))
9704887Schin 		{
9714887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
9724887Schin 			return(NIL(Namval_t*));
9734887Schin 		}
9744887Schin 		if(!ap || size>=ap->maxi)
9754887Schin 		{
9764887Schin 			if(size==0 && !(mode&ARRAY_FILL))
9774887Schin 				return(NIL(Namval_t*));
9784887Schin 			if(sh.subshell)
9794887Schin 				np = sh_assignok(np,1);
9804887Schin 			ap = array_grow(np, ap,size);
9814887Schin 		}
9824887Schin 		ap->header.nelem &= ~ARRAY_UNDEF;
9838462SApril.Chin@Sun.COM 		ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
9848462SApril.Chin@Sun.COM #if 0
9858462SApril.Chin@Sun.COM 		if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
9868462SApril.Chin@Sun.COM 			mp = ap->val[oldsize].np;
9878462SApril.Chin@Sun.COM 		if(size != oldsize && mp->nvalue.cp)
9888462SApril.Chin@Sun.COM 		{
9898462SApril.Chin@Sun.COM 			Namfun_t *nfp;
9908462SApril.Chin@Sun.COM 			for(nfp=np->nvfun; nfp; nfp=nfp->next)
9918462SApril.Chin@Sun.COM 			{
9928462SApril.Chin@Sun.COM 				if(nfp->disc && nfp->disc->readf)
9938462SApril.Chin@Sun.COM 				{
9948462SApril.Chin@Sun.COM 					(*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
9958462SApril.Chin@Sun.COM 					break;
9968462SApril.Chin@Sun.COM 				}
9978462SApril.Chin@Sun.COM 			}
9988462SApril.Chin@Sun.COM 		}
9998462SApril.Chin@Sun.COM #endif
10004887Schin 		ap->cur = size;
10018462SApril.Chin@Sun.COM 		if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
10024887Schin 			np = 0;
10038462SApril.Chin@Sun.COM 		if(mode&(ARRAY_FILL|ARRAY_ADD))
10044887Schin 		{
10054887Schin 			if(!(mode&ARRAY_ADD))
10064887Schin 			{
10074887Schin 				int n;
10088462SApril.Chin@Sun.COM 				for(n=0; n <= size; n++)
10094887Schin 				{
10104887Schin 					if(!ap->val[n].cp)
10118462SApril.Chin@Sun.COM 					{
10124887Schin 						ap->val[n].cp = Empty;
10138462SApril.Chin@Sun.COM 						if(!array_covered(np,ap))
10148462SApril.Chin@Sun.COM 							ap->header.nelem++;
10158462SApril.Chin@Sun.COM 					}
10164887Schin 				}
10174887Schin 				if(n=ap->maxi-ap->maxi)
10184887Schin 					memset(&ap->val[size],0,n*sizeof(union Value));
10194887Schin 			}
10204887Schin 			else if(!ap->val[size].cp)
10214887Schin 			{
10224887Schin 				if(sh.subshell)
10234887Schin 					np = sh_assignok(np,1);
10244887Schin 				ap->val[size].cp = Empty;
10258462SApril.Chin@Sun.COM 				if(!array_covered(np,ap))
10268462SApril.Chin@Sun.COM 					ap->header.nelem++;
10274887Schin 			}
10284887Schin 		}
10294887Schin 		else if(!(mode&ARRAY_SCAN))
10304887Schin 		{
10314887Schin 			ap->header.nelem &= ~ARRAY_SCAN;
10328462SApril.Chin@Sun.COM 			if(array_isbit(ap->bits,size,ARRAY_CHILD))
10334887Schin 				nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
10348462SApril.Chin@Sun.COM 			if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
10358462SApril.Chin@Sun.COM 				np = 0;
10364887Schin 		}
10374887Schin 		return((Namval_t*)np);
10384887Schin 	}
10394887Schin 	ap->header.nelem &= ~ARRAY_UNDEF;
10404887Schin 	if(!(mode&ARRAY_FILL))
10414887Schin 		ap->header.nelem &= ~ARRAY_SCAN;
10428462SApril.Chin@Sun.COM 	ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
10434887Schin 	if(sp)
10444887Schin 	{
10454887Schin 		if(mode&ARRAY_SETSUB)
10464887Schin 		{
10474887Schin 			(*ap->header.fun)(np, sp, NV_ASETSUB);
10484887Schin 			return(np);
10494887Schin 		}
10508462SApril.Chin@Sun.COM 		(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
10518462SApril.Chin@Sun.COM 		if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
10528462SApril.Chin@Sun.COM 			np = 0;
10534887Schin 	}
10544887Schin 	else if(mode&ARRAY_SCAN)
10554887Schin 		(*ap->header.fun)(np,(char*)np,0);
10564887Schin 	else if(mode&ARRAY_UNDEF)
10574887Schin 		(*ap->header.fun)(np, "",0);
10584887Schin 	if((mode&ARRAY_SCAN) && !nv_nextsub(np))
10594887Schin 		np = 0;
10604887Schin 	return(np);
10614887Schin }
10624887Schin 
10634887Schin /*
10644887Schin  * process an array subscript for node <np> given the subscript <cp>
10654887Schin  * returns pointer to character after the subscript
10664887Schin  */
nv_endsubscript(Namval_t * np,register char * cp,int mode)10674887Schin char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
10684887Schin {
10694887Schin 	register int count=1, quoted=0, c;
10704887Schin 	register char *sp = cp+1;
10714887Schin 	/* first find matching ']' */
10724887Schin 	while(count>0 && (c= *++cp))
10734887Schin 	{
10744887Schin 		if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
10754887Schin 		{
10764887Schin 			quoted=1;
10774887Schin 			cp++;
10784887Schin 		}
10794887Schin 		else if(c=='[')
10804887Schin 			count++;
10814887Schin 		else if(c==']')
10824887Schin 			count--;
10834887Schin 	}
10844887Schin 	*cp = 0;
10854887Schin 	if(quoted)
10864887Schin 	{
10874887Schin 		/* strip escape characters */
10884887Schin 		count = staktell();
10894887Schin 		stakwrite(sp,1+cp-sp);
10904887Schin 		sh_trim(sp=stakptr(count));
10914887Schin 	}
10924887Schin 	if(mode && np)
10938462SApril.Chin@Sun.COM 	{
109410898Sroland.mainz@nrubsig.org 		Namarr_t *ap = nv_arrayptr(np);
109510898Sroland.mainz@nrubsig.org 		int scan = 0;
109610898Sroland.mainz@nrubsig.org 		if(ap)
109710898Sroland.mainz@nrubsig.org 			scan = ap->nelem&ARRAY_SCAN;
10988462SApril.Chin@Sun.COM 		if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
10998462SApril.Chin@Sun.COM 			mode |= NV_ADD;
11008462SApril.Chin@Sun.COM 		nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
110110898Sroland.mainz@nrubsig.org 		if(scan)
110210898Sroland.mainz@nrubsig.org 			ap->nelem |= scan;
11038462SApril.Chin@Sun.COM 	}
11044887Schin 	if(quoted)
11054887Schin 		stakseek(count);
11064887Schin 	*cp++ = c;
11074887Schin 	return(cp);
11084887Schin }
11094887Schin 
11104887Schin 
nv_opensub(Namval_t * np)11114887Schin Namval_t *nv_opensub(Namval_t* np)
11124887Schin {
11134887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
11148462SApril.Chin@Sun.COM 	if(ap)
11158462SApril.Chin@Sun.COM 	{
11168462SApril.Chin@Sun.COM 		if(is_associative(ap))
11178462SApril.Chin@Sun.COM 			return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
11188462SApril.Chin@Sun.COM 		else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
11198462SApril.Chin@Sun.COM 			return(ap->val[ap->cur].np);
11208462SApril.Chin@Sun.COM 	}
11214887Schin 	return(NIL(Namval_t*));
11224887Schin }
11234887Schin 
nv_getsub(Namval_t * np)11244887Schin char	*nv_getsub(Namval_t* np)
11254887Schin {
11264887Schin 	static char numbuff[NUMSIZE];
11274887Schin 	register struct index_array *ap;
11284887Schin 	register unsigned dot, n;
11294887Schin 	register char *cp = &numbuff[NUMSIZE];
11304887Schin 	if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
11314887Schin 		return(NIL(char*));
11324887Schin 	if(is_associative(ap))
11334887Schin 		return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
11348462SApril.Chin@Sun.COM 	if(ap->xp)
11358462SApril.Chin@Sun.COM 	{
11368462SApril.Chin@Sun.COM 		np = nv_namptr(ap->xp,0);
11378462SApril.Chin@Sun.COM 		np->nvalue.s = ap->cur;
11388462SApril.Chin@Sun.COM 		return(nv_getval(np));
11398462SApril.Chin@Sun.COM 	}
11404887Schin 	if((dot = ap->cur)==0)
11414887Schin 		*--cp = '0';
11424887Schin 	else while(n=dot)
11434887Schin 	{
11444887Schin 		dot /= 10;
11454887Schin 		*--cp = '0' + (n-10*dot);
11464887Schin 	}
11474887Schin 	return(cp);
11484887Schin }
11494887Schin 
11504887Schin /*
11514887Schin  * If <np> is an indexed array node, the current subscript index
11524887Schin  * returned, otherwise returns -1
11534887Schin  */
nv_aindex(register Namval_t * np)11544887Schin int nv_aindex(register Namval_t* np)
11554887Schin {
11564887Schin 	Namarr_t *ap = nv_arrayptr(np);
11578462SApril.Chin@Sun.COM 	if(!ap)
11588462SApril.Chin@Sun.COM 		return(0);
11598462SApril.Chin@Sun.COM 	else if(is_associative(ap))
11604887Schin 		return(-1);
11614887Schin 	return(((struct index_array*)(ap))->cur&ARRAY_MASK);
11624887Schin }
11634887Schin 
nv_arraynsub(register Namarr_t * ap)11648462SApril.Chin@Sun.COM int nv_arraynsub(register Namarr_t* ap)
11658462SApril.Chin@Sun.COM {
11668462SApril.Chin@Sun.COM 	return(array_elem(ap));
11678462SApril.Chin@Sun.COM }
11688462SApril.Chin@Sun.COM 
nv_aimax(register Namval_t * np)11698462SApril.Chin@Sun.COM int nv_aimax(register Namval_t* np)
11708462SApril.Chin@Sun.COM {
11718462SApril.Chin@Sun.COM 	struct index_array *ap = (struct index_array*)nv_arrayptr(np);
11728462SApril.Chin@Sun.COM 	int sub = -1;
11738462SApril.Chin@Sun.COM 	if(!ap || is_associative(&ap->header))
11748462SApril.Chin@Sun.COM 		return(-1);
11758462SApril.Chin@Sun.COM 	sub = ap->maxi;
11768462SApril.Chin@Sun.COM 	while(--sub>0 && ap->val[sub].cp==0);
11778462SApril.Chin@Sun.COM 	return(sub);
11788462SApril.Chin@Sun.COM }
11794887Schin 
11804887Schin /*
11818462SApril.Chin@Sun.COM  *  This is the default implementation for associative arrays
11824887Schin  */
nv_associative(register Namval_t * np,const char * sp,int mode)11834887Schin void *nv_associative(register Namval_t *np,const char *sp,int mode)
11844887Schin {
11854887Schin 	register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
11864887Schin 	register int type;
11874887Schin 	switch(mode)
11884887Schin 	{
11894887Schin 	    case NV_AINIT:
11904887Schin 		if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
11914887Schin 		{
11928462SApril.Chin@Sun.COM 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
11934887Schin 			ap->cur = 0;
11944887Schin 			ap->pos = 0;
11954887Schin 			ap->header.hdr.disc = &array_disc;
11968462SApril.Chin@Sun.COM 			nv_disc(np,(Namfun_t*)ap, NV_FIRST);
11978462SApril.Chin@Sun.COM 			ap->header.hdr.dsize = sizeof(struct assoc_array);
11988462SApril.Chin@Sun.COM 			ap->header.hdr.nofree &= ~1;
11994887Schin 		}
12004887Schin 		return((void*)ap);
12014887Schin 	    case NV_ADELETE:
12024887Schin 		if(ap->cur)
12034887Schin 		{
12048462SApril.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))
12058462SApril.Chin@Sun.COM 				ap->header.nelem--;
12068462SApril.Chin@Sun.COM 			_nv_unset(ap->cur,NV_RDONLY);
12078462SApril.Chin@Sun.COM 			nv_delete(ap->cur,ap->header.table,0);
12088462SApril.Chin@Sun.COM 			ap->cur = 0;
12094887Schin 		}
12104887Schin 		return((void*)ap);
12114887Schin 	    case NV_AFREE:
12124887Schin 		ap->pos = 0;
12138462SApril.Chin@Sun.COM 		if(ap->header.scope)
12148462SApril.Chin@Sun.COM 		{
12158462SApril.Chin@Sun.COM 			ap->header.table = dtview(ap->header.table,(Dt_t*)0);
12168462SApril.Chin@Sun.COM 			dtclose(ap->header.scope);
12178462SApril.Chin@Sun.COM 			ap->header.scope = 0;
12188462SApril.Chin@Sun.COM 		}
12198462SApril.Chin@Sun.COM 		else
12208462SApril.Chin@Sun.COM 			dtclose(ap->header.table);
12214887Schin 		return((void*)ap);
12224887Schin 	    case NV_ANEXT:
12234887Schin 		if(!ap->pos)
12244887Schin 		{
12258462SApril.Chin@Sun.COM 			if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
12268462SApril.Chin@Sun.COM 			{
12278462SApril.Chin@Sun.COM 				ap->header.scope = dtvnext(ap->header.table);
12288462SApril.Chin@Sun.COM 				ap->header.table->view = 0;
12298462SApril.Chin@Sun.COM 			}
12304887Schin 			if(!(ap->pos=ap->cur))
12318462SApril.Chin@Sun.COM 				ap->pos = (Namval_t*)dtfirst(ap->header.table);
12324887Schin 		}
12334887Schin 		else
12344887Schin 			ap->pos = ap->nextpos;
12354887Schin 		for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
12364887Schin 		{
12378462SApril.Chin@Sun.COM 			ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
12384887Schin 			if(ap->cur->nvalue.cp)
12394887Schin 			{
12404887Schin 				if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
12414887Schin 					continue;
12424887Schin 				return((void*)ap);
12434887Schin 			}
12444887Schin 		}
12458462SApril.Chin@Sun.COM 		if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
12468462SApril.Chin@Sun.COM 		{
12478462SApril.Chin@Sun.COM 			ap->header.table->view = (Dt_t*)ap->header.scope;
12488462SApril.Chin@Sun.COM 			ap->header.scope = ap->header.table;
12498462SApril.Chin@Sun.COM 		}
12504887Schin 		return(NIL(void*));
12514887Schin 	    case NV_ASETSUB:
12524887Schin 		ap->cur = (Namval_t*)sp;
12538462SApril.Chin@Sun.COM 		return((void*)ap->cur);
12544887Schin 	    case NV_ACURRENT:
12558462SApril.Chin@Sun.COM 		if(ap->cur)
12568462SApril.Chin@Sun.COM 			ap->cur->nvenv = (char*)np;
12574887Schin 		return((void*)ap->cur);
12584887Schin 	    case NV_ANAME:
12594887Schin 		if(ap->cur)
1260*12068SRoger.Faulkner@Oracle.COM 		{
1261*12068SRoger.Faulkner@Oracle.COM 			Shell_t *shp = sh_getinterp();
1262*12068SRoger.Faulkner@Oracle.COM 			if(!shp->instance && nv_isnull(ap->cur))
1263*12068SRoger.Faulkner@Oracle.COM 				return(NIL(void*));
12648462SApril.Chin@Sun.COM 			return((void*)ap->cur->nvname);
1265*12068SRoger.Faulkner@Oracle.COM 		}
12664887Schin 		return(NIL(void*));
12674887Schin 	    default:
12684887Schin 		if(sp)
12694887Schin 		{
12708462SApril.Chin@Sun.COM 			Namval_t *mp=0;
12718462SApril.Chin@Sun.COM 			ap->cur = 0;
12724887Schin 			if(sp==(char*)np)
12738462SApril.Chin@Sun.COM 				return(0);
12748462SApril.Chin@Sun.COM 			type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
12758462SApril.Chin@Sun.COM 			if(mode)
12768462SApril.Chin@Sun.COM 				mode = NV_ADD|HASH_NOSCOPE;
12778462SApril.Chin@Sun.COM 			else if(ap->header.nelem&ARRAY_NOSCOPE)
12788462SApril.Chin@Sun.COM 				mode = HASH_NOSCOPE;
1279*12068SRoger.Faulkner@Oracle.COM 			if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD))
128010898Sroland.mainz@nrubsig.org 				errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript");
12818462SApril.Chin@Sun.COM 			if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
12828462SApril.Chin@Sun.COM 				ap->cur = mp;
12838462SApril.Chin@Sun.COM 			if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
12844887Schin 			{
12858462SApril.Chin@Sun.COM 				nv_onattr(mp,type);
12868462SApril.Chin@Sun.COM 				mp->nvenv = (char*)np;
12878462SApril.Chin@Sun.COM 				if((mode&NV_ADD) && nv_type(np))
12888462SApril.Chin@Sun.COM 					nv_arraychild(np,mp,0);
12898462SApril.Chin@Sun.COM 				if(sh.subshell)
12908462SApril.Chin@Sun.COM 					np = sh_assignok(np,1);
12918462SApril.Chin@Sun.COM 				if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
12928462SApril.Chin@Sun.COM 					ap->header.nelem++;
12938462SApril.Chin@Sun.COM 				if(nv_isnull(mp))
12948462SApril.Chin@Sun.COM 				{
12958462SApril.Chin@Sun.COM 					if(ap->header.nelem&ARRAY_TREE)
12968462SApril.Chin@Sun.COM 						nv_setvtree(mp);
12978462SApril.Chin@Sun.COM 					mp->nvalue.cp = Empty;
12988462SApril.Chin@Sun.COM 				}
12994887Schin 			}
13008462SApril.Chin@Sun.COM 			else if(ap->header.nelem&ARRAY_SCAN)
13018462SApril.Chin@Sun.COM 			{
13028462SApril.Chin@Sun.COM 				Namval_t fake;
13038462SApril.Chin@Sun.COM 				fake.nvname = (char*)sp;
13048462SApril.Chin@Sun.COM 				ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
13058462SApril.Chin@Sun.COM 				ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
13068462SApril.Chin@Sun.COM 			}
1307*12068SRoger.Faulkner@Oracle.COM 			else if(!mp && *sp && mode==0)
1308*12068SRoger.Faulkner@Oracle.COM 				mp = nv_search(sp,ap->header.table,NV_ADD);
13098462SApril.Chin@Sun.COM 			np = mp;
131010898Sroland.mainz@nrubsig.org 			if(ap->pos && ap->pos==np)
131110898Sroland.mainz@nrubsig.org 				ap->header.nelem |= ARRAY_SCAN;
131210898Sroland.mainz@nrubsig.org 			else if(!(ap->header.nelem&ARRAY_SCAN))
13134887Schin 				ap->pos = 0;
13144887Schin 			ap->cur = np;
13154887Schin 		}
13164887Schin 		if(ap->cur)
13174887Schin 			return((void*)(&ap->cur->nvalue));
13184887Schin 		else
13194887Schin 			return((void*)(&ap->cur));
13204887Schin 	}
13214887Schin }
13224887Schin 
13234887Schin /*
13244887Schin  * Assign values to an array
13254887Schin  */
nv_setvec(register Namval_t * np,int append,register int argc,register char * argv[])13264887Schin void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
13274887Schin {
13284887Schin 	int arg0=0;
13298462SApril.Chin@Sun.COM 	struct index_array *ap=0,*aq;
13304887Schin 	if(nv_isarray(np))
13314887Schin 	{
13324887Schin 		ap = (struct index_array*)nv_arrayptr(np);
13334887Schin 		if(ap && is_associative(ap))
13348462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
13354887Schin 	}
13364887Schin 	if(append)
13374887Schin 	{
13384887Schin 		if(ap)
13394887Schin 		{
13408462SApril.Chin@Sun.COM 			if(!(aq = (struct index_array*)ap->header.scope))
13418462SApril.Chin@Sun.COM 				aq = ap;
13424887Schin 			arg0 = ap->maxi;
13438462SApril.Chin@Sun.COM 			while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
13444887Schin 			arg0++;
13454887Schin 		}
13464887Schin 		else if(!nv_isnull(np))
13474887Schin 			arg0=1;
13484887Schin 	}
13494887Schin 	while(--argc >= 0)
13504887Schin 	{
13518462SApril.Chin@Sun.COM 		nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
13524887Schin 		nv_putval(np,argv[argc],0);
13534887Schin 	}
13544887Schin }
13554887Schin 
1356