1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * Array processing routines
23*4887Schin  *
24*4887Schin  *   David Korn
25*4887Schin  *   AT&T Labs
26*4887Schin  *   dgk@research.att.com
27*4887Schin  *
28*4887Schin  */
29*4887Schin 
30*4887Schin #include	"defs.h"
31*4887Schin #include	<stak.h>
32*4887Schin #include	"name.h"
33*4887Schin 
34*4887Schin #define NUMSIZE	(4+(ARRAY_MAX>999)+(ARRAY_MAX>9999)+(ARRAY_MAX>99999))
35*4887Schin #define is_associative(ap)	array_assoc((Namarr_t*)(ap))
36*4887Schin #define array_setbit(cp, n)	(cp[(n)/CHAR_BIT] |= 1<<(((n)&(CHAR_BIT-1))))
37*4887Schin #define array_clrbit(cp, n)	(cp[(n)/CHAR_BIT] &= ~(1<<(((n)&(CHAR_BIT-1)))))
38*4887Schin #define array_isbit(cp, n)	(cp[(n)/CHAR_BIT] & 1<<(((n)&(CHAR_BIT-1))))
39*4887Schin #define NV_CHILD		NV_EXPORT
40*4887Schin 
41*4887Schin static char Empty[] = "";
42*4887Schin 
43*4887Schin struct index_array
44*4887Schin {
45*4887Schin         Namarr_t        header;
46*4887Schin         int		cur;    /* index of current element */
47*4887Schin         int		maxi;   /* maximum index for array */
48*4887Schin 	unsigned char	*bits;	/* bit array for child subscripts */
49*4887Schin         union Value	val[1]; /* array of value holders */
50*4887Schin };
51*4887Schin 
52*4887Schin struct assoc_array
53*4887Schin {
54*4887Schin 	Namarr_t	header;
55*4887Schin 	Dt_t		*table;
56*4887Schin 	Namval_t	*pos;
57*4887Schin 	Namval_t	*nextpos;
58*4887Schin 	Namval_t	*cur;
59*4887Schin };
60*4887Schin 
61*4887Schin /*
62*4887Schin  * replace discipline with new one
63*4887Schin  */
64*4887Schin static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
65*4887Schin {
66*4887Schin 	register Namfun_t **fp = &np->nvfun;
67*4887Schin 	while(*fp && *fp!= &old->header.hdr)
68*4887Schin 		fp = &((*fp)->next);
69*4887Schin 	if(*fp)
70*4887Schin 	{
71*4887Schin 		new->header.hdr.next = (*fp)->next;
72*4887Schin 		*fp = &new->header.hdr;
73*4887Schin 	}
74*4887Schin 	else sfprintf(sfstderr,"discipline not replaced\n");
75*4887Schin }
76*4887Schin 
77*4887Schin /*
78*4887Schin  *   Calculate the amount of space to be allocated to hold an
79*4887Schin  *   indexed array into which <maxi> is a legal index.  The number of
80*4887Schin  *   elements that will actually fit into the array (> <maxi>
81*4887Schin  *   but <= ARRAY_MAX) is returned.
82*4887Schin  *
83*4887Schin  */
84*4887Schin static int	arsize(register int maxi)
85*4887Schin {
86*4887Schin 	register int i = roundof(maxi,ARRAY_INCR);
87*4887Schin 	return (i>ARRAY_MAX?ARRAY_MAX:i);
88*4887Schin }
89*4887Schin 
90*4887Schin static struct index_array *array_grow(Namval_t*, struct index_array*,int);
91*4887Schin 
92*4887Schin /* return index of highest element of an array */
93*4887Schin int array_maxindex(Namval_t *np)
94*4887Schin {
95*4887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
96*4887Schin 	register int i = ap->maxi;
97*4887Schin 	if(is_associative(ap))
98*4887Schin 		return(-1);
99*4887Schin 	while(i>0 && ap->val[--i].cp==0);
100*4887Schin 	return(i+1);
101*4887Schin }
102*4887Schin 
103*4887Schin static union Value *array_getup(Namval_t *np, Namarr_t *arp)
104*4887Schin {
105*4887Schin 	register struct index_array *ap = (struct index_array*)arp;
106*4887Schin 	register union Value *up;
107*4887Schin 	if(!nv_isarray(np))
108*4887Schin 		return(&np->nvalue);
109*4887Schin 	if(is_associative(ap))
110*4887Schin 		up = (union Value*)((*arp->fun)(np,NIL(char*),0));
111*4887Schin 	else
112*4887Schin 	{
113*4887Schin 		if(ap->cur >= ap->maxi)
114*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
115*4887Schin 		up = &(ap->val[ap->cur]);
116*4887Schin 	}
117*4887Schin 	return(up);
118*4887Schin }
119*4887Schin 
120*4887Schin /*
121*4887Schin  * Get the Value pointer for an array.
122*4887Schin  * Delete space as necessary if flag is ARRAY_DELETE
123*4887Schin  * After the lookup is done the last @ or * subscript is incremented
124*4887Schin  */
125*4887Schin static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
126*4887Schin {
127*4887Schin 	register struct index_array *ap = (struct index_array*)arp;
128*4887Schin 	register union Value	*up;
129*4887Schin 	Namval_t		*mp;
130*4887Schin 	int			wasundef;
131*4887Schin 	if(wasundef = ap->header.nelem&ARRAY_UNDEF)
132*4887Schin 	{
133*4887Schin 		ap->header.nelem &= ~ARRAY_UNDEF;
134*4887Schin 		/* delete array is the same as delete array[@] */
135*4887Schin 		if(flag&ARRAY_DELETE)
136*4887Schin 		{
137*4887Schin 			nv_putsub(np, NIL(char*), ARRAY_SCAN);
138*4887Schin 			ap->header.nelem |= ARRAY_SCAN;
139*4887Schin 		}
140*4887Schin 		else /* same as array[0] */
141*4887Schin 		{
142*4887Schin 			if(is_associative(ap))
143*4887Schin 				(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
144*4887Schin 			else
145*4887Schin 				ap->cur = 0;
146*4887Schin 		}
147*4887Schin 	}
148*4887Schin 	if(is_associative(ap))
149*4887Schin 	{
150*4887Schin 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
151*4887Schin 		if(!mp)
152*4887Schin 			up = (union Value*)&mp;
153*4887Schin 		else if(nv_isattr(mp,NV_CHILD))
154*4887Schin 		{
155*4887Schin 			if(wasundef && nv_isarray(mp->nvalue.np))
156*4887Schin 				nv_putsub(mp->nvalue.np,NIL(char*),ARRAY_UNDEF);
157*4887Schin 			return(mp->nvalue.np);
158*4887Schin 		}
159*4887Schin 		else
160*4887Schin 			up =  &mp->nvalue;
161*4887Schin 	}
162*4887Schin 	else
163*4887Schin 	{
164*4887Schin 		if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
165*4887Schin 			ap = array_grow(np, ap, (int)ap->cur);
166*4887Schin 		if(ap->cur>=ap->maxi)
167*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
168*4887Schin 		up = &(ap->val[ap->cur]);
169*4887Schin 		if(up->np && array_isbit(ap->bits,ap->cur))
170*4887Schin 		{
171*4887Schin 			if(wasundef && nv_isarray(up->np))
172*4887Schin 				nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
173*4887Schin 			return(up->np);
174*4887Schin 		}
175*4887Schin 	}
176*4887Schin 	np->nvalue.cp = up->cp;
177*4887Schin 	if(!up->cp)
178*4887Schin 	{
179*4887Schin 		if(flag!=ARRAY_ASSIGN)
180*4887Schin 			return(0);
181*4887Schin 		ap->header.nelem++;
182*4887Schin 	}
183*4887Schin 	return(np);
184*4887Schin }
185*4887Schin 
186*4887Schin static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
187*4887Schin {
188*4887Schin 	Namarr_t		*ap = (Namarr_t*)fp;
189*4887Schin 	Namval_t		*nq, *mq;
190*4887Schin 	char			*name, *sub=0;
191*4887Schin 	int			nelem = ap->nelem,offset=staktell();
192*4887Schin 	struct index_array	*aq, *ar;
193*4887Schin 	if(nelem&ARRAY_NOCLONE)
194*4887Schin 		return(0);
195*4887Schin 	if(array_assoc(ap))
196*4887Schin 		nv_setarray(mp,ap->fun);
197*4887Schin 	else
198*4887Schin 	{
199*4887Schin 		nv_putsub(mp,NIL(char*),ap->nelem);
200*4887Schin 		if(aq=(struct index_array*)nv_arrayptr(mp))
201*4887Schin 			aq->bits =  (unsigned char*)&aq->val[aq->maxi];
202*4887Schin 	}
203*4887Schin 	if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
204*4887Schin 		sub = strdup(sub);
205*4887Schin 	ar = (struct index_array*)ap;
206*4887Schin 	nv_onattr(mp,nv_isattr(np,NV_INTEGER|NV_UTOL|NV_LTOU|NV_LJUST|NV_RJUST|NV_ZFILL|NV_BINARY));
207*4887Schin 	nv_putsub(np,NIL(char*),ARRAY_SCAN);
208*4887Schin 	do
209*4887Schin 	{
210*4887Schin 	        if(array_assoc(ap))
211*4887Schin 			name = (char*)((*ap->fun)(np,NIL(char*),NV_ANAME));
212*4887Schin 		else
213*4887Schin 			name = nv_getsub(np);
214*4887Schin 		nv_putsub(mp,name,ARRAY_ADD);
215*4887Schin 		if((!array_assoc(ap) &&  array_isbit(ar->bits,ar->cur) && (nq=np)) ||
216*4887Schin 			(array_assoc(ap) && (nq = (Namval_t*)((*ap->fun)(np,NIL(char*),NV_ACURRENT))) && nv_isattr(nq, NV_CHILD)))
217*4887Schin 		{
218*4887Schin 			sfprintf(stkstd,"%s[%s]",nv_name(mp),name);
219*4887Schin 			stakputc(0);
220*4887Schin 			mq = nv_search(stakptr(offset), sh.var_tree, NV_ADD);
221*4887Schin 			stakseek(offset);
222*4887Schin 			if(mq)
223*4887Schin 			{
224*4887Schin 				nv_clone(nq->nvalue.np,mq,0);
225*4887Schin 				if(array_assoc(ap))
226*4887Schin 				{
227*4887Schin 					nq = (Namval_t*)((*ap->fun)(mp,NIL(char*),NV_ACURRENT));
228*4887Schin 					nq->nvalue.np = mp;
229*4887Schin 					nv_onattr(nq,NV_CHILD);
230*4887Schin 				}
231*4887Schin 				else if(aq)
232*4887Schin 				{
233*4887Schin 					array_setbit(aq->bits,aq->cur);
234*4887Schin 					aq->val[aq->cur].np = mq;
235*4887Schin 				}
236*4887Schin 			}
237*4887Schin 		}
238*4887Schin 		else if(nv_isattr(np,NV_INTEGER))
239*4887Schin 		{
240*4887Schin 			Sfdouble_t d= nv_getnum(np);
241*4887Schin 			nv_putval(mp,(char*)&d,NV_LDOUBLE);
242*4887Schin 		}
243*4887Schin 		else
244*4887Schin 			nv_putval(mp,nv_getval(np),NV_RDONLY);
245*4887Schin 	}
246*4887Schin 	while(nv_nextsub(np));
247*4887Schin 	if(sub)
248*4887Schin 	{
249*4887Schin 		nv_putsub(np,sub,0L);
250*4887Schin 		free((void*)sub);
251*4887Schin 	}
252*4887Schin 	ap->nelem = nelem;
253*4887Schin 	((Namarr_t*)mp->nvfun)->nelem = nelem;
254*4887Schin 	return(nv_stack(mp,(Namfun_t*)0));
255*4887Schin }
256*4887Schin 
257*4887Schin static char *array_getval(Namval_t *np, Namfun_t *disc)
258*4887Schin {
259*4887Schin 	register Namarr_t *ap = (Namarr_t*)disc;
260*4887Schin 	register Namval_t *mp;
261*4887Schin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
262*4887Schin 		return(mp?nv_getval(mp):0);
263*4887Schin 	return(nv_getv(np,&ap->hdr));
264*4887Schin }
265*4887Schin 
266*4887Schin static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
267*4887Schin {
268*4887Schin 	register Namarr_t *ap = (Namarr_t*)disc;
269*4887Schin 	register Namval_t *mp;
270*4887Schin 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
271*4887Schin 		return(mp?nv_getnum(mp):0);
272*4887Schin 	return(nv_getn(np,&ap->hdr));
273*4887Schin }
274*4887Schin 
275*4887Schin static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
276*4887Schin {
277*4887Schin 	register Namarr_t	*ap = (Namarr_t*)dp;
278*4887Schin 	register union Value	*up;
279*4887Schin 	register Namval_t	*mp;
280*4887Schin 	register struct index_array *aq = (struct index_array*)ap;
281*4887Schin 	do
282*4887Schin 	{
283*4887Schin 		mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
284*4887Schin 		if(mp && mp!=np)
285*4887Schin 			nv_putval(mp, string, flags);
286*4887Schin 		if(!string)
287*4887Schin 		{
288*4887Schin 			if(mp)
289*4887Schin 			{
290*4887Schin 				if(mp!=np)
291*4887Schin 				{
292*4887Schin 					dtdelete(sh.var_tree,(void*)mp);
293*4887Schin 					free((void*)mp);
294*4887Schin 				}
295*4887Schin 				if(is_associative(ap))
296*4887Schin 					(*ap->fun)(np,NIL(char*),NV_ADELETE);
297*4887Schin 				else if(mp!=np)
298*4887Schin 				{
299*4887Schin 					array_clrbit(aq->bits,aq->cur);
300*4887Schin 					aq->val[aq->cur].cp = 0;
301*4887Schin 				}
302*4887Schin 				ap->nelem--;
303*4887Schin 			}
304*4887Schin 			if(array_elem(ap)==0 && ((ap->nelem&ARRAY_SCAN) || !is_associative(ap)))
305*4887Schin 			{
306*4887Schin 				if(is_associative(ap))
307*4887Schin 					(*ap->fun)(np, NIL(char*), NV_AFREE);
308*4887Schin 				nv_offattr(np,NV_ARRAY);
309*4887Schin 			}
310*4887Schin 			if(!mp || mp!=np)
311*4887Schin 				continue;
312*4887Schin 		}
313*4887Schin 		/* prevent empty string from being deleted */
314*4887Schin 		if(np->nvalue.cp == Empty)
315*4887Schin 			np->nvalue.cp = 0;
316*4887Schin 		nv_putv(np,string,flags,&ap->hdr);
317*4887Schin 		up = array_getup(np,ap);
318*4887Schin 		up->cp = np->nvalue.cp;
319*4887Schin 	}
320*4887Schin 	while(!string && nv_nextsub(np));
321*4887Schin 	if(!string && !nv_isattr(np,NV_ARRAY))
322*4887Schin 	{
323*4887Schin 		Namfun_t *nfp;
324*4887Schin 		if(nfp = nv_disc(np,(Namfun_t*)ap,NV_POP))
325*4887Schin 			free((void*)nfp);
326*4887Schin 	}
327*4887Schin }
328*4887Schin 
329*4887Schin static const Namdisc_t array_disc =
330*4887Schin {
331*4887Schin 	sizeof(Namarr_t),
332*4887Schin 	array_putval,
333*4887Schin 	array_getval,
334*4887Schin 	array_getnum,
335*4887Schin 	0,
336*4887Schin 	0,
337*4887Schin 	array_clone
338*4887Schin };
339*4887Schin 
340*4887Schin /*
341*4887Schin  *        Increase the size of the indexed array of elements in <arp>
342*4887Schin  *        so that <maxi> is a legal index.  If <arp> is 0, an array
343*4887Schin  *        of the required size is allocated.  A pointer to the
344*4887Schin  *        allocated Namarr_t structure is returned.
345*4887Schin  *        <maxi> becomes the current index of the array.
346*4887Schin  */
347*4887Schin static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
348*4887Schin {
349*4887Schin 	register struct index_array *ap;
350*4887Schin 	register int i=0;
351*4887Schin 	register int newsize = arsize(maxi+1);
352*4887Schin 	if (maxi >= ARRAY_MAX)
353*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
354*4887Schin 	ap = new_of(struct index_array,(newsize-1)*sizeof(union Value*)+newsize/CHAR_BIT);
355*4887Schin 	memset((void*)ap,0,sizeof(*ap));
356*4887Schin 	ap->maxi = newsize;
357*4887Schin 	ap->cur = maxi;
358*4887Schin 	ap->bits =  (unsigned char*)&ap->val[newsize];
359*4887Schin 	memset(ap->bits, 0, newsize/CHAR_BIT);
360*4887Schin 	if(arp)
361*4887Schin 	{
362*4887Schin 		ap->header = arp->header;
363*4887Schin 		for(;i < arp->maxi;i++)
364*4887Schin 			ap->val[i].cp = arp->val[i].cp;
365*4887Schin 		memcpy(ap->bits, arp->bits, (arp->maxi/CHAR_BIT));
366*4887Schin 		array_setptr(np,arp,ap);
367*4887Schin 		free((void*)arp);
368*4887Schin 	}
369*4887Schin 	else
370*4887Schin 	{
371*4887Schin 		ap->header.fun = 0;
372*4887Schin 		if((ap->val[0].cp=np->nvalue.cp))
373*4887Schin 			i++;
374*4887Schin 		else if(nv_hasdisc(np,&array_disc))
375*4887Schin 		{
376*4887Schin 			Namval_t *mp;
377*4887Schin 			int offset = staktell();
378*4887Schin 			sfprintf(stkstd,"%s[0]",nv_name(np));
379*4887Schin 			stakputc(0);
380*4887Schin 			mp = nv_search(stakptr(offset), sh.var_tree, NV_ADD);
381*4887Schin 			stakseek(offset);
382*4887Schin 			if(mp && nv_isnull(mp))
383*4887Schin 			{
384*4887Schin 				nv_clone(np,mp,0);
385*4887Schin 				ap->val[0].np = mp;
386*4887Schin 				array_setbit(ap->bits,0);
387*4887Schin 			}
388*4887Schin 			i++;
389*4887Schin 		}
390*4887Schin 		else if(nv_isattr(np,NV_INTEGER))
391*4887Schin 		{
392*4887Schin 			Sfdouble_t d= nv_getnum(np);
393*4887Schin 			i++;
394*4887Schin 		}
395*4887Schin 		ap->header.nelem = i;
396*4887Schin 		ap->header.hdr.nofree = 1;
397*4887Schin 		ap->header.hdr.disc = &array_disc;
398*4887Schin 		nv_disc(np,(Namfun_t*)ap, NV_LAST);
399*4887Schin 	}
400*4887Schin 	for(;i < newsize;i++)
401*4887Schin 		ap->val[i].cp = 0;
402*4887Schin 	return(ap);
403*4887Schin }
404*4887Schin 
405*4887Schin Namarr_t *nv_arrayptr(register Namval_t *np)
406*4887Schin {
407*4887Schin 	if(nv_isattr(np,NV_ARRAY))
408*4887Schin 		return((Namarr_t*)nv_hasdisc(np, &array_disc));
409*4887Schin 	return(0);
410*4887Schin }
411*4887Schin 
412*4887Schin /*
413*4887Schin  * Verify that argument is an indexed array and convert to associative,
414*4887Schin  * freeing relevant storage
415*4887Schin  */
416*4887Schin static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
417*4887Schin {
418*4887Schin 	register Namarr_t *ap;
419*4887Schin 	char numbuff[NUMSIZE+1];
420*4887Schin 	unsigned dot, digit, n;
421*4887Schin 	union Value *up;
422*4887Schin 	struct index_array *save_ap;
423*4887Schin 	register char *string_index=&numbuff[NUMSIZE];
424*4887Schin 	numbuff[NUMSIZE]='\0';
425*4887Schin 
426*4887Schin 	if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
427*4887Schin 		return(NIL(Namarr_t*));
428*4887Schin 
429*4887Schin 	nv_stack(np,&ap->hdr);
430*4887Schin 	save_ap = (struct index_array*)nv_stack(np,0);
431*4887Schin 	ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
432*4887Schin 	ap->nelem = 0;
433*4887Schin 	ap->fun = fun;
434*4887Schin 	nv_onattr(np,NV_ARRAY);
435*4887Schin 
436*4887Schin 	for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
437*4887Schin 	{
438*4887Schin 		if(save_ap->val[dot].cp)
439*4887Schin 		{
440*4887Schin 			if ((digit = dot)== 0)
441*4887Schin 				*--string_index = '0';
442*4887Schin 			else while( n = digit )
443*4887Schin 			{
444*4887Schin 				digit /= 10;
445*4887Schin 				*--string_index = '0' + (n-10*digit);
446*4887Schin 			}
447*4887Schin 			nv_putsub(np, string_index, ARRAY_ADD);
448*4887Schin 			up = (union Value*)((*ap->fun)(np,NIL(char*),0));
449*4887Schin 			ap->nelem++;
450*4887Schin 			up->cp = save_ap->val[dot].cp;
451*4887Schin 			save_ap->val[dot].cp = 0;
452*4887Schin 		}
453*4887Schin 		string_index = &numbuff[NUMSIZE];
454*4887Schin 	}
455*4887Schin 	free((void*)save_ap);
456*4887Schin 	return(ap);
457*4887Schin }
458*4887Schin 
459*4887Schin /*
460*4887Schin  * set the associative array processing method for node <np> to <fun>
461*4887Schin  * The array pointer is returned if sucessful.
462*4887Schin  */
463*4887Schin Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
464*4887Schin {
465*4887Schin 	register Namarr_t *ap;
466*4887Schin 	char *value;
467*4887Schin 	if(fun && (ap = nv_arrayptr(np)))
468*4887Schin 	{
469*4887Schin 		/*
470*4887Schin 		 * if it's already an indexed array, convert to
471*4887Schin 		 * associative structure
472*4887Schin 		 */
473*4887Schin 		if(!is_associative(ap))
474*4887Schin 			ap = nv_changearray(np, fun);
475*4887Schin 		return(ap);
476*4887Schin 	}
477*4887Schin 	value = nv_getval(np);
478*4887Schin 	if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
479*4887Schin 	{
480*4887Schin 		/* check for preexisting initialization and save */
481*4887Schin 		ap->nelem = 0;
482*4887Schin 		ap->fun = fun;
483*4887Schin 		nv_onattr(np,NV_ARRAY);
484*4887Schin 		if(value)
485*4887Schin 		{
486*4887Schin 			nv_putsub(np, "0", ARRAY_ADD);
487*4887Schin 			nv_putval(np, value, 0);
488*4887Schin 		}
489*4887Schin 		return(ap);
490*4887Schin 	}
491*4887Schin 	return(NIL(Namarr_t*));
492*4887Schin }
493*4887Schin 
494*4887Schin /*
495*4887Schin  * move parent subscript into child
496*4887Schin  */
497*4887Schin Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
498*4887Schin {
499*4887Schin 	register Namarr_t *ap = nv_arrayptr(np);
500*4887Schin 	union Value *up;
501*4887Schin 	if(!(up = array_getup(np,ap)))
502*4887Schin 		return((Namval_t*)0);
503*4887Schin 	if(!nq)
504*4887Schin 		return(array_find(np,ap, ARRAY_LOOKUP));
505*4887Schin 	np->nvalue.cp = up->cp;
506*4887Schin 	ap->nelem |= ARRAY_NOCLONE;
507*4887Schin 	nv_clone(np, nq, NV_NODISC);
508*4887Schin 	nv_offattr(nq,NV_ARRAY);
509*4887Schin 	ap->nelem &= ~ARRAY_NOCLONE;
510*4887Schin 	if(ap->fun)
511*4887Schin 	{
512*4887Schin 		up->np = (Namval_t*)((*ap->fun)(np,NIL(char*),NV_ACURRENT));
513*4887Schin 		nv_onattr(up->np, NV_CHILD);
514*4887Schin 		(up->np)->nvalue.np = nq;
515*4887Schin 	}
516*4887Schin 	else
517*4887Schin 	{
518*4887Schin 		struct index_array *aq = (struct index_array*)ap;
519*4887Schin 		array_setbit(aq->bits,aq->cur);
520*4887Schin 		up->np = nq;
521*4887Schin 	}
522*4887Schin 	if(c=='.')
523*4887Schin 		nv_setvtree(nq);
524*4887Schin 	return(nq);
525*4887Schin }
526*4887Schin 
527*4887Schin /*
528*4887Schin  * This routine sets subscript of <np> to the next element, if any.
529*4887Schin  * The return value is zero, if there are no more elements
530*4887Schin  * Otherwise, 1 is returned.
531*4887Schin  */
532*4887Schin int nv_nextsub(Namval_t *np)
533*4887Schin {
534*4887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
535*4887Schin 	register unsigned dot;
536*4887Schin 	if(!ap || !(ap->header.nelem&ARRAY_SCAN))
537*4887Schin 		return(0);
538*4887Schin 	if(is_associative(ap))
539*4887Schin 	{
540*4887Schin 		struct assoc_array *aq;
541*4887Schin 		if(aq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT))
542*4887Schin 		{
543*4887Schin 			if(nv_isattr(aq->cur,NV_CHILD))
544*4887Schin 				nv_putsub(aq->cur->nvalue.np,NIL(char*),ARRAY_UNDEF);
545*4887Schin 			return(1);
546*4887Schin 		}
547*4887Schin 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
548*4887Schin 		return(0);
549*4887Schin 	}
550*4887Schin 	for(dot=ap->cur+1; dot <  (unsigned)ap->maxi; dot++)
551*4887Schin 	{
552*4887Schin 		if(ap->val[dot].cp)
553*4887Schin 		{
554*4887Schin 			ap->cur = dot;
555*4887Schin 			if(array_isbit(ap->bits, dot))
556*4887Schin 			{
557*4887Schin 
558*4887Schin 				if(ap->header.nelem&ARRAY_NOCHILD)
559*4887Schin 					continue;
560*4887Schin 				nv_putsub(ap->val[dot].np,NIL(char*),ARRAY_UNDEF);
561*4887Schin 			}
562*4887Schin 			return(1);
563*4887Schin 		}
564*4887Schin 	}
565*4887Schin 	ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
566*4887Schin 	ap->cur = 0;
567*4887Schin 	return(0);
568*4887Schin }
569*4887Schin 
570*4887Schin /*
571*4887Schin  * Set an array subscript for node <np> given the subscript <sp>
572*4887Schin  * An array is created if necessary.
573*4887Schin  * <mode> can be a number, plus or more of symbolic constants
574*4887Schin  *    ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
575*4887Schin  * The node pointer is returned which can be NULL if <np> is
576*4887Schin  *    not already array and the ARRAY_ADD bit of <mode> is not set.
577*4887Schin  * ARRAY_FILL sets the specified subscript to the empty string when
578*4887Schin  *   ARRAY_ADD is specified and there is no value or sets all
579*4887Schin  * the elements up to the number specified if ARRAY_ADD is not specified
580*4887Schin  */
581*4887Schin Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
582*4887Schin {
583*4887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
584*4887Schin 	register int size = (mode&ARRAY_MASK);
585*4887Schin 	if(!ap || !ap->header.fun)
586*4887Schin 	{
587*4887Schin 		if(sp)
588*4887Schin 			size = (int)sh_arith((char*)sp);
589*4887Schin 		if(size >= ARRAY_MAX || (size < 0))
590*4887Schin 		{
591*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
592*4887Schin 			return(NIL(Namval_t*));
593*4887Schin 		}
594*4887Schin 		if(!ap || size>=ap->maxi)
595*4887Schin 		{
596*4887Schin 			if(size==0 && !(mode&ARRAY_FILL))
597*4887Schin 				return(NIL(Namval_t*));
598*4887Schin 			if(sh.subshell)
599*4887Schin 				np = sh_assignok(np,1);
600*4887Schin 			ap = array_grow(np, ap,size);
601*4887Schin 			nv_onattr(np,NV_ARRAY);
602*4887Schin 		}
603*4887Schin 		ap->header.nelem &= ~ARRAY_UNDEF;
604*4887Schin 		ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF));
605*4887Schin 		ap->cur = size;
606*4887Schin 		if((mode&ARRAY_SCAN) && !ap->val[size].cp && !nv_nextsub(np))
607*4887Schin 			np = 0;
608*4887Schin 		if(mode&ARRAY_FILL)
609*4887Schin 		{
610*4887Schin 			if(!(mode&ARRAY_ADD))
611*4887Schin 			{
612*4887Schin 				int n;
613*4887Schin 				for(n=0; n < size; n++)
614*4887Schin 				{
615*4887Schin 					if(!ap->val[n].cp)
616*4887Schin 						ap->val[n].cp = Empty;
617*4887Schin 				}
618*4887Schin 				ap->header.nelem = n|(ap->header.nelem&(ARRAY_SCAN|ARRAY_UNDEF));
619*4887Schin 				if(n=ap->maxi-ap->maxi)
620*4887Schin 					memset(&ap->val[size],0,n*sizeof(union Value));
621*4887Schin 			}
622*4887Schin 			else if(!ap->val[size].cp)
623*4887Schin 			{
624*4887Schin 				if(sh.subshell)
625*4887Schin 					np = sh_assignok(np,1);
626*4887Schin 				ap->val[size].cp = Empty;
627*4887Schin 				ap->header.nelem++;
628*4887Schin 			}
629*4887Schin 		}
630*4887Schin 		else if(!(mode&ARRAY_SCAN))
631*4887Schin 		{
632*4887Schin 			ap->header.nelem &= ~ARRAY_SCAN;
633*4887Schin 			if(array_isbit(ap->bits,size))
634*4887Schin 				nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
635*4887Schin 		}
636*4887Schin 		return((Namval_t*)np);
637*4887Schin 	}
638*4887Schin 	ap->header.nelem &= ~ARRAY_UNDEF;
639*4887Schin 	if(!(mode&ARRAY_FILL))
640*4887Schin 		ap->header.nelem &= ~ARRAY_SCAN;
641*4887Schin 	ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF));
642*4887Schin 	if(sp)
643*4887Schin 	{
644*4887Schin 		union Value *up;
645*4887Schin 		if(mode&ARRAY_SETSUB)
646*4887Schin 		{
647*4887Schin 			(*ap->header.fun)(np, sp, NV_ASETSUB);
648*4887Schin 			return(np);
649*4887Schin 		}
650*4887Schin 		up = (union Value*)(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
651*4887Schin 		if(up && !up->cp && (mode&ARRAY_ADD) && (mode&ARRAY_FILL))
652*4887Schin 		{
653*4887Schin 			if(sh.subshell)
654*4887Schin 				np = sh_assignok(np,1);
655*4887Schin 			up->cp = Empty;
656*4887Schin 			ap->header.nelem++;
657*4887Schin 		}
658*4887Schin 	}
659*4887Schin 	else if(mode&ARRAY_SCAN)
660*4887Schin 		(*ap->header.fun)(np,(char*)np,0);
661*4887Schin 	else if(mode&ARRAY_UNDEF)
662*4887Schin 		(*ap->header.fun)(np, "",0);
663*4887Schin 	if((mode&ARRAY_SCAN) && !nv_nextsub(np))
664*4887Schin 		np = 0;
665*4887Schin 	return(np);
666*4887Schin }
667*4887Schin 
668*4887Schin /*
669*4887Schin  * process an array subscript for node <np> given the subscript <cp>
670*4887Schin  * returns pointer to character after the subscript
671*4887Schin  */
672*4887Schin char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
673*4887Schin {
674*4887Schin 	register int count=1, quoted=0, c;
675*4887Schin 	register char *sp = cp+1;
676*4887Schin 	/* first find matching ']' */
677*4887Schin 	while(count>0 && (c= *++cp))
678*4887Schin 	{
679*4887Schin 		if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
680*4887Schin 		{
681*4887Schin 			quoted=1;
682*4887Schin 			cp++;
683*4887Schin 		}
684*4887Schin 		else if(c=='[')
685*4887Schin 			count++;
686*4887Schin 		else if(c==']')
687*4887Schin 			count--;
688*4887Schin 	}
689*4887Schin 	*cp = 0;
690*4887Schin 	if(quoted)
691*4887Schin 	{
692*4887Schin 		/* strip escape characters */
693*4887Schin 		count = staktell();
694*4887Schin 		stakwrite(sp,1+cp-sp);
695*4887Schin 		sh_trim(sp=stakptr(count));
696*4887Schin 	}
697*4887Schin 	if(mode && np)
698*4887Schin 		nv_putsub(np, sp, ARRAY_ADD|(cp[1]?ARRAY_FILL:mode&ARRAY_FILL));
699*4887Schin 	if(quoted)
700*4887Schin 		stakseek(count);
701*4887Schin 	*cp++ = c;
702*4887Schin 	return(cp);
703*4887Schin }
704*4887Schin 
705*4887Schin 
706*4887Schin Namval_t *nv_opensub(Namval_t* np)
707*4887Schin {
708*4887Schin 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
709*4887Schin 	if(ap && is_associative(ap))
710*4887Schin 		return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
711*4887Schin 	return(NIL(Namval_t*));
712*4887Schin }
713*4887Schin 
714*4887Schin char	*nv_getsub(Namval_t* np)
715*4887Schin {
716*4887Schin 	static char numbuff[NUMSIZE];
717*4887Schin 	register struct index_array *ap;
718*4887Schin 	register unsigned dot, n;
719*4887Schin 	register char *cp = &numbuff[NUMSIZE];
720*4887Schin 	if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
721*4887Schin 		return(NIL(char*));
722*4887Schin 	if(is_associative(ap))
723*4887Schin 		return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
724*4887Schin 	if((dot = ap->cur)==0)
725*4887Schin 		*--cp = '0';
726*4887Schin 	else while(n=dot)
727*4887Schin 	{
728*4887Schin 		dot /= 10;
729*4887Schin 		*--cp = '0' + (n-10*dot);
730*4887Schin 	}
731*4887Schin 	return(cp);
732*4887Schin }
733*4887Schin 
734*4887Schin /*
735*4887Schin  * If <np> is an indexed array node, the current subscript index
736*4887Schin  * returned, otherwise returns -1
737*4887Schin  */
738*4887Schin int nv_aindex(register Namval_t* np)
739*4887Schin {
740*4887Schin 	Namarr_t *ap = nv_arrayptr(np);
741*4887Schin 	if(!ap || is_associative(ap))
742*4887Schin 		return(-1);
743*4887Schin 	return(((struct index_array*)(ap))->cur&ARRAY_MASK);
744*4887Schin }
745*4887Schin 
746*4887Schin 
747*4887Schin /*
748*4887Schin  *  This is the default implementation for associate arrays
749*4887Schin  */
750*4887Schin void *nv_associative(register Namval_t *np,const char *sp,int mode)
751*4887Schin {
752*4887Schin 	register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
753*4887Schin 	register int type;
754*4887Schin 	switch(mode)
755*4887Schin 	{
756*4887Schin 	    case NV_AINIT:
757*4887Schin 		if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
758*4887Schin 		{
759*4887Schin 			ap->table = dtopen(&_Nvdisc,Dtbag);
760*4887Schin 			ap->cur = 0;
761*4887Schin 			ap->pos = 0;
762*4887Schin 			ap->header.hdr.disc = &array_disc;
763*4887Schin 			ap->header.hdr.nofree = 1;
764*4887Schin 			nv_disc(np,(Namfun_t*)ap, NV_LAST);
765*4887Schin 		}
766*4887Schin 		return((void*)ap);
767*4887Schin 	    case NV_ADELETE:
768*4887Schin 		if(ap->cur)
769*4887Schin 		{
770*4887Schin 			if(nv_isattr(ap->cur,NV_NOFREE))
771*4887Schin 				nv_offattr(ap->cur,NV_NOFREE);
772*4887Schin 			else
773*4887Schin 			{
774*4887Schin 				dtdelete(ap->table,(void*)ap->cur);
775*4887Schin 				free((void*)ap->cur);
776*4887Schin 				ap->cur = 0;
777*4887Schin 			}
778*4887Schin 		}
779*4887Schin 		return((void*)ap);
780*4887Schin 	    case NV_AFREE:
781*4887Schin 		ap->pos = 0;
782*4887Schin 		dtclose(ap->table);
783*4887Schin 		return((void*)ap);
784*4887Schin 	    case NV_ANEXT:
785*4887Schin 		if(!ap->pos)
786*4887Schin 		{
787*4887Schin 			if(!(ap->pos=ap->cur))
788*4887Schin 				ap->pos = (Namval_t*)dtfirst(ap->table);
789*4887Schin 		}
790*4887Schin 		else
791*4887Schin 			ap->pos = ap->nextpos;
792*4887Schin 		for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
793*4887Schin 		{
794*4887Schin 			ap->nextpos = (Namval_t*)dtnext(ap->table,ap->pos);
795*4887Schin 			if(ap->cur->nvalue.cp)
796*4887Schin 			{
797*4887Schin 				if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
798*4887Schin 					continue;
799*4887Schin 				return((void*)ap);
800*4887Schin 			}
801*4887Schin 		}
802*4887Schin 		return(NIL(void*));
803*4887Schin 	    case NV_ASETSUB:
804*4887Schin 		ap->cur = (Namval_t*)sp;
805*4887Schin 		/* FALL THROUGH*/
806*4887Schin 	    case NV_ACURRENT:
807*4887Schin 		return((void*)ap->cur);
808*4887Schin 	    case NV_ANAME:
809*4887Schin 		if(ap->cur)
810*4887Schin 			return((void*)nv_name(ap->cur));
811*4887Schin 		return(NIL(void*));
812*4887Schin 	    default:
813*4887Schin 		if(sp)
814*4887Schin 		{
815*4887Schin 			if(sp==(char*)np)
816*4887Schin 			{
817*4887Schin 				ap->cur = 0;
818*4887Schin 				return(0);
819*4887Schin 			}
820*4887Schin 			else if(!(ap->header.nelem&ARRAY_SCAN))
821*4887Schin 				ap->pos = 0;
822*4887Schin 			type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD));
823*4887Schin 			if((np=nv_search(sp,ap->table,mode?NV_ADD:0)) && nv_isnull(np))
824*4887Schin 				nv_onattr(np,type);
825*4887Schin 			ap->cur = np;
826*4887Schin 		}
827*4887Schin 		if(ap->cur)
828*4887Schin 			return((void*)(&ap->cur->nvalue));
829*4887Schin 		else
830*4887Schin 			return((void*)(&ap->cur));
831*4887Schin 	}
832*4887Schin }
833*4887Schin 
834*4887Schin /*
835*4887Schin  * Assign values to an array
836*4887Schin  */
837*4887Schin void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
838*4887Schin {
839*4887Schin 	int arg0=0;
840*4887Schin 	struct index_array *ap=0;
841*4887Schin 	if(nv_isarray(np))
842*4887Schin 	{
843*4887Schin 		ap = (struct index_array*)nv_arrayptr(np);
844*4887Schin 		if(ap && is_associative(ap))
845*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associate array %s",nv_name(np));
846*4887Schin 	}
847*4887Schin 	if(append)
848*4887Schin 	{
849*4887Schin 		if(ap)
850*4887Schin 		{
851*4887Schin 			arg0 = ap->maxi;
852*4887Schin 			while(--arg0>0 && ap->val[arg0].cp==0);
853*4887Schin 			arg0++;
854*4887Schin 		}
855*4887Schin 		else if(!nv_isnull(np))
856*4887Schin 			arg0=1;
857*4887Schin 	}
858*4887Schin 	while(--argc >= 0)
859*4887Schin 	{
860*4887Schin 		if((argc+arg0)>0  || nv_isattr(np,NV_ARRAY))
861*4887Schin 			nv_putsub(np,NIL(char*),(long)argc+arg0);
862*4887Schin 		nv_putval(np,argv[argc],0);
863*4887Schin 	}
864*4887Schin }
865*4887Schin 
866