xref: /titanic_50/usr/src/lib/libshell/common/sh/name.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * AT&T Labs
23da2e3ebdSchin  *
24da2e3ebdSchin  */
25da2e3ebdSchin 
26da2e3ebdSchin #define putenv	___putenv
27da2e3ebdSchin 
28da2e3ebdSchin #include	"defs.h"
29da2e3ebdSchin #include	"variables.h"
30da2e3ebdSchin #include	"path.h"
31da2e3ebdSchin #include	"lexstates.h"
32da2e3ebdSchin #include	"timeout.h"
33da2e3ebdSchin #include	"FEATURE/externs"
34da2e3ebdSchin #include	"streval.h"
35da2e3ebdSchin 
367c2fbfb3SApril Chin #define NVCACHE		8	/* must be a power of 2 */
377c2fbfb3SApril Chin #define Empty	((char*)(e_sptbnl+3))
38da2e3ebdSchin static char	*savesub = 0;
39da2e3ebdSchin 
40da2e3ebdSchin #if !_lib_pathnative && _lib_uwin_path
41da2e3ebdSchin 
42da2e3ebdSchin #define _lib_pathnative		1
43da2e3ebdSchin 
44da2e3ebdSchin extern int	uwin_path(const char*, char*, int);
45da2e3ebdSchin 
46da2e3ebdSchin size_t
pathnative(const char * path,char * buf,size_t siz)47da2e3ebdSchin pathnative(const char* path, char* buf, size_t siz)
48da2e3ebdSchin {
49da2e3ebdSchin 	return uwin_path(path, buf, siz);
50da2e3ebdSchin }
51da2e3ebdSchin 
52da2e3ebdSchin #endif /* _lib_pathnative */
53da2e3ebdSchin 
54da2e3ebdSchin static void	attstore(Namval_t*,void*);
55da2e3ebdSchin #ifndef _ENV_H
56da2e3ebdSchin     static void	pushnam(Namval_t*,void*);
57da2e3ebdSchin     static char	*staknam(Namval_t*, char*);
58da2e3ebdSchin #endif
597c2fbfb3SApril Chin static void	ltou(char*);
607c2fbfb3SApril Chin static void	utol(char*);
61da2e3ebdSchin static void	rightjust(char*, int, int);
627c2fbfb3SApril Chin static char	*lastdot(char*, int);
63da2e3ebdSchin 
64da2e3ebdSchin struct adata
65da2e3ebdSchin {
667c2fbfb3SApril Chin 	Shell_t		*sh;
677c2fbfb3SApril Chin 	Namval_t	*tp;
68da2e3ebdSchin 	char		**argnam;
69da2e3ebdSchin 	int		attsize;
70da2e3ebdSchin 	char		*attval;
71da2e3ebdSchin };
72da2e3ebdSchin 
737c2fbfb3SApril Chin #if SHOPT_TYPEDEF
747c2fbfb3SApril Chin     struct sh_type
757c2fbfb3SApril Chin     {
767c2fbfb3SApril Chin 	void		*previous;
777c2fbfb3SApril Chin 	Namval_t	**nodes;
787c2fbfb3SApril Chin 	Namval_t	*rp;
797c2fbfb3SApril Chin 	short		numnodes;
807c2fbfb3SApril Chin 	short		maxnodes;
817c2fbfb3SApril Chin     };
827c2fbfb3SApril Chin #endif /*SHOPT_TYPEDEF */
837c2fbfb3SApril Chin 
847c2fbfb3SApril Chin #if NVCACHE
857c2fbfb3SApril Chin     struct Namcache
867c2fbfb3SApril Chin     {
877c2fbfb3SApril Chin 	struct Cache_entry
887c2fbfb3SApril Chin 	{
897c2fbfb3SApril Chin 		Dt_t		*root;
9034f9b3eeSRoland Mainz 		Dt_t		*last_root;
917c2fbfb3SApril Chin 		char		*name;
927c2fbfb3SApril Chin 		Namval_t	*np;
937c2fbfb3SApril Chin 		Namval_t	*last_table;
947c2fbfb3SApril Chin 		int		flags;
957c2fbfb3SApril Chin 		short		size;
967c2fbfb3SApril Chin 		short		len;
977c2fbfb3SApril Chin 	} entries[NVCACHE];
987c2fbfb3SApril Chin 	short		index;
997c2fbfb3SApril Chin 	short		ok;
1007c2fbfb3SApril Chin     };
1017c2fbfb3SApril Chin     static struct Namcache nvcache;
1027c2fbfb3SApril Chin #endif
1037c2fbfb3SApril Chin 
104da2e3ebdSchin char		nv_local = 0;
105da2e3ebdSchin #ifndef _ENV_H
106da2e3ebdSchin static void(*nullscan)(Namval_t*,void*);
107da2e3ebdSchin #endif
108da2e3ebdSchin 
109da2e3ebdSchin #if ( SFIO_VERSION  <= 20010201L )
110da2e3ebdSchin #   define _data        data
111da2e3ebdSchin #endif
112da2e3ebdSchin 
113da2e3ebdSchin #if !SHOPT_MULTIBYTE
114da2e3ebdSchin #   define mbchar(p)       (*(unsigned char*)p++)
115da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
116da2e3ebdSchin 
117da2e3ebdSchin /* ========	name value pair routines	======== */
118da2e3ebdSchin 
119da2e3ebdSchin #include	"shnodes.h"
120da2e3ebdSchin #include	"builtins.h"
121da2e3ebdSchin 
getbuf(size_t len)122da2e3ebdSchin static char *getbuf(size_t len)
123da2e3ebdSchin {
124da2e3ebdSchin 	static char *buf;
125da2e3ebdSchin 	static size_t buflen;
126da2e3ebdSchin 	if(buflen < len)
127da2e3ebdSchin 	{
128da2e3ebdSchin 		if(buflen==0)
129da2e3ebdSchin 			buf = (char*)malloc(len);
130da2e3ebdSchin 		else
131da2e3ebdSchin 			buf = (char*)realloc(buf,len);
132da2e3ebdSchin 		buflen = len;
133da2e3ebdSchin 	}
134da2e3ebdSchin 	return(buf);
135da2e3ebdSchin }
136da2e3ebdSchin 
137da2e3ebdSchin #ifdef _ENV_H
sh_envput(Env_t * ep,Namval_t * np)138da2e3ebdSchin void sh_envput(Env_t* ep,Namval_t *np)
139da2e3ebdSchin {
140da2e3ebdSchin 	int offset = staktell();
141da2e3ebdSchin 	Namarr_t *ap = nv_arrayptr(np);
142da2e3ebdSchin 	char *val;
143da2e3ebdSchin 	if(ap)
144da2e3ebdSchin 	{
145da2e3ebdSchin 		if(ap->nelem&ARRAY_UNDEF)
146da2e3ebdSchin 			nv_putsub(np,"0",0L);
147da2e3ebdSchin 		else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
148da2e3ebdSchin 			return;
149da2e3ebdSchin 	}
150da2e3ebdSchin 	if(!(val = nv_getval(np)))
151da2e3ebdSchin 		return;
152da2e3ebdSchin 	stakputs(nv_name(np));
153da2e3ebdSchin 	stakputc('=');
154da2e3ebdSchin 	stakputs(val);
155da2e3ebdSchin 	stakseek(offset);
156da2e3ebdSchin 	env_add(ep,stakptr(offset),ENV_STRDUP);
157da2e3ebdSchin }
158da2e3ebdSchin #endif
159da2e3ebdSchin 
160da2e3ebdSchin /*
161da2e3ebdSchin  * output variable name in format for re-input
162da2e3ebdSchin  */
nv_outname(Sfio_t * out,char * name,int len)163da2e3ebdSchin void nv_outname(Sfio_t *out, char *name, int len)
164da2e3ebdSchin {
165da2e3ebdSchin 	const char *cp=name, *sp;
166da2e3ebdSchin 	int c, offset = staktell();
167da2e3ebdSchin 	while(sp= strchr(cp,'['))
168da2e3ebdSchin 	{
169da2e3ebdSchin 		if(len>0 && cp+len <= sp)
170da2e3ebdSchin 			break;
171da2e3ebdSchin 		sfwrite(out,cp,++sp-cp);
172da2e3ebdSchin 		stakseek(offset);
1737c2fbfb3SApril Chin 		while(c= *sp++)
174da2e3ebdSchin 		{
175da2e3ebdSchin 			if(c==']')
176da2e3ebdSchin 				break;
177da2e3ebdSchin 			else if(c=='\\')
178da2e3ebdSchin 			{
179da2e3ebdSchin 				if(*sp=='[' || *sp==']' || *sp=='\\')
180da2e3ebdSchin 					c = *sp++;
181da2e3ebdSchin 			}
182da2e3ebdSchin 			stakputc(c);
183da2e3ebdSchin 		}
184da2e3ebdSchin 		stakputc(0);
185da2e3ebdSchin 		sfputr(out,sh_fmtq(stakptr(offset)),-1);
186da2e3ebdSchin 		if(len>0)
187da2e3ebdSchin 		{
188da2e3ebdSchin 			sfputc(out,']');
189da2e3ebdSchin 			return;
190da2e3ebdSchin 		}
1917c2fbfb3SApril Chin 		cp = sp-1;
192da2e3ebdSchin 	}
193da2e3ebdSchin 	if(*cp)
194da2e3ebdSchin 	{
195da2e3ebdSchin 		if(len>0)
196da2e3ebdSchin 			sfwrite(out,cp,len);
197da2e3ebdSchin 		else
198da2e3ebdSchin 			sfputr(out,cp,-1);
199da2e3ebdSchin 	}
200da2e3ebdSchin 	stakseek(offset);
201da2e3ebdSchin }
202da2e3ebdSchin 
2037c2fbfb3SApril Chin #if SHOPT_TYPEDEF
nv_addnode(Namval_t * np,int remove)2047c2fbfb3SApril Chin Namval_t *nv_addnode(Namval_t* np, int remove)
2057c2fbfb3SApril Chin {
2067c2fbfb3SApril Chin 	register struct sh_type	*sp = (struct sh_type*)sh.mktype;
2077c2fbfb3SApril Chin 	register int		i;
2087c2fbfb3SApril Chin 	register char		*name=0;
2097c2fbfb3SApril Chin 	if(sp->numnodes==0 && !nv_isnull(np) && sh.last_table)
2107c2fbfb3SApril Chin 	{
2117c2fbfb3SApril Chin 		/* could be an redefine */
2127c2fbfb3SApril Chin 		Dt_t *root = nv_dict(sh.last_table);
2137c2fbfb3SApril Chin 		sp->rp = np;
2147c2fbfb3SApril Chin 		nv_delete(np,root,NV_NOFREE);
2157c2fbfb3SApril Chin 		np = nv_search(sp->rp->nvname,root,NV_ADD);
2167c2fbfb3SApril Chin 	}
2177c2fbfb3SApril Chin 	if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1))
2187c2fbfb3SApril Chin 	{
2197c2fbfb3SApril Chin 		name = (sp->nodes[0])->nvname;
2207c2fbfb3SApril Chin 		i = strlen(name);
2217c2fbfb3SApril Chin 		if(memcmp(np->nvname,name,i))
2227c2fbfb3SApril Chin 			return(np);
2237c2fbfb3SApril Chin 	}
2247c2fbfb3SApril Chin 	if(sp->rp && sp->numnodes)
2257c2fbfb3SApril Chin 	{
2267c2fbfb3SApril Chin 		/* check for a redefine */
2277c2fbfb3SApril Chin 		if(name && np->nvname[i]=='.' && np->nvname[i+1]=='_' && np->nvname[i+2]==0)
2287c2fbfb3SApril Chin 			sp->rp = 0;
2297c2fbfb3SApril Chin 		else
2307c2fbfb3SApril Chin 		{
2317c2fbfb3SApril Chin 			Dt_t *root = nv_dict(sh.last_table);
2327c2fbfb3SApril Chin 			nv_delete(sp->nodes[0],root,NV_NOFREE);
2337c2fbfb3SApril Chin 			dtinsert(root,sp->rp);
2347c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_exit(1),e_redef,sp->nodes[0]->nvname);
2357c2fbfb3SApril Chin 		}
2367c2fbfb3SApril Chin 	}
2377c2fbfb3SApril Chin 	for(i=0; i < sp->numnodes; i++)
2387c2fbfb3SApril Chin 	{
2397c2fbfb3SApril Chin 		if(np == sp->nodes[i])
2407c2fbfb3SApril Chin 		{
2417c2fbfb3SApril Chin 			if(remove)
2427c2fbfb3SApril Chin 			{
2437c2fbfb3SApril Chin 				while(++i < sp->numnodes)
2447c2fbfb3SApril Chin 					sp->nodes[i-1] = sp->nodes[i];
2457c2fbfb3SApril Chin 				sp->numnodes--;
2467c2fbfb3SApril Chin 			}
2477c2fbfb3SApril Chin 			return(np);
2487c2fbfb3SApril Chin 		}
2497c2fbfb3SApril Chin 	}
2507c2fbfb3SApril Chin 	if(remove)
2517c2fbfb3SApril Chin 		return(np);
2527c2fbfb3SApril Chin 	if(sp->numnodes==sp->maxnodes)
2537c2fbfb3SApril Chin 	{
2547c2fbfb3SApril Chin 		sp->maxnodes += 20;
2557c2fbfb3SApril Chin 		sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes);
2567c2fbfb3SApril Chin 	}
2577c2fbfb3SApril Chin 	sp->nodes[sp->numnodes++] = np;
2587c2fbfb3SApril Chin 	return(np);
2597c2fbfb3SApril Chin }
2607c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
2617c2fbfb3SApril Chin 
2627c2fbfb3SApril Chin /*
2637c2fbfb3SApril Chin  * given a list of assignments, determine <name> is on the list
2647c2fbfb3SApril Chin    returns a pointer to the argnod on the list or NULL
2657c2fbfb3SApril Chin  */
nv_onlist(struct argnod * arg,const char * name)2667c2fbfb3SApril Chin struct argnod *nv_onlist(struct argnod *arg, const char *name)
2677c2fbfb3SApril Chin {
2687c2fbfb3SApril Chin 	char *cp;
2697c2fbfb3SApril Chin 	int len = strlen(name);
2707c2fbfb3SApril Chin 	for(;arg; arg=arg->argnxt.ap)
2717c2fbfb3SApril Chin 	{
2727c2fbfb3SApril Chin 		if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
2737c2fbfb3SApril Chin 			cp = ((struct fornod*)arg->argchn.ap)->fornam;
2747c2fbfb3SApril Chin 		else
2757c2fbfb3SApril Chin 			cp = arg->argval;
2767c2fbfb3SApril Chin 		if(memcmp(cp,name,len)==0 && (cp[len]==0 || cp[len]=='='))
2777c2fbfb3SApril Chin 			return(arg);
2787c2fbfb3SApril Chin 	}
2797c2fbfb3SApril Chin 	return(0);
2807c2fbfb3SApril Chin }
2817c2fbfb3SApril Chin 
282da2e3ebdSchin /*
283da2e3ebdSchin  * Perform parameter assignment for a linked list of parameters
284da2e3ebdSchin  * <flags> contains attributes for the parameters
285da2e3ebdSchin  */
nv_setlist(register struct argnod * arg,register int flags,Namval_t * typ)28634f9b3eeSRoland Mainz void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
287da2e3ebdSchin {
2887c2fbfb3SApril Chin 	Shell_t		*shp = &sh;
289da2e3ebdSchin 	register char	*cp;
2907c2fbfb3SApril Chin 	register Namval_t *np, *mp;
2917c2fbfb3SApril Chin 	char		*trap=shp->st.trap[SH_DEBUGTRAP];
2927c2fbfb3SApril Chin 	char		*prefix = shp->prefix;
293da2e3ebdSchin 	int		traceon = (sh_isoption(SH_XTRACE)!=0);
294da2e3ebdSchin 	int		array = (flags&(NV_ARRAY|NV_IARRAY));
2957c2fbfb3SApril Chin 	Namarr_t	*ap;
2967c2fbfb3SApril Chin 	Namval_t	node;
2977c2fbfb3SApril Chin 	struct Namref	nr;
2987c2fbfb3SApril Chin #if SHOPT_TYPEDEF
2997c2fbfb3SApril Chin 	int		maketype = flags&NV_TYPE;
3007c2fbfb3SApril Chin 	struct sh_type	shtp;
3017c2fbfb3SApril Chin 	if(maketype)
3027c2fbfb3SApril Chin 	{
3037c2fbfb3SApril Chin 		shtp.previous = shp->mktype;
3047c2fbfb3SApril Chin 		shp->mktype=(void*)&shtp;
3057c2fbfb3SApril Chin 		shtp.numnodes=0;
3067c2fbfb3SApril Chin 		shtp.maxnodes = 20;
3077c2fbfb3SApril Chin 		shtp.rp = 0;
3087c2fbfb3SApril Chin 		shtp.nodes =(Namval_t**)malloc(shtp.maxnodes*sizeof(Namval_t*));
3097c2fbfb3SApril Chin 	}
3107c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF*/
3117c2fbfb3SApril Chin 	flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY);
312da2e3ebdSchin 	if(sh_isoption(SH_ALLEXPORT))
313da2e3ebdSchin 		flags |= NV_EXPORT;
3147c2fbfb3SApril Chin 	if(shp->prefix)
315da2e3ebdSchin 	{
316da2e3ebdSchin 		flags &= ~(NV_IDENT|NV_EXPORT);
317da2e3ebdSchin 		flags |= NV_VARNAME;
318da2e3ebdSchin 	}
319da2e3ebdSchin 	for(;arg; arg=arg->argnxt.ap)
320da2e3ebdSchin 	{
3217c2fbfb3SApril Chin 		shp->used_pos = 0;
322da2e3ebdSchin 		if(arg->argflag&ARG_MAC)
3237c2fbfb3SApril Chin 		{
3247c2fbfb3SApril Chin 			shp->prefix = 0;
3257c2fbfb3SApril Chin 			cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1);
3267c2fbfb3SApril Chin 			shp->prefix = prefix;
3277c2fbfb3SApril Chin 		}
328da2e3ebdSchin 		else
329da2e3ebdSchin 		{
330da2e3ebdSchin 			stakseek(0);
3317c2fbfb3SApril Chin 			if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
332da2e3ebdSchin 			{
333da2e3ebdSchin 				int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
3347c2fbfb3SApril Chin 				int sub=0;
335da2e3ebdSchin 				struct fornod *fp=(struct fornod*)arg->argchn.ap;
336da2e3ebdSchin 				register Shnode_t *tp=fp->fortre;
3377c2fbfb3SApril Chin 				flag |= (flags&(NV_NOSCOPE|NV_STATIC));
338da2e3ebdSchin 				if(arg->argflag&ARG_QUOTED)
3397c2fbfb3SApril Chin 					cp = sh_mactrim(shp,fp->fornam,-1);
340da2e3ebdSchin 				else
341da2e3ebdSchin 					cp = fp->fornam;
3427c2fbfb3SApril Chin 				error_info.line = fp->fortyp-shp->st.firstline;
34334f9b3eeSRoland Mainz 				if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[')
34434f9b3eeSRoland Mainz 					array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY;
3457c2fbfb3SApril Chin 				if(shp->fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET)
346da2e3ebdSchin 			                flag |= NV_NOSCOPE;
347da2e3ebdSchin 				if(prefix && tp->com.comset && *cp=='[')
348da2e3ebdSchin 				{
3497c2fbfb3SApril Chin 					shp->prefix = 0;
3507c2fbfb3SApril Chin 					np = nv_open(prefix,shp->var_tree,flag);
3517c2fbfb3SApril Chin 					shp->prefix = prefix;
352da2e3ebdSchin 					if(np)
353da2e3ebdSchin 					{
3547c2fbfb3SApril Chin 						if(nv_isvtree(np) && !nv_isarray(np))
355da2e3ebdSchin 						{
356da2e3ebdSchin 							stakputc('.');
357da2e3ebdSchin 							stakputs(cp);
358da2e3ebdSchin 							cp = stakfreeze(1);
359da2e3ebdSchin 						}
360da2e3ebdSchin 						nv_close(np);
361da2e3ebdSchin 					}
362da2e3ebdSchin 				}
3637c2fbfb3SApril Chin 				np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN);
36434f9b3eeSRoland Mainz 				if(typ && !array  && (nv_isnull(np) || nv_isarray(np)))
36534f9b3eeSRoland Mainz 					nv_settype(np,typ,0);
3667c2fbfb3SApril Chin 				if((flags&NV_STATIC) && !nv_isnull(np))
3677c2fbfb3SApril Chin #if SHOPT_TYPEDEF
3687c2fbfb3SApril Chin 					goto check_type;
3697c2fbfb3SApril Chin #else
3707c2fbfb3SApril Chin 					continue;
3717c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
37234f9b3eeSRoland Mainz 				if(array && (!(ap=nv_arrayptr(np)) || !ap->hdr.type))
373da2e3ebdSchin 				{
3747c2fbfb3SApril Chin 					if(!(arg->argflag&ARG_APPEND))
375da2e3ebdSchin 						nv_unset(np);
376da2e3ebdSchin 					if(array&NV_ARRAY)
377da2e3ebdSchin 					{
378da2e3ebdSchin 						nv_setarray(np,nv_associative);
379da2e3ebdSchin 					}
380da2e3ebdSchin 					else
381da2e3ebdSchin 					{
382da2e3ebdSchin 						nv_onattr(np,NV_ARRAY);
383da2e3ebdSchin 					}
38434f9b3eeSRoland Mainz 				}
38534f9b3eeSRoland Mainz 				if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg)
38634f9b3eeSRoland Mainz 				{
3877c2fbfb3SApril Chin #if SHOPT_TYPEDEF
3887c2fbfb3SApril Chin 						goto check_type;
3897c2fbfb3SApril Chin #else
3907c2fbfb3SApril Chin 						continue;
3917c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
392da2e3ebdSchin 				}
393da2e3ebdSchin 				/* check for array assignment */
394da2e3ebdSchin 				if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))
395da2e3ebdSchin 				{
396da2e3ebdSchin 					int argc;
3977c2fbfb3SApril Chin 					Dt_t	*last_root = shp->last_root;
3987c2fbfb3SApril Chin 					char **argv = sh_argbuild(shp,&argc,&tp->com,0);
3997c2fbfb3SApril Chin 					shp->last_root = last_root;
4007c2fbfb3SApril Chin #if SHOPT_TYPEDEF
4017c2fbfb3SApril Chin 					if(shp->mktype && shp->dot_depth==0 && np==((struct sh_type*)shp->mktype)->nodes[0])
4027c2fbfb3SApril Chin 					{
4037c2fbfb3SApril Chin 						shp->mktype = 0;
4047c2fbfb3SApril Chin 						errormsg(SH_DICT,ERROR_exit(1),"%s: not a known type name",argv[0]);
4057c2fbfb3SApril Chin 					}
4067c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
407da2e3ebdSchin 					if(!(arg->argflag&ARG_APPEND))
408da2e3ebdSchin 					{
4097c2fbfb3SApril Chin 						if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && (ap->nelem&ARRAY_MASK)))
410da2e3ebdSchin 							nv_unset(np);
411da2e3ebdSchin 					}
412da2e3ebdSchin 					nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv);
413da2e3ebdSchin 					if(traceon || trap)
414da2e3ebdSchin 					{
415da2e3ebdSchin 						int n = -1;
416da2e3ebdSchin 						char *name = nv_name(np);
417da2e3ebdSchin 						if(arg->argflag&ARG_APPEND)
418da2e3ebdSchin 							n = '+';
419da2e3ebdSchin 						if(trap)
4207c2fbfb3SApril Chin 							sh_debug(shp,trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN);
421da2e3ebdSchin 						if(traceon)
422da2e3ebdSchin 						{
423da2e3ebdSchin 							sh_trace(NIL(char**),0);
424da2e3ebdSchin 							sfputr(sfstderr,name,n);
425da2e3ebdSchin 							sfwrite(sfstderr,"=( ",3);
426da2e3ebdSchin 							while(cp= *argv++)
427da2e3ebdSchin 								sfputr(sfstderr,sh_fmtq(cp),' ');
428da2e3ebdSchin 							sfwrite(sfstderr,")\n",2);
429da2e3ebdSchin 						}
430da2e3ebdSchin 					}
4317c2fbfb3SApril Chin #if SHOPT_TYPEDEF
4327c2fbfb3SApril Chin 					goto check_type;
4337c2fbfb3SApril Chin #else
434da2e3ebdSchin 					continue;
4357c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
436da2e3ebdSchin 				}
4377c2fbfb3SApril Chin 				if((tp->tre.tretyp&COMMSK)==TFUN)
4387c2fbfb3SApril Chin 					goto skip;
439da2e3ebdSchin 				if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[')
440da2e3ebdSchin 				{
4417c2fbfb3SApril Chin 					if(tp->tre.tretyp!=TLST && !tp->com.comnamp && tp->com.comset && tp->com.comset->argval[0]==0 && tp->com.comset->argchn.ap)
4427c2fbfb3SApril Chin 					{
4437c2fbfb3SApril Chin 						if(prefix)
4447c2fbfb3SApril Chin 							cp = stakcopy(nv_name(np));
4457c2fbfb3SApril Chin 						shp->prefix = cp;
4467c2fbfb3SApril Chin 						if(tp->com.comset->argval[1]=='[')
4477c2fbfb3SApril Chin 						{
4487c2fbfb3SApril Chin 							if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0)))
4497c2fbfb3SApril Chin 								nv_unset(np);
4507c2fbfb3SApril Chin 							if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE))
4517c2fbfb3SApril Chin 								nv_setarray(np,nv_associative);
4527c2fbfb3SApril Chin 						}
45334f9b3eeSRoland Mainz 						nv_setlist(tp->com.comset,flags,0);
4547c2fbfb3SApril Chin 						shp->prefix = prefix;
4557c2fbfb3SApril Chin 						if(tp->com.comset->argval[1]!='[')
4567c2fbfb3SApril Chin 							 nv_setvtree(np);
4577c2fbfb3SApril Chin 						nv_close(np);
4587c2fbfb3SApril Chin #if SHOPT_TYPEDEF
4597c2fbfb3SApril Chin 						goto check_type;
4607c2fbfb3SApril Chin #else
4617c2fbfb3SApril Chin 						continue;
4627c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
4637c2fbfb3SApril Chin 					}
464da2e3ebdSchin 					if(*cp!='.' && *cp!='[' && strchr(cp,'['))
465da2e3ebdSchin 					{
466da2e3ebdSchin 						nv_close(np);
4677c2fbfb3SApril Chin 						np = nv_open(cp,shp->var_tree,flag);
468da2e3ebdSchin 					}
4697c2fbfb3SApril Chin 					if(arg->argflag&ARG_APPEND)
4707c2fbfb3SApril Chin 					{
4717c2fbfb3SApril Chin 						if(nv_isarray(np))
4727c2fbfb3SApril Chin 						{
4737c2fbfb3SApril Chin 							if((sub=nv_aimax(np)) < 0  && nv_arrayptr(np))
4747c2fbfb3SApril Chin 								errormsg(SH_DICT,ERROR_exit(1),e_badappend,nv_name(np));
4757c2fbfb3SApril Chin 							if(sub>=0)
4767c2fbfb3SApril Chin 								sub++;
4777c2fbfb3SApril Chin 						}
4787c2fbfb3SApril Chin 						if(!nv_isnull(np) && np->nvalue.cp!=Empty && !nv_isvtree(np))
4797c2fbfb3SApril Chin 							sub=1;
4807c2fbfb3SApril Chin 					}
4817c2fbfb3SApril Chin 					else if(np->nvalue.cp && np->nvalue.cp!=Empty && !nv_type(np))
4827c2fbfb3SApril Chin 					{
4837c2fbfb3SApril Chin 						_nv_unset(np,NV_EXPORT);
4847c2fbfb3SApril Chin 					}
485da2e3ebdSchin 				}
486da2e3ebdSchin 				else
487da2e3ebdSchin 				{
488da2e3ebdSchin 					if(!(arg->argflag&ARG_APPEND))
4897c2fbfb3SApril Chin 						_nv_unset(np,NV_EXPORT);
4907c2fbfb3SApril Chin 					if(!sh_isoption(SH_BASH) && !(array&NV_IARRAY) && !nv_isarray(np))
4917c2fbfb3SApril Chin 						nv_setarray(np,nv_associative);
492da2e3ebdSchin 				}
4937c2fbfb3SApril Chin 			skip:
4947c2fbfb3SApril Chin 				if(sub>0)
495da2e3ebdSchin 				{
4967c2fbfb3SApril Chin 					sfprintf(stkstd,"%s[%d]",prefix?nv_name(np):cp,sub);
4977c2fbfb3SApril Chin 					shp->prefix = stakfreeze(1);
4987c2fbfb3SApril Chin 					nv_putsub(np,(char*)0,ARRAY_ADD|ARRAY_FILL|sub);
499da2e3ebdSchin 				}
5007c2fbfb3SApril Chin 				else if(prefix)
5017c2fbfb3SApril Chin 					shp->prefix = stakcopy(nv_name(np));
502da2e3ebdSchin 				else
5037c2fbfb3SApril Chin 					shp->prefix = cp;
5047c2fbfb3SApril Chin 				shp->last_table = 0;
50534f9b3eeSRoland Mainz 				if(shp->prefix)
50634f9b3eeSRoland Mainz 				{
50734f9b3eeSRoland Mainz 					if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD))
50834f9b3eeSRoland Mainz 					{
50934f9b3eeSRoland Mainz 						sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1);
51034f9b3eeSRoland Mainz 						shp->prefix = stkfreeze(stkstd,1);
51134f9b3eeSRoland Mainz 					}
5127c2fbfb3SApril Chin 					memset(&nr,0,sizeof(nr));
5137c2fbfb3SApril Chin 					memcpy(&node,L_ARGNOD,sizeof(node));
5147c2fbfb3SApril Chin 					L_ARGNOD->nvalue.nrp = &nr;
5157c2fbfb3SApril Chin 					nr.np = np;
5167c2fbfb3SApril Chin 					nr.root = shp->last_root;
5177c2fbfb3SApril Chin 					nr.table = shp->last_table;
5187c2fbfb3SApril Chin 					L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
5197c2fbfb3SApril Chin 					L_ARGNOD->nvfun = 0;
52034f9b3eeSRoland Mainz 				}
521da2e3ebdSchin 				sh_exec(tp,sh_isstate(SH_ERREXIT));
5227c2fbfb3SApril Chin #if SHOPT_TYPEDEF
52334f9b3eeSRoland Mainz 				if(shp->prefix)
5247c2fbfb3SApril Chin #endif
5257c2fbfb3SApril Chin 				{
5267c2fbfb3SApril Chin 					L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
5277c2fbfb3SApril Chin 					L_ARGNOD->nvflag = node.nvflag;
5287c2fbfb3SApril Chin 					L_ARGNOD->nvfun = node.nvfun;
5297c2fbfb3SApril Chin 				}
5307c2fbfb3SApril Chin 				shp->prefix = prefix;
531da2e3ebdSchin 				if(nv_isarray(np) && (mp=nv_opensub(np)))
532da2e3ebdSchin 					np = mp;
5337c2fbfb3SApril Chin 				while(tp->tre.tretyp==TLST)
5347c2fbfb3SApril Chin 				{
5357c2fbfb3SApril Chin 					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]!='[')
5367c2fbfb3SApril Chin 						break;
5377c2fbfb3SApril Chin 					tp = tp->lst.lstrit;
5387c2fbfb3SApril Chin 
5397c2fbfb3SApril Chin 				}
54034f9b3eeSRoland Mainz 				if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='['))
541*3e14f97fSRoger A. Faulkner 				{
542da2e3ebdSchin 					nv_setvtree(np);
543*3e14f97fSRoger A. Faulkner 					if(tp->com.comarg || tp->com.comset)
544*3e14f97fSRoger A. Faulkner 						np->nvfun->dsize = 0;
545*3e14f97fSRoger A. Faulkner 				}
5467c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5477c2fbfb3SApril Chin 				goto check_type;
5487c2fbfb3SApril Chin #else
549da2e3ebdSchin 				continue;
5507c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
551da2e3ebdSchin 			}
552da2e3ebdSchin 			cp = arg->argval;
5537c2fbfb3SApril Chin 			mp = 0;
554da2e3ebdSchin 		}
5557c2fbfb3SApril Chin 		np = nv_open(cp,shp->var_tree,flags);
5567c2fbfb3SApril Chin 		if(!np->nvfun && (flags&NV_NOREF))
557da2e3ebdSchin 		{
5587c2fbfb3SApril Chin 			if(shp->used_pos)
559da2e3ebdSchin 				nv_onattr(np,NV_PARAM);
560da2e3ebdSchin 			else
561da2e3ebdSchin 				nv_offattr(np,NV_PARAM);
562da2e3ebdSchin 		}
563da2e3ebdSchin 		if(traceon || trap)
564da2e3ebdSchin 		{
565da2e3ebdSchin 			register char *sp=cp;
566da2e3ebdSchin 			char *name=nv_name(np);
567da2e3ebdSchin 			char *sub=0;
568da2e3ebdSchin 			int append = 0;
569da2e3ebdSchin 			if(nv_isarray(np))
570da2e3ebdSchin 				sub = savesub;
5717c2fbfb3SApril Chin 			if(cp=lastdot(sp,'='))
572da2e3ebdSchin 			{
573da2e3ebdSchin 				if(cp[-1]=='+')
574da2e3ebdSchin 					append = ARG_APPEND;
575da2e3ebdSchin 				cp++;
576da2e3ebdSchin 			}
577da2e3ebdSchin 			if(traceon)
578da2e3ebdSchin 			{
579da2e3ebdSchin 				sh_trace(NIL(char**),0);
580da2e3ebdSchin 				nv_outname(sfstderr,name,-1);
581da2e3ebdSchin 				if(sub)
582da2e3ebdSchin 					sfprintf(sfstderr,"[%s]",sh_fmtq(sub));
583da2e3ebdSchin 				if(cp)
584da2e3ebdSchin 				{
585da2e3ebdSchin 					if(append)
586da2e3ebdSchin 						sfputc(sfstderr,'+');
587da2e3ebdSchin 					sfprintf(sfstderr,"=%s\n",sh_fmtq(cp));
588da2e3ebdSchin 				}
589da2e3ebdSchin 			}
590da2e3ebdSchin 			if(trap)
591da2e3ebdSchin 			{
592da2e3ebdSchin 					char *av[2];
593da2e3ebdSchin 					av[0] = cp;
594da2e3ebdSchin 					av[1] = 0;
5957c2fbfb3SApril Chin 					sh_debug(shp,trap,name,sub,av,append);
596da2e3ebdSchin 			}
597da2e3ebdSchin 		}
5987c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5997c2fbfb3SApril Chin 	check_type:
6007c2fbfb3SApril Chin 		if(maketype)
6017c2fbfb3SApril Chin 		{
6027c2fbfb3SApril Chin 			nv_open(shtp.nodes[0]->nvname,shp->var_tree,NV_ASSIGN|NV_VARNAME|NV_NOADD|NV_NOFAIL);
6037c2fbfb3SApril Chin 			np = nv_mktype(shtp.nodes,shtp.numnodes);
6047c2fbfb3SApril Chin 			free((void*)shtp.nodes);
6057c2fbfb3SApril Chin 			shp->mktype = shtp.previous;
6067c2fbfb3SApril Chin 			maketype = 0;
6077c2fbfb3SApril Chin 			shp->prefix = 0;
6087c2fbfb3SApril Chin 			if(nr.np == np)
6097c2fbfb3SApril Chin 			{
6107c2fbfb3SApril Chin 				L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
6117c2fbfb3SApril Chin 				L_ARGNOD->nvflag = node.nvflag;
6127c2fbfb3SApril Chin 				L_ARGNOD->nvfun = node.nvfun;
6137c2fbfb3SApril Chin 			}
6147c2fbfb3SApril Chin 		}
6157c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
616da2e3ebdSchin 	}
617da2e3ebdSchin }
618da2e3ebdSchin 
619da2e3ebdSchin /*
620da2e3ebdSchin  * copy the subscript onto the stack
621da2e3ebdSchin  */
stak_subscript(const char * sub,int last)622da2e3ebdSchin static void stak_subscript(const char *sub, int last)
623da2e3ebdSchin {
624da2e3ebdSchin 	register int c;
625da2e3ebdSchin 	stakputc('[');
626da2e3ebdSchin 	while(c= *sub++)
627da2e3ebdSchin 	{
628da2e3ebdSchin 		if(c=='[' || c==']' || c=='\\')
629da2e3ebdSchin 			stakputc('\\');
630da2e3ebdSchin 		stakputc(c);
631da2e3ebdSchin 	}
632da2e3ebdSchin 	stakputc(last);
633da2e3ebdSchin }
634da2e3ebdSchin 
635da2e3ebdSchin /*
636da2e3ebdSchin  * construct a new name from a prefix and base name on the stack
637da2e3ebdSchin  */
copystack(const char * prefix,register const char * name,const char * sub)638da2e3ebdSchin static char *copystack(const char *prefix, register const char *name, const char *sub)
639da2e3ebdSchin {
640da2e3ebdSchin 	register int last=0,offset = staktell();
641da2e3ebdSchin 	if(prefix)
642da2e3ebdSchin 	{
643da2e3ebdSchin 		stakputs(prefix);
644da2e3ebdSchin 		if(*stakptr(staktell()-1)=='.')
645da2e3ebdSchin 			stakseek(staktell()-1);
646da2e3ebdSchin 		if(*name=='.' && name[1]=='[')
647da2e3ebdSchin 			last = staktell()+2;
648da2e3ebdSchin 		if(*name!='['  && *name!='.' && *name!='=' && *name!='+')
649da2e3ebdSchin 			stakputc('.');
6507c2fbfb3SApril Chin 		if(*name=='.' && (name[1]=='=' || name[1]==0))
6517c2fbfb3SApril Chin 			stakputc('.');
652da2e3ebdSchin 	}
653da2e3ebdSchin 	if(last)
654da2e3ebdSchin 	{
655da2e3ebdSchin 		stakputs(name);
656da2e3ebdSchin 		if(sh_checkid(stakptr(last),(char*)0))
657da2e3ebdSchin 			stakseek(staktell()-2);
658da2e3ebdSchin 	}
659da2e3ebdSchin 	if(sub)
660da2e3ebdSchin 		stak_subscript(sub,']');
661da2e3ebdSchin 	if(!last)
662da2e3ebdSchin 		stakputs(name);
663da2e3ebdSchin 	stakputc(0);
664da2e3ebdSchin 	return(stakptr(offset));
665da2e3ebdSchin }
666da2e3ebdSchin 
667da2e3ebdSchin /*
668da2e3ebdSchin  * grow this stack string <name> by <n> bytes and move from cp-1 to end
669da2e3ebdSchin  * right by <n>.  Returns beginning of string on the stack
670da2e3ebdSchin  */
stack_extend(const char * cname,char * cp,int n)671da2e3ebdSchin static char *stack_extend(const char *cname, char *cp, int n)
672da2e3ebdSchin {
673da2e3ebdSchin 	register char *name = (char*)cname;
674da2e3ebdSchin 	int offset = name - stakptr(0);
675da2e3ebdSchin 	int m = cp-name;
676da2e3ebdSchin 	stakseek(strlen(name)+n+1);
677da2e3ebdSchin 	name = stakptr(offset);
678da2e3ebdSchin 	cp =  name + m;
679da2e3ebdSchin 	m = strlen(cp)+1;
680da2e3ebdSchin 	while(m-->0)
681da2e3ebdSchin 		cp[n+m]=cp[m];
682da2e3ebdSchin 	return((char*)name);
683da2e3ebdSchin }
684da2e3ebdSchin 
nv_create(const char * name,Dt_t * root,int flags,Namfun_t * dp)685da2e3ebdSchin Namval_t *nv_create(const char *name,  Dt_t *root, int flags, Namfun_t *dp)
686da2e3ebdSchin {
6877c2fbfb3SApril Chin 	Shell_t			*shp = &sh;
688da2e3ebdSchin 	char			*cp=(char*)name, *sp, *xp;
689da2e3ebdSchin 	register int		c;
690da2e3ebdSchin 	register Namval_t	*np=0, *nq=0;
691da2e3ebdSchin 	Namfun_t		*fp=0;
692da2e3ebdSchin 	long			mode, add=0;
693da2e3ebdSchin 	int			copy=1,isref,top=0,noscope=(flags&NV_NOSCOPE);
6947c2fbfb3SApril Chin 	if(root==shp->var_tree)
695da2e3ebdSchin 	{
696da2e3ebdSchin 		if(dtvnext(root))
697da2e3ebdSchin 			top = 1;
698da2e3ebdSchin 		else
699da2e3ebdSchin 			flags &= ~NV_NOSCOPE;
700da2e3ebdSchin 	}
701da2e3ebdSchin 	if(!dp->disc)
7027c2fbfb3SApril Chin 		copy = dp->nofree&1;
703da2e3ebdSchin 	if(*cp=='.')
704da2e3ebdSchin 		cp++;
705da2e3ebdSchin 	while(1)
706da2e3ebdSchin 	{
707da2e3ebdSchin 		switch(c = *(unsigned char*)(sp = cp))
708da2e3ebdSchin 		{
709da2e3ebdSchin 		    case '[':
710da2e3ebdSchin 			if(flags&NV_NOARRAY)
711da2e3ebdSchin 			{
712da2e3ebdSchin 				dp->last = cp;
713da2e3ebdSchin 				return(np);
714da2e3ebdSchin 			}
715da2e3ebdSchin 			cp = nv_endsubscript((Namval_t*)0,sp,0);
716da2e3ebdSchin 			if(sp==name || sp[-1]=='.')
717da2e3ebdSchin 				c = *(sp = cp);
718da2e3ebdSchin 			goto skip;
719da2e3ebdSchin 		    case '.':
720da2e3ebdSchin 			if(flags&NV_IDENT)
721da2e3ebdSchin 				return(0);
7227c2fbfb3SApril Chin 			if(root==shp->var_tree)
723da2e3ebdSchin 				flags &= ~NV_EXPORT;
724da2e3ebdSchin 			if(!copy && !(flags&NV_NOREF))
725da2e3ebdSchin 			{
726da2e3ebdSchin 				c = sp-name;
727da2e3ebdSchin 				copy = cp-name;
7287c2fbfb3SApril Chin 				dp->nofree |= 1;
729da2e3ebdSchin 				name = copystack((const char*)0, name,(const char*)0);
730da2e3ebdSchin 				cp = (char*)name+copy;
731da2e3ebdSchin 				sp = (char*)name+c;
732da2e3ebdSchin 				c = '.';
733da2e3ebdSchin 			}
734da2e3ebdSchin 		skip:
735da2e3ebdSchin 		    case '+':
736da2e3ebdSchin 		    case '=':
737da2e3ebdSchin 			*sp = 0;
738da2e3ebdSchin 		    case 0:
739da2e3ebdSchin 			isref = 0;
740da2e3ebdSchin 			dp->last = cp;
741da2e3ebdSchin 			mode =  (c=='.' || (flags&NV_NOADD))?add:NV_ADD;
7427c2fbfb3SApril Chin 			if((flags&NV_NOSCOPE) && c!='.')
743da2e3ebdSchin 				mode |= HASH_NOSCOPE;
7447c2fbfb3SApril Chin 			np=0;
745da2e3ebdSchin 			if(top)
7467c2fbfb3SApril Chin 			{
7477c2fbfb3SApril Chin 				struct Ufunction *rp;
7487c2fbfb3SApril Chin 				if((rp=shp->st.real_fun) && !rp->sdict && (flags&NV_STATIC))
7497c2fbfb3SApril Chin 				{
7507c2fbfb3SApril Chin 					Dt_t *dp = dtview(shp->var_tree,(Dt_t*)0);
7517c2fbfb3SApril Chin 					rp->sdict = dtopen(&_Nvdisc,Dtoset);
7527c2fbfb3SApril Chin 					dtview(rp->sdict,shp->var_base);
7537c2fbfb3SApril Chin 					dtview(shp->var_tree,rp->sdict);
7547c2fbfb3SApril Chin 				}
7557c2fbfb3SApril Chin 				if(np = nv_search(name,shp->var_tree,0))
7567c2fbfb3SApril Chin 				{
7577c2fbfb3SApril Chin 					if(shp->var_tree->walk == shp->var_base)
7587c2fbfb3SApril Chin 					{
7597c2fbfb3SApril Chin 						nq = np;
760*3e14f97fSRoger A. Faulkner 						if((flags&NV_NOSCOPE) && *cp!='.')
7617c2fbfb3SApril Chin 						{
7627c2fbfb3SApril Chin 							if(mode==0)
7637c2fbfb3SApril Chin 								root = shp->var_base;
7647c2fbfb3SApril Chin 							else
7657c2fbfb3SApril Chin 							{
7667c2fbfb3SApril Chin 								nv_delete(np,(Dt_t*)0,0);
7677c2fbfb3SApril Chin 								np = 0;
7687c2fbfb3SApril Chin 							}
7697c2fbfb3SApril Chin 						}
7707c2fbfb3SApril Chin 					}
7717c2fbfb3SApril Chin 					else
7727c2fbfb3SApril Chin 					{
7737c2fbfb3SApril Chin 						root = shp->var_tree->walk;
7747c2fbfb3SApril Chin 						flags |= NV_NOSCOPE;
7757c2fbfb3SApril Chin 						noscope = 1;
7767c2fbfb3SApril Chin 					}
7777c2fbfb3SApril Chin 				}
7787c2fbfb3SApril Chin 				if(rp && rp->sdict && (flags&NV_STATIC))
7797c2fbfb3SApril Chin 				{
7807c2fbfb3SApril Chin 					root = rp->sdict;
7817c2fbfb3SApril Chin 					if(np && shp->var_tree->walk==shp->var_tree)
7827c2fbfb3SApril Chin 					{
7837c2fbfb3SApril Chin 						_nv_unset(np,0);
7847c2fbfb3SApril Chin 						nv_delete(np,shp->var_tree,0);
7857c2fbfb3SApril Chin 						np = 0;
7867c2fbfb3SApril Chin 					}
7877c2fbfb3SApril Chin 					if(!np || shp->var_tree->walk!=root)
7887c2fbfb3SApril Chin 						np =  nv_search(name,root,HASH_NOSCOPE|NV_ADD);
7897c2fbfb3SApril Chin 				}
7907c2fbfb3SApril Chin 			}
7917c2fbfb3SApril Chin 			if(np ||  (np = nv_search(name,root,mode)))
792da2e3ebdSchin 			{
793da2e3ebdSchin 				isref = nv_isref(np);
794da2e3ebdSchin 				if(top)
795da2e3ebdSchin 				{
796da2e3ebdSchin 					if(nq==np)
79734f9b3eeSRoland Mainz 					{
798da2e3ebdSchin 						flags &= ~NV_NOSCOPE;
79934f9b3eeSRoland Mainz 						root = shp->var_base;
80034f9b3eeSRoland Mainz 					}
801da2e3ebdSchin 					else if(nq)
802da2e3ebdSchin 					{
803da2e3ebdSchin 						if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq)))
804da2e3ebdSchin 							np->nvname = nq->nvname;
805da2e3ebdSchin 						flags |= NV_NOSCOPE;
806da2e3ebdSchin 					}
807da2e3ebdSchin 				}
8087c2fbfb3SApril Chin 				else if(add && nv_isnull(np) && c=='.' && cp[1]!='.')
809da2e3ebdSchin 					nv_setvtree(np);
810da2e3ebdSchin 			}
811da2e3ebdSchin 			if(c)
812da2e3ebdSchin 				*sp = c;
813da2e3ebdSchin 			top = 0;
814da2e3ebdSchin 			if(isref)
815da2e3ebdSchin 			{
816da2e3ebdSchin 				char *sub=0;
8177c2fbfb3SApril Chin #if NVCACHE
8187c2fbfb3SApril Chin 				nvcache.ok = 0;
8197c2fbfb3SApril Chin #endif
820da2e3ebdSchin 				if(c=='.') /* don't optimize */
8217c2fbfb3SApril Chin 					shp->argaddr = 0;
82234f9b3eeSRoland Mainz 				else if((flags&NV_NOREF) && (c!='[' && *cp!='.'))
823da2e3ebdSchin 				{
8247c2fbfb3SApril Chin 					if(c && !(flags&NV_NOADD))
825da2e3ebdSchin 						nv_unref(np);
826da2e3ebdSchin 					return(np);
827da2e3ebdSchin 				}
8287c2fbfb3SApril Chin 				while(nv_isref(np) && np->nvalue.cp)
829da2e3ebdSchin 				{
830da2e3ebdSchin 					root = nv_reftree(np);
8317c2fbfb3SApril Chin 					shp->last_root = root;
8327c2fbfb3SApril Chin 					shp->last_table = nv_reftable(np);
833da2e3ebdSchin 					sub = nv_refsub(np);
834da2e3ebdSchin 					np = nv_refnode(np);
835da2e3ebdSchin 					if(sub && c!='.')
836da2e3ebdSchin 						nv_putsub(np,sub,0L);
837da2e3ebdSchin 					flags |= NV_NOSCOPE;
8387c2fbfb3SApril Chin 					noscope = 1;
839da2e3ebdSchin 				}
8407c2fbfb3SApril Chin 				if(nv_isref(np) && (c=='[' || c=='.' || !(flags&NV_ASSIGN)))
8417c2fbfb3SApril Chin 					errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np));
842da2e3ebdSchin 				if(sub && c==0)
843da2e3ebdSchin 					return(np);
844da2e3ebdSchin 				if(np==nq)
845da2e3ebdSchin 					flags &= ~(noscope?0:NV_NOSCOPE);
846da2e3ebdSchin 				else if(c)
847da2e3ebdSchin 				{
848da2e3ebdSchin 					c = (cp-sp);
849da2e3ebdSchin 					copy = strlen(cp=nv_name(np));
8507c2fbfb3SApril Chin 					dp->nofree |= 1;
851da2e3ebdSchin 					name = copystack(cp,sp,sub);
852da2e3ebdSchin 					sp = (char*)name + copy;
853da2e3ebdSchin 					cp = sp+c;
854da2e3ebdSchin 					c = *sp;
855da2e3ebdSchin 					if(!noscope)
856da2e3ebdSchin 						flags &= ~NV_NOSCOPE;
857da2e3ebdSchin 				}
858da2e3ebdSchin 				flags |= NV_NOREF;
85934f9b3eeSRoland Mainz 				if(nv_isnull(np))
86034f9b3eeSRoland Mainz 					nv_onattr(np,NV_NOFREE);
86134f9b3eeSRoland Mainz 
862da2e3ebdSchin 			}
8637c2fbfb3SApril Chin 			shp->last_root = root;
864*3e14f97fSRoger A. Faulkner 			if(*cp && cp[1]=='.')
8657c2fbfb3SApril Chin 				cp++;
8667c2fbfb3SApril Chin 			if(c=='.' && (cp[1]==0 ||  cp[1]=='=' || cp[1]=='+'))
8677c2fbfb3SApril Chin 			{
8687c2fbfb3SApril Chin 				nv_local = 1;
8697c2fbfb3SApril Chin 				return(np);
8707c2fbfb3SApril Chin 			}
8717c2fbfb3SApril Chin 			if(cp[-1]=='.')
8727c2fbfb3SApril Chin 				cp--;
873da2e3ebdSchin 			do
874da2e3ebdSchin 			{
875da2e3ebdSchin 				if(!np)
876da2e3ebdSchin 				{
8777c2fbfb3SApril Chin 					if(!nq && *sp=='[' && *cp==0 && cp[-1]==']')
878da2e3ebdSchin 					{
879da2e3ebdSchin 						/*
880da2e3ebdSchin 						 * for backward compatibility
881da2e3ebdSchin 						 * evaluate subscript for
882da2e3ebdSchin 						 * possible side effects
883da2e3ebdSchin 						 */
884da2e3ebdSchin 						cp[-1] = 0;
885da2e3ebdSchin 						sh_arith(sp+1);
886da2e3ebdSchin 						cp[-1] = ']';
887da2e3ebdSchin 					}
888da2e3ebdSchin 					return(np);
889da2e3ebdSchin 				}
890da2e3ebdSchin 				if(c=='[' || (c=='.' && nv_isarray(np)))
891da2e3ebdSchin 				{
8927c2fbfb3SApril Chin 					char *sub=0;
893da2e3ebdSchin 					int n = 0;
89434f9b3eeSRoland Mainz 					mode &= ~HASH_NOSCOPE;
895da2e3ebdSchin 					if(c=='[')
896da2e3ebdSchin 					{
89734f9b3eeSRoland Mainz #if 0
89834f9b3eeSRoland Mainz 						Namarr_t *ap = nv_arrayptr(np);
89934f9b3eeSRoland Mainz 						int scan = ap?(ap->nelem&ARRAY_SCAN):0;
90034f9b3eeSRoland Mainz #endif
901da2e3ebdSchin 						n = mode|nv_isarray(np);
902da2e3ebdSchin 						if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']')
903da2e3ebdSchin 						{
904da2e3ebdSchin 							/* not implemented yet */
905da2e3ebdSchin 							dp->last = cp;
906da2e3ebdSchin 							return(np);
907da2e3ebdSchin 						}
9087c2fbfb3SApril Chin 						if((n&NV_ADD)&&(flags&NV_ARRAY))
909da2e3ebdSchin 							n |= ARRAY_FILL;
9107c2fbfb3SApril Chin 						if(flags&NV_ASSIGN)
9117c2fbfb3SApril Chin 							n |= NV_ADD;
9127c2fbfb3SApril Chin 						cp = nv_endsubscript(np,sp,n|(flags&NV_ASSIGN));
91334f9b3eeSRoland Mainz #if 0
91434f9b3eeSRoland Mainz 						if(scan)
91534f9b3eeSRoland Mainz 							nv_putsub(np,NIL(char*),ARRAY_SCAN);
91634f9b3eeSRoland Mainz #endif
917da2e3ebdSchin 					}
918da2e3ebdSchin 					else
919da2e3ebdSchin 						cp = sp;
9207c2fbfb3SApril Chin 					if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || (flags&NV_ARRAY))
921da2e3ebdSchin 
922da2e3ebdSchin 					{
923da2e3ebdSchin 						int m = cp-sp;
9247c2fbfb3SApril Chin 						sub = m?nv_getsub(np):0;
925da2e3ebdSchin 						if(!sub)
9267c2fbfb3SApril Chin 						{
9277c2fbfb3SApril Chin 							if(m && !(n&NV_ADD))
9287c2fbfb3SApril Chin 								return(0);
929da2e3ebdSchin 							sub = "0";
9307c2fbfb3SApril Chin 						}
931da2e3ebdSchin 						n = strlen(sub)+2;
932da2e3ebdSchin 						if(!copy)
933da2e3ebdSchin 						{
934da2e3ebdSchin 							copy = cp-name;
9357c2fbfb3SApril Chin 							dp->nofree |= 1;
936da2e3ebdSchin 							name = copystack((const char*)0, name,(const char*)0);
937da2e3ebdSchin 							cp = (char*)name+copy;
938da2e3ebdSchin 							sp = cp-m;
939da2e3ebdSchin 						}
940da2e3ebdSchin 						if(n <= m)
941da2e3ebdSchin 						{
942da2e3ebdSchin 							if(n)
943da2e3ebdSchin 							{
944da2e3ebdSchin 								memcpy(sp+1,sub,n-2);
945da2e3ebdSchin 								sp[n-1] = ']';
946da2e3ebdSchin 							}
947da2e3ebdSchin 							if(n < m)
948da2e3ebdSchin 								cp=strcpy(sp+n,cp);
949da2e3ebdSchin 						}
950da2e3ebdSchin 						else
951da2e3ebdSchin 						{
952da2e3ebdSchin 							int r = n-m;
953da2e3ebdSchin 							m = sp-name;
954da2e3ebdSchin 							name = stack_extend(name, cp-1, r);
955da2e3ebdSchin 							sp = (char*)name + m;
956da2e3ebdSchin 							*sp = '[';
957da2e3ebdSchin 							memcpy(sp+1,sub,n-2);
958da2e3ebdSchin 							sp[n-1] = ']';
959da2e3ebdSchin 							cp = sp+n;
960da2e3ebdSchin 
961da2e3ebdSchin 						}
962da2e3ebdSchin 					}
963da2e3ebdSchin 					else if(c==0 && mode && (n=nv_aindex(np))>0)
9647c2fbfb3SApril Chin 						nv_putsub(np,(char*)0,n);
9657c2fbfb3SApril Chin 					else if(n==0 && (c==0 || (c=='[' && !nv_isarray(np))))
966da2e3ebdSchin 					{
967da2e3ebdSchin 						/* subscript must be 0*/
968da2e3ebdSchin 						cp[-1] = 0;
9697c2fbfb3SApril Chin 						n = sh_arith(sp+1);
970da2e3ebdSchin 						cp[-1] = ']';
9717c2fbfb3SApril Chin 						if(n)
972da2e3ebdSchin 							return(0);
9737c2fbfb3SApril Chin 						if(c)
9747c2fbfb3SApril Chin 							sp = cp;
975da2e3ebdSchin 					}
976da2e3ebdSchin 					dp->last = cp;
977da2e3ebdSchin 					if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY)))
978da2e3ebdSchin 					{
9797c2fbfb3SApril Chin 						sp = cp;
9807c2fbfb3SApril Chin 						if(!(nq = nv_opensub(np)))
9817c2fbfb3SApril Chin 						{
9827c2fbfb3SApril Chin 							Namarr_t *ap = nv_arrayptr(np);
9837c2fbfb3SApril Chin 							if(!sub && (flags&NV_NOADD))
9847c2fbfb3SApril Chin 								return(0);
9857c2fbfb3SApril Chin 							n = mode|((flags&NV_NOADD)?0:NV_ADD);
9867c2fbfb3SApril Chin 							if(!ap && (n&NV_ADD))
9877c2fbfb3SApril Chin 							{
9887c2fbfb3SApril Chin 								nv_putsub(np,sub,ARRAY_FILL);
9897c2fbfb3SApril Chin 								ap = nv_arrayptr(np);
9907c2fbfb3SApril Chin 							}
9917c2fbfb3SApril Chin 							if(n && ap && !ap->table)
9927c2fbfb3SApril Chin 								ap->table = dtopen(&_Nvdisc,Dtoset);
9937c2fbfb3SApril Chin 							if(ap && ap->table && (nq=nv_search(sub,ap->table,n)))
9947c2fbfb3SApril Chin 								nq->nvenv = (char*)np;
995da2e3ebdSchin 							if(nq && nv_isnull(nq))
996da2e3ebdSchin 								nq = nv_arraychild(np,nq,c);
9977c2fbfb3SApril Chin 						}
9987c2fbfb3SApril Chin 						if(nq)
9997c2fbfb3SApril Chin 						{
10007c2fbfb3SApril Chin 							if(c=='.' && !nv_isvtree(nq))
10017c2fbfb3SApril Chin 							{
10027c2fbfb3SApril Chin 								if(flags&NV_NOADD)
10037c2fbfb3SApril Chin 									return(0);
10047c2fbfb3SApril Chin 								nv_setvtree(nq);
10057c2fbfb3SApril Chin 							}
10067c2fbfb3SApril Chin 							np = nq;
10077c2fbfb3SApril Chin 						}
10087c2fbfb3SApril Chin 						else if(memcmp(cp,"[0]",3))
10097c2fbfb3SApril Chin 							return(nq);
10107c2fbfb3SApril Chin 						else
10117c2fbfb3SApril Chin 						{
10127c2fbfb3SApril Chin 							/* ignore [0]  */
10137c2fbfb3SApril Chin 							dp->last = cp += 3;
10147c2fbfb3SApril Chin 							c = *cp;
10157c2fbfb3SApril Chin 						}
1016da2e3ebdSchin 					}
1017da2e3ebdSchin 				}
1018da2e3ebdSchin 				else if(nv_isarray(np))
10197c2fbfb3SApril Chin 				{
10207c2fbfb3SApril Chin 					if(c==0 && (flags&NV_MOVE))
10217c2fbfb3SApril Chin 						return(np);
1022da2e3ebdSchin 					nv_putsub(np,NIL(char*),ARRAY_UNDEF);
10237c2fbfb3SApril Chin 				}
1024da2e3ebdSchin 				if(c=='.' && (fp=np->nvfun))
1025da2e3ebdSchin 				{
1026da2e3ebdSchin 					for(; fp; fp=fp->next)
1027da2e3ebdSchin 					{
1028da2e3ebdSchin 						if(fp->disc && fp->disc->createf)
1029da2e3ebdSchin 							break;
1030da2e3ebdSchin 					}
1031da2e3ebdSchin 					if(fp)
1032da2e3ebdSchin 					{
1033da2e3ebdSchin 						if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np)
1034da2e3ebdSchin 						{
1035da2e3ebdSchin 							add = NV_ADD;
103634f9b3eeSRoland Mainz 							shp->last_table = 0;
1037da2e3ebdSchin 							break;
1038da2e3ebdSchin 						}
10397c2fbfb3SApril Chin 						else if(np=nq)
10407c2fbfb3SApril Chin 						{
10417c2fbfb3SApril Chin 							if((c = *(sp=cp=dp->last=fp->last))==0)
10427c2fbfb3SApril Chin 							{
10437c2fbfb3SApril Chin 								if(nv_isarray(np) && sp[-1]!=']')
10447c2fbfb3SApril Chin 									nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1045da2e3ebdSchin 								return(np);
1046da2e3ebdSchin 							}
1047da2e3ebdSchin 						}
1048da2e3ebdSchin 					}
10497c2fbfb3SApril Chin 				}
10507c2fbfb3SApril Chin 			}
1051da2e3ebdSchin 			while(c=='[');
10527c2fbfb3SApril Chin 			if(c!='.' || cp[1]=='.')
1053da2e3ebdSchin 				return(np);
1054da2e3ebdSchin 			cp++;
1055da2e3ebdSchin 			break;
1056da2e3ebdSchin 		    default:
1057da2e3ebdSchin 			dp->last = cp;
1058da2e3ebdSchin 			if((c = mbchar(cp)) && !isaletter(c))
1059da2e3ebdSchin 				return(np);
1060da2e3ebdSchin 			while(xp=cp, c=mbchar(cp), isaname(c));
1061da2e3ebdSchin 			cp = xp;
1062da2e3ebdSchin 		}
1063da2e3ebdSchin 	}
1064da2e3ebdSchin 	return(np);
1065da2e3ebdSchin }
1066da2e3ebdSchin 
1067da2e3ebdSchin /*
10687c2fbfb3SApril Chin  * delete the node <np> from the dictionary <root> and clear from the cache
10697c2fbfb3SApril Chin  * if <root> is NULL, only the cache is cleared
10707c2fbfb3SApril Chin  * if flags does not contain NV_NOFREE, the node is freed
10717c2fbfb3SApril Chin  */
nv_delete(Namval_t * np,Dt_t * root,int flags)10727c2fbfb3SApril Chin void nv_delete(Namval_t* np, Dt_t *root, int flags)
10737c2fbfb3SApril Chin {
10747c2fbfb3SApril Chin #if NVCACHE
10757c2fbfb3SApril Chin 	register int		c;
10767c2fbfb3SApril Chin 	struct Cache_entry	*xp;
10777c2fbfb3SApril Chin 	for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
10787c2fbfb3SApril Chin 	{
10797c2fbfb3SApril Chin 		if(xp->np==np)
10807c2fbfb3SApril Chin 			xp->root = 0;
10817c2fbfb3SApril Chin 	}
10827c2fbfb3SApril Chin #endif
10837c2fbfb3SApril Chin 	if(root)
10847c2fbfb3SApril Chin 	{
10857c2fbfb3SApril Chin 		if(dtdelete(root,np))
10867c2fbfb3SApril Chin 		{
10877c2fbfb3SApril Chin 			if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np)))
10887c2fbfb3SApril Chin 				free((void*)np);
10897c2fbfb3SApril Chin 		}
10907c2fbfb3SApril Chin #if 0
10917c2fbfb3SApril Chin 		else
10927c2fbfb3SApril Chin 		{
10937c2fbfb3SApril Chin 			sfprintf(sfstderr,"%s not deleted\n",nv_name(np));
10947c2fbfb3SApril Chin 			sfsync(sfstderr);
10957c2fbfb3SApril Chin 		}
10967c2fbfb3SApril Chin #endif
10977c2fbfb3SApril Chin 	}
10987c2fbfb3SApril Chin }
10997c2fbfb3SApril Chin 
11007c2fbfb3SApril Chin /*
1101da2e3ebdSchin  * Put <arg> into associative memory.
1102da2e3ebdSchin  * If <flags> & NV_ARRAY then follow array to next subscript
1103da2e3ebdSchin  * If <flags> & NV_NOARRAY then subscript is not allowed
1104da2e3ebdSchin  * If <flags> & NV_NOSCOPE then use the current scope only
1105da2e3ebdSchin  * If <flags> & NV_ASSIGN then assignment is allowed
1106da2e3ebdSchin  * If <flags> & NV_IDENT then name must be an identifier
1107da2e3ebdSchin  * If <flags> & NV_VARNAME then name must be a valid variable name
1108da2e3ebdSchin  * If <flags> & NV_NOADD then node will not be added if not found
1109da2e3ebdSchin  * If <flags> & NV_NOREF then don't follow reference
1110da2e3ebdSchin  * If <flags> & NV_NOFAIL then don't generate an error message on failure
11117c2fbfb3SApril Chin  * If <flags> & NV_STATIC then unset before an assignment
111234f9b3eeSRoland Mainz  * If <flags> & NV_UNJUST then unset attributes before assignment
1113da2e3ebdSchin  * SH_INIT is only set while initializing the environment
1114da2e3ebdSchin  */
nv_open(const char * name,Dt_t * root,int flags)1115da2e3ebdSchin Namval_t *nv_open(const char *name, Dt_t *root, int flags)
1116da2e3ebdSchin {
11177c2fbfb3SApril Chin 	Shell_t			*shp = &sh;
1118da2e3ebdSchin 	register char		*cp=(char*)name;
1119da2e3ebdSchin 	register int		c;
1120da2e3ebdSchin 	register Namval_t	*np;
1121da2e3ebdSchin 	Namfun_t		fun;
1122da2e3ebdSchin 	int			append=0;
1123da2e3ebdSchin 	const char		*msg = e_varname;
1124da2e3ebdSchin 	char			*fname = 0;
1125da2e3ebdSchin 	int			offset = staktell();
1126da2e3ebdSchin 	Dt_t			*funroot;
11277c2fbfb3SApril Chin #if NVCACHE
11287c2fbfb3SApril Chin 	struct Cache_entry	*xp;
11297c2fbfb3SApril Chin #endif
1130da2e3ebdSchin 
11317c2fbfb3SApril Chin 	sh_stats(STAT_NVOPEN);
1132da2e3ebdSchin 	memset(&fun,0,sizeof(fun));
11337c2fbfb3SApril Chin 	shp->last_table = shp->namespace;
1134da2e3ebdSchin 	if(!root)
11357c2fbfb3SApril Chin 		root = shp->var_tree;
11367c2fbfb3SApril Chin 	shp->last_root = root;
11377c2fbfb3SApril Chin 	if(root==shp->fun_tree)
1138da2e3ebdSchin 	{
1139da2e3ebdSchin 		flags |= NV_NOREF;
1140da2e3ebdSchin 		msg = e_badfun;
11417c2fbfb3SApril Chin 		if((np=shp->namespace) || strchr(name,'.'))
1142da2e3ebdSchin 		{
1143da2e3ebdSchin 			name = cp = copystack(np?nv_name(np):0,name,(const char*)0);
1144da2e3ebdSchin 			fname = strrchr(cp,'.');
1145da2e3ebdSchin 			*fname = 0;
11467c2fbfb3SApril Chin 			fun.nofree |= 1;
1147da2e3ebdSchin 			flags &=  ~NV_IDENT;
1148da2e3ebdSchin 			funroot = root;
11497c2fbfb3SApril Chin 			root = shp->var_tree;
1150da2e3ebdSchin 		}
1151da2e3ebdSchin 	}
1152da2e3ebdSchin 	else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
1153da2e3ebdSchin 	{
1154da2e3ebdSchin 		long mode = ((flags&NV_NOADD)?0:NV_ADD);
1155da2e3ebdSchin 		if(flags&NV_NOSCOPE)
1156da2e3ebdSchin 			mode |= HASH_SCOPE|HASH_NOSCOPE;
1157da2e3ebdSchin 		np = nv_search(name,root,mode);
1158da2e3ebdSchin 		if(np && !(flags&NV_REF))
1159da2e3ebdSchin 		{
1160da2e3ebdSchin 			while(nv_isref(np))
1161da2e3ebdSchin 			{
11627c2fbfb3SApril Chin 				shp->last_table = nv_reftable(np);
1163da2e3ebdSchin 				np = nv_refnode(np);
1164da2e3ebdSchin 			}
1165da2e3ebdSchin 		}
1166da2e3ebdSchin 		return(np);
1167da2e3ebdSchin 	}
11687c2fbfb3SApril Chin 	else if(shp->prefix && (flags&NV_ASSIGN))
1169da2e3ebdSchin 	{
11707c2fbfb3SApril Chin 		name = cp = copystack(shp->prefix,name,(const char*)0);
11717c2fbfb3SApril Chin 		fun.nofree |= 1;
1172da2e3ebdSchin 	}
1173da2e3ebdSchin 	c = *(unsigned char*)cp;
11747c2fbfb3SApril Chin 	if(root==shp->alias_tree)
1175da2e3ebdSchin 	{
1176da2e3ebdSchin 		msg = e_aliname;
1177da2e3ebdSchin 		while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
11787c2fbfb3SApril Chin 			(c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON));
11797c2fbfb3SApril Chin 		if(shp->subshell && c=='=')
1180da2e3ebdSchin 			root = sh_subaliastree(1);
1181da2e3ebdSchin 		if(c= *--cp)
1182da2e3ebdSchin 			*cp = 0;
1183da2e3ebdSchin 		np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);
1184da2e3ebdSchin 		if(c)
1185da2e3ebdSchin 			*cp = c;
1186da2e3ebdSchin 		goto skip;
1187da2e3ebdSchin 	}
1188da2e3ebdSchin 	else if(flags&NV_IDENT)
1189da2e3ebdSchin 		msg = e_ident;
1190da2e3ebdSchin 	else if(c=='.')
1191da2e3ebdSchin 	{
1192da2e3ebdSchin 		c = *++cp;
1193da2e3ebdSchin 		flags |= NV_NOREF;
11947c2fbfb3SApril Chin 		if(root==shp->var_tree)
11957c2fbfb3SApril Chin 			root = shp->var_base;
11967c2fbfb3SApril Chin 		shp->last_table = 0;
1197da2e3ebdSchin 	}
1198da2e3ebdSchin 	if(c= !isaletter(c))
1199da2e3ebdSchin 		goto skip;
12007c2fbfb3SApril Chin #if NVCACHE
12017c2fbfb3SApril Chin 	for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
12027c2fbfb3SApril Chin 	{
12037c2fbfb3SApril Chin 		if(xp->root!=root)
12047c2fbfb3SApril Chin 			continue;
12057c2fbfb3SApril Chin 		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]=='+'))
12067c2fbfb3SApril Chin 		{
12077c2fbfb3SApril Chin 			sh_stats(STAT_NVHITS);
12087c2fbfb3SApril Chin 			np = xp->np;
12097c2fbfb3SApril Chin 			cp = (char*)name+xp->len;
12107c2fbfb3SApril Chin 			if(nv_isarray(np))
12117c2fbfb3SApril Chin 				 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
12127c2fbfb3SApril Chin 			shp->last_table = xp->last_table;
121334f9b3eeSRoland Mainz 			shp->last_root = xp->last_root;
12147c2fbfb3SApril Chin 			goto nocache;
12157c2fbfb3SApril Chin 		}
12167c2fbfb3SApril Chin 	}
12177c2fbfb3SApril Chin 	nvcache.ok = 1;
12187c2fbfb3SApril Chin #endif
1219da2e3ebdSchin 	np = nv_create(name, root, flags, &fun);
1220da2e3ebdSchin 	cp = fun.last;
12217c2fbfb3SApril Chin #if NVCACHE
12227c2fbfb3SApril Chin 	if(np && nvcache.ok && cp[-1]!=']')
12237c2fbfb3SApril Chin 	{
12247c2fbfb3SApril Chin 		xp = &nvcache.entries[nvcache.index];
12257c2fbfb3SApril Chin 		if(*cp)
12267c2fbfb3SApril Chin 		{
12277c2fbfb3SApril Chin 			char *sp = strchr(name,*cp);
12287c2fbfb3SApril Chin 			if(!sp)
12297c2fbfb3SApril Chin 				goto nocache;
12307c2fbfb3SApril Chin 			xp->len = sp-name;
12317c2fbfb3SApril Chin 		}
12327c2fbfb3SApril Chin 		else
12337c2fbfb3SApril Chin 			xp->len = strlen(name);
12347c2fbfb3SApril Chin 		c = roundof(xp->len+1,32);
12357c2fbfb3SApril Chin 		if(c > xp->size)
12367c2fbfb3SApril Chin 		{
12377c2fbfb3SApril Chin 			if(xp->size==0)
12387c2fbfb3SApril Chin 				xp->name = malloc(c);
12397c2fbfb3SApril Chin 			else
12407c2fbfb3SApril Chin 				xp->name = realloc(xp->name,c);
12417c2fbfb3SApril Chin 			xp->size = c;
12427c2fbfb3SApril Chin 		}
12437c2fbfb3SApril Chin 		memcpy(xp->name,name,xp->len);
12447c2fbfb3SApril Chin 		xp->name[xp->len] = 0;
12457c2fbfb3SApril Chin 		xp->root = root;
12467c2fbfb3SApril Chin 		xp->np = np;
12477c2fbfb3SApril Chin 		xp->last_table = shp->last_table;
124834f9b3eeSRoland Mainz 		xp->last_root = shp->last_root;
12497c2fbfb3SApril Chin 		xp->flags = (flags&(NV_ARRAY|NV_NOSCOPE));
12507c2fbfb3SApril Chin 		nvcache.index = (nvcache.index+1)&(NVCACHE-1);
12517c2fbfb3SApril Chin 	}
12527c2fbfb3SApril Chin nocache:
12537c2fbfb3SApril Chin 	nvcache.ok = 0;
12547c2fbfb3SApril Chin #endif
1255da2e3ebdSchin 	if(fname)
1256da2e3ebdSchin 	{
1257da2e3ebdSchin 		c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD);
1258da2e3ebdSchin 		*fname = '.';
1259da2e3ebdSchin 		np = nv_search(name, funroot, c);
1260da2e3ebdSchin 		*fname = 0;
1261da2e3ebdSchin 	}
12627c2fbfb3SApril Chin 	else
1263da2e3ebdSchin 	{
12647c2fbfb3SApril Chin 		if(*cp=='.' && cp[1]=='.')
12657c2fbfb3SApril Chin 		{
12667c2fbfb3SApril Chin 			append |= NV_NODISC;
12677c2fbfb3SApril Chin 			cp+=2;
12687c2fbfb3SApril Chin 		}
12697c2fbfb3SApril Chin 		if(*cp=='+' && cp[1]=='=')
12707c2fbfb3SApril Chin 		{
12717c2fbfb3SApril Chin 			append |= NV_APPEND;
1272da2e3ebdSchin 			cp++;
1273da2e3ebdSchin 		}
12747c2fbfb3SApril Chin 	}
1275da2e3ebdSchin 	c = *cp;
1276da2e3ebdSchin skip:
12777c2fbfb3SApril Chin #if SHOPT_TYPEDEF
12787c2fbfb3SApril Chin 	if(np && shp->mktype)
12797c2fbfb3SApril Chin 		np = nv_addnode(np,0);
12807c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
1281da2e3ebdSchin 	if(c=='=' && np && (flags&NV_ASSIGN))
1282da2e3ebdSchin 	{
1283da2e3ebdSchin 		cp++;
1284da2e3ebdSchin 		if(sh_isstate(SH_INIT))
1285da2e3ebdSchin 		{
1286da2e3ebdSchin 			nv_putval(np, cp, NV_RDONLY);
1287da2e3ebdSchin 			if(np==PWDNOD)
1288da2e3ebdSchin 				nv_onattr(np,NV_TAGGED);
1289da2e3ebdSchin 		}
1290da2e3ebdSchin 		else
1291da2e3ebdSchin 		{
12927c2fbfb3SApril Chin 			char *sub=0, *prefix= shp->prefix;
12937c2fbfb3SApril Chin 			int isref;
12947c2fbfb3SApril Chin 			shp->prefix = 0;
12957c2fbfb3SApril Chin 			if((flags&NV_STATIC) && !shp->mktype)
12967c2fbfb3SApril Chin 			{
12977c2fbfb3SApril Chin 				if(!nv_isnull(np))
129834f9b3eeSRoland Mainz 				{
129934f9b3eeSRoland Mainz 					shp->prefix = prefix;
13007c2fbfb3SApril Chin 					return(np);
13017c2fbfb3SApril Chin 				}
130234f9b3eeSRoland Mainz 			}
13037c2fbfb3SApril Chin 			isref = nv_isref(np);
1304da2e3ebdSchin 			if(sh_isoption(SH_XTRACE) && nv_isarray(np))
1305da2e3ebdSchin 				sub = nv_getsub(np);
1306da2e3ebdSchin 			c = msg==e_aliname? 0: (append | (flags&NV_EXPORT));
13077c2fbfb3SApril Chin 			if(isref)
13087c2fbfb3SApril Chin 				nv_offattr(np,NV_REF);
130934f9b3eeSRoland Mainz 			if(!append && (flags&NV_UNJUST))
131034f9b3eeSRoland Mainz 			{
131134f9b3eeSRoland Mainz 				nv_offattr(np,NV_LJUST|NV_RJUST|NV_ZFILL);
131234f9b3eeSRoland Mainz 				np->nvsize = 0;
131334f9b3eeSRoland Mainz 			}
1314da2e3ebdSchin 			nv_putval(np, cp, c);
13157c2fbfb3SApril Chin 			if(isref)
131634f9b3eeSRoland Mainz 			{
131734f9b3eeSRoland Mainz 				if(nv_search((char*)np,shp->var_base,HASH_BUCKET))
131834f9b3eeSRoland Mainz 					shp->last_root = shp->var_base;
13197c2fbfb3SApril Chin 				nv_setref(np,(Dt_t*)0,NV_VARNAME);
132034f9b3eeSRoland Mainz 			}
1321da2e3ebdSchin 			savesub = sub;
13227c2fbfb3SApril Chin 			shp->prefix = prefix;
1323da2e3ebdSchin 		}
1324da2e3ebdSchin 		nv_onattr(np, flags&NV_ATTRIBUTES);
1325da2e3ebdSchin 	}
1326da2e3ebdSchin 	else if(c)
1327da2e3ebdSchin 	{
1328da2e3ebdSchin 		if(flags&NV_NOFAIL)
1329da2e3ebdSchin 			return(0);
1330da2e3ebdSchin 		if(c=='.')
1331da2e3ebdSchin 			msg = e_noparent;
1332da2e3ebdSchin 		else if(c=='[')
1333da2e3ebdSchin 			msg = e_noarray;
1334da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),msg,name);
1335da2e3ebdSchin 	}
13367c2fbfb3SApril Chin 	if(fun.nofree&1)
1337da2e3ebdSchin 		stakseek(offset);
1338da2e3ebdSchin 	return(np);
1339da2e3ebdSchin }
1340da2e3ebdSchin 
1341da2e3ebdSchin #if SHOPT_MULTIBYTE
1342da2e3ebdSchin     static int ja_size(char*, int, int);
1343da2e3ebdSchin     static void ja_restore(void);
1344da2e3ebdSchin     static char *savep;
1345da2e3ebdSchin     static char savechars[8+1];
1346da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1347da2e3ebdSchin 
1348da2e3ebdSchin /*
1349da2e3ebdSchin  * put value <string> into name-value node <np>.
1350da2e3ebdSchin  * If <np> is an array, then the element given by the
1351da2e3ebdSchin  *   current index is assigned to.
1352da2e3ebdSchin  * If <flags> contains NV_RDONLY, readonly attribute is ignored
1353da2e3ebdSchin  * If <flags> contains NV_INTEGER, string is a pointer to a number
1354da2e3ebdSchin  * If <flags> contains NV_NOFREE, previous value is freed, and <string>
1355da2e3ebdSchin  * becomes value of node and <flags> becomes attributes
1356da2e3ebdSchin  */
nv_putval(register Namval_t * np,const char * string,int flags)1357da2e3ebdSchin void nv_putval(register Namval_t *np, const char *string, int flags)
1358da2e3ebdSchin {
1359da2e3ebdSchin 	register const char *sp=string;
1360da2e3ebdSchin 	register union Value *up;
1361da2e3ebdSchin 	register char *cp;
1362da2e3ebdSchin 	register int size = 0;
1363da2e3ebdSchin 	register int dot;
1364da2e3ebdSchin 	int	was_local = nv_local;
13657c2fbfb3SApril Chin 	union Value u;
1366da2e3ebdSchin 	if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
1367da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
1368da2e3ebdSchin 	/* The following could cause the shell to fork if assignment
1369da2e3ebdSchin 	 * would cause a side effect
1370da2e3ebdSchin 	 */
1371da2e3ebdSchin 	sh.argaddr = 0;
1372da2e3ebdSchin 	if(sh.subshell && !nv_local)
1373da2e3ebdSchin 		np = sh_assignok(np,1);
137434f9b3eeSRoland Mainz 	if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np))
1375da2e3ebdSchin 	{
1376da2e3ebdSchin 		/* This function contains disc */
1377da2e3ebdSchin 		if(!nv_local)
1378da2e3ebdSchin 		{
1379da2e3ebdSchin 			nv_local=1;
1380da2e3ebdSchin 			nv_putv(np,sp,flags,np->nvfun);
1381da2e3ebdSchin 			if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1382da2e3ebdSchin 				sh_envput(sh.env,np);
1383da2e3ebdSchin 			return;
1384da2e3ebdSchin 		}
1385da2e3ebdSchin 		/* called from disc, assign the actual value */
1386da2e3ebdSchin 	}
1387da2e3ebdSchin 	flags &= ~NV_NODISC;
13887c2fbfb3SApril Chin 	nv_local=0;
1389da2e3ebdSchin 	if(flags&(NV_NOREF|NV_NOFREE))
1390da2e3ebdSchin 	{
13917c2fbfb3SApril Chin 		if(np->nvalue.cp && np->nvalue.cp!=sp && !nv_isattr(np,NV_NOFREE))
13927c2fbfb3SApril Chin 			free((void*)np->nvalue.cp);
1393da2e3ebdSchin 		np->nvalue.cp = (char*)sp;
1394da2e3ebdSchin 		nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE);
1395da2e3ebdSchin 		return;
1396da2e3ebdSchin 	}
1397da2e3ebdSchin 	up= &np->nvalue;
13987c2fbfb3SApril Chin 	if(nv_isattr(np,NV_INT16P) == NV_INT16)
13997c2fbfb3SApril Chin 	{
14007c2fbfb3SApril Chin 		if(!np->nvalue.up || !nv_isarray(np))
14017c2fbfb3SApril Chin 		{
14027c2fbfb3SApril Chin 			up = &u;
14037c2fbfb3SApril Chin 			up->up = &np->nvalue;
14047c2fbfb3SApril Chin 		}
14057c2fbfb3SApril Chin 	}
14067c2fbfb3SApril Chin 	else if(np->nvalue.up && nv_isarray(np) && nv_arrayptr(np))
14077c2fbfb3SApril Chin 		up = np->nvalue.up;
14087c2fbfb3SApril Chin 	if(up && up->cp==Empty)
14097c2fbfb3SApril Chin 		up->cp = 0;
1410da2e3ebdSchin 	if(nv_isattr(np,NV_EXPORT))
1411da2e3ebdSchin 		nv_offattr(np,NV_IMPORT);
1412da2e3ebdSchin 	if(nv_isattr (np, NV_INTEGER))
1413da2e3ebdSchin 	{
14147c2fbfb3SApril Chin 		if(nv_isattr(np, NV_DOUBLE) == NV_DOUBLE)
1415da2e3ebdSchin 		{
1416da2e3ebdSchin 			if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t))
1417da2e3ebdSchin 			{
1418da2e3ebdSchin 				Sfdouble_t ld, old=0;
1419da2e3ebdSchin 				if(flags&NV_INTEGER)
1420da2e3ebdSchin 				{
1421da2e3ebdSchin 					if(flags&NV_LONG)
1422da2e3ebdSchin 						ld = *((Sfdouble_t*)sp);
1423da2e3ebdSchin 					else if(flags&NV_SHORT)
1424da2e3ebdSchin 						ld = *((float*)sp);
1425da2e3ebdSchin 					else
1426da2e3ebdSchin 						ld = *((double*)sp);
1427da2e3ebdSchin 				}
1428da2e3ebdSchin 				else
1429da2e3ebdSchin 					ld = sh_arith(sp);
1430da2e3ebdSchin 				if(!up->ldp)
1431da2e3ebdSchin 					up->ldp = new_of(Sfdouble_t,0);
1432da2e3ebdSchin 				else if(flags&NV_APPEND)
1433da2e3ebdSchin 					old = *(up->ldp);
143434f9b3eeSRoland Mainz 				*(up->ldp) = old?ld+old:ld;
1435da2e3ebdSchin 			}
1436da2e3ebdSchin 			else
1437da2e3ebdSchin 			{
1438da2e3ebdSchin 				double d,od=0;
1439da2e3ebdSchin 				if(flags&NV_INTEGER)
1440da2e3ebdSchin 				{
1441da2e3ebdSchin 					if(flags&NV_LONG)
1442da2e3ebdSchin 						d = (double)(*(Sfdouble_t*)sp);
1443da2e3ebdSchin 					else if(flags&NV_SHORT)
1444da2e3ebdSchin 						d = (double)(*(float*)sp);
1445da2e3ebdSchin 					else
1446da2e3ebdSchin 						d = *(double*)sp;
1447da2e3ebdSchin 				}
1448da2e3ebdSchin 				else
1449da2e3ebdSchin 					d = sh_arith(sp);
1450da2e3ebdSchin 				if(!up->dp)
1451da2e3ebdSchin 					up->dp = new_of(double,0);
1452da2e3ebdSchin 				else if(flags&NV_APPEND)
1453da2e3ebdSchin 					od = *(up->dp);
145434f9b3eeSRoland Mainz 				*(up->dp) = od?d+od:d;
1455da2e3ebdSchin 			}
1456da2e3ebdSchin 		}
1457da2e3ebdSchin 		else
1458da2e3ebdSchin 		{
1459da2e3ebdSchin 			if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t))
1460da2e3ebdSchin 			{
1461da2e3ebdSchin 				Sflong_t ll=0,oll=0;
1462da2e3ebdSchin 				if(flags&NV_INTEGER)
1463da2e3ebdSchin 				{
14647c2fbfb3SApril Chin 					if((flags&NV_DOUBLE) == NV_DOUBLE)
1465da2e3ebdSchin 					{
1466da2e3ebdSchin 						if(flags&NV_LONG)
1467da2e3ebdSchin 							ll = *((Sfdouble_t*)sp);
1468da2e3ebdSchin 						else if(flags&NV_SHORT)
1469da2e3ebdSchin 							ll = *((float*)sp);
1470da2e3ebdSchin 						else
1471da2e3ebdSchin 							ll = *((double*)sp);
1472da2e3ebdSchin 					}
1473da2e3ebdSchin 					else if(nv_isattr(np,NV_UNSIGN))
1474da2e3ebdSchin 					{
1475da2e3ebdSchin 						if(flags&NV_LONG)
1476da2e3ebdSchin 							ll = *((Sfulong_t*)sp);
1477da2e3ebdSchin 						else if(flags&NV_SHORT)
1478da2e3ebdSchin 							ll = *((uint16_t*)sp);
1479da2e3ebdSchin 						else
1480da2e3ebdSchin 							ll = *((uint32_t*)sp);
1481da2e3ebdSchin 					}
1482da2e3ebdSchin 					else
1483da2e3ebdSchin 					{
1484da2e3ebdSchin 						if(flags&NV_LONG)
1485da2e3ebdSchin 							ll = *((Sflong_t*)sp);
1486da2e3ebdSchin 						else if(flags&NV_SHORT)
1487da2e3ebdSchin 							ll = *((uint16_t*)sp);
1488da2e3ebdSchin 						else
1489da2e3ebdSchin 							ll = *((uint32_t*)sp);
1490da2e3ebdSchin 					}
1491da2e3ebdSchin 				}
1492da2e3ebdSchin 				else if(sp)
1493da2e3ebdSchin 					ll = (Sflong_t)sh_arith(sp);
1494da2e3ebdSchin 				if(!up->llp)
1495da2e3ebdSchin 					up->llp = new_of(Sflong_t,0);
1496da2e3ebdSchin 				else if(flags&NV_APPEND)
1497da2e3ebdSchin 					oll = *(up->llp);
1498da2e3ebdSchin 				*(up->llp) = ll+oll;
1499da2e3ebdSchin 			}
1500da2e3ebdSchin 			else
1501da2e3ebdSchin 			{
1502da2e3ebdSchin 				int32_t l=0,ol=0;
1503da2e3ebdSchin 				if(flags&NV_INTEGER)
1504da2e3ebdSchin 				{
15057c2fbfb3SApril Chin 					if((flags&NV_DOUBLE) == NV_DOUBLE)
1506da2e3ebdSchin 					{
1507da2e3ebdSchin 						Sflong_t ll;
1508da2e3ebdSchin 						if(flags&NV_LONG)
1509da2e3ebdSchin 							ll = *((Sfdouble_t*)sp);
1510da2e3ebdSchin 						else if(flags&NV_SHORT)
1511da2e3ebdSchin 							ll = *((float*)sp);
1512da2e3ebdSchin 						else
1513da2e3ebdSchin 							ll = *((double*)sp);
1514da2e3ebdSchin 						l = (int32_t)ll;
1515da2e3ebdSchin 					}
1516da2e3ebdSchin 					else if(nv_isattr(np,NV_UNSIGN))
1517da2e3ebdSchin 					{
1518da2e3ebdSchin 						if(flags&NV_LONG)
1519da2e3ebdSchin 							l = *((Sfulong_t*)sp);
1520da2e3ebdSchin 						else if(flags&NV_SHORT)
1521da2e3ebdSchin 							l = *((uint16_t*)sp);
1522da2e3ebdSchin 						else
1523da2e3ebdSchin 							l = *(uint32_t*)sp;
1524da2e3ebdSchin 					}
1525da2e3ebdSchin 					else
1526da2e3ebdSchin 					{
1527da2e3ebdSchin 						if(flags&NV_LONG)
1528da2e3ebdSchin 							l = *((Sflong_t*)sp);
1529da2e3ebdSchin 						else if(flags&NV_SHORT)
1530da2e3ebdSchin 							l = *((int16_t*)sp);
1531da2e3ebdSchin 						else
1532da2e3ebdSchin 							l = *(int32_t*)sp;
1533da2e3ebdSchin 					}
1534da2e3ebdSchin 				}
1535da2e3ebdSchin 				else if(sp)
1536da2e3ebdSchin 				{
1537da2e3ebdSchin 					Sfdouble_t ld = sh_arith(sp);
1538da2e3ebdSchin 					if(ld<0)
1539da2e3ebdSchin 						l = (int32_t)ld;
1540da2e3ebdSchin 					else
1541da2e3ebdSchin 						l = (uint32_t)ld;
1542da2e3ebdSchin 				}
1543da2e3ebdSchin 				if(nv_size(np) <= 1)
1544da2e3ebdSchin 					nv_setsize(np,10);
1545da2e3ebdSchin 				if(nv_isattr (np, NV_SHORT))
1546da2e3ebdSchin 				{
1547da2e3ebdSchin 					int16_t s=0;
1548da2e3ebdSchin 					if(flags&NV_APPEND)
15497c2fbfb3SApril Chin 						s = *up->sp;
15507c2fbfb3SApril Chin 					*(up->sp) = s+(int16_t)l;
1551da2e3ebdSchin 					nv_onattr(np,NV_NOFREE);
1552da2e3ebdSchin 				}
1553da2e3ebdSchin 				else
1554da2e3ebdSchin 				{
1555da2e3ebdSchin 					if(!up->lp)
1556da2e3ebdSchin 						up->lp = new_of(int32_t,0);
1557da2e3ebdSchin 					else if(flags&NV_APPEND)
1558da2e3ebdSchin 						ol =  *(up->lp);
1559da2e3ebdSchin 					*(up->lp) = l+ol;
1560da2e3ebdSchin 				}
1561da2e3ebdSchin 			}
1562da2e3ebdSchin 		}
1563da2e3ebdSchin 	}
1564da2e3ebdSchin 	else
1565da2e3ebdSchin 	{
1566da2e3ebdSchin 		const char *tofree=0;
1567da2e3ebdSchin 		int offset;
1568da2e3ebdSchin #if _lib_pathnative
1569da2e3ebdSchin 		char buff[PATH_MAX];
1570da2e3ebdSchin #endif /* _lib_pathnative */
1571da2e3ebdSchin 		if(flags&NV_INTEGER)
1572da2e3ebdSchin 		{
15737c2fbfb3SApril Chin 			if((flags&NV_DOUBLE)==NV_DOUBLE)
1574da2e3ebdSchin 			{
1575da2e3ebdSchin 				if(flags&NV_LONG)
1576da2e3ebdSchin 					sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp));
1577da2e3ebdSchin 				else
1578da2e3ebdSchin 					sfprintf(sh.strbuf,"%.*g",DBL_DIG,*((double*)sp));
1579da2e3ebdSchin 			}
15807c2fbfb3SApril Chin 			else if(flags&NV_UNSIGN)
15817c2fbfb3SApril Chin 			{
15827c2fbfb3SApril Chin 				if(flags&NV_LONG)
15837c2fbfb3SApril Chin 					sfprintf(sh.strbuf,"%I*lu",sizeof(Sfulong_t),*((Sfulong_t*)sp));
1584da2e3ebdSchin 				else
15857c2fbfb3SApril Chin 					sfprintf(sh.strbuf,"%lu",(unsigned long)((flags&NV_SHORT)?*((uint16_t*)sp):*((uint32_t*)sp)));
15867c2fbfb3SApril Chin 			}
15877c2fbfb3SApril Chin 			else
15887c2fbfb3SApril Chin 			{
15897c2fbfb3SApril Chin 				if(flags&NV_LONG)
15907c2fbfb3SApril Chin 					sfprintf(sh.strbuf,"%I*ld",sizeof(Sflong_t),*((Sflong_t*)sp));
15917c2fbfb3SApril Chin 				else
15927c2fbfb3SApril Chin 					sfprintf(sh.strbuf,"%ld",(long)((flags&NV_SHORT)?*((int16_t*)sp):*((int32_t*)sp)));
15937c2fbfb3SApril Chin 			}
1594da2e3ebdSchin 			sp = sfstruse(sh.strbuf);
1595da2e3ebdSchin 		}
15967c2fbfb3SApril Chin 		if(nv_isattr(np, NV_HOST|NV_INTEGER)==NV_HOST && sp)
1597da2e3ebdSchin 		{
1598da2e3ebdSchin #ifdef _lib_pathnative
1599da2e3ebdSchin 			/*
1600da2e3ebdSchin 			 * return the host file name given the UNIX name
1601da2e3ebdSchin 			 */
1602da2e3ebdSchin 			pathnative(sp,buff,sizeof(buff));
1603da2e3ebdSchin 			if(buff[1]==':' && buff[2]=='/')
1604da2e3ebdSchin 			{
1605da2e3ebdSchin 				buff[2] = '\\';
1606da2e3ebdSchin 				if(*buff>='A' &&  *buff<='Z')
1607da2e3ebdSchin 					*buff += 'a'-'A';
1608da2e3ebdSchin 			}
1609da2e3ebdSchin 			sp = buff;
1610da2e3ebdSchin #else
1611da2e3ebdSchin 			;
1612da2e3ebdSchin #endif /* _lib_pathnative */
1613da2e3ebdSchin 		}
1614da2e3ebdSchin 		else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
1615da2e3ebdSchin 		{
1616da2e3ebdSchin 			for(;*sp == ' '|| *sp=='\t';sp++);
1617da2e3ebdSchin 	        	if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST)))
1618da2e3ebdSchin 				for(;*sp=='0';sp++);
1619da2e3ebdSchin 			size = nv_size(np);
1620da2e3ebdSchin #if SHOPT_MULTIBYTE
1621da2e3ebdSchin 			if(size)
1622da2e3ebdSchin 				size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL));
1623da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1624da2e3ebdSchin 		}
1625da2e3ebdSchin 		if(!up->cp)
1626da2e3ebdSchin 			flags &= ~NV_APPEND;
1627da2e3ebdSchin 		if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY))
1628da2e3ebdSchin 		{
1629da2e3ebdSchin 			offset = staktell();
1630da2e3ebdSchin 			stakputs(up->cp);
1631da2e3ebdSchin 			stakputs(sp);
1632da2e3ebdSchin 			stakputc(0);
1633da2e3ebdSchin 			sp = stakptr(offset);
1634da2e3ebdSchin 		}
1635da2e3ebdSchin 		if(!nv_isattr(np, NV_NOFREE))
1636da2e3ebdSchin 		{
1637da2e3ebdSchin 			/* delay free in case <sp> points into free region */
1638da2e3ebdSchin 			tofree = up->cp;
1639da2e3ebdSchin 		}
16407c2fbfb3SApril Chin 		if(nv_isattr(np,NV_BINARY) && !(flags&NV_RAW))
16417c2fbfb3SApril Chin 			tofree = 0;
1642*3e14f97fSRoger A. Faulkner 		if(nv_isattr(np,NV_LJUST|NV_RJUST) && nv_isattr(np,NV_LJUST|NV_RJUST)!=(NV_LJUST|NV_RJUST))
16437c2fbfb3SApril Chin 			tofree = 0;
1644da2e3ebdSchin        	 	if (sp)
1645da2e3ebdSchin 		{
1646da2e3ebdSchin 			dot = strlen(sp);
1647da2e3ebdSchin #if (_AST_VERSION>=20030127L)
1648da2e3ebdSchin 			if(nv_isattr(np,NV_BINARY))
1649da2e3ebdSchin 			{
1650da2e3ebdSchin 				int oldsize = (flags&NV_APPEND)?nv_size(np):0;
1651da2e3ebdSchin 				if(flags&NV_RAW)
1652da2e3ebdSchin 				{
1653da2e3ebdSchin 					if(tofree)
16547c2fbfb3SApril Chin 					{
1655da2e3ebdSchin 						free((void*)tofree);
16567c2fbfb3SApril Chin 						nv_offattr(np,NV_NOFREE);
16577c2fbfb3SApril Chin 					}
1658da2e3ebdSchin 					up->cp = sp;
1659da2e3ebdSchin 					return;
1660da2e3ebdSchin 				}
1661da2e3ebdSchin 				size = 0;
1662da2e3ebdSchin 				if(nv_isattr(np,NV_ZFILL))
1663da2e3ebdSchin 					size = nv_size(np);
1664da2e3ebdSchin 				if(size==0)
1665da2e3ebdSchin 					size = oldsize + (3*dot/4);
1666da2e3ebdSchin 				cp = (char*)malloc(size+1);
16677c2fbfb3SApril Chin 				nv_offattr(np,NV_NOFREE);
1668da2e3ebdSchin 				if(oldsize)
1669da2e3ebdSchin 					memcpy((void*)cp,(void*)up->cp,oldsize);
1670da2e3ebdSchin 				up->cp = cp;
1671da2e3ebdSchin 				if(size <= oldsize)
1672da2e3ebdSchin 					return;
1673da2e3ebdSchin 				dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0);
1674da2e3ebdSchin 				dot += oldsize;
1675da2e3ebdSchin 				if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0)
1676da2e3ebdSchin 					nv_setsize(np,dot);
1677da2e3ebdSchin 				else if(nv_isattr(np,NV_ZFILL) && (size>dot))
1678da2e3ebdSchin 					memset((void*)&cp[dot],0,size-dot);
1679da2e3ebdSchin 				return;
1680da2e3ebdSchin 			}
1681da2e3ebdSchin 			else
1682da2e3ebdSchin #endif
1683*3e14f97fSRoger A. Faulkner 			if(size==0 && nv_isattr(np,NV_HOST)!=NV_HOST &&nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
1684da2e3ebdSchin 				nv_setsize(np,size=dot);
1685da2e3ebdSchin 			else if(size > dot)
1686da2e3ebdSchin 				dot = size;
1687*3e14f97fSRoger A. Faulkner 			else if(nv_isattr(np,NV_LJUST|NV_RJUST)==NV_LJUST && dot>size)
16887c2fbfb3SApril Chin 				dot = size;
16897c2fbfb3SApril Chin 			if(size==0 || tofree || !(cp=(char*)up->cp))
16907c2fbfb3SApril Chin 			{
1691da2e3ebdSchin 				cp = (char*)malloc(((unsigned)dot+1));
16927c2fbfb3SApril Chin 				cp[dot] = 0;
16937c2fbfb3SApril Chin 				nv_offattr(np,NV_NOFREE);
16947c2fbfb3SApril Chin 			}
16957c2fbfb3SApril Chin 
1696da2e3ebdSchin 		}
1697da2e3ebdSchin 		else
1698da2e3ebdSchin 			cp = 0;
1699da2e3ebdSchin 		up->cp = cp;
1700da2e3ebdSchin 		if(sp)
1701da2e3ebdSchin 		{
17027c2fbfb3SApril Chin 			int c = cp[dot];
17037c2fbfb3SApril Chin 			memcpy(cp,sp,dot);
17047c2fbfb3SApril Chin 			cp[dot]=0;
1705da2e3ebdSchin 			if(nv_isattr(np, NV_LTOU))
17067c2fbfb3SApril Chin 				ltou(cp);
1707da2e3ebdSchin 			else if(nv_isattr (np, NV_UTOL))
17087c2fbfb3SApril Chin 				utol(cp);
17097c2fbfb3SApril Chin 			cp[dot] = c;
1710da2e3ebdSchin 			if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL))
1711da2e3ebdSchin 				rightjust(cp,size,'0');
1712*3e14f97fSRoger A. Faulkner 			else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_RJUST)
1713da2e3ebdSchin 				rightjust(cp,size,' ');
1714*3e14f97fSRoger A. Faulkner 			else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_LJUST)
1715da2e3ebdSchin 			{
1716da2e3ebdSchin 				register char *dp;
1717da2e3ebdSchin 				dp = strlen (cp) + cp;
17187c2fbfb3SApril Chin 				cp = cp+size;
1719da2e3ebdSchin 				for (; dp < cp; *dp++ = ' ');
1720da2e3ebdSchin 			 }
1721da2e3ebdSchin #if SHOPT_MULTIBYTE
1722da2e3ebdSchin 			/* restore original string */
1723da2e3ebdSchin 			if(savep)
1724da2e3ebdSchin 				ja_restore();
1725da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1726da2e3ebdSchin 		}
1727da2e3ebdSchin 		if(flags&NV_APPEND)
1728da2e3ebdSchin 			stakseek(offset);
17297c2fbfb3SApril Chin 		if(tofree && tofree!=Empty)
1730da2e3ebdSchin 			free((void*)tofree);
1731da2e3ebdSchin 	}
1732da2e3ebdSchin 	if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1733da2e3ebdSchin 		sh_envput(sh.env,np);
1734da2e3ebdSchin 	return;
1735da2e3ebdSchin }
1736da2e3ebdSchin 
1737da2e3ebdSchin /*
1738da2e3ebdSchin  *
1739da2e3ebdSchin  *   Right-justify <str> so that it contains no more than
1740da2e3ebdSchin  *   <size> characters.  If <str> contains fewer than <size>
1741da2e3ebdSchin  *   characters, left-pad with <fill>.  Trailing blanks
1742da2e3ebdSchin  *   in <str> will be ignored.
1743da2e3ebdSchin  *
1744da2e3ebdSchin  *   If the leftmost digit in <str> is not a digit, <fill>
1745da2e3ebdSchin  *   will default to a blank.
1746da2e3ebdSchin  */
rightjust(char * str,int size,int fill)1747da2e3ebdSchin static void rightjust(char *str, int size, int fill)
1748da2e3ebdSchin {
1749da2e3ebdSchin 	register int n;
1750da2e3ebdSchin 	register char *cp,*sp;
1751da2e3ebdSchin 	n = strlen(str);
1752da2e3ebdSchin 
1753da2e3ebdSchin 	/* ignore trailing blanks */
1754da2e3ebdSchin 	for(cp=str+n;n && *--cp == ' ';n--);
1755da2e3ebdSchin 	if (n == size)
1756da2e3ebdSchin 		return;
1757da2e3ebdSchin 	if(n > size)
1758da2e3ebdSchin         {
1759da2e3ebdSchin         	*(str+n) = 0;
1760da2e3ebdSchin         	for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
1761da2e3ebdSchin         	return;
1762da2e3ebdSchin         }
1763da2e3ebdSchin 	else *(sp = str+size) = 0;
1764da2e3ebdSchin 	if (n == 0)
1765da2e3ebdSchin         {
1766da2e3ebdSchin         	while (sp > str)
1767da2e3ebdSchin                		*--sp = ' ';
1768da2e3ebdSchin         	return;
1769da2e3ebdSchin         }
1770da2e3ebdSchin 	while(n--)
1771da2e3ebdSchin 	{
1772da2e3ebdSchin 		sp--;
1773da2e3ebdSchin 		*sp = *cp--;
1774da2e3ebdSchin 	}
1775da2e3ebdSchin 	if(!isdigit(*str))
1776da2e3ebdSchin 		fill = ' ';
1777da2e3ebdSchin 	while(sp>str)
1778da2e3ebdSchin 		*--sp = fill;
1779da2e3ebdSchin 	return;
1780da2e3ebdSchin }
1781da2e3ebdSchin 
1782da2e3ebdSchin #if SHOPT_MULTIBYTE
1783da2e3ebdSchin     /*
1784da2e3ebdSchin      * handle left and right justified fields for multi-byte chars
1785da2e3ebdSchin      * given physical size, return a logical size which reflects the
1786da2e3ebdSchin      * screen width of multi-byte characters
1787da2e3ebdSchin      * Multi-width characters replaced by spaces if they cross the boundary
1788da2e3ebdSchin      * <type> is non-zero for right justified  fields
1789da2e3ebdSchin      */
1790da2e3ebdSchin 
ja_size(char * str,int size,int type)1791da2e3ebdSchin     static int ja_size(char *str,int size,int type)
1792da2e3ebdSchin     {
1793da2e3ebdSchin 	register char *cp = str;
1794da2e3ebdSchin 	register int c, n=size;
1795da2e3ebdSchin 	register int outsize;
1796da2e3ebdSchin 	register char *oldcp=cp;
1797da2e3ebdSchin 	int oldn;
1798da2e3ebdSchin 	wchar_t w;
1799da2e3ebdSchin 	while(*cp)
1800da2e3ebdSchin 	{
1801da2e3ebdSchin 		oldn = n;
1802da2e3ebdSchin 		w = mbchar(cp);
1803da2e3ebdSchin 		outsize = mbwidth(w);
1804da2e3ebdSchin 		size -= outsize;
1805da2e3ebdSchin 		c = cp-oldcp;
1806da2e3ebdSchin 		n += (c-outsize);
1807da2e3ebdSchin 		oldcp = cp;
1808da2e3ebdSchin 		if(size<=0 && type==0)
1809da2e3ebdSchin 			break;
1810da2e3ebdSchin 	}
1811da2e3ebdSchin 	/* check for right justified fields that need truncating */
1812da2e3ebdSchin 	if(size <0)
1813da2e3ebdSchin 	{
1814da2e3ebdSchin 		if(type==0)
1815da2e3ebdSchin 		{
1816da2e3ebdSchin 			/* left justified and character crosses field boundary */
1817da2e3ebdSchin 			n = oldn;
1818da2e3ebdSchin 			/* save boundary char and replace with spaces */
1819da2e3ebdSchin 			size = c;
1820da2e3ebdSchin 			savechars[size] = 0;
1821da2e3ebdSchin 			while(size--)
1822da2e3ebdSchin 			{
1823da2e3ebdSchin 				savechars[size] = cp[size];
1824da2e3ebdSchin 				cp[size] = ' ';
1825da2e3ebdSchin 			}
1826da2e3ebdSchin 			savep = cp;
1827da2e3ebdSchin 		}
1828da2e3ebdSchin 		size = -size;
1829da2e3ebdSchin 		if(type)
1830da2e3ebdSchin 			n -= (ja_size(str,size,0)-size);
1831da2e3ebdSchin 	}
1832da2e3ebdSchin 	return(n);
1833da2e3ebdSchin     }
1834da2e3ebdSchin 
ja_restore(void)1835da2e3ebdSchin     static void ja_restore(void)
1836da2e3ebdSchin     {
1837da2e3ebdSchin 	register char *cp = savechars;
1838da2e3ebdSchin 	while(*cp)
1839da2e3ebdSchin 		*savep++ = *cp++;
1840da2e3ebdSchin 	savep = 0;
1841da2e3ebdSchin     }
1842da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1843da2e3ebdSchin 
1844da2e3ebdSchin #ifndef _ENV_H
staknam(register Namval_t * np,char * value)1845da2e3ebdSchin static char *staknam(register Namval_t *np, char *value)
1846da2e3ebdSchin {
1847da2e3ebdSchin 	register char *p,*q;
1848da2e3ebdSchin 	q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2);
1849da2e3ebdSchin 	p=strcopy(q,nv_name(np));
1850da2e3ebdSchin 	if(value)
1851da2e3ebdSchin 	{
1852da2e3ebdSchin 		*p++ = '=';
1853da2e3ebdSchin 		strcpy(p,value);
1854da2e3ebdSchin 	}
1855da2e3ebdSchin 	return(q);
1856da2e3ebdSchin }
1857da2e3ebdSchin #endif
1858da2e3ebdSchin 
1859da2e3ebdSchin /*
1860da2e3ebdSchin  * put the name and attribute into value of attributes variable
1861da2e3ebdSchin  */
1862da2e3ebdSchin #ifdef _ENV_H
attstore(register Namval_t * np,void * data)1863da2e3ebdSchin static void attstore(register Namval_t *np, void *data)
1864da2e3ebdSchin {
1865da2e3ebdSchin 	register int flag, c = ' ';
1866da2e3ebdSchin 	NOT_USED(data);
1867da2e3ebdSchin 	if(!(nv_isattr(np,NV_EXPORT)))
1868da2e3ebdSchin 		return;
1869da2e3ebdSchin 	flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
1870da2e3ebdSchin 	stakputc('=');
18717c2fbfb3SApril Chin 	if((flag&NV_DOUBLE) == NV_DOUBLE)
1872da2e3ebdSchin 	{
1873da2e3ebdSchin 		/* export doubles as integers for ksh88 compatibility */
18747c2fbfb3SApril Chin 		stakputc(c+NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE)));
1875da2e3ebdSchin 	}
1876da2e3ebdSchin 	else
1877da2e3ebdSchin 	{
1878da2e3ebdSchin 		stakputc(c+flag);
1879da2e3ebdSchin 		if(flag&NV_INTEGER)
1880da2e3ebdSchin 			c +=  nv_size(np);
1881da2e3ebdSchin 	}
1882da2e3ebdSchin 	stakputc(c);
1883da2e3ebdSchin 	stakputs(nv_name(np));
1884da2e3ebdSchin }
1885da2e3ebdSchin #else
attstore(register Namval_t * np,void * data)1886da2e3ebdSchin static void attstore(register Namval_t *np, void *data)
1887da2e3ebdSchin {
1888da2e3ebdSchin 	register int flag = np->nvflag;
1889da2e3ebdSchin 	register struct adata *ap = (struct adata*)data;
18907c2fbfb3SApril Chin 	ap->sh = &sh;
18917c2fbfb3SApril Chin 	ap->tp = 0;
1892da2e3ebdSchin 	if(!(flag&NV_EXPORT) || (flag&NV_FUNCT))
1893da2e3ebdSchin 		return;
1894da2e3ebdSchin 	flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
1895da2e3ebdSchin 	*ap->attval++ = '=';
18967c2fbfb3SApril Chin 	if((flag&NV_DOUBLE) == NV_DOUBLE)
1897da2e3ebdSchin 	{
1898da2e3ebdSchin 		/* export doubles as integers for ksh88 compatibility */
18997c2fbfb3SApril Chin 		*ap->attval++ = ' '+ NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE));
1900da2e3ebdSchin 		*ap->attval = ' ';
1901da2e3ebdSchin 	}
1902da2e3ebdSchin 	else
1903da2e3ebdSchin 	{
1904da2e3ebdSchin 		*ap->attval++ = ' '+flag;
1905da2e3ebdSchin 		if(flag&NV_INTEGER)
1906da2e3ebdSchin 			*ap->attval = ' ' + nv_size(np);
1907da2e3ebdSchin 		else
1908da2e3ebdSchin 			*ap->attval = ' ';
1909da2e3ebdSchin 	}
1910da2e3ebdSchin 	ap->attval = strcopy(++ap->attval,nv_name(np));
1911da2e3ebdSchin }
1912da2e3ebdSchin #endif
1913da2e3ebdSchin 
1914da2e3ebdSchin #ifndef _ENV_H
pushnam(Namval_t * np,void * data)1915da2e3ebdSchin static void pushnam(Namval_t *np, void *data)
1916da2e3ebdSchin {
1917da2e3ebdSchin 	register char *value;
1918da2e3ebdSchin 	register struct adata *ap = (struct adata*)data;
19197c2fbfb3SApril Chin 	ap->sh = &sh;
19207c2fbfb3SApril Chin 	ap->tp = 0;
1921*3e14f97fSRoger A. Faulkner 	if(nv_isattr(np,NV_IMPORT) && np->nvenv)
1922da2e3ebdSchin 		*ap->argnam++ = np->nvenv;
1923da2e3ebdSchin 	else if(value=nv_getval(np))
1924da2e3ebdSchin 		*ap->argnam++ = staknam(np,value);
1925da2e3ebdSchin 	if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER))
1926da2e3ebdSchin 		ap->attsize += (strlen(nv_name(np))+4);
1927da2e3ebdSchin }
1928da2e3ebdSchin #endif
1929da2e3ebdSchin 
1930da2e3ebdSchin /*
1931da2e3ebdSchin  * Generate the environment list for the child.
1932da2e3ebdSchin  */
1933da2e3ebdSchin 
1934da2e3ebdSchin #ifdef _ENV_H
sh_envgen(void)1935da2e3ebdSchin char **sh_envgen(void)
1936da2e3ebdSchin {
1937da2e3ebdSchin 	int offset,tell;
1938da2e3ebdSchin 	register char **er;
1939da2e3ebdSchin 	env_delete(sh.env,"_");
1940da2e3ebdSchin 	er = env_get(sh.env);
1941da2e3ebdSchin 	offset = staktell();
1942da2e3ebdSchin 	stakputs(e_envmarker);
1943da2e3ebdSchin 	tell = staktell();
1944da2e3ebdSchin 	nv_scan(sh.var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
1945da2e3ebdSchin 	if(tell ==staktell())
1946da2e3ebdSchin 		stakseek(offset);
1947da2e3ebdSchin 	else
1948da2e3ebdSchin 		*--er = stakfreeze(1)+offset;
1949da2e3ebdSchin 	return(er);
1950da2e3ebdSchin }
1951da2e3ebdSchin #else
sh_envgen(void)1952da2e3ebdSchin char **sh_envgen(void)
1953da2e3ebdSchin {
1954da2e3ebdSchin 	register char **er;
1955da2e3ebdSchin 	register int namec;
1956da2e3ebdSchin 	register char *cp;
1957da2e3ebdSchin 	struct adata data;
19587c2fbfb3SApril Chin 	Shell_t	*shp = sh_getinterp();
19597c2fbfb3SApril Chin 	data.sh = shp;
19607c2fbfb3SApril Chin 	data.tp = 0;
1961da2e3ebdSchin 	/* L_ARGNOD gets generated automatically as full path name of command */
1962da2e3ebdSchin 	nv_offattr(L_ARGNOD,NV_EXPORT);
1963da2e3ebdSchin 	data.attsize = 6;
19647c2fbfb3SApril Chin 	namec = nv_scan(shp->var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT);
19657c2fbfb3SApril Chin 	namec += shp->nenv;
1966da2e3ebdSchin 	er = (char**)stakalloc((namec+4)*sizeof(char*));
19677c2fbfb3SApril Chin 	data.argnam = (er+=2) + shp->nenv;
19687c2fbfb3SApril Chin 	if(shp->nenv)
19697c2fbfb3SApril Chin 		memcpy((void*)er,environ,shp->nenv*sizeof(char*));
19707c2fbfb3SApril Chin 	nv_scan(shp->var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT);
1971da2e3ebdSchin 	*data.argnam = (char*)stakalloc(data.attsize);
1972da2e3ebdSchin 	cp = data.attval = strcopy(*data.argnam,e_envmarker);
19737c2fbfb3SApril Chin 	nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
1974da2e3ebdSchin 	*data.attval = 0;
1975da2e3ebdSchin 	if(cp!=data.attval)
1976da2e3ebdSchin 		data.argnam++;
1977da2e3ebdSchin 	*data.argnam = 0;
1978da2e3ebdSchin 	return(er);
1979da2e3ebdSchin }
1980da2e3ebdSchin #endif
1981da2e3ebdSchin 
1982da2e3ebdSchin struct scan
1983da2e3ebdSchin {
1984da2e3ebdSchin 	void    (*scanfn)(Namval_t*, void*);
1985da2e3ebdSchin 	int     scanmask;
1986da2e3ebdSchin 	int     scanflags;
1987da2e3ebdSchin 	int     scancount;
1988da2e3ebdSchin 	void    *scandata;
1989da2e3ebdSchin };
1990da2e3ebdSchin 
scanfilter(Dt_t * dict,void * arg,void * data)1991da2e3ebdSchin static int scanfilter(Dt_t *dict, void *arg, void *data)
1992da2e3ebdSchin {
1993da2e3ebdSchin 	register Namval_t *np = (Namval_t*)arg;
1994da2e3ebdSchin 	register int k=np->nvflag;
1995da2e3ebdSchin 	register struct scan *sp = (struct scan*)data;
19967c2fbfb3SApril Chin 	register struct adata *tp = (struct adata*)sp->scandata;
1997da2e3ebdSchin 	NOT_USED(dict);
19987c2fbfb3SApril Chin #if SHOPT_TYPEDEF
1999*3e14f97fSRoger A. Faulkner 	if(!is_abuiltin(np) && tp && tp->tp && nv_type(np)!=tp->tp)
20007c2fbfb3SApril Chin 		return(0);
20017c2fbfb3SApril Chin #endif /*SHOPT_TYPEDEF */
2002da2e3ebdSchin 	if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags)))
2003da2e3ebdSchin 	{
20047c2fbfb3SApril Chin 		if(!np->nvalue.cp && !np->nvfun && !nv_isattr(np,~NV_DEFAULT))
2005da2e3ebdSchin 			return(0);
2006da2e3ebdSchin 		if(sp->scanfn)
2007da2e3ebdSchin 		{
2008da2e3ebdSchin 			if(nv_isarray(np))
2009da2e3ebdSchin 				nv_putsub(np,NIL(char*),0L);
2010da2e3ebdSchin 			(*sp->scanfn)(np,sp->scandata);
2011da2e3ebdSchin 		}
2012da2e3ebdSchin 		sp->scancount++;
2013da2e3ebdSchin 	}
2014da2e3ebdSchin 	return(0);
2015da2e3ebdSchin }
2016da2e3ebdSchin 
2017da2e3ebdSchin /*
2018da2e3ebdSchin  * Walk through the name-value pairs
2019da2e3ebdSchin  * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
2020da2e3ebdSchin  *	are visited
2021da2e3ebdSchin  * If <mask> is zero, and <flags> non-zero, then nodes with one or
2022da2e3ebdSchin  *	more of <flags> is visited
2023da2e3ebdSchin  * If <mask> and <flags> are zero, then all nodes are visted
2024da2e3ebdSchin  */
nv_scan(Dt_t * root,void (* fn)(Namval_t *,void *),void * data,int mask,int flags)2025da2e3ebdSchin int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags)
2026da2e3ebdSchin {
2027da2e3ebdSchin 	Dt_t *base=0;
2028da2e3ebdSchin 	struct scan sdata;
2029da2e3ebdSchin 	int (*hashfn)(Dt_t*, void*, void*);
2030da2e3ebdSchin 	sdata.scanmask = mask;
2031da2e3ebdSchin 	sdata.scanflags = flags&~NV_NOSCOPE;
2032da2e3ebdSchin 	sdata.scanfn = fn;
2033da2e3ebdSchin 	sdata.scancount = 0;
2034da2e3ebdSchin 	sdata.scandata = data;
2035da2e3ebdSchin 	hashfn = scanfilter;
2036da2e3ebdSchin 	if(flags&NV_NOSCOPE)
2037da2e3ebdSchin 		base = dtview((Dt_t*)root,0);
2038da2e3ebdSchin 	dtwalk(root, hashfn,&sdata);
2039da2e3ebdSchin 	if(base)
2040da2e3ebdSchin 		 dtview((Dt_t*)root,base);
2041da2e3ebdSchin 	return(sdata.scancount);
2042da2e3ebdSchin }
2043da2e3ebdSchin 
2044da2e3ebdSchin /*
2045da2e3ebdSchin  * create a new environment scope
2046da2e3ebdSchin  */
sh_scope(Shell_t * shp,struct argnod * envlist,int fun)20477c2fbfb3SApril Chin void sh_scope(Shell_t *shp, struct argnod *envlist, int fun)
2048da2e3ebdSchin {
20497c2fbfb3SApril Chin 	register Dt_t		*newscope, *newroot=shp->var_base;
20507c2fbfb3SApril Chin 	struct Ufunction	*rp;
2051da2e3ebdSchin 	newscope = dtopen(&_Nvdisc,Dtoset);
2052da2e3ebdSchin 	if(envlist)
20537c2fbfb3SApril Chin 	{
20547c2fbfb3SApril Chin 		dtview(newscope,(Dt_t*)shp->var_tree);
20557c2fbfb3SApril Chin 		shp->var_tree = newscope;
205634f9b3eeSRoland Mainz 		nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN,0);
20577c2fbfb3SApril Chin 		if(!fun)
20587c2fbfb3SApril Chin 			return;
20597c2fbfb3SApril Chin 		shp->var_tree = dtview(newscope,0);
20607c2fbfb3SApril Chin 	}
20617c2fbfb3SApril Chin 	if((rp=shp->st.real_fun)  && rp->sdict)
20627c2fbfb3SApril Chin 	{
20637c2fbfb3SApril Chin 		dtview(rp->sdict,newroot);
20647c2fbfb3SApril Chin 		newroot = rp->sdict;
20657c2fbfb3SApril Chin 
20667c2fbfb3SApril Chin 	}
20677c2fbfb3SApril Chin 	dtview(newscope,(Dt_t*)newroot);
20687c2fbfb3SApril Chin 	shp->var_tree = newscope;
2069da2e3ebdSchin }
2070da2e3ebdSchin 
2071da2e3ebdSchin /*
2072da2e3ebdSchin  * Remove freeable local space associated with the nvalue field
2073da2e3ebdSchin  * of nnod. This includes any strings representing the value(s) of the
2074da2e3ebdSchin  * node, as well as its dope vector, if it is an array.
2075da2e3ebdSchin  */
2076da2e3ebdSchin 
sh_envnolocal(register Namval_t * np,void * data)2077da2e3ebdSchin void	sh_envnolocal (register Namval_t *np, void *data)
2078da2e3ebdSchin {
2079da2e3ebdSchin 	char *cp=0;
2080da2e3ebdSchin 	NOT_USED(data);
208134f9b3eeSRoland Mainz 	if(np==VERSIONNOD && nv_isref(np))
208234f9b3eeSRoland Mainz 		return;
208334f9b3eeSRoland Mainz 	if(np==L_ARGNOD)
208434f9b3eeSRoland Mainz 		return;
2085da2e3ebdSchin 	if(nv_isattr(np,NV_EXPORT) && nv_isarray(np))
2086da2e3ebdSchin 	{
2087da2e3ebdSchin 		nv_putsub(np,NIL(char*),0);
2088da2e3ebdSchin 		if(cp = nv_getval(np))
2089da2e3ebdSchin 			cp = strdup(cp);
2090da2e3ebdSchin 	}
2091da2e3ebdSchin 	if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
2092da2e3ebdSchin 	{
209334f9b3eeSRoland Mainz 		if(nv_isref(np) && np!=VERSIONNOD)
2094da2e3ebdSchin 		{
2095da2e3ebdSchin 			nv_offattr(np,NV_NOFREE|NV_REF);
2096da2e3ebdSchin 			free((void*)np->nvalue.nrp);
2097da2e3ebdSchin 			np->nvalue.cp = 0;
2098da2e3ebdSchin 		}
2099da2e3ebdSchin 		if(!cp)
2100da2e3ebdSchin 			return;
2101da2e3ebdSchin 	}
2102da2e3ebdSchin 	if(nv_isarray(np))
2103da2e3ebdSchin 		nv_putsub(np,NIL(char*),ARRAY_UNDEF);
2104da2e3ebdSchin 	_nv_unset(np,NV_RDONLY);
2105da2e3ebdSchin 	nv_setattr(np,0);
2106da2e3ebdSchin 	if(cp)
2107da2e3ebdSchin 	{
2108da2e3ebdSchin 		nv_putval(np,cp,0);
2109da2e3ebdSchin 		free((void*)cp);
2110da2e3ebdSchin 	}
2111da2e3ebdSchin }
2112da2e3ebdSchin 
2113da2e3ebdSchin /*
2114da2e3ebdSchin  * Currently this is a dummy, but someday will be needed
2115da2e3ebdSchin  * for reference counting
2116da2e3ebdSchin  */
nv_close(Namval_t * np)2117da2e3ebdSchin void	nv_close(Namval_t *np)
2118da2e3ebdSchin {
2119da2e3ebdSchin 	NOT_USED(np);
2120da2e3ebdSchin }
2121da2e3ebdSchin 
table_unset(Shell_t * shp,register Dt_t * root,int flags,Dt_t * oroot)21227c2fbfb3SApril Chin static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroot)
2123da2e3ebdSchin {
21247c2fbfb3SApril Chin 	register Namval_t *np,*nq, *npnext;
21257c2fbfb3SApril Chin 	for(np=(Namval_t*)dtfirst(root);np;np=npnext)
2126da2e3ebdSchin 	{
21277c2fbfb3SApril Chin 		if(nv_isref(np))
212834f9b3eeSRoland Mainz 		{
212934f9b3eeSRoland Mainz 			free((void*)np->nvalue.nrp);
213034f9b3eeSRoland Mainz 			np->nvalue.cp = 0;
213134f9b3eeSRoland Mainz 			np->nvflag = 0;
213234f9b3eeSRoland Mainz 		}
21337c2fbfb3SApril Chin 		if(nq=dtsearch(oroot,np))
21347c2fbfb3SApril Chin 		{
21357c2fbfb3SApril Chin 			if(nv_cover(nq))
21367c2fbfb3SApril Chin 			{
21377c2fbfb3SApril Chin 				int subshell = shp->subshell;
21387c2fbfb3SApril Chin 				shp->subshell = 0;
21397c2fbfb3SApril Chin 				if(nv_isattr(nq, NV_INTEGER))
21407c2fbfb3SApril Chin 				{
21417c2fbfb3SApril Chin 					Sfdouble_t d = nv_getnum(nq);
21427c2fbfb3SApril Chin 					nv_putval(nq,(char*)&d,NV_LDOUBLE);
21437c2fbfb3SApril Chin 				}
214434f9b3eeSRoland Mainz 				else if(shp->test&4)
214534f9b3eeSRoland Mainz 					nv_putval(nq, strdup(nv_getval(nq)), NV_RDONLY);
21467c2fbfb3SApril Chin 				else
21477c2fbfb3SApril Chin 					nv_putval(nq, nv_getval(nq), NV_RDONLY);
21487c2fbfb3SApril Chin 				shp->subshell = subshell;
21497c2fbfb3SApril Chin 				np->nvfun = 0;
21507c2fbfb3SApril Chin 			}
21517c2fbfb3SApril Chin 			if(nv_isattr(nq,NV_EXPORT))
21527c2fbfb3SApril Chin 				sh_envput(shp->env,nq);
21537c2fbfb3SApril Chin 		}
21547c2fbfb3SApril Chin 		npnext = (Namval_t*)dtnext(root,np);
21557c2fbfb3SApril Chin 		shp->last_root = root;
21567c2fbfb3SApril Chin 		shp->last_table = 0;
21577c2fbfb3SApril Chin 		if(nv_isvtree(np))
21587c2fbfb3SApril Chin 		{
21597c2fbfb3SApril Chin 			int len = strlen(np->nvname);
21607c2fbfb3SApril Chin 			while((nq=npnext) && memcmp(np->nvname,nq->nvname,len)==0 && nq->nvname[len]=='.')
21617c2fbfb3SApril Chin 
21627c2fbfb3SApril Chin 			{
21637c2fbfb3SApril Chin 				npnext = (Namval_t*)dtnext(root,nq);
21647c2fbfb3SApril Chin 				_nv_unset(nq,flags);
21657c2fbfb3SApril Chin 				nv_delete(nq,root,0);
21667c2fbfb3SApril Chin 			}
21677c2fbfb3SApril Chin 		}
2168da2e3ebdSchin 		_nv_unset(np,flags);
21697c2fbfb3SApril Chin 		nv_delete(np,root,0);
2170da2e3ebdSchin 	}
2171da2e3ebdSchin }
2172da2e3ebdSchin 
2173da2e3ebdSchin /*
2174da2e3ebdSchin  *
2175da2e3ebdSchin  *   Set the value of <np> to 0, and nullify any attributes
2176da2e3ebdSchin  *   that <np> may have had.  Free any freeable space occupied
2177da2e3ebdSchin  *   by the value of <np>.  If <np> denotes an array member, it
2178da2e3ebdSchin  *   will retain its attributes.
2179da2e3ebdSchin  *   <flags> can contain NV_RDONLY to override the readonly attribute
2180da2e3ebdSchin  *	being cleared.
21817c2fbfb3SApril Chin  *   <flags> can contain NV_EXPORT to override preserve nvenv
2182da2e3ebdSchin  */
_nv_unset(register Namval_t * np,int flags)2183da2e3ebdSchin void	_nv_unset(register Namval_t *np,int flags)
2184da2e3ebdSchin {
21857c2fbfb3SApril Chin 	Shell_t	*shp = &sh;
2186da2e3ebdSchin 	register union Value *up;
2187da2e3ebdSchin 	if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY))
2188da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
2189da2e3ebdSchin 	if(is_afunction(np) && np->nvalue.ip)
2190da2e3ebdSchin 	{
2191da2e3ebdSchin 		register struct slnod *slp = (struct slnod*)(np->nvenv);
2192da2e3ebdSchin 		if(slp && !nv_isattr(np,NV_NOFREE))
2193da2e3ebdSchin 		{
21947c2fbfb3SApril Chin 			struct Ufunction *rq,*rp = np->nvalue.rp;
2195da2e3ebdSchin 			/* free function definition */
2196da2e3ebdSchin 			register char *name=nv_name(np),*cp= strrchr(name,'.');
2197da2e3ebdSchin 			if(cp)
2198da2e3ebdSchin 			{
2199da2e3ebdSchin 				Namval_t *npv;
2200da2e3ebdSchin 				*cp = 0;
22017c2fbfb3SApril Chin 				 npv = nv_open(name,shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD);
2202da2e3ebdSchin 				*cp++ = '.';
2203da2e3ebdSchin 				if(npv)
2204da2e3ebdSchin 					nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv);
2205da2e3ebdSchin 			}
22067c2fbfb3SApril Chin 			if(rp->fname && shp->fpathdict && (rq = (struct Ufunction*)nv_search(rp->fname,shp->fpathdict,0)))
22077c2fbfb3SApril Chin 			{
22087c2fbfb3SApril Chin 				do
22097c2fbfb3SApril Chin 				{
22107c2fbfb3SApril Chin 					if(rq->np != np)
22117c2fbfb3SApril Chin 						continue;
22127c2fbfb3SApril Chin 					dtdelete(shp->fpathdict,rq);
22137c2fbfb3SApril Chin 					break;
22147c2fbfb3SApril Chin 				}
22157c2fbfb3SApril Chin 				while(rq = (struct Ufunction*)dtnext(shp->fpathdict,rq));
22167c2fbfb3SApril Chin 			}
22177c2fbfb3SApril Chin 			if(rp->sdict)
22187c2fbfb3SApril Chin 			{
22197c2fbfb3SApril Chin 				Namval_t *mp, *nq;
22207c2fbfb3SApril Chin 				for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq)
22217c2fbfb3SApril Chin 				{
22227c2fbfb3SApril Chin 					nq = dtnext(rp->sdict,mp);
22237c2fbfb3SApril Chin 					_nv_unset(mp,NV_RDONLY);
22247c2fbfb3SApril Chin 					nv_delete(mp,rp->sdict,0);
22257c2fbfb3SApril Chin 				}
22267c2fbfb3SApril Chin 				dtclose(rp->sdict);
22277c2fbfb3SApril Chin 			}
2228da2e3ebdSchin 			stakdelete(slp->slptr);
2229da2e3ebdSchin 			free((void*)np->nvalue.ip);
2230da2e3ebdSchin 			np->nvalue.ip = 0;
2231da2e3ebdSchin 		}
2232da2e3ebdSchin 		goto done;
2233da2e3ebdSchin 	}
22347c2fbfb3SApril Chin 	if(shp->subshell && !nv_isnull(np))
2235da2e3ebdSchin 		np = sh_assignok(np,0);
2236da2e3ebdSchin 	nv_offattr(np,NV_NODISC);
2237da2e3ebdSchin 	if(np->nvfun && !nv_isref(np))
2238da2e3ebdSchin 	{
2239da2e3ebdSchin 		/* This function contains disc */
2240da2e3ebdSchin 		if(!nv_local)
2241da2e3ebdSchin 		{
2242da2e3ebdSchin 			nv_local=1;
2243da2e3ebdSchin 			nv_putv(np,NIL(char*),flags,np->nvfun);
22447c2fbfb3SApril Chin 			nv_local=0;
2245da2e3ebdSchin 			return;
2246da2e3ebdSchin 		}
2247da2e3ebdSchin 		/* called from disc, assign the actual value */
2248da2e3ebdSchin 		nv_local=0;
2249da2e3ebdSchin 	}
225034f9b3eeSRoland Mainz 	if(nv_isattr(np,NV_INT16P) == NV_INT16)
225134f9b3eeSRoland Mainz 	{
225234f9b3eeSRoland Mainz 		np->nvalue.cp = nv_isarray(np)?Empty:0;
225334f9b3eeSRoland Mainz 		goto done;
225434f9b3eeSRoland Mainz 	}
22557c2fbfb3SApril Chin 	if(nv_isarray(np) && np->nvalue.cp!=Empty && np->nvfun)
22567c2fbfb3SApril Chin 		up = np->nvalue.up;
22577c2fbfb3SApril Chin 	else
2258da2e3ebdSchin 		up = &np->nvalue;
22597c2fbfb3SApril Chin 	if(up && up->cp)
2260da2e3ebdSchin 	{
22617c2fbfb3SApril Chin 		if(up->cp!=Empty && !nv_isattr(np, NV_NOFREE))
2262da2e3ebdSchin 			free((void*)up->cp);
2263da2e3ebdSchin 		up->cp = 0;
2264da2e3ebdSchin 	}
2265da2e3ebdSchin done:
2266da2e3ebdSchin 	if(!nv_isarray(np) || !nv_arrayptr(np))
2267da2e3ebdSchin 	{
22687c2fbfb3SApril Chin 		if(nv_isref(np) && !nv_isattr(np,NV_EXPORT))
2269da2e3ebdSchin 			free((void*)np->nvalue.nrp);
2270da2e3ebdSchin 		nv_setsize(np,0);
2271da2e3ebdSchin 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
2272da2e3ebdSchin 		{
2273da2e3ebdSchin 			if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'['))
22747c2fbfb3SApril Chin 				env_delete(shp->env,nv_name(np));
22757c2fbfb3SApril Chin 			if(!(flags&NV_EXPORT) ||  nv_isattr(np,NV_IMPORT|NV_EXPORT)==(NV_IMPORT|NV_EXPORT))
2276da2e3ebdSchin 				np->nvenv = 0;
2277da2e3ebdSchin 			nv_setattr(np,0);
2278da2e3ebdSchin 		}
2279da2e3ebdSchin 		else
2280da2e3ebdSchin 		{
22817c2fbfb3SApril Chin 			nv_setattr(np,NV_MINIMAL);
22827c2fbfb3SApril Chin 			nv_delete(np,(Dt_t*)0,0);
22837c2fbfb3SApril Chin 		}
22847c2fbfb3SApril Chin 	}
2285da2e3ebdSchin }
2286da2e3ebdSchin 
2287da2e3ebdSchin /*
2288da2e3ebdSchin  * return the node pointer in the highest level scope
2289da2e3ebdSchin  */
sh_scoped(Shell_t * shp,register Namval_t * np)22907c2fbfb3SApril Chin Namval_t *sh_scoped(Shell_t *shp, register Namval_t *np)
2291da2e3ebdSchin {
22927c2fbfb3SApril Chin 	if(!dtvnext(shp->var_tree))
2293da2e3ebdSchin 		return(np);
22947c2fbfb3SApril Chin 	return(dtsearch(shp->var_tree,np));
2295da2e3ebdSchin }
2296da2e3ebdSchin 
2297da2e3ebdSchin #if 1
2298da2e3ebdSchin /*
2299da2e3ebdSchin  * return space separated list of names of variables in given tree
2300da2e3ebdSchin  */
tableval(Dt_t * root)2301da2e3ebdSchin static char *tableval(Dt_t *root)
2302da2e3ebdSchin {
2303da2e3ebdSchin 	static Sfio_t *out;
2304da2e3ebdSchin 	register Namval_t *np;
2305da2e3ebdSchin 	register int first=1;
2306da2e3ebdSchin 	register Dt_t *base = dtview(root,0);
2307da2e3ebdSchin         if(out)
2308da2e3ebdSchin                 sfseek(out,(Sfoff_t)0,SEEK_SET);
2309da2e3ebdSchin         else
2310da2e3ebdSchin                 out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
2311da2e3ebdSchin 	for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
2312da2e3ebdSchin 	{
2313da2e3ebdSchin                 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
2314da2e3ebdSchin 		{
2315da2e3ebdSchin 			if(!first)
2316da2e3ebdSchin 				sfputc(out,' ');
2317da2e3ebdSchin 			else
2318da2e3ebdSchin 				first = 0;
2319da2e3ebdSchin 			sfputr(out,np->nvname,-1);
2320da2e3ebdSchin 		}
2321da2e3ebdSchin 	}
2322da2e3ebdSchin 	sfputc(out,0);
2323da2e3ebdSchin 	if(base)
2324da2e3ebdSchin 		dtview(root,base);
2325da2e3ebdSchin 	return((char*)out->_data);
2326da2e3ebdSchin }
2327da2e3ebdSchin #endif
2328da2e3ebdSchin 
2329da2e3ebdSchin #if SHOPT_OPTIMIZE
2330da2e3ebdSchin struct optimize
2331da2e3ebdSchin {
2332da2e3ebdSchin 	Namfun_t	hdr;
23337c2fbfb3SApril Chin 	Shell_t		*sh;
2334da2e3ebdSchin 	char		**ptr;
2335da2e3ebdSchin 	struct optimize	*next;
2336da2e3ebdSchin 	Namval_t	*np;
2337da2e3ebdSchin };
2338da2e3ebdSchin 
2339da2e3ebdSchin static struct optimize *opt_free;
2340da2e3ebdSchin 
optimize_clear(Namval_t * np,Namfun_t * fp)2341da2e3ebdSchin static void optimize_clear(Namval_t* np, Namfun_t *fp)
2342da2e3ebdSchin {
2343da2e3ebdSchin 	struct optimize *op = (struct optimize*)fp;
2344da2e3ebdSchin 	nv_stack(np,fp);
2345da2e3ebdSchin 	nv_stack(np,(Namfun_t*)0);
2346da2e3ebdSchin 	for(;op && op->np==np; op=op->next)
2347da2e3ebdSchin 	{
2348da2e3ebdSchin 		if(op->ptr)
2349da2e3ebdSchin 		{
2350da2e3ebdSchin 			*op->ptr = 0;
2351da2e3ebdSchin 			op->ptr = 0;
2352da2e3ebdSchin 		}
2353da2e3ebdSchin 	}
2354da2e3ebdSchin }
2355da2e3ebdSchin 
put_optimize(Namval_t * np,const char * val,int flags,Namfun_t * fp)2356da2e3ebdSchin static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp)
2357da2e3ebdSchin {
2358da2e3ebdSchin 	nv_putv(np,val,flags,fp);
2359da2e3ebdSchin 	optimize_clear(np,fp);
2360da2e3ebdSchin }
2361da2e3ebdSchin 
clone_optimize(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)23627c2fbfb3SApril Chin static Namfun_t *clone_optimize(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
23637c2fbfb3SApril Chin {
23647c2fbfb3SApril Chin 	return((Namfun_t*)0);
23657c2fbfb3SApril Chin }
23667c2fbfb3SApril Chin 
23677c2fbfb3SApril Chin static const Namdisc_t optimize_disc  = {sizeof(struct optimize),put_optimize,0,0,0,0,clone_optimize};
2368da2e3ebdSchin 
nv_optimize(Namval_t * np)2369da2e3ebdSchin void nv_optimize(Namval_t *np)
2370da2e3ebdSchin {
2371da2e3ebdSchin 	register Namfun_t *fp;
2372da2e3ebdSchin 	register struct optimize *op, *xp;
2373da2e3ebdSchin 	if(sh.argaddr)
2374da2e3ebdSchin 	{
23757c2fbfb3SApril Chin 		if(np==SH_LINENO)
23767c2fbfb3SApril Chin 		{
23777c2fbfb3SApril Chin 			sh.argaddr = 0;
23787c2fbfb3SApril Chin 			return;
23797c2fbfb3SApril Chin 		}
2380da2e3ebdSchin 		for(fp=np->nvfun; fp; fp = fp->next)
2381da2e3ebdSchin 		{
23827c2fbfb3SApril Chin 			if(fp->disc && (fp->disc->getnum || fp->disc->getval))
2383da2e3ebdSchin 			{
2384da2e3ebdSchin 				sh.argaddr = 0;
2385da2e3ebdSchin 				return;
2386da2e3ebdSchin 			}
2387da2e3ebdSchin 			if(fp->disc== &optimize_disc)
2388da2e3ebdSchin 				break;
2389da2e3ebdSchin 		}
2390da2e3ebdSchin 		if((xp= (struct optimize*)fp) && xp->ptr==sh.argaddr)
2391da2e3ebdSchin 			return;
2392da2e3ebdSchin 		if(op = opt_free)
2393da2e3ebdSchin 			opt_free = op->next;
2394da2e3ebdSchin 		else
2395da2e3ebdSchin 			op=(struct optimize*)calloc(1,sizeof(struct optimize));
2396da2e3ebdSchin 		op->ptr = sh.argaddr;
2397da2e3ebdSchin 		op->np = np;
2398da2e3ebdSchin 		if(xp)
2399da2e3ebdSchin 		{
2400da2e3ebdSchin 			op->hdr.disc = 0;
2401da2e3ebdSchin 			op->next = xp->next;
2402da2e3ebdSchin 			xp->next = op;
2403da2e3ebdSchin 		}
2404da2e3ebdSchin 		else
2405da2e3ebdSchin 		{
2406da2e3ebdSchin 			op->hdr.disc = &optimize_disc;
2407da2e3ebdSchin 			op->next = (struct optimize*)sh.optlist;
2408da2e3ebdSchin 			sh.optlist = (void*)op;
2409da2e3ebdSchin 			nv_stack(np,&op->hdr);
2410da2e3ebdSchin 		}
2411da2e3ebdSchin 	}
2412da2e3ebdSchin }
2413da2e3ebdSchin 
sh_optclear(Shell_t * shp,void * old)2414da2e3ebdSchin void sh_optclear(Shell_t *shp, void *old)
2415da2e3ebdSchin {
2416da2e3ebdSchin 	register struct optimize *op,*opnext;
2417da2e3ebdSchin 	for(op=(struct optimize*)shp->optlist; op; op = opnext)
2418da2e3ebdSchin 	{
2419da2e3ebdSchin 		opnext = op->next;
2420da2e3ebdSchin 		if(op->ptr && op->hdr.disc)
2421da2e3ebdSchin 		{
2422da2e3ebdSchin 			nv_stack(op->np,&op->hdr);
2423da2e3ebdSchin 			nv_stack(op->np,(Namfun_t*)0);
2424da2e3ebdSchin 		}
2425da2e3ebdSchin 		op->next = opt_free;
2426da2e3ebdSchin 		opt_free = op;
2427da2e3ebdSchin 	}
2428da2e3ebdSchin 	shp->optlist = old;
2429da2e3ebdSchin }
2430da2e3ebdSchin 
2431da2e3ebdSchin #else
2432da2e3ebdSchin #   define	optimize_clear(np,fp)
2433da2e3ebdSchin #endif /* SHOPT_OPTIMIZE */
2434da2e3ebdSchin 
2435da2e3ebdSchin /*
2436da2e3ebdSchin  *   Return a pointer to a character string that denotes the value
2437da2e3ebdSchin  *   of <np>.  If <np> refers to an array,  return a pointer to
2438da2e3ebdSchin  *   the value associated with the current index.
2439da2e3ebdSchin  *
2440da2e3ebdSchin  *   If the value of <np> is an integer, the string returned will
2441da2e3ebdSchin  *   be overwritten by the next call to nv_getval.
2442da2e3ebdSchin  *
2443da2e3ebdSchin  *   If <np> has no value, 0 is returned.
2444da2e3ebdSchin  */
2445da2e3ebdSchin 
nv_getval(register Namval_t * np)2446da2e3ebdSchin char *nv_getval(register Namval_t *np)
2447da2e3ebdSchin {
2448da2e3ebdSchin 	register union Value *up= &np->nvalue;
2449da2e3ebdSchin 	register int numeric;
2450da2e3ebdSchin #if SHOPT_OPTIMIZE
2451da2e3ebdSchin 	if(!nv_local && sh.argaddr)
2452da2e3ebdSchin 		nv_optimize(np);
2453da2e3ebdSchin #endif /* SHOPT_OPTIMIZE */
24547c2fbfb3SApril Chin 	if((!np->nvfun || !np->nvfun->disc) && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF|NV_TABLE))
2455da2e3ebdSchin 		goto done;
2456da2e3ebdSchin 	if(nv_isref(np))
2457da2e3ebdSchin 	{
24587c2fbfb3SApril Chin 		if(!np->nvalue.cp)
24597c2fbfb3SApril Chin 			return(0);
2460da2e3ebdSchin 		sh.last_table = nv_reftable(np);
2461da2e3ebdSchin 		return(nv_name(nv_refnode(np)));
2462da2e3ebdSchin 	}
24637c2fbfb3SApril Chin 	if(np->nvfun && np->nvfun->disc)
2464da2e3ebdSchin 	{
2465da2e3ebdSchin 		if(!nv_local)
2466da2e3ebdSchin 		{
2467da2e3ebdSchin 			nv_local=1;
2468da2e3ebdSchin 			return(nv_getv(np, np->nvfun));
2469da2e3ebdSchin 		}
2470da2e3ebdSchin 		nv_local=0;
2471da2e3ebdSchin 	}
2472da2e3ebdSchin 	numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
2473da2e3ebdSchin 	if(numeric)
2474da2e3ebdSchin 	{
2475da2e3ebdSchin 		Sflong_t  ll;
2476da2e3ebdSchin 		if(!up->cp)
2477da2e3ebdSchin 			return("0");
24787c2fbfb3SApril Chin 		if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE)
2479da2e3ebdSchin 		{
2480da2e3ebdSchin 			Sfdouble_t ld;
2481da2e3ebdSchin 			double d;
2482da2e3ebdSchin 			char *format;
2483da2e3ebdSchin 			if(nv_isattr(np,NV_LONG))
2484da2e3ebdSchin 			{
2485da2e3ebdSchin 				ld = *up->ldp;
2486da2e3ebdSchin 				if(nv_isattr (np,NV_EXPNOTE))
2487da2e3ebdSchin 					format = "%.*Lg";
24887c2fbfb3SApril Chin 				else if(nv_isattr (np,NV_HEXFLOAT))
24897c2fbfb3SApril Chin 					format = "%.*La";
2490da2e3ebdSchin 				else
2491da2e3ebdSchin 					format = "%.*Lf";
2492da2e3ebdSchin 				sfprintf(sh.strbuf,format,nv_size(np),ld);
2493da2e3ebdSchin 			}
2494da2e3ebdSchin 			else
2495da2e3ebdSchin 			{
2496da2e3ebdSchin 				d = *up->dp;
2497da2e3ebdSchin 				if(nv_isattr (np,NV_EXPNOTE))
2498da2e3ebdSchin 					format = "%.*g";
24997c2fbfb3SApril Chin 				else if(nv_isattr (np,NV_HEXFLOAT))
25007c2fbfb3SApril Chin 					format = "%.*a";
2501da2e3ebdSchin 				else
2502da2e3ebdSchin 					format = "%.*f";
2503da2e3ebdSchin 				sfprintf(sh.strbuf,format,nv_size(np),d);
2504da2e3ebdSchin 			}
2505da2e3ebdSchin 			return(sfstruse(sh.strbuf));
2506da2e3ebdSchin 		}
2507da2e3ebdSchin 		else if(nv_isattr(np,NV_UNSIGN))
2508da2e3ebdSchin 		{
2509da2e3ebdSchin 	        	if(nv_isattr (np,NV_LONG))
2510da2e3ebdSchin 				ll = *(Sfulong_t*)up->llp;
2511da2e3ebdSchin 			else if(nv_isattr (np,NV_SHORT))
25127c2fbfb3SApril Chin 			{
25137c2fbfb3SApril Chin 				if(nv_isattr(np,NV_INT16P)==NV_INT16P)
25147c2fbfb3SApril Chin 					ll = *(uint16_t*)(up->sp);
25157c2fbfb3SApril Chin 				else
2516da2e3ebdSchin 					ll = (uint16_t)up->s;
25177c2fbfb3SApril Chin 			}
2518da2e3ebdSchin 			else
2519da2e3ebdSchin 				ll = *(uint32_t*)(up->lp);
2520da2e3ebdSchin 		}
2521da2e3ebdSchin         	else if(nv_isattr (np,NV_LONG))
2522da2e3ebdSchin 			ll = *up->llp;
2523da2e3ebdSchin         	else if(nv_isattr (np,NV_SHORT))
25247c2fbfb3SApril Chin 		{
25257c2fbfb3SApril Chin 			if(nv_isattr(np,NV_INT16P)==NV_INT16P)
25267c2fbfb3SApril Chin 				ll = *up->sp;
25277c2fbfb3SApril Chin 			else
2528da2e3ebdSchin 				ll = up->s;
25297c2fbfb3SApril Chin 		}
2530da2e3ebdSchin         	else
2531da2e3ebdSchin 			ll = *(up->lp);
2532da2e3ebdSchin 		if((numeric=nv_size(np))==10)
2533da2e3ebdSchin 		{
2534da2e3ebdSchin 			if(nv_isattr(np,NV_UNSIGN))
2535da2e3ebdSchin 			{
2536da2e3ebdSchin 				sfprintf(sh.strbuf,"%I*u",sizeof(ll),ll);
2537da2e3ebdSchin 				return(sfstruse(sh.strbuf));
2538da2e3ebdSchin 			}
2539da2e3ebdSchin 			numeric = 0;
2540da2e3ebdSchin 		}
2541da2e3ebdSchin 		return(fmtbasell(ll,numeric, numeric&&numeric!=10));
2542da2e3ebdSchin 	}
2543da2e3ebdSchin done:
2544da2e3ebdSchin #if (_AST_VERSION>=20030127L)
2545da2e3ebdSchin 	/*
2546da2e3ebdSchin 	 * if NV_RAW flag is on, return pointer to binary data
2547da2e3ebdSchin 	 * otherwise, base64 encode the data and return this string
2548da2e3ebdSchin 	 */
2549da2e3ebdSchin 	if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
2550da2e3ebdSchin 	{
2551da2e3ebdSchin 		char *cp;
2552*3e14f97fSRoger A. Faulkner 		char *ep;
2553da2e3ebdSchin 		int size= nv_size(np), insize=(4*size)/3+size/45+8;
2554*3e14f97fSRoger A. Faulkner 		base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)&ep);
2555*3e14f97fSRoger A. Faulkner 		*ep = 0;
2556da2e3ebdSchin 		return(cp);
2557da2e3ebdSchin 	}
2558da2e3ebdSchin #endif
2559da2e3ebdSchin 	if((numeric=nv_size(np)) && up->cp && up->cp[numeric])
2560da2e3ebdSchin 	{
2561da2e3ebdSchin 		char *cp = getbuf(numeric+1);
2562da2e3ebdSchin 		memcpy(cp,up->cp,numeric);
2563da2e3ebdSchin 		cp[numeric]=0;
2564da2e3ebdSchin 		return(cp);
2565da2e3ebdSchin 	}
2566da2e3ebdSchin 	return ((char*)up->cp);
2567da2e3ebdSchin }
2568da2e3ebdSchin 
nv_getnum(register Namval_t * np)2569da2e3ebdSchin Sfdouble_t nv_getnum(register Namval_t *np)
2570da2e3ebdSchin {
2571da2e3ebdSchin 	register union Value *up;
2572da2e3ebdSchin 	register Sfdouble_t r=0;
2573da2e3ebdSchin 	register char *str;
2574da2e3ebdSchin #if SHOPT_OPTIMIZE
2575da2e3ebdSchin 	if(!nv_local && sh.argaddr)
2576da2e3ebdSchin 		nv_optimize(np);
2577da2e3ebdSchin #endif /* SHOPT_OPTIMIZE */
2578da2e3ebdSchin 	if(nv_istable(np))
2579da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np));
25807c2fbfb3SApril Chin      	if(np->nvfun && np->nvfun->disc)
2581da2e3ebdSchin 	{
2582da2e3ebdSchin 		if(!nv_local)
2583da2e3ebdSchin 		{
2584da2e3ebdSchin 			nv_local=1;
2585da2e3ebdSchin 			return(nv_getn(np, np->nvfun));
2586da2e3ebdSchin 		}
2587da2e3ebdSchin 		nv_local=0;
2588da2e3ebdSchin 	}
25897c2fbfb3SApril Chin 	if(nv_isref(np))
25907c2fbfb3SApril Chin 	{
25917c2fbfb3SApril Chin 		str = nv_refsub(np);
25927c2fbfb3SApril Chin 		np = nv_refnode(np);
25937c2fbfb3SApril Chin 		if(str)
25947c2fbfb3SApril Chin 			nv_putsub(np,str,0L);
25957c2fbfb3SApril Chin 	}
2596da2e3ebdSchin      	if(nv_isattr (np, NV_INTEGER))
2597da2e3ebdSchin 	{
2598da2e3ebdSchin 		up= &np->nvalue;
25997c2fbfb3SApril Chin 		if(!up->lp || up->cp==Empty)
2600da2e3ebdSchin 			r = 0;
26017c2fbfb3SApril Chin 		else if(nv_isattr(np, NV_DOUBLE)==NV_DOUBLE)
2602da2e3ebdSchin 		{
2603da2e3ebdSchin 			if(nv_isattr(np, NV_LONG))
2604da2e3ebdSchin 	                       	r = *up->ldp;
2605da2e3ebdSchin 			else
2606da2e3ebdSchin        	                	r = *up->dp;
2607da2e3ebdSchin 		}
2608da2e3ebdSchin 		else if(nv_isattr(np, NV_UNSIGN))
2609da2e3ebdSchin 		{
2610da2e3ebdSchin 			if(nv_isattr(np, NV_LONG))
2611da2e3ebdSchin 				r = (Sflong_t)*((Sfulong_t*)up->llp);
2612da2e3ebdSchin 			else if(nv_isattr(np, NV_SHORT))
26137c2fbfb3SApril Chin 			{
26147c2fbfb3SApril Chin 				if(nv_isattr(np,NV_INT16P)==NV_INT16P)
26157c2fbfb3SApril Chin 					r = (Sflong_t)(*(uint16_t*)up->sp);
26167c2fbfb3SApril Chin 				else
2617da2e3ebdSchin 					r = (Sflong_t)((uint16_t)up->s);
26187c2fbfb3SApril Chin 			}
2619da2e3ebdSchin 			else
2620da2e3ebdSchin 				r = *((uint32_t*)up->lp);
2621da2e3ebdSchin 		}
2622da2e3ebdSchin 		else
2623da2e3ebdSchin 		{
2624da2e3ebdSchin 			if(nv_isattr(np, NV_LONG))
2625da2e3ebdSchin 				r = *up->llp;
2626da2e3ebdSchin 			else if(nv_isattr(np, NV_SHORT))
26277c2fbfb3SApril Chin 			{
26287c2fbfb3SApril Chin 				if(nv_isattr(np,NV_INT16P)==NV_INT16P)
26297c2fbfb3SApril Chin 					r = *up->sp;
26307c2fbfb3SApril Chin 				else
2631da2e3ebdSchin 					r = up->s;
26327c2fbfb3SApril Chin 			}
2633da2e3ebdSchin 			else
2634da2e3ebdSchin 				r = *up->lp;
2635da2e3ebdSchin 		}
2636da2e3ebdSchin 	}
2637da2e3ebdSchin 	else if((str=nv_getval(np)) && *str!=0)
2638da2e3ebdSchin 	{
2639da2e3ebdSchin 		if(np->nvfun ||  nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
2640da2e3ebdSchin 		{
2641da2e3ebdSchin 			while(*str=='0')
2642da2e3ebdSchin 				str++;
2643da2e3ebdSchin 		}
2644da2e3ebdSchin 		r = sh_arith(str);
2645da2e3ebdSchin 	}
2646da2e3ebdSchin 	return(r);
2647da2e3ebdSchin }
2648da2e3ebdSchin /*
2649da2e3ebdSchin  *   Give <np> the attributes <newatts,> and change its current
2650da2e3ebdSchin  *   value to conform to <newatts>.  The <size> of left and right
2651da2e3ebdSchin  *   justified fields may be given.
2652da2e3ebdSchin  */
nv_newattr(register Namval_t * np,unsigned newatts,int size)2653da2e3ebdSchin void nv_newattr (register Namval_t *np, unsigned newatts, int size)
2654da2e3ebdSchin {
2655da2e3ebdSchin 	register char *sp;
2656da2e3ebdSchin 	register char *cp = 0;
2657da2e3ebdSchin 	register unsigned int n;
2658da2e3ebdSchin 	Namarr_t *ap = 0;
2659da2e3ebdSchin 	int oldsize,oldatts;
26607c2fbfb3SApril Chin 	Namfun_t *fp= (newatts&NV_NODISC)?np->nvfun:0;
266134f9b3eeSRoland Mainz 	char *prefix = sh.prefix;
26627c2fbfb3SApril Chin 	newatts &= ~NV_NODISC;
2663da2e3ebdSchin 
2664da2e3ebdSchin 	/* check for restrictions */
2665da2e3ebdSchin 	if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD)))
2666da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
2667da2e3ebdSchin 	/* handle attributes that do not change data separately */
2668da2e3ebdSchin 	n = np->nvflag;
2669da2e3ebdSchin 	if(newatts&NV_EXPORT)
2670da2e3ebdSchin 		nv_offattr(np,NV_IMPORT);
2671da2e3ebdSchin 	if(((n^newatts)&NV_EXPORT))
2672da2e3ebdSchin 	{
2673da2e3ebdSchin 		/* record changes to the environment */
2674da2e3ebdSchin 		if(n&NV_EXPORT)
2675da2e3ebdSchin 			env_delete(sh.env,nv_name(np));
2676da2e3ebdSchin 		else
2677da2e3ebdSchin 			sh_envput(sh.env,np);
2678da2e3ebdSchin 	}
267934f9b3eeSRoland Mainz 	oldsize = nv_size(np);
268034f9b3eeSRoland Mainz 	if((size==oldsize|| (n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0)
2681da2e3ebdSchin 	{
2682da2e3ebdSchin 		if(size)
2683da2e3ebdSchin 			nv_setsize(np,size);
2684da2e3ebdSchin 		nv_offattr(np, ~NV_NOFREE);
2685da2e3ebdSchin 		nv_onattr(np, newatts);
2686da2e3ebdSchin 		return;
2687da2e3ebdSchin 	}
2688da2e3ebdSchin 	/* for an array, change all the elements */
2689da2e3ebdSchin 	if((ap=nv_arrayptr(np)) && ap->nelem>0)
2690da2e3ebdSchin 		nv_putsub(np,NIL(char*),ARRAY_SCAN);
2691da2e3ebdSchin 	oldsize = nv_size(np);
2692da2e3ebdSchin 	oldatts = np->nvflag;
26937c2fbfb3SApril Chin 	if(fp)
26947c2fbfb3SApril Chin 		np->nvfun = 0;
2695da2e3ebdSchin 	if(ap) /* add element to prevent array deletion */
2696da2e3ebdSchin 		ap->nelem++;
2697da2e3ebdSchin 	do
2698da2e3ebdSchin 	{
2699da2e3ebdSchin 		nv_setsize(np,oldsize);
2700da2e3ebdSchin 		np->nvflag = oldatts;
2701da2e3ebdSchin 		if (sp = nv_getval(np))
2702da2e3ebdSchin  		{
2703da2e3ebdSchin 			if(nv_isattr(np,NV_ZFILL))
2704da2e3ebdSchin 				while(*sp=='0') sp++;
2705da2e3ebdSchin 			cp = (char*)malloc((n=strlen (sp)) + 1);
2706da2e3ebdSchin 			strcpy(cp, sp);
2707da2e3ebdSchin 			if(ap)
2708da2e3ebdSchin 			{
2709da2e3ebdSchin 				Namval_t *mp;
2710da2e3ebdSchin 				ap->nelem &= ~ARRAY_SCAN;
2711da2e3ebdSchin 				if(mp=nv_opensub(np))
27127c2fbfb3SApril Chin 				{
27137c2fbfb3SApril Chin 					nv_unset(mp);
27147c2fbfb3SApril Chin 					mp->nvalue.cp = Empty;
2715da2e3ebdSchin 				}
27167c2fbfb3SApril Chin 				else
2717da2e3ebdSchin 					nv_unset(np);
2718da2e3ebdSchin 				ap->nelem |= ARRAY_SCAN;
27197c2fbfb3SApril Chin 			}
27207c2fbfb3SApril Chin 			else
27217c2fbfb3SApril Chin 				nv_unset(np);
2722*3e14f97fSRoger A. Faulkner 			if(size==0 && (newatts&NV_HOST)!=NV_HOST && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL)))
2723da2e3ebdSchin 				size = n;
2724da2e3ebdSchin 		}
2725da2e3ebdSchin 		else
2726da2e3ebdSchin 			nv_unset(np);
2727da2e3ebdSchin 		nv_setsize(np,size);
2728da2e3ebdSchin 		np->nvflag &= NV_ARRAY;
2729da2e3ebdSchin 		np->nvflag |= newatts;
2730da2e3ebdSchin 		if (cp)
2731da2e3ebdSchin 		{
2732da2e3ebdSchin 			nv_putval (np, cp, NV_RDONLY);
2733da2e3ebdSchin 			free(cp);
2734da2e3ebdSchin 		}
2735da2e3ebdSchin 	}
2736da2e3ebdSchin 	while(ap && nv_nextsub(np));
27377c2fbfb3SApril Chin 	if(fp)
27387c2fbfb3SApril Chin 		np->nvfun = fp;
2739da2e3ebdSchin 	if(ap)
2740da2e3ebdSchin 		ap->nelem--;
274134f9b3eeSRoland Mainz 	sh.prefix = prefix;
2742da2e3ebdSchin 	return;
2743da2e3ebdSchin }
2744da2e3ebdSchin 
oldgetenv(const char * string)2745da2e3ebdSchin static char *oldgetenv(const char *string)
2746da2e3ebdSchin {
2747da2e3ebdSchin 	register char c0,c1;
2748da2e3ebdSchin 	register const char *cp, *sp;
2749da2e3ebdSchin 	register char **av = environ;
2750da2e3ebdSchin 	if(!string || (c0= *string)==0)
2751da2e3ebdSchin 		return(0);
2752da2e3ebdSchin 	if((c1=*++string)==0)
2753da2e3ebdSchin 		c1= '=';
2754da2e3ebdSchin 	while(cp = *av++)
2755da2e3ebdSchin 	{
2756da2e3ebdSchin 		if(cp[0]!=c0 || cp[1]!=c1)
2757da2e3ebdSchin 			continue;
2758da2e3ebdSchin 		sp = string;
2759da2e3ebdSchin 		while(*sp && *sp++ == *++cp);
2760da2e3ebdSchin 		if(*sp==0 && *++cp=='=')
2761da2e3ebdSchin 			return((char*)(cp+1));
2762da2e3ebdSchin 	}
2763da2e3ebdSchin 	return(0);
2764da2e3ebdSchin }
2765da2e3ebdSchin 
2766da2e3ebdSchin /*
2767da2e3ebdSchin  * This version of getenv uses the hash storage to access environment values
2768da2e3ebdSchin  */
sh_getenv(const char * name)2769*3e14f97fSRoger A. Faulkner char *sh_getenv(const char *name)
2770da2e3ebdSchin /*@
2771da2e3ebdSchin 	assume name!=0;
2772da2e3ebdSchin @*/
2773da2e3ebdSchin {
2774da2e3ebdSchin 	register Namval_t *np;
2775da2e3ebdSchin 	if(!sh.var_tree)
2776*3e14f97fSRoger A. Faulkner 	{
2777*3e14f97fSRoger A. Faulkner #if 0
2778*3e14f97fSRoger A. Faulkner 		if(name[0] == 'P' && name[1] == 'A' && name[2] == 'T' && name[3] == 'H' && name[4] == 0 || name[0] == 'L' && ((name[1] == 'C' || name[1] == 'D') && name[2] == '_' || name[1] == 'A' && name[1] == 'N') || name[0] == 'V' && name[1] == 'P' && name[2] == 'A' && name[3] == 'T' && name[4] == 'H' && name[5] == 0 || name[0] == '_' && name[1] == 'R' && name[2] == 'L' && name[3] == 'D' || name[0] == '_' && name[1] == 'A' && name[2] == 'S' && name[3] == 'T' && name[4] == '_')
2779*3e14f97fSRoger A. Faulkner #endif
2780da2e3ebdSchin 			return(oldgetenv(name));
2781*3e14f97fSRoger A. Faulkner 	}
2782*3e14f97fSRoger A. Faulkner 	else if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT))
2783da2e3ebdSchin 		return(nv_getval(np));
2784da2e3ebdSchin 	return(0);
2785da2e3ebdSchin }
2786*3e14f97fSRoger A. Faulkner 
2787*3e14f97fSRoger A. Faulkner #ifndef _NEXT_SOURCE
2788*3e14f97fSRoger A. Faulkner /*
2789*3e14f97fSRoger A. Faulkner  * Some dynamic linkers will make this file see the libc getenv(),
2790*3e14f97fSRoger A. Faulkner  * so sh_getenv() is used for the astintercept() callback.  Plain
2791*3e14f97fSRoger A. Faulkner  * getenv() is provided for static links.
2792*3e14f97fSRoger A. Faulkner  */
getenv(const char * name)2793*3e14f97fSRoger A. Faulkner char *getenv(const char *name)
2794*3e14f97fSRoger A. Faulkner {
2795*3e14f97fSRoger A. Faulkner 	return sh_getenv(name);
2796*3e14f97fSRoger A. Faulkner }
2797da2e3ebdSchin #endif /* _NEXT_SOURCE */
2798da2e3ebdSchin 
2799da2e3ebdSchin #undef putenv
2800da2e3ebdSchin /*
2801da2e3ebdSchin  * This version of putenv uses the hash storage to assign environment values
2802da2e3ebdSchin  */
putenv(const char * name)2803da2e3ebdSchin int putenv(const char *name)
2804da2e3ebdSchin {
2805da2e3ebdSchin 	register Namval_t *np;
2806da2e3ebdSchin 	if(name)
2807da2e3ebdSchin 	{
2808da2e3ebdSchin 		np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2809da2e3ebdSchin 		if(!strchr(name,'='))
2810da2e3ebdSchin 			nv_unset(np);
2811da2e3ebdSchin 	}
2812da2e3ebdSchin 	return(0);
2813da2e3ebdSchin }
2814da2e3ebdSchin 
2815da2e3ebdSchin /*
2816*3e14f97fSRoger A. Faulkner  * Override libast setenviron().
2817da2e3ebdSchin  */
sh_setenviron(const char * name)2818*3e14f97fSRoger A. Faulkner char* sh_setenviron(const char *name)
2819da2e3ebdSchin {
2820da2e3ebdSchin 	register Namval_t *np;
2821da2e3ebdSchin 	if(name)
2822da2e3ebdSchin 	{
2823da2e3ebdSchin 		np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2824da2e3ebdSchin 		if(strchr(name,'='))
2825da2e3ebdSchin 			return(nv_getval(np));
2826da2e3ebdSchin 		nv_unset(np);
2827da2e3ebdSchin 	}
2828da2e3ebdSchin 	return("");
2829da2e3ebdSchin }
2830da2e3ebdSchin 
2831da2e3ebdSchin /*
2832*3e14f97fSRoger A. Faulkner  * Same linker dance as with getenv() above.
2833*3e14f97fSRoger A. Faulkner  */
setenviron(const char * name)2834*3e14f97fSRoger A. Faulkner char* setenviron(const char *name)
2835*3e14f97fSRoger A. Faulkner {
2836*3e14f97fSRoger A. Faulkner 	return sh_setenviron(name);
2837*3e14f97fSRoger A. Faulkner }
2838*3e14f97fSRoger A. Faulkner 
2839*3e14f97fSRoger A. Faulkner /*
28407c2fbfb3SApril Chin  * convert <str> to upper case
2841da2e3ebdSchin  */
ltou(register char * str)28427c2fbfb3SApril Chin static void ltou(register char *str)
2843da2e3ebdSchin {
2844da2e3ebdSchin 	register int c;
28457c2fbfb3SApril Chin 	for(; c= *((unsigned char*)str); str++)
2846da2e3ebdSchin 	{
2847da2e3ebdSchin 		if(islower(c))
28487c2fbfb3SApril Chin 			*str = toupper(c);
2849da2e3ebdSchin 	}
28507c2fbfb3SApril Chin }
28517c2fbfb3SApril Chin 
28527c2fbfb3SApril Chin /*
28537c2fbfb3SApril Chin  * convert <str> to lower case
28547c2fbfb3SApril Chin  */
utol(register char * str)28557c2fbfb3SApril Chin static void utol(register char *str)
28567c2fbfb3SApril Chin {
28577c2fbfb3SApril Chin 	register int c;
28587c2fbfb3SApril Chin 	for(; c= *((unsigned char*)str); str++)
28597c2fbfb3SApril Chin 	{
28607c2fbfb3SApril Chin 		if(isupper(c))
28617c2fbfb3SApril Chin 			*str = tolower(c);
28627c2fbfb3SApril Chin 	}
2863da2e3ebdSchin }
2864da2e3ebdSchin 
2865da2e3ebdSchin /*
2866da2e3ebdSchin  * normalize <cp> and return pointer to subscript if any
28677c2fbfb3SApril Chin  * if <eq> is specified, return pointer to first = not in a subscript
2868da2e3ebdSchin  */
lastdot(register char * cp,int eq)28697c2fbfb3SApril Chin static char *lastdot(register char *cp, int eq)
2870da2e3ebdSchin {
28717c2fbfb3SApril Chin 	register char *ep=0;
2872da2e3ebdSchin 	register int c;
28737c2fbfb3SApril Chin 	if(eq)
28747c2fbfb3SApril Chin 		cp++;
2875da2e3ebdSchin 	while(c= *cp++)
2876da2e3ebdSchin 	{
2877da2e3ebdSchin 		if(c=='[')
287834f9b3eeSRoland Mainz 		{
287934f9b3eeSRoland Mainz 			if(*cp==']')
288034f9b3eeSRoland Mainz 				cp++;
288134f9b3eeSRoland Mainz 			else
28827c2fbfb3SApril Chin 				cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
288334f9b3eeSRoland Mainz 		}
2884da2e3ebdSchin 		else if(c=='.')
2885da2e3ebdSchin 		{
2886da2e3ebdSchin 			if(*cp=='[')
288734f9b3eeSRoland Mainz 			{
288834f9b3eeSRoland Mainz 				cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
288934f9b3eeSRoland Mainz 				if((ep=sh_checkid(ep+1,cp)) < cp)
289034f9b3eeSRoland Mainz 					cp=strcpy(ep,cp);
289134f9b3eeSRoland Mainz 			}
2892da2e3ebdSchin 			ep = 0;
2893da2e3ebdSchin 		}
28947c2fbfb3SApril Chin 		else if(eq && c == '=')
28957c2fbfb3SApril Chin 			return(cp-1);
2896da2e3ebdSchin 	}
28977c2fbfb3SApril Chin 	return(eq?0:ep);
28987c2fbfb3SApril Chin }
28997c2fbfb3SApril Chin 
nv_rename(register Namval_t * np,int flags)29007c2fbfb3SApril Chin int nv_rename(register Namval_t *np, int flags)
29017c2fbfb3SApril Chin {
29027c2fbfb3SApril Chin 	Shell_t			*shp = &sh;
29037c2fbfb3SApril Chin 	register Namval_t	*mp=0,*nr=0;
29047c2fbfb3SApril Chin 	register char		*cp;
29057c2fbfb3SApril Chin 	int			index= -1;
29067c2fbfb3SApril Chin 	Namval_t		*last_table = shp->last_table;
29077c2fbfb3SApril Chin 	Dt_t			*last_root = shp->last_root;
29087c2fbfb3SApril Chin 	Dt_t			*hp = 0;
290934f9b3eeSRoland Mainz 	char			*prefix=shp->prefix,*nvenv = 0;
29107c2fbfb3SApril Chin 	if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
29117c2fbfb3SApril Chin 	{
29127c2fbfb3SApril Chin 		if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
29137c2fbfb3SApril Chin 			hp = dtvnext(shp->var_tree);
29147c2fbfb3SApril Chin 	}
29157c2fbfb3SApril Chin 	if(!(cp=nv_getval(np)))
29167c2fbfb3SApril Chin 	{
29177c2fbfb3SApril Chin 		if(flags&NV_MOVE)
29187c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_exit(1),e_varname,"");
29197c2fbfb3SApril Chin 		return(0);
29207c2fbfb3SApril Chin 	}
29217c2fbfb3SApril Chin 	if(lastdot(cp,0) && nv_isattr(np,NV_MINIMAL))
29227c2fbfb3SApril Chin 		errormsg(SH_DICT,ERROR_exit(1),e_varname,nv_name(np));
29237c2fbfb3SApril Chin 	if(nv_isarray(np) && !(mp=nv_opensub(np)))
29247c2fbfb3SApril Chin 		index=nv_aindex(np);
292534f9b3eeSRoland Mainz 	shp->prefix = 0;
29267c2fbfb3SApril Chin 	if(!hp)
29277c2fbfb3SApril Chin 		hp = shp->var_tree;
29287c2fbfb3SApril Chin 	if(!(nr = nv_open(cp, hp, flags|NV_ARRAY|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
29297c2fbfb3SApril Chin 		hp = shp->var_base;
29307c2fbfb3SApril Chin 	else if(shp->last_root)
29317c2fbfb3SApril Chin 		hp = shp->last_root;
29327c2fbfb3SApril Chin 	if(!nr)
29337c2fbfb3SApril Chin 		nr= nv_open(cp, hp, flags|NV_NOREF|((flags&NV_MOVE)?0:NV_NOFAIL));
293434f9b3eeSRoland Mainz 	shp->prefix = prefix;
29357c2fbfb3SApril Chin 	if(!nr)
29367c2fbfb3SApril Chin 	{
29377c2fbfb3SApril Chin 		if(!nv_isvtree(np))
29387c2fbfb3SApril Chin 			_nv_unset(np,0);
29397c2fbfb3SApril Chin 		return(0);
29407c2fbfb3SApril Chin 	}
29417c2fbfb3SApril Chin 	if(!mp && index>=0 && nv_isvtree(nr))
29427c2fbfb3SApril Chin 	{
29437c2fbfb3SApril Chin 		sfprintf(shp->strbuf,"%s[%d]%c",nv_name(np),index,0);
29447c2fbfb3SApril Chin 		/* create a virtual node */
29457c2fbfb3SApril Chin 		if(mp = nv_open(sfstruse(shp->strbuf),shp->var_tree,NV_VARNAME|NV_ADD|NV_ARRAY))
29467c2fbfb3SApril Chin 			mp->nvenv = (void*)np;
29477c2fbfb3SApril Chin 	}
29487c2fbfb3SApril Chin 	if(mp)
294934f9b3eeSRoland Mainz 	{
295034f9b3eeSRoland Mainz 		nvenv = (char*)np;
29517c2fbfb3SApril Chin 		np = mp;
295234f9b3eeSRoland Mainz 	}
29537c2fbfb3SApril Chin 	if(nr==np)
29547c2fbfb3SApril Chin 	{
29557c2fbfb3SApril Chin 		if(index<0)
29567c2fbfb3SApril Chin 			return(0);
29577c2fbfb3SApril Chin 		if(cp = nv_getval(np))
29587c2fbfb3SApril Chin 			cp = strdup(cp);
29597c2fbfb3SApril Chin 	}
29607c2fbfb3SApril Chin 	_nv_unset(np,0);
296134f9b3eeSRoland Mainz 	if(!nv_isattr(np,NV_MINIMAL))
296234f9b3eeSRoland Mainz 		np->nvenv = nvenv;
29637c2fbfb3SApril Chin 	if(nr==np)
29647c2fbfb3SApril Chin 	{
29657c2fbfb3SApril Chin 		nv_putsub(np,(char*)0, index);
29667c2fbfb3SApril Chin 		nv_putval(np,cp,0);
29677c2fbfb3SApril Chin 		free((void*)cp);
29687c2fbfb3SApril Chin 		return(1);
29697c2fbfb3SApril Chin 	}
29707c2fbfb3SApril Chin 	shp->prev_table = shp->last_table;
29717c2fbfb3SApril Chin 	shp->prev_root = shp->last_root;
29727c2fbfb3SApril Chin 	shp->last_table = last_table;
29737c2fbfb3SApril Chin 	shp->last_root = last_root;
29747c2fbfb3SApril Chin 	nv_clone(nr,np,(flags&NV_MOVE)|NV_COMVAR);
29757c2fbfb3SApril Chin 	if(flags&NV_MOVE)
29767c2fbfb3SApril Chin 		nv_delete(nr,(Dt_t*)0,NV_NOFREE);
29777c2fbfb3SApril Chin 	return(1);
2978da2e3ebdSchin }
2979da2e3ebdSchin 
2980da2e3ebdSchin /*
2981da2e3ebdSchin  * Create a reference node from <np> to $np in dictionary <hp>
2982da2e3ebdSchin  */
nv_setref(register Namval_t * np,Dt_t * hp,int flags)2983da2e3ebdSchin void nv_setref(register Namval_t *np, Dt_t *hp, int flags)
2984da2e3ebdSchin {
29857c2fbfb3SApril Chin 	Shell_t		*shp = &sh;
29867c2fbfb3SApril Chin 	register Namval_t *nq, *nr=0;
2987da2e3ebdSchin 	register char	*ep,*cp;
298834f9b3eeSRoland Mainz 	Dt_t		*root = shp->last_root;
298934f9b3eeSRoland Mainz 	Namarr_t	*ap;
2990da2e3ebdSchin 	if(nv_isref(np))
2991da2e3ebdSchin 		return;
2992da2e3ebdSchin 	if(nv_isarray(np))
2993da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
2994da2e3ebdSchin 	if(!(cp=nv_getval(np)))
29957c2fbfb3SApril Chin 	{
29967c2fbfb3SApril Chin 		nv_unset(np);
29977c2fbfb3SApril Chin 		nv_onattr(np,NV_REF);
29987c2fbfb3SApril Chin 		return;
29997c2fbfb3SApril Chin 	}
30007c2fbfb3SApril Chin 	if((ep = lastdot(cp,0)) && nv_isattr(np,NV_MINIMAL))
3001da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
3002da2e3ebdSchin 	if(!hp)
30037c2fbfb3SApril Chin 		hp = shp->var_tree;
30047c2fbfb3SApril Chin 	if(!(nr = nq = nv_open(cp, hp, flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
300534f9b3eeSRoland Mainz 		hp = shp->last_root==shp->var_tree?shp->var_tree:shp->var_base;
30067c2fbfb3SApril Chin 	else if(shp->last_root)
30077c2fbfb3SApril Chin 		hp = shp->last_root;
30087c2fbfb3SApril Chin 	if(nq && ep && nv_isarray(nq) && !nv_getsub(nq))
30097c2fbfb3SApril Chin 		nv_endsubscript(nq,ep-1,NV_ADD);
30107c2fbfb3SApril Chin 	if(!nr)
301134f9b3eeSRoland Mainz 	{
30127c2fbfb3SApril Chin 		nr= nq = nv_open(cp, hp, flags);
301334f9b3eeSRoland Mainz 		hp = shp->last_root;
301434f9b3eeSRoland Mainz 	}
301534f9b3eeSRoland Mainz 	if(shp->last_root == shp->var_tree && root!=shp->var_tree)
301634f9b3eeSRoland Mainz 	{
301734f9b3eeSRoland Mainz 		_nv_unset(np,NV_RDONLY);
301834f9b3eeSRoland Mainz 		nv_onattr(np,NV_REF);
301934f9b3eeSRoland Mainz 		errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np));
302034f9b3eeSRoland Mainz 	}
3021da2e3ebdSchin 	if(nr==np)
3022da2e3ebdSchin 	{
30237c2fbfb3SApril Chin 		if(shp->namespace && nv_dict(shp->namespace)==hp)
3024da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
3025da2e3ebdSchin 		/* bind to earlier scope, or add to global scope */
3026da2e3ebdSchin 		if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np)
3027da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
3028da2e3ebdSchin 	}
302934f9b3eeSRoland Mainz 	if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN)))
303034f9b3eeSRoland Mainz 		ep =  nv_getsub(nq);
3031da2e3ebdSchin 	if(ep)
3032da2e3ebdSchin 	{
3033da2e3ebdSchin 		/* cause subscript evaluation and return result */
30347c2fbfb3SApril Chin 		if(nv_isarray(nq))
3035da2e3ebdSchin 			ep = nv_getsub(nq);
30367c2fbfb3SApril Chin 		else
30377c2fbfb3SApril Chin 		{
30387c2fbfb3SApril Chin 			ep[strlen(ep)-1] = 0;
30397c2fbfb3SApril Chin 			nv_putsub(nr, ep, 0);
30407c2fbfb3SApril Chin 			ep[strlen(ep)-1] = ']';
30417c2fbfb3SApril Chin 			if(nq = nv_opensub(nr))
30427c2fbfb3SApril Chin 				ep = 0;
30437c2fbfb3SApril Chin 			else
30447c2fbfb3SApril Chin 				nq = nr;
30457c2fbfb3SApril Chin 		}
3046da2e3ebdSchin 	}
3047da2e3ebdSchin 	nv_unset(np);
30487c2fbfb3SApril Chin 	nv_delete(np,(Dt_t*)0,0);
3049da2e3ebdSchin 	np->nvalue.nrp = newof(0,struct Namref,1,0);
3050da2e3ebdSchin 	np->nvalue.nrp->np = nq;
3051da2e3ebdSchin 	np->nvalue.nrp->root = hp;
3052da2e3ebdSchin 	if(ep)
3053da2e3ebdSchin 		np->nvalue.nrp->sub = strdup(ep);
30547c2fbfb3SApril Chin 	np->nvalue.nrp->table = shp->last_table;
3055da2e3ebdSchin 	nv_onattr(np,NV_REF|NV_NOFREE);
3056da2e3ebdSchin }
3057da2e3ebdSchin 
3058da2e3ebdSchin /*
3059da2e3ebdSchin  * get the scope corresponding to <index>
3060da2e3ebdSchin  * whence uses the same values as lseeek()
3061da2e3ebdSchin  */
sh_getscope(int index,int whence)3062da2e3ebdSchin Shscope_t *sh_getscope(int index, int whence)
3063da2e3ebdSchin {
3064da2e3ebdSchin 	register struct sh_scoped *sp, *topmost;
3065da2e3ebdSchin 	if(whence==SEEK_CUR)
3066da2e3ebdSchin 		sp = &sh.st;
3067da2e3ebdSchin 	else
3068da2e3ebdSchin 	{
3069da2e3ebdSchin 		if ((struct sh_scoped*)sh.topscope != sh.st.self)
3070da2e3ebdSchin 			topmost = (struct sh_scoped*)sh.topscope;
3071da2e3ebdSchin 		else
3072da2e3ebdSchin 			topmost = &(sh.st);
3073da2e3ebdSchin 		sp = topmost;
3074da2e3ebdSchin 		if(whence==SEEK_SET)
3075da2e3ebdSchin 		{
3076da2e3ebdSchin 			int n =0;
3077da2e3ebdSchin 			while(sp = sp->prevst)
3078da2e3ebdSchin 				n++;
3079da2e3ebdSchin 			index = n - index;
3080da2e3ebdSchin 			sp = topmost;
3081da2e3ebdSchin 		}
3082da2e3ebdSchin 	}
3083da2e3ebdSchin 	if(index < 0)
3084da2e3ebdSchin 		return((Shscope_t*)0);
3085da2e3ebdSchin 	while(index-- && (sp = sp->prevst));
3086da2e3ebdSchin 	return((Shscope_t*)sp);
3087da2e3ebdSchin }
3088da2e3ebdSchin 
3089da2e3ebdSchin /*
3090da2e3ebdSchin  * make <scoped> the top scope and return previous scope
3091da2e3ebdSchin  */
sh_setscope(Shscope_t * scope)3092da2e3ebdSchin Shscope_t *sh_setscope(Shscope_t *scope)
3093da2e3ebdSchin {
3094da2e3ebdSchin 	Shscope_t *old = (Shscope_t*)sh.st.self;
3095da2e3ebdSchin 	*sh.st.self = sh.st;
3096da2e3ebdSchin 	sh.st = *((struct sh_scoped*)scope);
3097da2e3ebdSchin 	sh.var_tree = scope->var_tree;
30987c2fbfb3SApril Chin 	SH_PATHNAMENOD->nvalue.cp = sh.st.filename;
30997c2fbfb3SApril Chin 	SH_FUNNAMENOD->nvalue.cp = sh.st.funname;
3100da2e3ebdSchin 	return(old);
3101da2e3ebdSchin }
3102da2e3ebdSchin 
sh_unscope(Shell_t * shp)31037c2fbfb3SApril Chin void sh_unscope(Shell_t *shp)
3104da2e3ebdSchin {
31057c2fbfb3SApril Chin 	register Dt_t *root = shp->var_tree;
3106da2e3ebdSchin 	register Dt_t *dp = dtview(root,(Dt_t*)0);
31077c2fbfb3SApril Chin 	table_unset(shp,root,NV_RDONLY|NV_NOSCOPE,dp);
31087c2fbfb3SApril Chin 	if(shp->st.real_fun  && dp==shp->st.real_fun->sdict)
31097c2fbfb3SApril Chin 	{
31107c2fbfb3SApril Chin 		dp = dtview(dp,(Dt_t*)0);
31117c2fbfb3SApril Chin 		shp->st.real_fun->sdict->view = dp;
31127c2fbfb3SApril Chin 	}
31137c2fbfb3SApril Chin 	shp->var_tree=dp;
3114da2e3ebdSchin 	dtclose(root);
3115da2e3ebdSchin }
3116da2e3ebdSchin 
3117da2e3ebdSchin /*
3118da2e3ebdSchin  * The inverse of creating a reference node
3119da2e3ebdSchin  */
nv_unref(register Namval_t * np)3120da2e3ebdSchin void nv_unref(register Namval_t *np)
3121da2e3ebdSchin {
3122da2e3ebdSchin 	Namval_t *nq;
3123da2e3ebdSchin 	if(!nv_isref(np))
3124da2e3ebdSchin 		return;
3125da2e3ebdSchin 	nv_offattr(np,NV_NOFREE|NV_REF);
312634f9b3eeSRoland Mainz 	if(!np->nvalue.nrp)
312734f9b3eeSRoland Mainz 		return;
312834f9b3eeSRoland Mainz 	nq = nv_refnode(np);
3129da2e3ebdSchin 	free((void*)np->nvalue.nrp);
3130da2e3ebdSchin 	np->nvalue.cp = strdup(nv_name(nq));
3131da2e3ebdSchin #if SHOPT_OPTIMIZE
3132da2e3ebdSchin 	{
3133da2e3ebdSchin 		Namfun_t *fp;
3134da2e3ebdSchin 		for(fp=nq->nvfun; fp; fp = fp->next)
3135da2e3ebdSchin 		{
3136da2e3ebdSchin 			if(fp->disc== &optimize_disc)
3137da2e3ebdSchin 			{
3138da2e3ebdSchin 				optimize_clear(nq,fp);
3139da2e3ebdSchin 				return;
3140da2e3ebdSchin 			}
3141da2e3ebdSchin 		}
3142da2e3ebdSchin 	}
3143da2e3ebdSchin #endif
3144da2e3ebdSchin }
3145da2e3ebdSchin 
3146da2e3ebdSchin /*
3147da2e3ebdSchin  * These following are for binary compatibility with the old hash library
3148da2e3ebdSchin  * They will be removed someday
3149da2e3ebdSchin  */
3150da2e3ebdSchin 
3151da2e3ebdSchin #if defined(__IMPORT__) && defined(__EXPORT__)
3152da2e3ebdSchin #   define extern __EXPORT__
3153da2e3ebdSchin #endif
3154da2e3ebdSchin 
3155da2e3ebdSchin #undef	hashscope
3156da2e3ebdSchin 
hashscope(Dt_t * root)3157da2e3ebdSchin extern Dt_t *hashscope(Dt_t *root)
3158da2e3ebdSchin {
3159da2e3ebdSchin 	return(dtvnext(root));
3160da2e3ebdSchin }
3161da2e3ebdSchin 
3162da2e3ebdSchin #undef	hashfree
3163da2e3ebdSchin 
hashfree(Dt_t * root)3164da2e3ebdSchin extern Dt_t	*hashfree(Dt_t *root)
3165da2e3ebdSchin {
3166da2e3ebdSchin 	Dt_t *dp = dtvnext(root);
3167da2e3ebdSchin 	dtclose(root);
3168da2e3ebdSchin 	return(dp);
3169da2e3ebdSchin }
3170da2e3ebdSchin 
3171da2e3ebdSchin #undef	hashname
3172da2e3ebdSchin 
hashname(void * obj)3173da2e3ebdSchin extern char	*hashname(void *obj)
3174da2e3ebdSchin {
3175da2e3ebdSchin 	Namval_t *np = (Namval_t*)obj;
3176da2e3ebdSchin 	return(np->nvname);
3177da2e3ebdSchin }
3178da2e3ebdSchin 
3179da2e3ebdSchin #undef	hashlook
3180da2e3ebdSchin 
hashlook(Dt_t * root,const char * name,int mode,int size)3181da2e3ebdSchin extern void *hashlook(Dt_t *root, const char *name, int mode,int size)
3182da2e3ebdSchin {
3183da2e3ebdSchin 	NOT_USED(size);
3184da2e3ebdSchin 	return((void*)nv_search(name,root,mode));
3185da2e3ebdSchin }
3186da2e3ebdSchin 
nv_name(register Namval_t * np)3187da2e3ebdSchin char *nv_name(register Namval_t *np)
3188da2e3ebdSchin {
3189da2e3ebdSchin 	register Namval_t *table;
3190da2e3ebdSchin 	register Namfun_t *fp;
3191da2e3ebdSchin 	char *cp;
3192da2e3ebdSchin 	if(is_abuiltin(np) || is_afunction(np))
3193da2e3ebdSchin 		return(np->nvname);
31947c2fbfb3SApril Chin 	if(!nv_isattr(np,NV_MINIMAL|NV_EXPORT) && np->nvenv)
31957c2fbfb3SApril Chin 	{
31967c2fbfb3SApril Chin 		Namval_t *nq= sh.last_table, *mp= (Namval_t*)np->nvenv;
31977c2fbfb3SApril Chin 		if(np==sh.last_table)
31987c2fbfb3SApril Chin 			sh.last_table = 0;
31997c2fbfb3SApril Chin 		if(nv_isarray(mp))
32007c2fbfb3SApril Chin 			sfprintf(sh.strbuf,"%s[%s]",nv_name(mp),np->nvname);
32017c2fbfb3SApril Chin 		else
32027c2fbfb3SApril Chin 			sfprintf(sh.strbuf,"%s.%s",nv_name(mp),np->nvname);
32037c2fbfb3SApril Chin 		sh.last_table = nq;
32047c2fbfb3SApril Chin 		return(sfstruse(sh.strbuf));
32057c2fbfb3SApril Chin 	}
3206da2e3ebdSchin 	if(nv_istable(np))
3207da2e3ebdSchin #if 1
3208da2e3ebdSchin 		sh.last_table = nv_parent(np);
3209da2e3ebdSchin #else
3210da2e3ebdSchin 		sh.last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0);
3211da2e3ebdSchin #endif
3212da2e3ebdSchin 	else if(!nv_isref(np))
3213da2e3ebdSchin 	{
3214da2e3ebdSchin 		for(fp= np->nvfun ; fp; fp=fp->next)
3215da2e3ebdSchin 		if(fp->disc && fp->disc->namef)
3216da2e3ebdSchin 		{
3217da2e3ebdSchin 			if(np==sh.last_table)
3218da2e3ebdSchin 				sh.last_table = 0;
3219da2e3ebdSchin 			return((*fp->disc->namef)(np,fp));
3220da2e3ebdSchin 		}
3221da2e3ebdSchin 	}
3222da2e3ebdSchin 	if(!(table=sh.last_table) || *np->nvname=='.' || table==sh.namespace || np==table)
3223da2e3ebdSchin 		return(np->nvname);
3224da2e3ebdSchin 	cp = nv_name(table);
3225da2e3ebdSchin 	sfprintf(sh.strbuf,"%s.%s",cp,np->nvname);
3226da2e3ebdSchin 	return(sfstruse(sh.strbuf));
3227da2e3ebdSchin }
3228da2e3ebdSchin 
nv_lastdict(void)3229da2e3ebdSchin Namval_t *nv_lastdict(void)
3230da2e3ebdSchin {
3231da2e3ebdSchin 	return(sh.last_table);
3232da2e3ebdSchin }
3233da2e3ebdSchin 
3234da2e3ebdSchin #undef nv_context
3235da2e3ebdSchin /*
3236da2e3ebdSchin  * returns the data context for a builtin
3237da2e3ebdSchin  */
nv_context(Namval_t * np)3238da2e3ebdSchin void *nv_context(Namval_t *np)
3239da2e3ebdSchin {
3240da2e3ebdSchin 	return((void*)np->nvfun);
3241da2e3ebdSchin }
3242da2e3ebdSchin 
3243da2e3ebdSchin #define DISABLE /* proto workaround */
3244da2e3ebdSchin 
DISABLE(register Namval_t * np)3245da2e3ebdSchin int nv_isnull DISABLE (register Namval_t *np)
3246da2e3ebdSchin {
3247da2e3ebdSchin 	return(nv_isnull(np));
3248da2e3ebdSchin }
3249da2e3ebdSchin 
3250da2e3ebdSchin #undef nv_setsize
nv_setsize(register Namval_t * np,int size)3251da2e3ebdSchin int nv_setsize(register Namval_t *np, int size)
3252da2e3ebdSchin {
3253da2e3ebdSchin 	int oldsize = nv_size(np);
3254da2e3ebdSchin 	if(size>=0)
3255da2e3ebdSchin 		np->nvsize = size;
3256da2e3ebdSchin 	return(oldsize);
3257da2e3ebdSchin }
32587c2fbfb3SApril Chin 
nv_shell(Namval_t * np)32597c2fbfb3SApril Chin Shell_t	*nv_shell(Namval_t *np)
32607c2fbfb3SApril Chin {
32617c2fbfb3SApril Chin 	Namfun_t *fp;
32627c2fbfb3SApril Chin 	for(fp=np->nvfun;fp;fp=fp->next)
32637c2fbfb3SApril Chin 	{
32647c2fbfb3SApril Chin 		if(!fp->disc)
32657c2fbfb3SApril Chin 			return((Shell_t*)fp->last);
32667c2fbfb3SApril Chin 	}
32677c2fbfb3SApril Chin 	return(0);
32687c2fbfb3SApril Chin }
32697c2fbfb3SApril Chin 
32707c2fbfb3SApril Chin #undef nv_unset
32717c2fbfb3SApril Chin 
nv_unset(register Namval_t * np)32727c2fbfb3SApril Chin void	nv_unset(register Namval_t *np)
32737c2fbfb3SApril Chin {
32747c2fbfb3SApril Chin 	_nv_unset(np,0);
32757c2fbfb3SApril Chin 	return;
32767c2fbfb3SApril Chin }
3277