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