1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * Array processing routines
26 * dgk@research.att.com
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
41 #define ARRAY_NOFREE 2
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 */
61 static Namarr_t
*array_scope(Namval_t
*np
, Namarr_t
*ap
, int flags
)
64 struct index_array
*ar
;
65 size_t size
= ap
->hdr
.dsize
;
67 size
= ap
->hdr
.disc
->dsize
;
68 if(!(aq
=newof(NIL(Namarr_t
*),Namarr_t
,1,size
-sizeof(Namarr_t
))))
72 aq
->hdr
.nofree
|= (flags
&NV_RDONLY
)?1:0;
73 if(is_associative(aq
))
75 aq
->scope
= (void*)dtopen(&_Nvdisc
,Dtoset
);
76 dtview((Dt_t
*)aq
->scope
,aq
->table
);
77 aq
->table
= (Dt_t
*)aq
->scope
;
80 aq
->scope
= (void*)ap
;
81 ar
= (struct index_array
*)aq
;
82 memset(ar
->val
, 0, ar
->maxi
*sizeof(char*));
86 static int array_unscope(Namval_t
*np
,Namarr_t
*ap
)
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))
95 nv_delete(np
,(Dt_t
*)0,0);
99 static void array_syncsub(Namarr_t
*ap
, Namarr_t
*aq
)
101 ((struct index_array
*)ap
)->cur
= ((struct index_array
*)aq
)->cur
;
104 static int array_covered(Namval_t
*np
, struct index_array
*ap
)
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
);
113 * replace discipline with new one
115 static void array_setptr(register Namval_t
*np
, struct index_array
*old
, struct index_array
*new)
117 register Namfun_t
**fp
= &np
->nvfun
;
118 while(*fp
&& *fp
!= &old
->header
.hdr
)
122 new->header
.hdr
.next
= (*fp
)->next
;
123 *fp
= &new->header
.hdr
;
125 else sfprintf(sfstderr
,"discipline not replaced\n");
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.
135 static int arsize(struct index_array
*ap
, register int maxi
)
137 if(ap
&& maxi
< 2*ap
->maxi
)
139 maxi
= roundof(maxi
,ARRAY_INCR
);
140 return (maxi
>ARRAY_MAX
?ARRAY_MAX
:maxi
);
143 static struct index_array
*array_grow(Namval_t
*, struct index_array
*,int);
145 /* return index of highest element of an array */
146 int array_maxindex(Namval_t
*np
)
148 register struct index_array
*ap
= (struct index_array
*)nv_arrayptr(np
);
149 register int i
= ap
->maxi
;
150 if(is_associative(ap
))
152 while(i
>0 && ap
->val
[--i
].cp
==0);
156 static union Value
*array_getup(Namval_t
*np
, Namarr_t
*arp
, int update
)
158 register struct index_array
*ap
= (struct index_array
*)arp
;
159 register union Value
*up
;
163 if(is_associative(ap
))
166 mp
= (Namval_t
*)((*arp
->fun
)(np
,NIL(char*),NV_ACURRENT
));
169 nofree
= nv_isattr(mp
,NV_NOFREE
);
173 return((union Value
*)((*arp
->fun
)(np
,NIL(char*),0)));
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
);
185 nv_onattr(np
,NV_NOFREE
);
187 nv_offattr(np
,NV_NOFREE
);
192 int nv_arrayisset(Namval_t
*np
, Namarr_t
*arp
)
194 register struct index_array
*ap
= (struct index_array
*)arp
;
196 if(is_associative(ap
))
197 return((np
= nv_opensub(np
)) && !nv_isnull(np
));
198 if(ap
->cur
>= ap
->maxi
)
200 up
= &(ap
->val
[ap
->cur
]);
201 return(up
->cp
&& up
->cp
!=Empty
);
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
209 static Namval_t
*array_find(Namval_t
*np
,Namarr_t
*arp
, int flag
)
211 register struct index_array
*ap
= (struct index_array
*)arp
;
212 register union Value
*up
;
215 if(flag
&ARRAY_LOOKUP
)
216 ap
->header
.nelem
&= ~ARRAY_NOSCOPE
;
218 ap
->header
.nelem
|= ARRAY_NOSCOPE
;
219 if(wasundef
= ap
->header
.nelem
&ARRAY_UNDEF
)
221 ap
->header
.nelem
&= ~ARRAY_UNDEF
;
222 /* delete array is the same as delete array[@] */
223 if(flag
&ARRAY_DELETE
)
225 nv_putsub(np
, NIL(char*), ARRAY_SCAN
|ARRAY_NOSCOPE
);
226 ap
->header
.nelem
|= ARRAY_SCAN
;
228 else /* same as array[0] */
230 if(is_associative(ap
))
231 (*ap
->header
.fun
)(np
,"0",flag
==ARRAY_ASSIGN
?NV_AADD
:0);
236 if(is_associative(ap
))
238 mp
= (Namval_t
*)((*arp
->fun
)(np
,NIL(char*),NV_ACURRENT
));
240 up
= (union Value
*)&mp
;
241 else if(nv_isarray(mp
))
244 nv_putsub(mp
,NIL(char*),ARRAY_UNDEF
);
252 if(!up
->cp
&& flag
==ARRAY_ASSIGN
)
254 nv_arraychild(np
,mp
,0);
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
))
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);
279 if(up
->np
&& array_isbit(ap
->bits
,ap
->cur
,ARRAY_CHILD
))
281 if(wasundef
&& nv_isarray(up
->np
))
282 nv_putsub(up
->np
,NIL(char*),ARRAY_UNDEF
);
286 np
->nvalue
.cp
= up
->cp
;
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
))
299 int nv_arraysettype(Namval_t
*np
, Namval_t
*tp
, const char *sub
, int flags
)
303 int rdonly
= nv_isattr(np
,NV_RDONLY
);
304 int xtrace
= sh_isoption(SH_XTRACE
);
305 Namarr_t
*ap
= nv_arrayptr(np
);
309 ap
->table
= dtopen(&_Nvdisc
,Dtoset
);
310 if(nq
= nv_search(sub
, ap
->table
, NV_ADD
))
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
))
317 sfprintf(sh
.strbuf
,"%s=%s",nv_name(nq
),nv_getval(np
));
318 av
[0] = strdup(sfstruse(sh
.strbuf
));
320 if(!nv_clone(tp
,nq
,flags
|NV_NOFREE
))
322 ap
->nelem
|= ARRAY_SCAN
;
324 nv_offattr(nq
,NV_RDONLY
);
325 if(!nv_isattr(tp
,NV_BINARY
))
328 sh_offoption(SH_XTRACE
);
329 ap
->nelem
&= ~ARRAY_SCAN
;
330 sh_eval(sh_sfeval(av
),0);
331 ap
->nelem
|= ARRAY_SCAN
;
334 sh_onoption(SH_XTRACE
);
340 #endif /* SHOPT_TYPEDEF */
343 static Namfun_t
*array_clone(Namval_t
*np
, Namval_t
*mp
, int flags
, Namfun_t
*fp
)
345 Namarr_t
*ap
= (Namarr_t
*)fp
;
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();
354 if((flags
&NV_COMVAR
) && nv_putsub(np
,NIL(char*),ARRAY_SCAN
))
358 if(nq
=nv_opensub(np
))
359 nq
->nvenv
= (void*)mp
;
361 while(nv_nextsub(np
));
366 if(nelem
&ARRAY_NOCLONE
)
368 if((flags
&NV_TYPE
) && !ap
->scope
)
370 ap
= array_scope(np
,ap
,flags
);
373 ap
= (Namarr_t
*)nv_clone_disc(fp
,0);
378 sh
.prev_table
= sh
.last_table
;
379 sh
.prev_root
= sh
.last_root
;
383 ap
->table
= dtopen(&_Nvdisc
,Dtoset
);
384 if(ap
->scope
&& !(flags
&NV_COMVAR
))
386 ap
->scope
= ap
->table
;
387 dtview(ap
->table
, otable
->view
);
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
)))
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
)))
401 (*ap
->fun
)(np
,(char*)np
,0);
407 name
= nv_getsub(np
);
408 nv_putsub(mp
,name
,ARRAY_ADD
|ARRAY_NOSCOPE
);
410 if(nq
=nv_opensub(np
))
411 mq
= nv_search(name
,ap
->table
,NV_ADD
);
412 if(nq
&& (flags
&NV_COMVAR
) && nv_isvtree(nq
))
415 if(!is_associative(ap
))
416 ar
->val
[ar
->cur
].np
= mq
;
417 nv_clone(nq
,mq
,flags
);
419 else if(flags
&NV_ARRAY
)
421 if((flags
&NV_NOFREE
) && !is_associative(ap
))
422 array_setbit(aq
->bits
,aq
->cur
,ARRAY_NOFREE
);
423 else if(nq
&& (flags
&NV_NOFREE
))
425 mq
->nvalue
= nq
->nvalue
;
426 nv_onattr(nq
,NV_NOFREE
);
429 else if(nv_isattr(np
,NV_INTEGER
))
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
);
438 if(!is_associative(ap
))
439 ar
->val
[ar
->cur
].cp
= 0;
440 nv_putval(mp
,nv_getval(np
),NV_RDONLY
);
442 aq
->header
.nelem
|= ARRAY_NOSCOPE
;
444 while(nv_nextsub(np
));
449 nv_putsub(np
,sub
,0L);
452 aq
->header
.nelem
= ap
->nelem
= nelem
;
456 static char *array_getval(Namval_t
*np
, Namfun_t
*disc
)
458 register Namarr_t
*aq
,*ap
= (Namarr_t
*)disc
;
459 register Namval_t
*mp
;
460 if((mp
=array_find(np
,ap
,ARRAY_LOOKUP
))!=np
)
462 if(!mp
&& !is_associative(ap
) && (aq
=(Namarr_t
*)ap
->scope
))
464 array_syncsub(aq
,ap
);
465 if((mp
=array_find(np
,aq
,ARRAY_LOOKUP
))==np
)
466 return(nv_getv(np
,&aq
->hdr
));
468 return(mp
?nv_getval(mp
):0);
470 return(nv_getv(np
,&ap
->hdr
));
473 static Sfdouble_t
array_getnum(Namval_t
*np
, Namfun_t
*disc
)
475 register Namarr_t
*aq
,*ap
= (Namarr_t
*)disc
;
476 register Namval_t
*mp
;
477 if((mp
=array_find(np
,ap
,ARRAY_LOOKUP
))!=np
)
479 if(!mp
&& !is_associative(ap
) && (aq
=(Namarr_t
*)ap
->scope
))
481 array_syncsub(aq
,ap
);
482 if((mp
=array_find(np
,aq
,ARRAY_LOOKUP
))==np
)
483 return(nv_getn(np
,&aq
->hdr
));
485 return(mp
?nv_getnum(mp
):0);
487 return(nv_getn(np
,&ap
->hdr
));
490 static void array_putval(Namval_t
*np
, const char *string
, int flags
, Namfun_t
*dp
)
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
);
499 mp
= array_find(np
,ap
,string
?ARRAY_ASSIGN
:ARRAY_DELETE
);
500 scan
= ap
->nelem
&ARRAY_SCAN
;
503 if(!is_associative(ap
) && string
&& !(flags
&NV_APPEND
) && !nv_type(np
) && nv_isvtree(mp
))
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);
513 nv_putval(mp
, string
, flags
);
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 */
528 if(is_associative(ap
))
530 (*ap
->fun
)(np
,NIL(char*),NV_ADELETE
);
537 array_clrbit(aq
->bits
,aq
->cur
,ARRAY_CHILD
);
538 aq
->val
[aq
->cur
].cp
= 0;
539 nv_delete(mp
,ap
->table
,0);
541 if(!array_covered(np
,(struct index_array
*)ap
))
545 if(array_elem(ap
)==0 && (ap
->nelem
&ARRAY_SCAN
))
547 if(is_associative(ap
))
548 (*ap
->fun
)(np
, NIL(char*), NV_AFREE
);
551 nv_offattr(np
,NV_ARRAY
);
553 if(!mp
|| mp
!=np
|| is_associative(ap
))
557 /* prevent empty string from being deleted */
558 up
= array_getup(np
,ap
,!nofree
);
563 nv_putv(np
,string
,flags
,&ap
->hdr
);
564 if(!is_associative(ap
))
567 array_clrbit(aq
->bits
,aq
->cur
,ARRAY_NOFREE
);
569 aq
->val
[aq
->cur
].cp
= 0;
572 if(string
&& ap
->hdr
.type
&& nv_isvtree(np
))
573 nv_arraysettype(np
,ap
->hdr
.type
,nv_getsub(np
),0);
574 #endif /* SHOPT_TYPEDEF */
576 while(!string
&& nv_nextsub(np
));
578 ap
->nelem
&= ~ARRAY_NOSCOPE
;
580 nv_onattr(np
,NV_NOFREE
);
582 nv_offattr(np
,NV_NOFREE
);
583 if(!string
&& !nv_isattr(np
,NV_ARRAY
))
586 if(!is_associative(ap
) && aq
->xp
)
588 _nv_unset(nv_namptr(aq
->xp
,0),NV_RDONLY
);
591 if((nfp
= nv_disc(np
,(Namfun_t
*)ap
,NV_POP
)) && !(nfp
->nofree
&1))
595 nv_onattr(np
,NV_NOFREE
);
598 if(np
->nvalue
.cp
==Empty
)
601 if(!string
&& (flags
&NV_TYPE
))
602 array_unscope(np
,ap
);
605 static const Namdisc_t array_disc
=
616 static void array_copytree(Namval_t
*np
, Namval_t
*mp
)
618 Namfun_t
*fp
= nv_disc(np
,NULL
,NV_POP
);
619 nv_offattr(np
,NV_ARRAY
);
621 if(np
->nvalue
.cp
&& !nv_isattr(np
,NV_NOFREE
))
622 free((void*)np
->nvalue
.cp
);
624 np
->nvalue
.up
= &mp
->nvalue
;
626 nv_disc(np
,(Namfun_t
*)fp
, NV_FIRST
);
628 nv_onattr(np
,NV_ARRAY
);
629 mp
->nvenv
= (char*)np
;
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.
639 static struct index_array
*array_grow(Namval_t
*np
, register struct index_array
*arp
,int maxi
)
641 register struct index_array
*ap
;
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
);
651 ap
->bits
= (unsigned char*)&ap
->val
[newsize
];
652 memset(ap
->bits
, 0, newsize
);
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
);
666 ap
->header
.hdr
.dsize
= sizeof(*ap
) + i
;
669 if(nv_isnull(np
) && nv_isattr(np
,NV_NOFREE
))
672 nv_offattr(np
,NV_NOFREE
);
674 if(np
->nvalue
.cp
==Empty
)
676 if(nv_hasdisc(np
,&array_disc
) || nv_isvtree(np
))
678 ap
->header
.table
= dtopen(&_Nvdisc
,Dtoset
);
679 mp
= nv_search("0", ap
->header
.table
,NV_ADD
);
680 if(mp
&& nv_isnull(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
);
691 else if((ap
->val
[0].cp
=np
->nvalue
.cp
))
693 else if(nv_isattr(np
,NV_INTEGER
) && !nv_isnull(np
))
695 Sfdouble_t d
= nv_getnum(np
);
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
);
704 array_copytree(np
,mp
);
705 ap
->header
.hdr
.nofree
&= ~1;
708 for(;i
< newsize
;i
++)
713 int nv_atypeindex(Namval_t
*np
, const char *tname
)
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
);
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
);
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
);
736 errormsg(SH_DICT
,ERROR_exit(1),e_unknowntype
, n
,tname
);
740 Namarr_t
*nv_arrayptr(register Namval_t
*np
)
742 if(nv_isattr(np
,NV_ARRAY
))
743 return((Namarr_t
*)nv_hasdisc(np
, &array_disc
));
748 * Verify that argument is an indexed array and convert to associative,
749 * freeing relevant storage
751 static Namarr_t
*nv_changearray(Namval_t
*np
, void *(*fun
)(Namval_t
*,const char*,int))
753 register Namarr_t
*ap
;
754 char numbuff
[NUMSIZE
+1];
755 unsigned dot
, digit
, n
;
757 struct index_array
*save_ap
;
758 register char *string_index
=&numbuff
[NUMSIZE
];
759 numbuff
[NUMSIZE
]='\0';
761 if(!fun
|| !(ap
= nv_arrayptr(np
)) || is_associative(ap
))
762 return(NIL(Namarr_t
*));
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
));
769 nv_onattr(np
,NV_ARRAY
);
771 for(dot
= 0; dot
< (unsigned)save_ap
->maxi
; dot
++)
773 if(save_ap
->val
[dot
].cp
)
775 if ((digit
= dot
)== 0)
776 *--string_index
= '0';
777 else while( n
= digit
)
780 *--string_index
= '0' + (n
-10*digit
);
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;
787 string_index
= &numbuff
[NUMSIZE
];
789 free((void*)save_ap
);
794 * set the associative array processing method for node <np> to <fun>
795 * The array pointer is returned if sucessful.
797 Namarr_t
*nv_setarray(Namval_t
*np
, void *(*fun
)(Namval_t
*,const char*,int))
799 register Namarr_t
*ap
;
803 if(fun
&& (ap
= nv_arrayptr(np
)))
806 * if it's already an indexed array, convert to
807 * associative structure
809 if(!is_associative(ap
))
810 ap
= nv_changearray(np
, fun
);
813 if(nv_isnull(np
) && nv_isattr(np
,NV_NOFREE
))
816 nv_offattr(np
,NV_NOFREE
);
818 if(!(fp
=nv_isvtree(np
)))
819 value
= nv_getval(np
);
820 if(fun
&& !ap
&& (ap
= (Namarr_t
*)((*fun
)(np
, NIL(char*), NV_AINIT
))))
822 /* check for preexisting initialization and save */
825 nv_onattr(np
,NV_ARRAY
);
828 nv_putsub(np
, "0", ARRAY_ADD
);
830 nv_putval(np
, value
, 0);
833 Namval_t
*mp
= (Namval_t
*)((*fun
)(np
,NIL(char*),NV_ACURRENT
));
834 array_copytree(np
,mp
);
839 return(NIL(Namarr_t
*));
843 * move parent subscript into child
845 Namval_t
*nv_arraychild(Namval_t
*np
, Namval_t
*nq
, int c
)
848 register Namarr_t
*ap
= nv_arrayptr(np
);
852 return(ap
?array_find(np
,ap
, ARRAY_LOOKUP
):0);
855 nv_putsub(np
, NIL(char*), ARRAY_FILL
);
856 ap
= nv_arrayptr(np
);
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
)
863 ap
->nelem
|= ARRAY_NOCLONE
;
864 nq
->nvenv
= (char*)np
;
868 nv_clone(np
, nq
, NV_NODISC
);
869 nv_offattr(nq
,NV_ARRAY
);
870 ap
->nelem
&= ~ARRAY_NOCLONE
;
872 nq
->nvenv
= (char*)np
;
873 if((fp
=nq
->nvfun
) && fp
->disc
&& fp
->disc
->setdisc
&& (fp
= nv_disc(nq
,fp
,NV_POP
)))
877 struct index_array
*aq
= (struct index_array
*)ap
;
878 array_setbit(aq
->bits
,aq
->cur
,ARRAY_CHILD
);
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.
891 int nv_nextsub(Namval_t
*np
)
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
))
898 if(is_associative(ap
))
901 if(nq
=(*ap
->header
.fun
)(np
,NIL(char*),NV_ANEXT
))
903 if(nv_isattr(nq
,NV_CHILD
))
904 nv_putsub(nq
->nvalue
.np
,NIL(char*),ARRAY_UNDEF
);
907 ap
->header
.nelem
&= ~(ARRAY_SCAN
|ARRAY_NOCHILD
);
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
++)
915 if(!ap
->val
[dot
].cp
&& !(ap
->header
.nelem
&ARRAY_NOSCOPE
))
917 if(!(aq
=ar
) || dot
>=(unsigned)aq
->maxi
)
923 if(array_isbit(aq
->bits
, dot
,ARRAY_CHILD
))
925 Namval_t
*mp
= aq
->val
[dot
].np
;
926 if((aq
->header
.nelem
&ARRAY_NOCHILD
) && nv_isvtree(mp
) && !mp
->nvfun
->dsize
)
929 nv_putsub(mp
,NIL(char*),ARRAY_UNDEF
);
934 ap
->header
.nelem
&= ~(ARRAY_SCAN
|ARRAY_NOCHILD
);
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
950 Namval_t
*nv_putsub(Namval_t
*np
,register char *sp
,register long mode
)
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
)
958 if(ap
&& ap
->xp
&& !strmatch(sp
,"+([0-9])"))
960 Namval_t
*mp
= nv_namptr(ap
->xp
,0);
962 size
= nv_getnum(mp
);
965 size
= (int)sh_arith((char*)sp
);
968 size
+= array_maxindex(np
);
969 if(size
>= ARRAY_MAX
|| (size
< 0))
971 errormsg(SH_DICT
,ERROR_exit(1),e_subscript
, nv_name(np
));
972 return(NIL(Namval_t
*));
974 if(!ap
|| size
>=ap
->maxi
)
976 if(size
==0 && !(mode
&ARRAY_FILL
))
977 return(NIL(Namval_t
*));
979 np
= sh_assignok(np
,1);
980 ap
= array_grow(np
, ap
,size
);
982 ap
->header
.nelem
&= ~ARRAY_UNDEF
;
983 ap
->header
.nelem
|= (mode
&(ARRAY_SCAN
|ARRAY_NOCHILD
|ARRAY_UNDEF
|ARRAY_NOSCOPE
));
985 if(array_isbit(ap
->bits
,oldsize
,ARRAY_CHILD
))
986 mp
= ap
->val
[oldsize
].np
;
987 if(size
!= oldsize
&& mp
->nvalue
.cp
)
990 for(nfp
=np
->nvfun
; nfp
; nfp
=nfp
->next
)
992 if(nfp
->disc
&& nfp
->disc
->readf
)
994 (*nfp
->disc
->readf
)(mp
,(Sfio_t
*)0,0,nfp
);
1001 if((mode
&ARRAY_SCAN
) && (ap
->cur
--,!nv_nextsub(np
)))
1003 if(mode
&(ARRAY_FILL
|ARRAY_ADD
))
1005 if(!(mode
&ARRAY_ADD
))
1008 for(n
=0; n
<= size
; n
++)
1012 ap
->val
[n
].cp
= Empty
;
1013 if(!array_covered(np
,ap
))
1017 if(n
=ap
->maxi
-ap
->maxi
)
1018 memset(&ap
->val
[size
],0,n
*sizeof(union Value
));
1020 else if(!ap
->val
[size
].cp
)
1023 np
= sh_assignok(np
,1);
1024 ap
->val
[size
].cp
= Empty
;
1025 if(!array_covered(np
,ap
))
1029 else if(!(mode
&ARRAY_SCAN
))
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
)
1037 return((Namval_t
*)np
);
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
));
1045 if(mode
&ARRAY_SETSUB
)
1047 (*ap
->header
.fun
)(np
, sp
, NV_ASETSUB
);
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
))
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
))
1064 * process an array subscript for node <np> given the subscript <cp>
1065 * returns pointer to character after the subscript
1067 char *nv_endsubscript(Namval_t
*np
, register char *cp
, int mode
)
1069 register int count
=1, quoted
=0, c
;
1070 register char *sp
= cp
+1;
1071 /* first find matching ']' */
1072 while(count
>0 && (c
= *++cp
))
1074 if(c
=='\\' && (!(mode
&NV_SUBQUOTE
) || (c
=cp
[1])=='[' || c
==']' || c
=='\\' || c
=='*' || c
=='@'))
1087 /* strip escape characters */
1089 stakwrite(sp
,1+cp
-sp
);
1090 sh_trim(sp
=stakptr(count
));
1094 Namarr_t
*ap
= nv_arrayptr(np
);
1097 scan
= ap
->nelem
&ARRAY_SCAN
;
1098 if((mode
&NV_ASSIGN
) && (cp
[1]=='=' || cp
[1]=='+'))
1100 nv_putsub(np
, sp
, ((mode
&NV_ADD
)?ARRAY_ADD
:0)|(cp
[1]&&(mode
&NV_ADD
)?ARRAY_FILL
:mode
&ARRAY_FILL
));
1111 Namval_t
*nv_opensub(Namval_t
* np
)
1113 register struct index_array
*ap
= (struct index_array
*)nv_arrayptr(np
);
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
);
1121 return(NIL(Namval_t
*));
1124 char *nv_getsub(Namval_t
* np
)
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
)))
1132 if(is_associative(ap
))
1133 return((char*)((*ap
->header
.fun
)(np
,NIL(char*),NV_ANAME
)));
1136 np
= nv_namptr(ap
->xp
,0);
1137 np
->nvalue
.s
= ap
->cur
;
1138 return(nv_getval(np
));
1140 if((dot
= ap
->cur
)==0)
1145 *--cp
= '0' + (n
-10*dot
);
1151 * If <np> is an indexed array node, the current subscript index
1152 * returned, otherwise returns -1
1154 int nv_aindex(register Namval_t
* np
)
1156 Namarr_t
*ap
= nv_arrayptr(np
);
1159 else if(is_associative(ap
))
1161 return(((struct index_array
*)(ap
))->cur
&ARRAY_MASK
);
1164 int nv_arraynsub(register Namarr_t
* ap
)
1166 return(array_elem(ap
));
1169 int nv_aimax(register Namval_t
* np
)
1171 struct index_array
*ap
= (struct index_array
*)nv_arrayptr(np
);
1173 if(!ap
|| is_associative(&ap
->header
))
1176 while(--sub
>0 && ap
->val
[sub
].cp
==0);
1181 * This is the default implementation for associative arrays
1183 void *nv_associative(register Namval_t
*np
,const char *sp
,int mode
)
1185 register struct assoc_array
*ap
= (struct assoc_array
*)nv_arrayptr(np
);
1190 if(ap
= (struct assoc_array
*)calloc(1,sizeof(struct assoc_array
)))
1192 ap
->header
.table
= dtopen(&_Nvdisc
,Dtoset
);
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;
1204 if(!ap
->header
.scope
|| (Dt_t
*)ap
->header
.scope
==ap
->header
.table
|| !nv_search(ap
->cur
->nvname
,(Dt_t
*)ap
->header
.scope
,0))
1206 _nv_unset(ap
->cur
,NV_RDONLY
);
1207 nv_delete(ap
->cur
,ap
->header
.table
,0);
1213 if(ap
->header
.scope
)
1215 ap
->header
.table
= dtview(ap
->header
.table
,(Dt_t
*)0);
1216 dtclose(ap
->header
.scope
);
1217 ap
->header
.scope
= 0;
1220 dtclose(ap
->header
.table
);
1225 if((ap
->header
.nelem
&ARRAY_NOSCOPE
) && ap
->header
.scope
&& dtvnext(ap
->header
.table
))
1227 ap
->header
.scope
= dtvnext(ap
->header
.table
);
1228 ap
->header
.table
->view
= 0;
1230 if(!(ap
->pos
=ap
->cur
))
1231 ap
->pos
= (Namval_t
*)dtfirst(ap
->header
.table
);
1234 ap
->pos
= ap
->nextpos
;
1235 for(;ap
->cur
=ap
->pos
; ap
->pos
=ap
->nextpos
)
1237 ap
->nextpos
= (Namval_t
*)dtnext(ap
->header
.table
,ap
->pos
);
1238 if(ap
->cur
->nvalue
.cp
)
1240 if((ap
->header
.nelem
&ARRAY_NOCHILD
) && nv_isattr(ap
->cur
,NV_CHILD
))
1245 if((ap
->header
.nelem
&ARRAY_NOSCOPE
) && ap
->header
.scope
&& !dtvnext(ap
->header
.table
))
1247 ap
->header
.table
->view
= (Dt_t
*)ap
->header
.scope
;
1248 ap
->header
.scope
= ap
->header
.table
;
1252 ap
->cur
= (Namval_t
*)sp
;
1253 return((void*)ap
->cur
);
1256 ap
->cur
->nvenv
= (char*)np
;
1257 return((void*)ap
->cur
);
1261 Shell_t
*shp
= sh_getinterp();
1262 if(!shp
->instance
&& nv_isnull(ap
->cur
))
1264 return((void*)ap
->cur
->nvname
);
1274 type
= nv_isattr(np
,NV_PUBLIC
&~(NV_ARRAY
|NV_CHILD
|NV_MINIMAL
));
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
))
1283 if((mp
|| (mp
=nv_search(sp
,ap
->header
.table
,mode
))) && nv_isnull(mp
) && (mode
&NV_ADD
))
1286 mp
->nvenv
= (char*)np
;
1287 if((mode
&NV_ADD
) && nv_type(np
))
1288 nv_arraychild(np
,mp
,0);
1290 np
= sh_assignok(np
,1);
1291 if(!ap
->header
.scope
|| !nv_search(sp
,dtvnext(ap
->header
.table
),0))
1295 if(ap
->header
.nelem
&ARRAY_TREE
)
1297 mp
->nvalue
.cp
= Empty
;
1300 else if(ap
->header
.nelem
&ARRAY_SCAN
)
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
);
1307 else if(!mp
&& *sp
&& mode
==0)
1308 mp
= nv_search(sp
,ap
->header
.table
,NV_ADD
);
1310 if(ap
->pos
&& ap
->pos
==np
)
1311 ap
->header
.nelem
|= ARRAY_SCAN
;
1312 else if(!(ap
->header
.nelem
&ARRAY_SCAN
))
1317 return((void*)(&ap
->cur
->nvalue
));
1319 return((void*)(&ap
->cur
));
1324 * Assign values to an array
1326 void nv_setvec(register Namval_t
*np
,int append
,register int argc
,register char *argv
[])
1329 struct index_array
*ap
=0,*aq
;
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
));
1340 if(!(aq
= (struct index_array
*)ap
->header
.scope
))
1343 while(--arg0
>0 && ap
->val
[arg0
].cp
==0 && aq
->val
[arg0
].cp
==0);
1346 else if(!nv_isnull(np
))
1351 nv_putsub(np
,NIL(char*),(long)argc
+arg0
|ARRAY_FILL
|ARRAY_ADD
);
1352 nv_putval(np
,argv
[argc
],0);