1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin * Array processing routines
23da2e3ebdSchin *
24da2e3ebdSchin * David Korn
25da2e3ebdSchin * AT&T Labs
26da2e3ebdSchin * dgk@research.att.com
27da2e3ebdSchin *
28da2e3ebdSchin */
29da2e3ebdSchin
30da2e3ebdSchin #include "defs.h"
31da2e3ebdSchin #include <stak.h>
32da2e3ebdSchin #include "name.h"
33da2e3ebdSchin
34da2e3ebdSchin #define NUMSIZE (4+(ARRAY_MAX>999)+(ARRAY_MAX>9999)+(ARRAY_MAX>99999))
35da2e3ebdSchin #define is_associative(ap) array_assoc((Namarr_t*)(ap))
367c2fbfb3SApril Chin #define array_setbit(cp, n, b) (cp[n] |= (b))
377c2fbfb3SApril Chin #define array_clrbit(cp, n, b) (cp[n] &= ~(b))
387c2fbfb3SApril Chin #define array_isbit(cp, n, b) (cp[n] & (b))
39da2e3ebdSchin #define NV_CHILD NV_EXPORT
407c2fbfb3SApril Chin #define ARRAY_CHILD 1
417c2fbfb3SApril Chin #define ARRAY_NOFREE 2
42da2e3ebdSchin
43da2e3ebdSchin struct index_array
44da2e3ebdSchin {
45da2e3ebdSchin Namarr_t header;
467c2fbfb3SApril Chin void *xp; /* if set, subscripts will be converted */
47da2e3ebdSchin int cur; /* index of current element */
48da2e3ebdSchin int maxi; /* maximum index for array */
49da2e3ebdSchin unsigned char *bits; /* bit array for child subscripts */
50da2e3ebdSchin union Value val[1]; /* array of value holders */
51da2e3ebdSchin };
52da2e3ebdSchin
53da2e3ebdSchin struct assoc_array
54da2e3ebdSchin {
55da2e3ebdSchin Namarr_t header;
56da2e3ebdSchin Namval_t *pos;
57da2e3ebdSchin Namval_t *nextpos;
58da2e3ebdSchin Namval_t *cur;
59da2e3ebdSchin };
60da2e3ebdSchin
array_scope(Namval_t * np,Namarr_t * ap,int flags)617c2fbfb3SApril Chin static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
627c2fbfb3SApril Chin {
637c2fbfb3SApril Chin Namarr_t *aq;
647c2fbfb3SApril Chin struct index_array *ar;
657c2fbfb3SApril Chin size_t size = ap->hdr.dsize;
667c2fbfb3SApril Chin if(size==0)
677c2fbfb3SApril Chin size = ap->hdr.disc->dsize;
687c2fbfb3SApril Chin if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
697c2fbfb3SApril Chin return(0);
707c2fbfb3SApril Chin memcpy(aq,ap,size);
717c2fbfb3SApril Chin aq->hdr.nofree &= ~1;
727c2fbfb3SApril Chin aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
737c2fbfb3SApril Chin if(is_associative(aq))
747c2fbfb3SApril Chin {
757c2fbfb3SApril Chin aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
767c2fbfb3SApril Chin dtview((Dt_t*)aq->scope,aq->table);
777c2fbfb3SApril Chin aq->table = (Dt_t*)aq->scope;
787c2fbfb3SApril Chin return(aq);
797c2fbfb3SApril Chin }
807c2fbfb3SApril Chin aq->scope = (void*)ap;
817c2fbfb3SApril Chin ar = (struct index_array*)aq;
827c2fbfb3SApril Chin memset(ar->val, 0, ar->maxi*sizeof(char*));
837c2fbfb3SApril Chin return(aq);
847c2fbfb3SApril Chin }
857c2fbfb3SApril Chin
array_unscope(Namval_t * np,Namarr_t * ap)867c2fbfb3SApril Chin static int array_unscope(Namval_t *np,Namarr_t *ap)
877c2fbfb3SApril Chin {
887c2fbfb3SApril Chin Namfun_t *fp;
897c2fbfb3SApril Chin if(!ap->scope)
907c2fbfb3SApril Chin return(0);
917c2fbfb3SApril Chin if(is_associative(ap))
927c2fbfb3SApril Chin (*ap->fun)(np, NIL(char*), NV_AFREE);
937c2fbfb3SApril Chin if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
947c2fbfb3SApril Chin free((void*)fp);
957c2fbfb3SApril Chin nv_delete(np,(Dt_t*)0,0);
967c2fbfb3SApril Chin return(1);
977c2fbfb3SApril Chin }
987c2fbfb3SApril Chin
array_syncsub(Namarr_t * ap,Namarr_t * aq)997c2fbfb3SApril Chin static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
1007c2fbfb3SApril Chin {
1017c2fbfb3SApril Chin ((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
1027c2fbfb3SApril Chin }
1037c2fbfb3SApril Chin
array_covered(Namval_t * np,struct index_array * ap)1047c2fbfb3SApril Chin static int array_covered(Namval_t *np, struct index_array *ap)
1057c2fbfb3SApril Chin {
1067c2fbfb3SApril Chin struct index_array *aq = (struct index_array*)ap->header.scope;
1077c2fbfb3SApril Chin if(!ap->header.fun && aq)
1087c2fbfb3SApril Chin return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
1097c2fbfb3SApril Chin return(0);
1107c2fbfb3SApril Chin }
1117c2fbfb3SApril Chin
112da2e3ebdSchin /*
113da2e3ebdSchin * replace discipline with new one
114da2e3ebdSchin */
array_setptr(register Namval_t * np,struct index_array * old,struct index_array * new)115da2e3ebdSchin static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
116da2e3ebdSchin {
117da2e3ebdSchin register Namfun_t **fp = &np->nvfun;
118da2e3ebdSchin while(*fp && *fp!= &old->header.hdr)
119da2e3ebdSchin fp = &((*fp)->next);
120da2e3ebdSchin if(*fp)
121da2e3ebdSchin {
122da2e3ebdSchin new->header.hdr.next = (*fp)->next;
123da2e3ebdSchin *fp = &new->header.hdr;
124da2e3ebdSchin }
125da2e3ebdSchin else sfprintf(sfstderr,"discipline not replaced\n");
126da2e3ebdSchin }
127da2e3ebdSchin
128da2e3ebdSchin /*
129da2e3ebdSchin * Calculate the amount of space to be allocated to hold an
130da2e3ebdSchin * indexed array into which <maxi> is a legal index. The number of
131da2e3ebdSchin * elements that will actually fit into the array (> <maxi>
132da2e3ebdSchin * but <= ARRAY_MAX) is returned.
133da2e3ebdSchin *
134da2e3ebdSchin */
arsize(struct index_array * ap,register int maxi)1357c2fbfb3SApril Chin static int arsize(struct index_array *ap, register int maxi)
136da2e3ebdSchin {
1377c2fbfb3SApril Chin if(ap && maxi < 2*ap->maxi)
1387c2fbfb3SApril Chin maxi = 2*ap->maxi;
1397c2fbfb3SApril Chin maxi = roundof(maxi,ARRAY_INCR);
1407c2fbfb3SApril Chin return (maxi>ARRAY_MAX?ARRAY_MAX:maxi);
141da2e3ebdSchin }
142da2e3ebdSchin
143da2e3ebdSchin static struct index_array *array_grow(Namval_t*, struct index_array*,int);
144da2e3ebdSchin
145da2e3ebdSchin /* return index of highest element of an array */
array_maxindex(Namval_t * np)146da2e3ebdSchin int array_maxindex(Namval_t *np)
147da2e3ebdSchin {
148da2e3ebdSchin register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
149da2e3ebdSchin register int i = ap->maxi;
150da2e3ebdSchin if(is_associative(ap))
151da2e3ebdSchin return(-1);
152da2e3ebdSchin while(i>0 && ap->val[--i].cp==0);
153da2e3ebdSchin return(i+1);
154da2e3ebdSchin }
155da2e3ebdSchin
array_getup(Namval_t * np,Namarr_t * arp,int update)1567c2fbfb3SApril Chin static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update)
157da2e3ebdSchin {
158da2e3ebdSchin register struct index_array *ap = (struct index_array*)arp;
159da2e3ebdSchin register union Value *up;
1607c2fbfb3SApril Chin int nofree;
1617c2fbfb3SApril Chin if(!arp)
162da2e3ebdSchin return(&np->nvalue);
163da2e3ebdSchin if(is_associative(ap))
1647c2fbfb3SApril Chin {
1657c2fbfb3SApril Chin Namval_t *mp;
1667c2fbfb3SApril Chin mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
1677c2fbfb3SApril Chin if(mp)
1687c2fbfb3SApril Chin {
1697c2fbfb3SApril Chin nofree = nv_isattr(mp,NV_NOFREE);
1707c2fbfb3SApril Chin up = &mp->nvalue;
1717c2fbfb3SApril Chin }
1727c2fbfb3SApril Chin else
1737c2fbfb3SApril Chin return((union Value*)((*arp->fun)(np,NIL(char*),0)));
1747c2fbfb3SApril Chin }
175da2e3ebdSchin else
176da2e3ebdSchin {
177da2e3ebdSchin if(ap->cur >= ap->maxi)
178da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
179da2e3ebdSchin up = &(ap->val[ap->cur]);
1807c2fbfb3SApril Chin nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
1817c2fbfb3SApril Chin }
1827c2fbfb3SApril Chin if(update)
1837c2fbfb3SApril Chin {
1847c2fbfb3SApril Chin if(nofree)
1857c2fbfb3SApril Chin nv_onattr(np,NV_NOFREE);
1867c2fbfb3SApril Chin else
1877c2fbfb3SApril Chin nv_offattr(np,NV_NOFREE);
188da2e3ebdSchin }
189da2e3ebdSchin return(up);
190da2e3ebdSchin }
191da2e3ebdSchin
nv_arrayisset(Namval_t * np,Namarr_t * arp)19234f9b3eeSRoland Mainz int nv_arrayisset(Namval_t *np, Namarr_t *arp)
19334f9b3eeSRoland Mainz {
19434f9b3eeSRoland Mainz register struct index_array *ap = (struct index_array*)arp;
19534f9b3eeSRoland Mainz union Value *up;
19634f9b3eeSRoland Mainz if(is_associative(ap))
19734f9b3eeSRoland Mainz return((np = nv_opensub(np)) && !nv_isnull(np));
19834f9b3eeSRoland Mainz if(ap->cur >= ap->maxi)
19934f9b3eeSRoland Mainz return(0);
20034f9b3eeSRoland Mainz up = &(ap->val[ap->cur]);
20134f9b3eeSRoland Mainz return(up->cp && up->cp!=Empty);
20234f9b3eeSRoland Mainz }
20334f9b3eeSRoland Mainz
204da2e3ebdSchin /*
205da2e3ebdSchin * Get the Value pointer for an array.
206da2e3ebdSchin * Delete space as necessary if flag is ARRAY_DELETE
207da2e3ebdSchin * After the lookup is done the last @ or * subscript is incremented
208da2e3ebdSchin */
array_find(Namval_t * np,Namarr_t * arp,int flag)209da2e3ebdSchin static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
210da2e3ebdSchin {
211da2e3ebdSchin register struct index_array *ap = (struct index_array*)arp;
212da2e3ebdSchin register union Value *up;
213da2e3ebdSchin Namval_t *mp;
214da2e3ebdSchin int wasundef;
2157c2fbfb3SApril Chin if(flag&ARRAY_LOOKUP)
2167c2fbfb3SApril Chin ap->header.nelem &= ~ARRAY_NOSCOPE;
2177c2fbfb3SApril Chin else
2187c2fbfb3SApril Chin ap->header.nelem |= ARRAY_NOSCOPE;
219da2e3ebdSchin if(wasundef = ap->header.nelem&ARRAY_UNDEF)
220da2e3ebdSchin {
221da2e3ebdSchin ap->header.nelem &= ~ARRAY_UNDEF;
222da2e3ebdSchin /* delete array is the same as delete array[@] */
223da2e3ebdSchin if(flag&ARRAY_DELETE)
224da2e3ebdSchin {
2257c2fbfb3SApril Chin nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
226da2e3ebdSchin ap->header.nelem |= ARRAY_SCAN;
227da2e3ebdSchin }
228da2e3ebdSchin else /* same as array[0] */
229da2e3ebdSchin {
230da2e3ebdSchin if(is_associative(ap))
231da2e3ebdSchin (*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
232da2e3ebdSchin else
233da2e3ebdSchin ap->cur = 0;
234da2e3ebdSchin }
235da2e3ebdSchin }
236da2e3ebdSchin if(is_associative(ap))
237da2e3ebdSchin {
238da2e3ebdSchin mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
239da2e3ebdSchin if(!mp)
240da2e3ebdSchin up = (union Value*)∓
2417c2fbfb3SApril Chin else if(nv_isarray(mp))
242da2e3ebdSchin {
2437c2fbfb3SApril Chin if(wasundef)
2447c2fbfb3SApril Chin nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
2457c2fbfb3SApril Chin return(mp);
246da2e3ebdSchin }
247da2e3ebdSchin else
2487c2fbfb3SApril Chin {
249da2e3ebdSchin up = &mp->nvalue;
2507c2fbfb3SApril Chin if(nv_isvtree(mp))
2517c2fbfb3SApril Chin {
2527c2fbfb3SApril Chin if(!up->cp && flag==ARRAY_ASSIGN)
2537c2fbfb3SApril Chin {
2547c2fbfb3SApril Chin nv_arraychild(np,mp,0);
2557c2fbfb3SApril Chin ap->header.nelem++;
2567c2fbfb3SApril Chin }
2577c2fbfb3SApril Chin return(mp);
2587c2fbfb3SApril Chin }
2597c2fbfb3SApril Chin }
260da2e3ebdSchin }
261da2e3ebdSchin else
262da2e3ebdSchin {
263da2e3ebdSchin if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
264da2e3ebdSchin ap = array_grow(np, ap, (int)ap->cur);
265da2e3ebdSchin if(ap->cur>=ap->maxi)
266da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
267da2e3ebdSchin up = &(ap->val[ap->cur]);
2687c2fbfb3SApril Chin if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
2697c2fbfb3SApril Chin {
2707c2fbfb3SApril Chin char *cp;
2717c2fbfb3SApril Chin if(!ap->header.table)
2727c2fbfb3SApril Chin ap->header.table = dtopen(&_Nvdisc,Dtoset);
2737c2fbfb3SApril Chin sfprintf(sh.strbuf,"%d",ap->cur);
2747c2fbfb3SApril Chin cp = sfstruse(sh.strbuf);
2757c2fbfb3SApril Chin mp = nv_search(cp, ap->header.table, NV_ADD);
2767c2fbfb3SApril Chin mp->nvenv = (char*)np;
2777c2fbfb3SApril Chin nv_arraychild(np,mp,0);
2787c2fbfb3SApril Chin }
2797c2fbfb3SApril Chin if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
280da2e3ebdSchin {
281da2e3ebdSchin if(wasundef && nv_isarray(up->np))
282da2e3ebdSchin nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
283da2e3ebdSchin return(up->np);
284da2e3ebdSchin }
285da2e3ebdSchin }
286da2e3ebdSchin np->nvalue.cp = up->cp;
287da2e3ebdSchin if(!up->cp)
288da2e3ebdSchin {
289*3e14f97fSRoger A. Faulkner char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np);
290da2e3ebdSchin if(flag!=ARRAY_ASSIGN)
291*3e14f97fSRoger A. Faulkner return(xp && xp!=(char*)np?np:0);
2927c2fbfb3SApril Chin if(!array_covered(np,ap))
293da2e3ebdSchin ap->header.nelem++;
294da2e3ebdSchin }
295da2e3ebdSchin return(np);
296da2e3ebdSchin }
297da2e3ebdSchin
2987c2fbfb3SApril Chin #if SHOPT_TYPEDEF
nv_arraysettype(Namval_t * np,Namval_t * tp,const char * sub,int flags)2997c2fbfb3SApril Chin int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
3007c2fbfb3SApril Chin {
3017c2fbfb3SApril Chin Namval_t *nq;
3027c2fbfb3SApril Chin char *av[2];
3037c2fbfb3SApril Chin int rdonly = nv_isattr(np,NV_RDONLY);
3047c2fbfb3SApril Chin int xtrace = sh_isoption(SH_XTRACE);
3057c2fbfb3SApril Chin Namarr_t *ap = nv_arrayptr(np);
3067c2fbfb3SApril Chin av[1] = 0;
3077c2fbfb3SApril Chin sh.last_table = 0;
3087c2fbfb3SApril Chin if(!ap->table)
3097c2fbfb3SApril Chin ap->table = dtopen(&_Nvdisc,Dtoset);
3107c2fbfb3SApril Chin if(nq = nv_search(sub, ap->table, NV_ADD))
3117c2fbfb3SApril Chin {
3127c2fbfb3SApril Chin if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
3137c2fbfb3SApril Chin _nv_unset(nq,NV_RDONLY);
3147c2fbfb3SApril Chin nv_arraychild(np,nq,0);
3157c2fbfb3SApril Chin if(!nv_isattr(tp,NV_BINARY))
3167c2fbfb3SApril Chin {
3177c2fbfb3SApril Chin sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
3187c2fbfb3SApril Chin av[0] = strdup(sfstruse(sh.strbuf));
3197c2fbfb3SApril Chin }
3207c2fbfb3SApril Chin if(!nv_clone(tp,nq,flags|NV_NOFREE))
3217c2fbfb3SApril Chin return(0);
3227c2fbfb3SApril Chin ap->nelem |= ARRAY_SCAN;
3237c2fbfb3SApril Chin if(!rdonly)
3247c2fbfb3SApril Chin nv_offattr(nq,NV_RDONLY);
3257c2fbfb3SApril Chin if(!nv_isattr(tp,NV_BINARY))
3267c2fbfb3SApril Chin {
3277c2fbfb3SApril Chin if(xtrace)
3287c2fbfb3SApril Chin sh_offoption(SH_XTRACE);
3297c2fbfb3SApril Chin ap->nelem &= ~ARRAY_SCAN;
3307c2fbfb3SApril Chin sh_eval(sh_sfeval(av),0);
3317c2fbfb3SApril Chin ap->nelem |= ARRAY_SCAN;
3327c2fbfb3SApril Chin free((void*)av[0]);
3337c2fbfb3SApril Chin if(xtrace)
3347c2fbfb3SApril Chin sh_onoption(SH_XTRACE);
3357c2fbfb3SApril Chin }
3367c2fbfb3SApril Chin return(1);
3377c2fbfb3SApril Chin }
3387c2fbfb3SApril Chin return(0);
3397c2fbfb3SApril Chin }
3407c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
3417c2fbfb3SApril Chin
3427c2fbfb3SApril Chin
array_clone(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)343da2e3ebdSchin static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
344da2e3ebdSchin {
345da2e3ebdSchin Namarr_t *ap = (Namarr_t*)fp;
346da2e3ebdSchin Namval_t *nq, *mq;
347da2e3ebdSchin char *name, *sub=0;
3487c2fbfb3SApril Chin int nelem, skipped=0;
3497c2fbfb3SApril Chin Dt_t *otable=ap->table;
3507c2fbfb3SApril Chin struct index_array *aq = (struct index_array*)ap, *ar;
3517c2fbfb3SApril Chin Shell_t *shp = sh_getinterp();
3527c2fbfb3SApril Chin if(flags&NV_MOVE)
3537c2fbfb3SApril Chin {
3547c2fbfb3SApril Chin if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
3557c2fbfb3SApril Chin {
3567c2fbfb3SApril Chin do
3577c2fbfb3SApril Chin {
3587c2fbfb3SApril Chin if(nq=nv_opensub(np))
3597c2fbfb3SApril Chin nq->nvenv = (void*)mp;
3607c2fbfb3SApril Chin }
3617c2fbfb3SApril Chin while(nv_nextsub(np));
3627c2fbfb3SApril Chin }
3637c2fbfb3SApril Chin return(fp);
3647c2fbfb3SApril Chin }
3657c2fbfb3SApril Chin nelem = ap->nelem;
366da2e3ebdSchin if(nelem&ARRAY_NOCLONE)
367da2e3ebdSchin return(0);
3687c2fbfb3SApril Chin if((flags&NV_TYPE) && !ap->scope)
369da2e3ebdSchin {
3707c2fbfb3SApril Chin ap = array_scope(np,ap,flags);
3717c2fbfb3SApril Chin return(&ap->hdr);
372da2e3ebdSchin }
3737c2fbfb3SApril Chin ap = (Namarr_t*)nv_clone_disc(fp,0);
3747c2fbfb3SApril Chin if(flags&NV_COMVAR)
3757c2fbfb3SApril Chin {
3767c2fbfb3SApril Chin ap->scope = 0;
3777c2fbfb3SApril Chin ap->nelem = 0;
3787c2fbfb3SApril Chin sh.prev_table = sh.last_table;
3797c2fbfb3SApril Chin sh.prev_root = sh.last_root;
3807c2fbfb3SApril Chin }
3817c2fbfb3SApril Chin if(ap->table)
3827c2fbfb3SApril Chin {
3837c2fbfb3SApril Chin ap->table = dtopen(&_Nvdisc,Dtoset);
3847c2fbfb3SApril Chin if(ap->scope && !(flags&NV_COMVAR))
3857c2fbfb3SApril Chin {
3867c2fbfb3SApril Chin ap->scope = ap->table;
3877c2fbfb3SApril Chin dtview(ap->table, otable->view);
3887c2fbfb3SApril Chin }
3897c2fbfb3SApril Chin }
3907c2fbfb3SApril Chin mp->nvfun = (Namfun_t*)ap;
3917c2fbfb3SApril Chin mp->nvflag &= NV_MINIMAL;
3927c2fbfb3SApril Chin mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
393da2e3ebdSchin if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
394da2e3ebdSchin sub = strdup(sub);
395da2e3ebdSchin ar = (struct index_array*)ap;
3967c2fbfb3SApril Chin if(!is_associative(ap))
3977c2fbfb3SApril Chin ar->bits = (unsigned char*)&ar->val[ar->maxi];
3987c2fbfb3SApril Chin if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
3997c2fbfb3SApril Chin {
4007c2fbfb3SApril Chin if(ap->fun)
4017c2fbfb3SApril Chin (*ap->fun)(np,(char*)np,0);
4027c2fbfb3SApril Chin skipped=1;
4037c2fbfb3SApril Chin goto skip;
4047c2fbfb3SApril Chin }
405da2e3ebdSchin do
406da2e3ebdSchin {
407da2e3ebdSchin name = nv_getsub(np);
4087c2fbfb3SApril Chin nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
4097c2fbfb3SApril Chin mq = 0;
4107c2fbfb3SApril Chin if(nq=nv_opensub(np))
4117c2fbfb3SApril Chin mq = nv_search(name,ap->table,NV_ADD);
4127c2fbfb3SApril Chin if(nq && (flags&NV_COMVAR) && nv_isvtree(nq))
413da2e3ebdSchin {
4147c2fbfb3SApril Chin mq->nvalue.cp = 0;
4157c2fbfb3SApril Chin if(!is_associative(ap))
4167c2fbfb3SApril Chin ar->val[ar->cur].np = mq;
4177c2fbfb3SApril Chin nv_clone(nq,mq,flags);
418da2e3ebdSchin }
4197c2fbfb3SApril Chin else if(flags&NV_ARRAY)
420da2e3ebdSchin {
4217c2fbfb3SApril Chin if((flags&NV_NOFREE) && !is_associative(ap))
4227c2fbfb3SApril Chin array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
4237c2fbfb3SApril Chin else if(nq && (flags&NV_NOFREE))
4247c2fbfb3SApril Chin {
4257c2fbfb3SApril Chin mq->nvalue = nq->nvalue;
4267c2fbfb3SApril Chin nv_onattr(nq,NV_NOFREE);
427da2e3ebdSchin }
428da2e3ebdSchin }
429da2e3ebdSchin else if(nv_isattr(np,NV_INTEGER))
430da2e3ebdSchin {
431da2e3ebdSchin Sfdouble_t d= nv_getnum(np);
4327c2fbfb3SApril Chin if(!is_associative(ap))
4337c2fbfb3SApril Chin ar->val[ar->cur].cp = 0;
434da2e3ebdSchin nv_putval(mp,(char*)&d,NV_LDOUBLE);
435da2e3ebdSchin }
436da2e3ebdSchin else
4377c2fbfb3SApril Chin {
4387c2fbfb3SApril Chin if(!is_associative(ap))
4397c2fbfb3SApril Chin ar->val[ar->cur].cp = 0;
440da2e3ebdSchin nv_putval(mp,nv_getval(np),NV_RDONLY);
441da2e3ebdSchin }
4427c2fbfb3SApril Chin aq->header.nelem |= ARRAY_NOSCOPE;
4437c2fbfb3SApril Chin }
444da2e3ebdSchin while(nv_nextsub(np));
4457c2fbfb3SApril Chin skip:
446da2e3ebdSchin if(sub)
447da2e3ebdSchin {
4487c2fbfb3SApril Chin if(!skipped)
449da2e3ebdSchin nv_putsub(np,sub,0L);
450da2e3ebdSchin free((void*)sub);
451da2e3ebdSchin }
4527c2fbfb3SApril Chin aq->header.nelem = ap->nelem = nelem;
4537c2fbfb3SApril Chin return(&ap->hdr);
454da2e3ebdSchin }
455da2e3ebdSchin
array_getval(Namval_t * np,Namfun_t * disc)456da2e3ebdSchin static char *array_getval(Namval_t *np, Namfun_t *disc)
457da2e3ebdSchin {
4587c2fbfb3SApril Chin register Namarr_t *aq,*ap = (Namarr_t*)disc;
459da2e3ebdSchin register Namval_t *mp;
460da2e3ebdSchin if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
4617c2fbfb3SApril Chin {
4627c2fbfb3SApril Chin if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
4637c2fbfb3SApril Chin {
4647c2fbfb3SApril Chin array_syncsub(aq,ap);
4657c2fbfb3SApril Chin if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
4667c2fbfb3SApril Chin return(nv_getv(np,&aq->hdr));
4677c2fbfb3SApril Chin }
468da2e3ebdSchin return(mp?nv_getval(mp):0);
4697c2fbfb3SApril Chin }
470da2e3ebdSchin return(nv_getv(np,&ap->hdr));
471da2e3ebdSchin }
472da2e3ebdSchin
array_getnum(Namval_t * np,Namfun_t * disc)473da2e3ebdSchin static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
474da2e3ebdSchin {
4757c2fbfb3SApril Chin register Namarr_t *aq,*ap = (Namarr_t*)disc;
476da2e3ebdSchin register Namval_t *mp;
477da2e3ebdSchin if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
4787c2fbfb3SApril Chin {
4797c2fbfb3SApril Chin if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
4807c2fbfb3SApril Chin {
4817c2fbfb3SApril Chin array_syncsub(aq,ap);
4827c2fbfb3SApril Chin if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
4837c2fbfb3SApril Chin return(nv_getn(np,&aq->hdr));
4847c2fbfb3SApril Chin }
485da2e3ebdSchin return(mp?nv_getnum(mp):0);
4867c2fbfb3SApril Chin }
487da2e3ebdSchin return(nv_getn(np,&ap->hdr));
488da2e3ebdSchin }
489da2e3ebdSchin
array_putval(Namval_t * np,const char * string,int flags,Namfun_t * dp)490da2e3ebdSchin static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
491da2e3ebdSchin {
492da2e3ebdSchin register Namarr_t *ap = (Namarr_t*)dp;
493da2e3ebdSchin register union Value *up;
494da2e3ebdSchin register Namval_t *mp;
495da2e3ebdSchin register struct index_array *aq = (struct index_array*)ap;
4967c2fbfb3SApril Chin int scan,nofree = nv_isattr(np,NV_NOFREE);
497da2e3ebdSchin do
498da2e3ebdSchin {
499da2e3ebdSchin mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
5007c2fbfb3SApril Chin scan = ap->nelem&ARRAY_SCAN;
501da2e3ebdSchin if(mp && mp!=np)
5027c2fbfb3SApril Chin {
50334f9b3eeSRoland Mainz if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp))
5047c2fbfb3SApril Chin {
5057c2fbfb3SApril Chin if(!nv_isattr(np,NV_NOFREE))
5067c2fbfb3SApril Chin _nv_unset(mp,flags&NV_RDONLY);
5077c2fbfb3SApril Chin array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
5087c2fbfb3SApril Chin aq->val[aq->cur].cp = 0;
5097c2fbfb3SApril Chin if(!nv_isattr(mp,NV_NOFREE))
5107c2fbfb3SApril Chin nv_delete(mp,ap->table,0);
5117c2fbfb3SApril Chin goto skip;
5127c2fbfb3SApril Chin }
513da2e3ebdSchin nv_putval(mp, string, flags);
5147c2fbfb3SApril Chin if(string)
5157c2fbfb3SApril Chin {
5167c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5177c2fbfb3SApril Chin if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
5187c2fbfb3SApril Chin nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
5197c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
5207c2fbfb3SApril Chin continue;
5217c2fbfb3SApril Chin }
5227c2fbfb3SApril Chin ap->nelem |= scan;
5237c2fbfb3SApril Chin }
524da2e3ebdSchin if(!string)
525da2e3ebdSchin {
526da2e3ebdSchin if(mp)
527da2e3ebdSchin {
5287c2fbfb3SApril Chin if(is_associative(ap))
5297c2fbfb3SApril Chin {
5307c2fbfb3SApril Chin (*ap->fun)(np,NIL(char*),NV_ADELETE);
5317c2fbfb3SApril Chin np->nvalue.cp = 0;
5327c2fbfb3SApril Chin }
5337c2fbfb3SApril Chin else
5347c2fbfb3SApril Chin {
535da2e3ebdSchin if(mp!=np)
536da2e3ebdSchin {
5377c2fbfb3SApril Chin array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
538da2e3ebdSchin aq->val[aq->cur].cp = 0;
5397c2fbfb3SApril Chin nv_delete(mp,ap->table,0);
540da2e3ebdSchin }
5417c2fbfb3SApril Chin if(!array_covered(np,(struct index_array*)ap))
542da2e3ebdSchin ap->nelem--;
543da2e3ebdSchin }
5447c2fbfb3SApril Chin }
54534f9b3eeSRoland Mainz if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN))
546da2e3ebdSchin {
547da2e3ebdSchin if(is_associative(ap))
548da2e3ebdSchin (*ap->fun)(np, NIL(char*), NV_AFREE);
5497c2fbfb3SApril Chin else if(ap->table)
5507c2fbfb3SApril Chin dtclose(ap->table);
551da2e3ebdSchin nv_offattr(np,NV_ARRAY);
552da2e3ebdSchin }
5537c2fbfb3SApril Chin if(!mp || mp!=np || is_associative(ap))
554da2e3ebdSchin continue;
555da2e3ebdSchin }
5567c2fbfb3SApril Chin skip:
557da2e3ebdSchin /* prevent empty string from being deleted */
5587c2fbfb3SApril Chin up = array_getup(np,ap,!nofree);
5597c2fbfb3SApril Chin if(up->cp == Empty)
5607c2fbfb3SApril Chin up->cp = 0;
5617c2fbfb3SApril Chin if(nv_isarray(np))
5627c2fbfb3SApril Chin np->nvalue.up = up;
563da2e3ebdSchin nv_putv(np,string,flags,&ap->hdr);
5647c2fbfb3SApril Chin if(!is_associative(ap))
5657c2fbfb3SApril Chin {
5667c2fbfb3SApril Chin if(string)
5677c2fbfb3SApril Chin array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
5687c2fbfb3SApril Chin else if(mp==np)
5697c2fbfb3SApril Chin aq->val[aq->cur].cp = 0;
5707c2fbfb3SApril Chin }
5717c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5727c2fbfb3SApril Chin if(string && ap->hdr.type && nv_isvtree(np))
5737c2fbfb3SApril Chin nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
5747c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
575da2e3ebdSchin }
576da2e3ebdSchin while(!string && nv_nextsub(np));
5777c2fbfb3SApril Chin if(ap)
5787c2fbfb3SApril Chin ap->nelem &= ~ARRAY_NOSCOPE;
5797c2fbfb3SApril Chin if(nofree)
5807c2fbfb3SApril Chin nv_onattr(np,NV_NOFREE);
5817c2fbfb3SApril Chin else
5827c2fbfb3SApril Chin nv_offattr(np,NV_NOFREE);
583da2e3ebdSchin if(!string && !nv_isattr(np,NV_ARRAY))
584da2e3ebdSchin {
585da2e3ebdSchin Namfun_t *nfp;
5867c2fbfb3SApril Chin if(!is_associative(ap) && aq->xp)
5877c2fbfb3SApril Chin {
5887c2fbfb3SApril Chin _nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
5897c2fbfb3SApril Chin free((void*)aq->xp);
590da2e3ebdSchin }
5917c2fbfb3SApril Chin if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
5927c2fbfb3SApril Chin free((void*)nfp);
5937c2fbfb3SApril Chin if(!nv_isnull(np))
5947c2fbfb3SApril Chin {
5957c2fbfb3SApril Chin nv_onattr(np,NV_NOFREE);
5967c2fbfb3SApril Chin _nv_unset(np,flags);
5977c2fbfb3SApril Chin }
5987c2fbfb3SApril Chin if(np->nvalue.cp==Empty)
5997c2fbfb3SApril Chin np->nvalue.cp = 0;
6007c2fbfb3SApril Chin }
6017c2fbfb3SApril Chin if(!string && (flags&NV_TYPE))
6027c2fbfb3SApril Chin array_unscope(np,ap);
603da2e3ebdSchin }
604da2e3ebdSchin
605da2e3ebdSchin static const Namdisc_t array_disc =
606da2e3ebdSchin {
607da2e3ebdSchin sizeof(Namarr_t),
608da2e3ebdSchin array_putval,
609da2e3ebdSchin array_getval,
610da2e3ebdSchin array_getnum,
611da2e3ebdSchin 0,
612da2e3ebdSchin 0,
613da2e3ebdSchin array_clone
614da2e3ebdSchin };
615da2e3ebdSchin
array_copytree(Namval_t * np,Namval_t * mp)6167c2fbfb3SApril Chin static void array_copytree(Namval_t *np, Namval_t *mp)
6177c2fbfb3SApril Chin {
6187c2fbfb3SApril Chin Namfun_t *fp = nv_disc(np,NULL,NV_POP);
6197c2fbfb3SApril Chin nv_offattr(np,NV_ARRAY);
6207c2fbfb3SApril Chin nv_clone(np,mp,0);
62134f9b3eeSRoland Mainz if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE))
62234f9b3eeSRoland Mainz free((void*)np->nvalue.cp);
62334f9b3eeSRoland Mainz np->nvalue.cp = 0;
6247c2fbfb3SApril Chin np->nvalue.up = &mp->nvalue;
6257c2fbfb3SApril Chin fp->nofree &= ~1;
6267c2fbfb3SApril Chin nv_disc(np,(Namfun_t*)fp, NV_FIRST);
6277c2fbfb3SApril Chin fp->nofree |= 1;
6287c2fbfb3SApril Chin nv_onattr(np,NV_ARRAY);
6297c2fbfb3SApril Chin mp->nvenv = (char*)np;
6307c2fbfb3SApril Chin }
6317c2fbfb3SApril Chin
632da2e3ebdSchin /*
633da2e3ebdSchin * Increase the size of the indexed array of elements in <arp>
634da2e3ebdSchin * so that <maxi> is a legal index. If <arp> is 0, an array
635da2e3ebdSchin * of the required size is allocated. A pointer to the
636da2e3ebdSchin * allocated Namarr_t structure is returned.
637da2e3ebdSchin * <maxi> becomes the current index of the array.
638da2e3ebdSchin */
array_grow(Namval_t * np,register struct index_array * arp,int maxi)639da2e3ebdSchin static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
640da2e3ebdSchin {
641da2e3ebdSchin register struct index_array *ap;
6427c2fbfb3SApril Chin register int i;
6437c2fbfb3SApril Chin register int newsize = arsize(arp,maxi+1);
644da2e3ebdSchin if (maxi >= ARRAY_MAX)
645da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
6467c2fbfb3SApril Chin i = (newsize-1)*sizeof(union Value*)+newsize;
6477c2fbfb3SApril Chin ap = new_of(struct index_array,i);
6487c2fbfb3SApril Chin memset((void*)ap,0,sizeof(*ap)+i);
649da2e3ebdSchin ap->maxi = newsize;
650da2e3ebdSchin ap->cur = maxi;
651da2e3ebdSchin ap->bits = (unsigned char*)&ap->val[newsize];
6527c2fbfb3SApril Chin memset(ap->bits, 0, newsize);
653da2e3ebdSchin if(arp)
654da2e3ebdSchin {
655da2e3ebdSchin ap->header = arp->header;
6567c2fbfb3SApril Chin ap->header.hdr.dsize = sizeof(*ap) + i;
6577c2fbfb3SApril Chin for(i=0;i < arp->maxi;i++)
658da2e3ebdSchin ap->val[i].cp = arp->val[i].cp;
6597c2fbfb3SApril Chin memcpy(ap->bits, arp->bits, arp->maxi);
660da2e3ebdSchin array_setptr(np,arp,ap);
661da2e3ebdSchin free((void*)arp);
662da2e3ebdSchin }
663da2e3ebdSchin else
664da2e3ebdSchin {
6657c2fbfb3SApril Chin Namval_t *mp=0;
6667c2fbfb3SApril Chin ap->header.hdr.dsize = sizeof(*ap) + i;
6677c2fbfb3SApril Chin i = 0;
668da2e3ebdSchin ap->header.fun = 0;
6697c2fbfb3SApril Chin if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
670da2e3ebdSchin {
6717c2fbfb3SApril Chin i = ARRAY_TREE;
6727c2fbfb3SApril Chin nv_offattr(np,NV_NOFREE);
6737c2fbfb3SApril Chin }
6747c2fbfb3SApril Chin if(np->nvalue.cp==Empty)
6757c2fbfb3SApril Chin np->nvalue.cp=0;
6767c2fbfb3SApril Chin if(nv_hasdisc(np,&array_disc) || nv_isvtree(np))
6777c2fbfb3SApril Chin {
6787c2fbfb3SApril Chin ap->header.table = dtopen(&_Nvdisc,Dtoset);
67934f9b3eeSRoland Mainz mp = nv_search("0", ap->header.table,NV_ADD);
680da2e3ebdSchin if(mp && nv_isnull(mp))
681da2e3ebdSchin {
6827c2fbfb3SApril Chin Namfun_t *fp;
683da2e3ebdSchin ap->val[0].np = mp;
6847c2fbfb3SApril Chin array_setbit(ap->bits,0,ARRAY_CHILD);
6857c2fbfb3SApril Chin for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
68634f9b3eeSRoland Mainz if(fp && fp->disc && fp->disc->readf)
6877c2fbfb3SApril Chin (*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
688da2e3ebdSchin i++;
689da2e3ebdSchin }
6907c2fbfb3SApril Chin }
6917c2fbfb3SApril Chin else if((ap->val[0].cp=np->nvalue.cp))
6927c2fbfb3SApril Chin i++;
69334f9b3eeSRoland Mainz else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np))
694da2e3ebdSchin {
695da2e3ebdSchin Sfdouble_t d= nv_getnum(np);
696da2e3ebdSchin i++;
697da2e3ebdSchin }
698da2e3ebdSchin ap->header.nelem = i;
699da2e3ebdSchin ap->header.hdr.disc = &array_disc;
7007c2fbfb3SApril Chin nv_disc(np,(Namfun_t*)ap, NV_FIRST);
7017c2fbfb3SApril Chin nv_onattr(np,NV_ARRAY);
7027c2fbfb3SApril Chin if(mp)
7037c2fbfb3SApril Chin {
7047c2fbfb3SApril Chin array_copytree(np,mp);
7057c2fbfb3SApril Chin ap->header.hdr.nofree &= ~1;
7067c2fbfb3SApril Chin }
707da2e3ebdSchin }
708da2e3ebdSchin for(;i < newsize;i++)
709da2e3ebdSchin ap->val[i].cp = 0;
710da2e3ebdSchin return(ap);
711da2e3ebdSchin }
712da2e3ebdSchin
nv_atypeindex(Namval_t * np,const char * tname)7137c2fbfb3SApril Chin int nv_atypeindex(Namval_t *np, const char *tname)
7147c2fbfb3SApril Chin {
7157c2fbfb3SApril Chin Namval_t *tp;
7167c2fbfb3SApril Chin int offset = staktell();
7177c2fbfb3SApril Chin int n = strlen(tname)-1;
7187c2fbfb3SApril Chin sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
7197c2fbfb3SApril Chin tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
7207c2fbfb3SApril Chin stakseek(offset);
7217c2fbfb3SApril Chin if(tp)
7227c2fbfb3SApril Chin {
7237c2fbfb3SApril Chin struct index_array *ap = (struct index_array*)nv_arrayptr(np);
7247c2fbfb3SApril Chin if(!nv_hasdisc(tp,&ENUM_disc))
7257c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
7267c2fbfb3SApril Chin if(!ap)
7277c2fbfb3SApril Chin ap = array_grow(np,ap,1);
7287c2fbfb3SApril Chin ap->xp = calloc(NV_MINSZ,1);
7297c2fbfb3SApril Chin np = nv_namptr(ap->xp,0);
7307c2fbfb3SApril Chin np->nvname = tp->nvname;
7317c2fbfb3SApril Chin nv_onattr(np,NV_MINIMAL);
7327c2fbfb3SApril Chin nv_clone(tp,np,NV_NOFREE);
7337c2fbfb3SApril Chin nv_offattr(np,NV_RDONLY);
7347c2fbfb3SApril Chin return(1);
7357c2fbfb3SApril Chin }
7367c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
7377c2fbfb3SApril Chin return(0);
7387c2fbfb3SApril Chin }
7397c2fbfb3SApril Chin
nv_arrayptr(register Namval_t * np)740da2e3ebdSchin Namarr_t *nv_arrayptr(register Namval_t *np)
741da2e3ebdSchin {
742da2e3ebdSchin if(nv_isattr(np,NV_ARRAY))
743da2e3ebdSchin return((Namarr_t*)nv_hasdisc(np, &array_disc));
744da2e3ebdSchin return(0);
745da2e3ebdSchin }
746da2e3ebdSchin
747da2e3ebdSchin /*
748da2e3ebdSchin * Verify that argument is an indexed array and convert to associative,
749da2e3ebdSchin * freeing relevant storage
750da2e3ebdSchin */
nv_changearray(Namval_t * np,void * (* fun)(Namval_t *,const char *,int))751da2e3ebdSchin static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
752da2e3ebdSchin {
753da2e3ebdSchin register Namarr_t *ap;
754da2e3ebdSchin char numbuff[NUMSIZE+1];
755da2e3ebdSchin unsigned dot, digit, n;
756da2e3ebdSchin union Value *up;
757da2e3ebdSchin struct index_array *save_ap;
758da2e3ebdSchin register char *string_index=&numbuff[NUMSIZE];
759da2e3ebdSchin numbuff[NUMSIZE]='\0';
760da2e3ebdSchin
761da2e3ebdSchin if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
762da2e3ebdSchin return(NIL(Namarr_t*));
763da2e3ebdSchin
764da2e3ebdSchin nv_stack(np,&ap->hdr);
765da2e3ebdSchin save_ap = (struct index_array*)nv_stack(np,0);
766da2e3ebdSchin ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
767da2e3ebdSchin ap->nelem = 0;
768da2e3ebdSchin ap->fun = fun;
769da2e3ebdSchin nv_onattr(np,NV_ARRAY);
770da2e3ebdSchin
771da2e3ebdSchin for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
772da2e3ebdSchin {
773da2e3ebdSchin if(save_ap->val[dot].cp)
774da2e3ebdSchin {
775da2e3ebdSchin if ((digit = dot)== 0)
776da2e3ebdSchin *--string_index = '0';
777da2e3ebdSchin else while( n = digit )
778da2e3ebdSchin {
779da2e3ebdSchin digit /= 10;
780da2e3ebdSchin *--string_index = '0' + (n-10*digit);
781da2e3ebdSchin }
782da2e3ebdSchin nv_putsub(np, string_index, ARRAY_ADD);
783da2e3ebdSchin up = (union Value*)((*ap->fun)(np,NIL(char*),0));
784da2e3ebdSchin up->cp = save_ap->val[dot].cp;
785da2e3ebdSchin save_ap->val[dot].cp = 0;
786da2e3ebdSchin }
787da2e3ebdSchin string_index = &numbuff[NUMSIZE];
788da2e3ebdSchin }
789da2e3ebdSchin free((void*)save_ap);
790da2e3ebdSchin return(ap);
791da2e3ebdSchin }
792da2e3ebdSchin
793da2e3ebdSchin /*
794da2e3ebdSchin * set the associative array processing method for node <np> to <fun>
795da2e3ebdSchin * The array pointer is returned if sucessful.
796da2e3ebdSchin */
nv_setarray(Namval_t * np,void * (* fun)(Namval_t *,const char *,int))797da2e3ebdSchin Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
798da2e3ebdSchin {
799da2e3ebdSchin register Namarr_t *ap;
8007c2fbfb3SApril Chin char *value=0;
8017c2fbfb3SApril Chin Namfun_t *fp;
8027c2fbfb3SApril Chin int nelem = 0;
803da2e3ebdSchin if(fun && (ap = nv_arrayptr(np)))
804da2e3ebdSchin {
805da2e3ebdSchin /*
806da2e3ebdSchin * if it's already an indexed array, convert to
807da2e3ebdSchin * associative structure
808da2e3ebdSchin */
809da2e3ebdSchin if(!is_associative(ap))
810da2e3ebdSchin ap = nv_changearray(np, fun);
811da2e3ebdSchin return(ap);
812da2e3ebdSchin }
8137c2fbfb3SApril Chin if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
8147c2fbfb3SApril Chin {
8157c2fbfb3SApril Chin nelem = ARRAY_TREE;
8167c2fbfb3SApril Chin nv_offattr(np,NV_NOFREE);
8177c2fbfb3SApril Chin }
8187c2fbfb3SApril Chin if(!(fp=nv_isvtree(np)))
819da2e3ebdSchin value = nv_getval(np);
820da2e3ebdSchin if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
821da2e3ebdSchin {
822da2e3ebdSchin /* check for preexisting initialization and save */
8237c2fbfb3SApril Chin ap->nelem = nelem;
824da2e3ebdSchin ap->fun = fun;
825da2e3ebdSchin nv_onattr(np,NV_ARRAY);
8267c2fbfb3SApril Chin if(fp || value)
827da2e3ebdSchin {
828da2e3ebdSchin nv_putsub(np, "0", ARRAY_ADD);
8297c2fbfb3SApril Chin if(value)
830da2e3ebdSchin nv_putval(np, value, 0);
8317c2fbfb3SApril Chin else
8327c2fbfb3SApril Chin {
8337c2fbfb3SApril Chin Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
8347c2fbfb3SApril Chin array_copytree(np,mp);
8357c2fbfb3SApril Chin }
836da2e3ebdSchin }
837da2e3ebdSchin return(ap);
838da2e3ebdSchin }
839da2e3ebdSchin return(NIL(Namarr_t*));
840da2e3ebdSchin }
841da2e3ebdSchin
842da2e3ebdSchin /*
843da2e3ebdSchin * move parent subscript into child
844da2e3ebdSchin */
nv_arraychild(Namval_t * np,Namval_t * nq,int c)845da2e3ebdSchin Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
846da2e3ebdSchin {
8477c2fbfb3SApril Chin Namfun_t *fp;
848da2e3ebdSchin register Namarr_t *ap = nv_arrayptr(np);
849da2e3ebdSchin union Value *up;
8507c2fbfb3SApril Chin Namval_t *tp;
851da2e3ebdSchin if(!nq)
8527c2fbfb3SApril Chin return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
8537c2fbfb3SApril Chin if(!ap)
8547c2fbfb3SApril Chin {
8557c2fbfb3SApril Chin nv_putsub(np, NIL(char*), ARRAY_FILL);
8567c2fbfb3SApril Chin ap = nv_arrayptr(np);
8577c2fbfb3SApril Chin }
8587c2fbfb3SApril Chin if(!(up = array_getup(np,ap,0)))
8597c2fbfb3SApril Chin return((Namval_t*)0);
860da2e3ebdSchin np->nvalue.cp = up->cp;
8617c2fbfb3SApril Chin if((tp=nv_type(np)) || c)
8627c2fbfb3SApril Chin {
863da2e3ebdSchin ap->nelem |= ARRAY_NOCLONE;
8647c2fbfb3SApril Chin nq->nvenv = (char*)np;
8657c2fbfb3SApril Chin if(c=='t')
8667c2fbfb3SApril Chin nv_clone(tp,nq, 0);
8677c2fbfb3SApril Chin else
868da2e3ebdSchin nv_clone(np, nq, NV_NODISC);
869da2e3ebdSchin nv_offattr(nq,NV_ARRAY);
870da2e3ebdSchin ap->nelem &= ~ARRAY_NOCLONE;
871da2e3ebdSchin }
8727c2fbfb3SApril Chin nq->nvenv = (char*)np;
8737c2fbfb3SApril Chin if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
8747c2fbfb3SApril Chin free((void*)fp);
8757c2fbfb3SApril Chin if(!ap->fun)
876da2e3ebdSchin {
877da2e3ebdSchin struct index_array *aq = (struct index_array*)ap;
8787c2fbfb3SApril Chin array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
879da2e3ebdSchin up->np = nq;
880da2e3ebdSchin }
881da2e3ebdSchin if(c=='.')
882da2e3ebdSchin nv_setvtree(nq);
883da2e3ebdSchin return(nq);
884da2e3ebdSchin }
885da2e3ebdSchin
886da2e3ebdSchin /*
887da2e3ebdSchin * This routine sets subscript of <np> to the next element, if any.
888da2e3ebdSchin * The return value is zero, if there are no more elements
889da2e3ebdSchin * Otherwise, 1 is returned.
890da2e3ebdSchin */
nv_nextsub(Namval_t * np)891da2e3ebdSchin int nv_nextsub(Namval_t *np)
892da2e3ebdSchin {
893da2e3ebdSchin register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
894da2e3ebdSchin register unsigned dot;
8957c2fbfb3SApril Chin struct index_array *aq=0, *ar=0;
896da2e3ebdSchin if(!ap || !(ap->header.nelem&ARRAY_SCAN))
897da2e3ebdSchin return(0);
898da2e3ebdSchin if(is_associative(ap))
899da2e3ebdSchin {
9007c2fbfb3SApril Chin Namval_t *nq;
9017c2fbfb3SApril Chin if(nq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT))
902da2e3ebdSchin {
9037c2fbfb3SApril Chin if(nv_isattr(nq,NV_CHILD))
9047c2fbfb3SApril Chin nv_putsub(nq->nvalue.np,NIL(char*),ARRAY_UNDEF);
905da2e3ebdSchin return(1);
906da2e3ebdSchin }
907da2e3ebdSchin ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
908da2e3ebdSchin return(0);
909da2e3ebdSchin }
9107c2fbfb3SApril Chin if(!(ap->header.nelem&ARRAY_NOSCOPE))
9117c2fbfb3SApril Chin ar = (struct index_array*)ap->header.scope;
912da2e3ebdSchin for(dot=ap->cur+1; dot < (unsigned)ap->maxi; dot++)
913da2e3ebdSchin {
9147c2fbfb3SApril Chin aq = ap;
9157c2fbfb3SApril Chin if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
9167c2fbfb3SApril Chin {
9177c2fbfb3SApril Chin if(!(aq=ar) || dot>=(unsigned)aq->maxi)
9187c2fbfb3SApril Chin continue;
9197c2fbfb3SApril Chin }
9207c2fbfb3SApril Chin if(aq->val[dot].cp)
921da2e3ebdSchin {
922da2e3ebdSchin ap->cur = dot;
9237c2fbfb3SApril Chin if(array_isbit(aq->bits, dot,ARRAY_CHILD))
924da2e3ebdSchin {
9257c2fbfb3SApril Chin Namval_t *mp = aq->val[dot].np;
926*3e14f97fSRoger A. Faulkner if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize)
927da2e3ebdSchin continue;
928*3e14f97fSRoger A. Faulkner if(nv_isarray(mp))
9297c2fbfb3SApril Chin nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
930da2e3ebdSchin }
931da2e3ebdSchin return(1);
932da2e3ebdSchin }
933da2e3ebdSchin }
934da2e3ebdSchin ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
935da2e3ebdSchin ap->cur = 0;
936da2e3ebdSchin return(0);
937da2e3ebdSchin }
938da2e3ebdSchin
939da2e3ebdSchin /*
940da2e3ebdSchin * Set an array subscript for node <np> given the subscript <sp>
941da2e3ebdSchin * An array is created if necessary.
942da2e3ebdSchin * <mode> can be a number, plus or more of symbolic constants
943da2e3ebdSchin * ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
944da2e3ebdSchin * The node pointer is returned which can be NULL if <np> is
945da2e3ebdSchin * not already array and the ARRAY_ADD bit of <mode> is not set.
946da2e3ebdSchin * ARRAY_FILL sets the specified subscript to the empty string when
947da2e3ebdSchin * ARRAY_ADD is specified and there is no value or sets all
948da2e3ebdSchin * the elements up to the number specified if ARRAY_ADD is not specified
949da2e3ebdSchin */
nv_putsub(Namval_t * np,register char * sp,register long mode)950da2e3ebdSchin Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
951da2e3ebdSchin {
952da2e3ebdSchin register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
953da2e3ebdSchin register int size = (mode&ARRAY_MASK);
954da2e3ebdSchin if(!ap || !ap->header.fun)
955da2e3ebdSchin {
956da2e3ebdSchin if(sp)
9577c2fbfb3SApril Chin {
9587c2fbfb3SApril Chin if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
9597c2fbfb3SApril Chin {
9607c2fbfb3SApril Chin Namval_t *mp = nv_namptr(ap->xp,0);
9617c2fbfb3SApril Chin nv_putval(mp, sp,0);
9627c2fbfb3SApril Chin size = nv_getnum(mp);
9637c2fbfb3SApril Chin }
9647c2fbfb3SApril Chin else
965da2e3ebdSchin size = (int)sh_arith((char*)sp);
9667c2fbfb3SApril Chin }
9677c2fbfb3SApril Chin if(size <0 && ap)
9687c2fbfb3SApril Chin size += array_maxindex(np);
969da2e3ebdSchin if(size >= ARRAY_MAX || (size < 0))
970da2e3ebdSchin {
971da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
972da2e3ebdSchin return(NIL(Namval_t*));
973da2e3ebdSchin }
974da2e3ebdSchin if(!ap || size>=ap->maxi)
975da2e3ebdSchin {
976da2e3ebdSchin if(size==0 && !(mode&ARRAY_FILL))
977da2e3ebdSchin return(NIL(Namval_t*));
978da2e3ebdSchin if(sh.subshell)
979da2e3ebdSchin np = sh_assignok(np,1);
980da2e3ebdSchin ap = array_grow(np, ap,size);
981da2e3ebdSchin }
982da2e3ebdSchin ap->header.nelem &= ~ARRAY_UNDEF;
9837c2fbfb3SApril Chin ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
9847c2fbfb3SApril Chin #if 0
9857c2fbfb3SApril Chin if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
9867c2fbfb3SApril Chin mp = ap->val[oldsize].np;
9877c2fbfb3SApril Chin if(size != oldsize && mp->nvalue.cp)
9887c2fbfb3SApril Chin {
9897c2fbfb3SApril Chin Namfun_t *nfp;
9907c2fbfb3SApril Chin for(nfp=np->nvfun; nfp; nfp=nfp->next)
9917c2fbfb3SApril Chin {
9927c2fbfb3SApril Chin if(nfp->disc && nfp->disc->readf)
9937c2fbfb3SApril Chin {
9947c2fbfb3SApril Chin (*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
9957c2fbfb3SApril Chin break;
9967c2fbfb3SApril Chin }
9977c2fbfb3SApril Chin }
9987c2fbfb3SApril Chin }
9997c2fbfb3SApril Chin #endif
1000da2e3ebdSchin ap->cur = size;
10017c2fbfb3SApril Chin if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
1002da2e3ebdSchin np = 0;
10037c2fbfb3SApril Chin if(mode&(ARRAY_FILL|ARRAY_ADD))
1004da2e3ebdSchin {
1005da2e3ebdSchin if(!(mode&ARRAY_ADD))
1006da2e3ebdSchin {
1007da2e3ebdSchin int n;
10087c2fbfb3SApril Chin for(n=0; n <= size; n++)
1009da2e3ebdSchin {
1010da2e3ebdSchin if(!ap->val[n].cp)
10117c2fbfb3SApril Chin {
1012da2e3ebdSchin ap->val[n].cp = Empty;
10137c2fbfb3SApril Chin if(!array_covered(np,ap))
10147c2fbfb3SApril Chin ap->header.nelem++;
1015da2e3ebdSchin }
10167c2fbfb3SApril Chin }
1017da2e3ebdSchin if(n=ap->maxi-ap->maxi)
1018da2e3ebdSchin memset(&ap->val[size],0,n*sizeof(union Value));
1019da2e3ebdSchin }
1020da2e3ebdSchin else if(!ap->val[size].cp)
1021da2e3ebdSchin {
1022da2e3ebdSchin if(sh.subshell)
1023da2e3ebdSchin np = sh_assignok(np,1);
1024da2e3ebdSchin ap->val[size].cp = Empty;
10257c2fbfb3SApril Chin if(!array_covered(np,ap))
1026da2e3ebdSchin ap->header.nelem++;
1027da2e3ebdSchin }
1028da2e3ebdSchin }
1029da2e3ebdSchin else if(!(mode&ARRAY_SCAN))
1030da2e3ebdSchin {
1031da2e3ebdSchin ap->header.nelem &= ~ARRAY_SCAN;
10327c2fbfb3SApril Chin if(array_isbit(ap->bits,size,ARRAY_CHILD))
1033da2e3ebdSchin nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
10347c2fbfb3SApril Chin if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
10357c2fbfb3SApril Chin np = 0;
1036da2e3ebdSchin }
1037da2e3ebdSchin return((Namval_t*)np);
1038da2e3ebdSchin }
1039da2e3ebdSchin ap->header.nelem &= ~ARRAY_UNDEF;
1040da2e3ebdSchin if(!(mode&ARRAY_FILL))
1041da2e3ebdSchin ap->header.nelem &= ~ARRAY_SCAN;
10427c2fbfb3SApril Chin ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1043da2e3ebdSchin if(sp)
1044da2e3ebdSchin {
1045da2e3ebdSchin if(mode&ARRAY_SETSUB)
1046da2e3ebdSchin {
1047da2e3ebdSchin (*ap->header.fun)(np, sp, NV_ASETSUB);
1048da2e3ebdSchin return(np);
1049da2e3ebdSchin }
10507c2fbfb3SApril Chin (*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
10517c2fbfb3SApril Chin if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
10527c2fbfb3SApril Chin np = 0;
1053da2e3ebdSchin }
1054da2e3ebdSchin else if(mode&ARRAY_SCAN)
1055da2e3ebdSchin (*ap->header.fun)(np,(char*)np,0);
1056da2e3ebdSchin else if(mode&ARRAY_UNDEF)
1057da2e3ebdSchin (*ap->header.fun)(np, "",0);
1058da2e3ebdSchin if((mode&ARRAY_SCAN) && !nv_nextsub(np))
1059da2e3ebdSchin np = 0;
1060da2e3ebdSchin return(np);
1061da2e3ebdSchin }
1062da2e3ebdSchin
1063da2e3ebdSchin /*
1064da2e3ebdSchin * process an array subscript for node <np> given the subscript <cp>
1065da2e3ebdSchin * returns pointer to character after the subscript
1066da2e3ebdSchin */
nv_endsubscript(Namval_t * np,register char * cp,int mode)1067da2e3ebdSchin char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
1068da2e3ebdSchin {
1069da2e3ebdSchin register int count=1, quoted=0, c;
1070da2e3ebdSchin register char *sp = cp+1;
1071da2e3ebdSchin /* first find matching ']' */
1072da2e3ebdSchin while(count>0 && (c= *++cp))
1073da2e3ebdSchin {
1074da2e3ebdSchin if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
1075da2e3ebdSchin {
1076da2e3ebdSchin quoted=1;
1077da2e3ebdSchin cp++;
1078da2e3ebdSchin }
1079da2e3ebdSchin else if(c=='[')
1080da2e3ebdSchin count++;
1081da2e3ebdSchin else if(c==']')
1082da2e3ebdSchin count--;
1083da2e3ebdSchin }
1084da2e3ebdSchin *cp = 0;
1085da2e3ebdSchin if(quoted)
1086da2e3ebdSchin {
1087da2e3ebdSchin /* strip escape characters */
1088da2e3ebdSchin count = staktell();
1089da2e3ebdSchin stakwrite(sp,1+cp-sp);
1090da2e3ebdSchin sh_trim(sp=stakptr(count));
1091da2e3ebdSchin }
1092da2e3ebdSchin if(mode && np)
10937c2fbfb3SApril Chin {
109434f9b3eeSRoland Mainz Namarr_t *ap = nv_arrayptr(np);
109534f9b3eeSRoland Mainz int scan = 0;
109634f9b3eeSRoland Mainz if(ap)
109734f9b3eeSRoland Mainz scan = ap->nelem&ARRAY_SCAN;
10987c2fbfb3SApril Chin if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
10997c2fbfb3SApril Chin mode |= NV_ADD;
11007c2fbfb3SApril Chin nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
110134f9b3eeSRoland Mainz if(scan)
110234f9b3eeSRoland Mainz ap->nelem |= scan;
11037c2fbfb3SApril Chin }
1104da2e3ebdSchin if(quoted)
1105da2e3ebdSchin stakseek(count);
1106da2e3ebdSchin *cp++ = c;
1107da2e3ebdSchin return(cp);
1108da2e3ebdSchin }
1109da2e3ebdSchin
1110da2e3ebdSchin
nv_opensub(Namval_t * np)1111da2e3ebdSchin Namval_t *nv_opensub(Namval_t* np)
1112da2e3ebdSchin {
1113da2e3ebdSchin register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
11147c2fbfb3SApril Chin if(ap)
11157c2fbfb3SApril Chin {
11167c2fbfb3SApril Chin if(is_associative(ap))
1117da2e3ebdSchin return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
11187c2fbfb3SApril Chin else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
11197c2fbfb3SApril Chin return(ap->val[ap->cur].np);
11207c2fbfb3SApril Chin }
1121da2e3ebdSchin return(NIL(Namval_t*));
1122da2e3ebdSchin }
1123da2e3ebdSchin
nv_getsub(Namval_t * np)1124da2e3ebdSchin char *nv_getsub(Namval_t* np)
1125da2e3ebdSchin {
1126da2e3ebdSchin static char numbuff[NUMSIZE];
1127da2e3ebdSchin register struct index_array *ap;
1128da2e3ebdSchin register unsigned dot, n;
1129da2e3ebdSchin register char *cp = &numbuff[NUMSIZE];
1130da2e3ebdSchin if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
1131da2e3ebdSchin return(NIL(char*));
1132da2e3ebdSchin if(is_associative(ap))
1133da2e3ebdSchin return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
11347c2fbfb3SApril Chin if(ap->xp)
11357c2fbfb3SApril Chin {
11367c2fbfb3SApril Chin np = nv_namptr(ap->xp,0);
11377c2fbfb3SApril Chin np->nvalue.s = ap->cur;
11387c2fbfb3SApril Chin return(nv_getval(np));
11397c2fbfb3SApril Chin }
1140da2e3ebdSchin if((dot = ap->cur)==0)
1141da2e3ebdSchin *--cp = '0';
1142da2e3ebdSchin else while(n=dot)
1143da2e3ebdSchin {
1144da2e3ebdSchin dot /= 10;
1145da2e3ebdSchin *--cp = '0' + (n-10*dot);
1146da2e3ebdSchin }
1147da2e3ebdSchin return(cp);
1148da2e3ebdSchin }
1149da2e3ebdSchin
1150da2e3ebdSchin /*
1151da2e3ebdSchin * If <np> is an indexed array node, the current subscript index
1152da2e3ebdSchin * returned, otherwise returns -1
1153da2e3ebdSchin */
nv_aindex(register Namval_t * np)1154da2e3ebdSchin int nv_aindex(register Namval_t* np)
1155da2e3ebdSchin {
1156da2e3ebdSchin Namarr_t *ap = nv_arrayptr(np);
11577c2fbfb3SApril Chin if(!ap)
11587c2fbfb3SApril Chin return(0);
11597c2fbfb3SApril Chin else if(is_associative(ap))
1160da2e3ebdSchin return(-1);
1161da2e3ebdSchin return(((struct index_array*)(ap))->cur&ARRAY_MASK);
1162da2e3ebdSchin }
1163da2e3ebdSchin
nv_arraynsub(register Namarr_t * ap)11647c2fbfb3SApril Chin int nv_arraynsub(register Namarr_t* ap)
11657c2fbfb3SApril Chin {
11667c2fbfb3SApril Chin return(array_elem(ap));
11677c2fbfb3SApril Chin }
11687c2fbfb3SApril Chin
nv_aimax(register Namval_t * np)11697c2fbfb3SApril Chin int nv_aimax(register Namval_t* np)
11707c2fbfb3SApril Chin {
11717c2fbfb3SApril Chin struct index_array *ap = (struct index_array*)nv_arrayptr(np);
11727c2fbfb3SApril Chin int sub = -1;
11737c2fbfb3SApril Chin if(!ap || is_associative(&ap->header))
11747c2fbfb3SApril Chin return(-1);
11757c2fbfb3SApril Chin sub = ap->maxi;
11767c2fbfb3SApril Chin while(--sub>0 && ap->val[sub].cp==0);
11777c2fbfb3SApril Chin return(sub);
11787c2fbfb3SApril Chin }
1179da2e3ebdSchin
1180da2e3ebdSchin /*
11817c2fbfb3SApril Chin * This is the default implementation for associative arrays
1182da2e3ebdSchin */
nv_associative(register Namval_t * np,const char * sp,int mode)1183da2e3ebdSchin void *nv_associative(register Namval_t *np,const char *sp,int mode)
1184da2e3ebdSchin {
1185da2e3ebdSchin register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
1186da2e3ebdSchin register int type;
1187da2e3ebdSchin switch(mode)
1188da2e3ebdSchin {
1189da2e3ebdSchin case NV_AINIT:
1190da2e3ebdSchin if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
1191da2e3ebdSchin {
11927c2fbfb3SApril Chin ap->header.table = dtopen(&_Nvdisc,Dtoset);
1193da2e3ebdSchin ap->cur = 0;
1194da2e3ebdSchin ap->pos = 0;
1195da2e3ebdSchin ap->header.hdr.disc = &array_disc;
11967c2fbfb3SApril Chin nv_disc(np,(Namfun_t*)ap, NV_FIRST);
11977c2fbfb3SApril Chin ap->header.hdr.dsize = sizeof(struct assoc_array);
11987c2fbfb3SApril Chin ap->header.hdr.nofree &= ~1;
1199da2e3ebdSchin }
1200da2e3ebdSchin return((void*)ap);
1201da2e3ebdSchin case NV_ADELETE:
1202da2e3ebdSchin if(ap->cur)
1203da2e3ebdSchin {
12047c2fbfb3SApril Chin if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0))
12057c2fbfb3SApril Chin ap->header.nelem--;
12067c2fbfb3SApril Chin _nv_unset(ap->cur,NV_RDONLY);
12077c2fbfb3SApril Chin nv_delete(ap->cur,ap->header.table,0);
1208da2e3ebdSchin ap->cur = 0;
1209da2e3ebdSchin }
1210da2e3ebdSchin return((void*)ap);
1211da2e3ebdSchin case NV_AFREE:
1212da2e3ebdSchin ap->pos = 0;
12137c2fbfb3SApril Chin if(ap->header.scope)
12147c2fbfb3SApril Chin {
12157c2fbfb3SApril Chin ap->header.table = dtview(ap->header.table,(Dt_t*)0);
12167c2fbfb3SApril Chin dtclose(ap->header.scope);
12177c2fbfb3SApril Chin ap->header.scope = 0;
12187c2fbfb3SApril Chin }
12197c2fbfb3SApril Chin else
12207c2fbfb3SApril Chin dtclose(ap->header.table);
1221da2e3ebdSchin return((void*)ap);
1222da2e3ebdSchin case NV_ANEXT:
1223da2e3ebdSchin if(!ap->pos)
1224da2e3ebdSchin {
12257c2fbfb3SApril Chin if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
12267c2fbfb3SApril Chin {
12277c2fbfb3SApril Chin ap->header.scope = dtvnext(ap->header.table);
12287c2fbfb3SApril Chin ap->header.table->view = 0;
12297c2fbfb3SApril Chin }
1230da2e3ebdSchin if(!(ap->pos=ap->cur))
12317c2fbfb3SApril Chin ap->pos = (Namval_t*)dtfirst(ap->header.table);
1232da2e3ebdSchin }
1233da2e3ebdSchin else
1234da2e3ebdSchin ap->pos = ap->nextpos;
1235da2e3ebdSchin for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
1236da2e3ebdSchin {
12377c2fbfb3SApril Chin ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
1238da2e3ebdSchin if(ap->cur->nvalue.cp)
1239da2e3ebdSchin {
1240da2e3ebdSchin if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
1241da2e3ebdSchin continue;
1242da2e3ebdSchin return((void*)ap);
1243da2e3ebdSchin }
1244da2e3ebdSchin }
12457c2fbfb3SApril Chin if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
12467c2fbfb3SApril Chin {
12477c2fbfb3SApril Chin ap->header.table->view = (Dt_t*)ap->header.scope;
12487c2fbfb3SApril Chin ap->header.scope = ap->header.table;
12497c2fbfb3SApril Chin }
1250da2e3ebdSchin return(NIL(void*));
1251da2e3ebdSchin case NV_ASETSUB:
1252da2e3ebdSchin ap->cur = (Namval_t*)sp;
12537c2fbfb3SApril Chin return((void*)ap->cur);
1254da2e3ebdSchin case NV_ACURRENT:
12557c2fbfb3SApril Chin if(ap->cur)
12567c2fbfb3SApril Chin ap->cur->nvenv = (char*)np;
1257da2e3ebdSchin return((void*)ap->cur);
1258da2e3ebdSchin case NV_ANAME:
1259da2e3ebdSchin if(ap->cur)
1260*3e14f97fSRoger A. Faulkner {
1261*3e14f97fSRoger A. Faulkner Shell_t *shp = sh_getinterp();
1262*3e14f97fSRoger A. Faulkner if(!shp->instance && nv_isnull(ap->cur))
1263*3e14f97fSRoger A. Faulkner return(NIL(void*));
12647c2fbfb3SApril Chin return((void*)ap->cur->nvname);
1265*3e14f97fSRoger A. Faulkner }
1266da2e3ebdSchin return(NIL(void*));
1267da2e3ebdSchin default:
1268da2e3ebdSchin if(sp)
1269da2e3ebdSchin {
12707c2fbfb3SApril Chin Namval_t *mp=0;
1271da2e3ebdSchin ap->cur = 0;
12727c2fbfb3SApril Chin if(sp==(char*)np)
1273da2e3ebdSchin return(0);
12747c2fbfb3SApril Chin type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
12757c2fbfb3SApril Chin if(mode)
12767c2fbfb3SApril Chin mode = NV_ADD|HASH_NOSCOPE;
12777c2fbfb3SApril Chin else if(ap->header.nelem&ARRAY_NOSCOPE)
12787c2fbfb3SApril Chin mode = HASH_NOSCOPE;
1279*3e14f97fSRoger A. Faulkner if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD))
128034f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript");
12817c2fbfb3SApril Chin if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
12827c2fbfb3SApril Chin ap->cur = mp;
12837c2fbfb3SApril Chin if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
12847c2fbfb3SApril Chin {
12857c2fbfb3SApril Chin nv_onattr(mp,type);
12867c2fbfb3SApril Chin mp->nvenv = (char*)np;
12877c2fbfb3SApril Chin if((mode&NV_ADD) && nv_type(np))
12887c2fbfb3SApril Chin nv_arraychild(np,mp,0);
12897c2fbfb3SApril Chin if(sh.subshell)
12907c2fbfb3SApril Chin np = sh_assignok(np,1);
12917c2fbfb3SApril Chin if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
12927c2fbfb3SApril Chin ap->header.nelem++;
12937c2fbfb3SApril Chin if(nv_isnull(mp))
12947c2fbfb3SApril Chin {
12957c2fbfb3SApril Chin if(ap->header.nelem&ARRAY_TREE)
12967c2fbfb3SApril Chin nv_setvtree(mp);
12977c2fbfb3SApril Chin mp->nvalue.cp = Empty;
1298da2e3ebdSchin }
12997c2fbfb3SApril Chin }
13007c2fbfb3SApril Chin else if(ap->header.nelem&ARRAY_SCAN)
13017c2fbfb3SApril Chin {
13027c2fbfb3SApril Chin Namval_t fake;
13037c2fbfb3SApril Chin fake.nvname = (char*)sp;
13047c2fbfb3SApril Chin ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
13057c2fbfb3SApril Chin ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
13067c2fbfb3SApril Chin }
1307*3e14f97fSRoger A. Faulkner else if(!mp && *sp && mode==0)
1308*3e14f97fSRoger A. Faulkner mp = nv_search(sp,ap->header.table,NV_ADD);
13097c2fbfb3SApril Chin np = mp;
131034f9b3eeSRoland Mainz if(ap->pos && ap->pos==np)
131134f9b3eeSRoland Mainz ap->header.nelem |= ARRAY_SCAN;
131234f9b3eeSRoland Mainz else if(!(ap->header.nelem&ARRAY_SCAN))
1313da2e3ebdSchin ap->pos = 0;
1314da2e3ebdSchin ap->cur = np;
1315da2e3ebdSchin }
1316da2e3ebdSchin if(ap->cur)
1317da2e3ebdSchin return((void*)(&ap->cur->nvalue));
1318da2e3ebdSchin else
1319da2e3ebdSchin return((void*)(&ap->cur));
1320da2e3ebdSchin }
1321da2e3ebdSchin }
1322da2e3ebdSchin
1323da2e3ebdSchin /*
1324da2e3ebdSchin * Assign values to an array
1325da2e3ebdSchin */
nv_setvec(register Namval_t * np,int append,register int argc,register char * argv[])1326da2e3ebdSchin void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
1327da2e3ebdSchin {
1328da2e3ebdSchin int arg0=0;
13297c2fbfb3SApril Chin struct index_array *ap=0,*aq;
1330da2e3ebdSchin if(nv_isarray(np))
1331da2e3ebdSchin {
1332da2e3ebdSchin ap = (struct index_array*)nv_arrayptr(np);
1333da2e3ebdSchin if(ap && is_associative(ap))
13347c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
1335da2e3ebdSchin }
1336da2e3ebdSchin if(append)
1337da2e3ebdSchin {
1338da2e3ebdSchin if(ap)
1339da2e3ebdSchin {
13407c2fbfb3SApril Chin if(!(aq = (struct index_array*)ap->header.scope))
13417c2fbfb3SApril Chin aq = ap;
1342da2e3ebdSchin arg0 = ap->maxi;
13437c2fbfb3SApril Chin while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
1344da2e3ebdSchin arg0++;
1345da2e3ebdSchin }
1346da2e3ebdSchin else if(!nv_isnull(np))
1347da2e3ebdSchin arg0=1;
1348da2e3ebdSchin }
1349da2e3ebdSchin while(--argc >= 0)
1350da2e3ebdSchin {
13517c2fbfb3SApril Chin nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
1352da2e3ebdSchin nv_putval(np,argv[argc],0);
1353da2e3ebdSchin }
1354da2e3ebdSchin }
1355da2e3ebdSchin
1356