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