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
43struct 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
53struct 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
80static 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
121static 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
134static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
135{
136	((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
137}
138
139static 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 */
154static 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 */
174static 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
182static struct index_array *array_grow(Namval_t*, struct index_array*,int);
183
184/* return index of highest element of an array */
185int 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
195static 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
246int 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 */
272static 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
403int 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
447static 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));
549skip:
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
560static 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
587static 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
604static 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
781static 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
792static 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 */
815static 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
893int 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
920Namarr_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 */
931static 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 */
977Namarr_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)
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 */
1025Namval_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 */
1073int 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 */
1170Namval_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
1356int 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
1381static 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
1396static 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
1446static 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	}
1485skip:
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 */
1500char *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
1561Namval_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
1600char	*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 */
1630int 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
1644int nv_arraynsub(register Namarr_t* ap)
1645{
1646	return(array_elem(ap));
1647}
1648
1649int 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 */
1667void *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 */
1810void 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