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