xref: /titanic_44/usr/src/lib/libshell/common/sh/array.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
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, b)	(cp[n] |= (b))
37 #define array_clrbit(cp, n, b)	(cp[n] &= ~(b))
38 #define array_isbit(cp, n, b)	(cp[n] & (b))
39 #define NV_CHILD		NV_EXPORT
40 #define ARRAY_CHILD		1
41 #define ARRAY_NOFREE		2
42 
43 struct index_array
44 {
45         Namarr_t        header;
46 	void		*xp;	/* if set, subscripts will be converted */
47         int		cur;    /* index of current element */
48         int		maxi;   /* maximum index for array */
49 	unsigned char	*bits;	/* bit array for child subscripts */
50         union Value	val[1]; /* array of value holders */
51 };
52 
53 struct assoc_array
54 {
55 	Namarr_t	header;
56 	Namval_t	*pos;
57 	Namval_t	*nextpos;
58 	Namval_t	*cur;
59 };
60 
61 static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
62 {
63 	Namarr_t *aq;
64 	struct index_array *ar;
65 	size_t size = ap->hdr.dsize;
66 	if(size==0)
67 		size = ap->hdr.disc->dsize;
68         if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
69                 return(0);
70         memcpy(aq,ap,size);
71 	aq->hdr.nofree &= ~1;
72         aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
73 	if(is_associative(aq))
74 	{
75 		aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
76 		dtview((Dt_t*)aq->scope,aq->table);
77 		aq->table = (Dt_t*)aq->scope;
78 		return(aq);
79 	}
80 	aq->scope = (void*)ap;
81 	ar = (struct index_array*)aq;
82 	memset(ar->val, 0, ar->maxi*sizeof(char*));
83 	return(aq);
84 }
85 
86 static int array_unscope(Namval_t *np,Namarr_t *ap)
87 {
88 	Namfun_t *fp;
89 	if(!ap->scope)
90 		return(0);
91 	if(is_associative(ap))
92 		(*ap->fun)(np, NIL(char*), NV_AFREE);
93 	if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
94 		free((void*)fp);
95 	nv_delete(np,(Dt_t*)0,0);
96 	return(1);
97 }
98 
99 static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
100 {
101 	((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
102 }
103 
104 static int array_covered(Namval_t *np, struct index_array *ap)
105 {
106 	struct index_array *aq = (struct index_array*)ap->header.scope;
107 	if(!ap->header.fun && aq)
108 		return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
109 	return(0);
110 }
111 
112 /*
113  * replace discipline with new one
114  */
115 static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
116 {
117 	register Namfun_t **fp = &np->nvfun;
118 	while(*fp && *fp!= &old->header.hdr)
119 		fp = &((*fp)->next);
120 	if(*fp)
121 	{
122 		new->header.hdr.next = (*fp)->next;
123 		*fp = &new->header.hdr;
124 	}
125 	else sfprintf(sfstderr,"discipline not replaced\n");
126 }
127 
128 /*
129  *   Calculate the amount of space to be allocated to hold an
130  *   indexed array into which <maxi> is a legal index.  The number of
131  *   elements that will actually fit into the array (> <maxi>
132  *   but <= ARRAY_MAX) is returned.
133  *
134  */
135 static int	arsize(struct index_array *ap, register int maxi)
136 {
137 	if(ap && maxi < 2*ap->maxi)
138 		maxi = 2*ap->maxi;
139 	maxi = roundof(maxi,ARRAY_INCR);
140 	return (maxi>ARRAY_MAX?ARRAY_MAX:maxi);
141 }
142 
143 static struct index_array *array_grow(Namval_t*, struct index_array*,int);
144 
145 /* return index of highest element of an array */
146 int array_maxindex(Namval_t *np)
147 {
148 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
149 	register int i = ap->maxi;
150 	if(is_associative(ap))
151 		return(-1);
152 	while(i>0 && ap->val[--i].cp==0);
153 	return(i+1);
154 }
155 
156 static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update)
157 {
158 	register struct index_array *ap = (struct index_array*)arp;
159 	register union Value *up;
160 	int	nofree;
161 	if(!arp)
162 		return(&np->nvalue);
163 	if(is_associative(ap))
164 	{
165 		Namval_t	*mp;
166 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
167 		if(mp)
168 		{
169 			nofree = nv_isattr(mp,NV_NOFREE);
170 			up = &mp->nvalue;
171 		}
172 		else
173 			return((union Value*)((*arp->fun)(np,NIL(char*),0)));
174 	}
175 	else
176 	{
177 		if(ap->cur >= ap->maxi)
178 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
179 		up = &(ap->val[ap->cur]);
180 		nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
181 	}
182 	if(update)
183 	{
184 		if(nofree)
185 			nv_onattr(np,NV_NOFREE);
186 		else
187 			nv_offattr(np,NV_NOFREE);
188 	}
189 	return(up);
190 }
191 
192 /*
193  * Get the Value pointer for an array.
194  * Delete space as necessary if flag is ARRAY_DELETE
195  * After the lookup is done the last @ or * subscript is incremented
196  */
197 static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
198 {
199 	register struct index_array *ap = (struct index_array*)arp;
200 	register union Value	*up;
201 	Namval_t		*mp;
202 	int			wasundef;
203 	if(flag&ARRAY_LOOKUP)
204 		ap->header.nelem &= ~ARRAY_NOSCOPE;
205 	else
206 		ap->header.nelem |= ARRAY_NOSCOPE;
207 	if(wasundef = ap->header.nelem&ARRAY_UNDEF)
208 	{
209 		ap->header.nelem &= ~ARRAY_UNDEF;
210 		/* delete array is the same as delete array[@] */
211 		if(flag&ARRAY_DELETE)
212 		{
213 			nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
214 			ap->header.nelem |= ARRAY_SCAN;
215 		}
216 		else /* same as array[0] */
217 		{
218 			if(is_associative(ap))
219 				(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
220 			else
221 				ap->cur = 0;
222 		}
223 	}
224 	if(is_associative(ap))
225 	{
226 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
227 		if(!mp)
228 			up = (union Value*)&mp;
229 		else if(nv_isarray(mp))
230 		{
231 			if(wasundef)
232 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
233 			return(mp);
234 		}
235 		else
236 		{
237 			up =  &mp->nvalue;
238 			if(nv_isvtree(mp))
239 			{
240 				if(!up->cp && flag==ARRAY_ASSIGN)
241 				{
242 					nv_arraychild(np,mp,0);
243 					ap->header.nelem++;
244 				}
245 				return(mp);
246 			}
247 		}
248 	}
249 	else
250 	{
251 		if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
252 			ap = array_grow(np, ap, (int)ap->cur);
253 		if(ap->cur>=ap->maxi)
254 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
255 		up = &(ap->val[ap->cur]);
256 		if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
257 		{
258 			char *cp;
259 			if(!ap->header.table)
260 				ap->header.table = dtopen(&_Nvdisc,Dtoset);
261 			sfprintf(sh.strbuf,"%d",ap->cur);
262 			cp = sfstruse(sh.strbuf);
263 			mp = nv_search(cp, ap->header.table, NV_ADD);
264 			mp->nvenv = (char*)np;
265 			nv_arraychild(np,mp,0);
266 		}
267 		if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
268 		{
269 			if(wasundef && nv_isarray(up->np))
270 				nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
271 			return(up->np);
272 		}
273 	}
274 	np->nvalue.cp = up->cp;
275 	if(!up->cp)
276 	{
277 		if(flag!=ARRAY_ASSIGN)
278 			return(0);
279 		if(!array_covered(np,ap))
280 			ap->header.nelem++;
281 	}
282 	return(np);
283 }
284 
285 #if SHOPT_TYPEDEF
286 int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
287 {
288 	Namval_t	*nq;
289 	char		*av[2];
290 	int		rdonly = nv_isattr(np,NV_RDONLY);
291 	int		xtrace = sh_isoption(SH_XTRACE);
292 	Namarr_t	*ap = nv_arrayptr(np);
293 	av[1] = 0;
294 	sh.last_table = 0;
295 	if(!ap->table)
296 		ap->table = dtopen(&_Nvdisc,Dtoset);
297 	if(nq = nv_search(sub, ap->table, NV_ADD))
298 	{
299 		if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
300 			_nv_unset(nq,NV_RDONLY);
301 		nv_arraychild(np,nq,0);
302 		if(!nv_isattr(tp,NV_BINARY))
303 		{
304 			sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
305 			av[0] = strdup(sfstruse(sh.strbuf));
306 		}
307 		if(!nv_clone(tp,nq,flags|NV_NOFREE))
308 			return(0);
309 		ap->nelem |= ARRAY_SCAN;
310 		if(!rdonly)
311 			nv_offattr(nq,NV_RDONLY);
312 		if(!nv_isattr(tp,NV_BINARY))
313 		{
314 			if(xtrace)
315 				sh_offoption(SH_XTRACE);
316 			ap->nelem &= ~ARRAY_SCAN;
317 			sh_eval(sh_sfeval(av),0);
318 			ap->nelem |= ARRAY_SCAN;
319 			free((void*)av[0]);
320 			if(xtrace)
321 				sh_onoption(SH_XTRACE);
322 		}
323 		return(1);
324 	}
325 	return(0);
326 }
327 #endif /* SHOPT_TYPEDEF */
328 
329 
330 static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
331 {
332 	Namarr_t		*ap = (Namarr_t*)fp;
333 	Namval_t		*nq, *mq;
334 	char			*name, *sub=0;
335 	int			nelem, skipped=0;
336 	Dt_t			*otable=ap->table;
337 	struct index_array	*aq = (struct index_array*)ap, *ar;
338 	Shell_t			*shp = sh_getinterp();
339 	if(flags&NV_MOVE)
340 	{
341 		if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
342 		{
343 			do
344 			{
345 				if(nq=nv_opensub(np))
346 					nq->nvenv = (void*)mp;
347 			}
348 			while(nv_nextsub(np));
349 		}
350 		return(fp);
351 	}
352 	nelem = ap->nelem;
353 	if(nelem&ARRAY_NOCLONE)
354 		return(0);
355 	if((flags&NV_TYPE) && !ap->scope)
356 	{
357 		ap = array_scope(np,ap,flags);
358 		return(&ap->hdr);
359 	}
360 	ap = (Namarr_t*)nv_clone_disc(fp,0);
361 	if(flags&NV_COMVAR)
362 	{
363 		ap->scope = 0;
364 		ap->nelem = 0;
365 		sh.prev_table = sh.last_table;
366 		sh.prev_root = sh.last_root;
367 	}
368 	if(ap->table)
369 	{
370 		ap->table = dtopen(&_Nvdisc,Dtoset);
371 		if(ap->scope && !(flags&NV_COMVAR))
372 		{
373 			ap->scope = ap->table;
374 			dtview(ap->table, otable->view);
375 		}
376 	}
377 	mp->nvfun = (Namfun_t*)ap;
378 	mp->nvflag &= NV_MINIMAL;
379 	mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
380 	if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
381 		sub = strdup(sub);
382 	ar = (struct index_array*)ap;
383 	if(!is_associative(ap))
384 		ar->bits = (unsigned char*)&ar->val[ar->maxi];
385 	if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
386 	{
387 		if(ap->fun)
388 			(*ap->fun)(np,(char*)np,0);
389 		skipped=1;
390 		goto skip;
391 	}
392 	do
393 	{
394 		name = nv_getsub(np);
395 		nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
396 		mq = 0;
397 		if(nq=nv_opensub(np))
398 			mq = nv_search(name,ap->table,NV_ADD);
399 		if(nq && (flags&NV_COMVAR) && nv_isvtree(nq))
400 		{
401 			mq->nvalue.cp = 0;
402 			if(!is_associative(ap))
403 				ar->val[ar->cur].np = mq;
404 			nv_clone(nq,mq,flags);
405 		}
406 		else if(flags&NV_ARRAY)
407 		{
408 			if((flags&NV_NOFREE) && !is_associative(ap))
409 				array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
410 			else if(nq && (flags&NV_NOFREE))
411 			{
412 				mq->nvalue = nq->nvalue;
413 				nv_onattr(nq,NV_NOFREE);
414 			}
415 		}
416 		else if(nv_isattr(np,NV_INTEGER))
417 		{
418 			Sfdouble_t d= nv_getnum(np);
419 			if(!is_associative(ap))
420 				ar->val[ar->cur].cp = 0;
421 			nv_putval(mp,(char*)&d,NV_LDOUBLE);
422 		}
423 		else
424 		{
425 			if(!is_associative(ap))
426 				ar->val[ar->cur].cp = 0;
427 			nv_putval(mp,nv_getval(np),NV_RDONLY);
428 		}
429 		aq->header.nelem |= ARRAY_NOSCOPE;
430 	}
431 	while(nv_nextsub(np));
432 skip:
433 	if(sub)
434 	{
435 		if(!skipped)
436 			nv_putsub(np,sub,0L);
437 		free((void*)sub);
438 	}
439 	aq->header.nelem = ap->nelem = nelem;
440 	return(&ap->hdr);
441 }
442 
443 static char *array_getval(Namval_t *np, Namfun_t *disc)
444 {
445 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
446 	register Namval_t *mp;
447 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
448 	{
449 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
450 		{
451 			array_syncsub(aq,ap);
452 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
453 				return(nv_getv(np,&aq->hdr));
454 		}
455 		return(mp?nv_getval(mp):0);
456 	}
457 	return(nv_getv(np,&ap->hdr));
458 }
459 
460 static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
461 {
462 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
463 	register Namval_t *mp;
464 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
465 	{
466 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
467 		{
468 			array_syncsub(aq,ap);
469 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
470 				return(nv_getn(np,&aq->hdr));
471 		}
472 		return(mp?nv_getnum(mp):0);
473 	}
474 	return(nv_getn(np,&ap->hdr));
475 }
476 
477 static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
478 {
479 	register Namarr_t	*ap = (Namarr_t*)dp;
480 	register union Value	*up;
481 	register Namval_t	*mp;
482 	register struct index_array *aq = (struct index_array*)ap;
483 	int			scan,nofree = nv_isattr(np,NV_NOFREE);
484 	do
485 	{
486 		mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
487 		scan = ap->nelem&ARRAY_SCAN;
488 		if(mp && mp!=np)
489 		{
490 			if(!is_associative(ap) && string && !nv_type(np) && nv_isvtree(mp))
491 			{
492 				if(!nv_isattr(np,NV_NOFREE))
493 					_nv_unset(mp,flags&NV_RDONLY);
494 				array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
495 				aq->val[aq->cur].cp = 0;
496 				if(!nv_isattr(mp,NV_NOFREE))
497 					nv_delete(mp,ap->table,0);
498 				goto skip;
499 			}
500 			nv_putval(mp, string, flags);
501 			if(string)
502 			{
503 #if SHOPT_TYPEDEF
504 				if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
505 					nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
506 #endif /* SHOPT_TYPEDEF */
507 				continue;
508 			}
509 			ap->nelem |= scan;
510 		}
511 		if(!string)
512 		{
513 			if(mp)
514 			{
515 				if(is_associative(ap))
516 				{
517 					(*ap->fun)(np,NIL(char*),NV_ADELETE);
518 					np->nvalue.cp = 0;
519 				}
520 				else
521 				{
522 					if(mp!=np)
523 					{
524 						array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
525 						aq->val[aq->cur].cp = 0;
526 						nv_delete(mp,ap->table,0);
527 					}
528 					if(!array_covered(np,(struct index_array*)ap))
529 						ap->nelem--;
530 				}
531 			}
532 			if(array_elem(ap)==0 && ((ap->nelem&ARRAY_SCAN) || !is_associative(ap)))
533 			{
534 				if(is_associative(ap))
535 					(*ap->fun)(np, NIL(char*), NV_AFREE);
536 				else if(ap->table)
537 					dtclose(ap->table);
538 				nv_offattr(np,NV_ARRAY);
539 			}
540 			if(!mp || mp!=np || is_associative(ap))
541 				continue;
542 		}
543 	skip:
544 		/* prevent empty string from being deleted */
545 		up = array_getup(np,ap,!nofree);
546 		if(up->cp ==  Empty)
547 			up->cp = 0;
548 		if(nv_isarray(np))
549 			np->nvalue.up = up;
550 		nv_putv(np,string,flags,&ap->hdr);
551 		if(!is_associative(ap))
552 		{
553 			if(string)
554 				array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
555 			else if(mp==np)
556 				aq->val[aq->cur].cp = 0;
557 		}
558 #if SHOPT_TYPEDEF
559 		if(string && ap->hdr.type && nv_isvtree(np))
560 			nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
561 #endif /* SHOPT_TYPEDEF */
562 	}
563 	while(!string && nv_nextsub(np));
564 	if(ap)
565 		ap->nelem &= ~ARRAY_NOSCOPE;
566 	if(nofree)
567 		nv_onattr(np,NV_NOFREE);
568 	else
569 		nv_offattr(np,NV_NOFREE);
570 	if(!string && !nv_isattr(np,NV_ARRAY))
571 	{
572 		Namfun_t *nfp;
573 		if(!is_associative(ap) && aq->xp)
574 		{
575 			_nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
576 			free((void*)aq->xp);
577 		}
578 		if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
579 			free((void*)nfp);
580 		if(!nv_isnull(np))
581 		{
582 			nv_onattr(np,NV_NOFREE);
583 			_nv_unset(np,flags);
584 		}
585 		if(np->nvalue.cp==Empty)
586 			np->nvalue.cp = 0;
587 	}
588 	if(!string && (flags&NV_TYPE))
589 		array_unscope(np,ap);
590 }
591 
592 static const Namdisc_t array_disc =
593 {
594 	sizeof(Namarr_t),
595 	array_putval,
596 	array_getval,
597 	array_getnum,
598 	0,
599 	0,
600 	array_clone
601 };
602 
603 static void array_copytree(Namval_t *np, Namval_t *mp)
604 {
605 	char		*val;
606 	Namfun_t	*fp = nv_disc(np,NULL,NV_POP);
607 	nv_offattr(np,NV_ARRAY);
608 	nv_clone(np,mp,0);
609 	np->nvalue.up = &mp->nvalue;
610 	val = sfstruse(sh.strbuf);
611 	fp->nofree  &= ~1;
612 	nv_disc(np,(Namfun_t*)fp, NV_FIRST);
613 	fp->nofree |= 1;
614 	nv_onattr(np,NV_ARRAY);
615 	mp->nvenv = (char*)np;
616 }
617 
618 /*
619  *        Increase the size of the indexed array of elements in <arp>
620  *        so that <maxi> is a legal index.  If <arp> is 0, an array
621  *        of the required size is allocated.  A pointer to the
622  *        allocated Namarr_t structure is returned.
623  *        <maxi> becomes the current index of the array.
624  */
625 static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
626 {
627 	register struct index_array *ap;
628 	register int i;
629 	register int newsize = arsize(arp,maxi+1);
630 	if (maxi >= ARRAY_MAX)
631 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
632 	i = (newsize-1)*sizeof(union Value*)+newsize;
633 	ap = new_of(struct index_array,i);
634 	memset((void*)ap,0,sizeof(*ap)+i);
635 	ap->maxi = newsize;
636 	ap->cur = maxi;
637 	ap->bits =  (unsigned char*)&ap->val[newsize];
638 	memset(ap->bits, 0, newsize);
639 	if(arp)
640 	{
641 		ap->header = arp->header;
642 		ap->header.hdr.dsize = sizeof(*ap) + i;
643 		for(i=0;i < arp->maxi;i++)
644 			ap->val[i].cp = arp->val[i].cp;
645 		memcpy(ap->bits, arp->bits, arp->maxi);
646 		array_setptr(np,arp,ap);
647 		free((void*)arp);
648 	}
649 	else
650 	{
651 		Namval_t *mp=0;
652 		ap->header.hdr.dsize = sizeof(*ap) + i;
653 		i = 0;
654 		ap->header.fun = 0;
655 		if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
656 		{
657 			i = ARRAY_TREE;
658 			nv_offattr(np,NV_NOFREE);
659 		}
660 		if(np->nvalue.cp==Empty)
661 			np->nvalue.cp=0;
662 		if(nv_hasdisc(np,&array_disc) || nv_isvtree(np))
663 		{
664 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
665 			mp = nv_search("0", ap->header.table, 0);
666 
667 			if(mp && nv_isnull(mp))
668 			{
669 				Namfun_t *fp;
670 				ap->val[0].np = mp;
671 				array_setbit(ap->bits,0,ARRAY_CHILD);
672 				for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
673 				if(fp)
674 					(*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
675 				i++;
676 			}
677 		}
678 		else if((ap->val[0].cp=np->nvalue.cp))
679 			i++;
680 		else if(nv_isattr(np,NV_INTEGER))
681 		{
682 			Sfdouble_t d= nv_getnum(np);
683 			i++;
684 		}
685 		ap->header.nelem = i;
686 		ap->header.hdr.disc = &array_disc;
687 		nv_disc(np,(Namfun_t*)ap, NV_FIRST);
688 		nv_onattr(np,NV_ARRAY);
689 		if(mp)
690 		{
691 			array_copytree(np,mp);
692 			ap->header.hdr.nofree &= ~1;
693 		}
694 	}
695 	for(;i < newsize;i++)
696 		ap->val[i].cp = 0;
697 	return(ap);
698 }
699 
700 int nv_atypeindex(Namval_t *np, const char *tname)
701 {
702 	Namval_t	*tp;
703 	int		offset = staktell();
704 	int		n = strlen(tname)-1;
705 	sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
706 	tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
707 	stakseek(offset);
708 	if(tp)
709 	{
710 		struct index_array *ap = (struct index_array*)nv_arrayptr(np);
711 		if(!nv_hasdisc(tp,&ENUM_disc))
712 			errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
713 		if(!ap)
714 			ap = array_grow(np,ap,1);
715 		ap->xp = calloc(NV_MINSZ,1);
716 		np = nv_namptr(ap->xp,0);
717 		np->nvname = tp->nvname;
718 		nv_onattr(np,NV_MINIMAL);
719 		nv_clone(tp,np,NV_NOFREE);
720 		nv_offattr(np,NV_RDONLY);
721 		return(1);
722 	}
723 	errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
724 	return(0);
725 }
726 
727 Namarr_t *nv_arrayptr(register Namval_t *np)
728 {
729 	if(nv_isattr(np,NV_ARRAY))
730 		return((Namarr_t*)nv_hasdisc(np, &array_disc));
731 	return(0);
732 }
733 
734 /*
735  * Verify that argument is an indexed array and convert to associative,
736  * freeing relevant storage
737  */
738 static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
739 {
740 	register Namarr_t *ap;
741 	char numbuff[NUMSIZE+1];
742 	unsigned dot, digit, n;
743 	union Value *up;
744 	struct index_array *save_ap;
745 	register char *string_index=&numbuff[NUMSIZE];
746 	numbuff[NUMSIZE]='\0';
747 
748 	if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
749 		return(NIL(Namarr_t*));
750 
751 	nv_stack(np,&ap->hdr);
752 	save_ap = (struct index_array*)nv_stack(np,0);
753 	ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
754 	ap->nelem = 0;
755 	ap->fun = fun;
756 	nv_onattr(np,NV_ARRAY);
757 
758 	for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
759 	{
760 		if(save_ap->val[dot].cp)
761 		{
762 			if ((digit = dot)== 0)
763 				*--string_index = '0';
764 			else while( n = digit )
765 			{
766 				digit /= 10;
767 				*--string_index = '0' + (n-10*digit);
768 			}
769 			nv_putsub(np, string_index, ARRAY_ADD);
770 			up = (union Value*)((*ap->fun)(np,NIL(char*),0));
771 			up->cp = save_ap->val[dot].cp;
772 			save_ap->val[dot].cp = 0;
773 		}
774 		string_index = &numbuff[NUMSIZE];
775 	}
776 	free((void*)save_ap);
777 	return(ap);
778 }
779 
780 /*
781  * set the associative array processing method for node <np> to <fun>
782  * The array pointer is returned if sucessful.
783  */
784 Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
785 {
786 	register Namarr_t *ap;
787 	char		*value=0;
788 	Namfun_t	*fp;
789 	int		nelem = 0;
790 	if(fun && (ap = nv_arrayptr(np)))
791 	{
792 		/*
793 		 * if it's already an indexed array, convert to
794 		 * associative structure
795 		 */
796 		if(!is_associative(ap))
797 			ap = nv_changearray(np, fun);
798 		return(ap);
799 	}
800 	if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
801 	{
802 		nelem = ARRAY_TREE;
803 		nv_offattr(np,NV_NOFREE);
804 	}
805 	if(!(fp=nv_isvtree(np)))
806 		value = nv_getval(np);
807 	if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
808 	{
809 		/* check for preexisting initialization and save */
810 		ap->nelem = nelem;
811 		ap->fun = fun;
812 		nv_onattr(np,NV_ARRAY);
813 		if(fp || value)
814 		{
815 			nv_putsub(np, "0", ARRAY_ADD);
816 			if(value)
817 				nv_putval(np, value, 0);
818 			else
819 			{
820 				Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
821 				array_copytree(np,mp);
822 			}
823 		}
824 		return(ap);
825 	}
826 	return(NIL(Namarr_t*));
827 }
828 
829 /*
830  * move parent subscript into child
831  */
832 Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
833 {
834 	Namfun_t		*fp;
835 	register Namarr_t	*ap = nv_arrayptr(np);
836 	union Value		*up;
837 	Namval_t		*tp;
838 	if(!nq)
839 		return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
840 	if(!ap)
841 	{
842 		nv_putsub(np, NIL(char*), ARRAY_FILL);
843 		ap = nv_arrayptr(np);
844 	}
845 	if(!(up = array_getup(np,ap,0)))
846 		return((Namval_t*)0);
847 	np->nvalue.cp = up->cp;
848 	if((tp=nv_type(np)) || c)
849 	{
850 		ap->nelem |= ARRAY_NOCLONE;
851 		nq->nvenv = (char*)np;
852 		if(c=='t')
853 			nv_clone(tp,nq, 0);
854 		else
855 			nv_clone(np, nq, NV_NODISC);
856 		nv_offattr(nq,NV_ARRAY);
857 		ap->nelem &= ~ARRAY_NOCLONE;
858 	}
859 	nq->nvenv = (char*)np;
860 	if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
861 		free((void*)fp);
862 	if(!ap->fun)
863 	{
864 		struct index_array *aq = (struct index_array*)ap;
865 		array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
866 		up->np = nq;
867 	}
868 	if(c=='.')
869 		nv_setvtree(nq);
870 	return(nq);
871 }
872 
873 /*
874  * This routine sets subscript of <np> to the next element, if any.
875  * The return value is zero, if there are no more elements
876  * Otherwise, 1 is returned.
877  */
878 int nv_nextsub(Namval_t *np)
879 {
880 	register struct index_array	*ap = (struct index_array*)nv_arrayptr(np);
881 	register unsigned		dot;
882 	struct index_array		*aq=0, *ar=0;
883 	if(!ap || !(ap->header.nelem&ARRAY_SCAN))
884 		return(0);
885 	if(is_associative(ap))
886 	{
887 		Namval_t	*nq;
888 		if(nq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT))
889 		{
890 			if(nv_isattr(nq,NV_CHILD))
891 				nv_putsub(nq->nvalue.np,NIL(char*),ARRAY_UNDEF);
892 			return(1);
893 		}
894 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
895 		return(0);
896 	}
897 	if(!(ap->header.nelem&ARRAY_NOSCOPE))
898 		ar = (struct index_array*)ap->header.scope;
899 	for(dot=ap->cur+1; dot <  (unsigned)ap->maxi; dot++)
900 	{
901 		aq = ap;
902 		if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
903 		{
904 			if(!(aq=ar) || dot>=(unsigned)aq->maxi)
905 				continue;
906 		}
907 		if(aq->val[dot].cp)
908 		{
909 			ap->cur = dot;
910 			if(array_isbit(aq->bits, dot,ARRAY_CHILD))
911 			{
912 				Namval_t *mp = aq->val[dot].np;
913 				if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp))
914 					continue;
915 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
916 			}
917 			return(1);
918 		}
919 	}
920 	ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
921 	ap->cur = 0;
922 	return(0);
923 }
924 
925 /*
926  * Set an array subscript for node <np> given the subscript <sp>
927  * An array is created if necessary.
928  * <mode> can be a number, plus or more of symbolic constants
929  *    ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
930  * The node pointer is returned which can be NULL if <np> is
931  *    not already array and the ARRAY_ADD bit of <mode> is not set.
932  * ARRAY_FILL sets the specified subscript to the empty string when
933  *   ARRAY_ADD is specified and there is no value or sets all
934  * the elements up to the number specified if ARRAY_ADD is not specified
935  */
936 Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
937 {
938 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
939 	register int size = (mode&ARRAY_MASK);
940 	if(!ap || !ap->header.fun)
941 	{
942 		if(sp)
943 		{
944 			if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
945 			{
946 				Namval_t *mp = nv_namptr(ap->xp,0);
947 				nv_putval(mp, sp,0);
948 				size = nv_getnum(mp);
949 			}
950 			else
951 				size = (int)sh_arith((char*)sp);
952 		}
953 		if(size <0 && ap)
954 			size += array_maxindex(np);
955 		if(size >= ARRAY_MAX || (size < 0))
956 		{
957 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
958 			return(NIL(Namval_t*));
959 		}
960 		if(!ap || size>=ap->maxi)
961 		{
962 			if(size==0 && !(mode&ARRAY_FILL))
963 				return(NIL(Namval_t*));
964 			if(sh.subshell)
965 				np = sh_assignok(np,1);
966 			ap = array_grow(np, ap,size);
967 		}
968 		ap->header.nelem &= ~ARRAY_UNDEF;
969 		ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
970 #if 0
971 		if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
972 			mp = ap->val[oldsize].np;
973 		if(size != oldsize && mp->nvalue.cp)
974 		{
975 			Namfun_t *nfp;
976 			for(nfp=np->nvfun; nfp; nfp=nfp->next)
977 			{
978 				if(nfp->disc && nfp->disc->readf)
979 				{
980 					(*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
981 					break;
982 				}
983 			}
984 		}
985 #endif
986 		ap->cur = size;
987 		if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
988 			np = 0;
989 		if(mode&(ARRAY_FILL|ARRAY_ADD))
990 		{
991 			if(!(mode&ARRAY_ADD))
992 			{
993 				int n;
994 				for(n=0; n <= size; n++)
995 				{
996 					if(!ap->val[n].cp)
997 					{
998 						ap->val[n].cp = Empty;
999 						if(!array_covered(np,ap))
1000 							ap->header.nelem++;
1001 					}
1002 				}
1003 				if(n=ap->maxi-ap->maxi)
1004 					memset(&ap->val[size],0,n*sizeof(union Value));
1005 			}
1006 			else if(!ap->val[size].cp)
1007 			{
1008 				if(sh.subshell)
1009 					np = sh_assignok(np,1);
1010 				ap->val[size].cp = Empty;
1011 				if(!array_covered(np,ap))
1012 					ap->header.nelem++;
1013 			}
1014 		}
1015 		else if(!(mode&ARRAY_SCAN))
1016 		{
1017 			ap->header.nelem &= ~ARRAY_SCAN;
1018 			if(array_isbit(ap->bits,size,ARRAY_CHILD))
1019 				nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
1020 			if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
1021 				np = 0;
1022 		}
1023 		return((Namval_t*)np);
1024 	}
1025 	ap->header.nelem &= ~ARRAY_UNDEF;
1026 	if(!(mode&ARRAY_FILL))
1027 		ap->header.nelem &= ~ARRAY_SCAN;
1028 	ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1029 	if(sp)
1030 	{
1031 		if(mode&ARRAY_SETSUB)
1032 		{
1033 			(*ap->header.fun)(np, sp, NV_ASETSUB);
1034 			return(np);
1035 		}
1036 		(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
1037 		if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
1038 			np = 0;
1039 	}
1040 	else if(mode&ARRAY_SCAN)
1041 		(*ap->header.fun)(np,(char*)np,0);
1042 	else if(mode&ARRAY_UNDEF)
1043 		(*ap->header.fun)(np, "",0);
1044 	if((mode&ARRAY_SCAN) && !nv_nextsub(np))
1045 		np = 0;
1046 	return(np);
1047 }
1048 
1049 /*
1050  * process an array subscript for node <np> given the subscript <cp>
1051  * returns pointer to character after the subscript
1052  */
1053 char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
1054 {
1055 	register int count=1, quoted=0, c;
1056 	register char *sp = cp+1;
1057 	/* first find matching ']' */
1058 	while(count>0 && (c= *++cp))
1059 	{
1060 		if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
1061 		{
1062 			quoted=1;
1063 			cp++;
1064 		}
1065 		else if(c=='[')
1066 			count++;
1067 		else if(c==']')
1068 			count--;
1069 	}
1070 	*cp = 0;
1071 	if(quoted)
1072 	{
1073 		/* strip escape characters */
1074 		count = staktell();
1075 		stakwrite(sp,1+cp-sp);
1076 		sh_trim(sp=stakptr(count));
1077 	}
1078 	if(mode && np)
1079 	{
1080 		if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
1081 			mode |= NV_ADD;
1082 		nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
1083 	}
1084 	if(quoted)
1085 		stakseek(count);
1086 	*cp++ = c;
1087 	return(cp);
1088 }
1089 
1090 
1091 Namval_t *nv_opensub(Namval_t* np)
1092 {
1093 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1094 	if(ap)
1095 	{
1096 		if(is_associative(ap))
1097 			return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
1098 		else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
1099 			return(ap->val[ap->cur].np);
1100 	}
1101 	return(NIL(Namval_t*));
1102 }
1103 
1104 char	*nv_getsub(Namval_t* np)
1105 {
1106 	static char numbuff[NUMSIZE];
1107 	register struct index_array *ap;
1108 	register unsigned dot, n;
1109 	register char *cp = &numbuff[NUMSIZE];
1110 	if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
1111 		return(NIL(char*));
1112 	if(is_associative(ap))
1113 		return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
1114 	if(ap->xp)
1115 	{
1116 		np = nv_namptr(ap->xp,0);
1117 		np->nvalue.s = ap->cur;
1118 		return(nv_getval(np));
1119 	}
1120 	if((dot = ap->cur)==0)
1121 		*--cp = '0';
1122 	else while(n=dot)
1123 	{
1124 		dot /= 10;
1125 		*--cp = '0' + (n-10*dot);
1126 	}
1127 	return(cp);
1128 }
1129 
1130 /*
1131  * If <np> is an indexed array node, the current subscript index
1132  * returned, otherwise returns -1
1133  */
1134 int nv_aindex(register Namval_t* np)
1135 {
1136 	Namarr_t *ap = nv_arrayptr(np);
1137 	if(!ap)
1138 		return(0);
1139 	else if(is_associative(ap))
1140 		return(-1);
1141 	return(((struct index_array*)(ap))->cur&ARRAY_MASK);
1142 }
1143 
1144 int nv_arraynsub(register Namarr_t* ap)
1145 {
1146 	return(array_elem(ap));
1147 }
1148 
1149 int nv_aimax(register Namval_t* np)
1150 {
1151 	struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1152 	int sub = -1;
1153 	if(!ap || is_associative(&ap->header))
1154 		return(-1);
1155 	sub = ap->maxi;
1156 	while(--sub>0 && ap->val[sub].cp==0);
1157 	return(sub);
1158 }
1159 
1160 /*
1161  *  This is the default implementation for associative arrays
1162  */
1163 void *nv_associative(register Namval_t *np,const char *sp,int mode)
1164 {
1165 	register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
1166 	register int type;
1167 	switch(mode)
1168 	{
1169 	    case NV_AINIT:
1170 		if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
1171 		{
1172 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
1173 			ap->cur = 0;
1174 			ap->pos = 0;
1175 			ap->header.hdr.disc = &array_disc;
1176 			nv_disc(np,(Namfun_t*)ap, NV_FIRST);
1177 			ap->header.hdr.dsize = sizeof(struct assoc_array);
1178 			ap->header.hdr.nofree &= ~1;
1179 		}
1180 		return((void*)ap);
1181 	    case NV_ADELETE:
1182 		if(ap->cur)
1183 		{
1184 			if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0))
1185 				ap->header.nelem--;
1186 			_nv_unset(ap->cur,NV_RDONLY);
1187 			nv_delete(ap->cur,ap->header.table,0);
1188 			ap->cur = 0;
1189 		}
1190 		return((void*)ap);
1191 	    case NV_AFREE:
1192 		ap->pos = 0;
1193 		if(ap->header.scope)
1194 		{
1195 			ap->header.table = dtview(ap->header.table,(Dt_t*)0);
1196 			dtclose(ap->header.scope);
1197 			ap->header.scope = 0;
1198 		}
1199 		else
1200 			dtclose(ap->header.table);
1201 		return((void*)ap);
1202 	    case NV_ANEXT:
1203 		if(!ap->pos)
1204 		{
1205 			if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
1206 			{
1207 				ap->header.scope = dtvnext(ap->header.table);
1208 				ap->header.table->view = 0;
1209 			}
1210 			if(!(ap->pos=ap->cur))
1211 				ap->pos = (Namval_t*)dtfirst(ap->header.table);
1212 		}
1213 		else
1214 			ap->pos = ap->nextpos;
1215 		for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
1216 		{
1217 			ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
1218 			if(ap->cur->nvalue.cp)
1219 			{
1220 				if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
1221 					continue;
1222 				return((void*)ap);
1223 			}
1224 		}
1225 		if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
1226 		{
1227 			ap->header.table->view = (Dt_t*)ap->header.scope;
1228 			ap->header.scope = ap->header.table;
1229 		}
1230 		return(NIL(void*));
1231 	    case NV_ASETSUB:
1232 		ap->cur = (Namval_t*)sp;
1233 		return((void*)ap->cur);
1234 	    case NV_ACURRENT:
1235 		if(ap->cur)
1236 			ap->cur->nvenv = (char*)np;
1237 		return((void*)ap->cur);
1238 	    case NV_ANAME:
1239 		if(ap->cur)
1240 			return((void*)ap->cur->nvname);
1241 		return(NIL(void*));
1242 	    default:
1243 		if(sp)
1244 		{
1245 			Namval_t *mp=0;
1246 			ap->cur = 0;
1247 			if(sp==(char*)np)
1248 				return(0);
1249 			type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
1250 			if(mode)
1251 				mode = NV_ADD|HASH_NOSCOPE;
1252 			else if(ap->header.nelem&ARRAY_NOSCOPE)
1253 				mode = HASH_NOSCOPE;
1254 			if(*sp==0 && (mode&NV_ADD))
1255 				sfprintf(sfstderr,"adding empty subscript\n");
1256 			if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
1257 				ap->cur = mp;
1258 			if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
1259 			{
1260 				nv_onattr(mp,type);
1261 				mp->nvenv = (char*)np;
1262 				if((mode&NV_ADD) && nv_type(np))
1263 					nv_arraychild(np,mp,0);
1264 				if(sh.subshell)
1265 					np = sh_assignok(np,1);
1266 				if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
1267 					ap->header.nelem++;
1268 				if(nv_isnull(mp))
1269 				{
1270 					if(ap->header.nelem&ARRAY_TREE)
1271 						nv_setvtree(mp);
1272 					mp->nvalue.cp = Empty;
1273 				}
1274 			}
1275 			else if(ap->header.nelem&ARRAY_SCAN)
1276 			{
1277 				Namval_t fake;
1278 				fake.nvname = (char*)sp;
1279 				ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
1280 				ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
1281 			}
1282 			np = mp;
1283 			if(ap->pos != np && !(ap->header.nelem&ARRAY_SCAN))
1284 				ap->pos = 0;
1285 			ap->cur = np;
1286 		}
1287 		if(ap->cur)
1288 			return((void*)(&ap->cur->nvalue));
1289 		else
1290 			return((void*)(&ap->cur));
1291 	}
1292 }
1293 
1294 /*
1295  * Assign values to an array
1296  */
1297 void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
1298 {
1299 	int arg0=0;
1300 	struct index_array *ap=0,*aq;
1301 	if(nv_isarray(np))
1302 	{
1303 		ap = (struct index_array*)nv_arrayptr(np);
1304 		if(ap && is_associative(ap))
1305 			errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
1306 	}
1307 	if(append)
1308 	{
1309 		if(ap)
1310 		{
1311 			if(!(aq = (struct index_array*)ap->header.scope))
1312 				aq = ap;
1313 			arg0 = ap->maxi;
1314 			while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
1315 			arg0++;
1316 		}
1317 		else if(!nv_isnull(np))
1318 			arg0=1;
1319 	}
1320 	while(--argc >= 0)
1321 	{
1322 		nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
1323 		nv_putval(np,argv[argc],0);
1324 	}
1325 }
1326 
1327