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 ***********************************************************************/
26 #define putenv ___putenv
29 #include "variables.h"
31 #include "lexstates.h"
33 #include "FEATURE/externs"
36 #define NVCACHE 8 /* must be a power of 2 */
37 #define Empty ((char*)(e_sptbnl+3))
38 static char *savesub
= 0;
40 #if !_lib_pathnative && _lib_uwin_path
42 #define _lib_pathnative 1
44 extern int uwin_path(const char*, char*, int);
47 pathnative(const char* path
, char* buf
, size_t siz
)
49 return uwin_path(path
, buf
, siz
);
52 #endif /* _lib_pathnative */
54 static void attstore(Namval_t
*,void*);
56 static void pushnam(Namval_t
*,void*);
57 static char *staknam(Namval_t
*, char*);
59 static void ltou(char*);
60 static void utol(char*);
61 static void rightjust(char*, int, int);
62 static char *lastdot(char*, int);
82 #endif /*SHOPT_TYPEDEF */
101 static struct Namcache nvcache
;
106 static void(*nullscan
)(Namval_t
*,void*);
109 #if ( SFIO_VERSION <= 20010201L )
114 # define mbchar(p) (*(unsigned char*)p++)
115 #endif /* SHOPT_MULTIBYTE */
117 /* ======== name value pair routines ======== */
120 #include "builtins.h"
122 static char *getbuf(size_t len
)
125 static size_t buflen
;
129 buf
= (char*)malloc(len
);
131 buf
= (char*)realloc(buf
,len
);
138 void sh_envput(Env_t
* ep
,Namval_t
*np
)
140 int offset
= staktell();
141 Namarr_t
*ap
= nv_arrayptr(np
);
145 if(ap
->nelem
&ARRAY_UNDEF
)
146 nv_putsub(np
,"0",0L);
147 else if(!(val
=nv_getsub(np
)) || strcmp(val
,"0"))
150 if(!(val
= nv_getval(np
)))
152 stakputs(nv_name(np
));
156 env_add(ep
,stakptr(offset
),ENV_STRDUP
);
161 * output variable name in format for re-input
163 void nv_outname(Sfio_t
*out
, char *name
, int len
)
165 const char *cp
=name
, *sp
;
166 int c
, offset
= staktell();
167 while(sp
= strchr(cp
,'['))
169 if(len
>0 && cp
+len
<= sp
)
171 sfwrite(out
,cp
,++sp
-cp
);
179 if(*sp
=='[' || *sp
==']' || *sp
=='\\')
185 sfputr(out
,sh_fmtq(stakptr(offset
)),-1);
204 Namval_t
*nv_addnode(Namval_t
* np
, int remove
)
206 register struct sh_type
*sp
= (struct sh_type
*)sh
.mktype
;
208 register char *name
=0;
209 if(sp
->numnodes
==0 && !nv_isnull(np
) && sh
.last_table
)
211 /* could be an redefine */
212 Dt_t
*root
= nv_dict(sh
.last_table
);
214 nv_delete(np
,root
,NV_NOFREE
);
215 np
= nv_search(sp
->rp
->nvname
,root
,NV_ADD
);
217 if(sp
->numnodes
&& memcmp(np
->nvname
,NV_CLASS
,sizeof(NV_CLASS
)-1))
219 name
= (sp
->nodes
[0])->nvname
;
221 if(memcmp(np
->nvname
,name
,i
))
224 if(sp
->rp
&& sp
->numnodes
)
226 /* check for a redefine */
227 if(name
&& np
->nvname
[i
]=='.' && np
->nvname
[i
+1]=='_' && np
->nvname
[i
+2]==0)
231 Dt_t
*root
= nv_dict(sh
.last_table
);
232 nv_delete(sp
->nodes
[0],root
,NV_NOFREE
);
233 dtinsert(root
,sp
->rp
);
234 errormsg(SH_DICT
,ERROR_exit(1),e_redef
,sp
->nodes
[0]->nvname
);
237 for(i
=0; i
< sp
->numnodes
; i
++)
239 if(np
== sp
->nodes
[i
])
243 while(++i
< sp
->numnodes
)
244 sp
->nodes
[i
-1] = sp
->nodes
[i
];
252 if(sp
->numnodes
==sp
->maxnodes
)
255 sp
->nodes
= (Namval_t
**)realloc(sp
->nodes
,sizeof(Namval_t
*)*sp
->maxnodes
);
257 sp
->nodes
[sp
->numnodes
++] = np
;
260 #endif /* SHOPT_TYPEDEF */
263 * given a list of assignments, determine <name> is on the list
264 returns a pointer to the argnod on the list or NULL
266 struct argnod
*nv_onlist(struct argnod
*arg
, const char *name
)
269 int len
= strlen(name
);
270 for(;arg
; arg
=arg
->argnxt
.ap
)
272 if(*arg
->argval
==0 && arg
->argchn
.ap
&& !(arg
->argflag
&~(ARG_APPEND
|ARG_QUOTED
|ARG_MESSAGE
)))
273 cp
= ((struct fornod
*)arg
->argchn
.ap
)->fornam
;
276 if(memcmp(cp
,name
,len
)==0 && (cp
[len
]==0 || cp
[len
]=='='))
283 * Perform parameter assignment for a linked list of parameters
284 * <flags> contains attributes for the parameters
286 void nv_setlist(register struct argnod
*arg
,register int flags
, Namval_t
*typ
)
290 register Namval_t
*np
, *mp
;
291 char *trap
=shp
->st
.trap
[SH_DEBUGTRAP
];
292 char *prefix
= shp
->prefix
;
293 int traceon
= (sh_isoption(SH_XTRACE
)!=0);
294 int array
= (flags
&(NV_ARRAY
|NV_IARRAY
));
299 int maketype
= flags
&NV_TYPE
;
303 shtp
.previous
= shp
->mktype
;
304 shp
->mktype
=(void*)&shtp
;
308 shtp
.nodes
=(Namval_t
**)malloc(shtp
.maxnodes
*sizeof(Namval_t
*));
310 #endif /* SHOPT_TYPEDEF*/
311 flags
&= ~(NV_TYPE
|NV_ARRAY
|NV_IARRAY
);
312 if(sh_isoption(SH_ALLEXPORT
))
316 flags
&= ~(NV_IDENT
|NV_EXPORT
);
319 for(;arg
; arg
=arg
->argnxt
.ap
)
322 if(arg
->argflag
&ARG_MAC
)
325 cp
= sh_mactrim(shp
,arg
->argval
,(flags
&NV_NOREF
)?-3:-1);
326 shp
->prefix
= prefix
;
331 if(*arg
->argval
==0 && arg
->argchn
.ap
&& !(arg
->argflag
&~(ARG_APPEND
|ARG_QUOTED
|ARG_MESSAGE
)))
333 int flag
= (NV_VARNAME
|NV_ARRAY
|NV_ASSIGN
);
335 struct fornod
*fp
=(struct fornod
*)arg
->argchn
.ap
;
336 register Shnode_t
*tp
=fp
->fortre
;
337 flag
|= (flags
&(NV_NOSCOPE
|NV_STATIC
));
338 if(arg
->argflag
&ARG_QUOTED
)
339 cp
= sh_mactrim(shp
,fp
->fornam
,-1);
342 error_info
.line
= fp
->fortyp
-shp
->st
.firstline
;
343 if(!array
&& tp
->tre
.tretyp
!=TLST
&& tp
->com
.comset
&& !tp
->com
.comarg
&& tp
->com
.comset
->argval
[0]==0 && tp
->com
.comset
->argval
[1]=='[')
344 array
|= (tp
->com
.comset
->argflag
&ARG_MESSAGE
)?NV_IARRAY
:NV_ARRAY
;
345 if(shp
->fn_depth
&& (Namval_t
*)tp
->com
.comnamp
==SYSTYPESET
)
347 if(prefix
&& tp
->com
.comset
&& *cp
=='[')
350 np
= nv_open(prefix
,shp
->var_tree
,flag
);
351 shp
->prefix
= prefix
;
354 if(nv_isvtree(np
) && !nv_isarray(np
))
363 np
= nv_open(cp
,shp
->var_tree
,flag
|NV_ASSIGN
);
364 if(typ
&& !array
&& (nv_isnull(np
) || nv_isarray(np
)))
365 nv_settype(np
,typ
,0);
366 if((flags
&NV_STATIC
) && !nv_isnull(np
))
371 #endif /* SHOPT_TYPEDEF */
372 if(array
&& (!(ap
=nv_arrayptr(np
)) || !ap
->hdr
.type
))
374 if(!(arg
->argflag
&ARG_APPEND
))
378 nv_setarray(np
,nv_associative
);
382 nv_onattr(np
,NV_ARRAY
);
385 if(array
&& tp
->tre
.tretyp
!=TLST
&& !tp
->com
.comset
&& !tp
->com
.comarg
)
391 #endif /* SHOPT_TYPEDEF */
393 /* check for array assignment */
394 if(tp
->tre
.tretyp
!=TLST
&& tp
->com
.comarg
&& !tp
->com
.comset
&& !((mp
=tp
->com
.comnamp
) && nv_isattr(mp
,BLT_DCL
)))
397 Dt_t
*last_root
= shp
->last_root
;
398 char **argv
= sh_argbuild(shp
,&argc
,&tp
->com
,0);
399 shp
->last_root
= last_root
;
401 if(shp
->mktype
&& shp
->dot_depth
==0 && np
==((struct sh_type
*)shp
->mktype
)->nodes
[0])
404 errormsg(SH_DICT
,ERROR_exit(1),"%s: not a known type name",argv
[0]);
406 #endif /* SHOPT_TYPEDEF */
407 if(!(arg
->argflag
&ARG_APPEND
))
409 if(!nv_isarray(np
) || ((ap
=nv_arrayptr(np
)) && (ap
->nelem
&ARRAY_MASK
)))
412 nv_setvec(np
,(arg
->argflag
&ARG_APPEND
),argc
,argv
);
416 char *name
= nv_name(np
);
417 if(arg
->argflag
&ARG_APPEND
)
420 sh_debug(shp
,trap
,name
,(char*)0,argv
,(arg
->argflag
&ARG_APPEND
)|ARG_ASSIGN
);
423 sh_trace(NIL(char**),0);
424 sfputr(sfstderr
,name
,n
);
425 sfwrite(sfstderr
,"=( ",3);
427 sfputr(sfstderr
,sh_fmtq(cp
),' ');
428 sfwrite(sfstderr
,")\n",2);
435 #endif /* SHOPT_TYPEDEF */
437 if((tp
->tre
.tretyp
&COMMSK
)==TFUN
)
439 if(tp
->tre
.tretyp
==TLST
|| !tp
->com
.comset
|| tp
->com
.comset
->argval
[0]!='[')
441 if(tp
->tre
.tretyp
!=TLST
&& !tp
->com
.comnamp
&& tp
->com
.comset
&& tp
->com
.comset
->argval
[0]==0 && tp
->com
.comset
->argchn
.ap
)
444 cp
= stakcopy(nv_name(np
));
446 if(tp
->com
.comset
->argval
[1]=='[')
448 if((arg
->argflag
&ARG_APPEND
) && (!nv_isarray(np
) || (nv_aindex(np
)>=0)))
450 if(!(array
&NV_IARRAY
) && !(tp
->com
.comset
->argflag
&ARG_MESSAGE
))
451 nv_setarray(np
,nv_associative
);
453 nv_setlist(tp
->com
.comset
,flags
,0);
454 shp
->prefix
= prefix
;
455 if(tp
->com
.comset
->argval
[1]!='[')
462 #endif /* SHOPT_TYPEDEF */
464 if(*cp
!='.' && *cp
!='[' && strchr(cp
,'['))
467 np
= nv_open(cp
,shp
->var_tree
,flag
);
469 if(arg
->argflag
&ARG_APPEND
)
473 if((sub
=nv_aimax(np
)) < 0 && nv_arrayptr(np
))
474 errormsg(SH_DICT
,ERROR_exit(1),e_badappend
,nv_name(np
));
478 if(!nv_isnull(np
) && np
->nvalue
.cp
!=Empty
&& !nv_isvtree(np
))
481 else if(np
->nvalue
.cp
&& np
->nvalue
.cp
!=Empty
&& !nv_type(np
))
483 _nv_unset(np
,NV_EXPORT
);
488 if(!(arg
->argflag
&ARG_APPEND
))
489 _nv_unset(np
,NV_EXPORT
);
490 if(!sh_isoption(SH_BASH
) && !(array
&NV_IARRAY
) && !nv_isarray(np
))
491 nv_setarray(np
,nv_associative
);
496 sfprintf(stkstd
,"%s[%d]",prefix
?nv_name(np
):cp
,sub
);
497 shp
->prefix
= stakfreeze(1);
498 nv_putsub(np
,(char*)0,ARRAY_ADD
|ARRAY_FILL
|sub
);
501 shp
->prefix
= stakcopy(nv_name(np
));
507 if(*shp
->prefix
=='_' && shp
->prefix
[1]=='.' && nv_isref(L_ARGNOD
))
509 sfprintf(stkstd
,"%s%s",nv_name(L_ARGNOD
->nvalue
.nrp
->np
),shp
->prefix
+1);
510 shp
->prefix
= stkfreeze(stkstd
,1);
512 memset(&nr
,0,sizeof(nr
));
513 memcpy(&node
,L_ARGNOD
,sizeof(node
));
514 L_ARGNOD
->nvalue
.nrp
= &nr
;
516 nr
.root
= shp
->last_root
;
517 nr
.table
= shp
->last_table
;
518 L_ARGNOD
->nvflag
= NV_REF
|NV_NOFREE
;
521 sh_exec(tp
,sh_isstate(SH_ERREXIT
));
526 L_ARGNOD
->nvalue
.nrp
= node
.nvalue
.nrp
;
527 L_ARGNOD
->nvflag
= node
.nvflag
;
528 L_ARGNOD
->nvfun
= node
.nvfun
;
530 shp
->prefix
= prefix
;
531 if(nv_isarray(np
) && (mp
=nv_opensub(np
)))
533 while(tp
->tre
.tretyp
==TLST
)
535 if(!tp
->lst
.lstlef
|| !tp
->lst
.lstlef
->tre
.tretyp
==TCOM
|| tp
->lst
.lstlef
->com
.comarg
|| tp
->lst
.lstlef
->com
.comset
&& tp
->lst
.lstlef
->com
.comset
->argval
[0]!='[')
540 if(!nv_isarray(np
) && !typ
&& (tp
->com
.comarg
|| !tp
->com
.comset
|| tp
->com
.comset
->argval
[0]!='['))
543 if(tp
->com
.comarg
|| tp
->com
.comset
)
544 np
->nvfun
->dsize
= 0;
550 #endif /* SHOPT_TYPEDEF */
555 np
= nv_open(cp
,shp
->var_tree
,flags
);
556 if(!np
->nvfun
&& (flags
&NV_NOREF
))
559 nv_onattr(np
,NV_PARAM
);
561 nv_offattr(np
,NV_PARAM
);
565 register char *sp
=cp
;
566 char *name
=nv_name(np
);
571 if(cp
=lastdot(sp
,'='))
579 sh_trace(NIL(char**),0);
580 nv_outname(sfstderr
,name
,-1);
582 sfprintf(sfstderr
,"[%s]",sh_fmtq(sub
));
586 sfputc(sfstderr
,'+');
587 sfprintf(sfstderr
,"=%s\n",sh_fmtq(cp
));
595 sh_debug(shp
,trap
,name
,sub
,av
,append
);
602 nv_open(shtp
.nodes
[0]->nvname
,shp
->var_tree
,NV_ASSIGN
|NV_VARNAME
|NV_NOADD
|NV_NOFAIL
);
603 np
= nv_mktype(shtp
.nodes
,shtp
.numnodes
);
604 free((void*)shtp
.nodes
);
605 shp
->mktype
= shtp
.previous
;
610 L_ARGNOD
->nvalue
.nrp
= node
.nvalue
.nrp
;
611 L_ARGNOD
->nvflag
= node
.nvflag
;
612 L_ARGNOD
->nvfun
= node
.nvfun
;
615 #endif /* SHOPT_TYPEDEF */
620 * copy the subscript onto the stack
622 static void stak_subscript(const char *sub
, int last
)
628 if(c
=='[' || c
==']' || c
=='\\')
636 * construct a new name from a prefix and base name on the stack
638 static char *copystack(const char *prefix
, register const char *name
, const char *sub
)
640 register int last
=0,offset
= staktell();
644 if(*stakptr(staktell()-1)=='.')
645 stakseek(staktell()-1);
646 if(*name
=='.' && name
[1]=='[')
648 if(*name
!='[' && *name
!='.' && *name
!='=' && *name
!='+')
650 if(*name
=='.' && (name
[1]=='=' || name
[1]==0))
656 if(sh_checkid(stakptr(last
),(char*)0))
657 stakseek(staktell()-2);
660 stak_subscript(sub
,']');
664 return(stakptr(offset
));
668 * grow this stack string <name> by <n> bytes and move from cp-1 to end
669 * right by <n>. Returns beginning of string on the stack
671 static char *stack_extend(const char *cname
, char *cp
, int n
)
673 register char *name
= (char*)cname
;
674 int offset
= name
- stakptr(0);
676 stakseek(strlen(name
)+n
+1);
677 name
= stakptr(offset
);
685 Namval_t
*nv_create(const char *name
, Dt_t
*root
, int flags
, Namfun_t
*dp
)
688 char *cp
=(char*)name
, *sp
, *xp
;
690 register Namval_t
*np
=0, *nq
=0;
693 int copy
=1,isref
,top
=0,noscope
=(flags
&NV_NOSCOPE
);
694 if(root
==shp
->var_tree
)
699 flags
&= ~NV_NOSCOPE
;
707 switch(c
= *(unsigned char*)(sp
= cp
))
715 cp
= nv_endsubscript((Namval_t
*)0,sp
,0);
716 if(sp
==name
|| sp
[-1]=='.')
722 if(root
==shp
->var_tree
)
724 if(!copy
&& !(flags
&NV_NOREF
))
729 name
= copystack((const char*)0, name
,(const char*)0);
730 cp
= (char*)name
+copy
;
741 mode
= (c
=='.' || (flags
&NV_NOADD
))?add
:NV_ADD
;
742 if((flags
&NV_NOSCOPE
) && c
!='.')
743 mode
|= HASH_NOSCOPE
;
747 struct Ufunction
*rp
;
748 if((rp
=shp
->st
.real_fun
) && !rp
->sdict
&& (flags
&NV_STATIC
))
750 Dt_t
*dp
= dtview(shp
->var_tree
,(Dt_t
*)0);
751 rp
->sdict
= dtopen(&_Nvdisc
,Dtoset
);
752 dtview(rp
->sdict
,shp
->var_base
);
753 dtview(shp
->var_tree
,rp
->sdict
);
755 if(np
= nv_search(name
,shp
->var_tree
,0))
757 if(shp
->var_tree
->walk
== shp
->var_base
)
760 if((flags
&NV_NOSCOPE
) && *cp
!='.')
763 root
= shp
->var_base
;
766 nv_delete(np
,(Dt_t
*)0,0);
773 root
= shp
->var_tree
->walk
;
778 if(rp
&& rp
->sdict
&& (flags
&NV_STATIC
))
781 if(np
&& shp
->var_tree
->walk
==shp
->var_tree
)
784 nv_delete(np
,shp
->var_tree
,0);
787 if(!np
|| shp
->var_tree
->walk
!=root
)
788 np
= nv_search(name
,root
,HASH_NOSCOPE
|NV_ADD
);
791 if(np
|| (np
= nv_search(name
,root
,mode
)))
793 isref
= nv_isref(np
);
798 flags
&= ~NV_NOSCOPE
;
799 root
= shp
->var_base
;
803 if(nv_isnull(np
) && c
!='.' && (np
->nvfun
=nv_cover(nq
)))
804 np
->nvname
= nq
->nvname
;
808 else if(add
&& nv_isnull(np
) && c
=='.' && cp
[1]!='.')
820 if(c
=='.') /* don't optimize */
822 else if((flags
&NV_NOREF
) && (c
!='[' && *cp
!='.'))
824 if(c
&& !(flags
&NV_NOADD
))
828 while(nv_isref(np
) && np
->nvalue
.cp
)
830 root
= nv_reftree(np
);
831 shp
->last_root
= root
;
832 shp
->last_table
= nv_reftable(np
);
836 nv_putsub(np
,sub
,0L);
840 if(nv_isref(np
) && (c
=='[' || c
=='.' || !(flags
&NV_ASSIGN
)))
841 errormsg(SH_DICT
,ERROR_exit(1),e_noref
,nv_name(np
));
845 flags
&= ~(noscope
?0:NV_NOSCOPE
);
849 copy
= strlen(cp
=nv_name(np
));
851 name
= copystack(cp
,sp
,sub
);
852 sp
= (char*)name
+ copy
;
856 flags
&= ~NV_NOSCOPE
;
860 nv_onattr(np
,NV_NOFREE
);
863 shp
->last_root
= root
;
864 if(*cp
&& cp
[1]=='.')
866 if(c
=='.' && (cp
[1]==0 || cp
[1]=='=' || cp
[1]=='+'))
877 if(!nq
&& *sp
=='[' && *cp
==0 && cp
[-1]==']')
880 * for backward compatibility
881 * evaluate subscript for
882 * possible side effects
890 if(c
=='[' || (c
=='.' && nv_isarray(np
)))
894 mode
&= ~HASH_NOSCOPE
;
898 Namarr_t
*ap
= nv_arrayptr(np
);
899 int scan
= ap
?(ap
->nelem
&ARRAY_SCAN
):0;
901 n
= mode
|nv_isarray(np
);
902 if(!mode
&& (flags
&NV_ARRAY
) && ((c
=sp
[1])=='*' || c
=='@') && sp
[2]==']')
904 /* not implemented yet */
908 if((n
&NV_ADD
)&&(flags
&NV_ARRAY
))
912 cp
= nv_endsubscript(np
,sp
,n
|(flags
&NV_ASSIGN
));
915 nv_putsub(np
,NIL(char*),ARRAY_SCAN
);
920 if((c
= *cp
)=='.' || (c
=='[' && nv_isarray(np
)) || (n
&ARRAY_FILL
) || (flags
&NV_ARRAY
))
924 sub
= m
?nv_getsub(np
):0;
936 name
= copystack((const char*)0, name
,(const char*)0);
937 cp
= (char*)name
+copy
;
944 memcpy(sp
+1,sub
,n
-2);
954 name
= stack_extend(name
, cp
-1, r
);
955 sp
= (char*)name
+ m
;
957 memcpy(sp
+1,sub
,n
-2);
963 else if(c
==0 && mode
&& (n
=nv_aindex(np
))>0)
964 nv_putsub(np
,(char*)0,n
);
965 else if(n
==0 && (c
==0 || (c
=='[' && !nv_isarray(np
))))
967 /* subscript must be 0*/
977 if(nv_isarray(np
) && (c
=='[' || c
=='.' || (flags
&NV_ARRAY
)))
980 if(!(nq
= nv_opensub(np
)))
982 Namarr_t
*ap
= nv_arrayptr(np
);
983 if(!sub
&& (flags
&NV_NOADD
))
985 n
= mode
|((flags
&NV_NOADD
)?0:NV_ADD
);
986 if(!ap
&& (n
&NV_ADD
))
988 nv_putsub(np
,sub
,ARRAY_FILL
);
989 ap
= nv_arrayptr(np
);
991 if(n
&& ap
&& !ap
->table
)
992 ap
->table
= dtopen(&_Nvdisc
,Dtoset
);
993 if(ap
&& ap
->table
&& (nq
=nv_search(sub
,ap
->table
,n
)))
994 nq
->nvenv
= (char*)np
;
995 if(nq
&& nv_isnull(nq
))
996 nq
= nv_arraychild(np
,nq
,c
);
1000 if(c
=='.' && !nv_isvtree(nq
))
1008 else if(memcmp(cp
,"[0]",3))
1018 else if(nv_isarray(np
))
1020 if(c
==0 && (flags
&NV_MOVE
))
1022 nv_putsub(np
,NIL(char*),ARRAY_UNDEF
);
1024 if(c
=='.' && (fp
=np
->nvfun
))
1026 for(; fp
; fp
=fp
->next
)
1028 if(fp
->disc
&& fp
->disc
->createf
)
1033 if((nq
= (*fp
->disc
->createf
)(np
,cp
+1,flags
,fp
)) == np
)
1036 shp
->last_table
= 0;
1041 if((c
= *(sp
=cp
=dp
->last
=fp
->last
))==0)
1043 if(nv_isarray(np
) && sp
[-1]!=']')
1044 nv_putsub(np
,NIL(char*),ARRAY_UNDEF
);
1052 if(c
!='.' || cp
[1]=='.')
1058 if((c
= mbchar(cp
)) && !isaletter(c
))
1060 while(xp
=cp
, c
=mbchar(cp
), isaname(c
));
1068 * delete the node <np> from the dictionary <root> and clear from the cache
1069 * if <root> is NULL, only the cache is cleared
1070 * if flags does not contain NV_NOFREE, the node is freed
1072 void nv_delete(Namval_t
* np
, Dt_t
*root
, int flags
)
1076 struct Cache_entry
*xp
;
1077 for(c
=0,xp
=nvcache
.entries
; c
< NVCACHE
; xp
= &nvcache
.entries
[++c
])
1085 if(dtdelete(root
,np
))
1087 if(!(flags
&NV_NOFREE
) && ((flags
&NV_FUNCTION
) || !nv_subsaved(np
)))
1093 sfprintf(sfstderr
,"%s not deleted\n",nv_name(np
));
1101 * Put <arg> into associative memory.
1102 * If <flags> & NV_ARRAY then follow array to next subscript
1103 * If <flags> & NV_NOARRAY then subscript is not allowed
1104 * If <flags> & NV_NOSCOPE then use the current scope only
1105 * If <flags> & NV_ASSIGN then assignment is allowed
1106 * If <flags> & NV_IDENT then name must be an identifier
1107 * If <flags> & NV_VARNAME then name must be a valid variable name
1108 * If <flags> & NV_NOADD then node will not be added if not found
1109 * If <flags> & NV_NOREF then don't follow reference
1110 * If <flags> & NV_NOFAIL then don't generate an error message on failure
1111 * If <flags> & NV_STATIC then unset before an assignment
1112 * If <flags> & NV_UNJUST then unset attributes before assignment
1113 * SH_INIT is only set while initializing the environment
1115 Namval_t
*nv_open(const char *name
, Dt_t
*root
, int flags
)
1118 register char *cp
=(char*)name
;
1120 register Namval_t
*np
;
1123 const char *msg
= e_varname
;
1125 int offset
= staktell();
1128 struct Cache_entry
*xp
;
1131 sh_stats(STAT_NVOPEN
);
1132 memset(&fun
,0,sizeof(fun
));
1133 shp
->last_table
= shp
->namespace;
1135 root
= shp
->var_tree
;
1136 shp
->last_root
= root
;
1137 if(root
==shp
->fun_tree
)
1141 if((np
=shp
->namespace) || strchr(name
,'.'))
1143 name
= cp
= copystack(np
?nv_name(np
):0,name
,(const char*)0);
1144 fname
= strrchr(cp
,'.');
1149 root
= shp
->var_tree
;
1152 else if(!(flags
&(NV_IDENT
|NV_VARNAME
|NV_ASSIGN
)))
1154 long mode
= ((flags
&NV_NOADD
)?0:NV_ADD
);
1155 if(flags
&NV_NOSCOPE
)
1156 mode
|= HASH_SCOPE
|HASH_NOSCOPE
;
1157 np
= nv_search(name
,root
,mode
);
1158 if(np
&& !(flags
&NV_REF
))
1162 shp
->last_table
= nv_reftable(np
);
1163 np
= nv_refnode(np
);
1168 else if(shp
->prefix
&& (flags
&NV_ASSIGN
))
1170 name
= cp
= copystack(shp
->prefix
,name
,(const char*)0);
1173 c
= *(unsigned char*)cp
;
1174 if(root
==shp
->alias_tree
)
1177 while((c
= *(unsigned char*)cp
++) && (c
!='=') && (c
!='/') &&
1178 (c
>=0x200 || !(c
=sh_lexstates
[ST_NORM
][c
]) || c
==S_EPAT
|| c
==S_COLON
));
1179 if(shp
->subshell
&& c
=='=')
1180 root
= sh_subaliastree(1);
1183 np
= nv_search(name
, root
, (flags
&NV_NOADD
)?0:NV_ADD
);
1188 else if(flags
&NV_IDENT
)
1194 if(root
==shp
->var_tree
)
1195 root
= shp
->var_base
;
1196 shp
->last_table
= 0;
1198 if(c
= !isaletter(c
))
1201 for(c
=0,xp
=nvcache
.entries
; c
< NVCACHE
; xp
= &nvcache
.entries
[++c
])
1205 if(*name
==*xp
->name
&& (flags
&(NV_ARRAY
|NV_NOSCOPE
))==xp
->flags
&& memcmp(xp
->name
,name
,xp
->len
)==0 && (name
[xp
->len
]==0 || name
[xp
->len
]=='=' || name
[xp
->len
]=='+'))
1207 sh_stats(STAT_NVHITS
);
1209 cp
= (char*)name
+xp
->len
;
1211 nv_putsub(np
,NIL(char*),ARRAY_UNDEF
);
1212 shp
->last_table
= xp
->last_table
;
1213 shp
->last_root
= xp
->last_root
;
1219 np
= nv_create(name
, root
, flags
, &fun
);
1222 if(np
&& nvcache
.ok
&& cp
[-1]!=']')
1224 xp
= &nvcache
.entries
[nvcache
.index
];
1227 char *sp
= strchr(name
,*cp
);
1233 xp
->len
= strlen(name
);
1234 c
= roundof(xp
->len
+1,32);
1238 xp
->name
= malloc(c
);
1240 xp
->name
= realloc(xp
->name
,c
);
1243 memcpy(xp
->name
,name
,xp
->len
);
1244 xp
->name
[xp
->len
] = 0;
1247 xp
->last_table
= shp
->last_table
;
1248 xp
->last_root
= shp
->last_root
;
1249 xp
->flags
= (flags
&(NV_ARRAY
|NV_NOSCOPE
));
1250 nvcache
.index
= (nvcache
.index
+1)&(NVCACHE
-1);
1257 c
= ((flags
&NV_NOSCOPE
)?HASH_NOSCOPE
:0)|((flags
&NV_NOADD
)?0:NV_ADD
);
1259 np
= nv_search(name
, funroot
, c
);
1264 if(*cp
=='.' && cp
[1]=='.')
1266 append
|= NV_NODISC
;
1269 if(*cp
=='+' && cp
[1]=='=')
1271 append
|= NV_APPEND
;
1278 if(np
&& shp
->mktype
)
1279 np
= nv_addnode(np
,0);
1280 #endif /* SHOPT_TYPEDEF */
1281 if(c
=='=' && np
&& (flags
&NV_ASSIGN
))
1284 if(sh_isstate(SH_INIT
))
1286 nv_putval(np
, cp
, NV_RDONLY
);
1288 nv_onattr(np
,NV_TAGGED
);
1292 char *sub
=0, *prefix
= shp
->prefix
;
1295 if((flags
&NV_STATIC
) && !shp
->mktype
)
1299 shp
->prefix
= prefix
;
1303 isref
= nv_isref(np
);
1304 if(sh_isoption(SH_XTRACE
) && nv_isarray(np
))
1305 sub
= nv_getsub(np
);
1306 c
= msg
==e_aliname
? 0: (append
| (flags
&NV_EXPORT
));
1308 nv_offattr(np
,NV_REF
);
1309 if(!append
&& (flags
&NV_UNJUST
))
1311 nv_offattr(np
,NV_LJUST
|NV_RJUST
|NV_ZFILL
);
1314 nv_putval(np
, cp
, c
);
1317 if(nv_search((char*)np
,shp
->var_base
,HASH_BUCKET
))
1318 shp
->last_root
= shp
->var_base
;
1319 nv_setref(np
,(Dt_t
*)0,NV_VARNAME
);
1322 shp
->prefix
= prefix
;
1324 nv_onattr(np
, flags
&NV_ATTRIBUTES
);
1334 errormsg(SH_DICT
,ERROR_exit(1),msg
,name
);
1342 static int ja_size(char*, int, int);
1343 static void ja_restore(void);
1345 static char savechars
[8+1];
1346 #endif /* SHOPT_MULTIBYTE */
1349 * put value <string> into name-value node <np>.
1350 * If <np> is an array, then the element given by the
1351 * current index is assigned to.
1352 * If <flags> contains NV_RDONLY, readonly attribute is ignored
1353 * If <flags> contains NV_INTEGER, string is a pointer to a number
1354 * If <flags> contains NV_NOFREE, previous value is freed, and <string>
1355 * becomes value of node and <flags> becomes attributes
1357 void nv_putval(register Namval_t
*np
, const char *string
, int flags
)
1359 register const char *sp
=string
;
1360 register union Value
*up
;
1362 register int size
= 0;
1364 int was_local
= nv_local
;
1366 if(!(flags
&NV_RDONLY
) && nv_isattr (np
, NV_RDONLY
))
1367 errormsg(SH_DICT
,ERROR_exit(1),e_readonly
, nv_name(np
));
1368 /* The following could cause the shell to fork if assignment
1369 * would cause a side effect
1372 if(sh
.subshell
&& !nv_local
)
1373 np
= sh_assignok(np
,1);
1374 if(np
->nvfun
&& np
->nvfun
->disc
&& !(flags
&NV_NODISC
) && !nv_isref(np
))
1376 /* This function contains disc */
1380 nv_putv(np
,sp
,flags
,np
->nvfun
);
1381 if(sp
&& ((flags
&NV_EXPORT
) || nv_isattr(np
,NV_EXPORT
)))
1382 sh_envput(sh
.env
,np
);
1385 /* called from disc, assign the actual value */
1387 flags
&= ~NV_NODISC
;
1389 if(flags
&(NV_NOREF
|NV_NOFREE
))
1391 if(np
->nvalue
.cp
&& np
->nvalue
.cp
!=sp
&& !nv_isattr(np
,NV_NOFREE
))
1392 free((void*)np
->nvalue
.cp
);
1393 np
->nvalue
.cp
= (char*)sp
;
1394 nv_setattr(np
,(flags
&~NV_RDONLY
)|NV_NOFREE
);
1398 if(nv_isattr(np
,NV_INT16P
) == NV_INT16
)
1400 if(!np
->nvalue
.up
|| !nv_isarray(np
))
1403 up
->up
= &np
->nvalue
;
1406 else if(np
->nvalue
.up
&& nv_isarray(np
) && nv_arrayptr(np
))
1408 if(up
&& up
->cp
==Empty
)
1410 if(nv_isattr(np
,NV_EXPORT
))
1411 nv_offattr(np
,NV_IMPORT
);
1412 if(nv_isattr (np
, NV_INTEGER
))
1414 if(nv_isattr(np
, NV_DOUBLE
) == NV_DOUBLE
)
1416 if(nv_isattr(np
, NV_LONG
) && sizeof(double)<sizeof(Sfdouble_t
))
1418 Sfdouble_t ld
, old
=0;
1419 if(flags
&NV_INTEGER
)
1422 ld
= *((Sfdouble_t
*)sp
);
1423 else if(flags
&NV_SHORT
)
1426 ld
= *((double*)sp
);
1431 up
->ldp
= new_of(Sfdouble_t
,0);
1432 else if(flags
&NV_APPEND
)
1434 *(up
->ldp
) = old
?ld
+old
:ld
;
1439 if(flags
&NV_INTEGER
)
1442 d
= (double)(*(Sfdouble_t
*)sp
);
1443 else if(flags
&NV_SHORT
)
1444 d
= (double)(*(float*)sp
);
1451 up
->dp
= new_of(double,0);
1452 else if(flags
&NV_APPEND
)
1454 *(up
->dp
) = od
?d
+od
:d
;
1459 if(nv_isattr(np
, NV_LONG
) && sizeof(int32_t)<sizeof(Sflong_t
))
1461 Sflong_t ll
=0,oll
=0;
1462 if(flags
&NV_INTEGER
)
1464 if((flags
&NV_DOUBLE
) == NV_DOUBLE
)
1467 ll
= *((Sfdouble_t
*)sp
);
1468 else if(flags
&NV_SHORT
)
1471 ll
= *((double*)sp
);
1473 else if(nv_isattr(np
,NV_UNSIGN
))
1476 ll
= *((Sfulong_t
*)sp
);
1477 else if(flags
&NV_SHORT
)
1478 ll
= *((uint16_t*)sp
);
1480 ll
= *((uint32_t*)sp
);
1485 ll
= *((Sflong_t
*)sp
);
1486 else if(flags
&NV_SHORT
)
1487 ll
= *((uint16_t*)sp
);
1489 ll
= *((uint32_t*)sp
);
1493 ll
= (Sflong_t
)sh_arith(sp
);
1495 up
->llp
= new_of(Sflong_t
,0);
1496 else if(flags
&NV_APPEND
)
1498 *(up
->llp
) = ll
+oll
;
1503 if(flags
&NV_INTEGER
)
1505 if((flags
&NV_DOUBLE
) == NV_DOUBLE
)
1509 ll
= *((Sfdouble_t
*)sp
);
1510 else if(flags
&NV_SHORT
)
1513 ll
= *((double*)sp
);
1516 else if(nv_isattr(np
,NV_UNSIGN
))
1519 l
= *((Sfulong_t
*)sp
);
1520 else if(flags
&NV_SHORT
)
1521 l
= *((uint16_t*)sp
);
1528 l
= *((Sflong_t
*)sp
);
1529 else if(flags
&NV_SHORT
)
1530 l
= *((int16_t*)sp
);
1537 Sfdouble_t ld
= sh_arith(sp
);
1543 if(nv_size(np
) <= 1)
1545 if(nv_isattr (np
, NV_SHORT
))
1550 *(up
->sp
) = s
+(int16_t)l
;
1551 nv_onattr(np
,NV_NOFREE
);
1556 up
->lp
= new_of(int32_t,0);
1557 else if(flags
&NV_APPEND
)
1566 const char *tofree
=0;
1569 char buff
[PATH_MAX
];
1570 #endif /* _lib_pathnative */
1571 if(flags
&NV_INTEGER
)
1573 if((flags
&NV_DOUBLE
)==NV_DOUBLE
)
1576 sfprintf(sh
.strbuf
,"%.*Lg",LDBL_DIG
,*((Sfdouble_t
*)sp
));
1578 sfprintf(sh
.strbuf
,"%.*g",DBL_DIG
,*((double*)sp
));
1580 else if(flags
&NV_UNSIGN
)
1583 sfprintf(sh
.strbuf
,"%I*lu",sizeof(Sfulong_t
),*((Sfulong_t
*)sp
));
1585 sfprintf(sh
.strbuf
,"%lu",(unsigned long)((flags
&NV_SHORT
)?*((uint16_t*)sp
):*((uint32_t*)sp
)));
1590 sfprintf(sh
.strbuf
,"%I*ld",sizeof(Sflong_t
),*((Sflong_t
*)sp
));
1592 sfprintf(sh
.strbuf
,"%ld",(long)((flags
&NV_SHORT
)?*((int16_t*)sp
):*((int32_t*)sp
)));
1594 sp
= sfstruse(sh
.strbuf
);
1596 if(nv_isattr(np
, NV_HOST
|NV_INTEGER
)==NV_HOST
&& sp
)
1598 #ifdef _lib_pathnative
1600 * return the host file name given the UNIX name
1602 pathnative(sp
,buff
,sizeof(buff
));
1603 if(buff
[1]==':' && buff
[2]=='/')
1606 if(*buff
>='A' && *buff
<='Z')
1612 #endif /* _lib_pathnative */
1614 else if((nv_isattr(np
, NV_RJUST
|NV_ZFILL
|NV_LJUST
)) && sp
)
1616 for(;*sp
== ' '|| *sp
=='\t';sp
++);
1617 if((nv_isattr(np
,NV_ZFILL
)) && (nv_isattr(np
,NV_LJUST
)))
1618 for(;*sp
=='0';sp
++);
1622 size
= ja_size((char*)sp
,size
,nv_isattr(np
,NV_RJUST
|NV_ZFILL
));
1623 #endif /* SHOPT_MULTIBYTE */
1626 flags
&= ~NV_APPEND
;
1627 if((flags
&NV_APPEND
) && !nv_isattr(np
,NV_BINARY
))
1629 offset
= staktell();
1633 sp
= stakptr(offset
);
1635 if(!nv_isattr(np
, NV_NOFREE
))
1637 /* delay free in case <sp> points into free region */
1640 if(nv_isattr(np
,NV_BINARY
) && !(flags
&NV_RAW
))
1642 if(nv_isattr(np
,NV_LJUST
|NV_RJUST
) && nv_isattr(np
,NV_LJUST
|NV_RJUST
)!=(NV_LJUST
|NV_RJUST
))
1647 #if (_AST_VERSION>=20030127L)
1648 if(nv_isattr(np
,NV_BINARY
))
1650 int oldsize
= (flags
&NV_APPEND
)?nv_size(np
):0;
1655 free((void*)tofree
);
1656 nv_offattr(np
,NV_NOFREE
);
1662 if(nv_isattr(np
,NV_ZFILL
))
1665 size
= oldsize
+ (3*dot
/4);
1666 cp
= (char*)malloc(size
+1);
1667 nv_offattr(np
,NV_NOFREE
);
1669 memcpy((void*)cp
,(void*)up
->cp
,oldsize
);
1673 dot
= base64decode(sp
,dot
, (void**)0, cp
+oldsize
, size
-oldsize
,(void**)0);
1675 if(!nv_isattr(np
,NV_ZFILL
) || nv_size(np
)==0)
1677 else if(nv_isattr(np
,NV_ZFILL
) && (size
>dot
))
1678 memset(&cp
[dot
],0,size
-dot
);
1683 if(size
==0 && nv_isattr(np
,NV_HOST
)!=NV_HOST
&&nv_isattr(np
,NV_LJUST
|NV_RJUST
|NV_ZFILL
))
1684 nv_setsize(np
,size
=dot
);
1687 else if(nv_isattr(np
,NV_LJUST
|NV_RJUST
)==NV_LJUST
&& dot
>size
)
1689 if(size
==0 || tofree
|| !(cp
=(char*)up
->cp
))
1691 cp
= (char*)malloc(((unsigned)dot
+1));
1693 nv_offattr(np
,NV_NOFREE
);
1705 if(nv_isattr(np
, NV_LTOU
))
1707 else if(nv_isattr (np
, NV_UTOL
))
1710 if(nv_isattr(np
, NV_RJUST
) && nv_isattr(np
, NV_ZFILL
))
1711 rightjust(cp
,size
,'0');
1712 else if(nv_isattr(np
, NV_LJUST
|NV_RJUST
)==NV_RJUST
)
1713 rightjust(cp
,size
,' ');
1714 else if(nv_isattr(np
, NV_LJUST
|NV_RJUST
)==NV_LJUST
)
1717 dp
= strlen (cp
) + cp
;
1719 for (; dp
< cp
; *dp
++ = ' ');
1722 /* restore original string */
1725 #endif /* SHOPT_MULTIBYTE */
1729 if(tofree
&& tofree
!=Empty
)
1730 free((void*)tofree
);
1732 if(!was_local
&& ((flags
&NV_EXPORT
) || nv_isattr(np
,NV_EXPORT
)))
1733 sh_envput(sh
.env
,np
);
1739 * Right-justify <str> so that it contains no more than
1740 * <size> characters. If <str> contains fewer than <size>
1741 * characters, left-pad with <fill>. Trailing blanks
1742 * in <str> will be ignored.
1744 * If the leftmost digit in <str> is not a digit, <fill>
1745 * will default to a blank.
1747 static void rightjust(char *str
, int size
, int fill
)
1750 register char *cp
,*sp
;
1753 /* ignore trailing blanks */
1754 for(cp
=str
+n
;n
&& *--cp
== ' ';n
--);
1760 for (sp
= str
, cp
= str
+n
-size
; sp
<= str
+size
; *sp
++ = *cp
++);
1763 else *(sp
= str
+size
) = 0;
1784 * handle left and right justified fields for multi-byte chars
1785 * given physical size, return a logical size which reflects the
1786 * screen width of multi-byte characters
1787 * Multi-width characters replaced by spaces if they cross the boundary
1788 * <type> is non-zero for right justified fields
1791 static int ja_size(char *str
,int size
,int type
)
1793 register char *cp
= str
;
1794 register int c
, n
=size
;
1795 register int outsize
;
1796 register char *oldcp
=cp
;
1803 outsize
= mbwidth(w
);
1808 if(size
<=0 && type
==0)
1811 /* check for right justified fields that need truncating */
1816 /* left justified and character crosses field boundary */
1818 /* save boundary char and replace with spaces */
1820 savechars
[size
] = 0;
1823 savechars
[size
] = cp
[size
];
1830 n
-= (ja_size(str
,size
,0)-size
);
1835 static void ja_restore(void)
1837 register char *cp
= savechars
;
1842 #endif /* SHOPT_MULTIBYTE */
1845 static char *staknam(register Namval_t
*np
, char *value
)
1847 register char *p
,*q
;
1848 q
= stakalloc(strlen(nv_name(np
))+(value
?strlen(value
):0)+2);
1849 p
=strcopy(q
,nv_name(np
));
1860 * put the name and attribute into value of attributes variable
1863 static void attstore(register Namval_t
*np
, void *data
)
1865 register int flag
, c
= ' ';
1867 if(!(nv_isattr(np
,NV_EXPORT
)))
1869 flag
= nv_isattr(np
,NV_RDONLY
|NV_UTOL
|NV_LTOU
|NV_RJUST
|NV_LJUST
|NV_ZFILL
|NV_INTEGER
);
1871 if((flag
&NV_DOUBLE
) == NV_DOUBLE
)
1873 /* export doubles as integers for ksh88 compatibility */
1874 stakputc(c
+NV_INTEGER
|(flag
&~(NV_DOUBLE
|NV_EXPNOTE
)));
1883 stakputs(nv_name(np
));
1886 static void attstore(register Namval_t
*np
, void *data
)
1888 register int flag
= np
->nvflag
;
1889 register struct adata
*ap
= (struct adata
*)data
;
1892 if(!(flag
&NV_EXPORT
) || (flag
&NV_FUNCT
))
1894 flag
&= (NV_RDONLY
|NV_UTOL
|NV_LTOU
|NV_RJUST
|NV_LJUST
|NV_ZFILL
|NV_INTEGER
);
1895 *ap
->attval
++ = '=';
1896 if((flag
&NV_DOUBLE
) == NV_DOUBLE
)
1898 /* export doubles as integers for ksh88 compatibility */
1899 *ap
->attval
++ = ' '+ NV_INTEGER
|(flag
&~(NV_DOUBLE
|NV_EXPNOTE
));
1904 *ap
->attval
++ = ' '+flag
;
1906 *ap
->attval
= ' ' + nv_size(np
);
1910 ap
->attval
= strcopy(++ap
->attval
,nv_name(np
));
1915 static void pushnam(Namval_t
*np
, void *data
)
1917 register char *value
;
1918 register struct adata
*ap
= (struct adata
*)data
;
1921 if(nv_isattr(np
,NV_IMPORT
) && np
->nvenv
)
1922 *ap
->argnam
++ = np
->nvenv
;
1923 else if(value
=nv_getval(np
))
1924 *ap
->argnam
++ = staknam(np
,value
);
1925 if(nv_isattr(np
,NV_RDONLY
|NV_UTOL
|NV_LTOU
|NV_RJUST
|NV_LJUST
|NV_ZFILL
|NV_INTEGER
))
1926 ap
->attsize
+= (strlen(nv_name(np
))+4);
1931 * Generate the environment list for the child.
1935 char **sh_envgen(void)
1939 env_delete(sh
.env
,"_");
1940 er
= env_get(sh
.env
);
1941 offset
= staktell();
1942 stakputs(e_envmarker
);
1944 nv_scan(sh
.var_tree
, attstore
,(void*)0,0,(NV_RDONLY
|NV_UTOL
|NV_LTOU
|NV_RJUST
|NV_LJUST
|NV_ZFILL
|NV_INTEGER
));
1945 if(tell
==staktell())
1948 *--er
= stakfreeze(1)+offset
;
1952 char **sh_envgen(void)
1958 Shell_t
*shp
= sh_getinterp();
1961 /* L_ARGNOD gets generated automatically as full path name of command */
1962 nv_offattr(L_ARGNOD
,NV_EXPORT
);
1964 namec
= nv_scan(shp
->var_tree
,nullscan
,(void*)0,NV_EXPORT
,NV_EXPORT
);
1966 er
= (char**)stakalloc((namec
+4)*sizeof(char*));
1967 data
.argnam
= (er
+=2) + shp
->nenv
;
1969 memcpy((void*)er
,environ
,shp
->nenv
*sizeof(char*));
1970 nv_scan(shp
->var_tree
, pushnam
,&data
,NV_EXPORT
, NV_EXPORT
);
1971 *data
.argnam
= (char*)stakalloc(data
.attsize
);
1972 cp
= data
.attval
= strcopy(*data
.argnam
,e_envmarker
);
1973 nv_scan(shp
->var_tree
, attstore
,&data
,0,(NV_RDONLY
|NV_UTOL
|NV_LTOU
|NV_RJUST
|NV_LJUST
|NV_ZFILL
|NV_INTEGER
));
1984 void (*scanfn
)(Namval_t
*, void*);
1991 static int scanfilter(Dt_t
*dict
, void *arg
, void *data
)
1993 register Namval_t
*np
= (Namval_t
*)arg
;
1994 register int k
=np
->nvflag
;
1995 register struct scan
*sp
= (struct scan
*)data
;
1996 register struct adata
*tp
= (struct adata
*)sp
->scandata
;
1999 if(!is_abuiltin(np
) && tp
&& tp
->tp
&& nv_type(np
)!=tp
->tp
)
2001 #endif /*SHOPT_TYPEDEF */
2002 if(sp
->scanmask
?(k
&sp
->scanmask
)==sp
->scanflags
:(!sp
->scanflags
|| (k
&sp
->scanflags
)))
2004 if(!np
->nvalue
.cp
&& !np
->nvfun
&& !nv_isattr(np
,~NV_DEFAULT
))
2009 nv_putsub(np
,NIL(char*),0L);
2010 (*sp
->scanfn
)(np
,sp
->scandata
);
2018 * Walk through the name-value pairs
2019 * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
2021 * If <mask> is zero, and <flags> non-zero, then nodes with one or
2022 * more of <flags> is visited
2023 * If <mask> and <flags> are zero, then all nodes are visted
2025 int nv_scan(Dt_t
*root
, void (*fn
)(Namval_t
*,void*), void *data
,int mask
, int flags
)
2029 int (*hashfn
)(Dt_t
*, void*, void*);
2030 sdata
.scanmask
= mask
;
2031 sdata
.scanflags
= flags
&~NV_NOSCOPE
;
2033 sdata
.scancount
= 0;
2034 sdata
.scandata
= data
;
2035 hashfn
= scanfilter
;
2036 if(flags
&NV_NOSCOPE
)
2037 base
= dtview((Dt_t
*)root
,0);
2038 dtwalk(root
, hashfn
,&sdata
);
2040 dtview((Dt_t
*)root
,base
);
2041 return(sdata
.scancount
);
2045 * create a new environment scope
2047 void sh_scope(Shell_t
*shp
, struct argnod
*envlist
, int fun
)
2049 register Dt_t
*newscope
, *newroot
=shp
->var_base
;
2050 struct Ufunction
*rp
;
2051 newscope
= dtopen(&_Nvdisc
,Dtoset
);
2054 dtview(newscope
,(Dt_t
*)shp
->var_tree
);
2055 shp
->var_tree
= newscope
;
2056 nv_setlist(envlist
,NV_EXPORT
|NV_NOSCOPE
|NV_IDENT
|NV_ASSIGN
,0);
2059 shp
->var_tree
= dtview(newscope
,0);
2061 if((rp
=shp
->st
.real_fun
) && rp
->sdict
)
2063 dtview(rp
->sdict
,newroot
);
2064 newroot
= rp
->sdict
;
2067 dtview(newscope
,(Dt_t
*)newroot
);
2068 shp
->var_tree
= newscope
;
2072 * Remove freeable local space associated with the nvalue field
2073 * of nnod. This includes any strings representing the value(s) of the
2074 * node, as well as its dope vector, if it is an array.
2077 void sh_envnolocal (register Namval_t
*np
, void *data
)
2081 if(np
==VERSIONNOD
&& nv_isref(np
))
2085 if(nv_isattr(np
,NV_EXPORT
) && nv_isarray(np
))
2087 nv_putsub(np
,NIL(char*),0);
2088 if(cp
= nv_getval(np
))
2091 if(nv_isattr(np
,NV_EXPORT
|NV_NOFREE
))
2093 if(nv_isref(np
) && np
!=VERSIONNOD
)
2095 nv_offattr(np
,NV_NOFREE
|NV_REF
);
2096 free((void*)np
->nvalue
.nrp
);
2103 nv_putsub(np
,NIL(char*),ARRAY_UNDEF
);
2104 _nv_unset(np
,NV_RDONLY
);
2114 * Currently this is a dummy, but someday will be needed
2115 * for reference counting
2117 void nv_close(Namval_t
*np
)
2122 static void table_unset(Shell_t
*shp
, register Dt_t
*root
, int flags
, Dt_t
*oroot
)
2124 register Namval_t
*np
,*nq
, *npnext
;
2125 for(np
=(Namval_t
*)dtfirst(root
);np
;np
=npnext
)
2129 free((void*)np
->nvalue
.nrp
);
2133 if(nq
=dtsearch(oroot
,np
))
2137 int subshell
= shp
->subshell
;
2139 if(nv_isattr(nq
, NV_INTEGER
))
2141 Sfdouble_t d
= nv_getnum(nq
);
2142 nv_putval(nq
,(char*)&d
,NV_LDOUBLE
);
2144 else if(shp
->test
&4)
2145 nv_putval(nq
, strdup(nv_getval(nq
)), NV_RDONLY
);
2147 nv_putval(nq
, nv_getval(nq
), NV_RDONLY
);
2148 shp
->subshell
= subshell
;
2151 if(nv_isattr(nq
,NV_EXPORT
))
2152 sh_envput(shp
->env
,nq
);
2154 npnext
= (Namval_t
*)dtnext(root
,np
);
2155 shp
->last_root
= root
;
2156 shp
->last_table
= 0;
2159 int len
= strlen(np
->nvname
);
2160 while((nq
=npnext
) && memcmp(np
->nvname
,nq
->nvname
,len
)==0 && nq
->nvname
[len
]=='.')
2163 npnext
= (Namval_t
*)dtnext(root
,nq
);
2164 _nv_unset(nq
,flags
);
2165 nv_delete(nq
,root
,0);
2168 _nv_unset(np
,flags
);
2169 nv_delete(np
,root
,0);
2175 * Set the value of <np> to 0, and nullify any attributes
2176 * that <np> may have had. Free any freeable space occupied
2177 * by the value of <np>. If <np> denotes an array member, it
2178 * will retain its attributes.
2179 * <flags> can contain NV_RDONLY to override the readonly attribute
2181 * <flags> can contain NV_EXPORT to override preserve nvenv
2183 void _nv_unset(register Namval_t
*np
,int flags
)
2186 register union Value
*up
;
2187 if(!(flags
&NV_RDONLY
) && nv_isattr (np
,NV_RDONLY
))
2188 errormsg(SH_DICT
,ERROR_exit(1),e_readonly
, nv_name(np
));
2189 if(is_afunction(np
) && np
->nvalue
.ip
)
2191 register struct slnod
*slp
= (struct slnod
*)(np
->nvenv
);
2192 if(slp
&& !nv_isattr(np
,NV_NOFREE
))
2194 struct Ufunction
*rq
,*rp
= np
->nvalue
.rp
;
2195 /* free function definition */
2196 register char *name
=nv_name(np
),*cp
= strrchr(name
,'.');
2201 npv
= nv_open(name
,shp
->var_tree
,NV_NOARRAY
|NV_VARNAME
|NV_NOADD
);
2204 nv_setdisc(npv
,cp
,NIL(Namval_t
*),(Namfun_t
*)npv
);
2206 if(rp
->fname
&& shp
->fpathdict
&& (rq
= (struct Ufunction
*)nv_search(rp
->fname
,shp
->fpathdict
,0)))
2212 dtdelete(shp
->fpathdict
,rq
);
2215 while(rq
= (struct Ufunction
*)dtnext(shp
->fpathdict
,rq
));
2220 for(mp
=(Namval_t
*)dtfirst(rp
->sdict
);mp
;mp
=nq
)
2222 nq
= dtnext(rp
->sdict
,mp
);
2223 _nv_unset(mp
,NV_RDONLY
);
2224 nv_delete(mp
,rp
->sdict
,0);
2228 stakdelete(slp
->slptr
);
2229 free((void*)np
->nvalue
.ip
);
2234 if(shp
->subshell
&& !nv_isnull(np
))
2235 np
= sh_assignok(np
,0);
2236 nv_offattr(np
,NV_NODISC
);
2237 if(np
->nvfun
&& !nv_isref(np
))
2239 /* This function contains disc */
2243 nv_putv(np
,NIL(char*),flags
,np
->nvfun
);
2247 /* called from disc, assign the actual value */
2250 if(nv_isattr(np
,NV_INT16P
) == NV_INT16
)
2252 np
->nvalue
.cp
= nv_isarray(np
)?Empty
:0;
2255 if(nv_isarray(np
) && np
->nvalue
.cp
!=Empty
&& np
->nvfun
)
2261 if(up
->cp
!=Empty
&& !nv_isattr(np
, NV_NOFREE
))
2262 free((void*)up
->cp
);
2266 if(!nv_isarray(np
) || !nv_arrayptr(np
))
2268 if(nv_isref(np
) && !nv_isattr(np
,NV_EXPORT
))
2269 free((void*)np
->nvalue
.nrp
);
2271 if(!nv_isattr(np
,NV_MINIMAL
) || nv_isattr(np
,NV_EXPORT
))
2273 if(nv_isattr(np
,NV_EXPORT
) && !strchr(np
->nvname
,'['))
2274 env_delete(shp
->env
,nv_name(np
));
2275 if(!(flags
&NV_EXPORT
) || nv_isattr(np
,NV_IMPORT
|NV_EXPORT
)==(NV_IMPORT
|NV_EXPORT
))
2281 nv_setattr(np
,NV_MINIMAL
);
2282 nv_delete(np
,(Dt_t
*)0,0);
2288 * return the node pointer in the highest level scope
2290 Namval_t
*sh_scoped(Shell_t
*shp
, register Namval_t
*np
)
2292 if(!dtvnext(shp
->var_tree
))
2294 return(dtsearch(shp
->var_tree
,np
));
2299 * return space separated list of names of variables in given tree
2301 static char *tableval(Dt_t
*root
)
2304 register Namval_t
*np
;
2305 register int first
=1;
2306 register Dt_t
*base
= dtview(root
,0);
2308 sfseek(out
,(Sfoff_t
)0,SEEK_SET
);
2310 out
= sfnew((Sfio_t
*)0,(char*)0,-1,-1,SF_WRITE
|SF_STRING
);
2311 for(np
=(Namval_t
*)dtfirst(root
);np
;np
=(Namval_t
*)dtnext(root
,np
))
2313 if(!nv_isnull(np
) || np
->nvfun
|| nv_isattr(np
,~NV_NOFREE
))
2319 sfputr(out
,np
->nvname
,-1);
2325 return((char*)out
->_data
);
2335 struct optimize
*next
;
2339 static struct optimize
*opt_free
;
2341 static void optimize_clear(Namval_t
* np
, Namfun_t
*fp
)
2343 struct optimize
*op
= (struct optimize
*)fp
;
2345 nv_stack(np
,(Namfun_t
*)0);
2346 for(;op
&& op
->np
==np
; op
=op
->next
)
2356 static void put_optimize(Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
2358 nv_putv(np
,val
,flags
,fp
);
2359 optimize_clear(np
,fp
);
2362 static Namfun_t
*clone_optimize(Namval_t
* np
, Namval_t
*mp
, int flags
, Namfun_t
*fp
)
2364 return((Namfun_t
*)0);
2367 static const Namdisc_t optimize_disc
= {sizeof(struct optimize
),put_optimize
,0,0,0,0,clone_optimize
};
2369 void nv_optimize(Namval_t
*np
)
2371 register Namfun_t
*fp
;
2372 register struct optimize
*op
, *xp
;
2380 for(fp
=np
->nvfun
; fp
; fp
= fp
->next
)
2382 if(fp
->disc
&& (fp
->disc
->getnum
|| fp
->disc
->getval
))
2387 if(fp
->disc
== &optimize_disc
)
2390 if((xp
= (struct optimize
*)fp
) && xp
->ptr
==sh
.argaddr
)
2393 opt_free
= op
->next
;
2395 op
=(struct optimize
*)calloc(1,sizeof(struct optimize
));
2396 op
->ptr
= sh
.argaddr
;
2401 op
->next
= xp
->next
;
2406 op
->hdr
.disc
= &optimize_disc
;
2407 op
->next
= (struct optimize
*)sh
.optlist
;
2408 sh
.optlist
= (void*)op
;
2409 nv_stack(np
,&op
->hdr
);
2414 void sh_optclear(Shell_t
*shp
, void *old
)
2416 register struct optimize
*op
,*opnext
;
2417 for(op
=(struct optimize
*)shp
->optlist
; op
; op
= opnext
)
2420 if(op
->ptr
&& op
->hdr
.disc
)
2422 nv_stack(op
->np
,&op
->hdr
);
2423 nv_stack(op
->np
,(Namfun_t
*)0);
2425 op
->next
= opt_free
;
2432 # define optimize_clear(np,fp)
2433 #endif /* SHOPT_OPTIMIZE */
2436 * Return a pointer to a character string that denotes the value
2437 * of <np>. If <np> refers to an array, return a pointer to
2438 * the value associated with the current index.
2440 * If the value of <np> is an integer, the string returned will
2441 * be overwritten by the next call to nv_getval.
2443 * If <np> has no value, 0 is returned.
2446 char *nv_getval(register Namval_t
*np
)
2448 register union Value
*up
= &np
->nvalue
;
2449 register int numeric
;
2451 if(!nv_local
&& sh
.argaddr
)
2453 #endif /* SHOPT_OPTIMIZE */
2454 if((!np
->nvfun
|| !np
->nvfun
->disc
) && !nv_isattr(np
,NV_ARRAY
|NV_INTEGER
|NV_FUNCT
|NV_REF
|NV_TABLE
))
2460 sh
.last_table
= nv_reftable(np
);
2461 return(nv_name(nv_refnode(np
)));
2463 if(np
->nvfun
&& np
->nvfun
->disc
)
2468 return(nv_getv(np
, np
->nvfun
));
2472 numeric
= ((nv_isattr (np
, NV_INTEGER
)) != 0);
2478 if(nv_isattr (np
,NV_DOUBLE
)==NV_DOUBLE
)
2483 if(nv_isattr(np
,NV_LONG
))
2486 if(nv_isattr (np
,NV_EXPNOTE
))
2488 else if(nv_isattr (np
,NV_HEXFLOAT
))
2492 sfprintf(sh
.strbuf
,format
,nv_size(np
),ld
);
2497 if(nv_isattr (np
,NV_EXPNOTE
))
2499 else if(nv_isattr (np
,NV_HEXFLOAT
))
2503 sfprintf(sh
.strbuf
,format
,nv_size(np
),d
);
2505 return(sfstruse(sh
.strbuf
));
2507 else if(nv_isattr(np
,NV_UNSIGN
))
2509 if(nv_isattr (np
,NV_LONG
))
2510 ll
= *(Sfulong_t
*)up
->llp
;
2511 else if(nv_isattr (np
,NV_SHORT
))
2513 if(nv_isattr(np
,NV_INT16P
)==NV_INT16P
)
2514 ll
= *(uint16_t*)(up
->sp
);
2516 ll
= (uint16_t)up
->s
;
2519 ll
= *(uint32_t*)(up
->lp
);
2521 else if(nv_isattr (np
,NV_LONG
))
2523 else if(nv_isattr (np
,NV_SHORT
))
2525 if(nv_isattr(np
,NV_INT16P
)==NV_INT16P
)
2532 if((numeric
=nv_size(np
))==10)
2534 if(nv_isattr(np
,NV_UNSIGN
))
2536 sfprintf(sh
.strbuf
,"%I*u",sizeof(ll
),ll
);
2537 return(sfstruse(sh
.strbuf
));
2541 return(fmtbasell(ll
,numeric
, numeric
&&numeric
!=10));
2544 #if (_AST_VERSION>=20030127L)
2546 * if NV_RAW flag is on, return pointer to binary data
2547 * otherwise, base64 encode the data and return this string
2549 if(up
->cp
&& nv_isattr(np
,NV_BINARY
) && !nv_isattr(np
,NV_RAW
))
2553 int size
= nv_size(np
), insize
=(4*size
)/3+size
/45+8;
2554 base64encode(up
->cp
, size
, (void**)0, cp
=getbuf(insize
), insize
, (void**)&ep
);
2559 if((numeric
=nv_size(np
)) && up
->cp
&& up
->cp
[numeric
])
2561 char *cp
= getbuf(numeric
+1);
2562 memcpy(cp
,up
->cp
,numeric
);
2566 return ((char*)up
->cp
);
2569 Sfdouble_t
nv_getnum(register Namval_t
*np
)
2571 register union Value
*up
;
2572 register Sfdouble_t r
=0;
2575 if(!nv_local
&& sh
.argaddr
)
2577 #endif /* SHOPT_OPTIMIZE */
2579 errormsg(SH_DICT
,ERROR_exit(1),e_number
,nv_name(np
));
2580 if(np
->nvfun
&& np
->nvfun
->disc
)
2585 return(nv_getn(np
, np
->nvfun
));
2591 str
= nv_refsub(np
);
2592 np
= nv_refnode(np
);
2594 nv_putsub(np
,str
,0L);
2596 if(nv_isattr (np
, NV_INTEGER
))
2599 if(!up
->lp
|| up
->cp
==Empty
)
2601 else if(nv_isattr(np
, NV_DOUBLE
)==NV_DOUBLE
)
2603 if(nv_isattr(np
, NV_LONG
))
2608 else if(nv_isattr(np
, NV_UNSIGN
))
2610 if(nv_isattr(np
, NV_LONG
))
2611 r
= (Sflong_t
)*((Sfulong_t
*)up
->llp
);
2612 else if(nv_isattr(np
, NV_SHORT
))
2614 if(nv_isattr(np
,NV_INT16P
)==NV_INT16P
)
2615 r
= (Sflong_t
)(*(uint16_t*)up
->sp
);
2617 r
= (Sflong_t
)((uint16_t)up
->s
);
2620 r
= *((uint32_t*)up
->lp
);
2624 if(nv_isattr(np
, NV_LONG
))
2626 else if(nv_isattr(np
, NV_SHORT
))
2628 if(nv_isattr(np
,NV_INT16P
)==NV_INT16P
)
2637 else if((str
=nv_getval(np
)) && *str
!=0)
2639 if(np
->nvfun
|| nv_isattr(np
,NV_LJUST
|NV_RJUST
|NV_ZFILL
))
2649 * Give <np> the attributes <newatts,> and change its current
2650 * value to conform to <newatts>. The <size> of left and right
2651 * justified fields may be given.
2653 void nv_newattr (register Namval_t
*np
, unsigned newatts
, int size
)
2656 register char *cp
= 0;
2657 register unsigned int n
;
2659 int oldsize
,oldatts
;
2660 Namfun_t
*fp
= (newatts
&NV_NODISC
)?np
->nvfun
:0;
2661 char *prefix
= sh
.prefix
;
2662 newatts
&= ~NV_NODISC
;
2664 /* check for restrictions */
2665 if(sh_isoption(SH_RESTRICTED
) && ((sp
=nv_name(np
))==nv_name(PATHNOD
) || sp
==nv_name(SHELLNOD
) || sp
==nv_name(ENVNOD
) || sp
==nv_name(FPATHNOD
)))
2666 errormsg(SH_DICT
,ERROR_exit(1),e_restricted
,nv_name(np
));
2667 /* handle attributes that do not change data separately */
2669 if(newatts
&NV_EXPORT
)
2670 nv_offattr(np
,NV_IMPORT
);
2671 if(((n
^newatts
)&NV_EXPORT
))
2673 /* record changes to the environment */
2675 env_delete(sh
.env
,nv_name(np
));
2677 sh_envput(sh
.env
,np
);
2679 oldsize
= nv_size(np
);
2680 if((size
==oldsize
|| (n
&NV_INTEGER
)) && ((n
^newatts
)&~NV_NOCHANGE
)==0)
2683 nv_setsize(np
,size
);
2684 nv_offattr(np
, ~NV_NOFREE
);
2685 nv_onattr(np
, newatts
);
2688 /* for an array, change all the elements */
2689 if((ap
=nv_arrayptr(np
)) && ap
->nelem
>0)
2690 nv_putsub(np
,NIL(char*),ARRAY_SCAN
);
2691 oldsize
= nv_size(np
);
2692 oldatts
= np
->nvflag
;
2695 if(ap
) /* add element to prevent array deletion */
2699 nv_setsize(np
,oldsize
);
2700 np
->nvflag
= oldatts
;
2701 if (sp
= nv_getval(np
))
2703 if(nv_isattr(np
,NV_ZFILL
))
2704 while(*sp
=='0') sp
++;
2705 cp
= (char*)malloc((n
=strlen (sp
)) + 1);
2710 ap
->nelem
&= ~ARRAY_SCAN
;
2711 if(mp
=nv_opensub(np
))
2714 mp
->nvalue
.cp
= Empty
;
2718 ap
->nelem
|= ARRAY_SCAN
;
2722 if(size
==0 && (newatts
&NV_HOST
)!=NV_HOST
&& (newatts
&(NV_LJUST
|NV_RJUST
|NV_ZFILL
)))
2727 nv_setsize(np
,size
);
2728 np
->nvflag
&= NV_ARRAY
;
2729 np
->nvflag
|= newatts
;
2732 nv_putval (np
, cp
, NV_RDONLY
);
2736 while(ap
&& nv_nextsub(np
));
2745 static char *oldgetenv(const char *string
)
2747 register char c0
,c1
;
2748 register const char *cp
, *sp
;
2749 register char **av
= environ
;
2750 if(!string
|| (c0
= *string
)==0)
2752 if((c1
=*++string
)==0)
2756 if(cp
[0]!=c0
|| cp
[1]!=c1
)
2759 while(*sp
&& *sp
++ == *++cp
);
2760 if(*sp
==0 && *++cp
=='=')
2761 return((char*)(cp
+1));
2767 * This version of getenv uses the hash storage to access environment values
2769 char *sh_getenv(const char *name
)
2774 register Namval_t
*np
;
2778 if(name
[0] == 'P' && name
[1] == 'A' && name
[2] == 'T' && name
[3] == 'H' && name
[4] == 0 || name
[0] == 'L' && ((name
[1] == 'C' || name
[1] == 'D') && name
[2] == '_' || name
[1] == 'A' && name
[1] == 'N') || name
[0] == 'V' && name
[1] == 'P' && name
[2] == 'A' && name
[3] == 'T' && name
[4] == 'H' && name
[5] == 0 || name
[0] == '_' && name
[1] == 'R' && name
[2] == 'L' && name
[3] == 'D' || name
[0] == '_' && name
[1] == 'A' && name
[2] == 'S' && name
[3] == 'T' && name
[4] == '_')
2780 return(oldgetenv(name
));
2782 else if((np
= nv_search(name
,sh
.var_tree
,0)) && nv_isattr(np
,NV_EXPORT
))
2783 return(nv_getval(np
));
2787 #ifndef _NEXT_SOURCE
2789 * Some dynamic linkers will make this file see the libc getenv(),
2790 * so sh_getenv() is used for the astintercept() callback. Plain
2791 * getenv() is provided for static links.
2793 char *getenv(const char *name
)
2795 return sh_getenv(name
);
2797 #endif /* _NEXT_SOURCE */
2801 * This version of putenv uses the hash storage to assign environment values
2803 int putenv(const char *name
)
2805 register Namval_t
*np
;
2808 np
= nv_open(name
,sh
.var_tree
,NV_EXPORT
|NV_IDENT
|NV_NOARRAY
|NV_ASSIGN
);
2809 if(!strchr(name
,'='))
2816 * Override libast setenviron().
2818 char* sh_setenviron(const char *name
)
2820 register Namval_t
*np
;
2823 np
= nv_open(name
,sh
.var_tree
,NV_EXPORT
|NV_IDENT
|NV_NOARRAY
|NV_ASSIGN
);
2824 if(strchr(name
,'='))
2825 return(nv_getval(np
));
2832 * Same linker dance as with getenv() above.
2834 char* setenviron(const char *name
)
2836 return sh_setenviron(name
);
2840 * convert <str> to upper case
2842 static void ltou(register char *str
)
2845 for(; c
= *((unsigned char*)str
); str
++)
2853 * convert <str> to lower case
2855 static void utol(register char *str
)
2858 for(; c
= *((unsigned char*)str
); str
++)
2866 * normalize <cp> and return pointer to subscript if any
2867 * if <eq> is specified, return pointer to first = not in a subscript
2869 static char *lastdot(register char *cp
, int eq
)
2871 register char *ep
=0;
2882 cp
= nv_endsubscript((Namval_t
*)0,ep
=cp
,0);
2888 cp
= nv_endsubscript((Namval_t
*)0,ep
=cp
,0);
2889 if((ep
=sh_checkid(ep
+1,cp
)) < cp
)
2894 else if(eq
&& c
== '=')
2900 int nv_rename(register Namval_t
*np
, int flags
)
2903 register Namval_t
*mp
=0,*nr
=0;
2906 Namval_t
*last_table
= shp
->last_table
;
2907 Dt_t
*last_root
= shp
->last_root
;
2909 char *prefix
=shp
->prefix
,*nvenv
= 0;
2910 if(nv_isattr(np
,NV_PARAM
) && shp
->st
.prevst
)
2912 if(!(hp
=(Dt_t
*)shp
->st
.prevst
->save_tree
))
2913 hp
= dtvnext(shp
->var_tree
);
2915 if(!(cp
=nv_getval(np
)))
2918 errormsg(SH_DICT
,ERROR_exit(1),e_varname
,"");
2921 if(lastdot(cp
,0) && nv_isattr(np
,NV_MINIMAL
))
2922 errormsg(SH_DICT
,ERROR_exit(1),e_varname
,nv_name(np
));
2923 if(nv_isarray(np
) && !(mp
=nv_opensub(np
)))
2924 index
=nv_aindex(np
);
2928 if(!(nr
= nv_open(cp
, hp
, flags
|NV_ARRAY
|NV_NOREF
|NV_NOSCOPE
|NV_NOADD
|NV_NOFAIL
)))
2930 else if(shp
->last_root
)
2931 hp
= shp
->last_root
;
2933 nr
= nv_open(cp
, hp
, flags
|NV_NOREF
|((flags
&NV_MOVE
)?0:NV_NOFAIL
));
2934 shp
->prefix
= prefix
;
2941 if(!mp
&& index
>=0 && nv_isvtree(nr
))
2943 sfprintf(shp
->strbuf
,"%s[%d]%c",nv_name(np
),index
,0);
2944 /* create a virtual node */
2945 if(mp
= nv_open(sfstruse(shp
->strbuf
),shp
->var_tree
,NV_VARNAME
|NV_ADD
|NV_ARRAY
))
2946 mp
->nvenv
= (void*)np
;
2957 if(cp
= nv_getval(np
))
2961 if(!nv_isattr(np
,NV_MINIMAL
))
2965 nv_putsub(np
,(char*)0, index
);
2970 shp
->prev_table
= shp
->last_table
;
2971 shp
->prev_root
= shp
->last_root
;
2972 shp
->last_table
= last_table
;
2973 shp
->last_root
= last_root
;
2974 nv_clone(nr
,np
,(flags
&NV_MOVE
)|NV_COMVAR
);
2976 nv_delete(nr
,(Dt_t
*)0,NV_NOFREE
);
2981 * Create a reference node from <np> to $np in dictionary <hp>
2983 void nv_setref(register Namval_t
*np
, Dt_t
*hp
, int flags
)
2986 register Namval_t
*nq
, *nr
=0;
2987 register char *ep
,*cp
;
2988 Dt_t
*root
= shp
->last_root
;
2993 errormsg(SH_DICT
,ERROR_exit(1),e_badref
,nv_name(np
));
2994 if(!(cp
=nv_getval(np
)))
2997 nv_onattr(np
,NV_REF
);
3000 if((ep
= lastdot(cp
,0)) && nv_isattr(np
,NV_MINIMAL
))
3001 errormsg(SH_DICT
,ERROR_exit(1),e_badref
,nv_name(np
));
3004 if(!(nr
= nq
= nv_open(cp
, hp
, flags
|NV_NOSCOPE
|NV_NOADD
|NV_NOFAIL
)))
3005 hp
= shp
->last_root
==shp
->var_tree
?shp
->var_tree
:shp
->var_base
;
3006 else if(shp
->last_root
)
3007 hp
= shp
->last_root
;
3008 if(nq
&& ep
&& nv_isarray(nq
) && !nv_getsub(nq
))
3009 nv_endsubscript(nq
,ep
-1,NV_ADD
);
3012 nr
= nq
= nv_open(cp
, hp
, flags
);
3013 hp
= shp
->last_root
;
3015 if(shp
->last_root
== shp
->var_tree
&& root
!=shp
->var_tree
)
3017 _nv_unset(np
,NV_RDONLY
);
3018 nv_onattr(np
,NV_REF
);
3019 errormsg(SH_DICT
,ERROR_exit(1),e_globalref
,nv_name(np
));
3023 if(shp
->namespace && nv_dict(shp
->namespace)==hp
)
3024 errormsg(SH_DICT
,ERROR_exit(1),e_selfref
,nv_name(np
));
3025 /* bind to earlier scope, or add to global scope */
3026 if(!(hp
=dtvnext(hp
)) || (nq
=nv_search((char*)np
,hp
,NV_ADD
|HASH_BUCKET
))==np
)
3027 errormsg(SH_DICT
,ERROR_exit(1),e_selfref
,nv_name(np
));
3029 if(nq
&& !ep
&& (ap
=nv_arrayptr(nq
)) && !(ap
->nelem
&(ARRAY_UNDEF
|ARRAY_SCAN
)))
3033 /* cause subscript evaluation and return result */
3038 ep
[strlen(ep
)-1] = 0;
3039 nv_putsub(nr
, ep
, 0);
3040 ep
[strlen(ep
)-1] = ']';
3041 if(nq
= nv_opensub(nr
))
3048 nv_delete(np
,(Dt_t
*)0,0);
3049 np
->nvalue
.nrp
= newof(0,struct Namref
,1,0);
3050 np
->nvalue
.nrp
->np
= nq
;
3051 np
->nvalue
.nrp
->root
= hp
;
3053 np
->nvalue
.nrp
->sub
= strdup(ep
);
3054 np
->nvalue
.nrp
->table
= shp
->last_table
;
3055 nv_onattr(np
,NV_REF
|NV_NOFREE
);
3059 * get the scope corresponding to <index>
3060 * whence uses the same values as lseeek()
3062 Shscope_t
*sh_getscope(int index
, int whence
)
3064 register struct sh_scoped
*sp
, *topmost
;
3065 if(whence
==SEEK_CUR
)
3069 if ((struct sh_scoped
*)sh
.topscope
!= sh
.st
.self
)
3070 topmost
= (struct sh_scoped
*)sh
.topscope
;
3074 if(whence
==SEEK_SET
)
3077 while(sp
= sp
->prevst
)
3084 return((Shscope_t
*)0);
3085 while(index
-- && (sp
= sp
->prevst
));
3086 return((Shscope_t
*)sp
);
3090 * make <scoped> the top scope and return previous scope
3092 Shscope_t
*sh_setscope(Shscope_t
*scope
)
3094 Shscope_t
*old
= (Shscope_t
*)sh
.st
.self
;
3095 *sh
.st
.self
= sh
.st
;
3096 sh
.st
= *((struct sh_scoped
*)scope
);
3097 sh
.var_tree
= scope
->var_tree
;
3098 SH_PATHNAMENOD
->nvalue
.cp
= sh
.st
.filename
;
3099 SH_FUNNAMENOD
->nvalue
.cp
= sh
.st
.funname
;
3103 void sh_unscope(Shell_t
*shp
)
3105 register Dt_t
*root
= shp
->var_tree
;
3106 register Dt_t
*dp
= dtview(root
,(Dt_t
*)0);
3107 table_unset(shp
,root
,NV_RDONLY
|NV_NOSCOPE
,dp
);
3108 if(shp
->st
.real_fun
&& dp
==shp
->st
.real_fun
->sdict
)
3110 dp
= dtview(dp
,(Dt_t
*)0);
3111 shp
->st
.real_fun
->sdict
->view
= dp
;
3118 * The inverse of creating a reference node
3120 void nv_unref(register Namval_t
*np
)
3125 nv_offattr(np
,NV_NOFREE
|NV_REF
);
3128 nq
= nv_refnode(np
);
3129 free((void*)np
->nvalue
.nrp
);
3130 np
->nvalue
.cp
= strdup(nv_name(nq
));
3134 for(fp
=nq
->nvfun
; fp
; fp
= fp
->next
)
3136 if(fp
->disc
== &optimize_disc
)
3138 optimize_clear(nq
,fp
);
3147 * These following are for binary compatibility with the old hash library
3148 * They will be removed someday
3151 #if defined(__IMPORT__) && defined(__EXPORT__)
3152 # define extern __EXPORT__
3157 extern Dt_t
*hashscope(Dt_t
*root
)
3159 return(dtvnext(root
));
3164 extern Dt_t
*hashfree(Dt_t
*root
)
3166 Dt_t
*dp
= dtvnext(root
);
3173 extern char *hashname(void *obj
)
3175 Namval_t
*np
= (Namval_t
*)obj
;
3181 extern void *hashlook(Dt_t
*root
, const char *name
, int mode
,int size
)
3184 return((void*)nv_search(name
,root
,mode
));
3187 char *nv_name(register Namval_t
*np
)
3189 register Namval_t
*table
;
3190 register Namfun_t
*fp
;
3192 if(is_abuiltin(np
) || is_afunction(np
))
3194 if(!nv_isattr(np
,NV_MINIMAL
|NV_EXPORT
) && np
->nvenv
)
3196 Namval_t
*nq
= sh
.last_table
, *mp
= (Namval_t
*)np
->nvenv
;
3197 if(np
==sh
.last_table
)
3200 sfprintf(sh
.strbuf
,"%s[%s]",nv_name(mp
),np
->nvname
);
3202 sfprintf(sh
.strbuf
,"%s.%s",nv_name(mp
),np
->nvname
);
3204 return(sfstruse(sh
.strbuf
));
3208 sh
.last_table
= nv_parent(np
);
3210 sh
.last_table
= nv_create(np
,0, NV_LAST
,(Namfun_t
*)0);
3212 else if(!nv_isref(np
))
3214 for(fp
= np
->nvfun
; fp
; fp
=fp
->next
)
3215 if(fp
->disc
&& fp
->disc
->namef
)
3217 if(np
==sh
.last_table
)
3219 return((*fp
->disc
->namef
)(np
,fp
));
3222 if(!(table
=sh
.last_table
) || *np
->nvname
=='.' || table
==sh
.namespace || np
==table
)
3224 cp
= nv_name(table
);
3225 sfprintf(sh
.strbuf
,"%s.%s",cp
,np
->nvname
);
3226 return(sfstruse(sh
.strbuf
));
3229 Namval_t
*nv_lastdict(void)
3231 return(sh
.last_table
);
3236 * returns the data context for a builtin
3238 void *nv_context(Namval_t
*np
)
3240 return((void*)np
->nvfun
);
3243 #define DISABLE /* proto workaround */
3245 int nv_isnull
DISABLE (register Namval_t
*np
)
3247 return(nv_isnull(np
));
3251 int nv_setsize(register Namval_t
*np
, int size
)
3253 int oldsize
= nv_size(np
);
3259 Shell_t
*nv_shell(Namval_t
*np
)
3262 for(fp
=np
->nvfun
;fp
;fp
=fp
->next
)
3265 return((Shell_t
*)fp
->last
);
3272 void nv_unset(register Namval_t
*np
)