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