14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1982-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * AT&T Labs
234887Schin  *
244887Schin  */
254887Schin 
264887Schin #define putenv	___putenv
274887Schin 
284887Schin #include	"defs.h"
294887Schin #include	"variables.h"
304887Schin #include	"path.h"
314887Schin #include	"lexstates.h"
324887Schin #include	"timeout.h"
334887Schin #include	"FEATURE/externs"
344887Schin #include	"streval.h"
354887Schin 
368462SApril.Chin@Sun.COM #define NVCACHE		8	/* must be a power of 2 */
378462SApril.Chin@Sun.COM #define Empty	((char*)(e_sptbnl+3))
384887Schin static char	*savesub = 0;
394887Schin 
404887Schin #if !_lib_pathnative && _lib_uwin_path
414887Schin 
424887Schin #define _lib_pathnative		1
434887Schin 
444887Schin extern int	uwin_path(const char*, char*, int);
454887Schin 
464887Schin size_t
474887Schin pathnative(const char* path, char* buf, size_t siz)
484887Schin {
494887Schin 	return uwin_path(path, buf, siz);
504887Schin }
514887Schin 
524887Schin #endif /* _lib_pathnative */
534887Schin 
544887Schin static void	attstore(Namval_t*,void*);
554887Schin #ifndef _ENV_H
564887Schin static void	pushnam(Namval_t*,void*);
574887Schin static char	*staknam(Namval_t*, char*);
584887Schin #endif
598462SApril.Chin@Sun.COM static void	ltou(char*);
608462SApril.Chin@Sun.COM static void	utol(char*);
614887Schin static void	rightjust(char*, int, int);
628462SApril.Chin@Sun.COM static char	*lastdot(char*, int);
634887Schin 
644887Schin struct adata
654887Schin {
668462SApril.Chin@Sun.COM 	Shell_t		*sh;
678462SApril.Chin@Sun.COM 	Namval_t	*tp;
688462SApril.Chin@Sun.COM 	char		**argnam;
698462SApril.Chin@Sun.COM 	int		attsize;
708462SApril.Chin@Sun.COM 	char		*attval;
714887Schin };
724887Schin 
738462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
748462SApril.Chin@Sun.COM     struct sh_type
758462SApril.Chin@Sun.COM     {
768462SApril.Chin@Sun.COM 	void		*previous;
778462SApril.Chin@Sun.COM 	Namval_t	**nodes;
788462SApril.Chin@Sun.COM 	Namval_t	*rp;
798462SApril.Chin@Sun.COM 	short		numnodes;
808462SApril.Chin@Sun.COM 	short		maxnodes;
818462SApril.Chin@Sun.COM     };
828462SApril.Chin@Sun.COM #endif /*SHOPT_TYPEDEF */
838462SApril.Chin@Sun.COM 
848462SApril.Chin@Sun.COM #if NVCACHE
858462SApril.Chin@Sun.COM     struct Namcache
868462SApril.Chin@Sun.COM     {
878462SApril.Chin@Sun.COM 	struct Cache_entry
888462SApril.Chin@Sun.COM 	{
898462SApril.Chin@Sun.COM 		Dt_t		*root;
90*10898Sroland.mainz@nrubsig.org 		Dt_t		*last_root;
918462SApril.Chin@Sun.COM 		char		*name;
928462SApril.Chin@Sun.COM 		Namval_t	*np;
938462SApril.Chin@Sun.COM 		Namval_t	*last_table;
948462SApril.Chin@Sun.COM 		int		flags;
958462SApril.Chin@Sun.COM 		short		size;
968462SApril.Chin@Sun.COM 		short		len;
978462SApril.Chin@Sun.COM 	} entries[NVCACHE];
988462SApril.Chin@Sun.COM 	short		index;
998462SApril.Chin@Sun.COM 	short		ok;
1008462SApril.Chin@Sun.COM     };
1018462SApril.Chin@Sun.COM     static struct Namcache nvcache;
1028462SApril.Chin@Sun.COM #endif
1038462SApril.Chin@Sun.COM 
1044887Schin char		nv_local = 0;
1054887Schin #ifndef _ENV_H
1064887Schin static void(*nullscan)(Namval_t*,void*);
1074887Schin #endif
1084887Schin 
1094887Schin #if ( SFIO_VERSION  <= 20010201L )
1104887Schin #   define _data        data
1114887Schin #endif
1124887Schin 
1134887Schin #if !SHOPT_MULTIBYTE
1144887Schin #   define mbchar(p)       (*(unsigned char*)p++)
1154887Schin #endif /* SHOPT_MULTIBYTE */
1164887Schin 
1174887Schin /* ========	name value pair routines	======== */
1184887Schin 
1194887Schin #include	"shnodes.h"
1204887Schin #include	"builtins.h"
1214887Schin 
1224887Schin static char *getbuf(size_t len)
1234887Schin {
1244887Schin 	static char *buf;
1254887Schin 	static size_t buflen;
1264887Schin 	if(buflen < len)
1274887Schin 	{
1284887Schin 		if(buflen==0)
1294887Schin 			buf = (char*)malloc(len);
1304887Schin 		else
1314887Schin 			buf = (char*)realloc(buf,len);
1324887Schin 		buflen = len;
1334887Schin 	}
1344887Schin 	return(buf);
1354887Schin }
1364887Schin 
1374887Schin #ifdef _ENV_H
1384887Schin void sh_envput(Env_t* ep,Namval_t *np)
1394887Schin {
1404887Schin 	int offset = staktell();
1414887Schin 	Namarr_t *ap = nv_arrayptr(np);
1424887Schin 	char *val;
1434887Schin 	if(ap)
1444887Schin 	{
1454887Schin 		if(ap->nelem&ARRAY_UNDEF)
1464887Schin 			nv_putsub(np,"0",0L);
1474887Schin 		else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
1484887Schin 			return;
1494887Schin 	}
1504887Schin 	if(!(val = nv_getval(np)))
1514887Schin 		return;
1524887Schin 	stakputs(nv_name(np));
1534887Schin 	stakputc('=');
1544887Schin 	stakputs(val);
1554887Schin 	stakseek(offset);
1564887Schin 	env_add(ep,stakptr(offset),ENV_STRDUP);
1574887Schin }
1584887Schin #endif
1594887Schin 
1604887Schin /*
1614887Schin  * output variable name in format for re-input
1624887Schin  */
1634887Schin void nv_outname(Sfio_t *out, char *name, int len)
1644887Schin {
1654887Schin 	const char *cp=name, *sp;
1664887Schin 	int c, offset = staktell();
1674887Schin 	while(sp= strchr(cp,'['))
1684887Schin 	{
1694887Schin 		if(len>0 && cp+len <= sp)
1704887Schin 			break;
1714887Schin 		sfwrite(out,cp,++sp-cp);
1724887Schin 		stakseek(offset);
1738462SApril.Chin@Sun.COM 		while(c= *sp++)
1744887Schin 		{
1754887Schin 			if(c==']')
1764887Schin 				break;
1774887Schin 			else if(c=='\\')
1784887Schin 			{
1794887Schin 				if(*sp=='[' || *sp==']' || *sp=='\\')
1804887Schin 					c = *sp++;
1814887Schin 			}
1824887Schin 			stakputc(c);
1834887Schin 		}
1844887Schin 		stakputc(0);
1854887Schin 		sfputr(out,sh_fmtq(stakptr(offset)),-1);
1864887Schin 		if(len>0)
1874887Schin 		{
1884887Schin 			sfputc(out,']');
1894887Schin 			return;
1904887Schin 		}
1918462SApril.Chin@Sun.COM 		cp = sp-1;
1924887Schin 	}
1934887Schin 	if(*cp)
1944887Schin 	{
1954887Schin 		if(len>0)
1964887Schin 			sfwrite(out,cp,len);
1974887Schin 		else
1984887Schin 			sfputr(out,cp,-1);
1994887Schin 	}
2004887Schin 	stakseek(offset);
2014887Schin }
2024887Schin 
2038462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
2048462SApril.Chin@Sun.COM Namval_t *nv_addnode(Namval_t* np, int remove)
2058462SApril.Chin@Sun.COM {
2068462SApril.Chin@Sun.COM 	register struct sh_type	*sp = (struct sh_type*)sh.mktype;
2078462SApril.Chin@Sun.COM 	register int		i;
2088462SApril.Chin@Sun.COM 	register char		*name=0;
2098462SApril.Chin@Sun.COM 	if(sp->numnodes==0 && !nv_isnull(np) && sh.last_table)
2108462SApril.Chin@Sun.COM 	{
2118462SApril.Chin@Sun.COM 		/* could be an redefine */
2128462SApril.Chin@Sun.COM 		Dt_t *root = nv_dict(sh.last_table);
2138462SApril.Chin@Sun.COM 		sp->rp = np;
2148462SApril.Chin@Sun.COM 		nv_delete(np,root,NV_NOFREE);
2158462SApril.Chin@Sun.COM 		np = nv_search(sp->rp->nvname,root,NV_ADD);
2168462SApril.Chin@Sun.COM 	}
2178462SApril.Chin@Sun.COM 	if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1))
2188462SApril.Chin@Sun.COM 	{
2198462SApril.Chin@Sun.COM 		name = (sp->nodes[0])->nvname;
2208462SApril.Chin@Sun.COM 		i = strlen(name);
2218462SApril.Chin@Sun.COM 		if(memcmp(np->nvname,name,i))
2228462SApril.Chin@Sun.COM 			return(np);
2238462SApril.Chin@Sun.COM 	}
2248462SApril.Chin@Sun.COM 	if(sp->rp && sp->numnodes)
2258462SApril.Chin@Sun.COM 	{
2268462SApril.Chin@Sun.COM 		/* check for a redefine */
2278462SApril.Chin@Sun.COM 		if(name && np->nvname[i]=='.' && np->nvname[i+1]=='_' && np->nvname[i+2]==0)
2288462SApril.Chin@Sun.COM 			sp->rp = 0;
2298462SApril.Chin@Sun.COM 		else
2308462SApril.Chin@Sun.COM 		{
2318462SApril.Chin@Sun.COM 			Dt_t *root = nv_dict(sh.last_table);
2328462SApril.Chin@Sun.COM 			nv_delete(sp->nodes[0],root,NV_NOFREE);
2338462SApril.Chin@Sun.COM 			dtinsert(root,sp->rp);
2348462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),e_redef,sp->nodes[0]->nvname);
2358462SApril.Chin@Sun.COM 		}
2368462SApril.Chin@Sun.COM 	}
2378462SApril.Chin@Sun.COM 	for(i=0; i < sp->numnodes; i++)
2388462SApril.Chin@Sun.COM 	{
2398462SApril.Chin@Sun.COM 		if(np == sp->nodes[i])
2408462SApril.Chin@Sun.COM 		{
2418462SApril.Chin@Sun.COM 			if(remove)
2428462SApril.Chin@Sun.COM 			{
2438462SApril.Chin@Sun.COM 				while(++i < sp->numnodes)
2448462SApril.Chin@Sun.COM 					sp->nodes[i-1] = sp->nodes[i];
2458462SApril.Chin@Sun.COM 				sp->numnodes--;
2468462SApril.Chin@Sun.COM 			}
2478462SApril.Chin@Sun.COM 			return(np);
2488462SApril.Chin@Sun.COM 		}
2498462SApril.Chin@Sun.COM 	}
2508462SApril.Chin@Sun.COM 	if(remove)
2518462SApril.Chin@Sun.COM 		return(np);
2528462SApril.Chin@Sun.COM 	if(sp->numnodes==sp->maxnodes)
2538462SApril.Chin@Sun.COM 	{
2548462SApril.Chin@Sun.COM 		sp->maxnodes += 20;
2558462SApril.Chin@Sun.COM 		sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes);
2568462SApril.Chin@Sun.COM 	}
2578462SApril.Chin@Sun.COM 	sp->nodes[sp->numnodes++] = np;
2588462SApril.Chin@Sun.COM 	return(np);
2598462SApril.Chin@Sun.COM }
2608462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
2618462SApril.Chin@Sun.COM 
2628462SApril.Chin@Sun.COM /*
2638462SApril.Chin@Sun.COM  * given a list of assignments, determine <name> is on the list
2648462SApril.Chin@Sun.COM    returns a pointer to the argnod on the list or NULL
2658462SApril.Chin@Sun.COM  */
2668462SApril.Chin@Sun.COM struct argnod *nv_onlist(struct argnod *arg, const char *name)
2678462SApril.Chin@Sun.COM {
2688462SApril.Chin@Sun.COM 	char *cp;
2698462SApril.Chin@Sun.COM 	int len = strlen(name);
2708462SApril.Chin@Sun.COM 	for(;arg; arg=arg->argnxt.ap)
2718462SApril.Chin@Sun.COM 	{
2728462SApril.Chin@Sun.COM 		if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
2738462SApril.Chin@Sun.COM 			cp = ((struct fornod*)arg->argchn.ap)->fornam;
2748462SApril.Chin@Sun.COM 		else
2758462SApril.Chin@Sun.COM 			cp = arg->argval;
2768462SApril.Chin@Sun.COM 		if(memcmp(cp,name,len)==0 && (cp[len]==0 || cp[len]=='='))
2778462SApril.Chin@Sun.COM 			return(arg);
2788462SApril.Chin@Sun.COM 	}
2798462SApril.Chin@Sun.COM 	return(0);
2808462SApril.Chin@Sun.COM }
2818462SApril.Chin@Sun.COM 
2824887Schin /*
2834887Schin  * Perform parameter assignment for a linked list of parameters
2844887Schin  * <flags> contains attributes for the parameters
2854887Schin  */
286*10898Sroland.mainz@nrubsig.org void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
2874887Schin {
2888462SApril.Chin@Sun.COM 	Shell_t		*shp = &sh;
2894887Schin 	register char	*cp;
2908462SApril.Chin@Sun.COM 	register Namval_t *np, *mp;
2918462SApril.Chin@Sun.COM 	char		*trap=shp->st.trap[SH_DEBUGTRAP];
2928462SApril.Chin@Sun.COM 	char		*prefix = shp->prefix;
2934887Schin 	int		traceon = (sh_isoption(SH_XTRACE)!=0);
2944887Schin 	int		array = (flags&(NV_ARRAY|NV_IARRAY));
2958462SApril.Chin@Sun.COM 	Namarr_t	*ap;
2968462SApril.Chin@Sun.COM 	Namval_t	node;
2978462SApril.Chin@Sun.COM 	struct Namref	nr;
2988462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
2998462SApril.Chin@Sun.COM 	int		maketype = flags&NV_TYPE;
3008462SApril.Chin@Sun.COM 	struct sh_type	shtp;
3018462SApril.Chin@Sun.COM 	if(maketype)
3028462SApril.Chin@Sun.COM 	{
3038462SApril.Chin@Sun.COM 		shtp.previous = shp->mktype;
3048462SApril.Chin@Sun.COM 		shp->mktype=(void*)&shtp;
3058462SApril.Chin@Sun.COM 		shtp.numnodes=0;
3068462SApril.Chin@Sun.COM 		shtp.maxnodes = 20;
3078462SApril.Chin@Sun.COM 		shtp.rp = 0;
3088462SApril.Chin@Sun.COM 		shtp.nodes =(Namval_t**)malloc(shtp.maxnodes*sizeof(Namval_t*));
3098462SApril.Chin@Sun.COM 	}
3108462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF*/
3118462SApril.Chin@Sun.COM 	flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY);
3124887Schin 	if(sh_isoption(SH_ALLEXPORT))
3134887Schin 		flags |= NV_EXPORT;
3148462SApril.Chin@Sun.COM 	if(shp->prefix)
3154887Schin 	{
3164887Schin 		flags &= ~(NV_IDENT|NV_EXPORT);
3174887Schin 		flags |= NV_VARNAME;
3184887Schin 	}
3194887Schin 	for(;arg; arg=arg->argnxt.ap)
3204887Schin 	{
3218462SApril.Chin@Sun.COM 		shp->used_pos = 0;
3224887Schin 		if(arg->argflag&ARG_MAC)
3238462SApril.Chin@Sun.COM 		{
3248462SApril.Chin@Sun.COM 			shp->prefix = 0;
3258462SApril.Chin@Sun.COM 			cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1);
3268462SApril.Chin@Sun.COM 			shp->prefix = prefix;
3278462SApril.Chin@Sun.COM 		}
3284887Schin 		else
3294887Schin 		{
3304887Schin 			stakseek(0);
3318462SApril.Chin@Sun.COM 			if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
3324887Schin 			{
3334887Schin 				int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
3348462SApril.Chin@Sun.COM 				int sub=0;
3354887Schin 				struct fornod *fp=(struct fornod*)arg->argchn.ap;
3364887Schin 				register Shnode_t *tp=fp->fortre;
3378462SApril.Chin@Sun.COM 				flag |= (flags&(NV_NOSCOPE|NV_STATIC));
3384887Schin 				if(arg->argflag&ARG_QUOTED)
3398462SApril.Chin@Sun.COM 					cp = sh_mactrim(shp,fp->fornam,-1);
3404887Schin 				else
3414887Schin 					cp = fp->fornam;
3428462SApril.Chin@Sun.COM 				error_info.line = fp->fortyp-shp->st.firstline;
343*10898Sroland.mainz@nrubsig.org 				if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[')
344*10898Sroland.mainz@nrubsig.org 					array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY;
3458462SApril.Chin@Sun.COM 				if(shp->fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET)
3464887Schin 			                flag |= NV_NOSCOPE;
3474887Schin 				if(prefix && tp->com.comset && *cp=='[')
3484887Schin 				{
3498462SApril.Chin@Sun.COM 					shp->prefix = 0;
3508462SApril.Chin@Sun.COM 					np = nv_open(prefix,shp->var_tree,flag);
3518462SApril.Chin@Sun.COM 					shp->prefix = prefix;
3524887Schin 					if(np)
3534887Schin 					{
3548462SApril.Chin@Sun.COM 						if(nv_isvtree(np) && !nv_isarray(np))
3554887Schin 						{
3564887Schin 							stakputc('.');
3574887Schin 							stakputs(cp);
3584887Schin 							cp = stakfreeze(1);
3594887Schin 						}
3604887Schin 						nv_close(np);
3614887Schin 					}
3624887Schin 				}
3638462SApril.Chin@Sun.COM 				np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN);
364*10898Sroland.mainz@nrubsig.org 				if(typ && !array  && (nv_isnull(np) || nv_isarray(np)))
365*10898Sroland.mainz@nrubsig.org 					nv_settype(np,typ,0);
3668462SApril.Chin@Sun.COM 				if((flags&NV_STATIC) && !nv_isnull(np))
3678462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
3688462SApril.Chin@Sun.COM 					goto check_type;
3698462SApril.Chin@Sun.COM #else
3708462SApril.Chin@Sun.COM 					continue;
3718462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
372*10898Sroland.mainz@nrubsig.org 				if(array && (!(ap=nv_arrayptr(np)) || !ap->hdr.type))
3734887Schin 				{
3748462SApril.Chin@Sun.COM 					if(!(arg->argflag&ARG_APPEND))
3754887Schin 						nv_unset(np);
3764887Schin 					if(array&NV_ARRAY)
3774887Schin 					{
3784887Schin 						nv_setarray(np,nv_associative);
3794887Schin 					}
3804887Schin 					else
3814887Schin 					{
3824887Schin 						nv_onattr(np,NV_ARRAY);
3834887Schin 					}
384*10898Sroland.mainz@nrubsig.org 				}
385*10898Sroland.mainz@nrubsig.org 				if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg)
386*10898Sroland.mainz@nrubsig.org 				{
3878462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
3888462SApril.Chin@Sun.COM 						goto check_type;
3898462SApril.Chin@Sun.COM #else
3908462SApril.Chin@Sun.COM 						continue;
3918462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
3924887Schin 				}
3934887Schin 				/* check for array assignment */
3944887Schin 				if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))
3954887Schin 				{
3964887Schin 					int argc;
3978462SApril.Chin@Sun.COM 					Dt_t	*last_root = shp->last_root;
3988462SApril.Chin@Sun.COM 					char **argv = sh_argbuild(shp,&argc,&tp->com,0);
3998462SApril.Chin@Sun.COM 					shp->last_root = last_root;
4008462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
4018462SApril.Chin@Sun.COM 					if(shp->mktype && shp->dot_depth==0 && np==((struct sh_type*)shp->mktype)->nodes[0])
4028462SApril.Chin@Sun.COM 					{
4038462SApril.Chin@Sun.COM 						shp->mktype = 0;
4048462SApril.Chin@Sun.COM 						errormsg(SH_DICT,ERROR_exit(1),"%s: not a known type name",argv[0]);
4058462SApril.Chin@Sun.COM 					}
4068462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
4074887Schin 					if(!(arg->argflag&ARG_APPEND))
4084887Schin 					{
4098462SApril.Chin@Sun.COM 						if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && (ap->nelem&ARRAY_MASK)))
4108462SApril.Chin@Sun.COM 							nv_unset(np);
4114887Schin 					}
4124887Schin 					nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv);
4134887Schin 					if(traceon || trap)
4144887Schin 					{
4154887Schin 						int n = -1;
4164887Schin 						char *name = nv_name(np);
4174887Schin 						if(arg->argflag&ARG_APPEND)
4184887Schin 							n = '+';
4194887Schin 						if(trap)
4208462SApril.Chin@Sun.COM 							sh_debug(shp,trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN);
4214887Schin 						if(traceon)
4224887Schin 						{
4234887Schin 							sh_trace(NIL(char**),0);
4244887Schin 							sfputr(sfstderr,name,n);
4254887Schin 							sfwrite(sfstderr,"=( ",3);
4264887Schin 							while(cp= *argv++)
4274887Schin 								sfputr(sfstderr,sh_fmtq(cp),' ');
4284887Schin 							sfwrite(sfstderr,")\n",2);
4294887Schin 						}
4304887Schin 					}
4318462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
4328462SApril.Chin@Sun.COM 					goto check_type;
4338462SApril.Chin@Sun.COM #else
4344887Schin 					continue;
4358462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
4364887Schin 				}
4378462SApril.Chin@Sun.COM 				if((tp->tre.tretyp&COMMSK)==TFUN)
4388462SApril.Chin@Sun.COM 					goto skip;
4394887Schin 				if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[')
4404887Schin 				{
4418462SApril.Chin@Sun.COM 					if(tp->tre.tretyp!=TLST && !tp->com.comnamp && tp->com.comset && tp->com.comset->argval[0]==0 && tp->com.comset->argchn.ap)
4428462SApril.Chin@Sun.COM 					{
4438462SApril.Chin@Sun.COM 						if(prefix)
4448462SApril.Chin@Sun.COM 							cp = stakcopy(nv_name(np));
4458462SApril.Chin@Sun.COM 						shp->prefix = cp;
4468462SApril.Chin@Sun.COM 						if(tp->com.comset->argval[1]=='[')
4478462SApril.Chin@Sun.COM 						{
4488462SApril.Chin@Sun.COM 							if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0)))
4498462SApril.Chin@Sun.COM 								nv_unset(np);
4508462SApril.Chin@Sun.COM 							if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE))
4518462SApril.Chin@Sun.COM 								nv_setarray(np,nv_associative);
4528462SApril.Chin@Sun.COM 						}
453*10898Sroland.mainz@nrubsig.org 						nv_setlist(tp->com.comset,flags,0);
4548462SApril.Chin@Sun.COM 						shp->prefix = prefix;
4558462SApril.Chin@Sun.COM 						if(tp->com.comset->argval[1]!='[')
4568462SApril.Chin@Sun.COM 							 nv_setvtree(np);
4578462SApril.Chin@Sun.COM 						nv_close(np);
4588462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
4598462SApril.Chin@Sun.COM 						goto check_type;
4608462SApril.Chin@Sun.COM #else
4618462SApril.Chin@Sun.COM 						continue;
4628462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
4638462SApril.Chin@Sun.COM 					}
4644887Schin 					if(*cp!='.' && *cp!='[' && strchr(cp,'['))
4654887Schin 					{
4664887Schin 						nv_close(np);
4678462SApril.Chin@Sun.COM 						np = nv_open(cp,shp->var_tree,flag);
4684887Schin 					}
4698462SApril.Chin@Sun.COM 					if(arg->argflag&ARG_APPEND)
4708462SApril.Chin@Sun.COM 					{
4718462SApril.Chin@Sun.COM 						if(nv_isarray(np))
4728462SApril.Chin@Sun.COM 						{
4738462SApril.Chin@Sun.COM 							if((sub=nv_aimax(np)) < 0  && nv_arrayptr(np))
4748462SApril.Chin@Sun.COM 								errormsg(SH_DICT,ERROR_exit(1),e_badappend,nv_name(np));
4758462SApril.Chin@Sun.COM 							if(sub>=0)
4768462SApril.Chin@Sun.COM 								sub++;
4778462SApril.Chin@Sun.COM 						}
4788462SApril.Chin@Sun.COM 						if(!nv_isnull(np) && np->nvalue.cp!=Empty && !nv_isvtree(np))
4798462SApril.Chin@Sun.COM 							sub=1;
4808462SApril.Chin@Sun.COM 					}
4818462SApril.Chin@Sun.COM 					else if(np->nvalue.cp && np->nvalue.cp!=Empty && !nv_type(np))
4828462SApril.Chin@Sun.COM 					{
4838462SApril.Chin@Sun.COM 						_nv_unset(np,NV_EXPORT);
4848462SApril.Chin@Sun.COM 					}
4854887Schin 				}
4864887Schin 				else
4874887Schin 				{
4888462SApril.Chin@Sun.COM 					if(!(arg->argflag&ARG_APPEND))
4898462SApril.Chin@Sun.COM 						_nv_unset(np,NV_EXPORT);
4908462SApril.Chin@Sun.COM 					if(!sh_isoption(SH_BASH) && !(array&NV_IARRAY) && !nv_isarray(np))
4914887Schin 						nv_setarray(np,nv_associative);
4924887Schin 				}
4938462SApril.Chin@Sun.COM 			skip:
4948462SApril.Chin@Sun.COM 				if(sub>0)
4958462SApril.Chin@Sun.COM 				{
4968462SApril.Chin@Sun.COM 					sfprintf(stkstd,"%s[%d]",prefix?nv_name(np):cp,sub);
4978462SApril.Chin@Sun.COM 					shp->prefix = stakfreeze(1);
4988462SApril.Chin@Sun.COM 					nv_putsub(np,(char*)0,ARRAY_ADD|ARRAY_FILL|sub);
4998462SApril.Chin@Sun.COM 				}
5008462SApril.Chin@Sun.COM 				else if(prefix)
5018462SApril.Chin@Sun.COM 					shp->prefix = stakcopy(nv_name(np));
5028462SApril.Chin@Sun.COM 				else
5038462SApril.Chin@Sun.COM 					shp->prefix = cp;
5048462SApril.Chin@Sun.COM 				shp->last_table = 0;
505*10898Sroland.mainz@nrubsig.org 				if(shp->prefix)
506*10898Sroland.mainz@nrubsig.org 				{
507*10898Sroland.mainz@nrubsig.org 					if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD))
508*10898Sroland.mainz@nrubsig.org 					{
509*10898Sroland.mainz@nrubsig.org 						sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1);
510*10898Sroland.mainz@nrubsig.org 						shp->prefix = stkfreeze(stkstd,1);
511*10898Sroland.mainz@nrubsig.org 					}
512*10898Sroland.mainz@nrubsig.org 					memset(&nr,0,sizeof(nr));
513*10898Sroland.mainz@nrubsig.org 					memcpy(&node,L_ARGNOD,sizeof(node));
514*10898Sroland.mainz@nrubsig.org 					L_ARGNOD->nvalue.nrp = &nr;
515*10898Sroland.mainz@nrubsig.org 					nr.np = np;
516*10898Sroland.mainz@nrubsig.org 					nr.root = shp->last_root;
517*10898Sroland.mainz@nrubsig.org 					nr.table = shp->last_table;
518*10898Sroland.mainz@nrubsig.org 					L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
519*10898Sroland.mainz@nrubsig.org 					L_ARGNOD->nvfun = 0;
520*10898Sroland.mainz@nrubsig.org 				}
5214887Schin 				sh_exec(tp,sh_isstate(SH_ERREXIT));
5228462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
523*10898Sroland.mainz@nrubsig.org 				if(shp->prefix)
5248462SApril.Chin@Sun.COM #endif
5258462SApril.Chin@Sun.COM 				{
5268462SApril.Chin@Sun.COM 					L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
5278462SApril.Chin@Sun.COM 					L_ARGNOD->nvflag = node.nvflag;
5288462SApril.Chin@Sun.COM 					L_ARGNOD->nvfun = node.nvfun;
5298462SApril.Chin@Sun.COM 				}
5308462SApril.Chin@Sun.COM 				shp->prefix = prefix;
5314887Schin 				if(nv_isarray(np) && (mp=nv_opensub(np)))
5324887Schin 					np = mp;
5338462SApril.Chin@Sun.COM 				while(tp->tre.tretyp==TLST)
5348462SApril.Chin@Sun.COM 				{
5358462SApril.Chin@Sun.COM 					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]!='[')
5368462SApril.Chin@Sun.COM 						break;
5378462SApril.Chin@Sun.COM 					tp = tp->lst.lstrit;
5388462SApril.Chin@Sun.COM 
5398462SApril.Chin@Sun.COM 				}
540*10898Sroland.mainz@nrubsig.org 				if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='['))
5418462SApril.Chin@Sun.COM 					nv_setvtree(np);
5428462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
5438462SApril.Chin@Sun.COM 				goto check_type;
5448462SApril.Chin@Sun.COM #else
5454887Schin 				continue;
5468462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
5474887Schin 			}
5484887Schin 			cp = arg->argval;
5498462SApril.Chin@Sun.COM 			mp = 0;
5504887Schin 		}
5518462SApril.Chin@Sun.COM 		np = nv_open(cp,shp->var_tree,flags);
5528462SApril.Chin@Sun.COM 		if(!np->nvfun && (flags&NV_NOREF))
5534887Schin 		{
5548462SApril.Chin@Sun.COM 			if(shp->used_pos)
5554887Schin 				nv_onattr(np,NV_PARAM);
5564887Schin 			else
5574887Schin 				nv_offattr(np,NV_PARAM);
5584887Schin 		}
5594887Schin 		if(traceon || trap)
5604887Schin 		{
5614887Schin 			register char *sp=cp;
5624887Schin 			char *name=nv_name(np);
5634887Schin 			char *sub=0;
5644887Schin 			int append = 0;
5654887Schin 			if(nv_isarray(np))
5664887Schin 				sub = savesub;
5678462SApril.Chin@Sun.COM 			if(cp=lastdot(sp,'='))
5684887Schin 			{
5694887Schin 				if(cp[-1]=='+')
5704887Schin 					append = ARG_APPEND;
5714887Schin 				cp++;
5724887Schin 			}
5734887Schin 			if(traceon)
5744887Schin 			{
5754887Schin 				sh_trace(NIL(char**),0);
5764887Schin 				nv_outname(sfstderr,name,-1);
5774887Schin 				if(sub)
5784887Schin 					sfprintf(sfstderr,"[%s]",sh_fmtq(sub));
5794887Schin 				if(cp)
5804887Schin 				{
5814887Schin 					if(append)
5824887Schin 						sfputc(sfstderr,'+');
5834887Schin 					sfprintf(sfstderr,"=%s\n",sh_fmtq(cp));
5844887Schin 				}
5854887Schin 			}
5864887Schin 			if(trap)
5874887Schin 			{
5884887Schin 					char *av[2];
5894887Schin 					av[0] = cp;
5904887Schin 					av[1] = 0;
5918462SApril.Chin@Sun.COM 					sh_debug(shp,trap,name,sub,av,append);
5924887Schin 			}
5934887Schin 		}
5948462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
5958462SApril.Chin@Sun.COM 	check_type:
5968462SApril.Chin@Sun.COM 		if(maketype)
5978462SApril.Chin@Sun.COM 		{
5988462SApril.Chin@Sun.COM 			nv_open(shtp.nodes[0]->nvname,shp->var_tree,NV_ASSIGN|NV_VARNAME|NV_NOADD|NV_NOFAIL);
5998462SApril.Chin@Sun.COM 			np = nv_mktype(shtp.nodes,shtp.numnodes);
6008462SApril.Chin@Sun.COM 			free((void*)shtp.nodes);
6018462SApril.Chin@Sun.COM 			shp->mktype = shtp.previous;
6028462SApril.Chin@Sun.COM 			maketype = 0;
6038462SApril.Chin@Sun.COM 			shp->prefix = 0;
6048462SApril.Chin@Sun.COM 			if(nr.np == np)
6058462SApril.Chin@Sun.COM 			{
6068462SApril.Chin@Sun.COM 				L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
6078462SApril.Chin@Sun.COM 				L_ARGNOD->nvflag = node.nvflag;
6088462SApril.Chin@Sun.COM 				L_ARGNOD->nvfun = node.nvfun;
6098462SApril.Chin@Sun.COM 			}
6108462SApril.Chin@Sun.COM 		}
6118462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
6124887Schin 	}
6134887Schin }
6144887Schin 
6154887Schin /*
6164887Schin  * copy the subscript onto the stack
6174887Schin  */
6184887Schin static void stak_subscript(const char *sub, int last)
6194887Schin {
6204887Schin 	register int c;
6214887Schin 	stakputc('[');
6224887Schin 	while(c= *sub++)
6234887Schin 	{
6244887Schin 		if(c=='[' || c==']' || c=='\\')
6254887Schin 			stakputc('\\');
6264887Schin 		stakputc(c);
6274887Schin 	}
6284887Schin 	stakputc(last);
6294887Schin }
6304887Schin 
6314887Schin /*
6324887Schin  * construct a new name from a prefix and base name on the stack
6334887Schin  */
6344887Schin static char *copystack(const char *prefix, register const char *name, const char *sub)
6354887Schin {
6364887Schin 	register int last=0,offset = staktell();
6374887Schin 	if(prefix)
6384887Schin 	{
6394887Schin 		stakputs(prefix);
6404887Schin 		if(*stakptr(staktell()-1)=='.')
6414887Schin 			stakseek(staktell()-1);
6424887Schin 		if(*name=='.' && name[1]=='[')
6434887Schin 			last = staktell()+2;
6448462SApril.Chin@Sun.COM 		if(*name!='['  && *name!='.' && *name!='=' && *name!='+')
6458462SApril.Chin@Sun.COM 			stakputc('.');
6468462SApril.Chin@Sun.COM 		if(*name=='.' && (name[1]=='=' || name[1]==0))
6474887Schin 			stakputc('.');
6484887Schin 	}
6494887Schin 	if(last)
6504887Schin 	{
6514887Schin 		stakputs(name);
6524887Schin 		if(sh_checkid(stakptr(last),(char*)0))
6534887Schin 			stakseek(staktell()-2);
6544887Schin 	}
6554887Schin 	if(sub)
6564887Schin 		stak_subscript(sub,']');
6574887Schin 	if(!last)
6584887Schin 		stakputs(name);
6594887Schin 	stakputc(0);
6604887Schin 	return(stakptr(offset));
6614887Schin }
6624887Schin 
6634887Schin /*
6644887Schin  * grow this stack string <name> by <n> bytes and move from cp-1 to end
6654887Schin  * right by <n>.  Returns beginning of string on the stack
6664887Schin  */
6674887Schin static char *stack_extend(const char *cname, char *cp, int n)
6684887Schin {
6694887Schin 	register char *name = (char*)cname;
6704887Schin 	int offset = name - stakptr(0);
6714887Schin 	int m = cp-name;
6724887Schin 	stakseek(strlen(name)+n+1);
6734887Schin 	name = stakptr(offset);
6744887Schin 	cp =  name + m;
6754887Schin 	m = strlen(cp)+1;
6764887Schin 	while(m-->0)
6774887Schin 		cp[n+m]=cp[m];
6784887Schin 	return((char*)name);
6794887Schin }
6804887Schin 
6818462SApril.Chin@Sun.COM Namval_t *nv_create(const char *name,  Dt_t *root, int flags, Namfun_t *dp)
6824887Schin {
6838462SApril.Chin@Sun.COM 	Shell_t			*shp = &sh;
6844887Schin 	char			*cp=(char*)name, *sp, *xp;
6854887Schin 	register int		c;
6864887Schin 	register Namval_t	*np=0, *nq=0;
6874887Schin 	Namfun_t		*fp=0;
6884887Schin 	long			mode, add=0;
6894887Schin 	int			copy=1,isref,top=0,noscope=(flags&NV_NOSCOPE);
6908462SApril.Chin@Sun.COM 	if(root==shp->var_tree)
6914887Schin 	{
6924887Schin 		if(dtvnext(root))
6934887Schin 			top = 1;
6944887Schin 		else
6954887Schin 			flags &= ~NV_NOSCOPE;
6964887Schin 	}
6974887Schin 	if(!dp->disc)
6988462SApril.Chin@Sun.COM 		copy = dp->nofree&1;
6994887Schin 	if(*cp=='.')
7004887Schin 		cp++;
7014887Schin 	while(1)
7024887Schin 	{
7034887Schin 		switch(c = *(unsigned char*)(sp = cp))
7044887Schin 		{
7054887Schin 		    case '[':
7064887Schin 			if(flags&NV_NOARRAY)
7074887Schin 			{
7084887Schin 				dp->last = cp;
7094887Schin 				return(np);
7104887Schin 			}
7114887Schin 			cp = nv_endsubscript((Namval_t*)0,sp,0);
7124887Schin 			if(sp==name || sp[-1]=='.')
7134887Schin 				c = *(sp = cp);
7144887Schin 			goto skip;
7154887Schin 		    case '.':
7164887Schin 			if(flags&NV_IDENT)
7174887Schin 				return(0);
7188462SApril.Chin@Sun.COM 			if(root==shp->var_tree)
7194887Schin 				flags &= ~NV_EXPORT;
7204887Schin 			if(!copy && !(flags&NV_NOREF))
7214887Schin 			{
7224887Schin 				c = sp-name;
7234887Schin 				copy = cp-name;
7248462SApril.Chin@Sun.COM 				dp->nofree |= 1;
7254887Schin 				name = copystack((const char*)0, name,(const char*)0);
7264887Schin 				cp = (char*)name+copy;
7274887Schin 				sp = (char*)name+c;
7284887Schin 				c = '.';
7294887Schin 			}
7304887Schin 		skip:
7314887Schin 		    case '+':
7324887Schin 		    case '=':
7334887Schin 			*sp = 0;
7344887Schin 		    case 0:
7354887Schin 			isref = 0;
7364887Schin 			dp->last = cp;
7374887Schin 			mode =  (c=='.' || (flags&NV_NOADD))?add:NV_ADD;
7388462SApril.Chin@Sun.COM 			if((flags&NV_NOSCOPE) && c!='.')
7394887Schin 				mode |= HASH_NOSCOPE;
7408462SApril.Chin@Sun.COM 			np=0;
7414887Schin 			if(top)
7428462SApril.Chin@Sun.COM 			{
7438462SApril.Chin@Sun.COM 				struct Ufunction *rp;
7448462SApril.Chin@Sun.COM 				if((rp=shp->st.real_fun) && !rp->sdict && (flags&NV_STATIC))
7458462SApril.Chin@Sun.COM 				{
7468462SApril.Chin@Sun.COM 					Dt_t *dp = dtview(shp->var_tree,(Dt_t*)0);
7478462SApril.Chin@Sun.COM 					rp->sdict = dtopen(&_Nvdisc,Dtoset);
7488462SApril.Chin@Sun.COM 					dtview(rp->sdict,shp->var_base);
7498462SApril.Chin@Sun.COM 					dtview(shp->var_tree,rp->sdict);
7508462SApril.Chin@Sun.COM 				}
7518462SApril.Chin@Sun.COM 				if(np = nv_search(name,shp->var_tree,0))
7528462SApril.Chin@Sun.COM 				{
7538462SApril.Chin@Sun.COM 					if(shp->var_tree->walk == shp->var_base)
7548462SApril.Chin@Sun.COM 					{
7558462SApril.Chin@Sun.COM 						nq = np;
7568462SApril.Chin@Sun.COM 						if(flags&NV_NOSCOPE)
7578462SApril.Chin@Sun.COM 						{
7588462SApril.Chin@Sun.COM 							if(mode==0)
7598462SApril.Chin@Sun.COM 								root = shp->var_base;
7608462SApril.Chin@Sun.COM 							else
7618462SApril.Chin@Sun.COM 							{
7628462SApril.Chin@Sun.COM 								nv_delete(np,(Dt_t*)0,0);
7638462SApril.Chin@Sun.COM 								np = 0;
7648462SApril.Chin@Sun.COM 							}
7658462SApril.Chin@Sun.COM 						}
7668462SApril.Chin@Sun.COM 					}
7678462SApril.Chin@Sun.COM 					else
7688462SApril.Chin@Sun.COM 					{
7698462SApril.Chin@Sun.COM 						root = shp->var_tree->walk;
7708462SApril.Chin@Sun.COM 						flags |= NV_NOSCOPE;
7718462SApril.Chin@Sun.COM 						noscope = 1;
7728462SApril.Chin@Sun.COM 					}
7738462SApril.Chin@Sun.COM 				}
7748462SApril.Chin@Sun.COM 				if(rp && rp->sdict && (flags&NV_STATIC))
7758462SApril.Chin@Sun.COM 				{
7768462SApril.Chin@Sun.COM 					root = rp->sdict;
7778462SApril.Chin@Sun.COM 					if(np && shp->var_tree->walk==shp->var_tree)
7788462SApril.Chin@Sun.COM 					{
7798462SApril.Chin@Sun.COM 						_nv_unset(np,0);
7808462SApril.Chin@Sun.COM 						nv_delete(np,shp->var_tree,0);
7818462SApril.Chin@Sun.COM 						np = 0;
7828462SApril.Chin@Sun.COM 					}
7838462SApril.Chin@Sun.COM 					if(!np || shp->var_tree->walk!=root)
7848462SApril.Chin@Sun.COM 						np =  nv_search(name,root,HASH_NOSCOPE|NV_ADD);
7858462SApril.Chin@Sun.COM 				}
7868462SApril.Chin@Sun.COM 			}
7878462SApril.Chin@Sun.COM 			if(np ||  (np = nv_search(name,root,mode)))
7884887Schin 			{
7894887Schin 				isref = nv_isref(np);
7904887Schin 				if(top)
7914887Schin 				{
7924887Schin 					if(nq==np)
793*10898Sroland.mainz@nrubsig.org 					{
7944887Schin 						flags &= ~NV_NOSCOPE;
795*10898Sroland.mainz@nrubsig.org 						root = shp->var_base;
796*10898Sroland.mainz@nrubsig.org 					}
7974887Schin 					else if(nq)
7984887Schin 					{
7994887Schin 						if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq)))
8004887Schin 							np->nvname = nq->nvname;
8014887Schin 						flags |= NV_NOSCOPE;
8024887Schin 					}
8034887Schin 				}
8048462SApril.Chin@Sun.COM 				else if(add && nv_isnull(np) && c=='.' && cp[1]!='.')
8054887Schin 					nv_setvtree(np);
8064887Schin 			}
8074887Schin 			if(c)
8084887Schin 				*sp = c;
8094887Schin 			top = 0;
8104887Schin 			if(isref)
8114887Schin 			{
8124887Schin 				char *sub=0;
8138462SApril.Chin@Sun.COM #if NVCACHE
8148462SApril.Chin@Sun.COM 				nvcache.ok = 0;
8158462SApril.Chin@Sun.COM #endif
8164887Schin 				if(c=='.') /* don't optimize */
8178462SApril.Chin@Sun.COM 					shp->argaddr = 0;
818*10898Sroland.mainz@nrubsig.org 				else if((flags&NV_NOREF) && (c!='[' && *cp!='.'))
8194887Schin 				{
8208462SApril.Chin@Sun.COM 					if(c && !(flags&NV_NOADD))
8214887Schin 						nv_unref(np);
8224887Schin 					return(np);
8234887Schin 				}
8248462SApril.Chin@Sun.COM 				while(nv_isref(np) && np->nvalue.cp)
8254887Schin 				{
8264887Schin 					root = nv_reftree(np);
8278462SApril.Chin@Sun.COM 					shp->last_root = root;
8288462SApril.Chin@Sun.COM 					shp->last_table = nv_reftable(np);
8294887Schin 					sub = nv_refsub(np);
8304887Schin 					np = nv_refnode(np);
8314887Schin 					if(sub && c!='.')
8324887Schin 						nv_putsub(np,sub,0L);
8334887Schin 					flags |= NV_NOSCOPE;
8348462SApril.Chin@Sun.COM 					noscope = 1;
8354887Schin 				}
8368462SApril.Chin@Sun.COM 				if(nv_isref(np) && (c=='[' || c=='.' || !(flags&NV_ASSIGN)))
8378462SApril.Chin@Sun.COM 					errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np));
8384887Schin 				if(sub && c==0)
8394887Schin 					return(np);
8404887Schin 				if(np==nq)
8414887Schin 					flags &= ~(noscope?0:NV_NOSCOPE);
8424887Schin 				else if(c)
8434887Schin 				{
8444887Schin 					c = (cp-sp);
8454887Schin 					copy = strlen(cp=nv_name(np));
8468462SApril.Chin@Sun.COM 					dp->nofree |= 1;
8474887Schin 					name = copystack(cp,sp,sub);
8484887Schin 					sp = (char*)name + copy;
8494887Schin 					cp = sp+c;
8504887Schin 					c = *sp;
8514887Schin 					if(!noscope)
8524887Schin 						flags &= ~NV_NOSCOPE;
8534887Schin 				}
8544887Schin 				flags |= NV_NOREF;
855*10898Sroland.mainz@nrubsig.org 				if(nv_isnull(np))
856*10898Sroland.mainz@nrubsig.org 					nv_onattr(np,NV_NOFREE);
857*10898Sroland.mainz@nrubsig.org 
8584887Schin 			}
8598462SApril.Chin@Sun.COM 			shp->last_root = root;
8608462SApril.Chin@Sun.COM 			if(cp[1]=='.')
8618462SApril.Chin@Sun.COM 				cp++;
8628462SApril.Chin@Sun.COM 			if(c=='.' && (cp[1]==0 ||  cp[1]=='=' || cp[1]=='+'))
8638462SApril.Chin@Sun.COM 			{
8648462SApril.Chin@Sun.COM 				nv_local = 1;
8658462SApril.Chin@Sun.COM 				return(np);
8668462SApril.Chin@Sun.COM 			}
8678462SApril.Chin@Sun.COM 			if(cp[-1]=='.')
8688462SApril.Chin@Sun.COM 				cp--;
8694887Schin 			do
8704887Schin 			{
8714887Schin 				if(!np)
8724887Schin 				{
8738462SApril.Chin@Sun.COM 					if(!nq && *sp=='[' && *cp==0 && cp[-1]==']')
8744887Schin 					{
8754887Schin 						/*
8764887Schin 						 * for backward compatibility
8774887Schin 						 * evaluate subscript for
8784887Schin 						 * possible side effects
8794887Schin 						 */
8804887Schin 						cp[-1] = 0;
8814887Schin 						sh_arith(sp+1);
8824887Schin 						cp[-1] = ']';
8834887Schin 					}
8844887Schin 					return(np);
8854887Schin 				}
8864887Schin 				if(c=='[' || (c=='.' && nv_isarray(np)))
8874887Schin 				{
8888462SApril.Chin@Sun.COM 					char *sub=0;
8894887Schin 					int n = 0;
890*10898Sroland.mainz@nrubsig.org 					mode &= ~HASH_NOSCOPE;
8914887Schin 					if(c=='[')
8924887Schin 					{
893*10898Sroland.mainz@nrubsig.org #if 0
894*10898Sroland.mainz@nrubsig.org 						Namarr_t *ap = nv_arrayptr(np);
895*10898Sroland.mainz@nrubsig.org 						int scan = ap?(ap->nelem&ARRAY_SCAN):0;
896*10898Sroland.mainz@nrubsig.org #endif
8974887Schin 						n = mode|nv_isarray(np);
8984887Schin 						if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']')
8994887Schin 						{
9004887Schin 							/* not implemented yet */
9014887Schin 							dp->last = cp;
9024887Schin 							return(np);
9034887Schin 						}
9048462SApril.Chin@Sun.COM 						if((n&NV_ADD)&&(flags&NV_ARRAY))
9054887Schin 							n |= ARRAY_FILL;
9068462SApril.Chin@Sun.COM 						if(flags&NV_ASSIGN)
9078462SApril.Chin@Sun.COM 							n |= NV_ADD;
9088462SApril.Chin@Sun.COM 						cp = nv_endsubscript(np,sp,n|(flags&NV_ASSIGN));
909*10898Sroland.mainz@nrubsig.org #if 0
910*10898Sroland.mainz@nrubsig.org 						if(scan)
911*10898Sroland.mainz@nrubsig.org 							nv_putsub(np,NIL(char*),ARRAY_SCAN);
912*10898Sroland.mainz@nrubsig.org #endif
9134887Schin 					}
9144887Schin 					else
9154887Schin 						cp = sp;
9168462SApril.Chin@Sun.COM 					if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || (flags&NV_ARRAY))
9174887Schin 
9184887Schin 					{
9194887Schin 						int m = cp-sp;
9208462SApril.Chin@Sun.COM 						sub = m?nv_getsub(np):0;
9214887Schin 						if(!sub)
9228462SApril.Chin@Sun.COM 						{
9238462SApril.Chin@Sun.COM 							if(m && !(n&NV_ADD))
9248462SApril.Chin@Sun.COM 								return(0);
9254887Schin 							sub = "0";
9268462SApril.Chin@Sun.COM 						}
9274887Schin 						n = strlen(sub)+2;
9284887Schin 						if(!copy)
9294887Schin 						{
9304887Schin 							copy = cp-name;
9318462SApril.Chin@Sun.COM 							dp->nofree |= 1;
9324887Schin 							name = copystack((const char*)0, name,(const char*)0);
9334887Schin 							cp = (char*)name+copy;
9344887Schin 							sp = cp-m;
9354887Schin 						}
9364887Schin 						if(n <= m)
9374887Schin 						{
9384887Schin 							if(n)
9394887Schin 							{
9404887Schin 								memcpy(sp+1,sub,n-2);
9414887Schin 								sp[n-1] = ']';
9424887Schin 							}
9434887Schin 							if(n < m)
9444887Schin 								cp=strcpy(sp+n,cp);
9454887Schin 						}
9464887Schin 						else
9474887Schin 						{
9484887Schin 							int r = n-m;
9494887Schin 							m = sp-name;
9504887Schin 							name = stack_extend(name, cp-1, r);
9514887Schin 							sp = (char*)name + m;
9524887Schin 							*sp = '[';
9534887Schin 							memcpy(sp+1,sub,n-2);
9544887Schin 							sp[n-1] = ']';
9554887Schin 							cp = sp+n;
9564887Schin 
9574887Schin 						}
9584887Schin 					}
9594887Schin 					else if(c==0 && mode && (n=nv_aindex(np))>0)
9608462SApril.Chin@Sun.COM 						nv_putsub(np,(char*)0,n);
9618462SApril.Chin@Sun.COM 					else if(n==0 && (c==0 || (c=='[' && !nv_isarray(np))))
9624887Schin 					{
9634887Schin 						/* subscript must be 0*/
9644887Schin 						cp[-1] = 0;
9658462SApril.Chin@Sun.COM 						n = sh_arith(sp+1);
9664887Schin 						cp[-1] = ']';
9678462SApril.Chin@Sun.COM 						if(n)
9688462SApril.Chin@Sun.COM 							return(0);
9694887Schin 						if(c)
9708462SApril.Chin@Sun.COM 							sp = cp;
9714887Schin 					}
9724887Schin 					dp->last = cp;
9734887Schin 					if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY)))
9744887Schin 					{
9758462SApril.Chin@Sun.COM 						sp = cp;
9768462SApril.Chin@Sun.COM 						if(!(nq = nv_opensub(np)))
9778462SApril.Chin@Sun.COM 						{
9788462SApril.Chin@Sun.COM 							Namarr_t *ap = nv_arrayptr(np);
9798462SApril.Chin@Sun.COM 							if(!sub && (flags&NV_NOADD))
9808462SApril.Chin@Sun.COM 								return(0);
9818462SApril.Chin@Sun.COM 							n = mode|((flags&NV_NOADD)?0:NV_ADD);
9828462SApril.Chin@Sun.COM 							if(!ap && (n&NV_ADD))
9838462SApril.Chin@Sun.COM 							{
9848462SApril.Chin@Sun.COM 								nv_putsub(np,sub,ARRAY_FILL);
9858462SApril.Chin@Sun.COM 								ap = nv_arrayptr(np);
9868462SApril.Chin@Sun.COM 							}
9878462SApril.Chin@Sun.COM 							if(n && ap && !ap->table)
9888462SApril.Chin@Sun.COM 								ap->table = dtopen(&_Nvdisc,Dtoset);
9898462SApril.Chin@Sun.COM 							if(ap && ap->table && (nq=nv_search(sub,ap->table,n)))
9908462SApril.Chin@Sun.COM 								nq->nvenv = (char*)np;
9918462SApril.Chin@Sun.COM 							if(nq && nv_isnull(nq))
9928462SApril.Chin@Sun.COM 								nq = nv_arraychild(np,nq,c);
9938462SApril.Chin@Sun.COM 						}
9948462SApril.Chin@Sun.COM 						if(nq)
9958462SApril.Chin@Sun.COM 						{
9968462SApril.Chin@Sun.COM 							if(c=='.' && !nv_isvtree(nq))
9978462SApril.Chin@Sun.COM 							{
9988462SApril.Chin@Sun.COM 								if(flags&NV_NOADD)
9998462SApril.Chin@Sun.COM 									return(0);
10008462SApril.Chin@Sun.COM 								nv_setvtree(nq);
10018462SApril.Chin@Sun.COM 							}
10028462SApril.Chin@Sun.COM 							np = nq;
10038462SApril.Chin@Sun.COM 						}
10048462SApril.Chin@Sun.COM 						else if(memcmp(cp,"[0]",3))
10058462SApril.Chin@Sun.COM 							return(nq);
10068462SApril.Chin@Sun.COM 						else
10078462SApril.Chin@Sun.COM 						{
10088462SApril.Chin@Sun.COM 							/* ignore [0]  */
10098462SApril.Chin@Sun.COM 							dp->last = cp += 3;
10108462SApril.Chin@Sun.COM 							c = *cp;
10118462SApril.Chin@Sun.COM 						}
10124887Schin 					}
10134887Schin 				}
10144887Schin 				else if(nv_isarray(np))
10158462SApril.Chin@Sun.COM 				{
10168462SApril.Chin@Sun.COM 					if(c==0 && (flags&NV_MOVE))
10178462SApril.Chin@Sun.COM 						return(np);
10184887Schin 					nv_putsub(np,NIL(char*),ARRAY_UNDEF);
10198462SApril.Chin@Sun.COM 				}
10204887Schin 				if(c=='.' && (fp=np->nvfun))
10214887Schin 				{
10224887Schin 					for(; fp; fp=fp->next)
10234887Schin 					{
10244887Schin 						if(fp->disc && fp->disc->createf)
10254887Schin 							break;
10264887Schin 					}
10274887Schin 					if(fp)
10284887Schin 					{
10294887Schin 						if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np)
10304887Schin 						{
10314887Schin 							add = NV_ADD;
1032*10898Sroland.mainz@nrubsig.org 							shp->last_table = 0;
10334887Schin 							break;
10344887Schin 						}
10358462SApril.Chin@Sun.COM 						else if(np=nq)
10368462SApril.Chin@Sun.COM 						{
10378462SApril.Chin@Sun.COM 							if((c = *(sp=cp=dp->last=fp->last))==0)
10388462SApril.Chin@Sun.COM 							{
10398462SApril.Chin@Sun.COM 								if(nv_isarray(np) && sp[-1]!=']')
10408462SApril.Chin@Sun.COM 									nv_putsub(np,NIL(char*),ARRAY_UNDEF);
10418462SApril.Chin@Sun.COM 								return(np);
10428462SApril.Chin@Sun.COM 							}
10438462SApril.Chin@Sun.COM 						}
10444887Schin 					}
10454887Schin 				}
10464887Schin 			}
10474887Schin 			while(c=='[');
10488462SApril.Chin@Sun.COM 			if(c!='.' || cp[1]=='.')
10494887Schin 				return(np);
10504887Schin 			cp++;
10514887Schin 			break;
10524887Schin 		    default:
10534887Schin 			dp->last = cp;
10544887Schin 			if((c = mbchar(cp)) && !isaletter(c))
10554887Schin 				return(np);
10564887Schin 			while(xp=cp, c=mbchar(cp), isaname(c));
10574887Schin 			cp = xp;
10584887Schin 		}
10594887Schin 	}
10604887Schin 	return(np);
10614887Schin }
10624887Schin 
10634887Schin /*
10648462SApril.Chin@Sun.COM  * delete the node <np> from the dictionary <root> and clear from the cache
10658462SApril.Chin@Sun.COM  * if <root> is NULL, only the cache is cleared
10668462SApril.Chin@Sun.COM  * if flags does not contain NV_NOFREE, the node is freed
10678462SApril.Chin@Sun.COM  */
10688462SApril.Chin@Sun.COM void nv_delete(Namval_t* np, Dt_t *root, int flags)
10698462SApril.Chin@Sun.COM {
10708462SApril.Chin@Sun.COM #if NVCACHE
10718462SApril.Chin@Sun.COM 	register int		c;
10728462SApril.Chin@Sun.COM 	struct Cache_entry	*xp;
10738462SApril.Chin@Sun.COM 	for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
10748462SApril.Chin@Sun.COM 	{
10758462SApril.Chin@Sun.COM 		if(xp->np==np)
10768462SApril.Chin@Sun.COM 			xp->root = 0;
10778462SApril.Chin@Sun.COM 	}
10788462SApril.Chin@Sun.COM #endif
10798462SApril.Chin@Sun.COM 	if(root)
10808462SApril.Chin@Sun.COM 	{
10818462SApril.Chin@Sun.COM 		if(dtdelete(root,np))
10828462SApril.Chin@Sun.COM 		{
10838462SApril.Chin@Sun.COM 			if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np)))
10848462SApril.Chin@Sun.COM 				free((void*)np);
10858462SApril.Chin@Sun.COM 		}
10868462SApril.Chin@Sun.COM #if 0
10878462SApril.Chin@Sun.COM 		else
10888462SApril.Chin@Sun.COM 		{
10898462SApril.Chin@Sun.COM 			sfprintf(sfstderr,"%s not deleted\n",nv_name(np));
10908462SApril.Chin@Sun.COM 			sfsync(sfstderr);
10918462SApril.Chin@Sun.COM 		}
10928462SApril.Chin@Sun.COM #endif
10938462SApril.Chin@Sun.COM 	}
10948462SApril.Chin@Sun.COM }
10958462SApril.Chin@Sun.COM 
10968462SApril.Chin@Sun.COM /*
10974887Schin  * Put <arg> into associative memory.
10984887Schin  * If <flags> & NV_ARRAY then follow array to next subscript
10994887Schin  * If <flags> & NV_NOARRAY then subscript is not allowed
11004887Schin  * If <flags> & NV_NOSCOPE then use the current scope only
11014887Schin  * If <flags> & NV_ASSIGN then assignment is allowed
11024887Schin  * If <flags> & NV_IDENT then name must be an identifier
11034887Schin  * If <flags> & NV_VARNAME then name must be a valid variable name
11044887Schin  * If <flags> & NV_NOADD then node will not be added if not found
11054887Schin  * If <flags> & NV_NOREF then don't follow reference
11064887Schin  * If <flags> & NV_NOFAIL then don't generate an error message on failure
11078462SApril.Chin@Sun.COM  * If <flags> & NV_STATIC then unset before an assignment
1108*10898Sroland.mainz@nrubsig.org  * If <flags> & NV_UNJUST then unset attributes before assignment
11094887Schin  * SH_INIT is only set while initializing the environment
11104887Schin  */
11114887Schin Namval_t *nv_open(const char *name, Dt_t *root, int flags)
11124887Schin {
11138462SApril.Chin@Sun.COM 	Shell_t			*shp = &sh;
11144887Schin 	register char		*cp=(char*)name;
11154887Schin 	register int		c;
11164887Schin 	register Namval_t	*np;
11174887Schin 	Namfun_t		fun;
11184887Schin 	int			append=0;
11194887Schin 	const char		*msg = e_varname;
11204887Schin 	char			*fname = 0;
11214887Schin 	int			offset = staktell();
11224887Schin 	Dt_t			*funroot;
11238462SApril.Chin@Sun.COM #if NVCACHE
11248462SApril.Chin@Sun.COM 	struct Cache_entry	*xp;
11258462SApril.Chin@Sun.COM #endif
11268462SApril.Chin@Sun.COM 
11278462SApril.Chin@Sun.COM 	sh_stats(STAT_NVOPEN);
11284887Schin 	memset(&fun,0,sizeof(fun));
11298462SApril.Chin@Sun.COM 	shp->last_table = shp->namespace;
11304887Schin 	if(!root)
11318462SApril.Chin@Sun.COM 		root = shp->var_tree;
11328462SApril.Chin@Sun.COM 	shp->last_root = root;
11338462SApril.Chin@Sun.COM 	if(root==shp->fun_tree)
11344887Schin 	{
11354887Schin 		flags |= NV_NOREF;
11364887Schin 		msg = e_badfun;
11378462SApril.Chin@Sun.COM 		if((np=shp->namespace) || strchr(name,'.'))
11384887Schin 		{
11394887Schin 			name = cp = copystack(np?nv_name(np):0,name,(const char*)0);
11404887Schin 			fname = strrchr(cp,'.');
11414887Schin 			*fname = 0;
11428462SApril.Chin@Sun.COM 			fun.nofree |= 1;
11434887Schin 			flags &=  ~NV_IDENT;
11444887Schin 			funroot = root;
11458462SApril.Chin@Sun.COM 			root = shp->var_tree;
11464887Schin 		}
11474887Schin 	}
11484887Schin 	else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
11494887Schin 	{
11504887Schin 		long mode = ((flags&NV_NOADD)?0:NV_ADD);
11514887Schin 		if(flags&NV_NOSCOPE)
11524887Schin 			mode |= HASH_SCOPE|HASH_NOSCOPE;
11534887Schin 		np = nv_search(name,root,mode);
11544887Schin 		if(np && !(flags&NV_REF))
11554887Schin 		{
11564887Schin 			while(nv_isref(np))
11574887Schin 			{
11588462SApril.Chin@Sun.COM 				shp->last_table = nv_reftable(np);
11594887Schin 				np = nv_refnode(np);
11604887Schin 			}
11614887Schin 		}
11624887Schin 		return(np);
11634887Schin 	}
11648462SApril.Chin@Sun.COM 	else if(shp->prefix && (flags&NV_ASSIGN))
11654887Schin 	{
11668462SApril.Chin@Sun.COM 		name = cp = copystack(shp->prefix,name,(const char*)0);
11678462SApril.Chin@Sun.COM 		fun.nofree |= 1;
11684887Schin 	}
11694887Schin 	c = *(unsigned char*)cp;
11708462SApril.Chin@Sun.COM 	if(root==shp->alias_tree)
11714887Schin 	{
11724887Schin 		msg = e_aliname;
11734887Schin 		while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
11748462SApril.Chin@Sun.COM 			(c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON));
11758462SApril.Chin@Sun.COM 		if(shp->subshell && c=='=')
11764887Schin 			root = sh_subaliastree(1);
11774887Schin 		if(c= *--cp)
11784887Schin 			*cp = 0;
11794887Schin 		np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);
11804887Schin 		if(c)
11814887Schin 			*cp = c;
11824887Schin 		goto skip;
11834887Schin 	}
11844887Schin 	else if(flags&NV_IDENT)
11854887Schin 		msg = e_ident;
11864887Schin 	else if(c=='.')
11874887Schin 	{
11884887Schin 		c = *++cp;
11894887Schin 		flags |= NV_NOREF;
11908462SApril.Chin@Sun.COM 		if(root==shp->var_tree)
11918462SApril.Chin@Sun.COM 			root = shp->var_base;
11928462SApril.Chin@Sun.COM 		shp->last_table = 0;
11934887Schin 	}
11944887Schin 	if(c= !isaletter(c))
11954887Schin 		goto skip;
11968462SApril.Chin@Sun.COM #if NVCACHE
11978462SApril.Chin@Sun.COM 	for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
11988462SApril.Chin@Sun.COM 	{
11998462SApril.Chin@Sun.COM 		if(xp->root!=root)
12008462SApril.Chin@Sun.COM 			continue;
12018462SApril.Chin@Sun.COM 		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]=='+'))
12028462SApril.Chin@Sun.COM 		{
12038462SApril.Chin@Sun.COM 			sh_stats(STAT_NVHITS);
12048462SApril.Chin@Sun.COM 			np = xp->np;
12058462SApril.Chin@Sun.COM 			cp = (char*)name+xp->len;
12068462SApril.Chin@Sun.COM 			if(nv_isarray(np))
12078462SApril.Chin@Sun.COM 				 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
12088462SApril.Chin@Sun.COM 			shp->last_table = xp->last_table;
1209*10898Sroland.mainz@nrubsig.org 			shp->last_root = xp->last_root;
12108462SApril.Chin@Sun.COM 			goto nocache;
12118462SApril.Chin@Sun.COM 		}
12128462SApril.Chin@Sun.COM 	}
12138462SApril.Chin@Sun.COM 	nvcache.ok = 1;
12148462SApril.Chin@Sun.COM #endif
12154887Schin 	np = nv_create(name, root, flags, &fun);
12164887Schin 	cp = fun.last;
12178462SApril.Chin@Sun.COM #if NVCACHE
12188462SApril.Chin@Sun.COM 	if(np && nvcache.ok && cp[-1]!=']')
12198462SApril.Chin@Sun.COM 	{
12208462SApril.Chin@Sun.COM 		xp = &nvcache.entries[nvcache.index];
12218462SApril.Chin@Sun.COM 		if(*cp)
12228462SApril.Chin@Sun.COM 		{
12238462SApril.Chin@Sun.COM 			char *sp = strchr(name,*cp);
12248462SApril.Chin@Sun.COM 			if(!sp)
12258462SApril.Chin@Sun.COM 				goto nocache;
12268462SApril.Chin@Sun.COM 			xp->len = sp-name;
12278462SApril.Chin@Sun.COM 		}
12288462SApril.Chin@Sun.COM 		else
12298462SApril.Chin@Sun.COM 			xp->len = strlen(name);
12308462SApril.Chin@Sun.COM 		c = roundof(xp->len+1,32);
12318462SApril.Chin@Sun.COM 		if(c > xp->size)
12328462SApril.Chin@Sun.COM 		{
12338462SApril.Chin@Sun.COM 			if(xp->size==0)
12348462SApril.Chin@Sun.COM 				xp->name = malloc(c);
12358462SApril.Chin@Sun.COM 			else
12368462SApril.Chin@Sun.COM 				xp->name = realloc(xp->name,c);
12378462SApril.Chin@Sun.COM 			xp->size = c;
12388462SApril.Chin@Sun.COM 		}
12398462SApril.Chin@Sun.COM 		memcpy(xp->name,name,xp->len);
12408462SApril.Chin@Sun.COM 		xp->name[xp->len] = 0;
12418462SApril.Chin@Sun.COM 		xp->root = root;
12428462SApril.Chin@Sun.COM 		xp->np = np;
12438462SApril.Chin@Sun.COM 		xp->last_table = shp->last_table;
1244*10898Sroland.mainz@nrubsig.org 		xp->last_root = shp->last_root;
12458462SApril.Chin@Sun.COM 		xp->flags = (flags&(NV_ARRAY|NV_NOSCOPE));
12468462SApril.Chin@Sun.COM 		nvcache.index = (nvcache.index+1)&(NVCACHE-1);
12478462SApril.Chin@Sun.COM 	}
12488462SApril.Chin@Sun.COM nocache:
12498462SApril.Chin@Sun.COM 	nvcache.ok = 0;
12508462SApril.Chin@Sun.COM #endif
12514887Schin 	if(fname)
12524887Schin 	{
12534887Schin 		c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD);
12544887Schin 		*fname = '.';
12554887Schin 		np = nv_search(name, funroot, c);
12564887Schin 		*fname = 0;
12574887Schin 	}
12588462SApril.Chin@Sun.COM 	else
12594887Schin 	{
12608462SApril.Chin@Sun.COM 		if(*cp=='.' && cp[1]=='.')
12618462SApril.Chin@Sun.COM 		{
12628462SApril.Chin@Sun.COM 			append |= NV_NODISC;
12638462SApril.Chin@Sun.COM 			cp+=2;
12648462SApril.Chin@Sun.COM 		}
12658462SApril.Chin@Sun.COM 		if(*cp=='+' && cp[1]=='=')
12668462SApril.Chin@Sun.COM 		{
12678462SApril.Chin@Sun.COM 			append |= NV_APPEND;
12688462SApril.Chin@Sun.COM 			cp++;
12698462SApril.Chin@Sun.COM 		}
12704887Schin 	}
12714887Schin 	c = *cp;
12724887Schin skip:
12738462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
12748462SApril.Chin@Sun.COM 	if(np && shp->mktype)
12758462SApril.Chin@Sun.COM 		np = nv_addnode(np,0);
12768462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
12774887Schin 	if(c=='=' && np && (flags&NV_ASSIGN))
12784887Schin 	{
12794887Schin 		cp++;
12804887Schin 		if(sh_isstate(SH_INIT))
12814887Schin 		{
12824887Schin 			nv_putval(np, cp, NV_RDONLY);
12834887Schin 			if(np==PWDNOD)
12844887Schin 				nv_onattr(np,NV_TAGGED);
12854887Schin 		}
12864887Schin 		else
12874887Schin 		{
12888462SApril.Chin@Sun.COM 			char *sub=0, *prefix= shp->prefix;
12898462SApril.Chin@Sun.COM 			int isref;
12908462SApril.Chin@Sun.COM 			shp->prefix = 0;
12918462SApril.Chin@Sun.COM 			if((flags&NV_STATIC) && !shp->mktype)
12928462SApril.Chin@Sun.COM 			{
12938462SApril.Chin@Sun.COM 				if(!nv_isnull(np))
1294*10898Sroland.mainz@nrubsig.org 				{
1295*10898Sroland.mainz@nrubsig.org 					shp->prefix = prefix;
12968462SApril.Chin@Sun.COM 					return(np);
1297*10898Sroland.mainz@nrubsig.org 				}
12988462SApril.Chin@Sun.COM 			}
12998462SApril.Chin@Sun.COM 			isref = nv_isref(np);
13004887Schin 			if(sh_isoption(SH_XTRACE) && nv_isarray(np))
13014887Schin 				sub = nv_getsub(np);
13024887Schin 			c = msg==e_aliname? 0: (append | (flags&NV_EXPORT));
13038462SApril.Chin@Sun.COM 			if(isref)
13048462SApril.Chin@Sun.COM 				nv_offattr(np,NV_REF);
1305*10898Sroland.mainz@nrubsig.org 			if(!append && (flags&NV_UNJUST))
1306*10898Sroland.mainz@nrubsig.org 			{
1307*10898Sroland.mainz@nrubsig.org 				nv_offattr(np,NV_LJUST|NV_RJUST|NV_ZFILL);
1308*10898Sroland.mainz@nrubsig.org 				np->nvsize = 0;
1309*10898Sroland.mainz@nrubsig.org 			}
13104887Schin 			nv_putval(np, cp, c);
13118462SApril.Chin@Sun.COM 			if(isref)
1312*10898Sroland.mainz@nrubsig.org 			{
1313*10898Sroland.mainz@nrubsig.org 				if(nv_search((char*)np,shp->var_base,HASH_BUCKET))
1314*10898Sroland.mainz@nrubsig.org 					shp->last_root = shp->var_base;
13158462SApril.Chin@Sun.COM 				nv_setref(np,(Dt_t*)0,NV_VARNAME);
1316*10898Sroland.mainz@nrubsig.org 			}
13174887Schin 			savesub = sub;
13188462SApril.Chin@Sun.COM 			shp->prefix = prefix;
13194887Schin 		}
13204887Schin 		nv_onattr(np, flags&NV_ATTRIBUTES);
13214887Schin 	}
13224887Schin 	else if(c)
13234887Schin 	{
13244887Schin 		if(flags&NV_NOFAIL)
13254887Schin 			return(0);
13264887Schin 		if(c=='.')
13274887Schin 			msg = e_noparent;
13284887Schin 		else if(c=='[')
13294887Schin 			msg = e_noarray;
13304887Schin 		errormsg(SH_DICT,ERROR_exit(1),msg,name);
13314887Schin 	}
13328462SApril.Chin@Sun.COM 	if(fun.nofree&1)
13334887Schin 		stakseek(offset);
13344887Schin 	return(np);
13354887Schin }
13364887Schin 
13374887Schin #if SHOPT_MULTIBYTE
13384887Schin     static int ja_size(char*, int, int);
13394887Schin     static void ja_restore(void);
13404887Schin     static char *savep;
13414887Schin     static char savechars[8+1];
13424887Schin #endif /* SHOPT_MULTIBYTE */
13434887Schin 
13444887Schin /*
13454887Schin  * put value <string> into name-value node <np>.
13464887Schin  * If <np> is an array, then the element given by the
13474887Schin  *   current index is assigned to.
13484887Schin  * If <flags> contains NV_RDONLY, readonly attribute is ignored
13494887Schin  * If <flags> contains NV_INTEGER, string is a pointer to a number
13504887Schin  * If <flags> contains NV_NOFREE, previous value is freed, and <string>
13514887Schin  * becomes value of node and <flags> becomes attributes
13524887Schin  */
13534887Schin void nv_putval(register Namval_t *np, const char *string, int flags)
13544887Schin {
13554887Schin 	register const char *sp=string;
13564887Schin 	register union Value *up;
13574887Schin 	register char *cp;
13584887Schin 	register int size = 0;
13594887Schin 	register int dot;
13608462SApril.Chin@Sun.COM #ifdef _ENV_H
13614887Schin 	int	was_local = nv_local;
13628462SApril.Chin@Sun.COM #endif
13638462SApril.Chin@Sun.COM 	union Value u;
13644887Schin 	if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
13654887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
13664887Schin 	/* The following could cause the shell to fork if assignment
13674887Schin 	 * would cause a side effect
13684887Schin 	 */
13694887Schin 	sh.argaddr = 0;
13704887Schin 	if(sh.subshell && !nv_local)
13714887Schin 		np = sh_assignok(np,1);
1372*10898Sroland.mainz@nrubsig.org 	if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np))
13734887Schin 	{
13744887Schin 		/* This function contains disc */
13754887Schin 		if(!nv_local)
13764887Schin 		{
13774887Schin 			nv_local=1;
13784887Schin 			nv_putv(np,sp,flags,np->nvfun);
13798462SApril.Chin@Sun.COM #ifdef _ENV_H
13804887Schin 			if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
13814887Schin 				sh_envput(sh.env,np);
13828462SApril.Chin@Sun.COM #endif
13834887Schin 			return;
13844887Schin 		}
13854887Schin 		/* called from disc, assign the actual value */
13864887Schin 	}
13874887Schin 	flags &= ~NV_NODISC;
13888462SApril.Chin@Sun.COM 	nv_local=0;
13894887Schin 	if(flags&(NV_NOREF|NV_NOFREE))
13904887Schin 	{
13918462SApril.Chin@Sun.COM 		if(np->nvalue.cp && np->nvalue.cp!=sp && !nv_isattr(np,NV_NOFREE))
13928462SApril.Chin@Sun.COM 			free((void*)np->nvalue.cp);
13934887Schin 		np->nvalue.cp = (char*)sp;
13944887Schin 		nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE);
13954887Schin 		return;
13964887Schin 	}
13974887Schin 	up= &np->nvalue;
13988462SApril.Chin@Sun.COM 	if(nv_isattr(np,NV_INT16P) == NV_INT16)
13998462SApril.Chin@Sun.COM 	{
14008462SApril.Chin@Sun.COM 		if(!np->nvalue.up || !nv_isarray(np))
14018462SApril.Chin@Sun.COM 		{
14028462SApril.Chin@Sun.COM 			up = &u;
14038462SApril.Chin@Sun.COM 			up->up = &np->nvalue;
14048462SApril.Chin@Sun.COM 		}
14058462SApril.Chin@Sun.COM 	}
14068462SApril.Chin@Sun.COM 	else if(np->nvalue.up && nv_isarray(np) && nv_arrayptr(np))
14078462SApril.Chin@Sun.COM 		up = np->nvalue.up;
14088462SApril.Chin@Sun.COM 	if(up && up->cp==Empty)
14098462SApril.Chin@Sun.COM 		up->cp = 0;
14104887Schin 	if(nv_isattr(np,NV_EXPORT))
14114887Schin 		nv_offattr(np,NV_IMPORT);
14124887Schin 	if(nv_isattr (np, NV_INTEGER))
14134887Schin 	{
14148462SApril.Chin@Sun.COM 		if(nv_isattr(np, NV_DOUBLE) == NV_DOUBLE)
14154887Schin 		{
14164887Schin 			if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t))
14174887Schin 			{
14184887Schin 				Sfdouble_t ld, old=0;
14194887Schin 				if(flags&NV_INTEGER)
14204887Schin 				{
14214887Schin 					if(flags&NV_LONG)
14224887Schin 						ld = *((Sfdouble_t*)sp);
14234887Schin 					else if(flags&NV_SHORT)
14244887Schin 						ld = *((float*)sp);
14254887Schin 					else
14264887Schin 						ld = *((double*)sp);
14274887Schin 				}
14284887Schin 				else
14294887Schin 					ld = sh_arith(sp);
14304887Schin 				if(!up->ldp)
14314887Schin 					up->ldp = new_of(Sfdouble_t,0);
14324887Schin 				else if(flags&NV_APPEND)
14334887Schin 					old = *(up->ldp);
1434*10898Sroland.mainz@nrubsig.org 				*(up->ldp) = old?ld+old:ld;
14354887Schin 			}
14364887Schin 			else
14374887Schin 			{
14384887Schin 				double d,od=0;
14394887Schin 				if(flags&NV_INTEGER)
14404887Schin 				{
14414887Schin 					if(flags&NV_LONG)
14424887Schin 						d = (double)(*(Sfdouble_t*)sp);
14434887Schin 					else if(flags&NV_SHORT)
14444887Schin 						d = (double)(*(float*)sp);
14454887Schin 					else
14464887Schin 						d = *(double*)sp;
14474887Schin 				}
14484887Schin 				else
14494887Schin 					d = sh_arith(sp);
14504887Schin 				if(!up->dp)
14514887Schin 					up->dp = new_of(double,0);
14524887Schin 				else if(flags&NV_APPEND)
14534887Schin 					od = *(up->dp);
1454*10898Sroland.mainz@nrubsig.org 				*(up->dp) = od?d+od:d;
14554887Schin 			}
14564887Schin 		}
14574887Schin 		else
14584887Schin 		{
14594887Schin 			if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t))
14604887Schin 			{
14614887Schin 				Sflong_t ll=0,oll=0;
14624887Schin 				if(flags&NV_INTEGER)
14634887Schin 				{
14648462SApril.Chin@Sun.COM 					if((flags&NV_DOUBLE) == NV_DOUBLE)
14654887Schin 					{
14664887Schin 						if(flags&NV_LONG)
14674887Schin 							ll = *((Sfdouble_t*)sp);
14684887Schin 						else if(flags&NV_SHORT)
14694887Schin 							ll = *((float*)sp);
14704887Schin 						else
14714887Schin 							ll = *((double*)sp);
14724887Schin 					}
14734887Schin 					else if(nv_isattr(np,NV_UNSIGN))
14744887Schin 					{
14754887Schin 						if(flags&NV_LONG)
14764887Schin 							ll = *((Sfulong_t*)sp);
14774887Schin 						else if(flags&NV_SHORT)
14784887Schin 							ll = *((uint16_t*)sp);
14794887Schin 						else
14804887Schin 							ll = *((uint32_t*)sp);
14814887Schin 					}
14824887Schin 					else
14834887Schin 					{
14844887Schin 						if(flags&NV_LONG)
14854887Schin 							ll = *((Sflong_t*)sp);
14864887Schin 						else if(flags&NV_SHORT)
14874887Schin 							ll = *((uint16_t*)sp);
14884887Schin 						else
14894887Schin 							ll = *((uint32_t*)sp);
14904887Schin 					}
14914887Schin 				}
14924887Schin 				else if(sp)
14934887Schin 					ll = (Sflong_t)sh_arith(sp);
14944887Schin 				if(!up->llp)
14954887Schin 					up->llp = new_of(Sflong_t,0);
14964887Schin 				else if(flags&NV_APPEND)
14974887Schin 					oll = *(up->llp);
14984887Schin 				*(up->llp) = ll+oll;
14994887Schin 			}
15004887Schin 			else
15014887Schin 			{
15024887Schin 				int32_t l=0,ol=0;
15034887Schin 				if(flags&NV_INTEGER)
15044887Schin 				{
15058462SApril.Chin@Sun.COM 					if((flags&NV_DOUBLE) == NV_DOUBLE)
15064887Schin 					{
15074887Schin 						Sflong_t ll;
15084887Schin 						if(flags&NV_LONG)
15094887Schin 							ll = *((Sfdouble_t*)sp);
15104887Schin 						else if(flags&NV_SHORT)
15114887Schin 							ll = *((float*)sp);
15124887Schin 						else
15134887Schin 							ll = *((double*)sp);
15144887Schin 						l = (int32_t)ll;
15154887Schin 					}
15164887Schin 					else if(nv_isattr(np,NV_UNSIGN))
15174887Schin 					{
15184887Schin 						if(flags&NV_LONG)
15194887Schin 							l = *((Sfulong_t*)sp);
15204887Schin 						else if(flags&NV_SHORT)
15214887Schin 							l = *((uint16_t*)sp);
15224887Schin 						else
15234887Schin 							l = *(uint32_t*)sp;
15244887Schin 					}
15254887Schin 					else
15264887Schin 					{
15274887Schin 						if(flags&NV_LONG)
15284887Schin 							l = *((Sflong_t*)sp);
15294887Schin 						else if(flags&NV_SHORT)
15304887Schin 							l = *((int16_t*)sp);
15314887Schin 						else
15324887Schin 							l = *(int32_t*)sp;
15334887Schin 					}
15344887Schin 				}
15354887Schin 				else if(sp)
15364887Schin 				{
15374887Schin 					Sfdouble_t ld = sh_arith(sp);
15384887Schin 					if(ld<0)
15394887Schin 						l = (int32_t)ld;
15404887Schin 					else
15414887Schin 						l = (uint32_t)ld;
15424887Schin 				}
15434887Schin 				if(nv_size(np) <= 1)
15444887Schin 					nv_setsize(np,10);
15454887Schin 				if(nv_isattr (np, NV_SHORT))
15464887Schin 				{
15474887Schin 					int16_t s=0;
15484887Schin 					if(flags&NV_APPEND)
15498462SApril.Chin@Sun.COM 						s = *up->sp;
15508462SApril.Chin@Sun.COM 					*(up->sp) = s+(int16_t)l;
15514887Schin 					nv_onattr(np,NV_NOFREE);
15524887Schin 				}
15534887Schin 				else
15544887Schin 				{
15554887Schin 					if(!up->lp)
15564887Schin 						up->lp = new_of(int32_t,0);
15574887Schin 					else if(flags&NV_APPEND)
15584887Schin 						ol =  *(up->lp);
15594887Schin 					*(up->lp) = l+ol;
15604887Schin 				}
15614887Schin 			}
15624887Schin 		}
15634887Schin 	}
15644887Schin 	else
15654887Schin 	{
15664887Schin 		const char *tofree=0;
15674887Schin 		int offset;
15684887Schin #if _lib_pathnative
15694887Schin 		char buff[PATH_MAX];
15704887Schin #endif /* _lib_pathnative */
15714887Schin 		if(flags&NV_INTEGER)
15724887Schin 		{
15738462SApril.Chin@Sun.COM 			if((flags&NV_DOUBLE)==NV_DOUBLE)
15744887Schin 			{
15754887Schin 				if(flags&NV_LONG)
15764887Schin 					sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp));
15774887Schin 				else
15784887Schin 					sfprintf(sh.strbuf,"%.*g",DBL_DIG,*((double*)sp));
15794887Schin 			}
15808462SApril.Chin@Sun.COM 			else if(flags&NV_UNSIGN)
15818462SApril.Chin@Sun.COM 			{
15828462SApril.Chin@Sun.COM 				if(flags&NV_LONG)
15838462SApril.Chin@Sun.COM 					sfprintf(sh.strbuf,"%I*lu",sizeof(Sfulong_t),*((Sfulong_t*)sp));
15848462SApril.Chin@Sun.COM 				else
15858462SApril.Chin@Sun.COM 					sfprintf(sh.strbuf,"%lu",(unsigned long)((flags&NV_SHORT)?*((uint16_t*)sp):*((uint32_t*)sp)));
15868462SApril.Chin@Sun.COM 			}
15874887Schin 			else
15888462SApril.Chin@Sun.COM 			{
15898462SApril.Chin@Sun.COM 				if(flags&NV_LONG)
15908462SApril.Chin@Sun.COM 					sfprintf(sh.strbuf,"%I*ld",sizeof(Sflong_t),*((Sflong_t*)sp));
15918462SApril.Chin@Sun.COM 				else
15928462SApril.Chin@Sun.COM 					sfprintf(sh.strbuf,"%ld",(long)((flags&NV_SHORT)?*((int16_t*)sp):*((int32_t*)sp)));
15938462SApril.Chin@Sun.COM 			}
15944887Schin 			sp = sfstruse(sh.strbuf);
15954887Schin 		}
15968462SApril.Chin@Sun.COM 		if(nv_isattr(np, NV_HOST|NV_INTEGER)==NV_HOST && sp)
15974887Schin 		{
15984887Schin #ifdef _lib_pathnative
15994887Schin 			/*
16004887Schin 			 * return the host file name given the UNIX name
16014887Schin 			 */
16024887Schin 			pathnative(sp,buff,sizeof(buff));
16034887Schin 			if(buff[1]==':' && buff[2]=='/')
16044887Schin 			{
16054887Schin 				buff[2] = '\\';
16064887Schin 				if(*buff>='A' &&  *buff<='Z')
16074887Schin 					*buff += 'a'-'A';
16084887Schin 			}
16094887Schin 			sp = buff;
16104887Schin #else
16114887Schin 			;
16124887Schin #endif /* _lib_pathnative */
16134887Schin 		}
16144887Schin 		else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
16154887Schin 		{
16164887Schin 			for(;*sp == ' '|| *sp=='\t';sp++);
16174887Schin 	        	if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST)))
16184887Schin 				for(;*sp=='0';sp++);
16194887Schin 			size = nv_size(np);
16204887Schin #if SHOPT_MULTIBYTE
16214887Schin 			if(size)
16224887Schin 				size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL));
16234887Schin #endif /* SHOPT_MULTIBYTE */
16244887Schin 		}
16254887Schin 		if(!up->cp)
16264887Schin 			flags &= ~NV_APPEND;
16274887Schin 		if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY))
16284887Schin 		{
16294887Schin 			offset = staktell();
16304887Schin 			stakputs(up->cp);
16314887Schin 			stakputs(sp);
16324887Schin 			stakputc(0);
16334887Schin 			sp = stakptr(offset);
16344887Schin 		}
16354887Schin 		if(!nv_isattr(np, NV_NOFREE))
16364887Schin 		{
16374887Schin 			/* delay free in case <sp> points into free region */
16384887Schin 			tofree = up->cp;
16394887Schin 		}
16408462SApril.Chin@Sun.COM 		if(nv_isattr(np,NV_BINARY) && !(flags&NV_RAW))
16418462SApril.Chin@Sun.COM 			tofree = 0;
16428462SApril.Chin@Sun.COM 		if(nv_isattr(np,NV_LJUST|NV_RJUST))
16438462SApril.Chin@Sun.COM 			tofree = 0;
16444887Schin        	 	if (sp)
16454887Schin 		{
16464887Schin 			dot = strlen(sp);
16474887Schin #if (_AST_VERSION>=20030127L)
16484887Schin 			if(nv_isattr(np,NV_BINARY))
16494887Schin 			{
16504887Schin 				int oldsize = (flags&NV_APPEND)?nv_size(np):0;
16514887Schin 				if(flags&NV_RAW)
16524887Schin 				{
16534887Schin 					if(tofree)
16548462SApril.Chin@Sun.COM 					{
16554887Schin 						free((void*)tofree);
16568462SApril.Chin@Sun.COM 						nv_offattr(np,NV_NOFREE);
16578462SApril.Chin@Sun.COM 					}
16584887Schin 					up->cp = sp;
16594887Schin 					return;
16604887Schin 				}
16614887Schin 				size = 0;
16624887Schin 				if(nv_isattr(np,NV_ZFILL))
16634887Schin 					size = nv_size(np);
16644887Schin 				if(size==0)
16654887Schin 					size = oldsize + (3*dot/4);
16664887Schin 				cp = (char*)malloc(size+1);
16678462SApril.Chin@Sun.COM 				nv_offattr(np,NV_NOFREE);
16684887Schin 				if(oldsize)
16694887Schin 					memcpy((void*)cp,(void*)up->cp,oldsize);
16704887Schin 				up->cp = cp;
16714887Schin 				if(size <= oldsize)
16724887Schin 					return;
16734887Schin 				dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0);
16744887Schin 				dot += oldsize;
16754887Schin 				if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0)
16764887Schin 					nv_setsize(np,dot);
16774887Schin 				else if(nv_isattr(np,NV_ZFILL) && (size>dot))
16784887Schin 					memset((void*)&cp[dot],0,size-dot);
16794887Schin 				return;
16804887Schin 			}
16814887Schin 			else
16824887Schin #endif
16834887Schin 			if(size==0 && nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
16844887Schin 				nv_setsize(np,size=dot);
16854887Schin 			else if(size > dot)
16864887Schin 				dot = size;
16878462SApril.Chin@Sun.COM 			else if(nv_isattr(np,NV_LJUST) && dot>size)
16888462SApril.Chin@Sun.COM 				dot = size;
16898462SApril.Chin@Sun.COM 			if(size==0 || tofree || !(cp=(char*)up->cp))
16908462SApril.Chin@Sun.COM 			{
16918462SApril.Chin@Sun.COM 				cp = (char*)malloc(((unsigned)dot+1));
16928462SApril.Chin@Sun.COM 				cp[dot] = 0;
16938462SApril.Chin@Sun.COM 				nv_offattr(np,NV_NOFREE);
16948462SApril.Chin@Sun.COM 			}
16958462SApril.Chin@Sun.COM 
16964887Schin 		}
16974887Schin 		else
16984887Schin 			cp = 0;
16994887Schin 		up->cp = cp;
17004887Schin 		if(sp)
17014887Schin 		{
17028462SApril.Chin@Sun.COM 			int c = cp[dot];
17038462SApril.Chin@Sun.COM 			memcpy(cp,sp,dot);
17048462SApril.Chin@Sun.COM 			cp[dot]=0;
17054887Schin 			if(nv_isattr(np, NV_LTOU))
17068462SApril.Chin@Sun.COM 				ltou(cp);
17074887Schin 			else if(nv_isattr (np, NV_UTOL))
17088462SApril.Chin@Sun.COM 				utol(cp);
17098462SApril.Chin@Sun.COM 			cp[dot] = c;
17104887Schin 			if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL))
17114887Schin 				rightjust(cp,size,'0');
17124887Schin 			else if(nv_isattr(np, NV_RJUST))
17134887Schin 				rightjust(cp,size,' ');
17144887Schin 			else if(nv_isattr(np, NV_LJUST))
17154887Schin 			{
17164887Schin 				register char *dp;
17174887Schin 				dp = strlen (cp) + cp;
17188462SApril.Chin@Sun.COM 				cp = cp+size;
17194887Schin 				for (; dp < cp; *dp++ = ' ');
17204887Schin 			 }
17214887Schin #if SHOPT_MULTIBYTE
17224887Schin 			/* restore original string */
17234887Schin 			if(savep)
17244887Schin 				ja_restore();
17254887Schin #endif /* SHOPT_MULTIBYTE */
17264887Schin 		}
17274887Schin 		if(flags&NV_APPEND)
17284887Schin 			stakseek(offset);
17298462SApril.Chin@Sun.COM 		if(tofree && tofree!=Empty)
17304887Schin 			free((void*)tofree);
17314887Schin 	}
17328462SApril.Chin@Sun.COM #ifdef _ENV_H
17334887Schin 	if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
17344887Schin 		sh_envput(sh.env,np);
17358462SApril.Chin@Sun.COM #endif
17364887Schin 	return;
17374887Schin }
17384887Schin 
17394887Schin /*
17404887Schin  *
17414887Schin  *   Right-justify <str> so that it contains no more than
17424887Schin  *   <size> characters.  If <str> contains fewer than <size>
17434887Schin  *   characters, left-pad with <fill>.  Trailing blanks
17444887Schin  *   in <str> will be ignored.
17454887Schin  *
17464887Schin  *   If the leftmost digit in <str> is not a digit, <fill>
17474887Schin  *   will default to a blank.
17484887Schin  */
17494887Schin static void rightjust(char *str, int size, int fill)
17504887Schin {
17514887Schin 	register int n;
17524887Schin 	register char *cp,*sp;
17534887Schin 	n = strlen(str);
17544887Schin 
17554887Schin 	/* ignore trailing blanks */
17564887Schin 	for(cp=str+n;n && *--cp == ' ';n--);
17574887Schin 	if (n == size)
17584887Schin 		return;
17594887Schin 	if(n > size)
17604887Schin         {
17614887Schin         	*(str+n) = 0;
17624887Schin         	for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
17634887Schin         	return;
17644887Schin         }
17654887Schin 	else *(sp = str+size) = 0;
17664887Schin 	if (n == 0)
17674887Schin         {
17684887Schin         	while (sp > str)
17694887Schin                		*--sp = ' ';
17704887Schin         	return;
17714887Schin         }
17724887Schin 	while(n--)
17734887Schin 	{
17744887Schin 		sp--;
17754887Schin 		*sp = *cp--;
17764887Schin 	}
17774887Schin 	if(!isdigit(*str))
17784887Schin 		fill = ' ';
17794887Schin 	while(sp>str)
17804887Schin 		*--sp = fill;
17814887Schin 	return;
17824887Schin }
17834887Schin 
17844887Schin #if SHOPT_MULTIBYTE
17854887Schin     /*
17864887Schin      * handle left and right justified fields for multi-byte chars
17874887Schin      * given physical size, return a logical size which reflects the
17884887Schin      * screen width of multi-byte characters
17894887Schin      * Multi-width characters replaced by spaces if they cross the boundary
17904887Schin      * <type> is non-zero for right justified  fields
17914887Schin      */
17924887Schin 
17934887Schin     static int ja_size(char *str,int size,int type)
17944887Schin     {
17954887Schin 	register char *cp = str;
17964887Schin 	register int c, n=size;
17974887Schin 	register int outsize;
17984887Schin 	register char *oldcp=cp;
17994887Schin 	int oldn;
18004887Schin 	wchar_t w;
18014887Schin 	while(*cp)
18024887Schin 	{
18034887Schin 		oldn = n;
18044887Schin 		w = mbchar(cp);
18054887Schin 		outsize = mbwidth(w);
18064887Schin 		size -= outsize;
18074887Schin 		c = cp-oldcp;
18084887Schin 		n += (c-outsize);
18094887Schin 		oldcp = cp;
18104887Schin 		if(size<=0 && type==0)
18114887Schin 			break;
18124887Schin 	}
18134887Schin 	/* check for right justified fields that need truncating */
18144887Schin 	if(size <0)
18154887Schin 	{
18164887Schin 		if(type==0)
18174887Schin 		{
18184887Schin 			/* left justified and character crosses field boundary */
18194887Schin 			n = oldn;
18204887Schin 			/* save boundary char and replace with spaces */
18214887Schin 			size = c;
18224887Schin 			savechars[size] = 0;
18234887Schin 			while(size--)
18244887Schin 			{
18254887Schin 				savechars[size] = cp[size];
18264887Schin 				cp[size] = ' ';
18274887Schin 			}
18284887Schin 			savep = cp;
18294887Schin 		}
18304887Schin 		size = -size;
18314887Schin 		if(type)
18324887Schin 			n -= (ja_size(str,size,0)-size);
18334887Schin 	}
18344887Schin 	return(n);
18354887Schin     }
18364887Schin 
18374887Schin     static void ja_restore(void)
18384887Schin     {
18394887Schin 	register char *cp = savechars;
18404887Schin 	while(*cp)
18414887Schin 		*savep++ = *cp++;
18424887Schin 	savep = 0;
18434887Schin     }
18444887Schin #endif /* SHOPT_MULTIBYTE */
18454887Schin 
18464887Schin #ifndef _ENV_H
18474887Schin static char *staknam(register Namval_t *np, char *value)
18484887Schin {
18494887Schin 	register char *p,*q;
18504887Schin 	q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2);
18514887Schin 	p=strcopy(q,nv_name(np));
18524887Schin 	if(value)
18534887Schin 	{
18544887Schin 		*p++ = '=';
18554887Schin 		strcpy(p,value);
18564887Schin 	}
18574887Schin 	return(q);
18584887Schin }
18594887Schin #endif
18604887Schin 
18614887Schin /*
18624887Schin  * put the name and attribute into value of attributes variable
18634887Schin  */
18644887Schin #ifdef _ENV_H
18654887Schin static void attstore(register Namval_t *np, void *data)
18664887Schin {
18674887Schin 	register int flag, c = ' ';
18684887Schin 	NOT_USED(data);
18694887Schin 	if(!(nv_isattr(np,NV_EXPORT)))
18704887Schin 		return;
18714887Schin 	flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
18724887Schin 	stakputc('=');
18738462SApril.Chin@Sun.COM 	if((flag&NV_DOUBLE) == NV_DOUBLE)
18744887Schin 	{
18754887Schin 		/* export doubles as integers for ksh88 compatibility */
18768462SApril.Chin@Sun.COM 		stakputc(c+NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE)));
18774887Schin 	}
18784887Schin 	else
18794887Schin 	{
18804887Schin 		stakputc(c+flag);
18814887Schin 		if(flag&NV_INTEGER)
18824887Schin 			c +=  nv_size(np);
18834887Schin 	}
18844887Schin 	stakputc(c);
18854887Schin 	stakputs(nv_name(np));
18864887Schin }
18874887Schin #else
18884887Schin static void attstore(register Namval_t *np, void *data)
18894887Schin {
18904887Schin 	register int flag = np->nvflag;
18914887Schin 	register struct adata *ap = (struct adata*)data;
18928462SApril.Chin@Sun.COM 	ap->sh = &sh;
18938462SApril.Chin@Sun.COM 	ap->tp = 0;
18944887Schin 	if(!(flag&NV_EXPORT) || (flag&NV_FUNCT))
18954887Schin 		return;
18964887Schin 	flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
18974887Schin 	*ap->attval++ = '=';
18988462SApril.Chin@Sun.COM 	if((flag&NV_DOUBLE) == NV_DOUBLE)
18994887Schin 	{
19004887Schin 		/* export doubles as integers for ksh88 compatibility */
19018462SApril.Chin@Sun.COM 		*ap->attval++ = ' '+ NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE));
19024887Schin 		*ap->attval = ' ';
19034887Schin 	}
19044887Schin 	else
19054887Schin 	{
19064887Schin 		*ap->attval++ = ' '+flag;
19074887Schin 		if(flag&NV_INTEGER)
19084887Schin 			*ap->attval = ' ' + nv_size(np);
19094887Schin 		else
19104887Schin 			*ap->attval = ' ';
19114887Schin 	}
19124887Schin 	ap->attval = strcopy(++ap->attval,nv_name(np));
19134887Schin }
19144887Schin #endif
19154887Schin 
19164887Schin #ifndef _ENV_H
19174887Schin static void pushnam(Namval_t *np, void *data)
19184887Schin {
19194887Schin 	register char *value;
19204887Schin 	register struct adata *ap = (struct adata*)data;
19218462SApril.Chin@Sun.COM 	ap->sh = &sh;
19228462SApril.Chin@Sun.COM 	ap->tp = 0;
19234887Schin 	if(nv_isattr(np,NV_IMPORT))
19244887Schin 	{
19254887Schin 		if(np->nvenv)
19264887Schin 			*ap->argnam++ = np->nvenv;
19274887Schin 	}
19284887Schin 	else if(value=nv_getval(np))
19294887Schin 		*ap->argnam++ = staknam(np,value);
19304887Schin 	if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER))
19314887Schin 		ap->attsize += (strlen(nv_name(np))+4);
19324887Schin }
19334887Schin #endif
19344887Schin 
19354887Schin /*
19364887Schin  * Generate the environment list for the child.
19374887Schin  */
19384887Schin 
19394887Schin #ifdef _ENV_H
19404887Schin char **sh_envgen(void)
19414887Schin {
19424887Schin 	int offset,tell;
19434887Schin 	register char **er;
19444887Schin 	env_delete(sh.env,"_");
19454887Schin 	er = env_get(sh.env);
19464887Schin 	offset = staktell();
19474887Schin 	stakputs(e_envmarker);
19484887Schin 	tell = staktell();
19494887Schin 	nv_scan(sh.var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
19504887Schin 	if(tell ==staktell())
19514887Schin 		stakseek(offset);
19524887Schin 	else
19534887Schin 		*--er = stakfreeze(1)+offset;
19544887Schin 	return(er);
19554887Schin }
19564887Schin #else
19574887Schin char **sh_envgen(void)
19584887Schin {
19594887Schin 	register char **er;
19604887Schin 	register int namec;
19614887Schin 	register char *cp;
19624887Schin 	struct adata data;
19638462SApril.Chin@Sun.COM 	Shell_t	*shp = sh_getinterp();
19648462SApril.Chin@Sun.COM 	data.sh = shp;
19658462SApril.Chin@Sun.COM 	data.tp = 0;
19664887Schin 	/* L_ARGNOD gets generated automatically as full path name of command */
19674887Schin 	nv_offattr(L_ARGNOD,NV_EXPORT);
19684887Schin 	data.attsize = 6;
19698462SApril.Chin@Sun.COM 	namec = nv_scan(shp->var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT);
19708462SApril.Chin@Sun.COM 	namec += shp->nenv;
19714887Schin 	er = (char**)stakalloc((namec+4)*sizeof(char*));
19728462SApril.Chin@Sun.COM 	data.argnam = (er+=2) + shp->nenv;
19738462SApril.Chin@Sun.COM 	if(shp->nenv)
19748462SApril.Chin@Sun.COM 		memcpy((void*)er,environ,shp->nenv*sizeof(char*));
19758462SApril.Chin@Sun.COM 	nv_scan(shp->var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT);
19764887Schin 	*data.argnam = (char*)stakalloc(data.attsize);
19774887Schin 	cp = data.attval = strcopy(*data.argnam,e_envmarker);
19788462SApril.Chin@Sun.COM 	nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
19794887Schin 	*data.attval = 0;
19804887Schin 	if(cp!=data.attval)
19814887Schin 		data.argnam++;
19824887Schin 	*data.argnam = 0;
19834887Schin 	return(er);
19844887Schin }
19854887Schin #endif
19864887Schin 
19874887Schin struct scan
19884887Schin {
19894887Schin 	void    (*scanfn)(Namval_t*, void*);
19904887Schin 	int     scanmask;
19914887Schin 	int     scanflags;
19924887Schin 	int     scancount;
19934887Schin 	void    *scandata;
19944887Schin };
19954887Schin 
19964887Schin static int scanfilter(Dt_t *dict, void *arg, void *data)
19974887Schin {
19984887Schin 	register Namval_t *np = (Namval_t*)arg;
19994887Schin 	register int k=np->nvflag;
20004887Schin 	register struct scan *sp = (struct scan*)data;
20018462SApril.Chin@Sun.COM 	register struct adata *tp = (struct adata*)sp->scandata;
20024887Schin 	NOT_USED(dict);
20038462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
2004*10898Sroland.mainz@nrubsig.org 	if(tp && !is_abuiltin(np) && tp && tp->tp && nv_type(np)!=tp->tp)
20058462SApril.Chin@Sun.COM 		return(0);
20068462SApril.Chin@Sun.COM #endif /*SHOPT_TYPEDEF */
20074887Schin 	if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags)))
20084887Schin 	{
20098462SApril.Chin@Sun.COM 		if(!np->nvalue.cp && !np->nvfun && !nv_isattr(np,~NV_DEFAULT))
20104887Schin 			return(0);
20114887Schin 		if(sp->scanfn)
20124887Schin 		{
20134887Schin 			if(nv_isarray(np))
20144887Schin 				nv_putsub(np,NIL(char*),0L);
20154887Schin 			(*sp->scanfn)(np,sp->scandata);
20164887Schin 		}
20174887Schin 		sp->scancount++;
20184887Schin 	}
20194887Schin 	return(0);
20204887Schin }
20214887Schin 
20224887Schin /*
20234887Schin  * Walk through the name-value pairs
20244887Schin  * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
20254887Schin  *	are visited
20264887Schin  * If <mask> is zero, and <flags> non-zero, then nodes with one or
20274887Schin  *	more of <flags> is visited
20284887Schin  * If <mask> and <flags> are zero, then all nodes are visted
20294887Schin  */
20304887Schin int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags)
20314887Schin {
20324887Schin 	Dt_t *base=0;
20334887Schin 	struct scan sdata;
20344887Schin 	int (*hashfn)(Dt_t*, void*, void*);
20354887Schin 	sdata.scanmask = mask;
20364887Schin 	sdata.scanflags = flags&~NV_NOSCOPE;
20374887Schin 	sdata.scanfn = fn;
20384887Schin 	sdata.scancount = 0;
20394887Schin 	sdata.scandata = data;
20404887Schin 	hashfn = scanfilter;
20414887Schin 	if(flags&NV_NOSCOPE)
20424887Schin 		base = dtview((Dt_t*)root,0);
20434887Schin 	dtwalk(root, hashfn,&sdata);
20444887Schin 	if(base)
20454887Schin 		 dtview((Dt_t*)root,base);
20464887Schin 	return(sdata.scancount);
20474887Schin }
20484887Schin 
20494887Schin /*
20504887Schin  * create a new environment scope
20514887Schin  */
20528462SApril.Chin@Sun.COM void sh_scope(Shell_t *shp, struct argnod *envlist, int fun)
20534887Schin {
20548462SApril.Chin@Sun.COM 	register Dt_t		*newscope, *newroot=shp->var_base;
20558462SApril.Chin@Sun.COM 	struct Ufunction	*rp;
20564887Schin 	newscope = dtopen(&_Nvdisc,Dtoset);
20574887Schin 	if(envlist)
20588462SApril.Chin@Sun.COM 	{
20598462SApril.Chin@Sun.COM 		dtview(newscope,(Dt_t*)shp->var_tree);
20608462SApril.Chin@Sun.COM 		shp->var_tree = newscope;
2061*10898Sroland.mainz@nrubsig.org 		nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN,0);
20628462SApril.Chin@Sun.COM 		if(!fun)
20638462SApril.Chin@Sun.COM 			return;
20648462SApril.Chin@Sun.COM 		shp->var_tree = dtview(newscope,0);
20658462SApril.Chin@Sun.COM 	}
20668462SApril.Chin@Sun.COM 	if((rp=shp->st.real_fun)  && rp->sdict)
20678462SApril.Chin@Sun.COM 	{
20688462SApril.Chin@Sun.COM 		dtview(rp->sdict,newroot);
20698462SApril.Chin@Sun.COM 		newroot = rp->sdict;
20708462SApril.Chin@Sun.COM 
20718462SApril.Chin@Sun.COM 	}
20728462SApril.Chin@Sun.COM 	dtview(newscope,(Dt_t*)newroot);
20738462SApril.Chin@Sun.COM 	shp->var_tree = newscope;
20744887Schin }
20754887Schin 
20764887Schin /*
20774887Schin  * Remove freeable local space associated with the nvalue field
20784887Schin  * of nnod. This includes any strings representing the value(s) of the
20794887Schin  * node, as well as its dope vector, if it is an array.
20804887Schin  */
20814887Schin 
20824887Schin void	sh_envnolocal (register Namval_t *np, void *data)
20834887Schin {
20844887Schin 	char *cp=0;
20854887Schin 	NOT_USED(data);
2086*10898Sroland.mainz@nrubsig.org 	if(np==VERSIONNOD && nv_isref(np))
2087*10898Sroland.mainz@nrubsig.org 		return;
2088*10898Sroland.mainz@nrubsig.org 	if(np==L_ARGNOD)
2089*10898Sroland.mainz@nrubsig.org 		return;
20904887Schin 	if(nv_isattr(np,NV_EXPORT) && nv_isarray(np))
20914887Schin 	{
20924887Schin 		nv_putsub(np,NIL(char*),0);
20934887Schin 		if(cp = nv_getval(np))
20944887Schin 			cp = strdup(cp);
20954887Schin 	}
20964887Schin 	if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
20974887Schin 	{
2098*10898Sroland.mainz@nrubsig.org 		if(nv_isref(np) && np!=VERSIONNOD)
20994887Schin 		{
21004887Schin 			nv_offattr(np,NV_NOFREE|NV_REF);
21014887Schin 			free((void*)np->nvalue.nrp);
21024887Schin 			np->nvalue.cp = 0;
21034887Schin 		}
21044887Schin 		if(!cp)
21054887Schin 			return;
21064887Schin 	}
21074887Schin 	if(nv_isarray(np))
21084887Schin 		nv_putsub(np,NIL(char*),ARRAY_UNDEF);
21094887Schin 	_nv_unset(np,NV_RDONLY);
21104887Schin 	nv_setattr(np,0);
21114887Schin 	if(cp)
21124887Schin 	{
21134887Schin 		nv_putval(np,cp,0);
21144887Schin 		free((void*)cp);
21154887Schin 	}
21164887Schin }
21174887Schin 
21184887Schin /*
21194887Schin  * Currently this is a dummy, but someday will be needed
21204887Schin  * for reference counting
21214887Schin  */
21224887Schin void	nv_close(Namval_t *np)
21234887Schin {
21244887Schin 	NOT_USED(np);
21254887Schin }
21264887Schin 
21278462SApril.Chin@Sun.COM static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroot)
21284887Schin {
21298462SApril.Chin@Sun.COM 	register Namval_t *np,*nq, *npnext;
21308462SApril.Chin@Sun.COM 	for(np=(Namval_t*)dtfirst(root);np;np=npnext)
21314887Schin 	{
21328462SApril.Chin@Sun.COM 		if(nv_isref(np))
2133*10898Sroland.mainz@nrubsig.org 		{
2134*10898Sroland.mainz@nrubsig.org 			free((void*)np->nvalue.nrp);
2135*10898Sroland.mainz@nrubsig.org 			np->nvalue.cp = 0;
2136*10898Sroland.mainz@nrubsig.org 			np->nvflag = 0;
2137*10898Sroland.mainz@nrubsig.org 		}
21388462SApril.Chin@Sun.COM 		if(nq=dtsearch(oroot,np))
21398462SApril.Chin@Sun.COM 		{
21408462SApril.Chin@Sun.COM 			if(nv_cover(nq))
21418462SApril.Chin@Sun.COM 			{
21428462SApril.Chin@Sun.COM 				int subshell = shp->subshell;
21438462SApril.Chin@Sun.COM 				shp->subshell = 0;
21448462SApril.Chin@Sun.COM 				if(nv_isattr(nq, NV_INTEGER))
21458462SApril.Chin@Sun.COM 				{
21468462SApril.Chin@Sun.COM 					Sfdouble_t d = nv_getnum(nq);
21478462SApril.Chin@Sun.COM 					nv_putval(nq,(char*)&d,NV_LDOUBLE);
21488462SApril.Chin@Sun.COM 				}
2149*10898Sroland.mainz@nrubsig.org 				else if(shp->test&4)
2150*10898Sroland.mainz@nrubsig.org 					nv_putval(nq, strdup(nv_getval(nq)), NV_RDONLY);
21518462SApril.Chin@Sun.COM 				else
21528462SApril.Chin@Sun.COM 					nv_putval(nq, nv_getval(nq), NV_RDONLY);
21538462SApril.Chin@Sun.COM 				shp->subshell = subshell;
21548462SApril.Chin@Sun.COM 				np->nvfun = 0;
21558462SApril.Chin@Sun.COM 			}
21568462SApril.Chin@Sun.COM #ifdef _ENV_H
21578462SApril.Chin@Sun.COM 			if(nv_isattr(nq,NV_EXPORT))
21588462SApril.Chin@Sun.COM 				sh_envput(shp->env,nq);
21598462SApril.Chin@Sun.COM #endif
21608462SApril.Chin@Sun.COM 		}
21618462SApril.Chin@Sun.COM 		npnext = (Namval_t*)dtnext(root,np);
21628462SApril.Chin@Sun.COM 		shp->last_root = root;
21638462SApril.Chin@Sun.COM 		shp->last_table = 0;
21648462SApril.Chin@Sun.COM 		if(nv_isvtree(np))
21658462SApril.Chin@Sun.COM 		{
21668462SApril.Chin@Sun.COM 			int len = strlen(np->nvname);
21678462SApril.Chin@Sun.COM 			while((nq=npnext) && memcmp(np->nvname,nq->nvname,len)==0 && nq->nvname[len]=='.')
21688462SApril.Chin@Sun.COM 
21698462SApril.Chin@Sun.COM 			{
21708462SApril.Chin@Sun.COM 				npnext = (Namval_t*)dtnext(root,nq);
21718462SApril.Chin@Sun.COM 				_nv_unset(nq,flags);
21728462SApril.Chin@Sun.COM 				nv_delete(nq,root,0);
21738462SApril.Chin@Sun.COM 			}
21748462SApril.Chin@Sun.COM 		}
21754887Schin 		_nv_unset(np,flags);
21768462SApril.Chin@Sun.COM 		nv_delete(np,root,0);
21774887Schin 	}
21784887Schin }
21794887Schin 
21804887Schin /*
21814887Schin  *
21824887Schin  *   Set the value of <np> to 0, and nullify any attributes
21834887Schin  *   that <np> may have had.  Free any freeable space occupied
21844887Schin  *   by the value of <np>.  If <np> denotes an array member, it
21854887Schin  *   will retain its attributes.
21864887Schin  *   <flags> can contain NV_RDONLY to override the readonly attribute
21874887Schin  *	being cleared.
21888462SApril.Chin@Sun.COM  *   <flags> can contain NV_EXPORT to override preserve nvenv
21894887Schin  */
21904887Schin void	_nv_unset(register Namval_t *np,int flags)
21914887Schin {
21928462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
21934887Schin 	register union Value *up;
21944887Schin 	if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY))
21954887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
21964887Schin 	if(is_afunction(np) && np->nvalue.ip)
21974887Schin 	{
21984887Schin 		register struct slnod *slp = (struct slnod*)(np->nvenv);
21994887Schin 		if(slp && !nv_isattr(np,NV_NOFREE))
22004887Schin 		{
22018462SApril.Chin@Sun.COM 			struct Ufunction *rq,*rp = np->nvalue.rp;
22024887Schin 			/* free function definition */
22034887Schin 			register char *name=nv_name(np),*cp= strrchr(name,'.');
22044887Schin 			if(cp)
22054887Schin 			{
22064887Schin 				Namval_t *npv;
22074887Schin 				*cp = 0;
22088462SApril.Chin@Sun.COM 				 npv = nv_open(name,shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD);
22094887Schin 				*cp++ = '.';
22104887Schin 				if(npv)
22114887Schin 					nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv);
22124887Schin 			}
22138462SApril.Chin@Sun.COM 			if(rp->fname && shp->fpathdict && (rq = (struct Ufunction*)nv_search(rp->fname,shp->fpathdict,0)))
22148462SApril.Chin@Sun.COM 			{
22158462SApril.Chin@Sun.COM 				do
22168462SApril.Chin@Sun.COM 				{
22178462SApril.Chin@Sun.COM 					if(rq->np != np)
22188462SApril.Chin@Sun.COM 						continue;
22198462SApril.Chin@Sun.COM 					dtdelete(shp->fpathdict,rq);
22208462SApril.Chin@Sun.COM 					break;
22218462SApril.Chin@Sun.COM 				}
22228462SApril.Chin@Sun.COM 				while(rq = (struct Ufunction*)dtnext(shp->fpathdict,rq));
22238462SApril.Chin@Sun.COM 			}
22248462SApril.Chin@Sun.COM 			if(rp->sdict)
22258462SApril.Chin@Sun.COM 			{
22268462SApril.Chin@Sun.COM 				Namval_t *mp, *nq;
22278462SApril.Chin@Sun.COM 				for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq)
22288462SApril.Chin@Sun.COM 				{
22298462SApril.Chin@Sun.COM 					nq = dtnext(rp->sdict,mp);
22308462SApril.Chin@Sun.COM 					_nv_unset(mp,NV_RDONLY);
22318462SApril.Chin@Sun.COM 					nv_delete(mp,rp->sdict,0);
22328462SApril.Chin@Sun.COM 				}
22338462SApril.Chin@Sun.COM 				dtclose(rp->sdict);
22348462SApril.Chin@Sun.COM 			}
22354887Schin 			stakdelete(slp->slptr);
22364887Schin 			free((void*)np->nvalue.ip);
22374887Schin 			np->nvalue.ip = 0;
22384887Schin 		}
22394887Schin 		goto done;
22404887Schin 	}
22418462SApril.Chin@Sun.COM 	if(shp->subshell && !nv_isnull(np))
22424887Schin 		np = sh_assignok(np,0);
22434887Schin 	nv_offattr(np,NV_NODISC);
22444887Schin 	if(np->nvfun && !nv_isref(np))
22454887Schin 	{
22464887Schin 		/* This function contains disc */
22474887Schin 		if(!nv_local)
22484887Schin 		{
22494887Schin 			nv_local=1;
22504887Schin 			nv_putv(np,NIL(char*),flags,np->nvfun);
22518462SApril.Chin@Sun.COM 			nv_local=0;
22524887Schin 			return;
22534887Schin 		}
22544887Schin 		/* called from disc, assign the actual value */
22554887Schin 		nv_local=0;
22564887Schin 	}
2257*10898Sroland.mainz@nrubsig.org 	if(nv_isattr(np,NV_INT16P) == NV_INT16)
2258*10898Sroland.mainz@nrubsig.org 	{
2259*10898Sroland.mainz@nrubsig.org 		np->nvalue.cp = nv_isarray(np)?Empty:0;
2260*10898Sroland.mainz@nrubsig.org 		goto done;
2261*10898Sroland.mainz@nrubsig.org 	}
22628462SApril.Chin@Sun.COM 	if(nv_isarray(np) && np->nvalue.cp!=Empty && np->nvfun)
22638462SApril.Chin@Sun.COM 		up = np->nvalue.up;
22648462SApril.Chin@Sun.COM 	else
22658462SApril.Chin@Sun.COM 		up = &np->nvalue;
22668462SApril.Chin@Sun.COM 	if(up && up->cp)
22674887Schin 	{
22688462SApril.Chin@Sun.COM 		if(up->cp!=Empty && !nv_isattr(np, NV_NOFREE))
22694887Schin 			free((void*)up->cp);
22704887Schin 		up->cp = 0;
22714887Schin 	}
22724887Schin done:
22734887Schin 	if(!nv_isarray(np) || !nv_arrayptr(np))
22744887Schin 	{
22758462SApril.Chin@Sun.COM 		if(nv_isref(np) && !nv_isattr(np,NV_EXPORT))
22764887Schin 			free((void*)np->nvalue.nrp);
22774887Schin 		nv_setsize(np,0);
22784887Schin 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
22794887Schin 		{
22804887Schin 			if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'['))
22818462SApril.Chin@Sun.COM 				env_delete(shp->env,nv_name(np));
22828462SApril.Chin@Sun.COM 			if(!(flags&NV_EXPORT) ||  nv_isattr(np,NV_IMPORT|NV_EXPORT)==(NV_IMPORT|NV_EXPORT))
22838462SApril.Chin@Sun.COM 				np->nvenv = 0;
22844887Schin 			nv_setattr(np,0);
22854887Schin 		}
22864887Schin 		else
22878462SApril.Chin@Sun.COM 		{
22884887Schin 			nv_setattr(np,NV_MINIMAL);
22898462SApril.Chin@Sun.COM 			nv_delete(np,(Dt_t*)0,0);
22908462SApril.Chin@Sun.COM 		}
22914887Schin 	}
22924887Schin }
22934887Schin 
22944887Schin /*
22954887Schin  * return the node pointer in the highest level scope
22964887Schin  */
22978462SApril.Chin@Sun.COM Namval_t *sh_scoped(Shell_t *shp, register Namval_t *np)
22984887Schin {
22998462SApril.Chin@Sun.COM 	if(!dtvnext(shp->var_tree))
23004887Schin 		return(np);
23018462SApril.Chin@Sun.COM 	return(dtsearch(shp->var_tree,np));
23024887Schin }
23034887Schin 
23044887Schin #if 1
23054887Schin /*
23064887Schin  * return space separated list of names of variables in given tree
23074887Schin  */
23084887Schin static char *tableval(Dt_t *root)
23094887Schin {
23104887Schin 	static Sfio_t *out;
23114887Schin 	register Namval_t *np;
23124887Schin 	register int first=1;
23134887Schin 	register Dt_t *base = dtview(root,0);
23144887Schin         if(out)
23154887Schin                 sfseek(out,(Sfoff_t)0,SEEK_SET);
23164887Schin         else
23174887Schin                 out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
23184887Schin 	for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
23194887Schin 	{
23204887Schin                 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
23214887Schin 		{
23224887Schin 			if(!first)
23234887Schin 				sfputc(out,' ');
23244887Schin 			else
23254887Schin 				first = 0;
23264887Schin 			sfputr(out,np->nvname,-1);
23274887Schin 		}
23284887Schin 	}
23294887Schin 	sfputc(out,0);
23304887Schin 	if(base)
23314887Schin 		dtview(root,base);
23324887Schin 	return((char*)out->_data);
23334887Schin }
23344887Schin #endif
23354887Schin 
23364887Schin #if SHOPT_OPTIMIZE
23374887Schin struct optimize
23384887Schin {
23394887Schin 	Namfun_t	hdr;
23408462SApril.Chin@Sun.COM 	Shell_t		*sh;
23414887Schin 	char		**ptr;
23424887Schin 	struct optimize	*next;
23434887Schin 	Namval_t	*np;
23444887Schin };
23454887Schin 
23464887Schin static struct optimize *opt_free;
23474887Schin 
23484887Schin static void optimize_clear(Namval_t* np, Namfun_t *fp)
23494887Schin {
23504887Schin 	struct optimize *op = (struct optimize*)fp;
23514887Schin 	nv_stack(np,fp);
23524887Schin 	nv_stack(np,(Namfun_t*)0);
23534887Schin 	for(;op && op->np==np; op=op->next)
23544887Schin 	{
23554887Schin 		if(op->ptr)
23564887Schin 		{
23574887Schin 			*op->ptr = 0;
23584887Schin 			op->ptr = 0;
23594887Schin 		}
23604887Schin 	}
23614887Schin }
23624887Schin 
23634887Schin static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp)
23644887Schin {
23654887Schin 	nv_putv(np,val,flags,fp);
23664887Schin 	optimize_clear(np,fp);
23674887Schin }
23684887Schin 
23698462SApril.Chin@Sun.COM static Namfun_t *clone_optimize(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
23708462SApril.Chin@Sun.COM {
23718462SApril.Chin@Sun.COM 	return((Namfun_t*)0);
23728462SApril.Chin@Sun.COM }
23738462SApril.Chin@Sun.COM 
23748462SApril.Chin@Sun.COM static const Namdisc_t optimize_disc  = {sizeof(struct optimize),put_optimize,0,0,0,0,clone_optimize};
23754887Schin 
23764887Schin void nv_optimize(Namval_t *np)
23774887Schin {
23784887Schin 	register Namfun_t *fp;
23794887Schin 	register struct optimize *op, *xp;
23804887Schin 	if(sh.argaddr)
23814887Schin 	{
23828462SApril.Chin@Sun.COM 		if(np==SH_LINENO)
23838462SApril.Chin@Sun.COM 		{
23848462SApril.Chin@Sun.COM 			sh.argaddr = 0;
23858462SApril.Chin@Sun.COM 			return;
23868462SApril.Chin@Sun.COM 		}
23874887Schin 		for(fp=np->nvfun; fp; fp = fp->next)
23884887Schin 		{
23898462SApril.Chin@Sun.COM 			if(fp->disc && (fp->disc->getnum || fp->disc->getval))
23904887Schin 			{
23914887Schin 				sh.argaddr = 0;
23924887Schin 				return;
23934887Schin 			}
23944887Schin 			if(fp->disc== &optimize_disc)
23954887Schin 				break;
23964887Schin 		}
23974887Schin 		if((xp= (struct optimize*)fp) && xp->ptr==sh.argaddr)
23984887Schin 			return;
23994887Schin 		if(op = opt_free)
24004887Schin 			opt_free = op->next;
24014887Schin 		else
24024887Schin 			op=(struct optimize*)calloc(1,sizeof(struct optimize));
24034887Schin 		op->ptr = sh.argaddr;
24044887Schin 		op->np = np;
24054887Schin 		if(xp)
24064887Schin 		{
24074887Schin 			op->hdr.disc = 0;
24084887Schin 			op->next = xp->next;
24094887Schin 			xp->next = op;
24104887Schin 		}
24114887Schin 		else
24124887Schin 		{
24134887Schin 			op->hdr.disc = &optimize_disc;
24144887Schin 			op->next = (struct optimize*)sh.optlist;
24154887Schin 			sh.optlist = (void*)op;
24164887Schin 			nv_stack(np,&op->hdr);
24174887Schin 		}
24184887Schin 	}
24194887Schin }
24204887Schin 
24214887Schin void sh_optclear(Shell_t *shp, void *old)
24224887Schin {
24234887Schin 	register struct optimize *op,*opnext;
24244887Schin 	for(op=(struct optimize*)shp->optlist; op; op = opnext)
24254887Schin 	{
24264887Schin 		opnext = op->next;
24274887Schin 		if(op->ptr && op->hdr.disc)
24284887Schin 		{
24294887Schin 			nv_stack(op->np,&op->hdr);
24304887Schin 			nv_stack(op->np,(Namfun_t*)0);
24314887Schin 		}
24324887Schin 		op->next = opt_free;
24334887Schin 		opt_free = op;
24344887Schin 	}
24354887Schin 	shp->optlist = old;
24364887Schin }
24374887Schin 
24384887Schin #else
24394887Schin #   define	optimize_clear(np,fp)
24404887Schin #endif /* SHOPT_OPTIMIZE */
24414887Schin 
24424887Schin /*
24434887Schin  *   Return a pointer to a character string that denotes the value
24444887Schin  *   of <np>.  If <np> refers to an array,  return a pointer to
24454887Schin  *   the value associated with the current index.
24464887Schin  *
24474887Schin  *   If the value of <np> is an integer, the string returned will
24484887Schin  *   be overwritten by the next call to nv_getval.
24494887Schin  *
24504887Schin  *   If <np> has no value, 0 is returned.
24514887Schin  */
24524887Schin 
24534887Schin char *nv_getval(register Namval_t *np)
24544887Schin {
24554887Schin 	register union Value *up= &np->nvalue;
24564887Schin 	register int numeric;
24574887Schin #if SHOPT_OPTIMIZE
24584887Schin 	if(!nv_local && sh.argaddr)
24594887Schin 		nv_optimize(np);
24604887Schin #endif /* SHOPT_OPTIMIZE */
24618462SApril.Chin@Sun.COM 	if((!np->nvfun || !np->nvfun->disc) && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF|NV_TABLE))
24624887Schin 		goto done;
24634887Schin 	if(nv_isref(np))
24644887Schin 	{
24658462SApril.Chin@Sun.COM 		if(!np->nvalue.cp)
24668462SApril.Chin@Sun.COM 			return(0);
24674887Schin 		sh.last_table = nv_reftable(np);
24684887Schin 		return(nv_name(nv_refnode(np)));
24694887Schin 	}
24708462SApril.Chin@Sun.COM 	if(np->nvfun && np->nvfun->disc)
24714887Schin 	{
24724887Schin 		if(!nv_local)
24734887Schin 		{
24744887Schin 			nv_local=1;
24754887Schin 			return(nv_getv(np, np->nvfun));
24764887Schin 		}
24774887Schin 		nv_local=0;
24784887Schin 	}
24794887Schin 	numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
24804887Schin 	if(numeric)
24814887Schin 	{
24824887Schin 		Sflong_t  ll;
24834887Schin 		if(!up->cp)
24844887Schin 			return("0");
24858462SApril.Chin@Sun.COM 		if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE)
24864887Schin 		{
24874887Schin 			Sfdouble_t ld;
24884887Schin 			double d;
24894887Schin 			char *format;
24904887Schin 			if(nv_isattr(np,NV_LONG))
24914887Schin 			{
24924887Schin 				ld = *up->ldp;
24934887Schin 				if(nv_isattr (np,NV_EXPNOTE))
24944887Schin 					format = "%.*Lg";
24958462SApril.Chin@Sun.COM 				else if(nv_isattr (np,NV_HEXFLOAT))
24968462SApril.Chin@Sun.COM 					format = "%.*La";
24974887Schin 				else
24984887Schin 					format = "%.*Lf";
24994887Schin 				sfprintf(sh.strbuf,format,nv_size(np),ld);
25004887Schin 			}
25014887Schin 			else
25024887Schin 			{
25034887Schin 				d = *up->dp;
25044887Schin 				if(nv_isattr (np,NV_EXPNOTE))
25054887Schin 					format = "%.*g";
25068462SApril.Chin@Sun.COM 				else if(nv_isattr (np,NV_HEXFLOAT))
25078462SApril.Chin@Sun.COM 					format = "%.*a";
25084887Schin 				else
25094887Schin 					format = "%.*f";
25104887Schin 				sfprintf(sh.strbuf,format,nv_size(np),d);
25114887Schin 			}
25124887Schin 			return(sfstruse(sh.strbuf));
25134887Schin 		}
25144887Schin 		else if(nv_isattr(np,NV_UNSIGN))
25154887Schin 		{
25164887Schin 	        	if(nv_isattr (np,NV_LONG))
25174887Schin 				ll = *(Sfulong_t*)up->llp;
25184887Schin 			else if(nv_isattr (np,NV_SHORT))
25198462SApril.Chin@Sun.COM 			{
25208462SApril.Chin@Sun.COM 				if(nv_isattr(np,NV_INT16P)==NV_INT16P)
25218462SApril.Chin@Sun.COM 					ll = *(uint16_t*)(up->sp);
25228462SApril.Chin@Sun.COM 				else
25238462SApril.Chin@Sun.COM 					ll = (uint16_t)up->s;
25248462SApril.Chin@Sun.COM 			}
25254887Schin 			else
25264887Schin 				ll = *(uint32_t*)(up->lp);
25274887Schin 		}
25284887Schin         	else if(nv_isattr (np,NV_LONG))
25294887Schin 			ll = *up->llp;
25304887Schin         	else if(nv_isattr (np,NV_SHORT))
25318462SApril.Chin@Sun.COM 		{
25328462SApril.Chin@Sun.COM 			if(nv_isattr(np,NV_INT16P)==NV_INT16P)
25338462SApril.Chin@Sun.COM 				ll = *up->sp;
25348462SApril.Chin@Sun.COM 			else
25358462SApril.Chin@Sun.COM 				ll = up->s;
25368462SApril.Chin@Sun.COM 		}
25374887Schin         	else
25384887Schin 			ll = *(up->lp);
25394887Schin 		if((numeric=nv_size(np))==10)
25404887Schin 		{
25414887Schin 			if(nv_isattr(np,NV_UNSIGN))
25424887Schin 			{
25434887Schin 				sfprintf(sh.strbuf,"%I*u",sizeof(ll),ll);
25444887Schin 				return(sfstruse(sh.strbuf));
25454887Schin 			}
25464887Schin 			numeric = 0;
25474887Schin 		}
25484887Schin 		return(fmtbasell(ll,numeric, numeric&&numeric!=10));
25494887Schin 	}
25504887Schin done:
25514887Schin #if (_AST_VERSION>=20030127L)
25524887Schin 	/*
25534887Schin 	 * if NV_RAW flag is on, return pointer to binary data
25544887Schin 	 * otherwise, base64 encode the data and return this string
25554887Schin 	 */
25564887Schin 	if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
25574887Schin 	{
25584887Schin 		char *cp;
25594887Schin 		int size= nv_size(np), insize=(4*size)/3+size/45+8;
25604887Schin 		base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)0);
25614887Schin 		return(cp);
25624887Schin 	}
25634887Schin #endif
25644887Schin 	if((numeric=nv_size(np)) && up->cp && up->cp[numeric])
25654887Schin 	{
25664887Schin 		char *cp = getbuf(numeric+1);
25674887Schin 		memcpy(cp,up->cp,numeric);
25684887Schin 		cp[numeric]=0;
25694887Schin 		return(cp);
25704887Schin 	}
25714887Schin 	return ((char*)up->cp);
25724887Schin }
25734887Schin 
25744887Schin Sfdouble_t nv_getnum(register Namval_t *np)
25754887Schin {
25764887Schin 	register union Value *up;
25774887Schin 	register Sfdouble_t r=0;
25784887Schin 	register char *str;
25794887Schin #if SHOPT_OPTIMIZE
25804887Schin 	if(!nv_local && sh.argaddr)
25814887Schin 		nv_optimize(np);
25824887Schin #endif /* SHOPT_OPTIMIZE */
25834887Schin 	if(nv_istable(np))
25844887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np));
25858462SApril.Chin@Sun.COM      	if(np->nvfun && np->nvfun->disc)
25864887Schin 	{
25874887Schin 		if(!nv_local)
25884887Schin 		{
25894887Schin 			nv_local=1;
25904887Schin 			return(nv_getn(np, np->nvfun));
25914887Schin 		}
25924887Schin 		nv_local=0;
25934887Schin 	}
25948462SApril.Chin@Sun.COM 	if(nv_isref(np))
25958462SApril.Chin@Sun.COM 	{
25968462SApril.Chin@Sun.COM 		str = nv_refsub(np);
25978462SApril.Chin@Sun.COM 		np = nv_refnode(np);
25988462SApril.Chin@Sun.COM 		if(str)
25998462SApril.Chin@Sun.COM 			nv_putsub(np,str,0L);
26008462SApril.Chin@Sun.COM 	}
26014887Schin      	if(nv_isattr (np, NV_INTEGER))
26024887Schin 	{
26034887Schin 		up= &np->nvalue;
26048462SApril.Chin@Sun.COM 		if(!up->lp || up->cp==Empty)
26054887Schin 			r = 0;
26068462SApril.Chin@Sun.COM 		else if(nv_isattr(np, NV_DOUBLE)==NV_DOUBLE)
26074887Schin 		{
26084887Schin 			if(nv_isattr(np, NV_LONG))
26094887Schin 	                       	r = *up->ldp;
26104887Schin 			else
26114887Schin        	                	r = *up->dp;
26124887Schin 		}
26134887Schin 		else if(nv_isattr(np, NV_UNSIGN))
26144887Schin 		{
26154887Schin 			if(nv_isattr(np, NV_LONG))
26164887Schin 				r = (Sflong_t)*((Sfulong_t*)up->llp);
26174887Schin 			else if(nv_isattr(np, NV_SHORT))
26188462SApril.Chin@Sun.COM 			{
26198462SApril.Chin@Sun.COM 				if(nv_isattr(np,NV_INT16P)==NV_INT16P)
26208462SApril.Chin@Sun.COM 					r = (Sflong_t)(*(uint16_t*)up->sp);
26218462SApril.Chin@Sun.COM 				else
26228462SApril.Chin@Sun.COM 					r = (Sflong_t)((uint16_t)up->s);
26238462SApril.Chin@Sun.COM 			}
26244887Schin 			else
26254887Schin 				r = *((uint32_t*)up->lp);
26264887Schin 		}
26274887Schin 		else
26284887Schin 		{
26294887Schin 			if(nv_isattr(np, NV_LONG))
26304887Schin 				r = *up->llp;
26314887Schin 			else if(nv_isattr(np, NV_SHORT))
26328462SApril.Chin@Sun.COM 			{
26338462SApril.Chin@Sun.COM 				if(nv_isattr(np,NV_INT16P)==NV_INT16P)
26348462SApril.Chin@Sun.COM 					r = *up->sp;
26358462SApril.Chin@Sun.COM 				else
26368462SApril.Chin@Sun.COM 					r = up->s;
26378462SApril.Chin@Sun.COM 			}
26384887Schin 			else
26394887Schin 				r = *up->lp;
26404887Schin 		}
26414887Schin 	}
26424887Schin 	else if((str=nv_getval(np)) && *str!=0)
26434887Schin 	{
26444887Schin 		if(np->nvfun ||  nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
26454887Schin 		{
26464887Schin 			while(*str=='0')
26474887Schin 				str++;
26484887Schin 		}
26494887Schin 		r = sh_arith(str);
26504887Schin 	}
26514887Schin 	return(r);
26524887Schin }
26534887Schin /*
26544887Schin  *   Give <np> the attributes <newatts,> and change its current
26554887Schin  *   value to conform to <newatts>.  The <size> of left and right
26564887Schin  *   justified fields may be given.
26574887Schin  */
26584887Schin void nv_newattr (register Namval_t *np, unsigned newatts, int size)
26594887Schin {
26604887Schin 	register char *sp;
26614887Schin 	register char *cp = 0;
26624887Schin 	register unsigned int n;
26634887Schin 	Namarr_t *ap = 0;
26644887Schin 	int oldsize,oldatts;
26658462SApril.Chin@Sun.COM 	Namfun_t *fp= (newatts&NV_NODISC)?np->nvfun:0;
2666*10898Sroland.mainz@nrubsig.org 	char *prefix = sh.prefix;
26678462SApril.Chin@Sun.COM 	newatts &= ~NV_NODISC;
26684887Schin 
26694887Schin 	/* check for restrictions */
26704887Schin 	if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD)))
26714887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
26724887Schin 	/* handle attributes that do not change data separately */
26734887Schin 	n = np->nvflag;
26744887Schin 	if(newatts&NV_EXPORT)
26754887Schin 		nv_offattr(np,NV_IMPORT);
26768462SApril.Chin@Sun.COM #ifdef _ENV_H
26774887Schin 	if(((n^newatts)&NV_EXPORT))
26784887Schin 	{
26794887Schin 		/* record changes to the environment */
26804887Schin 		if(n&NV_EXPORT)
26814887Schin 			env_delete(sh.env,nv_name(np));
26824887Schin 		else
26834887Schin 			sh_envput(sh.env,np);
26844887Schin 	}
26858462SApril.Chin@Sun.COM #endif
2686*10898Sroland.mainz@nrubsig.org 	oldsize = nv_size(np);
2687*10898Sroland.mainz@nrubsig.org 	if((size==oldsize|| (n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0)
26884887Schin 	{
26894887Schin 		if(size)
26904887Schin 			nv_setsize(np,size);
26914887Schin 		nv_offattr(np, ~NV_NOFREE);
26924887Schin 		nv_onattr(np, newatts);
26934887Schin 		return;
26944887Schin 	}
26954887Schin 	/* for an array, change all the elements */
26964887Schin 	if((ap=nv_arrayptr(np)) && ap->nelem>0)
26974887Schin 		nv_putsub(np,NIL(char*),ARRAY_SCAN);
26984887Schin 	oldsize = nv_size(np);
26994887Schin 	oldatts = np->nvflag;
27008462SApril.Chin@Sun.COM 	if(fp)
27018462SApril.Chin@Sun.COM 		np->nvfun = 0;
27024887Schin 	if(ap) /* add element to prevent array deletion */
27034887Schin 		ap->nelem++;
27044887Schin 	do
27054887Schin 	{
27064887Schin 		nv_setsize(np,oldsize);
27074887Schin 		np->nvflag = oldatts;
27084887Schin 		if (sp = nv_getval(np))
27094887Schin  		{
27104887Schin 			if(nv_isattr(np,NV_ZFILL))
27114887Schin 				while(*sp=='0') sp++;
27124887Schin 			cp = (char*)malloc((n=strlen (sp)) + 1);
27134887Schin 			strcpy(cp, sp);
27144887Schin 			if(ap)
27154887Schin 			{
27164887Schin 				Namval_t *mp;
27174887Schin 				ap->nelem &= ~ARRAY_SCAN;
27184887Schin 				if(mp=nv_opensub(np))
27198462SApril.Chin@Sun.COM 				{
27208462SApril.Chin@Sun.COM 					nv_unset(mp);
27218462SApril.Chin@Sun.COM 					mp->nvalue.cp = Empty;
27228462SApril.Chin@Sun.COM 				}
27238462SApril.Chin@Sun.COM 				else
27248462SApril.Chin@Sun.COM 					nv_unset(np);
27258462SApril.Chin@Sun.COM 				ap->nelem |= ARRAY_SCAN;
27264887Schin 			}
27278462SApril.Chin@Sun.COM 			else
27288462SApril.Chin@Sun.COM 				nv_unset(np);
27294887Schin 			if(size==0 && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL)))
27304887Schin 				size = n;
27314887Schin 		}
27324887Schin 		else
27334887Schin 			nv_unset(np);
27344887Schin 		nv_setsize(np,size);
27354887Schin 		np->nvflag &= NV_ARRAY;
27364887Schin 		np->nvflag |= newatts;
27374887Schin 		if (cp)
27384887Schin 		{
27394887Schin 			nv_putval (np, cp, NV_RDONLY);
27404887Schin 			free(cp);
27414887Schin 		}
27424887Schin 	}
27434887Schin 	while(ap && nv_nextsub(np));
27448462SApril.Chin@Sun.COM 	if(fp)
27458462SApril.Chin@Sun.COM 		np->nvfun = fp;
27464887Schin 	if(ap)
27474887Schin 		ap->nelem--;
2748*10898Sroland.mainz@nrubsig.org 	sh.prefix = prefix;
27494887Schin 	return;
27504887Schin }
27514887Schin 
27524887Schin #ifndef _NEXT_SOURCE
27534887Schin static char *oldgetenv(const char *string)
27544887Schin {
27554887Schin 	register char c0,c1;
27564887Schin 	register const char *cp, *sp;
27574887Schin 	register char **av = environ;
27584887Schin 	if(!string || (c0= *string)==0)
27594887Schin 		return(0);
27604887Schin 	if((c1=*++string)==0)
27614887Schin 		c1= '=';
27624887Schin 	while(cp = *av++)
27634887Schin 	{
27644887Schin 		if(cp[0]!=c0 || cp[1]!=c1)
27654887Schin 			continue;
27664887Schin 		sp = string;
27674887Schin 		while(*sp && *sp++ == *++cp);
27684887Schin 		if(*sp==0 && *++cp=='=')
27694887Schin 			return((char*)(cp+1));
27704887Schin 	}
27714887Schin 	return(0);
27724887Schin }
27734887Schin 
27744887Schin /*
27754887Schin  * This version of getenv uses the hash storage to access environment values
27764887Schin  */
27774887Schin char *getenv(const char *name)
27784887Schin /*@
27794887Schin 	assume name!=0;
27804887Schin @*/
27814887Schin {
27824887Schin 	register Namval_t *np;
27834887Schin 	if(!sh.var_tree)
27844887Schin 		return(oldgetenv(name));
27854887Schin 	if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT))
27864887Schin 		return(nv_getval(np));
27874887Schin 	if(name[0] == 'P' && name[1] == 'A' && name[2] == 'T' && name[3] == 'H' && name[4] == 0)
27884887Schin 		return(oldgetenv(name));
27894887Schin 	return(0);
27904887Schin }
27914887Schin #endif /* _NEXT_SOURCE */
27924887Schin 
27934887Schin #undef putenv
27944887Schin /*
27954887Schin  * This version of putenv uses the hash storage to assign environment values
27964887Schin  */
27974887Schin int putenv(const char *name)
27984887Schin {
27994887Schin 	register Namval_t *np;
28004887Schin 	if(name)
28014887Schin 	{
28024887Schin 		np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
28034887Schin 		if(!strchr(name,'='))
28044887Schin 			nv_unset(np);
28054887Schin 	}
28064887Schin 	return(0);
28074887Schin }
28084887Schin 
28094887Schin 
28104887Schin /*
28114887Schin  * Override libast setenv()
28124887Schin  */
28134887Schin char* setenviron(const char *name)
28144887Schin {
28154887Schin 	register Namval_t *np;
28164887Schin 	if(name)
28174887Schin 	{
28184887Schin 		np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
28194887Schin 		if(strchr(name,'='))
28204887Schin 			return(nv_getval(np));
28214887Schin 		nv_unset(np);
28224887Schin 	}
28234887Schin 	return("");
28244887Schin }
28254887Schin 
28264887Schin /*
28278462SApril.Chin@Sun.COM  * convert <str> to upper case
28284887Schin  */
28298462SApril.Chin@Sun.COM static void ltou(register char *str)
28304887Schin {
28314887Schin 	register int c;
28328462SApril.Chin@Sun.COM 	for(; c= *((unsigned char*)str); str++)
28334887Schin 	{
28344887Schin 		if(islower(c))
28358462SApril.Chin@Sun.COM 			*str = toupper(c);
28364887Schin 	}
28378462SApril.Chin@Sun.COM }
28388462SApril.Chin@Sun.COM 
28398462SApril.Chin@Sun.COM /*
28408462SApril.Chin@Sun.COM  * convert <str> to lower case
28418462SApril.Chin@Sun.COM  */
28428462SApril.Chin@Sun.COM static void utol(register char *str)
28438462SApril.Chin@Sun.COM {
28448462SApril.Chin@Sun.COM 	register int c;
28458462SApril.Chin@Sun.COM 	for(; c= *((unsigned char*)str); str++)
28468462SApril.Chin@Sun.COM 	{
28478462SApril.Chin@Sun.COM 		if(isupper(c))
28488462SApril.Chin@Sun.COM 			*str = tolower(c);
28498462SApril.Chin@Sun.COM 	}
28504887Schin }
28514887Schin 
28524887Schin /*
28534887Schin  * normalize <cp> and return pointer to subscript if any
28548462SApril.Chin@Sun.COM  * if <eq> is specified, return pointer to first = not in a subscript
28554887Schin  */
28568462SApril.Chin@Sun.COM static char *lastdot(register char *cp, int eq)
28574887Schin {
28588462SApril.Chin@Sun.COM 	register char *ep=0;
28594887Schin 	register int c;
28608462SApril.Chin@Sun.COM 	if(eq)
28618462SApril.Chin@Sun.COM 		cp++;
28624887Schin 	while(c= *cp++)
28634887Schin 	{
28644887Schin 		if(c=='[')
2865*10898Sroland.mainz@nrubsig.org 		{
2866*10898Sroland.mainz@nrubsig.org 			if(*cp==']')
2867*10898Sroland.mainz@nrubsig.org 				cp++;
2868*10898Sroland.mainz@nrubsig.org 			else
2869*10898Sroland.mainz@nrubsig.org 				cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
2870*10898Sroland.mainz@nrubsig.org 		}
28714887Schin 		else if(c=='.')
28724887Schin 		{
28734887Schin 			if(*cp=='[')
2874*10898Sroland.mainz@nrubsig.org 			{
2875*10898Sroland.mainz@nrubsig.org 				cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
2876*10898Sroland.mainz@nrubsig.org 				if((ep=sh_checkid(ep+1,cp)) < cp)
2877*10898Sroland.mainz@nrubsig.org 					cp=strcpy(ep,cp);
2878*10898Sroland.mainz@nrubsig.org 			}
28794887Schin 			ep = 0;
28804887Schin 		}
28818462SApril.Chin@Sun.COM 		else if(eq && c == '=')
28828462SApril.Chin@Sun.COM 			return(cp-1);
28834887Schin 	}
28848462SApril.Chin@Sun.COM 	return(eq?0:ep);
28858462SApril.Chin@Sun.COM }
28868462SApril.Chin@Sun.COM 
28878462SApril.Chin@Sun.COM int nv_rename(register Namval_t *np, int flags)
28888462SApril.Chin@Sun.COM {
28898462SApril.Chin@Sun.COM 	Shell_t			*shp = &sh;
28908462SApril.Chin@Sun.COM 	register Namval_t	*mp=0,*nr=0;
28918462SApril.Chin@Sun.COM 	register char		*cp;
28928462SApril.Chin@Sun.COM 	int			index= -1;
28938462SApril.Chin@Sun.COM 	Namval_t		*last_table = shp->last_table;
28948462SApril.Chin@Sun.COM 	Dt_t			*last_root = shp->last_root;
28958462SApril.Chin@Sun.COM 	Dt_t			*hp = 0;
2896*10898Sroland.mainz@nrubsig.org 	char			*prefix=shp->prefix,*nvenv = 0;
28978462SApril.Chin@Sun.COM 	if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
28988462SApril.Chin@Sun.COM 	{
28998462SApril.Chin@Sun.COM 		if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
29008462SApril.Chin@Sun.COM 			hp = dtvnext(shp->var_tree);
29018462SApril.Chin@Sun.COM 	}
29028462SApril.Chin@Sun.COM 	if(!(cp=nv_getval(np)))
29038462SApril.Chin@Sun.COM 	{
29048462SApril.Chin@Sun.COM 		if(flags&NV_MOVE)
29058462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),e_varname,"");
29068462SApril.Chin@Sun.COM 		return(0);
29078462SApril.Chin@Sun.COM 	}
29088462SApril.Chin@Sun.COM 	if(lastdot(cp,0) && nv_isattr(np,NV_MINIMAL))
29098462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_exit(1),e_varname,nv_name(np));
29108462SApril.Chin@Sun.COM 	if(nv_isarray(np) && !(mp=nv_opensub(np)))
29118462SApril.Chin@Sun.COM 		index=nv_aindex(np);
2912*10898Sroland.mainz@nrubsig.org 	shp->prefix = 0;
29138462SApril.Chin@Sun.COM 	if(!hp)
29148462SApril.Chin@Sun.COM 		hp = shp->var_tree;
29158462SApril.Chin@Sun.COM 	if(!(nr = nv_open(cp, hp, flags|NV_ARRAY|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
29168462SApril.Chin@Sun.COM 		hp = shp->var_base;
29178462SApril.Chin@Sun.COM 	else if(shp->last_root)
29188462SApril.Chin@Sun.COM 		hp = shp->last_root;
29198462SApril.Chin@Sun.COM 	if(!nr)
29208462SApril.Chin@Sun.COM 		nr= nv_open(cp, hp, flags|NV_NOREF|((flags&NV_MOVE)?0:NV_NOFAIL));
2921*10898Sroland.mainz@nrubsig.org 	shp->prefix = prefix;
29228462SApril.Chin@Sun.COM 	if(!nr)
29238462SApril.Chin@Sun.COM 	{
29248462SApril.Chin@Sun.COM 		if(!nv_isvtree(np))
29258462SApril.Chin@Sun.COM 			_nv_unset(np,0);
29268462SApril.Chin@Sun.COM 		return(0);
29278462SApril.Chin@Sun.COM 	}
29288462SApril.Chin@Sun.COM 	if(!mp && index>=0 && nv_isvtree(nr))
29298462SApril.Chin@Sun.COM 	{
29308462SApril.Chin@Sun.COM 		sfprintf(shp->strbuf,"%s[%d]%c",nv_name(np),index,0);
29318462SApril.Chin@Sun.COM 		/* create a virtual node */
29328462SApril.Chin@Sun.COM 		if(mp = nv_open(sfstruse(shp->strbuf),shp->var_tree,NV_VARNAME|NV_ADD|NV_ARRAY))
29338462SApril.Chin@Sun.COM 			mp->nvenv = (void*)np;
29348462SApril.Chin@Sun.COM 	}
29358462SApril.Chin@Sun.COM 	if(mp)
2936*10898Sroland.mainz@nrubsig.org 	{
2937*10898Sroland.mainz@nrubsig.org 		nvenv = (char*)np;
29388462SApril.Chin@Sun.COM 		np = mp;
2939*10898Sroland.mainz@nrubsig.org 	}
29408462SApril.Chin@Sun.COM 	if(nr==np)
29418462SApril.Chin@Sun.COM 	{
29428462SApril.Chin@Sun.COM 		if(index<0)
29438462SApril.Chin@Sun.COM 			return(0);
29448462SApril.Chin@Sun.COM 		if(cp = nv_getval(np))
29458462SApril.Chin@Sun.COM 			cp = strdup(cp);
29468462SApril.Chin@Sun.COM 	}
29478462SApril.Chin@Sun.COM 	_nv_unset(np,0);
2948*10898Sroland.mainz@nrubsig.org 	if(!nv_isattr(np,NV_MINIMAL))
2949*10898Sroland.mainz@nrubsig.org 		np->nvenv = nvenv;
29508462SApril.Chin@Sun.COM 	if(nr==np)
29518462SApril.Chin@Sun.COM 	{
29528462SApril.Chin@Sun.COM 		nv_putsub(np,(char*)0, index);
29538462SApril.Chin@Sun.COM 		nv_putval(np,cp,0);
29548462SApril.Chin@Sun.COM 		free((void*)cp);
29558462SApril.Chin@Sun.COM 		return(1);
29568462SApril.Chin@Sun.COM 	}
29578462SApril.Chin@Sun.COM 	shp->prev_table = shp->last_table;
29588462SApril.Chin@Sun.COM 	shp->prev_root = shp->last_root;
29598462SApril.Chin@Sun.COM 	shp->last_table = last_table;
29608462SApril.Chin@Sun.COM 	shp->last_root = last_root;
29618462SApril.Chin@Sun.COM 	nv_clone(nr,np,(flags&NV_MOVE)|NV_COMVAR);
29628462SApril.Chin@Sun.COM 	if(flags&NV_MOVE)
29638462SApril.Chin@Sun.COM 		nv_delete(nr,(Dt_t*)0,NV_NOFREE);
29648462SApril.Chin@Sun.COM 	return(1);
29654887Schin }
29664887Schin 
29674887Schin /*
29684887Schin  * Create a reference node from <np> to $np in dictionary <hp>
29694887Schin  */
29704887Schin void nv_setref(register Namval_t *np, Dt_t *hp, int flags)
29714887Schin {
29728462SApril.Chin@Sun.COM 	Shell_t		*shp = &sh;
29738462SApril.Chin@Sun.COM 	register Namval_t *nq, *nr=0;
2974*10898Sroland.mainz@nrubsig.org 	register char	*ep,*cp;
2975*10898Sroland.mainz@nrubsig.org 	Dt_t		*root = shp->last_root;
2976*10898Sroland.mainz@nrubsig.org 	Namarr_t	*ap;
29774887Schin 	if(nv_isref(np))
29784887Schin 		return;
29794887Schin 	if(nv_isarray(np))
29804887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
29814887Schin 	if(!(cp=nv_getval(np)))
29828462SApril.Chin@Sun.COM 	{
29838462SApril.Chin@Sun.COM 		nv_unset(np);
29848462SApril.Chin@Sun.COM 		nv_onattr(np,NV_REF);
29858462SApril.Chin@Sun.COM 		return;
29868462SApril.Chin@Sun.COM 	}
29878462SApril.Chin@Sun.COM 	if((ep = lastdot(cp,0)) && nv_isattr(np,NV_MINIMAL))
29884887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
29894887Schin 	if(!hp)
29908462SApril.Chin@Sun.COM 		hp = shp->var_tree;
29918462SApril.Chin@Sun.COM 	if(!(nr = nq = nv_open(cp, hp, flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
2992*10898Sroland.mainz@nrubsig.org 		hp = shp->last_root==shp->var_tree?shp->var_tree:shp->var_base;
29938462SApril.Chin@Sun.COM 	else if(shp->last_root)
29948462SApril.Chin@Sun.COM 		hp = shp->last_root;
29958462SApril.Chin@Sun.COM 	if(nq && ep && nv_isarray(nq) && !nv_getsub(nq))
29968462SApril.Chin@Sun.COM 		nv_endsubscript(nq,ep-1,NV_ADD);
29978462SApril.Chin@Sun.COM 	if(!nr)
2998*10898Sroland.mainz@nrubsig.org 	{
29998462SApril.Chin@Sun.COM 		nr= nq = nv_open(cp, hp, flags);
3000*10898Sroland.mainz@nrubsig.org 		hp = shp->last_root;
3001*10898Sroland.mainz@nrubsig.org 	}
3002*10898Sroland.mainz@nrubsig.org 	if(shp->last_root == shp->var_tree && root!=shp->var_tree)
3003*10898Sroland.mainz@nrubsig.org 	{
3004*10898Sroland.mainz@nrubsig.org 		_nv_unset(np,NV_RDONLY);
3005*10898Sroland.mainz@nrubsig.org 		nv_onattr(np,NV_REF);
3006*10898Sroland.mainz@nrubsig.org 		errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np));
3007*10898Sroland.mainz@nrubsig.org 	}
30084887Schin 	if(nr==np)
30094887Schin 	{
30108462SApril.Chin@Sun.COM 		if(shp->namespace && nv_dict(shp->namespace)==hp)
30114887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
30124887Schin 		/* bind to earlier scope, or add to global scope */
30134887Schin 		if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np)
30144887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
30154887Schin 	}
3016*10898Sroland.mainz@nrubsig.org 	if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN)))
3017*10898Sroland.mainz@nrubsig.org 		ep =  nv_getsub(nq);
30184887Schin 	if(ep)
30194887Schin 	{
30204887Schin 		/* cause subscript evaluation and return result */
30218462SApril.Chin@Sun.COM 		if(nv_isarray(nq))
30228462SApril.Chin@Sun.COM 			ep = nv_getsub(nq);
30238462SApril.Chin@Sun.COM 		else
30248462SApril.Chin@Sun.COM 		{
30258462SApril.Chin@Sun.COM 			ep[strlen(ep)-1] = 0;
30268462SApril.Chin@Sun.COM 			nv_putsub(nr, ep, 0);
30278462SApril.Chin@Sun.COM 			ep[strlen(ep)-1] = ']';
30288462SApril.Chin@Sun.COM 			if(nq = nv_opensub(nr))
30298462SApril.Chin@Sun.COM 				ep = 0;
30308462SApril.Chin@Sun.COM 			else
30318462SApril.Chin@Sun.COM 				nq = nr;
30328462SApril.Chin@Sun.COM 		}
30334887Schin 	}
30344887Schin 	nv_unset(np);
30358462SApril.Chin@Sun.COM 	nv_delete(np,(Dt_t*)0,0);
30364887Schin 	np->nvalue.nrp = newof(0,struct Namref,1,0);
30374887Schin 	np->nvalue.nrp->np = nq;
30384887Schin 	np->nvalue.nrp->root = hp;
30394887Schin 	if(ep)
30404887Schin 		np->nvalue.nrp->sub = strdup(ep);
30418462SApril.Chin@Sun.COM 	np->nvalue.nrp->table = shp->last_table;
30424887Schin 	nv_onattr(np,NV_REF|NV_NOFREE);
30434887Schin }
30444887Schin 
30454887Schin /*
30464887Schin  * get the scope corresponding to <index>
30474887Schin  * whence uses the same values as lseeek()
30484887Schin  */
30494887Schin Shscope_t *sh_getscope(int index, int whence)
30504887Schin {
30514887Schin 	register struct sh_scoped *sp, *topmost;
30524887Schin 	if(whence==SEEK_CUR)
30534887Schin 		sp = &sh.st;
30544887Schin 	else
30554887Schin 	{
30564887Schin 		if ((struct sh_scoped*)sh.topscope != sh.st.self)
30574887Schin 			topmost = (struct sh_scoped*)sh.topscope;
30584887Schin 		else
30594887Schin 			topmost = &(sh.st);
30604887Schin 		sp = topmost;
30614887Schin 		if(whence==SEEK_SET)
30624887Schin 		{
30634887Schin 			int n =0;
30644887Schin 			while(sp = sp->prevst)
30654887Schin 				n++;
30664887Schin 			index = n - index;
30674887Schin 			sp = topmost;
30684887Schin 		}
30694887Schin 	}
30704887Schin 	if(index < 0)
30714887Schin 		return((Shscope_t*)0);
30724887Schin 	while(index-- && (sp = sp->prevst));
30734887Schin 	return((Shscope_t*)sp);
30744887Schin }
30754887Schin 
30764887Schin /*
30774887Schin  * make <scoped> the top scope and return previous scope
30784887Schin  */
30794887Schin Shscope_t *sh_setscope(Shscope_t *scope)
30804887Schin {
30814887Schin 	Shscope_t *old = (Shscope_t*)sh.st.self;
30824887Schin 	*sh.st.self = sh.st;
30834887Schin 	sh.st = *((struct sh_scoped*)scope);
30844887Schin 	sh.var_tree = scope->var_tree;
30858462SApril.Chin@Sun.COM 	SH_PATHNAMENOD->nvalue.cp = sh.st.filename;
30868462SApril.Chin@Sun.COM 	SH_FUNNAMENOD->nvalue.cp = sh.st.funname;
30874887Schin 	return(old);
30884887Schin }
30894887Schin 
30908462SApril.Chin@Sun.COM void sh_unscope(Shell_t *shp)
30914887Schin {
30928462SApril.Chin@Sun.COM 	register Dt_t *root = shp->var_tree;
30934887Schin 	register Dt_t *dp = dtview(root,(Dt_t*)0);
30948462SApril.Chin@Sun.COM 	table_unset(shp,root,NV_RDONLY|NV_NOSCOPE,dp);
30958462SApril.Chin@Sun.COM 	if(shp->st.real_fun  && dp==shp->st.real_fun->sdict)
30968462SApril.Chin@Sun.COM 	{
30978462SApril.Chin@Sun.COM 		dp = dtview(dp,(Dt_t*)0);
30988462SApril.Chin@Sun.COM 		shp->st.real_fun->sdict->view = dp;
30998462SApril.Chin@Sun.COM 	}
31008462SApril.Chin@Sun.COM 	shp->var_tree=dp;
31014887Schin 	dtclose(root);
31024887Schin }
31034887Schin 
31044887Schin /*
31054887Schin  * The inverse of creating a reference node
31064887Schin  */
31074887Schin void nv_unref(register Namval_t *np)
31084887Schin {
31094887Schin 	Namval_t *nq;
31104887Schin 	if(!nv_isref(np))
31114887Schin 		return;
3112*10898Sroland.mainz@nrubsig.org 	nv_offattr(np,NV_NOFREE|NV_REF);
3113*10898Sroland.mainz@nrubsig.org 	if(!np->nvalue.nrp)
3114*10898Sroland.mainz@nrubsig.org 		return;
31154887Schin 	nq = nv_refnode(np);
31164887Schin 	free((void*)np->nvalue.nrp);
31174887Schin 	np->nvalue.cp = strdup(nv_name(nq));
31184887Schin #if SHOPT_OPTIMIZE
31194887Schin 	{
31204887Schin 		Namfun_t *fp;
31214887Schin 		for(fp=nq->nvfun; fp; fp = fp->next)
31224887Schin 		{
31234887Schin 			if(fp->disc== &optimize_disc)
31244887Schin 			{
31254887Schin 				optimize_clear(nq,fp);
31264887Schin 				return;
31274887Schin 			}
31284887Schin 		}
31294887Schin 	}
31304887Schin #endif
31314887Schin }
31324887Schin 
31334887Schin /*
31344887Schin  * These following are for binary compatibility with the old hash library
31354887Schin  * They will be removed someday
31364887Schin  */
31374887Schin 
31384887Schin #if defined(__IMPORT__) && defined(__EXPORT__)
31394887Schin #   define extern __EXPORT__
31404887Schin #endif
31414887Schin 
31424887Schin #undef	hashscope
31434887Schin 
31444887Schin extern Dt_t *hashscope(Dt_t *root)
31454887Schin {
31464887Schin 	return(dtvnext(root));
31474887Schin }
31484887Schin 
31494887Schin #undef	hashfree
31504887Schin 
31514887Schin extern Dt_t	*hashfree(Dt_t *root)
31524887Schin {
31534887Schin 	Dt_t *dp = dtvnext(root);
31544887Schin 	dtclose(root);
31554887Schin 	return(dp);
31564887Schin }
31574887Schin 
31584887Schin #undef	hashname
31594887Schin 
31604887Schin extern char	*hashname(void *obj)
31614887Schin {
31624887Schin 	Namval_t *np = (Namval_t*)obj;
31634887Schin 	return(np->nvname);
31644887Schin }
31654887Schin 
31664887Schin #undef	hashlook
31674887Schin 
31684887Schin extern void *hashlook(Dt_t *root, const char *name, int mode,int size)
31694887Schin {
31704887Schin 	NOT_USED(size);
31714887Schin 	return((void*)nv_search(name,root,mode));
31724887Schin }
31734887Schin 
31744887Schin char *nv_name(register Namval_t *np)
31754887Schin {
31764887Schin 	register Namval_t *table;
31774887Schin 	register Namfun_t *fp;
31784887Schin 	char *cp;
31794887Schin 	if(is_abuiltin(np) || is_afunction(np))
31804887Schin 		return(np->nvname);
31818462SApril.Chin@Sun.COM 	if(!nv_isattr(np,NV_MINIMAL|NV_EXPORT) && np->nvenv)
31828462SApril.Chin@Sun.COM 	{
31838462SApril.Chin@Sun.COM 		Namval_t *nq= sh.last_table, *mp= (Namval_t*)np->nvenv;
31848462SApril.Chin@Sun.COM 		if(np==sh.last_table)
31858462SApril.Chin@Sun.COM 			sh.last_table = 0;
31868462SApril.Chin@Sun.COM 		if(nv_isarray(mp))
31878462SApril.Chin@Sun.COM 			sfprintf(sh.strbuf,"%s[%s]",nv_name(mp),np->nvname);
31888462SApril.Chin@Sun.COM 		else
31898462SApril.Chin@Sun.COM 			sfprintf(sh.strbuf,"%s.%s",nv_name(mp),np->nvname);
31908462SApril.Chin@Sun.COM 		sh.last_table = nq;
31918462SApril.Chin@Sun.COM 		return(sfstruse(sh.strbuf));
31928462SApril.Chin@Sun.COM 	}
31934887Schin 	if(nv_istable(np))
31944887Schin #if 1
31954887Schin 		sh.last_table = nv_parent(np);
31964887Schin #else
31974887Schin 		sh.last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0);
31984887Schin #endif
31994887Schin 	else if(!nv_isref(np))
32004887Schin 	{
32014887Schin 		for(fp= np->nvfun ; fp; fp=fp->next)
32024887Schin 		if(fp->disc && fp->disc->namef)
32034887Schin 		{
32044887Schin 			if(np==sh.last_table)
32054887Schin 				sh.last_table = 0;
32064887Schin 			return((*fp->disc->namef)(np,fp));
32074887Schin 		}
32084887Schin 	}
32094887Schin 	if(!(table=sh.last_table) || *np->nvname=='.' || table==sh.namespace || np==table)
32104887Schin 		return(np->nvname);
32114887Schin 	cp = nv_name(table);
32124887Schin 	sfprintf(sh.strbuf,"%s.%s",cp,np->nvname);
32134887Schin 	return(sfstruse(sh.strbuf));
32144887Schin }
32154887Schin 
32164887Schin Namval_t *nv_lastdict(void)
32174887Schin {
32184887Schin 	return(sh.last_table);
32194887Schin }
32204887Schin 
32214887Schin #undef nv_context
32224887Schin /*
32234887Schin  * returns the data context for a builtin
32244887Schin  */
32254887Schin void *nv_context(Namval_t *np)
32264887Schin {
32274887Schin 	return((void*)np->nvfun);
32284887Schin }
32294887Schin 
32304887Schin #define DISABLE /* proto workaround */
32314887Schin 
32324887Schin int nv_isnull DISABLE (register Namval_t *np)
32334887Schin {
32344887Schin 	return(nv_isnull(np));
32354887Schin }
32364887Schin 
32374887Schin #undef nv_setsize
32384887Schin int nv_setsize(register Namval_t *np, int size)
32394887Schin {
32404887Schin 	int oldsize = nv_size(np);
32414887Schin 	if(size>=0)
32424887Schin 		np->nvsize = size;
32434887Schin 	return(oldsize);
32444887Schin }
32458462SApril.Chin@Sun.COM 
32468462SApril.Chin@Sun.COM Shell_t	*nv_shell(Namval_t *np)
32478462SApril.Chin@Sun.COM {
32488462SApril.Chin@Sun.COM 	Namfun_t *fp;
32498462SApril.Chin@Sun.COM 	for(fp=np->nvfun;fp;fp=fp->next)
32508462SApril.Chin@Sun.COM 	{
32518462SApril.Chin@Sun.COM 		if(!fp->disc)
32528462SApril.Chin@Sun.COM 			return((Shell_t*)fp->last);
32538462SApril.Chin@Sun.COM 	}
32548462SApril.Chin@Sun.COM 	return(0);
32558462SApril.Chin@Sun.COM }
32568462SApril.Chin@Sun.COM 
32578462SApril.Chin@Sun.COM #undef nv_unset
32588462SApril.Chin@Sun.COM 
32598462SApril.Chin@Sun.COM void	nv_unset(register Namval_t *np)
32608462SApril.Chin@Sun.COM {
32618462SApril.Chin@Sun.COM 	_nv_unset(np,0);
32628462SApril.Chin@Sun.COM 	return;
32638462SApril.Chin@Sun.COM }
3264