1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * AT&T Labs
23*4887Schin  *
24*4887Schin  */
25*4887Schin 
26*4887Schin #define putenv	___putenv
27*4887Schin 
28*4887Schin #include	"defs.h"
29*4887Schin #include	<ctype.h>
30*4887Schin #include	"variables.h"
31*4887Schin #include	"path.h"
32*4887Schin #include	"lexstates.h"
33*4887Schin #include	"timeout.h"
34*4887Schin #include	"FEATURE/externs"
35*4887Schin #include	"streval.h"
36*4887Schin 
37*4887Schin static char	*savesub = 0;
38*4887Schin 
39*4887Schin #if !_lib_pathnative && _lib_uwin_path
40*4887Schin 
41*4887Schin #define _lib_pathnative		1
42*4887Schin 
43*4887Schin extern int	uwin_path(const char*, char*, int);
44*4887Schin 
45*4887Schin size_t
46*4887Schin pathnative(const char* path, char* buf, size_t siz)
47*4887Schin {
48*4887Schin 	return uwin_path(path, buf, siz);
49*4887Schin }
50*4887Schin 
51*4887Schin #endif /* _lib_pathnative */
52*4887Schin 
53*4887Schin static void	attstore(Namval_t*,void*);
54*4887Schin #ifndef _ENV_H
55*4887Schin static void	pushnam(Namval_t*,void*);
56*4887Schin static char	*staknam(Namval_t*, char*);
57*4887Schin #endif
58*4887Schin static void	ltou(const char*,char*);
59*4887Schin static void	rightjust(char*, int, int);
60*4887Schin 
61*4887Schin struct adata
62*4887Schin {
63*4887Schin 	char    **argnam;
64*4887Schin 	int     attsize;
65*4887Schin 	char    *attval;
66*4887Schin };
67*4887Schin 
68*4887Schin char		nv_local = 0;
69*4887Schin #ifndef _ENV_H
70*4887Schin static void(*nullscan)(Namval_t*,void*);
71*4887Schin #endif
72*4887Schin 
73*4887Schin #if ( SFIO_VERSION  <= 20010201L )
74*4887Schin #   define _data        data
75*4887Schin #endif
76*4887Schin 
77*4887Schin #if !SHOPT_MULTIBYTE
78*4887Schin #   define mbchar(p)       (*(unsigned char*)p++)
79*4887Schin #endif /* SHOPT_MULTIBYTE */
80*4887Schin 
81*4887Schin /* ========	name value pair routines	======== */
82*4887Schin 
83*4887Schin #include	"shnodes.h"
84*4887Schin #include	"builtins.h"
85*4887Schin 
86*4887Schin static char *getbuf(size_t len)
87*4887Schin {
88*4887Schin 	static char *buf;
89*4887Schin 	static size_t buflen;
90*4887Schin 	if(buflen < len)
91*4887Schin 	{
92*4887Schin 		if(buflen==0)
93*4887Schin 			buf = (char*)malloc(len);
94*4887Schin 		else
95*4887Schin 			buf = (char*)realloc(buf,len);
96*4887Schin 		buflen = len;
97*4887Schin 	}
98*4887Schin 	return(buf);
99*4887Schin }
100*4887Schin 
101*4887Schin #ifdef _ENV_H
102*4887Schin void sh_envput(Env_t* ep,Namval_t *np)
103*4887Schin {
104*4887Schin 	int offset = staktell();
105*4887Schin 	Namarr_t *ap = nv_arrayptr(np);
106*4887Schin 	char *val;
107*4887Schin 	if(ap)
108*4887Schin 	{
109*4887Schin 		if(ap->nelem&ARRAY_UNDEF)
110*4887Schin 			nv_putsub(np,"0",0L);
111*4887Schin 		else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
112*4887Schin 			return;
113*4887Schin 	}
114*4887Schin 	if(!(val = nv_getval(np)))
115*4887Schin 		return;
116*4887Schin 	stakputs(nv_name(np));
117*4887Schin 	stakputc('=');
118*4887Schin 	stakputs(val);
119*4887Schin 	stakseek(offset);
120*4887Schin 	env_add(ep,stakptr(offset),ENV_STRDUP);
121*4887Schin }
122*4887Schin #endif
123*4887Schin 
124*4887Schin /*
125*4887Schin  * output variable name in format for re-input
126*4887Schin  */
127*4887Schin void nv_outname(Sfio_t *out, char *name, int len)
128*4887Schin {
129*4887Schin 	const char *cp=name, *sp;
130*4887Schin 	int c, offset = staktell();
131*4887Schin 	while(sp= strchr(cp,'['))
132*4887Schin 	{
133*4887Schin 		if(len>0 && cp+len <= sp)
134*4887Schin 			break;
135*4887Schin 		sfwrite(out,cp,++sp-cp);
136*4887Schin 		stakseek(offset);
137*4887Schin 		for(; c= *sp; sp++)
138*4887Schin 		{
139*4887Schin 			if(c==']')
140*4887Schin 				break;
141*4887Schin 			else if(c=='\\')
142*4887Schin 			{
143*4887Schin 				if(*sp=='[' || *sp==']' || *sp=='\\')
144*4887Schin 					c = *sp++;
145*4887Schin 			}
146*4887Schin 			stakputc(c);
147*4887Schin 		}
148*4887Schin 		stakputc(0);
149*4887Schin 		sfputr(out,sh_fmtq(stakptr(offset)),-1);
150*4887Schin 		if(len>0)
151*4887Schin 		{
152*4887Schin 			sfputc(out,']');
153*4887Schin 			return;
154*4887Schin 		}
155*4887Schin 		cp = sp;
156*4887Schin 	}
157*4887Schin 	if(*cp)
158*4887Schin 	{
159*4887Schin 		if(len>0)
160*4887Schin 			sfwrite(out,cp,len);
161*4887Schin 		else
162*4887Schin 			sfputr(out,cp,-1);
163*4887Schin 	}
164*4887Schin 	stakseek(offset);
165*4887Schin }
166*4887Schin 
167*4887Schin /*
168*4887Schin  * Perform parameter assignment for a linked list of parameters
169*4887Schin  * <flags> contains attributes for the parameters
170*4887Schin  */
171*4887Schin void nv_setlist(register struct argnod *arg,register int flags)
172*4887Schin {
173*4887Schin 	register char	*cp;
174*4887Schin 	register Namval_t *np;
175*4887Schin 	char		*trap=sh.st.trap[SH_DEBUGTRAP];
176*4887Schin 	int		traceon = (sh_isoption(SH_XTRACE)!=0);
177*4887Schin 	int		array = (flags&(NV_ARRAY|NV_IARRAY));
178*4887Schin 	flags &= ~(NV_TYPE|NV_ARRAY);
179*4887Schin 	if(sh_isoption(SH_ALLEXPORT))
180*4887Schin 		flags |= NV_EXPORT;
181*4887Schin 	if(sh.prefix)
182*4887Schin 	{
183*4887Schin 		flags &= ~(NV_IDENT|NV_EXPORT);
184*4887Schin 		flags |= NV_VARNAME;
185*4887Schin 	}
186*4887Schin 	for(;arg; arg=arg->argnxt.ap)
187*4887Schin 	{
188*4887Schin 		sh.used_pos = 0;
189*4887Schin 		if(arg->argflag&ARG_MAC)
190*4887Schin 			cp = sh_mactrim(arg->argval,-1);
191*4887Schin 		else
192*4887Schin 		{
193*4887Schin 			Namval_t *mp;
194*4887Schin 			stakseek(0);
195*4887Schin 			if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED)))
196*4887Schin 			{
197*4887Schin 				int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
198*4887Schin 				struct fornod *fp=(struct fornod*)arg->argchn.ap;
199*4887Schin 				register Shnode_t *tp=fp->fortre;
200*4887Schin 				char *prefix = sh.prefix;
201*4887Schin 				flag |= (flags&NV_NOSCOPE);
202*4887Schin 				if(arg->argflag&ARG_QUOTED)
203*4887Schin 					cp = sh_mactrim(fp->fornam,-1);
204*4887Schin 				else
205*4887Schin 					cp = fp->fornam;
206*4887Schin 				error_info.line = fp->fortyp-sh.st.firstline;
207*4887Schin 				if(sh.fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET)
208*4887Schin 			                flag |= NV_NOSCOPE;
209*4887Schin 				if(prefix && tp->com.comset && *cp=='[')
210*4887Schin 				{
211*4887Schin 					sh.prefix = 0;
212*4887Schin 					np = nv_open(prefix,sh.var_tree,flag);
213*4887Schin 					sh.prefix = prefix;
214*4887Schin 					if(np)
215*4887Schin 					{
216*4887Schin 						if(!nv_isarray(np))
217*4887Schin 						{
218*4887Schin 							stakputc('.');
219*4887Schin 							stakputs(cp);
220*4887Schin 							cp = stakfreeze(1);
221*4887Schin 						}
222*4887Schin 						nv_close(np);
223*4887Schin 					}
224*4887Schin 				}
225*4887Schin 				np = nv_open(cp,sh.var_tree,flag);
226*4887Schin 				if(array)
227*4887Schin 				{
228*4887Schin 					if(!(flags&NV_APPEND))
229*4887Schin 						nv_unset(np);
230*4887Schin 					if(array&NV_ARRAY)
231*4887Schin 					{
232*4887Schin 						nv_setarray(np,nv_associative);
233*4887Schin 					}
234*4887Schin 					else
235*4887Schin 					{
236*4887Schin 						nv_onattr(np,NV_ARRAY);
237*4887Schin 					}
238*4887Schin 				}
239*4887Schin 				/* check for array assignment */
240*4887Schin 				if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))
241*4887Schin 				{
242*4887Schin 					int argc;
243*4887Schin 					char **argv = sh_argbuild(&argc,&tp->com,0);
244*4887Schin 					if(!(arg->argflag&ARG_APPEND))
245*4887Schin 					{
246*4887Schin 						nv_unset(np);
247*4887Schin 					}
248*4887Schin 					nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv);
249*4887Schin 					if(traceon || trap)
250*4887Schin 					{
251*4887Schin 						int n = -1;
252*4887Schin 						char *name = nv_name(np);
253*4887Schin 						if(arg->argflag&ARG_APPEND)
254*4887Schin 							n = '+';
255*4887Schin 						if(trap)
256*4887Schin 							sh_debug(trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN);
257*4887Schin 						if(traceon)
258*4887Schin 						{
259*4887Schin 							sh_trace(NIL(char**),0);
260*4887Schin 							sfputr(sfstderr,name,n);
261*4887Schin 							sfwrite(sfstderr,"=( ",3);
262*4887Schin 							while(cp= *argv++)
263*4887Schin 								sfputr(sfstderr,sh_fmtq(cp),' ');
264*4887Schin 							sfwrite(sfstderr,")\n",2);
265*4887Schin 						}
266*4887Schin 					}
267*4887Schin 					continue;
268*4887Schin 				}
269*4887Schin 				if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[')
270*4887Schin 				{
271*4887Schin 					if(*cp!='.' && *cp!='[' && strchr(cp,'['))
272*4887Schin 					{
273*4887Schin 						nv_close(np);
274*4887Schin 						np = nv_open(cp,sh.var_tree,flag);
275*4887Schin 					}
276*4887Schin 					if((arg->argflag&ARG_APPEND) && !nv_isarray(np))
277*4887Schin 						nv_unset(np);
278*4887Schin 				}
279*4887Schin 				else
280*4887Schin 				{
281*4887Schin 					if(sh_isoption(SH_BASH) || (array&NV_IARRAY))
282*4887Schin 					{
283*4887Schin 						if(!(arg->argflag&ARG_APPEND))
284*4887Schin 							nv_unset(np);
285*4887Schin 					}
286*4887Schin 					else if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0)))
287*4887Schin 					{
288*4887Schin 						nv_unset(np);
289*4887Schin 						nv_setarray(np,nv_associative);
290*4887Schin 					}
291*4887Schin 					else
292*4887Schin 						nv_setarray(np,nv_associative);
293*4887Schin 				}
294*4887Schin 				if(prefix)
295*4887Schin 					cp = stakcopy(nv_name(np));
296*4887Schin 				sh.prefix = cp;
297*4887Schin 				sh_exec(tp,sh_isstate(SH_ERREXIT));
298*4887Schin 				sh.prefix = prefix;
299*4887Schin 				if(nv_isarray(np) && (mp=nv_opensub(np)))
300*4887Schin 					np = mp;
301*4887Schin 				nv_setvtree(np);
302*4887Schin 				continue;
303*4887Schin 			}
304*4887Schin 			cp = arg->argval;
305*4887Schin 		}
306*4887Schin 		if(sh.prefix && *cp=='.' && cp[1]=='=')
307*4887Schin 			cp++;
308*4887Schin 		np = nv_open(cp,sh.var_tree,flags);
309*4887Schin 		if(!np->nvfun)
310*4887Schin 		{
311*4887Schin 			if(sh.used_pos)
312*4887Schin 				nv_onattr(np,NV_PARAM);
313*4887Schin 			else
314*4887Schin 				nv_offattr(np,NV_PARAM);
315*4887Schin 		}
316*4887Schin 		if(traceon || trap)
317*4887Schin 		{
318*4887Schin 			register char *sp=cp;
319*4887Schin 			char *name=nv_name(np);
320*4887Schin 			char *sub=0;
321*4887Schin 			int append = 0;
322*4887Schin 			if(nv_isarray(np))
323*4887Schin 				sub = savesub;
324*4887Schin 			if(cp=strchr(sp,'='))
325*4887Schin 			{
326*4887Schin 				if(cp[-1]=='+')
327*4887Schin 					append = ARG_APPEND;
328*4887Schin 				cp++;
329*4887Schin 			}
330*4887Schin 			if(traceon)
331*4887Schin 			{
332*4887Schin 				sh_trace(NIL(char**),0);
333*4887Schin 				nv_outname(sfstderr,name,-1);
334*4887Schin 				if(sub)
335*4887Schin 					sfprintf(sfstderr,"[%s]",sh_fmtq(sub));
336*4887Schin 				if(cp)
337*4887Schin 				{
338*4887Schin 					if(append)
339*4887Schin 						sfputc(sfstderr,'+');
340*4887Schin 					sfprintf(sfstderr,"=%s\n",sh_fmtq(cp));
341*4887Schin 				}
342*4887Schin 			}
343*4887Schin 			if(trap)
344*4887Schin 			{
345*4887Schin 					char *av[2];
346*4887Schin 					av[0] = cp;
347*4887Schin 					av[1] = 0;
348*4887Schin 					sh_debug(trap,name,sub,av,append);
349*4887Schin 			}
350*4887Schin 		}
351*4887Schin 	}
352*4887Schin }
353*4887Schin 
354*4887Schin /*
355*4887Schin  * copy the subscript onto the stack
356*4887Schin  */
357*4887Schin static void stak_subscript(const char *sub, int last)
358*4887Schin {
359*4887Schin 	register int c;
360*4887Schin 	stakputc('[');
361*4887Schin 	while(c= *sub++)
362*4887Schin 	{
363*4887Schin 		if(c=='[' || c==']' || c=='\\')
364*4887Schin 			stakputc('\\');
365*4887Schin 		stakputc(c);
366*4887Schin 	}
367*4887Schin 	stakputc(last);
368*4887Schin }
369*4887Schin 
370*4887Schin /*
371*4887Schin  * construct a new name from a prefix and base name on the stack
372*4887Schin  */
373*4887Schin static char *copystack(const char *prefix, register const char *name, const char *sub)
374*4887Schin {
375*4887Schin 	register int last=0,offset = staktell();
376*4887Schin 	if(prefix)
377*4887Schin 	{
378*4887Schin 		stakputs(prefix);
379*4887Schin 		if(*stakptr(staktell()-1)=='.')
380*4887Schin 			stakseek(staktell()-1);
381*4887Schin 		if(*name=='.' && name[1]=='[')
382*4887Schin 			last = staktell()+2;
383*4887Schin 		if(*name!='[' && *name!='.' && *name!='=' && *name!='+')
384*4887Schin 			stakputc('.');
385*4887Schin 	}
386*4887Schin 	if(last)
387*4887Schin 	{
388*4887Schin 		stakputs(name);
389*4887Schin 		if(sh_checkid(stakptr(last),(char*)0))
390*4887Schin 			stakseek(staktell()-2);
391*4887Schin 	}
392*4887Schin 	if(sub)
393*4887Schin 		stak_subscript(sub,']');
394*4887Schin 	if(!last)
395*4887Schin 		stakputs(name);
396*4887Schin 	stakputc(0);
397*4887Schin 	return(stakptr(offset));
398*4887Schin }
399*4887Schin 
400*4887Schin /*
401*4887Schin  * grow this stack string <name> by <n> bytes and move from cp-1 to end
402*4887Schin  * right by <n>.  Returns beginning of string on the stack
403*4887Schin  */
404*4887Schin static char *stack_extend(const char *cname, char *cp, int n)
405*4887Schin {
406*4887Schin 	register char *name = (char*)cname;
407*4887Schin 	int offset = name - stakptr(0);
408*4887Schin 	int m = cp-name;
409*4887Schin 	stakseek(strlen(name)+n+1);
410*4887Schin 	name = stakptr(offset);
411*4887Schin 	cp =  name + m;
412*4887Schin 	m = strlen(cp)+1;
413*4887Schin 	while(m-->0)
414*4887Schin 		cp[n+m]=cp[m];
415*4887Schin 	return((char*)name);
416*4887Schin }
417*4887Schin 
418*4887Schin Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp)
419*4887Schin {
420*4887Schin 	char			*cp=(char*)name, *sp, *xp;
421*4887Schin 	register int		c;
422*4887Schin 	register Namval_t	*np=0, *nq=0;
423*4887Schin 	Namfun_t		*fp=0;
424*4887Schin 	long			mode, add=0;
425*4887Schin 	int			copy=1,isref,top=0,noscope=(flags&NV_NOSCOPE);
426*4887Schin 	if(root==sh.var_tree)
427*4887Schin 	{
428*4887Schin 		if(dtvnext(root))
429*4887Schin 			top = 1;
430*4887Schin 		else
431*4887Schin 			flags &= ~NV_NOSCOPE;
432*4887Schin 	}
433*4887Schin 	if(!dp->disc)
434*4887Schin 		copy = dp->nofree;
435*4887Schin 	if(*cp=='.')
436*4887Schin 		cp++;
437*4887Schin 	while(1)
438*4887Schin 	{
439*4887Schin 		switch(c = *(unsigned char*)(sp = cp))
440*4887Schin 		{
441*4887Schin 		    case '[':
442*4887Schin 			if(flags&NV_NOARRAY)
443*4887Schin 			{
444*4887Schin 				dp->last = cp;
445*4887Schin 				return(np);
446*4887Schin 			}
447*4887Schin 			cp = nv_endsubscript((Namval_t*)0,sp,0);
448*4887Schin 			if(sp==name || sp[-1]=='.')
449*4887Schin 				c = *(sp = cp);
450*4887Schin 			goto skip;
451*4887Schin 		    case '.':
452*4887Schin 			if(flags&NV_IDENT)
453*4887Schin 				return(0);
454*4887Schin 			if(root==sh.var_tree)
455*4887Schin 				flags &= ~NV_EXPORT;
456*4887Schin 			if(!copy && !(flags&NV_NOREF))
457*4887Schin 			{
458*4887Schin 				c = sp-name;
459*4887Schin 				copy = cp-name;
460*4887Schin 				dp->nofree = 1;
461*4887Schin 				name = copystack((const char*)0, name,(const char*)0);
462*4887Schin 				cp = (char*)name+copy;
463*4887Schin 				sp = (char*)name+c;
464*4887Schin 				c = '.';
465*4887Schin 			}
466*4887Schin 		skip:
467*4887Schin 		    case '+':
468*4887Schin 		    case '=':
469*4887Schin 			*sp = 0;
470*4887Schin 		    case 0:
471*4887Schin 			isref = 0;
472*4887Schin 			dp->last = cp;
473*4887Schin 			mode =  (c=='.' || (flags&NV_NOADD))?add:NV_ADD;
474*4887Schin 			if(flags&NV_NOSCOPE)
475*4887Schin 				mode |= HASH_NOSCOPE;
476*4887Schin 			if(top)
477*4887Schin 				nq = nv_search(name,sh.var_base,0);
478*4887Schin 			if(np = nv_search(name,root,mode))
479*4887Schin 			{
480*4887Schin 				isref = nv_isref(np);
481*4887Schin 				if(top)
482*4887Schin 				{
483*4887Schin 					if(nq==np)
484*4887Schin 						flags &= ~NV_NOSCOPE;
485*4887Schin 					else if(nq)
486*4887Schin 					{
487*4887Schin 						if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq)))
488*4887Schin 							np->nvname = nq->nvname;
489*4887Schin 						flags |= NV_NOSCOPE;
490*4887Schin 					}
491*4887Schin 				}
492*4887Schin 				else if(add && nv_isnull(np) && c=='.')
493*4887Schin 					nv_setvtree(np);
494*4887Schin 			}
495*4887Schin 			if(c)
496*4887Schin 				*sp = c;
497*4887Schin 			top = 0;
498*4887Schin 			if(isref)
499*4887Schin 			{
500*4887Schin 				char *sub=0;
501*4887Schin 				if(c=='.') /* don't optimize */
502*4887Schin 					sh.argaddr = 0;
503*4887Schin 				else if(flags&NV_NOREF)
504*4887Schin 				{
505*4887Schin 					if(c)
506*4887Schin 						nv_unref(np);
507*4887Schin 					return(np);
508*4887Schin 				}
509*4887Schin 				while(nv_isref(np))
510*4887Schin 				{
511*4887Schin 					root = nv_reftree(np);
512*4887Schin 					sh.last_table = nv_reftable(np);
513*4887Schin 					sub = nv_refsub(np);
514*4887Schin 					np = nv_refnode(np);
515*4887Schin 					if(sub && c!='.')
516*4887Schin 						nv_putsub(np,sub,0L);
517*4887Schin 					flags |= NV_NOSCOPE;
518*4887Schin 				}
519*4887Schin 				if(sub && c==0)
520*4887Schin 					return(np);
521*4887Schin 				if(np==nq)
522*4887Schin 					flags &= ~(noscope?0:NV_NOSCOPE);
523*4887Schin 				else if(c)
524*4887Schin 				{
525*4887Schin 					c = (cp-sp);
526*4887Schin 					copy = strlen(cp=nv_name(np));
527*4887Schin 					dp->nofree = 1;
528*4887Schin 					name = copystack(cp,sp,sub);
529*4887Schin 					sp = (char*)name + copy;
530*4887Schin 					cp = sp+c;
531*4887Schin 					c = *sp;
532*4887Schin 					if(!noscope)
533*4887Schin 						flags &= ~NV_NOSCOPE;
534*4887Schin 				}
535*4887Schin 				flags |= NV_NOREF;
536*4887Schin 			}
537*4887Schin 			sh.last_root = root;
538*4887Schin 			do
539*4887Schin 			{
540*4887Schin 				if(!np)
541*4887Schin 				{
542*4887Schin 					if(*sp=='[' && *cp==0 && cp[-1]==']')
543*4887Schin 					{
544*4887Schin 						/*
545*4887Schin 						 * for backward compatibility
546*4887Schin 						 * evaluate subscript for
547*4887Schin 						 * possible side effects
548*4887Schin 						 */
549*4887Schin 						cp[-1] = 0;
550*4887Schin 						sh_arith(sp+1);
551*4887Schin 						cp[-1] = ']';
552*4887Schin 					}
553*4887Schin 					return(np);
554*4887Schin 				}
555*4887Schin 				if(c=='[' || (c=='.' && nv_isarray(np)))
556*4887Schin 				{
557*4887Schin 					int n = 0;
558*4887Schin 					if(c=='[')
559*4887Schin 					{
560*4887Schin 						n = mode|nv_isarray(np);
561*4887Schin 						if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']')
562*4887Schin 						{
563*4887Schin 							/* not implemented yet */
564*4887Schin 							dp->last = cp;
565*4887Schin 							return(np);
566*4887Schin 						}
567*4887Schin 						if(n&&(flags&NV_ARRAY))
568*4887Schin 							n |= ARRAY_FILL;
569*4887Schin 						cp = nv_endsubscript(np,sp,n);
570*4887Schin 					}
571*4887Schin 					else
572*4887Schin 						cp = sp;
573*4887Schin 					if((c = *cp)=='.' || c=='[' || (n&ARRAY_FILL))
574*4887Schin 
575*4887Schin 					{
576*4887Schin 						int m = cp-sp;
577*4887Schin 						char *sub = m?nv_getsub(np):0;
578*4887Schin 						if(!sub)
579*4887Schin 							sub = "0";
580*4887Schin 						n = strlen(sub)+2;
581*4887Schin 						if(!copy)
582*4887Schin 						{
583*4887Schin 							copy = cp-name;
584*4887Schin 							dp->nofree = 1;
585*4887Schin 							name = copystack((const char*)0, name,(const char*)0);
586*4887Schin 							cp = (char*)name+copy;
587*4887Schin 							sp = cp-m;
588*4887Schin 						}
589*4887Schin 						if(n <= m)
590*4887Schin 						{
591*4887Schin 							if(n)
592*4887Schin 							{
593*4887Schin 								memcpy(sp+1,sub,n-2);
594*4887Schin 								sp[n-1] = ']';
595*4887Schin 							}
596*4887Schin 							if(n < m)
597*4887Schin 								cp=strcpy(sp+n,cp);
598*4887Schin 						}
599*4887Schin 						else
600*4887Schin 						{
601*4887Schin 							int r = n-m;
602*4887Schin 							m = sp-name;
603*4887Schin 							name = stack_extend(name, cp-1, r);
604*4887Schin 							sp = (char*)name + m;
605*4887Schin 							*sp = '[';
606*4887Schin 							memcpy(sp+1,sub,n-2);
607*4887Schin 							sp[n-1] = ']';
608*4887Schin 							cp = sp+n;
609*4887Schin 
610*4887Schin 						}
611*4887Schin 					}
612*4887Schin 					else if(c==0 && mode && (n=nv_aindex(np))>0)
613*4887Schin 						nv_putsub(np,(char*)0,n|ARRAY_FILL);
614*4887Schin 					else if(n==0 && c==0)
615*4887Schin 					{
616*4887Schin 						/* subscript must be 0*/
617*4887Schin 						cp[-1] = 0;
618*4887Schin 						c = sh_arith(sp+1);
619*4887Schin 						cp[-1] = ']';
620*4887Schin 						if(c)
621*4887Schin 							return(0);
622*4887Schin 					}
623*4887Schin 					dp->last = cp;
624*4887Schin 					if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY)))
625*4887Schin 					{
626*4887Schin 						*(sp=cp) = 0;
627*4887Schin 						nq = nv_search(name,root,mode);
628*4887Schin 						*sp = c;
629*4887Schin 						if(nq && nv_isnull(nq))
630*4887Schin 							nq = nv_arraychild(np,nq,c);
631*4887Schin 						if(!(np=nq))
632*4887Schin 							return(np);
633*4887Schin 					}
634*4887Schin 				}
635*4887Schin 				else if(nv_isarray(np))
636*4887Schin 					nv_putsub(np,NIL(char*),ARRAY_UNDEF);
637*4887Schin 				if(c=='.' && (fp=np->nvfun))
638*4887Schin 				{
639*4887Schin 					for(; fp; fp=fp->next)
640*4887Schin 					{
641*4887Schin 						if(fp->disc && fp->disc->createf)
642*4887Schin 							break;
643*4887Schin 					}
644*4887Schin 					if(fp)
645*4887Schin 					{
646*4887Schin 						if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np)
647*4887Schin 						{
648*4887Schin 							add = NV_ADD;
649*4887Schin 							break;
650*4887Schin 						}
651*4887Schin 						else if((np=nq) && (c = *(cp=dp->last=fp->last))==0)
652*4887Schin 							return(np);
653*4887Schin 					}
654*4887Schin 				}
655*4887Schin 			}
656*4887Schin 			while(c=='[');
657*4887Schin 			if(c!='.')
658*4887Schin 				return(np);
659*4887Schin 			cp++;
660*4887Schin 			break;
661*4887Schin 		    default:
662*4887Schin 			dp->last = cp;
663*4887Schin 			if((c = mbchar(cp)) && !isaletter(c))
664*4887Schin 				return(np);
665*4887Schin 			while(xp=cp, c=mbchar(cp), isaname(c));
666*4887Schin 			cp = xp;
667*4887Schin 		}
668*4887Schin 	}
669*4887Schin 	return(np);
670*4887Schin }
671*4887Schin 
672*4887Schin /*
673*4887Schin  * Put <arg> into associative memory.
674*4887Schin  * If <flags> & NV_ARRAY then follow array to next subscript
675*4887Schin  * If <flags> & NV_NOARRAY then subscript is not allowed
676*4887Schin  * If <flags> & NV_NOSCOPE then use the current scope only
677*4887Schin  * If <flags> & NV_ASSIGN then assignment is allowed
678*4887Schin  * If <flags> & NV_IDENT then name must be an identifier
679*4887Schin  * If <flags> & NV_VARNAME then name must be a valid variable name
680*4887Schin  * If <flags> & NV_NOADD then node will not be added if not found
681*4887Schin  * If <flags> & NV_NOREF then don't follow reference
682*4887Schin  * If <flags> & NV_NOFAIL then don't generate an error message on failure
683*4887Schin  * SH_INIT is only set while initializing the environment
684*4887Schin  */
685*4887Schin Namval_t *nv_open(const char *name, Dt_t *root, int flags)
686*4887Schin {
687*4887Schin 	register char		*cp=(char*)name;
688*4887Schin 	register int		c;
689*4887Schin 	register Namval_t	*np;
690*4887Schin 	Namfun_t		fun;
691*4887Schin 	int			append=0;
692*4887Schin 	const char		*msg = e_varname;
693*4887Schin 	char			*fname = 0;
694*4887Schin 	int			offset = staktell();
695*4887Schin 	Dt_t			*funroot;
696*4887Schin 
697*4887Schin 	memset(&fun,0,sizeof(fun));
698*4887Schin 	sh.last_table = sh.namespace;
699*4887Schin 	if(!root)
700*4887Schin 		root = sh.var_tree;
701*4887Schin 	sh.last_root = root;
702*4887Schin 	if(root==sh_subfuntree(1))
703*4887Schin 	{
704*4887Schin 		flags |= NV_NOREF;
705*4887Schin 		msg = e_badfun;
706*4887Schin 		if((np=sh.namespace) || strchr(name,'.'))
707*4887Schin 		{
708*4887Schin 			name = cp = copystack(np?nv_name(np):0,name,(const char*)0);
709*4887Schin 			fname = strrchr(cp,'.');
710*4887Schin 			*fname = 0;
711*4887Schin 			fun.nofree = 1;
712*4887Schin 			flags &=  ~NV_IDENT;
713*4887Schin 			funroot = root;
714*4887Schin 			root = sh.var_tree;
715*4887Schin 		}
716*4887Schin 	}
717*4887Schin 	else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
718*4887Schin 	{
719*4887Schin 		long mode = ((flags&NV_NOADD)?0:NV_ADD);
720*4887Schin 		if(flags&NV_NOSCOPE)
721*4887Schin 			mode |= HASH_SCOPE|HASH_NOSCOPE;
722*4887Schin 		np = nv_search(name,root,mode);
723*4887Schin 		if(np && !(flags&NV_REF))
724*4887Schin 		{
725*4887Schin 			while(nv_isref(np))
726*4887Schin 			{
727*4887Schin 				sh.last_table = nv_reftable(np);
728*4887Schin 				np = nv_refnode(np);
729*4887Schin 			}
730*4887Schin 		}
731*4887Schin 		return(np);
732*4887Schin 	}
733*4887Schin 	else if(sh.prefix && /**name!='.' &&*/ (flags&NV_ASSIGN))
734*4887Schin 	{
735*4887Schin 		name = cp = copystack(sh.prefix,name,(const char*)0);
736*4887Schin 		fun.nofree = 1;
737*4887Schin 	}
738*4887Schin 	c = *(unsigned char*)cp;
739*4887Schin 	if(root==sh.alias_tree)
740*4887Schin 	{
741*4887Schin 		msg = e_aliname;
742*4887Schin 		while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
743*4887Schin 			(c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT));
744*4887Schin 		if(sh.subshell && c=='=')
745*4887Schin 			root = sh_subaliastree(1);
746*4887Schin 		if(c= *--cp)
747*4887Schin 			*cp = 0;
748*4887Schin 		np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);
749*4887Schin 		if(c)
750*4887Schin 			*cp = c;
751*4887Schin 		goto skip;
752*4887Schin 	}
753*4887Schin 	else if(flags&NV_IDENT)
754*4887Schin 		msg = e_ident;
755*4887Schin 	else if(c=='.')
756*4887Schin 	{
757*4887Schin 		c = *++cp;
758*4887Schin 		flags |= NV_NOREF;
759*4887Schin 		if(root==sh.var_tree)
760*4887Schin 			root = sh.var_base;
761*4887Schin 		sh.last_table = 0;
762*4887Schin 	}
763*4887Schin 	if(c= !isaletter(c))
764*4887Schin 		goto skip;
765*4887Schin 	np = nv_create(name, root, flags, &fun);
766*4887Schin 	cp = fun.last;
767*4887Schin 	if(fname)
768*4887Schin 	{
769*4887Schin 		c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD);
770*4887Schin 		*fname = '.';
771*4887Schin 		np = nv_search(name, funroot, c);
772*4887Schin 		*fname = 0;
773*4887Schin 	}
774*4887Schin 	else if(*cp=='+' && cp[1]=='=')
775*4887Schin 	{
776*4887Schin 		append=NV_APPEND;
777*4887Schin 		cp++;
778*4887Schin 	}
779*4887Schin 	c = *cp;
780*4887Schin skip:
781*4887Schin 	if(c=='=' && np && (flags&NV_ASSIGN))
782*4887Schin 	{
783*4887Schin 		cp++;
784*4887Schin 		if(sh_isstate(SH_INIT))
785*4887Schin 		{
786*4887Schin 			nv_putval(np, cp, NV_RDONLY);
787*4887Schin 			if(np==PWDNOD)
788*4887Schin 				nv_onattr(np,NV_TAGGED);
789*4887Schin 		}
790*4887Schin 		else
791*4887Schin 		{
792*4887Schin 			char *sub=0;
793*4887Schin 			if(sh_isoption(SH_XTRACE) && nv_isarray(np))
794*4887Schin 				sub = nv_getsub(np);
795*4887Schin 			c = msg==e_aliname? 0: (append | (flags&NV_EXPORT));
796*4887Schin 			nv_putval(np, cp, c);
797*4887Schin 			savesub = sub;
798*4887Schin 		}
799*4887Schin 		nv_onattr(np, flags&NV_ATTRIBUTES);
800*4887Schin 	}
801*4887Schin 	else if(c)
802*4887Schin 	{
803*4887Schin 		if(flags&NV_NOFAIL)
804*4887Schin 			return(0);
805*4887Schin 		if(c=='.')
806*4887Schin 			msg = e_noparent;
807*4887Schin 		else if(c=='[')
808*4887Schin 			msg = e_noarray;
809*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),msg,name);
810*4887Schin 	}
811*4887Schin 	if(fun.nofree)
812*4887Schin 		stakseek(offset);
813*4887Schin 	return(np);
814*4887Schin }
815*4887Schin 
816*4887Schin #if SHOPT_MULTIBYTE
817*4887Schin     static int ja_size(char*, int, int);
818*4887Schin     static void ja_restore(void);
819*4887Schin     static char *savep;
820*4887Schin     static char savechars[8+1];
821*4887Schin #endif /* SHOPT_MULTIBYTE */
822*4887Schin 
823*4887Schin /*
824*4887Schin  * put value <string> into name-value node <np>.
825*4887Schin  * If <np> is an array, then the element given by the
826*4887Schin  *   current index is assigned to.
827*4887Schin  * If <flags> contains NV_RDONLY, readonly attribute is ignored
828*4887Schin  * If <flags> contains NV_INTEGER, string is a pointer to a number
829*4887Schin  * If <flags> contains NV_NOFREE, previous value is freed, and <string>
830*4887Schin  * becomes value of node and <flags> becomes attributes
831*4887Schin  */
832*4887Schin void nv_putval(register Namval_t *np, const char *string, int flags)
833*4887Schin {
834*4887Schin 	register const char *sp=string;
835*4887Schin 	register union Value *up;
836*4887Schin 	register char *cp;
837*4887Schin 	register int size = 0;
838*4887Schin 	register int dot;
839*4887Schin 	int	was_local = nv_local;
840*4887Schin 	if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
841*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
842*4887Schin 	/* The following could cause the shell to fork if assignment
843*4887Schin 	 * would cause a side effect
844*4887Schin 	 */
845*4887Schin 	sh.argaddr = 0;
846*4887Schin 	if(sh.subshell && !nv_local)
847*4887Schin 		np = sh_assignok(np,1);
848*4887Schin 	if(np->nvfun && !nv_isattr(np,NV_REF))
849*4887Schin 	{
850*4887Schin 		/* This function contains disc */
851*4887Schin 		if(!nv_local)
852*4887Schin 		{
853*4887Schin 			nv_local=1;
854*4887Schin 			nv_putv(np,sp,flags,np->nvfun);
855*4887Schin 			if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
856*4887Schin 				sh_envput(sh.env,np);
857*4887Schin 			return;
858*4887Schin 		}
859*4887Schin 		/* called from disc, assign the actual value */
860*4887Schin 	}
861*4887Schin 	flags &= ~NV_NODISC;
862*4887Schin 	if(flags&(NV_NOREF|NV_NOFREE))
863*4887Schin 	{
864*4887Schin 		if(!nv_isnull(np) && np->nvalue.cp!=sp)
865*4887Schin 			nv_unset(np);
866*4887Schin 		nv_local=0;
867*4887Schin 		np->nvalue.cp = (char*)sp;
868*4887Schin 		nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE);
869*4887Schin 		return;
870*4887Schin 	}
871*4887Schin 	nv_local=0;
872*4887Schin 	up= &np->nvalue;
873*4887Schin #if !SHOPT_BSH
874*4887Schin 	if(nv_isattr(np,NV_EXPORT))
875*4887Schin 		nv_offattr(np,NV_IMPORT);
876*4887Schin 	else if(!nv_isattr(np,NV_MINIMAL))
877*4887Schin 		np->nvenv = 0;
878*4887Schin #endif /* SHOPT_BSH */
879*4887Schin 	if(nv_isattr (np, NV_INTEGER))
880*4887Schin 	{
881*4887Schin 		if(nv_isattr(np, NV_DOUBLE))
882*4887Schin 		{
883*4887Schin 			if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t))
884*4887Schin 			{
885*4887Schin 				Sfdouble_t ld, old=0;
886*4887Schin 				if(flags&NV_INTEGER)
887*4887Schin 				{
888*4887Schin 					if(flags&NV_LONG)
889*4887Schin 						ld = *((Sfdouble_t*)sp);
890*4887Schin 					else if(flags&NV_SHORT)
891*4887Schin 						ld = *((float*)sp);
892*4887Schin 					else
893*4887Schin 						ld = *((double*)sp);
894*4887Schin 				}
895*4887Schin 				else
896*4887Schin 					ld = sh_arith(sp);
897*4887Schin 				if(!up->ldp)
898*4887Schin 					up->ldp = new_of(Sfdouble_t,0);
899*4887Schin 				else if(flags&NV_APPEND)
900*4887Schin 					old = *(up->ldp);
901*4887Schin 				*(up->ldp) = ld+old;
902*4887Schin 			}
903*4887Schin 			else
904*4887Schin 			{
905*4887Schin 				double d,od=0;
906*4887Schin 				if(flags&NV_INTEGER)
907*4887Schin 				{
908*4887Schin 					if(flags&NV_LONG)
909*4887Schin 						d = (double)(*(Sfdouble_t*)sp);
910*4887Schin 					else if(flags&NV_SHORT)
911*4887Schin 						d = (double)(*(float*)sp);
912*4887Schin 					else
913*4887Schin 						d = *(double*)sp;
914*4887Schin 				}
915*4887Schin 				else
916*4887Schin 					d = sh_arith(sp);
917*4887Schin 				if(!up->dp)
918*4887Schin 					up->dp = new_of(double,0);
919*4887Schin 				else if(flags&NV_APPEND)
920*4887Schin 					od = *(up->dp);
921*4887Schin 				*(up->dp) = d+od;
922*4887Schin 			}
923*4887Schin 		}
924*4887Schin 		else
925*4887Schin 		{
926*4887Schin 			if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t))
927*4887Schin 			{
928*4887Schin 				Sflong_t ll=0,oll=0;
929*4887Schin 				if(flags&NV_INTEGER)
930*4887Schin 				{
931*4887Schin 					if(flags&NV_DOUBLE)
932*4887Schin 					{
933*4887Schin 						if(flags&NV_LONG)
934*4887Schin 							ll = *((Sfdouble_t*)sp);
935*4887Schin 						else if(flags&NV_SHORT)
936*4887Schin 							ll = *((float*)sp);
937*4887Schin 						else
938*4887Schin 							ll = *((double*)sp);
939*4887Schin 					}
940*4887Schin 					else if(nv_isattr(np,NV_UNSIGN))
941*4887Schin 					{
942*4887Schin 						if(flags&NV_LONG)
943*4887Schin 							ll = *((Sfulong_t*)sp);
944*4887Schin 						else if(flags&NV_SHORT)
945*4887Schin 							ll = *((uint16_t*)sp);
946*4887Schin 						else
947*4887Schin 							ll = *((uint32_t*)sp);
948*4887Schin 					}
949*4887Schin 					else
950*4887Schin 					{
951*4887Schin 						if(flags&NV_LONG)
952*4887Schin 							ll = *((Sflong_t*)sp);
953*4887Schin 						else if(flags&NV_SHORT)
954*4887Schin 							ll = *((uint16_t*)sp);
955*4887Schin 						else
956*4887Schin 							ll = *((uint32_t*)sp);
957*4887Schin 					}
958*4887Schin 				}
959*4887Schin 				else if(sp)
960*4887Schin 					ll = (Sflong_t)sh_arith(sp);
961*4887Schin 				if(!up->llp)
962*4887Schin 					up->llp = new_of(Sflong_t,0);
963*4887Schin 				else if(flags&NV_APPEND)
964*4887Schin 					oll = *(up->llp);
965*4887Schin 				*(up->llp) = ll+oll;
966*4887Schin 			}
967*4887Schin 			else
968*4887Schin 			{
969*4887Schin 				int32_t l=0,ol=0;
970*4887Schin 				if(flags&NV_INTEGER)
971*4887Schin 				{
972*4887Schin 					if(flags&NV_DOUBLE)
973*4887Schin 					{
974*4887Schin 						Sflong_t ll;
975*4887Schin 						if(flags&NV_LONG)
976*4887Schin 							ll = *((Sfdouble_t*)sp);
977*4887Schin 						else if(flags&NV_SHORT)
978*4887Schin 							ll = *((float*)sp);
979*4887Schin 						else
980*4887Schin 							ll = *((double*)sp);
981*4887Schin 						l = (int32_t)ll;
982*4887Schin 					}
983*4887Schin 					else if(nv_isattr(np,NV_UNSIGN))
984*4887Schin 					{
985*4887Schin 						if(flags&NV_LONG)
986*4887Schin 							l = *((Sfulong_t*)sp);
987*4887Schin 						else if(flags&NV_SHORT)
988*4887Schin 							l = *((uint16_t*)sp);
989*4887Schin 						else
990*4887Schin 							l = *(uint32_t*)sp;
991*4887Schin 					}
992*4887Schin 					else
993*4887Schin 					{
994*4887Schin 						if(flags&NV_LONG)
995*4887Schin 							l = *((Sflong_t*)sp);
996*4887Schin 						else if(flags&NV_SHORT)
997*4887Schin 							l = *((int16_t*)sp);
998*4887Schin 						else
999*4887Schin 							l = *(int32_t*)sp;
1000*4887Schin 					}
1001*4887Schin 				}
1002*4887Schin 				else if(sp)
1003*4887Schin 				{
1004*4887Schin 					Sfdouble_t ld = sh_arith(sp);
1005*4887Schin 					if(ld<0)
1006*4887Schin 						l = (int32_t)ld;
1007*4887Schin 					else
1008*4887Schin 						l = (uint32_t)ld;
1009*4887Schin 				}
1010*4887Schin 				if(nv_size(np) <= 1)
1011*4887Schin 					nv_setsize(np,10);
1012*4887Schin 				if(nv_isattr (np, NV_SHORT))
1013*4887Schin 				{
1014*4887Schin 					int16_t s=0;
1015*4887Schin 					if(flags&NV_APPEND)
1016*4887Schin 						s = up->s;
1017*4887Schin 					up->s = s+(int16_t)l;
1018*4887Schin 					nv_onattr(np,NV_NOFREE);
1019*4887Schin 				}
1020*4887Schin 				else
1021*4887Schin 				{
1022*4887Schin 					if(!up->lp)
1023*4887Schin 						up->lp = new_of(int32_t,0);
1024*4887Schin 					else if(flags&NV_APPEND)
1025*4887Schin 						ol =  *(up->lp);
1026*4887Schin 					*(up->lp) = l+ol;
1027*4887Schin 				}
1028*4887Schin 			}
1029*4887Schin 		}
1030*4887Schin 	}
1031*4887Schin 	else
1032*4887Schin 	{
1033*4887Schin 		const char *tofree=0;
1034*4887Schin 		int offset;
1035*4887Schin #if _lib_pathnative
1036*4887Schin 		char buff[PATH_MAX];
1037*4887Schin #endif /* _lib_pathnative */
1038*4887Schin 		if(flags&NV_INTEGER)
1039*4887Schin 		{
1040*4887Schin 			if(flags&NV_DOUBLE)
1041*4887Schin 			{
1042*4887Schin 				if(flags&NV_LONG)
1043*4887Schin 					sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp));
1044*4887Schin 				else
1045*4887Schin 					sfprintf(sh.strbuf,"%.*g",DBL_DIG,*((double*)sp));
1046*4887Schin 			}
1047*4887Schin 			else if(flags&NV_LONG)
1048*4887Schin 				sfprintf(sh.strbuf,"%lld\0",*((Sflong_t*)sp));
1049*4887Schin 			else
1050*4887Schin 				sfprintf(sh.strbuf,"%ld\0",*((int32_t*)sp));
1051*4887Schin 			sp = sfstruse(sh.strbuf);
1052*4887Schin 		}
1053*4887Schin 		if(nv_isattr(np, NV_HOST)==NV_HOST && sp)
1054*4887Schin 		{
1055*4887Schin #ifdef _lib_pathnative
1056*4887Schin 			/*
1057*4887Schin 			 * return the host file name given the UNIX name
1058*4887Schin 			 */
1059*4887Schin 			pathnative(sp,buff,sizeof(buff));
1060*4887Schin 			if(buff[1]==':' && buff[2]=='/')
1061*4887Schin 			{
1062*4887Schin 				buff[2] = '\\';
1063*4887Schin 				if(*buff>='A' &&  *buff<='Z')
1064*4887Schin 					*buff += 'a'-'A';
1065*4887Schin 			}
1066*4887Schin 			sp = buff;
1067*4887Schin #else
1068*4887Schin 			;
1069*4887Schin #endif /* _lib_pathnative */
1070*4887Schin 		}
1071*4887Schin 		else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
1072*4887Schin 		{
1073*4887Schin 			for(;*sp == ' '|| *sp=='\t';sp++);
1074*4887Schin 	        	if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST)))
1075*4887Schin 				for(;*sp=='0';sp++);
1076*4887Schin 			size = nv_size(np);
1077*4887Schin #if SHOPT_MULTIBYTE
1078*4887Schin 			if(size)
1079*4887Schin 				size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL));
1080*4887Schin #endif /* SHOPT_MULTIBYTE */
1081*4887Schin 		}
1082*4887Schin 		if(!up->cp)
1083*4887Schin 			flags &= ~NV_APPEND;
1084*4887Schin 		if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY))
1085*4887Schin 		{
1086*4887Schin 			offset = staktell();
1087*4887Schin 			stakputs(up->cp);
1088*4887Schin 			stakputs(sp);
1089*4887Schin 			stakputc(0);
1090*4887Schin 			sp = stakptr(offset);
1091*4887Schin 		}
1092*4887Schin 		if(!nv_isattr(np, NV_NOFREE))
1093*4887Schin 		{
1094*4887Schin 			/* delay free in case <sp> points into free region */
1095*4887Schin 			tofree = up->cp;
1096*4887Schin 		}
1097*4887Schin 		nv_offattr(np,NV_NOFREE);
1098*4887Schin        	 	if (sp)
1099*4887Schin 		{
1100*4887Schin 			dot = strlen(sp);
1101*4887Schin #if (_AST_VERSION>=20030127L)
1102*4887Schin 			if(nv_isattr(np,NV_BINARY))
1103*4887Schin 			{
1104*4887Schin 				int oldsize = (flags&NV_APPEND)?nv_size(np):0;
1105*4887Schin 				if(flags&NV_RAW)
1106*4887Schin 				{
1107*4887Schin 					if(tofree)
1108*4887Schin 						free((void*)tofree);
1109*4887Schin 					up->cp = sp;
1110*4887Schin 					return;
1111*4887Schin 				}
1112*4887Schin 				size = 0;
1113*4887Schin 				if(nv_isattr(np,NV_ZFILL))
1114*4887Schin 					size = nv_size(np);
1115*4887Schin 				if(size==0)
1116*4887Schin 					size = oldsize + (3*dot/4);
1117*4887Schin 				cp = (char*)malloc(size+1);
1118*4887Schin 				if(oldsize)
1119*4887Schin 					memcpy((void*)cp,(void*)up->cp,oldsize);
1120*4887Schin 				up->cp = cp;
1121*4887Schin 				if(size <= oldsize)
1122*4887Schin 					return;
1123*4887Schin 				dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0);
1124*4887Schin 				dot += oldsize;
1125*4887Schin 				if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0)
1126*4887Schin 					nv_setsize(np,dot);
1127*4887Schin 				else if(nv_isattr(np,NV_ZFILL) && (size>dot))
1128*4887Schin 					memset((void*)&cp[dot],0,size-dot);
1129*4887Schin 				return;
1130*4887Schin 			}
1131*4887Schin 			else
1132*4887Schin #endif
1133*4887Schin 			if(size==0 && nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
1134*4887Schin 				nv_setsize(np,size=dot);
1135*4887Schin 			else if(size > dot)
1136*4887Schin 				dot = size;
1137*4887Schin 			cp = (char*)malloc(((unsigned)dot+1));
1138*4887Schin 		}
1139*4887Schin 		else
1140*4887Schin 			cp = 0;
1141*4887Schin 		up->cp = cp;
1142*4887Schin 		if(sp)
1143*4887Schin 		{
1144*4887Schin 			if(nv_isattr(np, NV_LTOU))
1145*4887Schin 				ltou(sp,cp);
1146*4887Schin 			else if(nv_isattr (np, NV_UTOL))
1147*4887Schin 				sh_utol(sp,cp);
1148*4887Schin 			else
1149*4887Schin        			 	strcpy(cp, sp);
1150*4887Schin 			if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL))
1151*4887Schin 				rightjust(cp,size,'0');
1152*4887Schin 			else if(nv_isattr(np, NV_RJUST))
1153*4887Schin 				rightjust(cp,size,' ');
1154*4887Schin 			else if(nv_isattr(np, NV_LJUST))
1155*4887Schin 			{
1156*4887Schin 				register char *dp;
1157*4887Schin 				dp = strlen (cp) + cp;
1158*4887Schin 				*(cp = (cp + size)) = 0;
1159*4887Schin 				for (; dp < cp; *dp++ = ' ');
1160*4887Schin 			 }
1161*4887Schin #if SHOPT_MULTIBYTE
1162*4887Schin 			/* restore original string */
1163*4887Schin 			if(savep)
1164*4887Schin 				ja_restore();
1165*4887Schin #endif /* SHOPT_MULTIBYTE */
1166*4887Schin 		}
1167*4887Schin 		if(flags&NV_APPEND)
1168*4887Schin 			stakseek(offset);
1169*4887Schin 		if(tofree)
1170*4887Schin 			free((void*)tofree);
1171*4887Schin 	}
1172*4887Schin 	if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1173*4887Schin 		sh_envput(sh.env,np);
1174*4887Schin 	return;
1175*4887Schin }
1176*4887Schin 
1177*4887Schin /*
1178*4887Schin  *
1179*4887Schin  *   Right-justify <str> so that it contains no more than
1180*4887Schin  *   <size> characters.  If <str> contains fewer than <size>
1181*4887Schin  *   characters, left-pad with <fill>.  Trailing blanks
1182*4887Schin  *   in <str> will be ignored.
1183*4887Schin  *
1184*4887Schin  *   If the leftmost digit in <str> is not a digit, <fill>
1185*4887Schin  *   will default to a blank.
1186*4887Schin  */
1187*4887Schin static void rightjust(char *str, int size, int fill)
1188*4887Schin {
1189*4887Schin 	register int n;
1190*4887Schin 	register char *cp,*sp;
1191*4887Schin 	n = strlen(str);
1192*4887Schin 
1193*4887Schin 	/* ignore trailing blanks */
1194*4887Schin 	for(cp=str+n;n && *--cp == ' ';n--);
1195*4887Schin 	if (n == size)
1196*4887Schin 		return;
1197*4887Schin 	if(n > size)
1198*4887Schin         {
1199*4887Schin         	*(str+n) = 0;
1200*4887Schin         	for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
1201*4887Schin         	return;
1202*4887Schin         }
1203*4887Schin 	else *(sp = str+size) = 0;
1204*4887Schin 	if (n == 0)
1205*4887Schin         {
1206*4887Schin         	while (sp > str)
1207*4887Schin                		*--sp = ' ';
1208*4887Schin         	return;
1209*4887Schin         }
1210*4887Schin 	while(n--)
1211*4887Schin 	{
1212*4887Schin 		sp--;
1213*4887Schin 		*sp = *cp--;
1214*4887Schin 	}
1215*4887Schin 	if(!isdigit(*str))
1216*4887Schin 		fill = ' ';
1217*4887Schin 	while(sp>str)
1218*4887Schin 		*--sp = fill;
1219*4887Schin 	return;
1220*4887Schin }
1221*4887Schin 
1222*4887Schin #if SHOPT_MULTIBYTE
1223*4887Schin     /*
1224*4887Schin      * handle left and right justified fields for multi-byte chars
1225*4887Schin      * given physical size, return a logical size which reflects the
1226*4887Schin      * screen width of multi-byte characters
1227*4887Schin      * Multi-width characters replaced by spaces if they cross the boundary
1228*4887Schin      * <type> is non-zero for right justified  fields
1229*4887Schin      */
1230*4887Schin 
1231*4887Schin     static int ja_size(char *str,int size,int type)
1232*4887Schin     {
1233*4887Schin 	register char *cp = str;
1234*4887Schin 	register int c, n=size;
1235*4887Schin 	register int outsize;
1236*4887Schin 	register char *oldcp=cp;
1237*4887Schin 	int oldn;
1238*4887Schin 	wchar_t w;
1239*4887Schin 	while(*cp)
1240*4887Schin 	{
1241*4887Schin 		oldn = n;
1242*4887Schin 		w = mbchar(cp);
1243*4887Schin 		outsize = mbwidth(w);
1244*4887Schin 		size -= outsize;
1245*4887Schin 		c = cp-oldcp;
1246*4887Schin 		n += (c-outsize);
1247*4887Schin 		oldcp = cp;
1248*4887Schin 		if(size<=0 && type==0)
1249*4887Schin 			break;
1250*4887Schin 	}
1251*4887Schin 	/* check for right justified fields that need truncating */
1252*4887Schin 	if(size <0)
1253*4887Schin 	{
1254*4887Schin 		if(type==0)
1255*4887Schin 		{
1256*4887Schin 			/* left justified and character crosses field boundary */
1257*4887Schin 			n = oldn;
1258*4887Schin 			/* save boundary char and replace with spaces */
1259*4887Schin 			size = c;
1260*4887Schin 			savechars[size] = 0;
1261*4887Schin 			while(size--)
1262*4887Schin 			{
1263*4887Schin 				savechars[size] = cp[size];
1264*4887Schin 				cp[size] = ' ';
1265*4887Schin 			}
1266*4887Schin 			savep = cp;
1267*4887Schin 		}
1268*4887Schin 		size = -size;
1269*4887Schin 		if(type)
1270*4887Schin 			n -= (ja_size(str,size,0)-size);
1271*4887Schin 	}
1272*4887Schin 	return(n);
1273*4887Schin     }
1274*4887Schin 
1275*4887Schin     static void ja_restore(void)
1276*4887Schin     {
1277*4887Schin 	register char *cp = savechars;
1278*4887Schin 	while(*cp)
1279*4887Schin 		*savep++ = *cp++;
1280*4887Schin 	savep = 0;
1281*4887Schin     }
1282*4887Schin #endif /* SHOPT_MULTIBYTE */
1283*4887Schin 
1284*4887Schin #ifndef _ENV_H
1285*4887Schin static char *staknam(register Namval_t *np, char *value)
1286*4887Schin {
1287*4887Schin 	register char *p,*q;
1288*4887Schin 	q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2);
1289*4887Schin 	p=strcopy(q,nv_name(np));
1290*4887Schin 	if(value)
1291*4887Schin 	{
1292*4887Schin 		*p++ = '=';
1293*4887Schin 		strcpy(p,value);
1294*4887Schin 	}
1295*4887Schin 	return(q);
1296*4887Schin }
1297*4887Schin #endif
1298*4887Schin 
1299*4887Schin /*
1300*4887Schin  * put the name and attribute into value of attributes variable
1301*4887Schin  */
1302*4887Schin #ifdef _ENV_H
1303*4887Schin static void attstore(register Namval_t *np, void *data)
1304*4887Schin {
1305*4887Schin 	register int flag, c = ' ';
1306*4887Schin 	NOT_USED(data);
1307*4887Schin 	if(!(nv_isattr(np,NV_EXPORT)))
1308*4887Schin 		return;
1309*4887Schin 	flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
1310*4887Schin 	stakputc('=');
1311*4887Schin 	if((flag&NV_DOUBLE) && (flag&NV_INTEGER))
1312*4887Schin 	{
1313*4887Schin 		/* export doubles as integers for ksh88 compatibility */
1314*4887Schin 		stakputc(c+(flag&~(NV_DOUBLE|NV_EXPNOTE)));
1315*4887Schin 	}
1316*4887Schin 	else
1317*4887Schin 	{
1318*4887Schin 		stakputc(c+flag);
1319*4887Schin 		if(flag&NV_INTEGER)
1320*4887Schin 			c +=  nv_size(np);
1321*4887Schin 	}
1322*4887Schin 	stakputc(c);
1323*4887Schin 	stakputs(nv_name(np));
1324*4887Schin }
1325*4887Schin #else
1326*4887Schin static void attstore(register Namval_t *np, void *data)
1327*4887Schin {
1328*4887Schin 	register int flag = np->nvflag;
1329*4887Schin 	register struct adata *ap = (struct adata*)data;
1330*4887Schin 	if(!(flag&NV_EXPORT) || (flag&NV_FUNCT))
1331*4887Schin 		return;
1332*4887Schin 	flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
1333*4887Schin 	*ap->attval++ = '=';
1334*4887Schin 	if((flag&NV_DOUBLE) && (flag&NV_INTEGER))
1335*4887Schin 	{
1336*4887Schin 		/* export doubles as integers for ksh88 compatibility */
1337*4887Schin 		*ap->attval++ = ' '+(flag&~(NV_DOUBLE|NV_EXPNOTE));
1338*4887Schin 		*ap->attval = ' ';
1339*4887Schin 	}
1340*4887Schin 	else
1341*4887Schin 	{
1342*4887Schin 		*ap->attval++ = ' '+flag;
1343*4887Schin 		if(flag&NV_INTEGER)
1344*4887Schin 			*ap->attval = ' ' + nv_size(np);
1345*4887Schin 		else
1346*4887Schin 			*ap->attval = ' ';
1347*4887Schin 	}
1348*4887Schin 	ap->attval = strcopy(++ap->attval,nv_name(np));
1349*4887Schin }
1350*4887Schin #endif
1351*4887Schin 
1352*4887Schin #ifndef _ENV_H
1353*4887Schin static void pushnam(Namval_t *np, void *data)
1354*4887Schin {
1355*4887Schin 	register char *value;
1356*4887Schin 	register struct adata *ap = (struct adata*)data;
1357*4887Schin 	if(nv_isattr(np,NV_IMPORT))
1358*4887Schin 	{
1359*4887Schin 		if(np->nvenv)
1360*4887Schin 			*ap->argnam++ = np->nvenv;
1361*4887Schin 	}
1362*4887Schin 	else if(value=nv_getval(np))
1363*4887Schin 		*ap->argnam++ = staknam(np,value);
1364*4887Schin 	if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER))
1365*4887Schin 		ap->attsize += (strlen(nv_name(np))+4);
1366*4887Schin }
1367*4887Schin #endif
1368*4887Schin 
1369*4887Schin /*
1370*4887Schin  * Generate the environment list for the child.
1371*4887Schin  */
1372*4887Schin 
1373*4887Schin #ifdef _ENV_H
1374*4887Schin char **sh_envgen(void)
1375*4887Schin {
1376*4887Schin 	int offset,tell;
1377*4887Schin 	register char **er;
1378*4887Schin 	env_delete(sh.env,"_");
1379*4887Schin 	er = env_get(sh.env);
1380*4887Schin 	offset = staktell();
1381*4887Schin 	stakputs(e_envmarker);
1382*4887Schin 	tell = staktell();
1383*4887Schin 	nv_scan(sh.var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
1384*4887Schin 	if(tell ==staktell())
1385*4887Schin 		stakseek(offset);
1386*4887Schin 	else
1387*4887Schin 		*--er = stakfreeze(1)+offset;
1388*4887Schin 	return(er);
1389*4887Schin }
1390*4887Schin #else
1391*4887Schin char **sh_envgen(void)
1392*4887Schin {
1393*4887Schin 	register char **er;
1394*4887Schin 	register int namec;
1395*4887Schin 	register char *cp;
1396*4887Schin 	struct adata data;
1397*4887Schin 	/* L_ARGNOD gets generated automatically as full path name of command */
1398*4887Schin 	nv_offattr(L_ARGNOD,NV_EXPORT);
1399*4887Schin 	data.attsize = 6;
1400*4887Schin 	namec = nv_scan(sh.var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT);
1401*4887Schin 	er = (char**)stakalloc((namec+4)*sizeof(char*));
1402*4887Schin 	data.argnam = (er+=2);
1403*4887Schin 	nv_scan(sh.var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT);
1404*4887Schin 	*data.argnam = (char*)stakalloc(data.attsize);
1405*4887Schin 	cp = data.attval = strcopy(*data.argnam,e_envmarker);
1406*4887Schin 	nv_scan(sh.var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
1407*4887Schin 	*data.attval = 0;
1408*4887Schin 	if(cp!=data.attval)
1409*4887Schin 		data.argnam++;
1410*4887Schin 	*data.argnam = 0;
1411*4887Schin 	return(er);
1412*4887Schin }
1413*4887Schin #endif
1414*4887Schin 
1415*4887Schin struct scan
1416*4887Schin {
1417*4887Schin 	void    (*scanfn)(Namval_t*, void*);
1418*4887Schin 	int     scanmask;
1419*4887Schin 	int     scanflags;
1420*4887Schin 	int     scancount;
1421*4887Schin 	void    *scandata;
1422*4887Schin };
1423*4887Schin 
1424*4887Schin 
1425*4887Schin static int scanfilter(Dt_t *dict, void *arg, void *data)
1426*4887Schin {
1427*4887Schin 	register Namval_t *np = (Namval_t*)arg;
1428*4887Schin 	register int k=np->nvflag;
1429*4887Schin 	register struct scan *sp = (struct scan*)data;
1430*4887Schin 	NOT_USED(dict);
1431*4887Schin 	if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags)))
1432*4887Schin 	{
1433*4887Schin 		if(!np->nvalue.cp && !nv_isattr(np,~NV_DEFAULT))
1434*4887Schin 			return(0);
1435*4887Schin 		if(sp->scanfn)
1436*4887Schin 		{
1437*4887Schin 			if(nv_isarray(np))
1438*4887Schin 				nv_putsub(np,NIL(char*),0L);
1439*4887Schin 			(*sp->scanfn)(np,sp->scandata);
1440*4887Schin 		}
1441*4887Schin 		sp->scancount++;
1442*4887Schin 	}
1443*4887Schin 	return(0);
1444*4887Schin }
1445*4887Schin 
1446*4887Schin /*
1447*4887Schin  * Walk through the name-value pairs
1448*4887Schin  * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
1449*4887Schin  *	are visited
1450*4887Schin  * If <mask> is zero, and <flags> non-zero, then nodes with one or
1451*4887Schin  *	more of <flags> is visited
1452*4887Schin  * If <mask> and <flags> are zero, then all nodes are visted
1453*4887Schin  */
1454*4887Schin int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags)
1455*4887Schin {
1456*4887Schin 	Dt_t *base=0;
1457*4887Schin 	struct scan sdata;
1458*4887Schin 	int (*hashfn)(Dt_t*, void*, void*);
1459*4887Schin 	sdata.scanmask = mask;
1460*4887Schin 	sdata.scanflags = flags&~NV_NOSCOPE;
1461*4887Schin 	sdata.scanfn = fn;
1462*4887Schin 	sdata.scancount = 0;
1463*4887Schin 	sdata.scandata = data;
1464*4887Schin 	hashfn = scanfilter;
1465*4887Schin 	if(flags&NV_NOSCOPE)
1466*4887Schin 		base = dtview((Dt_t*)root,0);
1467*4887Schin 	dtwalk(root, hashfn,&sdata);
1468*4887Schin 	if(base)
1469*4887Schin 		 dtview((Dt_t*)root,base);
1470*4887Schin 	return(sdata.scancount);
1471*4887Schin }
1472*4887Schin 
1473*4887Schin /*
1474*4887Schin  * create a new environment scope
1475*4887Schin  */
1476*4887Schin void nv_scope(struct argnod *envlist)
1477*4887Schin {
1478*4887Schin 	register Dt_t *newscope;
1479*4887Schin 	newscope = dtopen(&_Nvdisc,Dtoset);
1480*4887Schin 	dtview(newscope,(Dt_t*)sh.var_tree);
1481*4887Schin 	sh.var_tree = (Dt_t*)newscope;
1482*4887Schin 	if(envlist)
1483*4887Schin 		nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN);
1484*4887Schin }
1485*4887Schin 
1486*4887Schin /*
1487*4887Schin  * Remove freeable local space associated with the nvalue field
1488*4887Schin  * of nnod. This includes any strings representing the value(s) of the
1489*4887Schin  * node, as well as its dope vector, if it is an array.
1490*4887Schin  */
1491*4887Schin 
1492*4887Schin void	sh_envnolocal (register Namval_t *np, void *data)
1493*4887Schin {
1494*4887Schin 	char *cp=0;
1495*4887Schin 	NOT_USED(data);
1496*4887Schin 	if(nv_isattr(np,NV_EXPORT) && nv_isarray(np))
1497*4887Schin 	{
1498*4887Schin 		nv_putsub(np,NIL(char*),0);
1499*4887Schin 		if(cp = nv_getval(np))
1500*4887Schin 			cp = strdup(cp);
1501*4887Schin 	}
1502*4887Schin 	if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
1503*4887Schin 	{
1504*4887Schin 		if(nv_isref(np))
1505*4887Schin 		{
1506*4887Schin 			nv_offattr(np,NV_NOFREE|NV_REF);
1507*4887Schin 			free((void*)np->nvalue.nrp);
1508*4887Schin 			np->nvalue.cp = 0;
1509*4887Schin 		}
1510*4887Schin 		if(!cp)
1511*4887Schin 			return;
1512*4887Schin 	}
1513*4887Schin 	if(nv_isarray(np))
1514*4887Schin 		nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1515*4887Schin 	_nv_unset(np,NV_RDONLY);
1516*4887Schin 	nv_setattr(np,0);
1517*4887Schin 	if(cp)
1518*4887Schin 	{
1519*4887Schin 		nv_putval(np,cp,0);
1520*4887Schin 		free((void*)cp);
1521*4887Schin 	}
1522*4887Schin }
1523*4887Schin 
1524*4887Schin /*
1525*4887Schin  * Currently this is a dummy, but someday will be needed
1526*4887Schin  * for reference counting
1527*4887Schin  */
1528*4887Schin void	nv_close(Namval_t *np)
1529*4887Schin {
1530*4887Schin 	NOT_USED(np);
1531*4887Schin }
1532*4887Schin 
1533*4887Schin static void table_unset(register Dt_t *root, int flags, Dt_t *oroot)
1534*4887Schin {
1535*4887Schin 	register Namval_t *np,*nq;
1536*4887Schin 	for(np=(Namval_t*)dtfirst(root);np;np=nq)
1537*4887Schin 	{
1538*4887Schin 		_nv_unset(np,flags);
1539*4887Schin 		if(oroot && (nq=nv_search(nv_name(np),oroot,0)) && nv_isattr(nq,NV_EXPORT))
1540*4887Schin 			sh_envput(sh.env,nq);
1541*4887Schin 		nq = (Namval_t*)dtnext(root,np);
1542*4887Schin 		dtdelete(root,np);
1543*4887Schin 		free((void*)np);
1544*4887Schin 	}
1545*4887Schin }
1546*4887Schin 
1547*4887Schin /*
1548*4887Schin  *
1549*4887Schin  *   Set the value of <np> to 0, and nullify any attributes
1550*4887Schin  *   that <np> may have had.  Free any freeable space occupied
1551*4887Schin  *   by the value of <np>.  If <np> denotes an array member, it
1552*4887Schin  *   will retain its attributes.
1553*4887Schin  *   <flags> can contain NV_RDONLY to override the readonly attribute
1554*4887Schin  *	being cleared.
1555*4887Schin  */
1556*4887Schin void	_nv_unset(register Namval_t *np,int flags)
1557*4887Schin {
1558*4887Schin 	register union Value *up;
1559*4887Schin 	if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY))
1560*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
1561*4887Schin 	if(is_afunction(np) && np->nvalue.ip)
1562*4887Schin 	{
1563*4887Schin 		register struct slnod *slp = (struct slnod*)(np->nvenv);
1564*4887Schin 		if(slp && !nv_isattr(np,NV_NOFREE))
1565*4887Schin 		{
1566*4887Schin 			/* free function definition */
1567*4887Schin 			register char *name=nv_name(np),*cp= strrchr(name,'.');
1568*4887Schin 			if(cp)
1569*4887Schin 			{
1570*4887Schin 				Namval_t *npv;
1571*4887Schin 				*cp = 0;
1572*4887Schin 				 npv = nv_open(name,sh.var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD);
1573*4887Schin 				*cp++ = '.';
1574*4887Schin 				if(npv)
1575*4887Schin 					nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv);
1576*4887Schin 			}
1577*4887Schin 			stakdelete(slp->slptr);
1578*4887Schin 			free((void*)np->nvalue.ip);
1579*4887Schin 			np->nvalue.ip = 0;
1580*4887Schin 		}
1581*4887Schin 		goto done;
1582*4887Schin 	}
1583*4887Schin 	if(sh.subshell && !nv_isnull(np))
1584*4887Schin 		np = sh_assignok(np,0);
1585*4887Schin 	nv_offattr(np,NV_NODISC);
1586*4887Schin 	if(np->nvfun && !nv_isref(np))
1587*4887Schin 	{
1588*4887Schin 		/* This function contains disc */
1589*4887Schin 		if(!nv_local)
1590*4887Schin 		{
1591*4887Schin 			nv_local=1;
1592*4887Schin 			nv_putv(np,NIL(char*),flags,np->nvfun);
1593*4887Schin 			return;
1594*4887Schin 		}
1595*4887Schin 		/* called from disc, assign the actual value */
1596*4887Schin 		nv_local=0;
1597*4887Schin 	}
1598*4887Schin 	up = &np->nvalue;
1599*4887Schin 	if(up->cp)
1600*4887Schin 	{
1601*4887Schin 		if(!nv_isattr (np, NV_NOFREE))
1602*4887Schin 			free((void*)up->cp);
1603*4887Schin 		up->cp = 0;
1604*4887Schin 	}
1605*4887Schin done:
1606*4887Schin 	if(!nv_isarray(np) || !nv_arrayptr(np))
1607*4887Schin 	{
1608*4887Schin 		if(nv_isref(np))
1609*4887Schin 			free((void*)np->nvalue.nrp);
1610*4887Schin 		nv_setsize(np,0);
1611*4887Schin 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
1612*4887Schin 		{
1613*4887Schin 			if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'['))
1614*4887Schin 				env_delete(sh.env,nv_name(np));
1615*4887Schin 			np->nvenv = 0;
1616*4887Schin 			nv_setattr(np,0);
1617*4887Schin 		}
1618*4887Schin 		else
1619*4887Schin 			nv_setattr(np,NV_MINIMAL);
1620*4887Schin 	}
1621*4887Schin }
1622*4887Schin 
1623*4887Schin void	nv_unset(register Namval_t *np)
1624*4887Schin {
1625*4887Schin 	_nv_unset(np,0);
1626*4887Schin }
1627*4887Schin 
1628*4887Schin /*
1629*4887Schin  * return the node pointer in the highest level scope
1630*4887Schin  */
1631*4887Schin Namval_t *nv_scoped(register Namval_t *np)
1632*4887Schin {
1633*4887Schin 	if(!dtvnext(sh.var_tree))
1634*4887Schin 		return(np);
1635*4887Schin 	return(dtsearch(sh.var_tree,np));
1636*4887Schin }
1637*4887Schin 
1638*4887Schin #if 1
1639*4887Schin /*
1640*4887Schin  * return space separated list of names of variables in given tree
1641*4887Schin  */
1642*4887Schin static char *tableval(Dt_t *root)
1643*4887Schin {
1644*4887Schin 	static Sfio_t *out;
1645*4887Schin 	register Namval_t *np;
1646*4887Schin 	register int first=1;
1647*4887Schin 	register Dt_t *base = dtview(root,0);
1648*4887Schin         if(out)
1649*4887Schin                 sfseek(out,(Sfoff_t)0,SEEK_SET);
1650*4887Schin         else
1651*4887Schin                 out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
1652*4887Schin 	for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
1653*4887Schin 	{
1654*4887Schin                 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
1655*4887Schin 		{
1656*4887Schin 			if(!first)
1657*4887Schin 				sfputc(out,' ');
1658*4887Schin 			else
1659*4887Schin 				first = 0;
1660*4887Schin 			sfputr(out,np->nvname,-1);
1661*4887Schin 		}
1662*4887Schin 	}
1663*4887Schin 	sfputc(out,0);
1664*4887Schin 	if(base)
1665*4887Schin 		dtview(root,base);
1666*4887Schin 	return((char*)out->_data);
1667*4887Schin }
1668*4887Schin #endif
1669*4887Schin 
1670*4887Schin #if SHOPT_OPTIMIZE
1671*4887Schin struct optimize
1672*4887Schin {
1673*4887Schin 	Namfun_t	hdr;
1674*4887Schin 	char		**ptr;
1675*4887Schin 	struct optimize	*next;
1676*4887Schin 	Namval_t	*np;
1677*4887Schin };
1678*4887Schin 
1679*4887Schin static struct optimize *opt_free;
1680*4887Schin 
1681*4887Schin static void optimize_clear(Namval_t* np, Namfun_t *fp)
1682*4887Schin {
1683*4887Schin 	struct optimize *op = (struct optimize*)fp;
1684*4887Schin 	nv_stack(np,fp);
1685*4887Schin 	nv_stack(np,(Namfun_t*)0);
1686*4887Schin 	for(;op && op->np==np; op=op->next)
1687*4887Schin 	{
1688*4887Schin 		if(op->ptr)
1689*4887Schin 		{
1690*4887Schin 			*op->ptr = 0;
1691*4887Schin 			op->ptr = 0;
1692*4887Schin 		}
1693*4887Schin 	}
1694*4887Schin }
1695*4887Schin 
1696*4887Schin static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp)
1697*4887Schin {
1698*4887Schin 	nv_putv(np,val,flags,fp);
1699*4887Schin 	optimize_clear(np,fp);
1700*4887Schin }
1701*4887Schin 
1702*4887Schin static const Namdisc_t optimize_disc  = {sizeof(struct optimize),put_optimize};
1703*4887Schin 
1704*4887Schin void nv_optimize(Namval_t *np)
1705*4887Schin {
1706*4887Schin 	register Namfun_t *fp;
1707*4887Schin 	register struct optimize *op, *xp;
1708*4887Schin 	if(sh.argaddr)
1709*4887Schin 	{
1710*4887Schin 		for(fp=np->nvfun; fp; fp = fp->next)
1711*4887Schin 		{
1712*4887Schin 			if(fp->disc->getnum || fp->disc->getval)
1713*4887Schin 			{
1714*4887Schin 				sh.argaddr = 0;
1715*4887Schin 				return;
1716*4887Schin 			}
1717*4887Schin 			if(fp->disc== &optimize_disc)
1718*4887Schin 				break;
1719*4887Schin 		}
1720*4887Schin 		if((xp= (struct optimize*)fp) && xp->ptr==sh.argaddr)
1721*4887Schin 			return;
1722*4887Schin 		if(op = opt_free)
1723*4887Schin 			opt_free = op->next;
1724*4887Schin 		else
1725*4887Schin 			op=(struct optimize*)calloc(1,sizeof(struct optimize));
1726*4887Schin 		op->ptr = sh.argaddr;
1727*4887Schin 		op->np = np;
1728*4887Schin 		if(xp)
1729*4887Schin 		{
1730*4887Schin 			op->hdr.disc = 0;
1731*4887Schin 			op->next = xp->next;
1732*4887Schin 			xp->next = op;
1733*4887Schin 		}
1734*4887Schin 		else
1735*4887Schin 		{
1736*4887Schin 			op->hdr.disc = &optimize_disc;
1737*4887Schin 			op->next = (struct optimize*)sh.optlist;
1738*4887Schin 			sh.optlist = (void*)op;
1739*4887Schin 			nv_stack(np,&op->hdr);
1740*4887Schin 		}
1741*4887Schin 	}
1742*4887Schin }
1743*4887Schin 
1744*4887Schin void sh_optclear(Shell_t *shp, void *old)
1745*4887Schin {
1746*4887Schin 	register struct optimize *op,*opnext;
1747*4887Schin 	for(op=(struct optimize*)shp->optlist; op; op = opnext)
1748*4887Schin 	{
1749*4887Schin 		opnext = op->next;
1750*4887Schin 		if(op->ptr && op->hdr.disc)
1751*4887Schin 		{
1752*4887Schin 			nv_stack(op->np,&op->hdr);
1753*4887Schin 			nv_stack(op->np,(Namfun_t*)0);
1754*4887Schin 		}
1755*4887Schin 		op->next = opt_free;
1756*4887Schin 		opt_free = op;
1757*4887Schin 	}
1758*4887Schin 	shp->optlist = old;
1759*4887Schin }
1760*4887Schin 
1761*4887Schin #else
1762*4887Schin #   define	optimize_clear(np,fp)
1763*4887Schin #endif /* SHOPT_OPTIMIZE */
1764*4887Schin 
1765*4887Schin /*
1766*4887Schin  *   Return a pointer to a character string that denotes the value
1767*4887Schin  *   of <np>.  If <np> refers to an array,  return a pointer to
1768*4887Schin  *   the value associated with the current index.
1769*4887Schin  *
1770*4887Schin  *   If the value of <np> is an integer, the string returned will
1771*4887Schin  *   be overwritten by the next call to nv_getval.
1772*4887Schin  *
1773*4887Schin  *   If <np> has no value, 0 is returned.
1774*4887Schin  */
1775*4887Schin 
1776*4887Schin char *nv_getval(register Namval_t *np)
1777*4887Schin {
1778*4887Schin 	register union Value *up= &np->nvalue;
1779*4887Schin 	register int numeric;
1780*4887Schin #if SHOPT_OPTIMIZE
1781*4887Schin 	if(!nv_local && sh.argaddr)
1782*4887Schin 		nv_optimize(np);
1783*4887Schin #endif /* SHOPT_OPTIMIZE */
1784*4887Schin 	if(!np->nvfun && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF|NV_TABLE))
1785*4887Schin 		goto done;
1786*4887Schin 	if(nv_isref(np))
1787*4887Schin 	{
1788*4887Schin 		sh.last_table = nv_reftable(np);
1789*4887Schin 		return(nv_name(nv_refnode(np)));
1790*4887Schin 	}
1791*4887Schin 	if(np->nvfun)
1792*4887Schin 	{
1793*4887Schin 		if(!nv_local)
1794*4887Schin 		{
1795*4887Schin 			nv_local=1;
1796*4887Schin 			return(nv_getv(np, np->nvfun));
1797*4887Schin 		}
1798*4887Schin 		nv_local=0;
1799*4887Schin 	}
1800*4887Schin 	numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
1801*4887Schin 	if(numeric)
1802*4887Schin 	{
1803*4887Schin 		Sflong_t  ll;
1804*4887Schin 		if(!up->cp)
1805*4887Schin 			return("0");
1806*4887Schin 		if(nv_isattr (np,NV_DOUBLE))
1807*4887Schin 		{
1808*4887Schin 			Sfdouble_t ld;
1809*4887Schin 			double d;
1810*4887Schin 			char *format;
1811*4887Schin 			if(nv_isattr(np,NV_LONG))
1812*4887Schin 			{
1813*4887Schin 				ld = *up->ldp;
1814*4887Schin 				if(nv_isattr (np,NV_EXPNOTE))
1815*4887Schin 					format = "%.*Lg";
1816*4887Schin 				else
1817*4887Schin 					format = "%.*Lf";
1818*4887Schin 				sfprintf(sh.strbuf,format,nv_size(np),ld);
1819*4887Schin 			}
1820*4887Schin 			else
1821*4887Schin 			{
1822*4887Schin 				d = *up->dp;
1823*4887Schin 				if(nv_isattr (np,NV_EXPNOTE))
1824*4887Schin 					format = "%.*g";
1825*4887Schin 				else
1826*4887Schin 					format = "%.*f";
1827*4887Schin 				sfprintf(sh.strbuf,format,nv_size(np),d);
1828*4887Schin 			}
1829*4887Schin 			return(sfstruse(sh.strbuf));
1830*4887Schin 		}
1831*4887Schin 		else if(nv_isattr(np,NV_UNSIGN))
1832*4887Schin 		{
1833*4887Schin 	        	if(nv_isattr (np,NV_LONG))
1834*4887Schin 				ll = *(Sfulong_t*)up->llp;
1835*4887Schin 			else if(nv_isattr (np,NV_SHORT))
1836*4887Schin 				ll = (uint16_t)up->s;
1837*4887Schin 			else
1838*4887Schin 				ll = *(uint32_t*)(up->lp);
1839*4887Schin 		}
1840*4887Schin         	else if(nv_isattr (np,NV_LONG))
1841*4887Schin 			ll = *up->llp;
1842*4887Schin         	else if(nv_isattr (np,NV_SHORT))
1843*4887Schin 			ll = up->s;
1844*4887Schin         	else
1845*4887Schin 			ll = *(up->lp);
1846*4887Schin 		if((numeric=nv_size(np))==10)
1847*4887Schin 		{
1848*4887Schin 			if(nv_isattr(np,NV_UNSIGN))
1849*4887Schin 			{
1850*4887Schin 				sfprintf(sh.strbuf,"%I*u",sizeof(ll),ll);
1851*4887Schin 				return(sfstruse(sh.strbuf));
1852*4887Schin 			}
1853*4887Schin 			numeric = 0;
1854*4887Schin 		}
1855*4887Schin 		return(fmtbasell(ll,numeric, numeric&&numeric!=10));
1856*4887Schin 	}
1857*4887Schin done:
1858*4887Schin #if (_AST_VERSION>=20030127L)
1859*4887Schin 	/*
1860*4887Schin 	 * if NV_RAW flag is on, return pointer to binary data
1861*4887Schin 	 * otherwise, base64 encode the data and return this string
1862*4887Schin 	 */
1863*4887Schin 	if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
1864*4887Schin 	{
1865*4887Schin 		char *cp;
1866*4887Schin 		int size= nv_size(np), insize=(4*size)/3+size/45+8;
1867*4887Schin 		base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)0);
1868*4887Schin 		return(cp);
1869*4887Schin 	}
1870*4887Schin #endif
1871*4887Schin 	if((numeric=nv_size(np)) && up->cp && up->cp[numeric])
1872*4887Schin 	{
1873*4887Schin 		char *cp = getbuf(numeric+1);
1874*4887Schin 		memcpy(cp,up->cp,numeric);
1875*4887Schin 		cp[numeric]=0;
1876*4887Schin 		return(cp);
1877*4887Schin 	}
1878*4887Schin 	return ((char*)up->cp);
1879*4887Schin }
1880*4887Schin 
1881*4887Schin Sfdouble_t nv_getnum(register Namval_t *np)
1882*4887Schin {
1883*4887Schin 	register union Value *up;
1884*4887Schin 	register Sfdouble_t r=0;
1885*4887Schin 	register char *str;
1886*4887Schin #if SHOPT_OPTIMIZE
1887*4887Schin 	if(!nv_local && sh.argaddr)
1888*4887Schin 		nv_optimize(np);
1889*4887Schin #endif /* SHOPT_OPTIMIZE */
1890*4887Schin 	if(nv_istable(np))
1891*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np));
1892*4887Schin      	if(np->nvfun)
1893*4887Schin 	{
1894*4887Schin 		if(!nv_local)
1895*4887Schin 		{
1896*4887Schin 			nv_local=1;
1897*4887Schin 			return(nv_getn(np, np->nvfun));
1898*4887Schin 		}
1899*4887Schin 		nv_local=0;
1900*4887Schin 	}
1901*4887Schin      	if(nv_isattr (np, NV_INTEGER))
1902*4887Schin 	{
1903*4887Schin 		up= &np->nvalue;
1904*4887Schin 		if(!up->lp)
1905*4887Schin 			r = 0;
1906*4887Schin 		else if(nv_isattr(np, NV_DOUBLE))
1907*4887Schin 		{
1908*4887Schin 			if(nv_isattr(np, NV_LONG))
1909*4887Schin 	                       	r = *up->ldp;
1910*4887Schin 			else
1911*4887Schin        	                	r = *up->dp;
1912*4887Schin 		}
1913*4887Schin 		else if(nv_isattr(np, NV_UNSIGN))
1914*4887Schin 		{
1915*4887Schin 			if(nv_isattr(np, NV_LONG))
1916*4887Schin 				r = (Sflong_t)*((Sfulong_t*)up->llp);
1917*4887Schin 			else if(nv_isattr(np, NV_SHORT))
1918*4887Schin 				r = (Sflong_t)((uint16_t)up->s);
1919*4887Schin 			else
1920*4887Schin 				r = *((uint32_t*)up->lp);
1921*4887Schin 		}
1922*4887Schin 		else
1923*4887Schin 		{
1924*4887Schin 			if(nv_isattr(np, NV_LONG))
1925*4887Schin 				r = *up->llp;
1926*4887Schin 			else if(nv_isattr(np, NV_SHORT))
1927*4887Schin 				r = up->s;
1928*4887Schin 			else
1929*4887Schin 				r = *up->lp;
1930*4887Schin 		}
1931*4887Schin 	}
1932*4887Schin 	else if((str=nv_getval(np)) && *str!=0)
1933*4887Schin 	{
1934*4887Schin 		if(np->nvfun ||  nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
1935*4887Schin 		{
1936*4887Schin 			while(*str=='0')
1937*4887Schin 				str++;
1938*4887Schin 		}
1939*4887Schin 		r = sh_arith(str);
1940*4887Schin 	}
1941*4887Schin 	return(r);
1942*4887Schin }
1943*4887Schin /*
1944*4887Schin  *   Give <np> the attributes <newatts,> and change its current
1945*4887Schin  *   value to conform to <newatts>.  The <size> of left and right
1946*4887Schin  *   justified fields may be given.
1947*4887Schin  */
1948*4887Schin void nv_newattr (register Namval_t *np, unsigned newatts, int size)
1949*4887Schin {
1950*4887Schin 	register char *sp;
1951*4887Schin 	register char *cp = 0;
1952*4887Schin 	register unsigned int n;
1953*4887Schin 	Namarr_t *ap = 0;
1954*4887Schin 	int oldsize,oldatts;
1955*4887Schin 
1956*4887Schin 	/* check for restrictions */
1957*4887Schin 	if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD)))
1958*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
1959*4887Schin 	/* handle attributes that do not change data separately */
1960*4887Schin 	n = np->nvflag;
1961*4887Schin #if SHOPT_BSH
1962*4887Schin 	if(newatts&NV_EXPORT)
1963*4887Schin 		nv_offattr(np,NV_IMPORT);
1964*4887Schin #endif /* SHOPT_BSH */
1965*4887Schin 	if(((n^newatts)&NV_EXPORT))
1966*4887Schin 	{
1967*4887Schin 		/* record changes to the environment */
1968*4887Schin 		if(n&NV_EXPORT)
1969*4887Schin 			env_delete(sh.env,nv_name(np));
1970*4887Schin 		else
1971*4887Schin 			sh_envput(sh.env,np);
1972*4887Schin 	}
1973*4887Schin 	if((size==0||(n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0)
1974*4887Schin 	{
1975*4887Schin 		if(size)
1976*4887Schin 			nv_setsize(np,size);
1977*4887Schin 		nv_offattr(np, ~NV_NOFREE);
1978*4887Schin 		nv_onattr(np, newatts);
1979*4887Schin 		return;
1980*4887Schin 	}
1981*4887Schin 	/* for an array, change all the elements */
1982*4887Schin 	if((ap=nv_arrayptr(np)) && ap->nelem>0)
1983*4887Schin 		nv_putsub(np,NIL(char*),ARRAY_SCAN);
1984*4887Schin 	oldsize = nv_size(np);
1985*4887Schin 	oldatts = np->nvflag;
1986*4887Schin 	if(ap) /* add element to prevent array deletion */
1987*4887Schin 		ap->nelem++;
1988*4887Schin 	do
1989*4887Schin 	{
1990*4887Schin 		nv_setsize(np,oldsize);
1991*4887Schin 		np->nvflag = oldatts;
1992*4887Schin 		if (sp = nv_getval(np))
1993*4887Schin  		{
1994*4887Schin 			if(nv_isattr(np,NV_ZFILL))
1995*4887Schin 				while(*sp=='0') sp++;
1996*4887Schin 			cp = (char*)malloc((n=strlen (sp)) + 1);
1997*4887Schin 			strcpy(cp, sp);
1998*4887Schin 			if(ap)
1999*4887Schin 			{
2000*4887Schin 				Namval_t *mp;
2001*4887Schin 				ap->nelem &= ~ARRAY_SCAN;
2002*4887Schin 				if(mp=nv_opensub(np))
2003*4887Schin 					nv_onattr(mp,NV_NOFREE);
2004*4887Schin 			}
2005*4887Schin 			nv_unset(np);
2006*4887Schin 			if(ap)
2007*4887Schin 				ap->nelem |= ARRAY_SCAN;
2008*4887Schin 			if(size==0 && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL)))
2009*4887Schin 				size = n;
2010*4887Schin 		}
2011*4887Schin 		else
2012*4887Schin 			nv_unset(np);
2013*4887Schin 		nv_setsize(np,size);
2014*4887Schin 		np->nvflag &= NV_ARRAY;
2015*4887Schin 		np->nvflag |= newatts;
2016*4887Schin 		if (cp)
2017*4887Schin 		{
2018*4887Schin 			nv_putval (np, cp, NV_RDONLY);
2019*4887Schin 			free(cp);
2020*4887Schin 		}
2021*4887Schin 	}
2022*4887Schin 	while(ap && nv_nextsub(np));
2023*4887Schin 	if(ap)
2024*4887Schin 		ap->nelem--;
2025*4887Schin 	return;
2026*4887Schin }
2027*4887Schin 
2028*4887Schin #ifndef _NEXT_SOURCE
2029*4887Schin static char *oldgetenv(const char *string)
2030*4887Schin {
2031*4887Schin 	register char c0,c1;
2032*4887Schin 	register const char *cp, *sp;
2033*4887Schin 	register char **av = environ;
2034*4887Schin 	if(!string || (c0= *string)==0)
2035*4887Schin 		return(0);
2036*4887Schin 	if((c1=*++string)==0)
2037*4887Schin 		c1= '=';
2038*4887Schin 	while(cp = *av++)
2039*4887Schin 	{
2040*4887Schin 		if(cp[0]!=c0 || cp[1]!=c1)
2041*4887Schin 			continue;
2042*4887Schin 		sp = string;
2043*4887Schin 		while(*sp && *sp++ == *++cp);
2044*4887Schin 		if(*sp==0 && *++cp=='=')
2045*4887Schin 			return((char*)(cp+1));
2046*4887Schin 	}
2047*4887Schin 	return(0);
2048*4887Schin }
2049*4887Schin 
2050*4887Schin /*
2051*4887Schin  * This version of getenv uses the hash storage to access environment values
2052*4887Schin  */
2053*4887Schin char *getenv(const char *name)
2054*4887Schin /*@
2055*4887Schin 	assume name!=0;
2056*4887Schin @*/
2057*4887Schin {
2058*4887Schin 	register Namval_t *np;
2059*4887Schin 	if(!sh.var_tree)
2060*4887Schin 		return(oldgetenv(name));
2061*4887Schin 	if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT))
2062*4887Schin 		return(nv_getval(np));
2063*4887Schin 	if(name[0] == 'P' && name[1] == 'A' && name[2] == 'T' && name[3] == 'H' && name[4] == 0)
2064*4887Schin 		return(oldgetenv(name));
2065*4887Schin 	return(0);
2066*4887Schin }
2067*4887Schin #endif /* _NEXT_SOURCE */
2068*4887Schin 
2069*4887Schin #undef putenv
2070*4887Schin /*
2071*4887Schin  * This version of putenv uses the hash storage to assign environment values
2072*4887Schin  */
2073*4887Schin int putenv(const char *name)
2074*4887Schin {
2075*4887Schin 	register Namval_t *np;
2076*4887Schin 	if(name)
2077*4887Schin 	{
2078*4887Schin 		np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2079*4887Schin 		if(!strchr(name,'='))
2080*4887Schin 			nv_unset(np);
2081*4887Schin 	}
2082*4887Schin 	return(0);
2083*4887Schin }
2084*4887Schin 
2085*4887Schin 
2086*4887Schin /*
2087*4887Schin  * Override libast setenv()
2088*4887Schin  */
2089*4887Schin char* setenviron(const char *name)
2090*4887Schin {
2091*4887Schin 	register Namval_t *np;
2092*4887Schin 	if(name)
2093*4887Schin 	{
2094*4887Schin 		np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2095*4887Schin 		if(strchr(name,'='))
2096*4887Schin 			return(nv_getval(np));
2097*4887Schin 		nv_unset(np);
2098*4887Schin 	}
2099*4887Schin 	return("");
2100*4887Schin }
2101*4887Schin 
2102*4887Schin /*
2103*4887Schin  * copy <str1> to <str2> changing lower case to upper case
2104*4887Schin  * <str2> must be big enough to hold <str1>
2105*4887Schin  * <str1> and <str2> may point to the same place.
2106*4887Schin  */
2107*4887Schin 
2108*4887Schin static void ltou(register char const *str1,register char *str2)
2109*4887Schin /*@
2110*4887Schin 	assume str1!=0 && str2!=0;
2111*4887Schin 	return x satisfying strlen(in str1)==strlen(in str2);
2112*4887Schin @*/
2113*4887Schin {
2114*4887Schin 	register int c;
2115*4887Schin 	for(; c= *((unsigned char*)str1); str1++,str2++)
2116*4887Schin 	{
2117*4887Schin 		if(islower(c))
2118*4887Schin 			*str2 = toupper(c);
2119*4887Schin 		else
2120*4887Schin 			*str2 = c;
2121*4887Schin 	}
2122*4887Schin 	*str2 = 0;
2123*4887Schin }
2124*4887Schin 
2125*4887Schin /*
2126*4887Schin  * normalize <cp> and return pointer to subscript if any
2127*4887Schin  */
2128*4887Schin static char *lastdot(register char *cp)
2129*4887Schin {
2130*4887Schin 	register char *dp=cp, *ep=0;
2131*4887Schin 	register int c;
2132*4887Schin 	while(c= *cp++)
2133*4887Schin 	{
2134*4887Schin 		*dp++ = c;
2135*4887Schin 		if(c=='[')
2136*4887Schin 			ep = cp;
2137*4887Schin 		else if(c=='.')
2138*4887Schin 		{
2139*4887Schin 			if(*cp=='[')
2140*4887Schin 			{
2141*4887Schin 				ep = nv_endsubscript((Namval_t*)0,cp,0);
2142*4887Schin 				c = ep-cp;
2143*4887Schin 				memcpy(dp,cp,c);
2144*4887Schin 				dp = sh_checkid(dp+1,dp+c);
2145*4887Schin 				cp = ep;
2146*4887Schin 			}
2147*4887Schin 			ep = 0;
2148*4887Schin 		}
2149*4887Schin 	}
2150*4887Schin 	*dp = 0;
2151*4887Schin 	return(ep);
2152*4887Schin }
2153*4887Schin 
2154*4887Schin /*
2155*4887Schin  * Create a reference node from <np> to $np in dictionary <hp>
2156*4887Schin  */
2157*4887Schin void nv_setref(register Namval_t *np, Dt_t *hp, int flags)
2158*4887Schin {
2159*4887Schin 	register Namval_t *nq, *nr;
2160*4887Schin 	register char *ep,*cp;
2161*4887Schin 	if(nv_isref(np))
2162*4887Schin 		return;
2163*4887Schin 	if(nv_isarray(np))
2164*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
2165*4887Schin 	if(!(cp=nv_getval(np)))
2166*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np));
2167*4887Schin 	if((ep = lastdot(cp)) && nv_isattr(np,NV_MINIMAL))
2168*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
2169*4887Schin 	if(!hp)
2170*4887Schin 		hp = sh.var_tree;
2171*4887Schin 	nr= nq = nv_open(cp, hp, flags|NV_NOREF);
2172*4887Schin 	while(nv_isref(nr))
2173*4887Schin 	{
2174*4887Schin 		sh.last_table = nv_reftable(nr);
2175*4887Schin 		hp = nv_reftree(nr);
2176*4887Schin 		nr = nv_refnode(nr);
2177*4887Schin 	}
2178*4887Schin 	if(nr==np)
2179*4887Schin 	{
2180*4887Schin 		if(sh.namespace && nv_dict(sh.namespace)==hp)
2181*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
2182*4887Schin 		/* bind to earlier scope, or add to global scope */
2183*4887Schin 		if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np)
2184*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
2185*4887Schin 	}
2186*4887Schin 	if(ep)
2187*4887Schin 	{
2188*4887Schin 		/* cause subscript evaluation and return result */
2189*4887Schin #if 0
2190*4887Schin 		nv_endsubscript(nq,ep,NV_ADD);
2191*4887Schin #endif
2192*4887Schin 		ep = nv_getsub(nq);
2193*4887Schin 	}
2194*4887Schin 	nv_unset(np);
2195*4887Schin 	np->nvalue.nrp = newof(0,struct Namref,1,0);
2196*4887Schin 	np->nvalue.nrp->np = nq;
2197*4887Schin 	np->nvalue.nrp->root = hp;
2198*4887Schin 	if(ep)
2199*4887Schin 		np->nvalue.nrp->sub = strdup(ep);
2200*4887Schin 	np->nvalue.nrp->table = sh.last_table;
2201*4887Schin 	nv_onattr(np,NV_REF|NV_NOFREE);
2202*4887Schin }
2203*4887Schin 
2204*4887Schin /*
2205*4887Schin  * get the scope corresponding to <index>
2206*4887Schin  * whence uses the same values as lseeek()
2207*4887Schin  */
2208*4887Schin Shscope_t *sh_getscope(int index, int whence)
2209*4887Schin {
2210*4887Schin 	register struct sh_scoped *sp, *topmost;
2211*4887Schin 	if(whence==SEEK_CUR)
2212*4887Schin 		sp = &sh.st;
2213*4887Schin 	else
2214*4887Schin 	{
2215*4887Schin 		if ((struct sh_scoped*)sh.topscope != sh.st.self)
2216*4887Schin 			topmost = (struct sh_scoped*)sh.topscope;
2217*4887Schin 		else
2218*4887Schin 			topmost = &(sh.st);
2219*4887Schin 		sp = topmost;
2220*4887Schin 		if(whence==SEEK_SET)
2221*4887Schin 		{
2222*4887Schin 			int n =0;
2223*4887Schin 			while(sp = sp->prevst)
2224*4887Schin 				n++;
2225*4887Schin 			index = n - index;
2226*4887Schin 			sp = topmost;
2227*4887Schin 		}
2228*4887Schin 	}
2229*4887Schin 	if(index < 0)
2230*4887Schin 		return((Shscope_t*)0);
2231*4887Schin 	while(index-- && (sp = sp->prevst));
2232*4887Schin 	return((Shscope_t*)sp);
2233*4887Schin }
2234*4887Schin 
2235*4887Schin /*
2236*4887Schin  * make <scoped> the top scope and return previous scope
2237*4887Schin  */
2238*4887Schin Shscope_t *sh_setscope(Shscope_t *scope)
2239*4887Schin {
2240*4887Schin 	Shscope_t *old = (Shscope_t*)sh.st.self;
2241*4887Schin 	*sh.st.self = sh.st;
2242*4887Schin 	sh.st = *((struct sh_scoped*)scope);
2243*4887Schin 	sh.var_tree = scope->var_tree;
2244*4887Schin 	return(old);
2245*4887Schin }
2246*4887Schin 
2247*4887Schin void nv_unscope(void)
2248*4887Schin {
2249*4887Schin 	register Dt_t *root = sh.var_tree;
2250*4887Schin 	register Dt_t *dp = dtview(root,(Dt_t*)0);
2251*4887Schin 	table_unset(root,NV_RDONLY|NV_NOSCOPE,dp);
2252*4887Schin 	sh.var_tree=dp;
2253*4887Schin 	dtclose(root);
2254*4887Schin }
2255*4887Schin 
2256*4887Schin /*
2257*4887Schin  * The inverse of creating a reference node
2258*4887Schin  */
2259*4887Schin void nv_unref(register Namval_t *np)
2260*4887Schin {
2261*4887Schin 	Namval_t *nq;
2262*4887Schin 	if(!nv_isref(np))
2263*4887Schin 		return;
2264*4887Schin 	nq = nv_refnode(np);
2265*4887Schin 	nv_offattr(np,NV_NOFREE|NV_REF);
2266*4887Schin 	free((void*)np->nvalue.nrp);
2267*4887Schin 	np->nvalue.cp = strdup(nv_name(nq));
2268*4887Schin #if SHOPT_OPTIMIZE
2269*4887Schin 	{
2270*4887Schin 		Namfun_t *fp;
2271*4887Schin 		for(fp=nq->nvfun; fp; fp = fp->next)
2272*4887Schin 		{
2273*4887Schin 			if(fp->disc== &optimize_disc)
2274*4887Schin 			{
2275*4887Schin 				optimize_clear(nq,fp);
2276*4887Schin 				return;
2277*4887Schin 			}
2278*4887Schin 		}
2279*4887Schin 	}
2280*4887Schin #endif
2281*4887Schin }
2282*4887Schin 
2283*4887Schin /*
2284*4887Schin  * These following are for binary compatibility with the old hash library
2285*4887Schin  * They will be removed someday
2286*4887Schin  */
2287*4887Schin 
2288*4887Schin #if defined(__IMPORT__) && defined(__EXPORT__)
2289*4887Schin #   define extern __EXPORT__
2290*4887Schin #endif
2291*4887Schin 
2292*4887Schin #undef	hashscope
2293*4887Schin 
2294*4887Schin extern Dt_t *hashscope(Dt_t *root)
2295*4887Schin {
2296*4887Schin 	return(dtvnext(root));
2297*4887Schin }
2298*4887Schin 
2299*4887Schin #undef	hashfree
2300*4887Schin 
2301*4887Schin extern Dt_t	*hashfree(Dt_t *root)
2302*4887Schin {
2303*4887Schin 	Dt_t *dp = dtvnext(root);
2304*4887Schin 	dtclose(root);
2305*4887Schin 	return(dp);
2306*4887Schin }
2307*4887Schin 
2308*4887Schin #undef	hashname
2309*4887Schin 
2310*4887Schin extern char	*hashname(void *obj)
2311*4887Schin {
2312*4887Schin 	Namval_t *np = (Namval_t*)obj;
2313*4887Schin 	return(np->nvname);
2314*4887Schin }
2315*4887Schin 
2316*4887Schin #undef	hashlook
2317*4887Schin 
2318*4887Schin extern void *hashlook(Dt_t *root, const char *name, int mode,int size)
2319*4887Schin {
2320*4887Schin 	NOT_USED(size);
2321*4887Schin 	return((void*)nv_search(name,root,mode));
2322*4887Schin }
2323*4887Schin 
2324*4887Schin char *nv_name(register Namval_t *np)
2325*4887Schin {
2326*4887Schin 	register Namval_t *table;
2327*4887Schin 	register Namfun_t *fp;
2328*4887Schin 	char *cp;
2329*4887Schin 	if(is_abuiltin(np) || is_afunction(np))
2330*4887Schin 		return(np->nvname);
2331*4887Schin 	if(nv_istable(np))
2332*4887Schin #if 1
2333*4887Schin 		sh.last_table = nv_parent(np);
2334*4887Schin #else
2335*4887Schin 		sh.last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0);
2336*4887Schin #endif
2337*4887Schin 	else if(!nv_isref(np))
2338*4887Schin 	{
2339*4887Schin 		for(fp= np->nvfun ; fp; fp=fp->next)
2340*4887Schin 		if(fp->disc && fp->disc->namef)
2341*4887Schin 		{
2342*4887Schin 			if(np==sh.last_table)
2343*4887Schin 				sh.last_table = 0;
2344*4887Schin 			return((*fp->disc->namef)(np,fp));
2345*4887Schin 		}
2346*4887Schin 	}
2347*4887Schin 	if(!(table=sh.last_table) || *np->nvname=='.' || table==sh.namespace || np==table)
2348*4887Schin 		return(np->nvname);
2349*4887Schin 	cp = nv_name(table);
2350*4887Schin 	sfprintf(sh.strbuf,"%s.%s",cp,np->nvname);
2351*4887Schin 	return(sfstruse(sh.strbuf));
2352*4887Schin }
2353*4887Schin 
2354*4887Schin Namval_t *nv_lastdict(void)
2355*4887Schin {
2356*4887Schin 	return(sh.last_table);
2357*4887Schin }
2358*4887Schin 
2359*4887Schin #undef nv_context
2360*4887Schin /*
2361*4887Schin  * returns the data context for a builtin
2362*4887Schin  */
2363*4887Schin void *nv_context(Namval_t *np)
2364*4887Schin {
2365*4887Schin 	return((void*)np->nvfun);
2366*4887Schin }
2367*4887Schin 
2368*4887Schin #define DISABLE /* proto workaround */
2369*4887Schin 
2370*4887Schin int nv_isnull DISABLE (register Namval_t *np)
2371*4887Schin {
2372*4887Schin 	return(nv_isnull(np));
2373*4887Schin }
2374*4887Schin 
2375*4887Schin #undef nv_setsize
2376*4887Schin int nv_setsize(register Namval_t *np, int size)
2377*4887Schin {
2378*4887Schin 	int oldsize = nv_size(np);
2379*4887Schin 	if(size>=0)
2380*4887Schin 		np->nvsize = size;
2381*4887Schin 	return(oldsize);
2382*4887Schin }
2383