xref: /titanic_52/usr/src/contrib/ast/src/cmd/ksh93/sh/array.c (revision 906afcb89d0412cc073b95c2d701a804a8cdb62c)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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	11
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 #if SHOPT_FIXEDARRAY
62    struct fixed_array
63    {
64 	unsigned char	ndim;
65 	unsigned char	dim;
66 	unsigned char	level;
67 	unsigned char	ptr;
68 	short		size;
69 	int		nelem;
70 	int		curi;
71 	int		*max;
72 	int		*incr;
73 	int		*cur;
74 	char		*data;
75    };
76 #  define array_fixed_data(ap)	((ap)?((struct fixed_array*)((ap)->fixed))->data:0)
77    static void array_fixed_setdata(Namval_t*,Namarr_t*,struct fixed_array*);
78 #endif /* SHOPT_FIXEDARRAY */
79 
80 static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
81 {
82 	Namarr_t *aq;
83 #if SHOPT_FIXEDARRAY
84 	struct fixed_array *fp;
85 #endif /* SHOPT_FIXEDARRAY */
86 	struct index_array *ar;
87 	size_t size = ap->hdr.dsize;
88 	if(size==0)
89 		size = ap->hdr.disc->dsize;
90         if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
91                 return(0);
92         memcpy(aq,ap,size);
93 	aq->hdr.nofree &= ~1;
94         aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
95 	if(is_associative(aq))
96 	{
97 		aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
98 		dtview((Dt_t*)aq->scope,aq->table);
99 		aq->table = (Dt_t*)aq->scope;
100 		return(aq);
101 	}
102 #if SHOPT_FIXEDARRAY
103 	else if(fp = (struct fixed_array*)ap->fixed)
104 	{
105 		aq->scope = (void*)ap;
106 		fp = (struct fixed_array*)(aq+1);
107 		aq->fixed = (void*)fp;
108 		fp->max = (int*)(fp+1);
109 		fp->incr = fp->max+fp->ndim;
110 		fp->cur = fp->incr+fp->ndim;
111 		return(aq);
112 	}
113 #endif /* SHOPT_FIXEDARRAY */
114 	aq->scope = (void*)ap;
115 	ar = (struct index_array*)aq;
116 	memset(ar->val, 0, ar->maxi*sizeof(char*));
117 	ar->bits =  (unsigned char*)&ar->val[ar->maxi];
118 	return(aq);
119 }
120 
121 static int array_unscope(Namval_t *np,Namarr_t *ap)
122 {
123 	Namfun_t *fp;
124 	if(!ap->scope)
125 		return(0);
126 	if(is_associative(ap))
127 		(*ap->fun)(np, NIL(char*), NV_AFREE);
128 	if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
129 		free((void*)fp);
130 	nv_delete(np,(Dt_t*)0,0);
131 	return(1);
132 }
133 
134 static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
135 {
136 	((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
137 }
138 
139 static int array_covered(Namval_t *np, struct index_array *ap)
140 {
141 	struct index_array *aq = (struct index_array*)ap->header.scope;
142 	if(!ap->header.fun && aq)
143 #if SHOPT_FIXEDARRAY
144 		return (ap->header.fixed || ((ap->cur<aq->maxi) && aq->val[ap->cur].cp));
145 #else
146 		return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
147 #endif /* SHOPT_FIXEDARRAY */
148 	return(0);
149 }
150 
151 /*
152  * replace discipline with new one
153  */
154 static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
155 {
156 	register Namfun_t **fp = &np->nvfun;
157 	while(*fp && *fp!= &old->header.hdr)
158 		fp = &((*fp)->next);
159 	if(*fp)
160 	{
161 		new->header.hdr.next = (*fp)->next;
162 		*fp = &new->header.hdr;
163 	}
164 	else sfprintf(sfstderr,"discipline not replaced\n");
165 }
166 
167 /*
168  *   Calculate the amount of space to be allocated to hold an
169  *   indexed array into which <maxi> is a legal index.  The number of
170  *   elements that will actually fit into the array (> <maxi>
171  *   but <= ARRAY_MAX) is returned.
172  *
173  */
174 static int	arsize(struct index_array *ap, register int maxi)
175 {
176 	if(ap && maxi < 2*ap->maxi)
177 		maxi = 2*ap->maxi;
178 	maxi = roundof(maxi,ARRAY_INCR);
179 	return (maxi>ARRAY_MAX?ARRAY_MAX:maxi);
180 }
181 
182 static struct index_array *array_grow(Namval_t*, struct index_array*,int);
183 
184 /* return index of highest element of an array */
185 int array_maxindex(Namval_t *np)
186 {
187 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
188 	register int i = ap->maxi;
189 	if(is_associative(ap))
190 		return(-1);
191 	while(i>0 && ap->val[--i].cp==0);
192 	return(i+1);
193 }
194 
195 static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update)
196 {
197 	register struct index_array *ap = (struct index_array*)arp;
198 	register union Value *up;
199 #if SHOPT_FIXEDARRAY
200 	struct fixed_array *fp;
201 #endif /* SHOPT_FIXEDARRAY */
202 	int	nofree=0;
203 	if(!arp)
204 		return(&np->nvalue);
205 	if(is_associative(ap))
206 	{
207 		Namval_t	*mp;
208 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
209 		if(mp)
210 		{
211 			nofree = nv_isattr(mp,NV_NOFREE);
212 			up = &mp->nvalue;
213 		}
214 		else
215 			return((union Value*)((*arp->fun)(np,NIL(char*),0)));
216 	}
217 #if SHOPT_FIXEDARRAY
218 	else if(fp = (struct fixed_array*)arp->fixed)
219 	{
220 		if(!fp->data)
221 			array_fixed_setdata(np,arp,fp);
222 		up = &np->nvalue;
223 		if(fp->ptr)
224 			up->cp =  *(((char**)fp->data)+fp->curi);
225 		else
226 			up->cp = fp->data+fp->size*fp->curi;
227         }
228 #endif /* SHOPT_FIXEDARRAY */
229 	else
230 	{
231 		if(ap->cur >= ap->maxi)
232 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
233 		up = &(ap->val[ap->cur]);
234 		nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
235 	}
236 	if(update)
237 	{
238 		if(nofree)
239 			nv_onattr(np,NV_NOFREE);
240 		else
241 			nv_offattr(np,NV_NOFREE);
242 	}
243 	return(up);
244 }
245 
246 int nv_arrayisset(Namval_t *np, Namarr_t *arp)
247 {
248 	register struct index_array *ap = (struct index_array*)arp;
249 	union Value *up;
250 	if(is_associative(ap))
251 		return((np = nv_opensub(np)) && !nv_isnull(np));
252 	if(ap->cur >= ap->maxi)
253 		return(0);
254 	up = &(ap->val[ap->cur]);
255 	if(up->cp==Empty)
256 	{
257 		Namfun_t *fp = &arp->hdr;
258 		for(fp=fp->next; fp; fp = fp->next)
259 		{
260 			if(fp->disc && (fp->disc->getnum || fp->disc->getval))
261 				return(1);
262 		}
263 	}
264 	return(up->cp && up->cp!=Empty);
265 }
266 
267 /*
268  * Get the Value pointer for an array.
269  * Delete space as necessary if flag is ARRAY_DELETE
270  * After the lookup is done the last @ or * subscript is incremented
271  */
272 static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
273 {
274 	register struct index_array *ap = (struct index_array*)arp;
275 	register union Value	*up;
276 	Namval_t		*mp;
277 	int			wasundef;
278 #if SHOPT_FIXEDARRAY
279 	struct fixed_array	*fp=(struct fixed_array*)(arp->fixed);
280 #endif /* SHOPT_FIXEDARRAY */
281 	if(flag&ARRAY_LOOKUP)
282 		ap->header.nelem &= ~ARRAY_NOSCOPE;
283 	else
284 		ap->header.nelem |= ARRAY_NOSCOPE;
285 	if(wasundef = ap->header.nelem&ARRAY_UNDEF)
286 	{
287 		ap->header.nelem &= ~ARRAY_UNDEF;
288 		/* delete array is the same as delete array[@] */
289 		if(flag&ARRAY_DELETE)
290 		{
291 #if SHOPT_FIXEDARRAY
292 			nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE|(ap->header.fixed?(ARRAY_UNDEF|ARRAY_FIXED):0));
293 #else
294 			nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
295 #endif /* SHOPT_FIXEDARRAY */
296 			ap->header.nelem |= ARRAY_SCAN;
297 		}
298 		else /* same as array[0] */
299 		{
300 			if(is_associative(ap))
301 				(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
302 #if SHOPT_FIXEDARRAY
303 			else if(fp)
304 			{
305 				int n=fp->ndim;
306 				fp->curi = 0;
307 				while(--n>=0)
308 					fp->cur[n] = 0;
309 			}
310 #endif /* SHOPT_FIXEDARRAY */
311 			else
312 				ap->cur = 0;
313 		}
314 	}
315 	if(is_associative(ap))
316 	{
317 		mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
318 		if(!mp)
319 			up = (union Value*)&mp;
320 		else if(nv_isarray(mp))
321 		{
322 			if(wasundef)
323 				nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
324 			return(mp);
325 		}
326 		else
327 		{
328 			up =  &mp->nvalue;
329 			if(nv_isvtree(mp))
330 			{
331 				if(!up->cp && flag==ARRAY_ASSIGN)
332 				{
333 					nv_arraychild(np,mp,0);
334 					ap->header.nelem++;
335 				}
336 				return(mp);
337 			}
338 		}
339 	}
340 #if SHOPT_FIXEDARRAY
341 	else if(fp)
342 	{
343 		char	*data = array_fixed_data((Namarr_t*)ap->header.scope);
344 		if(flag==ARRAY_ASSIGN && data==fp->data)
345 		{
346 			if(data)
347 			{
348 				fp->data = (char*)malloc(fp->nelem*fp->size);
349 				memcpy(fp->data,data,fp->nelem*fp->size);
350 			}
351 			else
352 				array_fixed_setdata(np,&ap->header,fp);
353 		}
354 		if(fp->ptr)
355 		{
356 			if(!fp->data)
357 				array_fixed_setdata(np,&ap->header,fp);
358 			np->nvalue.cp =  *(((char**)fp->data)+fp->curi);
359 		}
360 		else
361 			np->nvalue.cp =  fp->data+fp->size*fp->curi;
362 		return(np);
363 	}
364 #endif /* SHOPT_FIXEDARRAY */
365 	else
366 	{
367 		if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
368 			ap = array_grow(np, ap, (int)ap->cur);
369 		if(ap->cur>=ap->maxi)
370 			errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
371 		up = &(ap->val[ap->cur]);
372 		if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
373 		{
374 			char *cp;
375 			if(!ap->header.table)
376 				ap->header.table = dtopen(&_Nvdisc,Dtoset);
377 			sfprintf(sh.strbuf,"%d",ap->cur);
378 			cp = sfstruse(sh.strbuf);
379 			mp = nv_search(cp, ap->header.table, NV_ADD);
380 			mp->nvenv = (char*)np;
381 			nv_arraychild(np,mp,0);
382 		}
383 		if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
384 		{
385 			if(wasundef && nv_isarray(up->np))
386 				nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
387 			return(up->np);
388 		}
389 	}
390 	np->nvalue.cp = up->cp;
391 	if(!up->cp)
392 	{
393 			char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np);
394 		if(flag!=ARRAY_ASSIGN)
395 			return(xp && xp!=(char*)np?np:0);
396 		if(!array_covered(np,ap))
397 			ap->header.nelem++;
398 	}
399 	return(np);
400 }
401 
402 #if SHOPT_TYPEDEF
403 int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
404 {
405 	Namval_t	*nq;
406 	char		*av[2];
407 	int		rdonly = nv_isattr(np,NV_RDONLY);
408 	int		xtrace = sh_isoption(SH_XTRACE);
409 	Namarr_t	*ap = nv_arrayptr(np);
410 	av[1] = 0;
411 	sh.last_table = 0;
412 	if(!ap->table)
413 		ap->table = dtopen(&_Nvdisc,Dtoset);
414 	if(nq = nv_search(sub, ap->table, NV_ADD))
415 	{
416 		if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
417 			_nv_unset(nq,NV_RDONLY);
418 		nv_arraychild(np,nq,0);
419 		if(!nv_isattr(tp,NV_BINARY))
420 		{
421 			sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
422 			av[0] = strdup(sfstruse(sh.strbuf));
423 		}
424 		if(!nv_clone(tp,nq,flags|NV_NOFREE))
425 			return(0);
426 		ap->nelem |= ARRAY_SCAN;
427 		if(!rdonly)
428 			nv_offattr(nq,NV_RDONLY);
429 		if(!nv_isattr(tp,NV_BINARY))
430 		{
431 			if(xtrace)
432 				sh_offoption(SH_XTRACE);
433 			ap->nelem &= ~ARRAY_SCAN;
434 			sh_eval(sh_sfeval(av),0);
435 			ap->nelem |= ARRAY_SCAN;
436 			free((void*)av[0]);
437 			if(xtrace)
438 				sh_onoption(SH_XTRACE);
439 		}
440 		return(1);
441 	}
442 	return(0);
443 }
444 #endif /* SHOPT_TYPEDEF */
445 
446 
447 static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
448 {
449 	Namarr_t		*ap = (Namarr_t*)fp;
450 	Namval_t		*nq, *mq;
451 	char			*name, *sub=0;
452 	int			nelem, skipped=0;
453 	Dt_t			*otable=ap->table;
454 	struct index_array	*aq = (struct index_array*)ap, *ar;
455 	Shell_t			*shp = sh_getinterp();
456 	if(flags&NV_MOVE)
457 	{
458 		if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
459 		{
460 			do
461 			{
462 				if(nq=nv_opensub(np))
463 					nq->nvenv = (void*)mp;
464 			}
465 			while(nv_nextsub(np));
466 		}
467 		return(fp);
468 	}
469 	nelem = ap->nelem;
470 	if(nelem&ARRAY_NOCLONE)
471 		return(0);
472 	if((flags&NV_TYPE) && !ap->scope)
473 	{
474 		ap = array_scope(np,ap,flags);
475 		return(&ap->hdr);
476 	}
477 	ap = (Namarr_t*)nv_clone_disc(fp,0);
478 	if(flags&NV_COMVAR)
479 	{
480 		ap->scope = 0;
481 		ap->nelem = 0;
482 		sh.prev_table = sh.last_table;
483 		sh.prev_root = sh.last_root;
484 	}
485 	if(ap->table)
486 	{
487 		ap->table = dtopen(&_Nvdisc,Dtoset);
488 		if(ap->scope && !(flags&NV_COMVAR))
489 		{
490 			ap->scope = ap->table;
491 			dtview(ap->table, otable->view);
492 		}
493 	}
494 	mp->nvfun = (Namfun_t*)ap;
495 	mp->nvflag &= NV_MINIMAL;
496 	mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
497 	if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
498 		sub = strdup(sub);
499 	ar = (struct index_array*)ap;
500 	if(!is_associative(ap))
501 		ar->bits = (unsigned char*)&ar->val[ar->maxi];
502 	if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
503 	{
504 		if(ap->fun)
505 			(*ap->fun)(np,(char*)np,0);
506 		skipped=1;
507 		goto skip;
508 	}
509 	do
510 	{
511 		name = nv_getsub(np);
512 		nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
513 		mq = 0;
514 		if(nq=nv_opensub(np))
515 			mq = nv_search(name,ap->table,NV_ADD);
516 		if(nq && (((flags&NV_COMVAR) && nv_isvtree(nq)) || nv_isarray(nq)))
517 		{
518 			mq->nvalue.cp = 0;
519 			if(!is_associative(ap))
520 				ar->val[ar->cur].np = mq;
521 			nv_clone(nq,mq,flags);
522 		}
523 		else if(flags&NV_ARRAY)
524 		{
525 			if((flags&NV_NOFREE) && !is_associative(ap))
526 				array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
527 			else if(nq && (flags&NV_NOFREE))
528 			{
529 				mq->nvalue = nq->nvalue;
530 				nv_onattr(nq,NV_NOFREE);
531 			}
532 		}
533 		else if(nv_isattr(np,NV_INTEGER))
534 		{
535 			Sfdouble_t d= nv_getnum(np);
536 			if(!is_associative(ap))
537 				ar->val[ar->cur].cp = 0;
538 			nv_putval(mp,(char*)&d,NV_LDOUBLE);
539 		}
540 		else
541 		{
542 			if(!is_associative(ap))
543 				ar->val[ar->cur].cp = 0;
544 			nv_putval(mp,nv_getval(np),NV_RDONLY);
545 		}
546 		aq->header.nelem |= ARRAY_NOSCOPE;
547 	}
548 	while(nv_nextsub(np));
549 skip:
550 	if(sub)
551 	{
552 		if(!skipped)
553 			nv_putsub(np,sub,0L);
554 		free((void*)sub);
555 	}
556 	aq->header.nelem = ap->nelem = nelem;
557 	return(&ap->hdr);
558 }
559 
560 static char *array_getval(Namval_t *np, Namfun_t *disc)
561 {
562 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
563 	register Namval_t *mp;
564 	register char	  *cp=0;
565 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
566 	{
567 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
568 		{
569 			array_syncsub(aq,ap);
570 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
571 				return(nv_getv(np,&aq->hdr));
572 		}
573 		if(mp)
574 		{
575 			cp = nv_getval(mp);
576 			nv_offattr(mp,NV_EXPORT);
577 		}
578 		return(cp);
579 	}
580 #if SHOPT_FIXEDARRAY
581 	if(ap->fixed && nv_isattr(np,NV_INT16P) == NV_INT16)
582 		np->nvalue.s = *np->nvalue.sp;
583 #endif /* SHOPT_FIXEDARRAY */
584 	return(nv_getv(np,&ap->hdr));
585 }
586 
587 static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
588 {
589 	register Namarr_t *aq,*ap = (Namarr_t*)disc;
590 	register Namval_t *mp;
591 	if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
592 	{
593 		if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
594 		{
595 			array_syncsub(aq,ap);
596 			if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
597 				return(nv_getn(np,&aq->hdr));
598 		}
599 		return(mp?nv_getnum(mp):0);
600 	}
601 	return(nv_getn(np,&ap->hdr));
602 }
603 
604 static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
605 {
606 	register Namarr_t	*ap = (Namarr_t*)dp;
607 	register union Value	*up;
608 	register Namval_t	*mp;
609 	register struct index_array *aq = (struct index_array*)ap;
610 	int			scan,nofree = nv_isattr(np,NV_NOFREE);
611 #if SHOPT_FIXEDARRAY
612 	struct fixed_array	*fp;
613 #endif /* SHOPT_FIXEDARRAY */
614 	do
615 	{
616 		int xfree = (ap->fixed||is_associative(ap))?0:array_isbit(aq->bits,aq->cur,ARRAY_NOFREE);
617 		mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
618 		scan = ap->nelem&ARRAY_SCAN;
619 		if(mp && mp!=np)
620 		{
621 			if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp) && !(ap->nelem&ARRAY_TREE))
622 
623 			{
624 				if(!nv_isattr(np,NV_NOFREE))
625 					_nv_unset(mp,flags&NV_RDONLY);
626 				array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
627 				aq->val[aq->cur].cp = 0;
628 				if(!nv_isattr(mp,NV_NOFREE))
629 					nv_delete(mp,ap->table,0);
630 				goto skip;
631 			}
632 			if(!xfree)
633 				nv_putval(mp, string, flags);
634 			if(string)
635 			{
636 #if SHOPT_TYPEDEF
637 				if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
638 					nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
639 #endif /* SHOPT_TYPEDEF */
640 				continue;
641 			}
642 			ap->nelem |= scan;
643 		}
644 		if(!string)
645 		{
646 			if(mp)
647 			{
648 				if(is_associative(ap))
649 				{
650 					(*ap->fun)(np,NIL(char*),NV_ADELETE);
651 					np->nvalue.cp = 0;
652 				}
653 				else
654 				{
655 					if(mp!=np)
656 					{
657 						array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
658 						aq->val[aq->cur].cp = 0;
659 						if(!xfree)
660 							nv_delete(mp,ap->table,0);
661 					}
662 					if(!array_covered(np,(struct index_array*)ap))
663 					{
664 						if(array_elem(ap))
665 							ap->nelem--;
666 					}
667 #if SHOPT_FIXEDARRAY
668 					else if(fp=(struct fixed_array*)ap->fixed)
669 					{
670 						char *data = array_fixed_data((Namarr_t*)ap->scope);
671 						int n = fp->size*fp->curi;
672 						if(data)
673 						{
674 							memcpy(fp->data+n,data+n,fp->size);
675 							continue;
676 						}
677 					}
678 #endif /* SHOPT_FIXEDARRAY */
679 				}
680 			}
681 			if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN))
682 			{
683 				if(is_associative(ap))
684 					(*ap->fun)(np, NIL(char*), NV_AFREE);
685 				else if(ap->table)
686 					dtclose(ap->table);
687 				nv_offattr(np,NV_ARRAY);
688 			}
689 			if(!mp || mp!=np || is_associative(ap))
690 				continue;
691 		}
692 	skip:
693 		/* prevent empty string from being deleted */
694 		up = array_getup(np,ap,!nofree);
695 		if(up->cp ==  Empty)
696 			up->cp = 0;
697 #if SHOPT_FIXEDARRAY
698 		if(nv_isarray(np) && !ap->fixed)
699 #else
700 		if(nv_isarray(np))
701 #endif /* SHOPT_FIXEDARRAY */
702 			np->nvalue.up = up;
703 		nv_putv(np,string,flags,&ap->hdr);
704 #if SHOPT_FIXEDARRAY
705 		if(fp = (struct fixed_array*)ap->fixed)
706 		{
707 			if(fp->ptr)
708 			{
709 				char **cp = (char**)fp->data;
710 				cp[fp->curi] = (char*)(np->nvalue.cp?np->nvalue.cp:Empty);
711 			}
712 		}
713 		else
714 #endif /* SHOPT_FIXEDARRAY */
715 		if(!is_associative(ap))
716 		{
717 			if(string)
718 				array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
719 			else if(mp==np)
720 				aq->val[aq->cur].cp = 0;
721 		}
722 #if SHOPT_TYPEDEF
723 		if(string && ap->hdr.type && nv_isvtree(np))
724 			nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
725 #endif /* SHOPT_TYPEDEF */
726 	}
727 	while(!string && nv_nextsub(np));
728 	if(ap)
729 		ap->nelem &= ~ARRAY_NOSCOPE;
730 	if(nofree)
731 		nv_onattr(np,NV_NOFREE);
732 	else
733 		nv_offattr(np,NV_NOFREE);
734 	if(!string && !nv_isattr(np,NV_ARRAY))
735 	{
736 		Namfun_t *nfp;
737 #if SHOPT_FIXEDARRAY
738 		char	*data = array_fixed_data((Namarr_t*)ap->scope);
739 		fp = (struct fixed_array*)ap->fixed;
740 		if(fp && (!ap->scope || data!=fp->data))
741 		{
742 			if(fp->ptr)
743 			{
744 				int n = fp->nelem;
745 				char **cp = (char**)fp->data;
746 				while(n-->0)
747 				{
748 					if(cp && *cp!=Empty)
749 						free(*cp);
750 					cp++;
751 				}
752 			}
753 			free((void*)fp->data);
754 			if(data)
755 				fp->data = data;
756 		}
757 		else
758 #endif /* SHOPT_FIXEDARRAY */
759 		if(!is_associative(ap) && aq->xp)
760 		{
761 			_nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
762 			free((void*)aq->xp);
763 		}
764 		if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
765 			free((void*)nfp);
766 		if(!nv_isnull(np))
767 		{
768 			if(!np->nvfun)
769 				nv_onattr(np,NV_NOFREE);
770 			_nv_unset(np,flags);
771 		}
772 		else
773 			nv_offattr(np,NV_NOFREE);
774 		if(np->nvalue.cp==Empty)
775 			np->nvalue.cp = 0;
776 	}
777 	if(!string && (flags&NV_TYPE))
778 		array_unscope(np,ap);
779 }
780 
781 static const Namdisc_t array_disc =
782 {
783 	sizeof(Namarr_t),
784 	array_putval,
785 	array_getval,
786 	array_getnum,
787 	0,
788 	0,
789 	array_clone
790 };
791 
792 static void array_copytree(Namval_t *np, Namval_t *mp)
793 {
794 	Namfun_t	*fp = nv_disc(np,NULL,NV_POP);
795 	nv_offattr(np,NV_ARRAY);
796 	nv_clone(np,mp,0);
797 	if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE))
798 		free((void*)np->nvalue.cp);
799 	np->nvalue.cp = 0;
800 	np->nvalue.up = &mp->nvalue;
801 	fp->nofree  &= ~1;
802 	nv_disc(np,(Namfun_t*)fp, NV_FIRST);
803 	fp->nofree |= 1;
804 	nv_onattr(np,NV_ARRAY);
805 	mp->nvenv = (char*)np;
806 }
807 
808 /*
809  *        Increase the size of the indexed array of elements in <arp>
810  *        so that <maxi> is a legal index.  If <arp> is 0, an array
811  *        of the required size is allocated.  A pointer to the
812  *        allocated Namarr_t structure is returned.
813  *        <maxi> becomes the current index of the array.
814  */
815 static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
816 {
817 	register struct index_array *ap;
818 	register int i;
819 	register int newsize = arsize(arp,maxi+1);
820 	if (maxi >= ARRAY_MAX)
821 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
822 	i = (newsize-1)*sizeof(union Value*)+newsize;
823 	ap = new_of(struct index_array,i);
824 	memset((void*)ap,0,sizeof(*ap)+i);
825 	ap->maxi = newsize;
826 	ap->cur = maxi;
827 	ap->bits =  (unsigned char*)&ap->val[newsize];
828 	memset(ap->bits, 0, newsize);
829 	if(arp)
830 	{
831 		ap->header = arp->header;
832 		ap->header.hdr.dsize = sizeof(*ap) + i;
833 		for(i=0;i < arp->maxi;i++)
834 		{
835 			ap->bits[i] = arp->bits[i];
836 			ap->val[i].cp = arp->val[i].cp;
837 		}
838 		memcpy(ap->bits, arp->bits, arp->maxi);
839 		array_setptr(np,arp,ap);
840 		free((void*)arp);
841 	}
842 	else
843 	{
844 		Namval_t *mp=0;
845 		ap->header.hdr.dsize = sizeof(*ap) + i;
846 		i = 0;
847 		ap->header.fun = 0;
848 		if((nv_isnull(np)||np->nvalue.cp==Empty) && nv_isattr(np,NV_NOFREE))
849 		{
850 			i = ARRAY_TREE;
851 			nv_offattr(np,NV_NOFREE);
852 		}
853 		if(np->nvalue.cp==Empty)
854 			np->nvalue.cp=0;
855 		if(nv_hasdisc(np,&array_disc) || (nv_type(np) && nv_isvtree(np)))
856 		{
857 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
858 			mp = nv_search("0", ap->header.table,NV_ADD);
859 			if(mp && nv_isnull(mp))
860 			{
861 				Namfun_t *fp;
862 				ap->val[0].np = mp;
863 				array_setbit(ap->bits,0,ARRAY_CHILD);
864 				for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
865 				if(fp && fp->disc && fp->disc->readf)
866 					(*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
867 				i++;
868 			}
869 		}
870 		else
871 		if((ap->val[0].cp=np->nvalue.cp))
872 			i++;
873 		else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np))
874 		{
875 			Sfdouble_t d= nv_getnum(np);
876 			i++;
877 		}
878 		ap->header.nelem = i;
879 		ap->header.hdr.disc = &array_disc;
880 		nv_disc(np,(Namfun_t*)ap, NV_FIRST);
881 		nv_onattr(np,NV_ARRAY);
882 		if(mp)
883 		{
884 			array_copytree(np,mp);
885 			ap->header.hdr.nofree &= ~1;
886 		}
887 	}
888 	for(;i < newsize;i++)
889 		ap->val[i].cp = 0;
890 	return(ap);
891 }
892 
893 int nv_atypeindex(Namval_t *np, const char *tname)
894 {
895 	Namval_t	*tp;
896 	int		offset = staktell();
897 	size_t		n = strlen(tname)-1;
898 	sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
899 	tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
900 	stakseek(offset);
901 	if(tp)
902 	{
903 		struct index_array *ap = (struct index_array*)nv_arrayptr(np);
904 		if(!nv_hasdisc(tp,&ENUM_disc))
905 			errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
906 		if(!ap)
907 			ap = array_grow(np,ap,1);
908 		ap->xp = calloc(NV_MINSZ,1);
909 		np = nv_namptr(ap->xp,0);
910 		np->nvname = tp->nvname;
911 		nv_onattr(np,NV_MINIMAL);
912 		nv_clone(tp,np,NV_NOFREE);
913 		nv_offattr(np,NV_RDONLY);
914 		return(1);
915 	}
916 	errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
917 	return(0);
918 }
919 
920 Namarr_t *nv_arrayptr(register Namval_t *np)
921 {
922 	if(nv_isattr(np,NV_ARRAY))
923 		return((Namarr_t*)nv_hasdisc(np, &array_disc));
924 	return(0);
925 }
926 
927 /*
928  * Verify that argument is an indexed array and convert to associative,
929  * freeing relevant storage
930  */
931 static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
932 {
933 	register Namarr_t *ap;
934 	char numbuff[NUMSIZE+1];
935 	unsigned dot, digit, n;
936 	union Value *up;
937 	struct index_array *save_ap;
938 	register char *string_index=&numbuff[NUMSIZE];
939 	numbuff[NUMSIZE]='\0';
940 
941 	if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
942 		return(NIL(Namarr_t*));
943 
944 	nv_stack(np,&ap->hdr);
945 	save_ap = (struct index_array*)nv_stack(np,0);
946 	ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
947 	ap->nelem = 0;
948 	ap->fun = fun;
949 	nv_onattr(np,NV_ARRAY);
950 
951 	for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
952 	{
953 		if(save_ap->val[dot].cp)
954 		{
955 			if ((digit = dot)== 0)
956 				*--string_index = '0';
957 			else while( n = digit )
958 			{
959 				digit /= 10;
960 				*--string_index = '0' + (n-10*digit);
961 			}
962 			nv_putsub(np, string_index, ARRAY_ADD);
963 			up = (union Value*)((*ap->fun)(np,NIL(char*),0));
964 			up->cp = save_ap->val[dot].cp;
965 			save_ap->val[dot].cp = 0;
966 		}
967 		string_index = &numbuff[NUMSIZE];
968 	}
969 	free((void*)save_ap);
970 	return(ap);
971 }
972 
973 /*
974  * set the associative array processing method for node <np> to <fun>
975  * The array pointer is returned if sucessful.
976  */
977 Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
978 {
979 	register Namarr_t *ap;
980 	char		*value=0;
981 	Namfun_t	*fp;
982 	int		nelem = 0;
983 	if(fun && (ap = nv_arrayptr(np)))
984 	{
985 		/*
986 		 * if it's already an indexed array, convert to
987 		 * associative structure
988 		 */
989 		if(!is_associative(ap))
990 			ap = nv_changearray(np, fun);
991 		return(ap);
992 	}
993 	if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
994 	{
995 		nelem = ARRAY_TREE;
996 		nv_offattr(np,NV_NOFREE);
997 	}
998 	if(!(fp=nv_isvtree(np)))
999 		value = nv_getval(np);
1000 	if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
1001 	{
1002 		/* check for preexisting initialization and save */
1003 		ap->nelem = nelem;
1004 		ap->fun = fun;
1005 		nv_onattr(np,NV_ARRAY);
1006 		if(fp || (value && value!=Empty))
1007 		{
1008 			nv_putsub(np, "0", ARRAY_ADD);
1009 			if(value)
1010 				nv_putval(np, value, 0);
1011 			else
1012 			{
1013 				Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
1014 				array_copytree(np,mp);
1015 			}
1016 		}
1017 		return(ap);
1018 	}
1019 	return(NIL(Namarr_t*));
1020 }
1021 
1022 /*
1023  * move parent subscript into child
1024  */
1025 Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
1026 {
1027 	Namfun_t		*fp;
1028 	register Namarr_t	*ap = nv_arrayptr(np);
1029 	union Value		*up;
1030 	Namval_t		*tp;
1031 	if(!nq)
1032 		return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
1033 	if(!ap)
1034 	{
1035 		nv_putsub(np, NIL(char*), ARRAY_FILL);
1036 		ap = nv_arrayptr(np);
1037 	}
1038 	if(!(up = array_getup(np,ap,0)))
1039 		return((Namval_t*)0);
1040 	np->nvalue.cp = up->cp;
1041 	if((tp=nv_type(np)) || c)
1042 	{
1043 		ap->nelem |= ARRAY_NOCLONE;
1044 		nq->nvenv = (char*)np;
1045 		if(c=='t')
1046 			nv_clone(tp,nq, 0);
1047 		else
1048 			nv_clone(np, nq, NV_NODISC);
1049 		nv_offattr(nq,NV_ARRAY);
1050 		ap->nelem &= ~ARRAY_NOCLONE;
1051 	}
1052 	nq->nvenv = (char*)np;
1053 	if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
1054 		free((void*)fp);
1055 	if(!ap->fun)
1056 	{
1057 		struct index_array *aq = (struct index_array*)ap;
1058 		array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
1059 		if(c=='.' && !nq->nvalue.cp)
1060 			ap->nelem++;
1061 		up->np = nq;
1062 	}
1063 	if(c=='.')
1064 		nv_setvtree(nq);
1065 	return(nq);
1066 }
1067 
1068 /*
1069  * This routine sets subscript of <np> to the next element, if any.
1070  * The return value is zero, if there are no more elements
1071  * Otherwise, 1 is returned.
1072  */
1073 int nv_nextsub(Namval_t *np)
1074 {
1075 	register struct index_array	*ap = (struct index_array*)nv_arrayptr(np);
1076 	register unsigned		dot;
1077 	struct index_array		*aq=0, *ar=0;
1078 #if SHOPT_FIXEDARRAY
1079 	struct fixed_array		*fp;
1080 #endif /* SHOPT_FIXEDARRAY */
1081 	if(!ap || !(ap->header.nelem&ARRAY_SCAN))
1082 		return(0);
1083 	if(is_associative(ap))
1084 	{
1085 		if((*ap->header.fun)(np,NIL(char*),NV_ANEXT))
1086 			return(1);
1087 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
1088 		return(0);
1089 	}
1090 #if SHOPT_FIXEDARRAY
1091 	else if(fp = (struct fixed_array*)ap->header.fixed)
1092 	{
1093 		if(ap->header.nelem&ARRAY_FIXED)
1094 		{
1095 			while(++fp->curi < fp->nelem)
1096 			{
1097 				nv_putsub(np,0,fp->curi|ARRAY_FIXED|ARRAY_SCAN);
1098 				if(fp->ptr && *(((char**)fp->data)+fp->curi))
1099 				return(1);
1100 			}
1101 			ap->header.nelem &= ~ARRAY_FIXED;
1102 			return(0);
1103 		}
1104 		dot = fp->dim;
1105 		if((fp->cur[dot]+1) < fp->max[dot])
1106 		{
1107 			fp->cur[dot]++;
1108 			for(fp->curi=0,dot=0; dot < fp->ndim; dot++)
1109 				fp->curi +=  fp->incr[dot]*fp->cur[dot];
1110 			return(1);
1111 		}
1112 		if(fp->level)
1113 		{
1114 			dot= --fp->dim;
1115 			while((dot+1) < fp->ndim)
1116 				fp->cur[++dot] = 0;
1117 			fp->level--;
1118 			fp->curi = 0;
1119 		}
1120 		else
1121 		ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
1122 		return(0);
1123 	}
1124 #endif /* SHOPT_FIXEDARRAY */
1125 	if(!(ap->header.nelem&ARRAY_NOSCOPE))
1126 		ar = (struct index_array*)ap->header.scope;
1127 	for(dot=ap->cur+1; dot <  (unsigned)ap->maxi; dot++)
1128 	{
1129 		aq = ap;
1130 		if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
1131 		{
1132 			if(!(aq=ar) || dot>=(unsigned)aq->maxi)
1133 				continue;
1134 		}
1135 		if(aq->val[dot].cp==Empty && array_elem(&aq->header) < nv_aimax(np)+1)		{
1136 			ap->cur = dot;
1137 			if(nv_getval(np)==Empty)
1138 				continue;
1139 		}
1140 		if(aq->val[dot].cp)
1141 		{
1142 			ap->cur = dot;
1143 			if(array_isbit(aq->bits, dot,ARRAY_CHILD))
1144 			{
1145 				Namval_t *mp = aq->val[dot].np;
1146 				if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize)
1147 					continue;
1148 				if(nv_isarray(mp))
1149 					nv_putsub(mp,NIL(char*),ARRAY_SCAN);
1150 			}
1151 			return(1);
1152 		}
1153 	}
1154 	ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
1155 	ap->cur = 0;
1156 	return(0);
1157 }
1158 
1159 /*
1160  * Set an array subscript for node <np> given the subscript <sp>
1161  * An array is created if necessary.
1162  * <mode> can be a number, plus or more of symbolic constants
1163  *    ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
1164  * The node pointer is returned which can be NULL if <np> is
1165  *    not already array and the ARRAY_ADD bit of <mode> is not set.
1166  * ARRAY_FILL sets the specified subscript to the empty string when
1167  *   ARRAY_ADD is specified and there is no value or sets all
1168  * the elements up to the number specified if ARRAY_ADD is not specified
1169  */
1170 Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
1171 {
1172 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1173 	register int size = (mode&ARRAY_MASK);
1174 #if SHOPT_FIXEDARRAY
1175 	struct fixed_array	*fp;
1176 	if(!ap || (!ap->header.fixed && !ap->header.fun))
1177 #else
1178 	if(!ap || !ap->header.fun)
1179 #endif /* SHOPT_FIXEDARRAY */
1180 	{
1181 		if(sp)
1182 		{
1183 			Shell_t	*shp = sh_getinterp();
1184 			if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
1185 			{
1186 				Namval_t *mp = nv_namptr(ap->xp,0);
1187 				nv_putval(mp, sp,0);
1188 				size = nv_getnum(mp);
1189 			}
1190 			else
1191 				size = (int)sh_arith(shp,(char*)sp);
1192 		}
1193 		if(size <0 && ap)
1194 			size += array_maxindex(np);
1195 		if(size >= ARRAY_MAX || (size < 0))
1196 		{
1197 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1198 			return(NIL(Namval_t*));
1199 		}
1200 		if(!ap || size>=ap->maxi)
1201 		{
1202 			if(size==0 && !(mode&ARRAY_FILL))
1203 				return(NIL(Namval_t*));
1204 			if(sh.subshell)
1205 				np = sh_assignok(np,1);
1206 			ap = array_grow(np, ap,size);
1207 		}
1208 		ap->header.nelem &= ~ARRAY_UNDEF;
1209 		ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1210 #if 0
1211 		if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
1212 			mp = ap->val[oldsize].np;
1213 		if(size != oldsize && mp->nvalue.cp)
1214 		{
1215 			Namfun_t *nfp;
1216 			for(nfp=np->nvfun; nfp; nfp=nfp->next)
1217 			{
1218 				if(nfp->disc && nfp->disc->readf)
1219 				{
1220 					(*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
1221 					break;
1222 				}
1223 			}
1224 		}
1225 #endif
1226 		ap->cur = size;
1227 		if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
1228 			np = 0;
1229 		if(mode&(ARRAY_FILL|ARRAY_ADD))
1230 		{
1231 			if(!(mode&ARRAY_ADD))
1232 			{
1233 				int n;
1234 				if(mode&ARRAY_SETSUB)
1235 				{
1236 					for(n=0; n <= ap->maxi; n++)
1237 						ap->val[n].cp = 0;
1238 					ap->header.nelem = 0;
1239 				}
1240 				for(n=0; n <= size; n++)
1241 				{
1242 					if(!ap->val[n].cp)
1243 					{
1244 						ap->val[n].cp = Empty;
1245 						if(!array_covered(np,ap))
1246 							ap->header.nelem++;
1247 					}
1248 				}
1249 				if(n=ap->maxi-ap->maxi)
1250 					memset(&ap->val[size],0,n*sizeof(union Value));
1251 			}
1252 			else if(!(sp=(char*)ap->val[size].cp) || sp==Empty)
1253 			{
1254 				if(sh.subshell)
1255 					np = sh_assignok(np,1);
1256 				if(ap->header.nelem&ARRAY_TREE)
1257 				{
1258 					char *cp;
1259 					Namval_t *mp;
1260 					if(!ap->header.table)
1261 						ap->header.table = dtopen(&_Nvdisc,Dtoset);
1262 					sfprintf(sh.strbuf,"%d",ap->cur);
1263 					cp = sfstruse(sh.strbuf);
1264 					mp = nv_search(cp, ap->header.table, NV_ADD);
1265 					mp->nvenv = (char*)np;
1266 					nv_arraychild(np,mp,0);
1267 					nv_setvtree(mp);
1268 				}
1269 				else
1270 					ap->val[size].cp = Empty;
1271 				if(!sp && !array_covered(np,ap))
1272 					ap->header.nelem++;
1273 			}
1274 		}
1275 		else if(!(mode&ARRAY_SCAN))
1276 		{
1277 			ap->header.nelem &= ~ARRAY_SCAN;
1278 			if(array_isbit(ap->bits,size,ARRAY_CHILD))
1279 				nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
1280 			if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
1281 				np = 0;
1282 		}
1283 		return((Namval_t*)np);
1284 	}
1285 #if SHOPT_FIXEDARRAY
1286 	if(fp=(struct fixed_array*)ap->header.fixed)
1287 	{
1288 		if(!fp->data)
1289 			return(np);
1290 		if(mode&ARRAY_UNDEF)
1291 		{
1292 			fp->dim = 0;
1293 			fp->curi = 0;
1294 			for(size=fp->ndim;--size>=0;)
1295 				fp->cur[size] = 0;
1296 			ap->header.nelem &= ~ARRAY_MASK;
1297 			if(mode&ARRAY_FIXED)
1298 			{
1299 				mode &= ~ARRAY_UNDEF;
1300 				ap->header.nelem |= (ARRAY_FIXED|fp->nelem);
1301 			}
1302 			else
1303 				ap->header.nelem |=  fp->max[0];
1304 		}
1305 		else if(mode&ARRAY_FIXED)
1306 		{
1307 			size = (mode&ARRAY_MASK)&~(ARRAY_FIXED);
1308 			fp->curi = size;
1309 			for(fp->dim=0;size>0 && fp->dim<fp->ndim; fp->dim++)
1310 			{
1311 				fp->cur[fp->dim] = size/fp->incr[fp->dim];
1312 				size -= fp->incr[fp->dim]*fp->cur[fp->dim];
1313 			}
1314 			while(fp->dim < fp->ndim)
1315 				fp->cur[fp->dim++] = 0;
1316 			fp->dim = ap->header.nelem;
1317 			ap->header.nelem |= ARRAY_FIXED;
1318 		}
1319 		else if(fp->dim< fp->ndim)
1320 		{
1321 			fp->curi += (size-fp->cur[fp->dim])*fp->incr[fp->dim];
1322 			fp->cur[fp->dim] = size;
1323 		}
1324 	}
1325 #endif /* SHOPT_FIXEDARRAY */
1326 	ap->header.nelem &= ~ARRAY_UNDEF;
1327 	if(!(mode&ARRAY_FILL))
1328 		ap->header.nelem &= ~ARRAY_SCAN;
1329 	ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1330 #if SHOPT_FIXEDARRAY
1331 	if(fp)
1332 		return(np);
1333 	else
1334 #endif /* SHOPT_FIXEDARRAY */
1335 	if(sp)
1336 	{
1337 		if(mode&ARRAY_SETSUB)
1338 		{
1339 			(*ap->header.fun)(np, sp, NV_ASETSUB);
1340 			return(np);
1341 		}
1342 		(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
1343 		if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
1344 			np = 0;
1345 	}
1346 	else if(mode&ARRAY_SCAN)
1347 		(*ap->header.fun)(np,(char*)np,0);
1348 	else if(mode&ARRAY_UNDEF)
1349 		(*ap->header.fun)(np, "",0);
1350 	if((mode&ARRAY_SCAN) && !nv_nextsub(np))
1351 		np = 0;
1352 	return(np);
1353 }
1354 
1355 #if SHOPT_FIXEDARRAY
1356 int nv_arrfixed(Namval_t *np, Sfio_t *out, int flag, char *dim)
1357 {
1358 	Namarr_t		*ap =  nv_arrayptr(np);
1359 	struct fixed_array	*fp = (struct fixed_array*)ap->fixed;
1360 	int			n;
1361 	if(flag)
1362 	{
1363 		if(out)
1364 		{
1365 			for(n=0; n < fp->dim; n++)
1366 				sfprintf(out,"[%d]",fp->cur[n]);
1367 		}
1368 		if(dim)
1369 			*dim = fp->dim;
1370 		return(fp->curi);
1371 	}
1372 	if(out)
1373 	{
1374 		for(n=0; n < fp->ndim; n++)
1375 			sfprintf(out,"[%d]",fp->max[n]);
1376 	}
1377 	fp->dim = 0;
1378 	return(fp->curi);
1379 }
1380 
1381 static void array_fixed_setdata(Namval_t *np,Namarr_t* ap,struct fixed_array* fp)
1382 {
1383 	int n = ap->nelem;
1384 	ap->nelem = 1;
1385 	fp->size = fp->ptr?sizeof(void*):nv_datasize(np,0);
1386 	ap->nelem = n;
1387 	fp->data = (char*)calloc(fp->nelem,fp->size);
1388 	if(fp->ptr)
1389 	{
1390 		char **cp = (char**)fp->data;
1391 		for(n=fp->nelem; n-->0;)
1392 			*cp++ = Empty;
1393 	}
1394 }
1395 
1396 static int array_fixed_init(Namval_t *np, char *sub, char *cp)
1397 {
1398 	Shell_t			*shp=sh_getinterp();
1399 	Namarr_t		*ap;
1400 	struct fixed_array	*fp;
1401 	int			n=1,sz;
1402 	char			*ep=cp;
1403 	while(*ep=='[')
1404 	{
1405 		ep = nv_endsubscript(np,ep,0);
1406 		n++;
1407 	}
1408 	if(*ep)
1409 		return(0);
1410 	sz = sizeof(struct fixed_array)+ 3*n*sizeof(int);
1411         if(!(ap=newof(NIL(Namarr_t*),Namarr_t,1,sz)))
1412                 return(0);
1413 	ap->hdr.disc = &array_disc;
1414 	ap->hdr.dsize = sizeof(Namarr_t)+sz;
1415 	ap->hdr.nofree &= ~1;
1416 	fp = (struct fixed_array*)(ap+1);
1417 	ap->fixed = (void*)fp;
1418 	fp->ndim = n;
1419 	fp->max = (int*)(fp+1);
1420 	fp->incr = fp->max+n;
1421 	fp->cur = fp->incr+n;
1422 	fp->max[0] = (int)sh_arith(shp,(char*)sub);
1423 	for(n=1,ep=cp;*ep=='['; ep=cp)
1424 	{
1425 		cp = nv_endsubscript(np,ep,0);
1426 		cp[-1]=0;
1427 		fp->max[n++] = sz = (int)sh_arith(shp,(char*)ep+1);
1428 		if(sz<0)
1429 		{
1430 			free((void*)ap);
1431 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1432 		}
1433 		cp[-1] = ']';
1434 	}
1435 	nv_disc(np,(Namfun_t*)ap, NV_FIRST);
1436 	fp->ptr = !np->nvsize;
1437 	nv_onattr(np,NV_ARRAY|(fp->ptr?0:NV_NOFREE));
1438 	fp->incr[n=fp->ndim-1] = 1;
1439 	for(sz=1; --n>=0;)
1440 		sz = fp->incr[n] = sz*fp->max[n+1];
1441 	fp->nelem = sz*fp->max[0];
1442 	ap->nelem = fp->max[0];
1443 	return(1);
1444 }
1445 
1446 static char *array_fixed(Namval_t *np, char *sub, char *cp,int mode)
1447 {
1448 	Shell_t			*shp=sh_getinterp();
1449 	Namarr_t		*ap = nv_arrayptr(np);
1450 	struct fixed_array	*fp = (struct fixed_array*)ap->fixed;
1451 	char			*ep;
1452 	int			size,n=0,sz;
1453 	if(!fp->data)
1454 		array_fixed_setdata(np,ap,fp);
1455 	ap->nelem &= ~ARRAY_UNDEF;
1456 	if(ap->nelem&ARRAY_FIXED)
1457 	{
1458 		ap->nelem &= ~ARRAY_FIXED;
1459 		n = fp->dim;
1460 		sz = fp->curi;
1461 		if(*sub==0)
1462 			goto skip;
1463 	}
1464 	else
1465 		fp->curi = 0;
1466 	size = (int)sh_arith(shp,(char*)sub);
1467 	fp->cur[n] = size;
1468 	if(size >= fp->max[n] || (size < 0))
1469 		errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1470 	*cp++ = ']';
1471 	sz = fp->curi + fp->cur[n]*fp->incr[n];
1472 	for(n++,ep=cp;*ep=='['; ep=cp,n++)
1473 	{
1474 		if(n >= fp->ndim)
1475 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1476 		cp = nv_endsubscript(np,ep,0);
1477 		cp[-1]=0;
1478 		size = (int)sh_arith(shp,(char*)ep+1);
1479 		if(size >= fp->max[n] || (size < 0))
1480 			errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1481 		fp->cur[n] = size;
1482 		cp[-1] = ']';
1483 		sz += fp->cur[n]*fp->incr[n];
1484 	}
1485 skip:
1486 	fp->dim = n;
1487 	ap->nelem &= ~ARRAY_MASK;
1488 	ap->nelem |= fp->max[n];
1489 	while(n < fp->ndim)
1490 		fp->cur[n++] = 0;
1491 	fp->curi = sz;
1492 	return(cp-1);
1493 }
1494 #endif /* SHOPT_FIXEDARRAY */
1495 
1496 /*
1497  * process an array subscript for node <np> given the subscript <cp>
1498  * returns pointer to character after the subscript
1499  */
1500 char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
1501 {
1502 	register int count=1, quoted=0, c;
1503 	register char *sp = cp+1;
1504 	/* first find matching ']' */
1505 	while(count>0 && (c= *++cp))
1506 	{
1507 		if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
1508 		{
1509 			quoted=1;
1510 			cp++;
1511 		}
1512 		else if(c=='[')
1513 			count++;
1514 		else if(c==']')
1515 			count--;
1516 	}
1517 	*cp = 0;
1518 	if(quoted)
1519 	{
1520 		/* strip escape characters */
1521 		count = staktell();
1522 		stakwrite(sp,1+cp-sp);
1523 		sh_trim(sp=stakptr(count));
1524 	}
1525 	if(mode && np)
1526 	{
1527 		Namarr_t *ap = nv_arrayptr(np);
1528 		int scan = 0;
1529 #if SHOPT_FIXEDARRAY
1530 		if((mode&NV_FARRAY) && !nv_isarray(np))
1531 		{
1532 			if(array_fixed_init(np,sp,cp+1))
1533 			{
1534 				*cp++ = c;
1535 				return(strchr(cp,0));
1536 			}
1537 		}
1538 #endif /* SHOPT_FIXEDARRAY */
1539 		if(ap)
1540 			scan = ap->nelem&ARRAY_SCAN;
1541 		if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
1542 			mode |= NV_ADD;
1543 		else if(ap && cp[1]=='.' && (mode&NV_FARRAY))
1544 			mode |= NV_ADD;
1545 #if SHOPT_FIXEDARRAY
1546 		if(ap && ap->fixed)
1547 			cp = array_fixed(np,sp,cp,mode);
1548 		else
1549 #endif /* SHOPT_FIXEDARRAY */
1550 		nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
1551 		if(scan)
1552 			ap->nelem |= scan;
1553 	}
1554 	if(quoted)
1555 		stakseek(count);
1556 	*cp++ = c;
1557 	return(cp);
1558 }
1559 
1560 
1561 Namval_t *nv_opensub(Namval_t* np)
1562 {
1563 	register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1564 #if SHOPT_FIXEDARRAY
1565 	struct fixed_array *fp;
1566 #endif /* SHOPT_FIXEDARRAY */
1567 	if(ap)
1568 	{
1569 		if(is_associative(ap))
1570 			return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
1571 #if SHOPT_FIXEDARRAY
1572 		else if(!(fp=(struct fixed_array*)ap->header.fixed) && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
1573 #else
1574 		else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
1575 #endif /* SHOPT_FIXEDARRAY */
1576 		{
1577 			return(ap->val[ap->cur].np);
1578 		}
1579 #if SHOPT_FIXEDARRAY
1580 		else if(fp)
1581 		{
1582 			int n = fp->dim;
1583 			if((fp->dim+1) < fp->ndim)
1584 			{
1585 				fp->dim++;
1586 				if(ap->header.nelem&ARRAY_SCAN)
1587 				{
1588 					while(++n < fp->ndim)
1589 						fp->cur[n] = 0;
1590 					fp->level++;
1591 				}
1592 				return(np);
1593 			}
1594 		}
1595 #endif /* SHOPT_FIXEDARRAY */
1596 	}
1597 	return(NIL(Namval_t*));
1598 }
1599 
1600 char	*nv_getsub(Namval_t* np)
1601 {
1602 	static char numbuff[NUMSIZE+1];
1603 	register struct index_array *ap;
1604 	register unsigned dot, n;
1605 	register char *cp = &numbuff[NUMSIZE];
1606 	if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
1607 		return(NIL(char*));
1608 	if(is_associative(ap))
1609 		return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
1610 	if(ap->xp)
1611 	{
1612 		np = nv_namptr(ap->xp,0);
1613 		np->nvalue.s = ap->cur;
1614 		return(nv_getval(np));
1615 	}
1616 	if((dot = ap->cur)==0)
1617 		*--cp = '0';
1618 	else while(n=dot)
1619 	{
1620 		dot /= 10;
1621 		*--cp = '0' + (n-10*dot);
1622 	}
1623 	return(cp);
1624 }
1625 
1626 /*
1627  * If <np> is an indexed array node, the current subscript index
1628  * returned, otherwise returns -1
1629  */
1630 int nv_aindex(register Namval_t* np)
1631 {
1632 	Namarr_t *ap = nv_arrayptr(np);
1633 	if(!ap)
1634 		return(0);
1635 	else if(is_associative(ap))
1636 		return(-1);
1637 #if SHOPT_FIXEDARRAY
1638 	else if(ap->fixed)
1639 		return(-1);
1640 #endif /* SHOPT_FIXEDARRAY */
1641 	return(((struct index_array*)(ap))->cur&ARRAY_MASK);
1642 }
1643 
1644 int nv_arraynsub(register Namarr_t* ap)
1645 {
1646 	return(array_elem(ap));
1647 }
1648 
1649 int nv_aimax(register Namval_t* np)
1650 {
1651 	struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1652 	int sub = -1;
1653 #if SHOPT_FIXEDARRAY
1654 	if(!ap || is_associative(&ap->header) || ap->header.fixed)
1655 #else
1656 	if(!ap || is_associative(&ap->header))
1657 #endif /* SHOPT_FIXEDARRAY */
1658 		return(-1);
1659 	sub = ap->maxi;
1660 	while(--sub>0 && ap->val[sub].cp==0);
1661 	return(sub);
1662 }
1663 
1664 /*
1665  *  This is the default implementation for associative arrays
1666  */
1667 void *nv_associative(register Namval_t *np,const char *sp,int mode)
1668 {
1669 	register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
1670 	register int type;
1671 	switch(mode)
1672 	{
1673 	    case NV_AINIT:
1674 		if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
1675 		{
1676 			ap->header.table = dtopen(&_Nvdisc,Dtoset);
1677 			ap->cur = 0;
1678 			ap->pos = 0;
1679 			ap->header.hdr.disc = &array_disc;
1680 			nv_disc(np,(Namfun_t*)ap, NV_FIRST);
1681 			ap->header.hdr.dsize = sizeof(struct assoc_array);
1682 			ap->header.hdr.nofree &= ~1;
1683 		}
1684 		return((void*)ap);
1685 	    case NV_ADELETE:
1686 		if(ap->cur)
1687 		{
1688 			if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0))
1689 				ap->header.nelem--;
1690 			_nv_unset(ap->cur,NV_RDONLY);
1691 			nv_delete(ap->cur,ap->header.table,0);
1692 			ap->cur = 0;
1693 		}
1694 		return((void*)ap);
1695 	    case NV_AFREE:
1696 		ap->pos = 0;
1697 		if(ap->header.scope)
1698 		{
1699 			ap->header.table = dtview(ap->header.table,(Dt_t*)0);
1700 			dtclose(ap->header.scope);
1701 			ap->header.scope = 0;
1702 		}
1703 		else
1704 			dtclose(ap->header.table);
1705 		return((void*)ap);
1706 	    case NV_ANEXT:
1707 		if(!ap->pos)
1708 		{
1709 			if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
1710 			{
1711 				ap->header.scope = dtvnext(ap->header.table);
1712 				ap->header.table->view = 0;
1713 			}
1714 			if(!(ap->pos=ap->cur))
1715 				ap->pos = (Namval_t*)dtfirst(ap->header.table);
1716 		}
1717 		else
1718 			ap->pos = ap->nextpos;
1719 		for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
1720 		{
1721 			ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
1722 			if(!nv_isnull(ap->cur))
1723 			{
1724 				if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
1725 					continue;
1726 				return((void*)ap);
1727 			}
1728 		}
1729 		if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
1730 		{
1731 			ap->header.table->view = (Dt_t*)ap->header.scope;
1732 			ap->header.scope = ap->header.table;
1733 		}
1734 		return(NIL(void*));
1735 	    case NV_ASETSUB:
1736 		ap->cur = (Namval_t*)sp;
1737 		return((void*)ap->cur);
1738 	    case NV_ACURRENT:
1739 		if(ap->cur)
1740 			ap->cur->nvenv = (char*)np;
1741 		return((void*)ap->cur);
1742 	    case NV_ANAME:
1743 		if(ap->cur)
1744 		{
1745 			Shell_t *shp = sh_getinterp();
1746 			if(!shp->instance && nv_isnull(ap->cur))
1747 				return(NIL(void*));
1748 			return((void*)ap->cur->nvname);
1749 		}
1750 		return(NIL(void*));
1751 	    default:
1752 		if(sp)
1753 		{
1754 			Namval_t *mp=0;
1755 			ap->cur = 0;
1756 			if(sp==(char*)np)
1757 				return(0);
1758 			type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
1759 			if(mode)
1760 				mode = NV_ADD|HASH_NOSCOPE;
1761 			else if(ap->header.nelem&ARRAY_NOSCOPE)
1762 				mode = HASH_NOSCOPE;
1763 			if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD))
1764 				errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript");
1765 			if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
1766 				ap->cur = mp;
1767 			if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
1768 			{
1769 				nv_onattr(mp,type);
1770 				mp->nvenv = (char*)np;
1771 				if((mode&NV_ADD) && nv_type(np))
1772 					nv_arraychild(np,mp,0);
1773 				if(sh.subshell)
1774 					np = sh_assignok(np,1);
1775 				if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
1776 					ap->header.nelem++;
1777 				if(nv_isnull(mp))
1778 				{
1779 					if(ap->header.nelem&ARRAY_TREE)
1780 						nv_setvtree(mp);
1781 					mp->nvalue.cp = Empty;
1782 				}
1783 			}
1784 			else if(ap->header.nelem&ARRAY_SCAN)
1785 			{
1786 				Namval_t fake;
1787 				fake.nvname = (char*)sp;
1788 				ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
1789 				ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
1790 			}
1791 			else if(!mp && *sp && mode==0)
1792 				mp = nv_search(sp,ap->header.table,NV_ADD|HASH_NOSCOPE);
1793 			np = mp;
1794 			if(ap->pos && ap->pos==np)
1795 				ap->header.nelem |= ARRAY_SCAN;
1796 			else if(!(ap->header.nelem&ARRAY_SCAN))
1797 				ap->pos = 0;
1798 			ap->cur = np;
1799 		}
1800 		if(ap->cur)
1801 			return((void*)(&ap->cur->nvalue));
1802 		else
1803 			return((void*)(&ap->cur));
1804 	}
1805 }
1806 
1807 /*
1808  * Assign values to an array
1809  */
1810 void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
1811 {
1812 	int arg0=0;
1813 	struct index_array *ap=0,*aq;
1814 	if(nv_isarray(np))
1815 	{
1816 		ap = (struct index_array*)nv_arrayptr(np);
1817 		if(ap && is_associative(ap))
1818 			errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
1819 	}
1820 	if(append)
1821 	{
1822 		if(ap)
1823 		{
1824 			if(!(aq = (struct index_array*)ap->header.scope))
1825 				aq = ap;
1826 			arg0 = ap->maxi;
1827 			while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
1828 			arg0++;
1829 		}
1830 		else
1831 		{
1832 			nv_offattr(np,NV_ARRAY);
1833 			if(!nv_isnull(np) && np->nvalue.cp!=Empty)
1834 				arg0=1;
1835 		}
1836 	}
1837 	while(--argc >= 0)
1838 	{
1839 		nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
1840 		nv_putval(np,argv[argc],0);
1841 	}
1842 }
1843 
1844