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  *
23*4887Schin  * Shell initialization
24*4887Schin  *
25*4887Schin  *   David Korn
26*4887Schin  *   AT&T Labs
27*4887Schin  *
28*4887Schin  */
29*4887Schin 
30*4887Schin #include        "defs.h"
31*4887Schin #include        <stak.h>
32*4887Schin #include        <ctype.h>
33*4887Schin #include        <ccode.h>
34*4887Schin #include        <pwd.h>
35*4887Schin #include        "variables.h"
36*4887Schin #include        "path.h"
37*4887Schin #include        "fault.h"
38*4887Schin #include        "name.h"
39*4887Schin #include	"edit.h"
40*4887Schin #include	"jobs.h"
41*4887Schin #include	"io.h"
42*4887Schin #include	"shlex.h"
43*4887Schin #include	"builtins.h"
44*4887Schin #include	"FEATURE/time"
45*4887Schin #include	"FEATURE/dynamic"
46*4887Schin #include	"lexstates.h"
47*4887Schin #include	"version.h"
48*4887Schin 
49*4887Schin #if SHOPT_MULTIBYTE
50*4887Schin     char e_version[]	= "\n@(#)$Id: Version M "SH_RELEASE" $\0\n";
51*4887Schin #else
52*4887Schin     char e_version[]	= "\n@(#)$Id: Version "SH_RELEASE" $\0\n";
53*4887Schin #endif /* SHOPT_MULTIBYTE */
54*4887Schin 
55*4887Schin #if SHOPT_BASH
56*4887Schin     extern void bash_init(int);
57*4887Schin #endif
58*4887Schin 
59*4887Schin #define RANDMASK	0x7fff
60*4887Schin #ifndef CLK_TCK
61*4887Schin #   define CLK_TCK	60
62*4887Schin #endif /* CLK_TCK */
63*4887Schin 
64*4887Schin #ifndef environ
65*4887Schin     extern char	**environ;
66*4887Schin #endif
67*4887Schin 
68*4887Schin #undef	getconf
69*4887Schin #define getconf(x)	strtol(astconf(x,NiL,NiL),NiL,0)
70*4887Schin 
71*4887Schin struct seconds
72*4887Schin {
73*4887Schin 	Namfun_t	hdr;
74*4887Schin 	Shell_t		*sh;
75*4887Schin };
76*4887Schin 
77*4887Schin struct rand
78*4887Schin {
79*4887Schin 	Namfun_t	hdr;
80*4887Schin 	Shell_t		*sh;
81*4887Schin 	int32_t		rand_last;
82*4887Schin };
83*4887Schin 
84*4887Schin struct ifs
85*4887Schin {
86*4887Schin 	Namfun_t	hdr;
87*4887Schin 	Shell_t		*sh;
88*4887Schin 	Namval_t	*ifsnp;
89*4887Schin };
90*4887Schin 
91*4887Schin struct shell
92*4887Schin {
93*4887Schin 	Namfun_t	hdr;
94*4887Schin 	Shell_t		*sh;
95*4887Schin };
96*4887Schin 
97*4887Schin struct match
98*4887Schin {
99*4887Schin 	Namfun_t	hdr;
100*4887Schin 	char		*val;
101*4887Schin 	char		*rval;
102*4887Schin 	int		vsize;
103*4887Schin 	int		nmatch;
104*4887Schin 	int		lastsub;
105*4887Schin 	int		match[2*(MATCH_MAX+1)];
106*4887Schin };
107*4887Schin 
108*4887Schin typedef struct _init_
109*4887Schin {
110*4887Schin 	Shell_t		*sh;
111*4887Schin #if SHOPT_FS_3D
112*4887Schin 	Namfun_t	VPATH_init;
113*4887Schin #endif /* SHOPT_FS_3D */
114*4887Schin 	struct ifs	IFS_init;
115*4887Schin 	struct shell	PATH_init;
116*4887Schin #ifdef PATH_BFPATH
117*4887Schin 	struct shell	FPATH_init;
118*4887Schin 	struct shell	CDPATH_init;
119*4887Schin #endif
120*4887Schin 	struct shell	SHELL_init;
121*4887Schin 	struct shell	ENV_init;
122*4887Schin 	struct shell	VISUAL_init;
123*4887Schin 	struct shell	EDITOR_init;
124*4887Schin 	struct shell	OPTINDEX_init;
125*4887Schin 	struct seconds	SECONDS_init;
126*4887Schin 	struct rand	RAND_init;
127*4887Schin 	struct shell	LINENO_init;
128*4887Schin 	struct shell	L_ARG_init;
129*4887Schin 	struct match	SH_MATCH_init;
130*4887Schin #ifdef _hdr_locale
131*4887Schin 	struct shell	LC_TYPE_init;
132*4887Schin 	struct shell	LC_NUM_init;
133*4887Schin 	struct shell	LC_COLL_init;
134*4887Schin 	struct shell	LC_MSG_init;
135*4887Schin 	struct shell	LC_ALL_init;
136*4887Schin 	struct shell	LANG_init;
137*4887Schin #endif /* _hdr_locale */
138*4887Schin } Init_t;
139*4887Schin 
140*4887Schin static void		env_init(Shell_t*);
141*4887Schin static Init_t		*nv_init(Shell_t*);
142*4887Schin static Dt_t		*inittree(Shell_t*,const struct shtable2*);
143*4887Schin 
144*4887Schin #ifdef _WINIX
145*4887Schin #   define EXE	"?(.exe)"
146*4887Schin #else
147*4887Schin #   define EXE
148*4887Schin #endif
149*4887Schin 
150*4887Schin static int		rand_shift;
151*4887Schin 
152*4887Schin 
153*4887Schin /*
154*4887Schin  * Invalidate all path name bindings
155*4887Schin  */
156*4887Schin static void rehash(register Namval_t *np,void *data)
157*4887Schin {
158*4887Schin 	NOT_USED(data);
159*4887Schin 	nv_onattr(np,NV_NOALIAS);
160*4887Schin }
161*4887Schin 
162*4887Schin /*
163*4887Schin  * out of memory routine for stak routines
164*4887Schin  */
165*4887Schin static char *nospace(int unused)
166*4887Schin {
167*4887Schin 	NOT_USED(unused);
168*4887Schin 	errormsg(SH_DICT,ERROR_exit(3),e_nospace);
169*4887Schin 	return(NIL(char*));
170*4887Schin }
171*4887Schin 
172*4887Schin /* Trap for VISUAL and EDITOR variables */
173*4887Schin static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
174*4887Schin {
175*4887Schin 	register const char *cp, *name=nv_name(np);
176*4887Schin 	if(*name=='E' && nv_getval(nv_scoped(VISINOD)))
177*4887Schin 		goto done;
178*4887Schin 	sh_offoption(SH_VI);
179*4887Schin 	sh_offoption(SH_EMACS);
180*4887Schin 	sh_offoption(SH_GMACS);
181*4887Schin 	if(!(cp=val) && (*name=='E' || !(cp=nv_getval(nv_scoped(EDITNOD)))))
182*4887Schin 		goto done;
183*4887Schin 	/* turn on vi or emacs option if editor name is either*/
184*4887Schin 	cp = path_basename(cp);
185*4887Schin 	if(strmatch(cp,"*[Vv][Ii]*"))
186*4887Schin 		sh_onoption(SH_VI);
187*4887Schin 	else if(strmatch(cp,"*gmacs*"))
188*4887Schin 		sh_onoption(SH_GMACS);
189*4887Schin 	else if(strmatch(cp,"*macs*"))
190*4887Schin 		sh_onoption(SH_EMACS);
191*4887Schin done:
192*4887Schin 	nv_putv(np, val, flags, fp);
193*4887Schin }
194*4887Schin 
195*4887Schin /* Trap for OPTINDEX */
196*4887Schin static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp)
197*4887Schin {
198*4887Schin 	Shell_t *shp = ((struct shell*)fp)->sh;
199*4887Schin 	shp->st.opterror = shp->st.optchar = 0;
200*4887Schin 	nv_putv(np, val, flags, fp);
201*4887Schin }
202*4887Schin 
203*4887Schin static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
204*4887Schin {
205*4887Schin 	return((Sfdouble_t)*np->nvalue.lp);
206*4887Schin }
207*4887Schin 
208*4887Schin /* Trap for restricted variables FPATH, PATH, SHELL, ENV */
209*4887Schin static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
210*4887Schin {
211*4887Schin 	Shell_t *shp = ((struct shell*)fp)->sh;
212*4887Schin 	int		path_scoped = 0;
213*4887Schin #ifdef PATH_BFPATH
214*4887Schin 	Pathcomp_t *pp;
215*4887Schin 	char *name = nv_name(np);
216*4887Schin #endif
217*4887Schin 	if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
218*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
219*4887Schin 	if(np==PATHNOD	|| (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
220*4887Schin 	{
221*4887Schin #ifndef PATH_BFPATH
222*4887Schin 		shp->lastpath = 0;
223*4887Schin #endif
224*4887Schin 		nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
225*4887Schin 		if(path_scoped && !val)
226*4887Schin 			val = PATHNOD->nvalue.cp;
227*4887Schin 	}
228*4887Schin 	if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0)
229*4887Schin 		 return;
230*4887Schin #ifdef PATH_BFPATH
231*4887Schin 	if(shp->pathlist  && np==FPATHNOD)
232*4887Schin 		shp->pathlist = (void*)path_unsetfpath((Pathcomp_t*)shp->pathlist);
233*4887Schin #endif
234*4887Schin 	nv_putv(np, val, flags, fp);
235*4887Schin #ifdef PATH_BFPATH
236*4887Schin 	if(shp->pathlist)
237*4887Schin 	{
238*4887Schin 		val = np->nvalue.cp;
239*4887Schin 		if(np==PATHNOD || path_scoped)
240*4887Schin 			pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
241*4887Schin 		else if(val && np==FPATHNOD)
242*4887Schin 			pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
243*4887Schin 		else
244*4887Schin 			return;
245*4887Schin 		if(shp->pathlist = (void*)pp)
246*4887Schin 			pp->shp = shp;
247*4887Schin 		if(!val && (flags&NV_NOSCOPE))
248*4887Schin 		{
249*4887Schin 			Namval_t *mp = dtsearch(shp->var_tree,np);
250*4887Schin 			if(mp && (val=nv_getval(mp)))
251*4887Schin 				nv_putval(mp,val,NV_RDONLY);
252*4887Schin 		}
253*4887Schin #if 0
254*4887Schin sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val);
255*4887Schin path_dump((Pathcomp_t*)shp->pathlist);
256*4887Schin #endif
257*4887Schin 	}
258*4887Schin #endif
259*4887Schin }
260*4887Schin 
261*4887Schin #ifdef PATH_BFPATH
262*4887Schin static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
263*4887Schin {
264*4887Schin 	Pathcomp_t *pp;
265*4887Schin 	Shell_t *shp = ((struct shell*)fp)->sh;
266*4887Schin 	nv_putv(np, val, flags, fp);
267*4887Schin 	if(!shp->cdpathlist)
268*4887Schin 		return;
269*4887Schin 	val = np->nvalue.cp;
270*4887Schin 	pp = (void*)path_addpath((Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH);
271*4887Schin 	if(shp->cdpathlist = (void*)pp)
272*4887Schin 		pp->shp = shp;
273*4887Schin }
274*4887Schin #endif
275*4887Schin 
276*4887Schin #ifdef _hdr_locale
277*4887Schin     /*
278*4887Schin      * This function needs to be modified to handle international
279*4887Schin      * error message translations
280*4887Schin      */
281*4887Schin #if ERROR_VERSION >= 20000101L
282*4887Schin     static char* msg_translate(const char* catalog, const char* message)
283*4887Schin     {
284*4887Schin 	NOT_USED(catalog);
285*4887Schin 	return((char*)message);
286*4887Schin     }
287*4887Schin #else
288*4887Schin     static char* msg_translate(const char* message, int type)
289*4887Schin     {
290*4887Schin 	NOT_USED(type);
291*4887Schin 	return((char*)message);
292*4887Schin     }
293*4887Schin #endif
294*4887Schin 
295*4887Schin     /* Trap for LC_ALL, LC_TYPE, LC_MESSAGES, LC_COLLATE and LANG */
296*4887Schin     static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp)
297*4887Schin     {
298*4887Schin 	int type;
299*4887Schin 	char *lc_all = nv_getval(LCALLNOD);
300*4887Schin 	char *name = nv_name(np);
301*4887Schin 	if(name==(LCALLNOD)->nvname)
302*4887Schin 		type = LC_ALL;
303*4887Schin 	else if(name==(LCTYPENOD)->nvname)
304*4887Schin 		type = LC_CTYPE;
305*4887Schin 	else if(name==(LCMSGNOD)->nvname)
306*4887Schin 		type = LC_MESSAGES;
307*4887Schin 	else if(name==(LCCOLLNOD)->nvname)
308*4887Schin 		type = LC_COLLATE;
309*4887Schin 	else if(name==(LCNUMNOD)->nvname)
310*4887Schin 		type = LC_NUMERIC;
311*4887Schin 	else if(name==(LANGNOD)->nvname && (!lc_all || *lc_all==0))
312*4887Schin 		type = LC_ALL;
313*4887Schin 	else
314*4887Schin 		type= -1;
315*4887Schin 	if(sh_isstate(SH_INIT) && type>=0 && type!=LC_ALL && lc_all && *lc_all)
316*4887Schin 		type= -1;
317*4887Schin 	if(type>=0)
318*4887Schin 	{
319*4887Schin 		if(!setlocale(type,val?val:""))
320*4887Schin 		{
321*4887Schin 			if(!sh_isstate(SH_INIT) || sh.login_sh==0)
322*4887Schin 				errormsg(SH_DICT,0,e_badlocale,val);
323*4887Schin 			return;
324*4887Schin 		}
325*4887Schin 	}
326*4887Schin 	if(CC_NATIVE==CC_ASCII && (type==LC_ALL || type==LC_CTYPE))
327*4887Schin 	{
328*4887Schin 		if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
329*4887Schin 			free((void*)sh_lexstates[ST_BEGIN]);
330*4887Schin 		if(ast.locale.set&(1<<AST_LC_CTYPE))
331*4887Schin 		{
332*4887Schin 			register int c;
333*4887Schin 			char *state[4];
334*4887Schin 			sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
335*4887Schin 			memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
336*4887Schin 			sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
337*4887Schin 			memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
338*4887Schin 			sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
339*4887Schin 			memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
340*4887Schin 			sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
341*4887Schin 			memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
342*4887Schin 			for(c=0; c<(1<<CHAR_BIT); c++)
343*4887Schin 			{
344*4887Schin 				if(state[0][c]!=S_REG)
345*4887Schin 					continue;
346*4887Schin 				if(state[2][c]!=S_ERR)
347*4887Schin 					continue;
348*4887Schin 				if(isblank(c))
349*4887Schin 				{
350*4887Schin 					state[0][c]=0;
351*4887Schin 					state[1][c]=S_BREAK;
352*4887Schin 					state[2][c]=S_BREAK;
353*4887Schin 					continue;
354*4887Schin 				}
355*4887Schin 				if(!isalpha(c))
356*4887Schin 					continue;
357*4887Schin 				state[0][c]=S_NAME;
358*4887Schin 				if(state[1][c]==S_REG)
359*4887Schin 					state[1][c]=0;
360*4887Schin 				state[2][c]=S_ALP;
361*4887Schin 				if(state[3][c]==S_ERR)
362*4887Schin 					state[3][c]=0;
363*4887Schin 			}
364*4887Schin 		}
365*4887Schin 		else
366*4887Schin 		{
367*4887Schin 			sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
368*4887Schin 			sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
369*4887Schin 			sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
370*4887Schin 			sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
371*4887Schin 		}
372*4887Schin 	}
373*4887Schin #if ERROR_VERSION < 20000101L
374*4887Schin 	if(type==LC_ALL || type==LC_MESSAGES)
375*4887Schin 		error_info.translate = msg_translate;
376*4887Schin #endif
377*4887Schin 	nv_putv(np, val, flags, fp);
378*4887Schin     }
379*4887Schin #endif /* _hdr_locale */
380*4887Schin 
381*4887Schin /* Trap for IFS assignment and invalidates state table */
382*4887Schin static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
383*4887Schin {
384*4887Schin 	register struct ifs *ip = (struct ifs*)fp;
385*4887Schin 	ip->ifsnp = 0;
386*4887Schin 	if(val != np->nvalue.cp)
387*4887Schin 		nv_putv(np, val, flags, fp);
388*4887Schin 
389*4887Schin }
390*4887Schin 
391*4887Schin /*
392*4887Schin  * This is the lookup function for IFS
393*4887Schin  * It keeps the sh.ifstable up to date
394*4887Schin  */
395*4887Schin static char* get_ifs(register Namval_t* np, Namfun_t *fp)
396*4887Schin {
397*4887Schin 	register struct ifs *ip = (struct ifs*)fp;
398*4887Schin 	register char *cp, *value;
399*4887Schin 	register int c,n;
400*4887Schin 	register Shell_t *shp = ip->sh;
401*4887Schin 	value = nv_getv(np,fp);
402*4887Schin 	if(np!=ip->ifsnp)
403*4887Schin 	{
404*4887Schin 		ip->ifsnp = np;
405*4887Schin 		memset(shp->ifstable,0,(1<<CHAR_BIT));
406*4887Schin 		if(cp=value)
407*4887Schin 		{
408*4887Schin #if SHOPT_MULTIBYTE
409*4887Schin 			while(n=mbsize(cp),c= *(unsigned char*)cp)
410*4887Schin #else
411*4887Schin 			while(c= *(unsigned char*)cp++)
412*4887Schin #endif /* SHOPT_MULTIBYTE */
413*4887Schin 			{
414*4887Schin #if SHOPT_MULTIBYTE
415*4887Schin 				cp++;
416*4887Schin 				if(n>1)
417*4887Schin 				{
418*4887Schin 					cp += (n-1);
419*4887Schin 					shp->ifstable[c] = S_MBYTE;
420*4887Schin 					continue;
421*4887Schin 				}
422*4887Schin #endif /* SHOPT_MULTIBYTE */
423*4887Schin 				n = S_DELIM;
424*4887Schin 				if(c== *cp)
425*4887Schin 					cp++;
426*4887Schin 				else if(c=='\n')
427*4887Schin 					n = S_NL;
428*4887Schin 				else if(isspace(c))
429*4887Schin 					n = S_SPACE;
430*4887Schin 				shp->ifstable[c] = n;
431*4887Schin 			}
432*4887Schin 		}
433*4887Schin 		else
434*4887Schin 		{
435*4887Schin 			shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE;
436*4887Schin 			shp->ifstable['\n'] = S_NL;
437*4887Schin 		}
438*4887Schin 	}
439*4887Schin 	return(value);
440*4887Schin }
441*4887Schin 
442*4887Schin /*
443*4887Schin  * these functions are used to get and set the SECONDS variable
444*4887Schin  */
445*4887Schin #ifdef timeofday
446*4887Schin #   define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
447*4887Schin #   define tms	timeval
448*4887Schin #else
449*4887Schin #   define dtime(tp)	(((double)times(tp))/sh.lim.clk_tck)
450*4887Schin #   define timeofday(a)
451*4887Schin #endif
452*4887Schin 
453*4887Schin static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
454*4887Schin {
455*4887Schin 	double d;
456*4887Schin 	struct tms tp;
457*4887Schin 	if(!val)
458*4887Schin 	{
459*4887Schin 		nv_stack(np, NIL(Namfun_t*));
460*4887Schin 		nv_unset(np);
461*4887Schin 		return;
462*4887Schin 	}
463*4887Schin 	if(!np->nvalue.dp)
464*4887Schin 	{
465*4887Schin 		nv_setsize(np,3);
466*4887Schin 		np->nvalue.dp = new_of(double,0);
467*4887Schin 	}
468*4887Schin 	nv_putv(np, val, flags, fp);
469*4887Schin 	d = *np->nvalue.dp;
470*4887Schin 	timeofday(&tp);
471*4887Schin 	*np->nvalue.dp = dtime(&tp)-d;
472*4887Schin }
473*4887Schin 
474*4887Schin static char* get_seconds(register Namval_t* np, Namfun_t *fp)
475*4887Schin {
476*4887Schin 	register int places = nv_size(np);
477*4887Schin 	struct tms tp;
478*4887Schin 	double d, offset = (np->nvalue.dp?*np->nvalue.dp:0);
479*4887Schin 	NOT_USED(fp);
480*4887Schin 	timeofday(&tp);
481*4887Schin 	d = dtime(&tp)- offset;
482*4887Schin 	sfprintf(sh.strbuf,"%.*f",places,d);
483*4887Schin 	return(sfstruse(sh.strbuf));
484*4887Schin }
485*4887Schin 
486*4887Schin static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp)
487*4887Schin {
488*4887Schin 	struct tms tp;
489*4887Schin 	double offset = (np->nvalue.dp?*np->nvalue.dp:0);
490*4887Schin 	NOT_USED(fp);
491*4887Schin 	timeofday(&tp);
492*4887Schin 	return(dtime(&tp)- offset);
493*4887Schin }
494*4887Schin 
495*4887Schin /*
496*4887Schin  * These three functions are used to get and set the RANDOM variable
497*4887Schin  */
498*4887Schin static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
499*4887Schin {
500*4887Schin 	struct rand *rp = (struct rand*)fp;
501*4887Schin 	register long n;
502*4887Schin 	if(!val)
503*4887Schin 	{
504*4887Schin 		nv_stack(np, NIL(Namfun_t*));
505*4887Schin 		nv_unset(np);
506*4887Schin 		return;
507*4887Schin 	}
508*4887Schin 	if(flags&NV_INTEGER)
509*4887Schin 		n = *(double*)val;
510*4887Schin 	else
511*4887Schin 		n = sh_arith(val);
512*4887Schin 	srand((int)(n&RANDMASK));
513*4887Schin 	rp->rand_last = -1;
514*4887Schin 	if(!np->nvalue.lp)
515*4887Schin 		np->nvalue.lp = &rp->rand_last;
516*4887Schin }
517*4887Schin 
518*4887Schin /*
519*4887Schin  * get random number in range of 0 - 2**15
520*4887Schin  * never pick same number twice in a row
521*4887Schin  */
522*4887Schin static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp)
523*4887Schin {
524*4887Schin 	register long cur, last= *np->nvalue.lp;
525*4887Schin 	NOT_USED(fp);
526*4887Schin 	do
527*4887Schin 		cur = (rand()>>rand_shift)&RANDMASK;
528*4887Schin 	while(cur==last);
529*4887Schin 	*np->nvalue.lp = cur;
530*4887Schin 	return((Sfdouble_t)cur);
531*4887Schin }
532*4887Schin 
533*4887Schin static char* get_rand(register Namval_t* np, Namfun_t *fp)
534*4887Schin {
535*4887Schin 	register long n = nget_rand(np,fp);
536*4887Schin 	return(fmtbase(n, 10, 0));
537*4887Schin }
538*4887Schin 
539*4887Schin /*
540*4887Schin  * These three routines are for LINENO
541*4887Schin  */
542*4887Schin static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp)
543*4887Schin {
544*4887Schin 	double d=1;
545*4887Schin 	if(error_info.line >0)
546*4887Schin 		d = error_info.line;
547*4887Schin 	else if(error_info.context && error_info.context->line>0)
548*4887Schin 		d = error_info.context->line;
549*4887Schin 	NOT_USED(np);
550*4887Schin 	NOT_USED(fp);
551*4887Schin 	return(d);
552*4887Schin }
553*4887Schin 
554*4887Schin static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
555*4887Schin {
556*4887Schin 	register long n;
557*4887Schin 	Shell_t *shp = ((struct shell*)fp)->sh;
558*4887Schin 	if(!val)
559*4887Schin 	{
560*4887Schin 		nv_stack(np, NIL(Namfun_t*));
561*4887Schin 		nv_unset(np);
562*4887Schin 		return;
563*4887Schin 	}
564*4887Schin 	if(flags&NV_INTEGER)
565*4887Schin 		n = *(double*)val;
566*4887Schin 	else
567*4887Schin 		n = sh_arith(val);
568*4887Schin 	shp->st.firstline += nget_lineno(np,fp)+1-n;
569*4887Schin }
570*4887Schin 
571*4887Schin static char* get_lineno(register Namval_t* np, Namfun_t *fp)
572*4887Schin {
573*4887Schin 	register long n = nget_lineno(np,fp);
574*4887Schin 	return(fmtbase(n, 10, 0));
575*4887Schin }
576*4887Schin 
577*4887Schin static char* get_lastarg(Namval_t* np, Namfun_t *fp)
578*4887Schin {
579*4887Schin 	NOT_USED(np);
580*4887Schin 	return(sh.lastarg);
581*4887Schin }
582*4887Schin 
583*4887Schin static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp)
584*4887Schin {
585*4887Schin 	if(flags&NV_INTEGER)
586*4887Schin 	{
587*4887Schin 		sfprintf(sh.strbuf,"%.*g",12,*((double*)val));
588*4887Schin 		val = sfstruse(sh.strbuf);
589*4887Schin 	}
590*4887Schin 	if(sh.lastarg && !nv_isattr(np,NV_NOFREE))
591*4887Schin 		free((void*)sh.lastarg);
592*4887Schin 	else
593*4887Schin 		nv_offattr(np,NV_NOFREE);
594*4887Schin 	if(val)
595*4887Schin 		sh.lastarg = strdup(val);
596*4887Schin 	else
597*4887Schin 		sh.lastarg = 0;
598*4887Schin }
599*4887Schin 
600*4887Schin static int hasgetdisc(register Namfun_t *fp)
601*4887Schin {
602*4887Schin         while(fp && !fp->disc->getnum && !fp->disc->getval)
603*4887Schin                 fp = fp->next;
604*4887Schin 	return(fp!=0);
605*4887Schin }
606*4887Schin 
607*4887Schin /*
608*4887Schin  * store the most recent value for use in .sh.match
609*4887Schin  */
610*4887Schin void sh_setmatch(const char *v, int vsize, int nmatch, int match[])
611*4887Schin {
612*4887Schin 	struct match *mp = (struct match*)(SH_MATCHNOD->nvfun);
613*4887Schin 	register int i,n;
614*4887Schin 	if(mp->nmatch = nmatch)
615*4887Schin 	{
616*4887Schin 		memcpy(mp->match,match,nmatch*2*sizeof(match[0]));
617*4887Schin 		for(n=match[0],i=1; i < 2*nmatch; i++)
618*4887Schin 		{
619*4887Schin 			if(mp->match[i] < n)
620*4887Schin 				n = mp->match[i];
621*4887Schin 		}
622*4887Schin 		for(vsize=0,i=0; i < 2*nmatch; i++)
623*4887Schin 		{
624*4887Schin 			if((mp->match[i] -= n) > vsize)
625*4887Schin 				vsize = mp->match[i];
626*4887Schin 		}
627*4887Schin 		v += n;
628*4887Schin 		if(vsize >= mp->vsize)
629*4887Schin 		{
630*4887Schin 			if(mp->vsize)
631*4887Schin 				mp->val = (char*)realloc(mp->val,vsize+1);
632*4887Schin 			else
633*4887Schin 				mp->val = (char*)malloc(vsize+1);
634*4887Schin 			mp->vsize = vsize;
635*4887Schin 		}
636*4887Schin 		memcpy(mp->val,v,vsize);
637*4887Schin 		mp->val[vsize] = 0;
638*4887Schin 		nv_putsub(SH_MATCHNOD, NIL(char*), nmatch|ARRAY_FILL);
639*4887Schin 		mp->lastsub = -1;
640*4887Schin 	}
641*4887Schin }
642*4887Schin 
643*4887Schin #define array_scan(np)	((nv_arrayptr(np)->nelem&ARRAY_SCAN))
644*4887Schin 
645*4887Schin static char* get_match(register Namval_t* np, Namfun_t *fp)
646*4887Schin {
647*4887Schin 	struct match *mp = (struct match*)fp;
648*4887Schin 	int sub,n;
649*4887Schin 	char *val;
650*4887Schin 	sub = nv_aindex(np);
651*4887Schin 	if(sub>=mp->nmatch)
652*4887Schin 		return(0);
653*4887Schin 	if(sub==mp->lastsub)
654*4887Schin 		return(mp->rval);
655*4887Schin 	if(mp->rval)
656*4887Schin 	{
657*4887Schin 		free((void*)mp->rval);
658*4887Schin 		mp->rval = 0;
659*4887Schin 	}
660*4887Schin 	n = mp->match[2*sub+1]-mp->match[2*sub];
661*4887Schin 	if(n<=0)
662*4887Schin 		return("");
663*4887Schin 	val = mp->val+mp->match[2*sub];
664*4887Schin 	if(mp->val[mp->match[2*sub+1]]==0)
665*4887Schin 		return(val);
666*4887Schin 	mp->rval = (char*)malloc(n+1);
667*4887Schin 	mp->lastsub = sub;
668*4887Schin 	memcpy(mp->rval,val,n);
669*4887Schin 	mp->rval[n] = 0;
670*4887Schin 	return(mp->rval);
671*4887Schin }
672*4887Schin 
673*4887Schin static const Namdisc_t SH_MATCH_disc  = {  sizeof(struct match), 0, get_match };
674*4887Schin 
675*4887Schin #if SHOPT_FS_3D
676*4887Schin     /*
677*4887Schin      * set or unset the mappings given a colon separated list of directories
678*4887Schin      */
679*4887Schin     static void vpath_set(char *str, int mode)
680*4887Schin     {
681*4887Schin 	register char *lastp, *oldp=str, *newp=strchr(oldp,':');
682*4887Schin 	if(!sh.lim.fs3d)
683*4887Schin 		return;
684*4887Schin 	while(newp)
685*4887Schin 	{
686*4887Schin 		*newp++ = 0;
687*4887Schin 		if(lastp=strchr(newp,':'))
688*4887Schin 			*lastp = 0;
689*4887Schin 		mount((mode?newp:""),oldp,FS3D_VIEW,0);
690*4887Schin 		newp[-1] = ':';
691*4887Schin 		oldp = newp;
692*4887Schin 		newp=lastp;
693*4887Schin 	}
694*4887Schin     }
695*4887Schin 
696*4887Schin     /* catch vpath assignments */
697*4887Schin     static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
698*4887Schin     {
699*4887Schin 	register char *cp;
700*4887Schin 	if(cp = nv_getval(np))
701*4887Schin 		vpath_set(cp,0);
702*4887Schin 	if(val)
703*4887Schin 		vpath_set((char*)val,1);
704*4887Schin 	nv_putv(np,val,flags,fp);
705*4887Schin     }
706*4887Schin     static const Namdisc_t VPATH_disc	= { 0, put_vpath  };
707*4887Schin     static Namfun_t VPATH_init	= { &VPATH_disc, 1  };
708*4887Schin #endif /* SHOPT_FS_3D */
709*4887Schin 
710*4887Schin 
711*4887Schin static const Namdisc_t IFS_disc		= {  sizeof(struct ifs), put_ifs, get_ifs };
712*4887Schin const Namdisc_t RESTRICTED_disc	= {  sizeof(struct shell), put_restricted };
713*4887Schin #ifdef PATH_BFPATH
714*4887Schin static const Namdisc_t CDPATH_disc	= {  sizeof(struct shell), put_cdpath };
715*4887Schin #endif
716*4887Schin static const Namdisc_t EDITOR_disc	= {  sizeof(struct shell), put_ed };
717*4887Schin static const Namdisc_t OPTINDEX_disc	= {  sizeof(struct shell), put_optindex, 0, nget_optindex };
718*4887Schin static const Namdisc_t SECONDS_disc	= {  sizeof(struct seconds), put_seconds, get_seconds, nget_seconds };
719*4887Schin static const Namdisc_t RAND_disc	= {  sizeof(struct rand), put_rand, get_rand, nget_rand };
720*4887Schin static const Namdisc_t LINENO_disc	= {  sizeof(struct shell), put_lineno, get_lineno, nget_lineno };
721*4887Schin static const Namdisc_t L_ARG_disc	= {  sizeof(struct shell), put_lastarg, get_lastarg };
722*4887Schin 
723*4887Schin #if SHOPT_NAMESPACE
724*4887Schin     static char* get_nspace(Namval_t* np, Namfun_t *fp)
725*4887Schin     {
726*4887Schin 	if(sh.namespace)
727*4887Schin 		return(nv_name(sh.namespace));
728*4887Schin 	return((char*)np->nvalue.cp);
729*4887Schin     }
730*4887Schin     static const Namdisc_t NSPACE_disc	= {  0, 0, get_nspace };
731*4887Schin     static Namfun_t NSPACE_init	= {  &NSPACE_disc, 1};
732*4887Schin #endif /* SHOPT_NAMESPACE */
733*4887Schin 
734*4887Schin #ifdef _hdr_locale
735*4887Schin     static const Namdisc_t LC_disc	= {  sizeof(struct shell), put_lang };
736*4887Schin #endif /* _hdr_locale */
737*4887Schin 
738*4887Schin /*
739*4887Schin  * This function will get called whenever a configuration parameter changes
740*4887Schin  */
741*4887Schin static int newconf(const char *name, const char *path, const char *value)
742*4887Schin {
743*4887Schin 	register char *arg;
744*4887Schin 	if(!name)
745*4887Schin 		setenviron(value);
746*4887Schin 	else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
747*4887Schin 	{
748*4887Schin 		sh.universe = 0;
749*4887Schin 		/* set directory in new universe */
750*4887Schin 		if(*(arg = path_pwd(0))=='/')
751*4887Schin 			chdir(arg);
752*4887Schin 		/* clear out old tracked alias */
753*4887Schin 		stakseek(0);
754*4887Schin 		stakputs(nv_getval(PATHNOD));
755*4887Schin 		stakputc(0);
756*4887Schin 		nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
757*4887Schin 	}
758*4887Schin 	return(1);
759*4887Schin }
760*4887Schin 
761*4887Schin #if	(CC_NATIVE != CC_ASCII)
762*4887Schin     static void a2e(char *d, const char *s)
763*4887Schin     {
764*4887Schin 	register const unsigned char *t;
765*4887Schin 	register int i;
766*4887Schin 	t = CCMAP(CC_ASCII, CC_NATIVE);
767*4887Schin 	for(i=0; i<(1<<CHAR_BIT); i++)
768*4887Schin 		d[t[i]] = s[i];
769*4887Schin     }
770*4887Schin 
771*4887Schin     static void init_ebcdic(void)
772*4887Schin     {
773*4887Schin 	int i;
774*4887Schin 	char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT));
775*4887Schin 	for(i=0; i < ST_NONE; i++)
776*4887Schin 	{
777*4887Schin 		a2e(cp,sh_lexrstates[i]);
778*4887Schin 		sh_lexstates[i] = cp;
779*4887Schin 		cp += (1<<CHAR_BIT);
780*4887Schin 	}
781*4887Schin     }
782*4887Schin #endif
783*4887Schin 
784*4887Schin /*
785*4887Schin  * return SH_TYPE_* bitmask for path
786*4887Schin  * 0 for "not a shell"
787*4887Schin  */
788*4887Schin int sh_type(register const char *path)
789*4887Schin {
790*4887Schin 	register const char*	s;
791*4887Schin 	register int		t = 0;
792*4887Schin 
793*4887Schin 	if (s = (const char*)strrchr(path, '/'))
794*4887Schin 	{
795*4887Schin 		if (*path == '-')
796*4887Schin 			t |= SH_TYPE_LOGIN;
797*4887Schin 		s++;
798*4887Schin 	}
799*4887Schin 	else
800*4887Schin 		s = path;
801*4887Schin 	if (*s == '-')
802*4887Schin 	{
803*4887Schin 		s++;
804*4887Schin 		t |= SH_TYPE_LOGIN;
805*4887Schin 	}
806*4887Schin 	for (;;)
807*4887Schin 	{
808*4887Schin 		if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH)))
809*4887Schin 		{
810*4887Schin 			if (*s == 'k')
811*4887Schin 			{
812*4887Schin 				s++;
813*4887Schin 				t |= SH_TYPE_KSH;
814*4887Schin 				continue;
815*4887Schin 			}
816*4887Schin #if SHOPT_BASH
817*4887Schin 			if (*s == 'b' && *(s+1) == 'a')
818*4887Schin 			{
819*4887Schin 				s += 2;
820*4887Schin 				t |= SH_TYPE_BASH;
821*4887Schin 				continue;
822*4887Schin 			}
823*4887Schin #endif
824*4887Schin 		}
825*4887Schin 		if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED)))
826*4887Schin 		{
827*4887Schin #if SHOPT_PFSH
828*4887Schin 			if (*s == 'p' && *(s+1) == 'f')
829*4887Schin 			{
830*4887Schin 				s += 2;
831*4887Schin 				t |= SH_TYPE_PROFILE;
832*4887Schin 				continue;
833*4887Schin 			}
834*4887Schin #endif
835*4887Schin 			if (*s == 'r')
836*4887Schin 			{
837*4887Schin 				s++;
838*4887Schin 				t |= SH_TYPE_RESTRICTED;
839*4887Schin 				continue;
840*4887Schin 			}
841*4887Schin 		}
842*4887Schin 		break;
843*4887Schin 	}
844*4887Schin 	if (*s++ != 's' || *s++ != 'h')
845*4887Schin 		return 0;
846*4887Schin 	t |= SH_TYPE_SH;
847*4887Schin 	if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3')
848*4887Schin 		s += 2;
849*4887Schin #if _WINIX
850*4887Schin 	if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e')
851*4887Schin 		s += 4;
852*4887Schin #endif
853*4887Schin 	if (*s)
854*4887Schin 		t &= ~(SH_TYPE_PROFILE|SH_TYPE_RESTRICTED);
855*4887Schin 	return t;
856*4887Schin }
857*4887Schin 
858*4887Schin /*
859*4887Schin  * initialize the shell
860*4887Schin  */
861*4887Schin Shell_t *sh_init(register int argc,register char *argv[], void(*userinit)(int))
862*4887Schin {
863*4887Schin 	register int n;
864*4887Schin 	int type;
865*4887Schin 	static char *login_files[3];
866*4887Schin 	n = strlen(e_version);
867*4887Schin 	if(e_version[n-1]=='$' && e_version[n-2]==' ')
868*4887Schin 		e_version[n-2]=0;
869*4887Schin #if	(CC_NATIVE == CC_ASCII)
870*4887Schin 	memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
871*4887Schin #else
872*4887Schin 	init_ebcdic();
873*4887Schin #endif
874*4887Schin 	umask(umask(0));
875*4887Schin 	sh.mac_context = sh_macopen(&sh);
876*4887Schin 	sh.arg_context = sh_argopen(&sh);
877*4887Schin 	sh.lex_context = (void*)sh_lexopen(0,&sh,1);
878*4887Schin 	sh.ed_context = (void*)ed_open(&sh);
879*4887Schin 	sh.strbuf = sfstropen();
880*4887Schin 	sfsetbuf(sh.strbuf,(char*)0,64);
881*4887Schin 	sh_onstate(SH_INIT);
882*4887Schin 	error_info.exit = sh_exit;
883*4887Schin 	error_info.id = path_basename(argv[0]);
884*4887Schin #if ERROR_VERSION >= 20000102L
885*4887Schin 	error_info.catalog = e_dict;
886*4887Schin #endif
887*4887Schin 	sh.cpipe[0] = -1;
888*4887Schin 	sh.coutpipe = -1;
889*4887Schin 	sh.userid=getuid();
890*4887Schin 	sh.euserid=geteuid();
891*4887Schin 	sh.groupid=getgid();
892*4887Schin 	sh.egroupid=getegid();
893*4887Schin 	for(n=0;n < 10; n++)
894*4887Schin 	{
895*4887Schin 		/* don't use lower bits when rand() generates large numbers */
896*4887Schin 		if(rand() > RANDMASK)
897*4887Schin 		{
898*4887Schin 			rand_shift = 3;
899*4887Schin 			break;
900*4887Schin 		}
901*4887Schin 	}
902*4887Schin 	sh.lim.clk_tck = getconf("CLK_TCK");
903*4887Schin 	sh.lim.arg_max = getconf("ARG_MAX");
904*4887Schin 	sh.lim.open_max = getconf("OPEN_MAX");
905*4887Schin 	sh.lim.child_max = getconf("CHILD_MAX");
906*4887Schin 	sh.lim.ngroups_max = getconf("NGROUPS_MAX");
907*4887Schin 	sh.lim.posix_version = getconf("VERSION");
908*4887Schin 	sh.lim.posix_jobcontrol = getconf("JOB_CONTROL");
909*4887Schin 	if(sh.lim.arg_max <=0)
910*4887Schin 		sh.lim.arg_max = ARG_MAX;
911*4887Schin 	if(sh.lim.child_max <=0)
912*4887Schin 		sh.lim.child_max = CHILD_MAX;
913*4887Schin 	if(sh.lim.open_max <0)
914*4887Schin 		sh.lim.open_max = OPEN_MAX;
915*4887Schin 	if(sh.lim.open_max > (SHRT_MAX-2))
916*4887Schin 		sh.lim.open_max = SHRT_MAX-2;
917*4887Schin 	if(sh.lim.clk_tck <=0)
918*4887Schin 		sh.lim.clk_tck = CLK_TCK;
919*4887Schin #if SHOPT_FS_3D
920*4887Schin 	if(fs3d(FS3D_TEST))
921*4887Schin 		sh.lim.fs3d = 1;
922*4887Schin #endif /* SHOPT_FS_3D */
923*4887Schin 	sh_ioinit();
924*4887Schin 	/* initialize signal handling */
925*4887Schin 	sh_siginit();
926*4887Schin 	stakinstall(NIL(Stak_t*),nospace);
927*4887Schin 	/* set up memory for name-value pairs */
928*4887Schin 	sh.init_context =  nv_init(&sh);
929*4887Schin 	/* read the environment */
930*4887Schin 	if(argc>0)
931*4887Schin 	{
932*4887Schin 		type = sh_type(*argv);
933*4887Schin 		if(type&SH_TYPE_LOGIN)
934*4887Schin 			sh.login_sh = 2;
935*4887Schin 	}
936*4887Schin 	env_init(&sh);
937*4887Schin #if SHOPT_SPAWN
938*4887Schin 	{
939*4887Schin 		/*
940*4887Schin 		 * try to find the pathname for this interpreter
941*4887Schin 		 * try using environment variable _ or argv[0]
942*4887Schin 		 */
943*4887Schin 		char *last, *cp=nv_getval(L_ARGNOD);
944*4887Schin 		char buff[PATH_MAX+1];
945*4887Schin 		sh.shpath = 0;
946*4887Schin 		sfprintf(sh.strbuf,"/proc/%d/exe",getpid());
947*4887Schin 		if((n=readlink(sfstruse(sh.strbuf),buff,sizeof(buff)-1))>0)
948*4887Schin 		{
949*4887Schin 			buff[n] = 0;
950*4887Schin 			sh.shpath = strdup(buff);
951*4887Schin 		}
952*4887Schin 		else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
953*4887Schin 		{
954*4887Schin 			if(*cp=='/')
955*4887Schin 				sh.shpath = strdup(cp);
956*4887Schin 			else if(cp = nv_getval(PWDNOD))
957*4887Schin 			{
958*4887Schin 				int offset = staktell();
959*4887Schin 				stakputs(cp);
960*4887Schin 				stakputc('/');
961*4887Schin 				stakputs(argv[0]);
962*4887Schin 				pathcanon(stakptr(offset),PATH_DOTDOT);
963*4887Schin 				sh.shpath = strdup(stakptr(offset));
964*4887Schin 				stakseek(offset);
965*4887Schin 			}
966*4887Schin 		}
967*4887Schin 	}
968*4887Schin #endif
969*4887Schin 	nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
970*4887Schin #if SHOPT_FS_3D
971*4887Schin 	nv_stack(VPATHNOD, &VPATH_init);
972*4887Schin #endif /* SHOPT_FS_3D */
973*4887Schin 	astconfdisc(newconf);
974*4887Schin #if SHOPT_TIMEOUT
975*4887Schin 	sh.st.tmout = SHOPT_TIMEOUT;
976*4887Schin #endif /* SHOPT_TIMEOUT */
977*4887Schin 	/* initialize jobs table */
978*4887Schin 	job_clear();
979*4887Schin 	if(argc>0)
980*4887Schin 	{
981*4887Schin 		/* check for restricted shell */
982*4887Schin 		if(type&SH_TYPE_RESTRICTED)
983*4887Schin 			sh_onoption(SH_RESTRICTED);
984*4887Schin #if SHOPT_PFSH
985*4887Schin 		/* check for profile shell */
986*4887Schin 		else if(type&SH_TYPE_PROFILE)
987*4887Schin 			sh_onoption(SH_PFSH);
988*4887Schin #endif
989*4887Schin #if SHOPT_BASH
990*4887Schin 		/* check for invocation as bash */
991*4887Schin 		if(type&SH_TYPE_BASH)
992*4887Schin 		{
993*4887Schin 		        sh.userinit = userinit = bash_init;
994*4887Schin 			sh_onoption(SH_BASH);
995*4887Schin 			sh_onstate(SH_PREINIT);
996*4887Schin 			(*userinit)(0);
997*4887Schin 			sh_offstate(SH_PREINIT);
998*4887Schin 		}
999*4887Schin #endif
1000*4887Schin 		/* look for options */
1001*4887Schin 		/* sh.st.dolc is $#	*/
1002*4887Schin 		if((sh.st.dolc = sh_argopts(-argc,argv)) < 0)
1003*4887Schin 		{
1004*4887Schin 			sh.exitval = 2;
1005*4887Schin 			sh_done(0);
1006*4887Schin 		}
1007*4887Schin 		opt_info.disc = 0;
1008*4887Schin 		sh.st.dolv=argv+(argc-1)-sh.st.dolc;
1009*4887Schin 		sh.st.dolv[0] = argv[0];
1010*4887Schin 		if(sh.st.dolc < 1)
1011*4887Schin 			sh_onoption(SH_SFLAG);
1012*4887Schin 		if(!sh_isoption(SH_SFLAG))
1013*4887Schin 		{
1014*4887Schin 			sh.st.dolc--;
1015*4887Schin 			sh.st.dolv++;
1016*4887Schin #if _WINIX
1017*4887Schin 			{
1018*4887Schin 				char*	name;
1019*4887Schin 				name = sh.st.dolv[0];
1020*4887Schin 				if(name[1]==':' && (name[2]=='/' || name[2]=='\\'))
1021*4887Schin 				{
1022*4887Schin #if _lib_pathposix
1023*4887Schin 					char*	p;
1024*4887Schin 
1025*4887Schin 					if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n)))
1026*4887Schin 					{
1027*4887Schin 						pathposix(name, p, n);
1028*4887Schin 						name = p;
1029*4887Schin 					}
1030*4887Schin 					else
1031*4887Schin #endif
1032*4887Schin 					{
1033*4887Schin 						name[1] = name[0];
1034*4887Schin 						name[0] = name[2] = '/';
1035*4887Schin 					}
1036*4887Schin 				}
1037*4887Schin 			}
1038*4887Schin #endif /* _WINIX */
1039*4887Schin 		}
1040*4887Schin 	}
1041*4887Schin #if SHOPT_PFSH
1042*4887Schin 	if (sh_isoption(SH_PFSH))
1043*4887Schin 	{
1044*4887Schin 		struct passwd *pw = getpwuid(sh.userid);
1045*4887Schin 		if(pw)
1046*4887Schin 			sh.user = strdup(pw->pw_name);
1047*4887Schin 
1048*4887Schin 	}
1049*4887Schin #endif
1050*4887Schin 	/* set[ug]id scripts require the -p flag */
1051*4887Schin 	if(sh.userid!=sh.euserid || sh.groupid!=sh.egroupid)
1052*4887Schin 	{
1053*4887Schin #if SHOPT_P_SUID
1054*4887Schin 		/* require sh -p to run setuid and/or setgid */
1055*4887Schin 		if(!sh_isoption(SH_PRIVILEGED) && sh.euserid < SHOPT_P_SUID)
1056*4887Schin 		{
1057*4887Schin 			setuid(sh.euserid=sh.userid);
1058*4887Schin 			setgid(sh.egroupid=sh.groupid);
1059*4887Schin 		}
1060*4887Schin 		else
1061*4887Schin #else
1062*4887Schin 			sh_onoption(SH_PRIVILEGED);
1063*4887Schin #endif /* SHOPT_P_SUID */
1064*4887Schin #ifdef SHELLMAGIC
1065*4887Schin 		/* careful of #! setuid scripts with name beginning with - */
1066*4887Schin 		if(sh.login_sh && argv[1] && strcmp(argv[0],argv[1])==0)
1067*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_prohibited);
1068*4887Schin #endif /*SHELLMAGIC*/
1069*4887Schin 	}
1070*4887Schin 	else
1071*4887Schin 		sh_offoption(SH_PRIVILEGED);
1072*4887Schin 	/* shname for $0 in profiles and . scripts */
1073*4887Schin 	if(strmatch(argv[1],e_devfdNN))
1074*4887Schin 		sh.shname = strdup(argv[0]);
1075*4887Schin 	else
1076*4887Schin 		sh.shname = strdup(sh.st.dolv[0]);
1077*4887Schin 	/*
1078*4887Schin 	 * return here for shell script execution
1079*4887Schin 	 * but not for parenthesis subshells
1080*4887Schin 	 */
1081*4887Schin 	error_info.id = strdup(sh.st.dolv[0]); /* error_info.id is $0 */
1082*4887Schin 	sh.jmpbuffer = (void*)&sh.checkbase;
1083*4887Schin 	sh_pushcontext(&sh.checkbase,SH_JMPSCRIPT);
1084*4887Schin 	sh.st.self = &sh.global;
1085*4887Schin         sh.topscope = (Shscope_t*)sh.st.self;
1086*4887Schin 	sh_offstate(SH_INIT);
1087*4887Schin 	login_files[0] = (char*)e_profile;
1088*4887Schin 	login_files[1] = ".profile";
1089*4887Schin 	sh.login_files = login_files;
1090*4887Schin 	if(sh.userinit=userinit)
1091*4887Schin 		(*userinit)(0);
1092*4887Schin 	return(&sh);
1093*4887Schin }
1094*4887Schin 
1095*4887Schin Shell_t *sh_getinterp(void)
1096*4887Schin {
1097*4887Schin 	return(&sh);
1098*4887Schin }
1099*4887Schin 
1100*4887Schin /*
1101*4887Schin  * reinitialize before executing a script
1102*4887Schin  */
1103*4887Schin int sh_reinit(char *argv[])
1104*4887Schin {
1105*4887Schin 	Shopt_t opt;
1106*4887Schin 	dtclear(sh.fun_tree);
1107*4887Schin 	dtclose(sh.alias_tree);
1108*4887Schin 	sh.alias_tree = inittree(&sh,shtab_aliases);
1109*4887Schin 	sh.namespace = 0;
1110*4887Schin 	sh.inuse_bits = 0;
1111*4887Schin 	if(sh.userinit)
1112*4887Schin 		(*sh.userinit)(1);
1113*4887Schin 	if(sh.heredocs)
1114*4887Schin 	{
1115*4887Schin 		sfclose(sh.heredocs);
1116*4887Schin 		sh.heredocs = 0;
1117*4887Schin 	}
1118*4887Schin 	/* remove locals */
1119*4887Schin 	sh_onstate(SH_INIT);
1120*4887Schin 	nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_EXPORT,0);
1121*4887Schin 	nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_ARRAY,NV_ARRAY);
1122*4887Schin 	sh_offstate(SH_INIT);
1123*4887Schin 	memset(sh.st.trapcom,0,(sh.st.trapmax+1)*sizeof(char*));
1124*4887Schin 	memset((void*)&opt,0,sizeof(opt));
1125*4887Schin 	if(sh_isoption(SH_TRACKALL))
1126*4887Schin 		on_option(&opt,SH_TRACKALL);
1127*4887Schin 	if(sh_isoption(SH_EMACS))
1128*4887Schin 		on_option(&opt,SH_EMACS);
1129*4887Schin 	if(sh_isoption(SH_GMACS))
1130*4887Schin 		on_option(&opt,SH_GMACS);
1131*4887Schin 	if(sh_isoption(SH_VI))
1132*4887Schin 		on_option(&opt,SH_VI);
1133*4887Schin 	if(sh_isoption(SH_VIRAW))
1134*4887Schin 		on_option(&opt,SH_VIRAW);
1135*4887Schin 	sh.options = opt;
1136*4887Schin 	/* set up new args */
1137*4887Schin 	if(argv)
1138*4887Schin 		sh.arglist = sh_argcreate(argv);
1139*4887Schin 	if(sh.arglist)
1140*4887Schin 		sh_argreset(sh.arglist,NIL(struct dolnod*));
1141*4887Schin 	sh.envlist=0;
1142*4887Schin 	sh.curenv = 0;
1143*4887Schin 	sh.shname = error_info.id = strdup(sh.st.dolv[0]);
1144*4887Schin 	sh_offstate(SH_FORKED);
1145*4887Schin 	sh.fn_depth = sh.dot_depth = 0;
1146*4887Schin 	sh_sigreset(0);
1147*4887Schin 	return(1);
1148*4887Schin }
1149*4887Schin 
1150*4887Schin /*
1151*4887Schin  * set when creating a local variable of this name
1152*4887Schin  */
1153*4887Schin Namfun_t *nv_cover(register Namval_t *np)
1154*4887Schin {
1155*4887Schin #ifdef PATH_BFPATH
1156*4887Schin 	if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS)
1157*4887Schin #else
1158*4887Schin 	if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==SECONDS)
1159*4887Schin #endif
1160*4887Schin 		return(np->nvfun);
1161*4887Schin #ifdef _hdr_locale
1162*4887Schin 	if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD)
1163*4887Schin 		return(np->nvfun);
1164*4887Schin #endif
1165*4887Schin 	 return(0);
1166*4887Schin }
1167*4887Schin 
1168*4887Schin static Namtype_t typeset;
1169*4887Schin static const char *shdiscnames[] = { "tilde", 0};
1170*4887Schin 
1171*4887Schin /*
1172*4887Schin  * Initialize the shell name and alias table
1173*4887Schin  */
1174*4887Schin static Init_t *nv_init(Shell_t *shp)
1175*4887Schin {
1176*4887Schin 	Namval_t *np;
1177*4887Schin 	register Init_t *ip;
1178*4887Schin 	double d=0;
1179*4887Schin 	ip = newof(0,Init_t,1,0);
1180*4887Schin 	if(!ip)
1181*4887Schin 		return(0);
1182*4887Schin 	ip->sh = shp;
1183*4887Schin 	shp->var_base = shp->var_tree = inittree(shp,shtab_variables);
1184*4887Schin 	ip->IFS_init.hdr.disc = &IFS_disc;
1185*4887Schin 	ip->IFS_init.hdr.nofree = 1;
1186*4887Schin 	ip->IFS_init.sh = shp;
1187*4887Schin 	ip->PATH_init.hdr.disc = &RESTRICTED_disc;
1188*4887Schin 	ip->PATH_init.hdr.nofree = 1;
1189*4887Schin 	ip->PATH_init.sh = shp;
1190*4887Schin #ifdef PATH_BFPATH
1191*4887Schin 	ip->FPATH_init.hdr.disc = &RESTRICTED_disc;
1192*4887Schin 	ip->FPATH_init.hdr.nofree = 1;
1193*4887Schin 	ip->FPATH_init.sh = shp;
1194*4887Schin 	ip->CDPATH_init.hdr.disc = &CDPATH_disc;
1195*4887Schin 	ip->CDPATH_init.hdr.nofree = 1;
1196*4887Schin 	ip->CDPATH_init.sh = shp;
1197*4887Schin #endif
1198*4887Schin 	ip->SHELL_init.hdr.disc = &RESTRICTED_disc;
1199*4887Schin 	ip->SHELL_init.sh = shp;
1200*4887Schin 	ip->SHELL_init.hdr.nofree = 1;
1201*4887Schin 	ip->ENV_init.hdr.disc = &RESTRICTED_disc;
1202*4887Schin 	ip->ENV_init.hdr.nofree = 1;
1203*4887Schin 	ip->ENV_init.sh = shp;
1204*4887Schin 	ip->VISUAL_init.hdr.disc = &EDITOR_disc;
1205*4887Schin 	ip->VISUAL_init.hdr.nofree = 1;
1206*4887Schin 	ip->VISUAL_init.sh = shp;
1207*4887Schin 	ip->EDITOR_init.hdr.disc = &EDITOR_disc;
1208*4887Schin 	ip->EDITOR_init.hdr.nofree = 1;
1209*4887Schin 	ip->EDITOR_init.sh = shp;
1210*4887Schin 	ip->OPTINDEX_init.hdr.disc = &OPTINDEX_disc;
1211*4887Schin 	ip->OPTINDEX_init.hdr.nofree = 1;
1212*4887Schin 	ip->OPTINDEX_init.sh = shp;
1213*4887Schin 	ip->SECONDS_init.hdr.disc = &SECONDS_disc;
1214*4887Schin 	ip->SECONDS_init.hdr.nofree = 1;
1215*4887Schin 	ip->SECONDS_init.sh = shp;
1216*4887Schin 	ip->RAND_init.hdr.disc = &RAND_disc;
1217*4887Schin 	ip->RAND_init.hdr.nofree = 1;
1218*4887Schin 	ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc;
1219*4887Schin 	ip->SH_MATCH_init.hdr.nofree = 1;
1220*4887Schin 	ip->LINENO_init.hdr.disc = &LINENO_disc;
1221*4887Schin 	ip->LINENO_init.hdr.nofree = 1;
1222*4887Schin 	ip->LINENO_init.sh = shp;
1223*4887Schin 	ip->L_ARG_init.hdr.disc = &L_ARG_disc;
1224*4887Schin 	ip->L_ARG_init.hdr.nofree = 1;
1225*4887Schin #ifdef _hdr_locale
1226*4887Schin 	ip->LC_TYPE_init.hdr.disc = &LC_disc;
1227*4887Schin 	ip->LC_TYPE_init.hdr.nofree = 1;
1228*4887Schin 	ip->LC_NUM_init.hdr.disc = &LC_disc;
1229*4887Schin 	ip->LC_NUM_init.hdr.nofree = 1;
1230*4887Schin 	ip->LC_COLL_init.hdr.disc = &LC_disc;
1231*4887Schin 	ip->LC_COLL_init.hdr.nofree = 1;
1232*4887Schin 	ip->LC_MSG_init.hdr.disc = &LC_disc;
1233*4887Schin 	ip->LC_MSG_init.hdr.nofree = 1;
1234*4887Schin 	ip->LC_ALL_init.hdr.disc = &LC_disc;
1235*4887Schin 	ip->LC_ALL_init.hdr.nofree = 1;
1236*4887Schin 	ip->LANG_init.hdr.disc = &LC_disc;
1237*4887Schin 	ip->LANG_init.hdr.nofree = 1;
1238*4887Schin 	ip->LC_TYPE_init.sh = shp;
1239*4887Schin 	ip->LC_NUM_init.sh = shp;
1240*4887Schin 	ip->LC_COLL_init.sh = shp;
1241*4887Schin 	ip->LC_MSG_init.sh = shp;
1242*4887Schin 	ip->LANG_init.sh = shp;
1243*4887Schin #endif /* _hdr_locale */
1244*4887Schin 	nv_stack(IFSNOD, &ip->IFS_init.hdr);
1245*4887Schin 	nv_stack(PATHNOD, &ip->PATH_init.hdr);
1246*4887Schin #ifdef PATH_BFPATH
1247*4887Schin 	nv_stack(FPATHNOD, &ip->FPATH_init.hdr);
1248*4887Schin 	nv_stack(CDPNOD, &ip->CDPATH_init.hdr);
1249*4887Schin #endif
1250*4887Schin 	nv_stack(SHELLNOD, &ip->SHELL_init.hdr);
1251*4887Schin 	nv_stack(ENVNOD, &ip->ENV_init.hdr);
1252*4887Schin 	nv_stack(VISINOD, &ip->VISUAL_init.hdr);
1253*4887Schin 	nv_stack(EDITNOD, &ip->EDITOR_init.hdr);
1254*4887Schin 	nv_stack(OPTINDNOD, &ip->OPTINDEX_init.hdr);
1255*4887Schin 	nv_stack(SECONDS, &ip->SECONDS_init.hdr);
1256*4887Schin 	nv_stack(L_ARGNOD, &ip->L_ARG_init.hdr);
1257*4887Schin 	nv_putval(SECONDS, (char*)&d, NV_INTEGER|NV_DOUBLE);
1258*4887Schin 	nv_stack(RANDNOD, &ip->RAND_init.hdr);
1259*4887Schin 	d = (shp->pid&RANDMASK);
1260*4887Schin 	nv_putval(RANDNOD, (char*)&d, NV_INTEGER|NV_DOUBLE);
1261*4887Schin 	nv_stack(LINENO, &ip->LINENO_init.hdr);
1262*4887Schin 	nv_putsub(SH_MATCHNOD,(char*)0,10);
1263*4887Schin 	nv_onattr(SH_MATCHNOD,NV_RDONLY);
1264*4887Schin 	nv_stack(SH_MATCHNOD, &ip->SH_MATCH_init.hdr);
1265*4887Schin #ifdef _hdr_locale
1266*4887Schin 	nv_stack(LCTYPENOD, &ip->LC_TYPE_init.hdr);
1267*4887Schin 	nv_stack(LCALLNOD, &ip->LC_ALL_init.hdr);
1268*4887Schin 	nv_stack(LCMSGNOD, &ip->LC_MSG_init.hdr);
1269*4887Schin 	nv_stack(LCCOLLNOD, &ip->LC_COLL_init.hdr);
1270*4887Schin 	nv_stack(LCNUMNOD, &ip->LC_NUM_init.hdr);
1271*4887Schin 	nv_stack(LANGNOD, &ip->LANG_init.hdr);
1272*4887Schin #endif /* _hdr_locale */
1273*4887Schin 	(PPIDNOD)->nvalue.lp = (&shp->ppid);
1274*4887Schin 	(TMOUTNOD)->nvalue.lp = (&shp->st.tmout);
1275*4887Schin 	(MCHKNOD)->nvalue.lp = (&sh_mailchk);
1276*4887Schin 	(OPTINDNOD)->nvalue.lp = (&shp->st.optindex);
1277*4887Schin 	/* set up the seconds clock */
1278*4887Schin 	shp->alias_tree = inittree(shp,shtab_aliases);
1279*4887Schin 	shp->track_tree = dtopen(&_Nvdisc,Dtset);
1280*4887Schin 	shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins);
1281*4887Schin 	typeset.shp = shp;
1282*4887Schin 	typeset.optstring = sh_opttypeset;
1283*4887Schin 	nv_search("typeset",shp->bltin_tree,0)->nvfun = (void*)&typeset;
1284*4887Schin #if SHOPT_BASH
1285*4887Schin 	nv_search("local",shp->bltin_tree,0)->nvfun = (void*)&typeset;
1286*4887Schin #endif
1287*4887Schin 	shp->fun_tree = dtopen(&_Nvdisc,Dtoset);
1288*4887Schin 	dtview(shp->fun_tree,shp->bltin_tree);
1289*4887Schin #if SHOPT_NAMESPACE
1290*4887Schin 	if(np = nv_mount(DOTSHNOD, "global", shp->var_tree))
1291*4887Schin 		nv_onattr(np,NV_RDONLY);
1292*4887Schin 	np = nv_search("namespace",nv_dict(DOTSHNOD),NV_ADD);
1293*4887Schin 	nv_putval(np,".sh.global",NV_RDONLY|NV_NOFREE);
1294*4887Schin 	nv_stack(np, &NSPACE_init);
1295*4887Schin #endif /* SHOPT_NAMESPACE */
1296*4887Schin 	np = nv_mount(DOTSHNOD, "type", dtopen(&_Nvdisc,Dtoset));
1297*4887Schin 	nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0);
1298*4887Schin 	return(ip);
1299*4887Schin }
1300*4887Schin 
1301*4887Schin /*
1302*4887Schin  * initialize name-value pairs
1303*4887Schin  */
1304*4887Schin 
1305*4887Schin static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
1306*4887Schin {
1307*4887Schin 	register Namval_t *np;
1308*4887Schin 	register const struct shtable2 *tp;
1309*4887Schin 	register unsigned n = 0;
1310*4887Schin 	register Dt_t *treep;
1311*4887Schin 	Dt_t *base_treep, *dict;
1312*4887Schin 	for(tp=name_vals;*tp->sh_name;tp++)
1313*4887Schin 		n++;
1314*4887Schin 	np = (Namval_t*)calloc(n,sizeof(Namval_t));
1315*4887Schin 	if(!shp->bltin_nodes)
1316*4887Schin 		shp->bltin_nodes = np;
1317*4887Schin 	else if(name_vals==(const struct shtable2*)shtab_builtins)
1318*4887Schin 		shp->bltin_cmds = np;
1319*4887Schin 	base_treep = treep = dtopen(&_Nvdisc,Dtoset);
1320*4887Schin 	for(tp=name_vals;*tp->sh_name;tp++,np++)
1321*4887Schin 	{
1322*4887Schin 		if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name))
1323*4887Schin 			np->nvname++;
1324*4887Schin 		else
1325*4887Schin 		{
1326*4887Schin 			np->nvname = (char*)tp->sh_name;
1327*4887Schin 			treep = base_treep;
1328*4887Schin 		}
1329*4887Schin 		np->nvenv = 0;
1330*4887Schin 		if(name_vals==(const struct shtable2*)shtab_builtins)
1331*4887Schin 			np->nvalue.bfp = ((struct shtable3*)tp)->sh_value;
1332*4887Schin 		else
1333*4887Schin 			np->nvalue.cp = (char*)tp->sh_value;
1334*4887Schin 		nv_setattr(np,tp->sh_number);
1335*4887Schin 		if(nv_istable(np))
1336*4887Schin 			nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset));
1337*4887Schin 		if(nv_isattr(np,NV_INTEGER))
1338*4887Schin 			nv_setsize(np,10);
1339*4887Schin 		else
1340*4887Schin 			nv_setsize(np,0);
1341*4887Schin 		dtinsert(treep,np);
1342*4887Schin 		if(nv_istable(np))
1343*4887Schin 			treep = dict;
1344*4887Schin 	}
1345*4887Schin 	return(treep);
1346*4887Schin }
1347*4887Schin 
1348*4887Schin /*
1349*4887Schin  * read in the process environment and set up name-value pairs
1350*4887Schin  * skip over items that are not name-value pairs
1351*4887Schin  */
1352*4887Schin 
1353*4887Schin static void env_init(Shell_t *shp)
1354*4887Schin {
1355*4887Schin 	register char *cp;
1356*4887Schin 	register Namval_t	*np;
1357*4887Schin 	register char **ep=environ;
1358*4887Schin 	register char *next=0;
1359*4887Schin #ifdef _ENV_H
1360*4887Schin 	shp->env = env_open(environ,3);
1361*4887Schin 	env_delete(shp->env,"_");
1362*4887Schin #endif
1363*4887Schin 	if(ep)
1364*4887Schin 	{
1365*4887Schin 		while(cp= *ep++)
1366*4887Schin 		{
1367*4887Schin 			if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=')
1368*4887Schin 				next = cp+4;
1369*4887Schin 			else if(np=nv_open(cp,shp->var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN|NV_NOFAIL)))
1370*4887Schin 			{
1371*4887Schin 				nv_onattr(np,NV_IMPORT);
1372*4887Schin 				np->nvenv = cp;
1373*4887Schin 				nv_close(np);
1374*4887Schin 			}
1375*4887Schin 		}
1376*4887Schin 		while(cp=next)
1377*4887Schin 		{
1378*4887Schin 			if(next = strchr(++cp,'='))
1379*4887Schin 				*next = 0;
1380*4887Schin 			np = nv_search(cp+2,shp->var_tree,NV_ADD);
1381*4887Schin 			if(nv_isattr(np,NV_IMPORT|NV_EXPORT))
1382*4887Schin 			{
1383*4887Schin 				int flag = *(unsigned char*)cp-' ';
1384*4887Schin 				int size = *(unsigned char*)(cp+1)-' ';
1385*4887Schin 				if((flag&NV_INTEGER) && size==0)
1386*4887Schin 				{
1387*4887Schin 					/* check for floating*/
1388*4887Schin 					char *ep,*val = nv_getval(np);
1389*4887Schin 					strtol(val,&ep,10);
1390*4887Schin 					if(*ep=='.' || *ep=='e' || *ep=='E')
1391*4887Schin 					{
1392*4887Schin 						char *lp;
1393*4887Schin 						flag |= NV_DOUBLE;
1394*4887Schin 						if(*ep=='.')
1395*4887Schin 						{
1396*4887Schin 							strtol(ep+1,&lp,10);
1397*4887Schin 							if(*lp)
1398*4887Schin 								ep = lp;
1399*4887Schin 						}
1400*4887Schin 						if(*ep && *ep!='.')
1401*4887Schin 						{
1402*4887Schin 							flag |= NV_EXPNOTE;
1403*4887Schin 							size = ep-val;
1404*4887Schin 						}
1405*4887Schin 						else
1406*4887Schin 							size = strlen(ep);
1407*4887Schin 						size--;
1408*4887Schin 					}
1409*4887Schin 				}
1410*4887Schin 				nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
1411*4887Schin 			}
1412*4887Schin 		}
1413*4887Schin 	}
1414*4887Schin #ifdef _ENV_H
1415*4887Schin 	env_delete(sh.env,e_envmarker);
1416*4887Schin #endif
1417*4887Schin 	if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
1418*4887Schin 	{
1419*4887Schin 		nv_offattr(PWDNOD,NV_TAGGED);
1420*4887Schin 		path_pwd(0);
1421*4887Schin 	}
1422*4887Schin 	if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
1423*4887Schin 		sh_onoption(SH_RESTRICTED); /* restricted shell */
1424*4887Schin 	return;
1425*4887Schin }
1426*4887Schin 
1427*4887Schin /*
1428*4887Schin  * terminate shell and free up the space
1429*4887Schin  */
1430*4887Schin int sh_term(void)
1431*4887Schin {
1432*4887Schin 	sfdisc(sfstdin,SF_POPDISC);
1433*4887Schin 	free((char*)sh.outbuff);
1434*4887Schin 	stakset(NIL(char*),0);
1435*4887Schin 	return(0);
1436*4887Schin }
1437*4887Schin 
1438*4887Schin /* function versions of these */
1439*4887Schin 
1440*4887Schin #define DISABLE	/* proto workaround */
1441*4887Schin 
1442*4887Schin unsigned long sh_isoption DISABLE (int opt)
1443*4887Schin {
1444*4887Schin 	return(sh_isoption(opt));
1445*4887Schin }
1446*4887Schin 
1447*4887Schin unsigned long sh_onoption DISABLE (int opt)
1448*4887Schin {
1449*4887Schin 	return(sh_onoption(opt));
1450*4887Schin }
1451*4887Schin 
1452*4887Schin unsigned long sh_offoption DISABLE (int opt)
1453*4887Schin {
1454*4887Schin 	return(sh_offoption(opt));
1455*4887Schin }
1456*4887Schin 
1457*4887Schin void	sh_sigcheck DISABLE (void)
1458*4887Schin {
1459*4887Schin 	sh_sigcheck();
1460*4887Schin }
1461*4887Schin 
1462*4887Schin Dt_t*	sh_bltin_tree DISABLE (void)
1463*4887Schin {
1464*4887Schin 	return(sh.bltin_tree);
1465*4887Schin }
1466