14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1982-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  *
234887Schin  * Shell initialization
244887Schin  *
254887Schin  *   David Korn
264887Schin  *   AT&T Labs
274887Schin  *
284887Schin  */
294887Schin 
304887Schin #include        "defs.h"
314887Schin #include        <stak.h>
324887Schin #include        <ccode.h>
334887Schin #include        <pwd.h>
348462SApril.Chin@Sun.COM #include        <tmx.h>
354887Schin #include        "variables.h"
364887Schin #include        "path.h"
374887Schin #include        "fault.h"
384887Schin #include        "name.h"
394887Schin #include	"edit.h"
404887Schin #include	"jobs.h"
414887Schin #include	"io.h"
424887Schin #include	"shlex.h"
434887Schin #include	"builtins.h"
444887Schin #include	"FEATURE/time"
454887Schin #include	"FEATURE/dynamic"
46*10898Sroland.mainz@nrubsig.org #include	"FEATURE/externs"
474887Schin #include	"lexstates.h"
484887Schin #include	"version.h"
494887Schin 
508462SApril.Chin@Sun.COM char e_version[]	= "\n@(#)$Id: Version "
518462SApril.Chin@Sun.COM #if SHOPT_AUDIT
528462SApril.Chin@Sun.COM #define ATTRS		1
538462SApril.Chin@Sun.COM 			"A"
548462SApril.Chin@Sun.COM #endif
558462SApril.Chin@Sun.COM #if SHOPT_BASH
568462SApril.Chin@Sun.COM #define ATTRS		1
578462SApril.Chin@Sun.COM 			"B"
588462SApril.Chin@Sun.COM #endif
59*10898Sroland.mainz@nrubsig.org #if SHOPT_BGX
60*10898Sroland.mainz@nrubsig.org #define ATTRS		1
61*10898Sroland.mainz@nrubsig.org 			"J"
62*10898Sroland.mainz@nrubsig.org #endif
638462SApril.Chin@Sun.COM #if SHOPT_ACCT
648462SApril.Chin@Sun.COM #define ATTRS		1
658462SApril.Chin@Sun.COM 			"L"
668462SApril.Chin@Sun.COM #endif
674887Schin #if SHOPT_MULTIBYTE
688462SApril.Chin@Sun.COM #define ATTRS		1
698462SApril.Chin@Sun.COM 			"M"
708462SApril.Chin@Sun.COM #endif
718462SApril.Chin@Sun.COM #if SHOPT_PFSH && _hdr_exec_attr
728462SApril.Chin@Sun.COM #define ATTRS		1
738462SApril.Chin@Sun.COM 			"P"
748462SApril.Chin@Sun.COM #endif
75*10898Sroland.mainz@nrubsig.org #if SHOPT_REGRESS
76*10898Sroland.mainz@nrubsig.org #define ATTRS		1
77*10898Sroland.mainz@nrubsig.org 			"R"
78*10898Sroland.mainz@nrubsig.org #endif
798462SApril.Chin@Sun.COM #if ATTRS
808462SApril.Chin@Sun.COM 			" "
818462SApril.Chin@Sun.COM #endif
828462SApril.Chin@Sun.COM 			SH_RELEASE " $\0\n";
834887Schin 
844887Schin #if SHOPT_BASH
858462SApril.Chin@Sun.COM     extern void bash_init(Shell_t*,int);
864887Schin #endif
874887Schin 
884887Schin #define RANDMASK	0x7fff
898462SApril.Chin@Sun.COM 
908462SApril.Chin@Sun.COM #ifndef ARG_MAX
918462SApril.Chin@Sun.COM #   define ARG_MAX	(1*1024*1024)
928462SApril.Chin@Sun.COM #endif
938462SApril.Chin@Sun.COM #ifndef CHILD_MAX
948462SApril.Chin@Sun.COM #   define CHILD_MAX	(1*1024)
958462SApril.Chin@Sun.COM #endif
964887Schin #ifndef CLK_TCK
974887Schin #   define CLK_TCK	60
984887Schin #endif /* CLK_TCK */
994887Schin 
1004887Schin #ifndef environ
1014887Schin     extern char	**environ;
1024887Schin #endif
1034887Schin 
1044887Schin #undef	getconf
1054887Schin #define getconf(x)	strtol(astconf(x,NiL,NiL),NiL,0)
1064887Schin 
1074887Schin struct seconds
1084887Schin {
1094887Schin 	Namfun_t	hdr;
1104887Schin 	Shell_t		*sh;
1114887Schin };
1124887Schin 
1134887Schin struct rand
1144887Schin {
1154887Schin 	Namfun_t	hdr;
1164887Schin 	int32_t		rand_last;
1174887Schin };
1184887Schin 
1194887Schin struct ifs
1204887Schin {
1214887Schin 	Namfun_t	hdr;
1224887Schin 	Namval_t	*ifsnp;
1234887Schin };
1244887Schin 
1254887Schin struct match
1264887Schin {
1274887Schin 	Namfun_t	hdr;
1284887Schin 	char		*val;
1294887Schin 	char		*rval;
1304887Schin 	int		vsize;
1314887Schin 	int		nmatch;
1324887Schin 	int		lastsub;
1334887Schin 	int		match[2*(MATCH_MAX+1)];
1344887Schin };
1354887Schin 
1364887Schin typedef struct _init_
1374887Schin {
1384887Schin 	Shell_t		*sh;
1394887Schin #if SHOPT_FS_3D
1404887Schin 	Namfun_t	VPATH_init;
1414887Schin #endif /* SHOPT_FS_3D */
1424887Schin 	struct ifs	IFS_init;
1438462SApril.Chin@Sun.COM 	Namfun_t	PATH_init;
1448462SApril.Chin@Sun.COM 	Namfun_t	FPATH_init;
1458462SApril.Chin@Sun.COM 	Namfun_t	CDPATH_init;
1468462SApril.Chin@Sun.COM 	Namfun_t	SHELL_init;
1478462SApril.Chin@Sun.COM 	Namfun_t	ENV_init;
1488462SApril.Chin@Sun.COM 	Namfun_t	VISUAL_init;
1498462SApril.Chin@Sun.COM 	Namfun_t	EDITOR_init;
1508462SApril.Chin@Sun.COM 	Namfun_t	HISTFILE_init;
1518462SApril.Chin@Sun.COM 	Namfun_t	HISTSIZE_init;
1528462SApril.Chin@Sun.COM 	Namfun_t	OPTINDEX_init;
1534887Schin 	struct seconds	SECONDS_init;
1544887Schin 	struct rand	RAND_init;
1558462SApril.Chin@Sun.COM 	Namfun_t	LINENO_init;
1568462SApril.Chin@Sun.COM 	Namfun_t	L_ARG_init;
1578462SApril.Chin@Sun.COM 	Namfun_t	SH_VERSION_init;
1584887Schin 	struct match	SH_MATCH_init;
1594887Schin #ifdef _hdr_locale
1608462SApril.Chin@Sun.COM 	Namfun_t	LC_TYPE_init;
1618462SApril.Chin@Sun.COM 	Namfun_t	LC_NUM_init;
1628462SApril.Chin@Sun.COM 	Namfun_t	LC_COLL_init;
1638462SApril.Chin@Sun.COM 	Namfun_t	LC_MSG_init;
1648462SApril.Chin@Sun.COM 	Namfun_t	LC_ALL_init;
1658462SApril.Chin@Sun.COM 	Namfun_t	LANG_init;
1664887Schin #endif /* _hdr_locale */
1674887Schin } Init_t;
1684887Schin 
1698462SApril.Chin@Sun.COM static int		nbltins;
1704887Schin static void		env_init(Shell_t*);
1714887Schin static Init_t		*nv_init(Shell_t*);
1724887Schin static Dt_t		*inittree(Shell_t*,const struct shtable2*);
173*10898Sroland.mainz@nrubsig.org static int		shlvl;
1744887Schin 
1754887Schin #ifdef _WINIX
1764887Schin #   define EXE	"?(.exe)"
1774887Schin #else
1784887Schin #   define EXE
1794887Schin #endif
1804887Schin 
1814887Schin static int		rand_shift;
1824887Schin 
1834887Schin 
1844887Schin /*
1854887Schin  * Invalidate all path name bindings
1864887Schin  */
1874887Schin static void rehash(register Namval_t *np,void *data)
1884887Schin {
1894887Schin 	NOT_USED(data);
1904887Schin 	nv_onattr(np,NV_NOALIAS);
1914887Schin }
1924887Schin 
1934887Schin /*
1944887Schin  * out of memory routine for stak routines
1954887Schin  */
1964887Schin static char *nospace(int unused)
1974887Schin {
1984887Schin 	NOT_USED(unused);
1994887Schin 	errormsg(SH_DICT,ERROR_exit(3),e_nospace);
2004887Schin 	return(NIL(char*));
2014887Schin }
2024887Schin 
2034887Schin /* Trap for VISUAL and EDITOR variables */
2044887Schin static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
2054887Schin {
2064887Schin 	register const char *cp, *name=nv_name(np);
207*10898Sroland.mainz@nrubsig.org 	register int	newopt=0;
2088462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
2098462SApril.Chin@Sun.COM 	if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD)))
2104887Schin 		goto done;
2118462SApril.Chin@Sun.COM 	if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD)))))
2124887Schin 		goto done;
2134887Schin 	/* turn on vi or emacs option if editor name is either*/
2144887Schin 	cp = path_basename(cp);
2154887Schin 	if(strmatch(cp,"*[Vv][Ii]*"))
216*10898Sroland.mainz@nrubsig.org 		newopt=SH_VI;
2174887Schin 	else if(strmatch(cp,"*gmacs*"))
218*10898Sroland.mainz@nrubsig.org 		newopt=SH_GMACS;
2194887Schin 	else if(strmatch(cp,"*macs*"))
220*10898Sroland.mainz@nrubsig.org 		newopt=SH_EMACS;
221*10898Sroland.mainz@nrubsig.org 	if(newopt)
222*10898Sroland.mainz@nrubsig.org 	{
223*10898Sroland.mainz@nrubsig.org 		sh_offoption(SH_VI);
224*10898Sroland.mainz@nrubsig.org 		sh_offoption(SH_EMACS);
225*10898Sroland.mainz@nrubsig.org 		sh_offoption(SH_GMACS);
226*10898Sroland.mainz@nrubsig.org 		sh_onoption(newopt);
227*10898Sroland.mainz@nrubsig.org 	}
2284887Schin done:
2294887Schin 	nv_putv(np, val, flags, fp);
2304887Schin }
2314887Schin 
2328462SApril.Chin@Sun.COM /* Trap for HISTFILE and HISTSIZE variables */
2338462SApril.Chin@Sun.COM static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
2348462SApril.Chin@Sun.COM {
2358462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
2368462SApril.Chin@Sun.COM 	void 	*histopen = shp->hist_ptr;
237*10898Sroland.mainz@nrubsig.org 	char	*cp;
2388462SApril.Chin@Sun.COM 	if(val && histopen)
2398462SApril.Chin@Sun.COM 	{
240*10898Sroland.mainz@nrubsig.org 		if(np==HISTFILE && (cp=nv_getval(np)) && strcmp(val,cp)==0)
2418462SApril.Chin@Sun.COM 			return;
242*10898Sroland.mainz@nrubsig.org 		if(np==HISTSIZE && sh_arith(val)==nv_getnum(HISTSIZE))
2438462SApril.Chin@Sun.COM 			return;
2448462SApril.Chin@Sun.COM 		hist_close(shp->hist_ptr);
2458462SApril.Chin@Sun.COM 	}
2468462SApril.Chin@Sun.COM 	nv_putv(np, val, flags, fp);
2478462SApril.Chin@Sun.COM 	if(histopen)
2488462SApril.Chin@Sun.COM 	{
2498462SApril.Chin@Sun.COM 		if(val)
2508462SApril.Chin@Sun.COM 			sh_histinit(shp);
2518462SApril.Chin@Sun.COM 		else
2528462SApril.Chin@Sun.COM 			hist_close(histopen);
2538462SApril.Chin@Sun.COM 	}
2548462SApril.Chin@Sun.COM }
2558462SApril.Chin@Sun.COM 
2564887Schin /* Trap for OPTINDEX */
2574887Schin static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp)
2584887Schin {
2598462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
2604887Schin 	shp->st.opterror = shp->st.optchar = 0;
2614887Schin 	nv_putv(np, val, flags, fp);
2628462SApril.Chin@Sun.COM 	if(!val)
2638462SApril.Chin@Sun.COM 		nv_disc(np,fp,NV_POP);
2644887Schin }
2654887Schin 
2664887Schin static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
2674887Schin {
2684887Schin 	return((Sfdouble_t)*np->nvalue.lp);
2694887Schin }
2704887Schin 
2718462SApril.Chin@Sun.COM static Namfun_t *clone_optindex(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
2728462SApril.Chin@Sun.COM {
2738462SApril.Chin@Sun.COM 	Namfun_t *dp = (Namfun_t*)malloc(sizeof(Namfun_t));
2748462SApril.Chin@Sun.COM 	memcpy((void*)dp,(void*)fp,sizeof(Namfun_t));
2758462SApril.Chin@Sun.COM 	mp->nvalue.lp = np->nvalue.lp;
2768462SApril.Chin@Sun.COM 	dp->nofree = 0;
2778462SApril.Chin@Sun.COM 	return(dp);
2788462SApril.Chin@Sun.COM }
2798462SApril.Chin@Sun.COM 
2808462SApril.Chin@Sun.COM 
2814887Schin /* Trap for restricted variables FPATH, PATH, SHELL, ENV */
2824887Schin static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
2834887Schin {
2848462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
2858462SApril.Chin@Sun.COM 	int	path_scoped = 0;
2864887Schin 	Pathcomp_t *pp;
2874887Schin 	char *name = nv_name(np);
2884887Schin 	if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
2894887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
2904887Schin 	if(np==PATHNOD	|| (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
2914887Schin 	{
2924887Schin 		nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
2934887Schin 		if(path_scoped && !val)
2944887Schin 			val = PATHNOD->nvalue.cp;
2954887Schin 	}
2964887Schin 	if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0)
2974887Schin 		 return;
2988462SApril.Chin@Sun.COM 	if(np==FPATHNOD)
2994887Schin 		shp->pathlist = (void*)path_unsetfpath((Pathcomp_t*)shp->pathlist);
3004887Schin 	nv_putv(np, val, flags, fp);
3018462SApril.Chin@Sun.COM 	shp->universe = 0;
3024887Schin 	if(shp->pathlist)
3034887Schin 	{
3044887Schin 		val = np->nvalue.cp;
3054887Schin 		if(np==PATHNOD || path_scoped)
3064887Schin 			pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
3074887Schin 		else if(val && np==FPATHNOD)
3084887Schin 			pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
3094887Schin 		else
3104887Schin 			return;
3114887Schin 		if(shp->pathlist = (void*)pp)
3124887Schin 			pp->shp = shp;
3134887Schin 		if(!val && (flags&NV_NOSCOPE))
3144887Schin 		{
3154887Schin 			Namval_t *mp = dtsearch(shp->var_tree,np);
3164887Schin 			if(mp && (val=nv_getval(mp)))
3174887Schin 				nv_putval(mp,val,NV_RDONLY);
3184887Schin 		}
3194887Schin #if 0
3204887Schin sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val);
3214887Schin path_dump((Pathcomp_t*)shp->pathlist);
3224887Schin #endif
3234887Schin 	}
3244887Schin }
3254887Schin 
3264887Schin static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
3274887Schin {
3284887Schin 	Pathcomp_t *pp;
3298462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
3304887Schin 	nv_putv(np, val, flags, fp);
3314887Schin 	if(!shp->cdpathlist)
3324887Schin 		return;
3334887Schin 	val = np->nvalue.cp;
3344887Schin 	pp = (void*)path_addpath((Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH);
3354887Schin 	if(shp->cdpathlist = (void*)pp)
3364887Schin 		pp->shp = shp;
3374887Schin }
3384887Schin 
3394887Schin #ifdef _hdr_locale
3404887Schin     /*
3414887Schin      * This function needs to be modified to handle international
3424887Schin      * error message translations
3434887Schin      */
3444887Schin #if ERROR_VERSION >= 20000101L
3454887Schin     static char* msg_translate(const char* catalog, const char* message)
3464887Schin     {
3474887Schin 	NOT_USED(catalog);
3484887Schin 	return((char*)message);
3494887Schin     }
3504887Schin #else
3514887Schin     static char* msg_translate(const char* message, int type)
3524887Schin     {
3534887Schin 	NOT_USED(type);
3544887Schin 	return((char*)message);
3554887Schin     }
3564887Schin #endif
3574887Schin 
358*10898Sroland.mainz@nrubsig.org     /* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */
3594887Schin     static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp)
3604887Schin     {
3618462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
3624887Schin 	int type;
3634887Schin 	char *lc_all = nv_getval(LCALLNOD);
3644887Schin 	char *name = nv_name(np);
365*10898Sroland.mainz@nrubsig.org 	if((shp->test&1) && !val && !nv_getval(np))
366*10898Sroland.mainz@nrubsig.org 		return;
367*10898Sroland.mainz@nrubsig.org 	if(shp->test&2)
368*10898Sroland.mainz@nrubsig.org 		nv_putv(np, val, flags, fp);
3694887Schin 	if(name==(LCALLNOD)->nvname)
3704887Schin 		type = LC_ALL;
3714887Schin 	else if(name==(LCTYPENOD)->nvname)
3724887Schin 		type = LC_CTYPE;
3734887Schin 	else if(name==(LCMSGNOD)->nvname)
3744887Schin 		type = LC_MESSAGES;
3754887Schin 	else if(name==(LCCOLLNOD)->nvname)
3764887Schin 		type = LC_COLLATE;
3774887Schin 	else if(name==(LCNUMNOD)->nvname)
3784887Schin 		type = LC_NUMERIC;
379*10898Sroland.mainz@nrubsig.org #ifdef LC_LANG
380*10898Sroland.mainz@nrubsig.org 	else if(name==(LANGNOD)->nvname)
381*10898Sroland.mainz@nrubsig.org 		type = LC_LANG;
382*10898Sroland.mainz@nrubsig.org #else
383*10898Sroland.mainz@nrubsig.org #define LC_LANG		LC_ALL
384*10898Sroland.mainz@nrubsig.org 	else if(name==(LANGNOD)->nvname && (!lc_all || !*lc_all))
385*10898Sroland.mainz@nrubsig.org 		type = LC_LANG;
386*10898Sroland.mainz@nrubsig.org #endif
3874887Schin 	else
3884887Schin 		type= -1;
3894887Schin 	if(sh_isstate(SH_INIT) && type>=0 && type!=LC_ALL && lc_all && *lc_all)
3904887Schin 		type= -1;
391*10898Sroland.mainz@nrubsig.org 	if(type>=0 || type==LC_ALL || type==LC_LANG)
3924887Schin 	{
393*10898Sroland.mainz@nrubsig.org 		if(!setlocale(type,val?val:"-") && val)
3944887Schin 		{
3958462SApril.Chin@Sun.COM 			if(!sh_isstate(SH_INIT) || shp->login_sh==0)
3964887Schin 				errormsg(SH_DICT,0,e_badlocale,val);
3974887Schin 			return;
3984887Schin 		}
3994887Schin 	}
400*10898Sroland.mainz@nrubsig.org 	if(!(shp->test&2))
401*10898Sroland.mainz@nrubsig.org 		nv_putv(np, val, flags, fp);
402*10898Sroland.mainz@nrubsig.org 	if(CC_NATIVE==CC_ASCII && (type==LC_ALL || type==LC_LANG || type==LC_CTYPE))
4034887Schin 	{
4044887Schin 		if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
4054887Schin 			free((void*)sh_lexstates[ST_BEGIN]);
4064887Schin 		if(ast.locale.set&(1<<AST_LC_CTYPE))
4074887Schin 		{
4084887Schin 			register int c;
4094887Schin 			char *state[4];
4104887Schin 			sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
4114887Schin 			memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
4124887Schin 			sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
4134887Schin 			memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
4144887Schin 			sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
4154887Schin 			memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
4164887Schin 			sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
4174887Schin 			memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
4184887Schin 			for(c=0; c<(1<<CHAR_BIT); c++)
4194887Schin 			{
4204887Schin 				if(state[0][c]!=S_REG)
4214887Schin 					continue;
4224887Schin 				if(state[2][c]!=S_ERR)
4234887Schin 					continue;
4244887Schin 				if(isblank(c))
4254887Schin 				{
4264887Schin 					state[0][c]=0;
4274887Schin 					state[1][c]=S_BREAK;
4284887Schin 					state[2][c]=S_BREAK;
4294887Schin 					continue;
4304887Schin 				}
4314887Schin 				if(!isalpha(c))
4324887Schin 					continue;
4334887Schin 				state[0][c]=S_NAME;
4344887Schin 				if(state[1][c]==S_REG)
4354887Schin 					state[1][c]=0;
4364887Schin 				state[2][c]=S_ALP;
4374887Schin 				if(state[3][c]==S_ERR)
4384887Schin 					state[3][c]=0;
4394887Schin 			}
4404887Schin 		}
4414887Schin 		else
4424887Schin 		{
4434887Schin 			sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
4444887Schin 			sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
4454887Schin 			sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
4464887Schin 			sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
4474887Schin 		}
4484887Schin 	}
4494887Schin #if ERROR_VERSION < 20000101L
4504887Schin 	if(type==LC_ALL || type==LC_MESSAGES)
4514887Schin 		error_info.translate = msg_translate;
4524887Schin #endif
4534887Schin     }
4544887Schin #endif /* _hdr_locale */
4554887Schin 
4564887Schin /* Trap for IFS assignment and invalidates state table */
4574887Schin static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
4584887Schin {
4594887Schin 	register struct ifs *ip = (struct ifs*)fp;
460*10898Sroland.mainz@nrubsig.org 	Shell_t		*shp;
4614887Schin 	ip->ifsnp = 0;
462*10898Sroland.mainz@nrubsig.org 	if(!val)
463*10898Sroland.mainz@nrubsig.org 	{
464*10898Sroland.mainz@nrubsig.org 		fp = nv_stack(np, NIL(Namfun_t*));
465*10898Sroland.mainz@nrubsig.org 		if(fp && !fp->nofree)
466*10898Sroland.mainz@nrubsig.org 			free((void*)fp);
467*10898Sroland.mainz@nrubsig.org 	}
4684887Schin 	if(val != np->nvalue.cp)
4694887Schin 		nv_putv(np, val, flags, fp);
470*10898Sroland.mainz@nrubsig.org 	if(!val && !(flags&NV_CLONE) && (fp=np->nvfun) && !fp->disc && (shp=(Shell_t*)(fp->last)))
471*10898Sroland.mainz@nrubsig.org 		nv_stack(np,&((Init_t*)shp->init_context)->IFS_init.hdr);
4724887Schin }
4734887Schin 
4744887Schin /*
4754887Schin  * This is the lookup function for IFS
4764887Schin  * It keeps the sh.ifstable up to date
4774887Schin  */
4784887Schin static char* get_ifs(register Namval_t* np, Namfun_t *fp)
4794887Schin {
4804887Schin 	register struct ifs *ip = (struct ifs*)fp;
4814887Schin 	register char *cp, *value;
4824887Schin 	register int c,n;
4838462SApril.Chin@Sun.COM 	register Shell_t *shp = nv_shell(np);
4844887Schin 	value = nv_getv(np,fp);
4854887Schin 	if(np!=ip->ifsnp)
4864887Schin 	{
4874887Schin 		ip->ifsnp = np;
4884887Schin 		memset(shp->ifstable,0,(1<<CHAR_BIT));
4894887Schin 		if(cp=value)
4904887Schin 		{
4914887Schin #if SHOPT_MULTIBYTE
4924887Schin 			while(n=mbsize(cp),c= *(unsigned char*)cp)
4934887Schin #else
4944887Schin 			while(c= *(unsigned char*)cp++)
4954887Schin #endif /* SHOPT_MULTIBYTE */
4964887Schin 			{
4974887Schin #if SHOPT_MULTIBYTE
4984887Schin 				cp++;
4994887Schin 				if(n>1)
5004887Schin 				{
5014887Schin 					cp += (n-1);
5024887Schin 					shp->ifstable[c] = S_MBYTE;
5034887Schin 					continue;
5044887Schin 				}
5054887Schin #endif /* SHOPT_MULTIBYTE */
5064887Schin 				n = S_DELIM;
5074887Schin 				if(c== *cp)
5084887Schin 					cp++;
5094887Schin 				else if(c=='\n')
5104887Schin 					n = S_NL;
5114887Schin 				else if(isspace(c))
5124887Schin 					n = S_SPACE;
5134887Schin 				shp->ifstable[c] = n;
5144887Schin 			}
5154887Schin 		}
5164887Schin 		else
5174887Schin 		{
5184887Schin 			shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE;
5194887Schin 			shp->ifstable['\n'] = S_NL;
5204887Schin 		}
5214887Schin 	}
5224887Schin 	return(value);
5234887Schin }
5244887Schin 
5254887Schin /*
5264887Schin  * these functions are used to get and set the SECONDS variable
5274887Schin  */
5284887Schin #ifdef timeofday
5294887Schin #   define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
5304887Schin #   define tms	timeval
5314887Schin #else
5324887Schin #   define dtime(tp)	(((double)times(tp))/sh.lim.clk_tck)
5334887Schin #   define timeofday(a)
5344887Schin #endif
5354887Schin 
5364887Schin static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
5374887Schin {
5384887Schin 	double d;
5394887Schin 	struct tms tp;
5404887Schin 	if(!val)
5414887Schin 	{
542*10898Sroland.mainz@nrubsig.org 		fp = nv_stack(np, NIL(Namfun_t*));
543*10898Sroland.mainz@nrubsig.org 		if(fp && !fp->nofree)
544*10898Sroland.mainz@nrubsig.org 			free((void*)fp);
545*10898Sroland.mainz@nrubsig.org 		nv_putv(np, val, flags, fp);
5464887Schin 		return;
5474887Schin 	}
5484887Schin 	if(!np->nvalue.dp)
5494887Schin 	{
5504887Schin 		nv_setsize(np,3);
5518462SApril.Chin@Sun.COM 		nv_onattr(np,NV_DOUBLE);
5524887Schin 		np->nvalue.dp = new_of(double,0);
5534887Schin 	}
5544887Schin 	nv_putv(np, val, flags, fp);
5554887Schin 	d = *np->nvalue.dp;
5564887Schin 	timeofday(&tp);
5574887Schin 	*np->nvalue.dp = dtime(&tp)-d;
5584887Schin }
5594887Schin 
5604887Schin static char* get_seconds(register Namval_t* np, Namfun_t *fp)
5614887Schin {
5628462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
5634887Schin 	register int places = nv_size(np);
5644887Schin 	struct tms tp;
5654887Schin 	double d, offset = (np->nvalue.dp?*np->nvalue.dp:0);
5664887Schin 	NOT_USED(fp);
5674887Schin 	timeofday(&tp);
5684887Schin 	d = dtime(&tp)- offset;
5698462SApril.Chin@Sun.COM 	sfprintf(shp->strbuf,"%.*f",places,d);
5708462SApril.Chin@Sun.COM 	return(sfstruse(shp->strbuf));
5714887Schin }
5724887Schin 
5734887Schin static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp)
5744887Schin {
5754887Schin 	struct tms tp;
5764887Schin 	double offset = (np->nvalue.dp?*np->nvalue.dp:0);
5774887Schin 	NOT_USED(fp);
5784887Schin 	timeofday(&tp);
5794887Schin 	return(dtime(&tp)- offset);
5804887Schin }
5814887Schin 
5824887Schin /*
5834887Schin  * These three functions are used to get and set the RANDOM variable
5844887Schin  */
5854887Schin static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
5864887Schin {
5874887Schin 	struct rand *rp = (struct rand*)fp;
5884887Schin 	register long n;
5894887Schin 	if(!val)
5904887Schin 	{
591*10898Sroland.mainz@nrubsig.org 		fp = nv_stack(np, NIL(Namfun_t*));
592*10898Sroland.mainz@nrubsig.org 		if(fp && !fp->nofree)
593*10898Sroland.mainz@nrubsig.org 			free((void*)fp);
5944887Schin 		nv_unset(np);
5954887Schin 		return;
5964887Schin 	}
5974887Schin 	if(flags&NV_INTEGER)
5984887Schin 		n = *(double*)val;
5994887Schin 	else
6004887Schin 		n = sh_arith(val);
6014887Schin 	srand((int)(n&RANDMASK));
6024887Schin 	rp->rand_last = -1;
6034887Schin 	if(!np->nvalue.lp)
6044887Schin 		np->nvalue.lp = &rp->rand_last;
6054887Schin }
6064887Schin 
6074887Schin /*
6084887Schin  * get random number in range of 0 - 2**15
6094887Schin  * never pick same number twice in a row
6104887Schin  */
6114887Schin static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp)
6124887Schin {
6134887Schin 	register long cur, last= *np->nvalue.lp;
6144887Schin 	NOT_USED(fp);
6154887Schin 	do
6164887Schin 		cur = (rand()>>rand_shift)&RANDMASK;
6174887Schin 	while(cur==last);
6184887Schin 	*np->nvalue.lp = cur;
6194887Schin 	return((Sfdouble_t)cur);
6204887Schin }
6214887Schin 
6224887Schin static char* get_rand(register Namval_t* np, Namfun_t *fp)
6234887Schin {
6244887Schin 	register long n = nget_rand(np,fp);
6254887Schin 	return(fmtbase(n, 10, 0));
6264887Schin }
6274887Schin 
6284887Schin /*
6294887Schin  * These three routines are for LINENO
6304887Schin  */
6314887Schin static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp)
6324887Schin {
6334887Schin 	double d=1;
6344887Schin 	if(error_info.line >0)
6354887Schin 		d = error_info.line;
6364887Schin 	else if(error_info.context && error_info.context->line>0)
6374887Schin 		d = error_info.context->line;
6384887Schin 	NOT_USED(np);
6394887Schin 	NOT_USED(fp);
6404887Schin 	return(d);
6414887Schin }
6424887Schin 
6434887Schin static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
6444887Schin {
6454887Schin 	register long n;
6468462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
6474887Schin 	if(!val)
6484887Schin 	{
649*10898Sroland.mainz@nrubsig.org 		fp = nv_stack(np, NIL(Namfun_t*));
650*10898Sroland.mainz@nrubsig.org 		if(fp && !fp->nofree)
651*10898Sroland.mainz@nrubsig.org 			free((void*)fp);
6524887Schin 		nv_unset(np);
6534887Schin 		return;
6544887Schin 	}
6554887Schin 	if(flags&NV_INTEGER)
6564887Schin 		n = *(double*)val;
6574887Schin 	else
6584887Schin 		n = sh_arith(val);
6594887Schin 	shp->st.firstline += nget_lineno(np,fp)+1-n;
6604887Schin }
6614887Schin 
6624887Schin static char* get_lineno(register Namval_t* np, Namfun_t *fp)
6634887Schin {
6644887Schin 	register long n = nget_lineno(np,fp);
6654887Schin 	return(fmtbase(n, 10, 0));
6664887Schin }
6674887Schin 
6684887Schin static char* get_lastarg(Namval_t* np, Namfun_t *fp)
6694887Schin {
670*10898Sroland.mainz@nrubsig.org 	Shell_t	*shp = nv_shell(np);
671*10898Sroland.mainz@nrubsig.org 	char	*cp;
672*10898Sroland.mainz@nrubsig.org 	int	pid;
673*10898Sroland.mainz@nrubsig.org         if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*')
674*10898Sroland.mainz@nrubsig.org 		nv_putval(np,(pid==getppid()?cp+1:0),0);
6758462SApril.Chin@Sun.COM 	return(shp->lastarg);
6764887Schin }
6774887Schin 
6784887Schin static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp)
6794887Schin {
6808462SApril.Chin@Sun.COM 	Shell_t *shp = nv_shell(np);
6814887Schin 	if(flags&NV_INTEGER)
6824887Schin 	{
6838462SApril.Chin@Sun.COM 		sfprintf(shp->strbuf,"%.*g",12,*((double*)val));
6848462SApril.Chin@Sun.COM 		val = sfstruse(shp->strbuf);
6854887Schin 	}
686*10898Sroland.mainz@nrubsig.org 	if(val)
687*10898Sroland.mainz@nrubsig.org 		val = strdup(val);
6888462SApril.Chin@Sun.COM 	if(shp->lastarg && !nv_isattr(np,NV_NOFREE))
6898462SApril.Chin@Sun.COM 		free((void*)shp->lastarg);
6904887Schin 	else
6914887Schin 		nv_offattr(np,NV_NOFREE);
692*10898Sroland.mainz@nrubsig.org 	shp->lastarg = (char*)val;
693*10898Sroland.mainz@nrubsig.org 	nv_offattr(np,NV_EXPORT);
694*10898Sroland.mainz@nrubsig.org 	np->nvenv = 0;
6954887Schin }
6964887Schin 
6974887Schin static int hasgetdisc(register Namfun_t *fp)
6984887Schin {
6994887Schin         while(fp && !fp->disc->getnum && !fp->disc->getval)
7004887Schin                 fp = fp->next;
7014887Schin 	return(fp!=0);
7024887Schin }
7034887Schin 
7044887Schin /*
7054887Schin  * store the most recent value for use in .sh.match
7064887Schin  */
7074887Schin void sh_setmatch(const char *v, int vsize, int nmatch, int match[])
7084887Schin {
7094887Schin 	struct match *mp = (struct match*)(SH_MATCHNOD->nvfun);
7104887Schin 	register int i,n;
7114887Schin 	if(mp->nmatch = nmatch)
7124887Schin 	{
7134887Schin 		memcpy(mp->match,match,nmatch*2*sizeof(match[0]));
7144887Schin 		for(n=match[0],i=1; i < 2*nmatch; i++)
7154887Schin 		{
7164887Schin 			if(mp->match[i] < n)
7174887Schin 				n = mp->match[i];
7184887Schin 		}
7194887Schin 		for(vsize=0,i=0; i < 2*nmatch; i++)
7204887Schin 		{
7214887Schin 			if((mp->match[i] -= n) > vsize)
7224887Schin 				vsize = mp->match[i];
7234887Schin 		}
7244887Schin 		v += n;
7254887Schin 		if(vsize >= mp->vsize)
7264887Schin 		{
7274887Schin 			if(mp->vsize)
7284887Schin 				mp->val = (char*)realloc(mp->val,vsize+1);
7294887Schin 			else
7304887Schin 				mp->val = (char*)malloc(vsize+1);
7314887Schin 			mp->vsize = vsize;
7324887Schin 		}
7334887Schin 		memcpy(mp->val,v,vsize);
7344887Schin 		mp->val[vsize] = 0;
7358462SApril.Chin@Sun.COM 		nv_putsub(SH_MATCHNOD, NIL(char*), (nmatch-1)|ARRAY_FILL);
7364887Schin 		mp->lastsub = -1;
7374887Schin 	}
7384887Schin }
7394887Schin 
7404887Schin #define array_scan(np)	((nv_arrayptr(np)->nelem&ARRAY_SCAN))
7414887Schin 
7424887Schin static char* get_match(register Namval_t* np, Namfun_t *fp)
7434887Schin {
7444887Schin 	struct match *mp = (struct match*)fp;
7454887Schin 	int sub,n;
7464887Schin 	char *val;
7474887Schin 	sub = nv_aindex(np);
7484887Schin 	if(sub>=mp->nmatch)
7494887Schin 		return(0);
7504887Schin 	if(sub==mp->lastsub)
7514887Schin 		return(mp->rval);
7524887Schin 	if(mp->rval)
7534887Schin 	{
7544887Schin 		free((void*)mp->rval);
7554887Schin 		mp->rval = 0;
7564887Schin 	}
7574887Schin 	n = mp->match[2*sub+1]-mp->match[2*sub];
7584887Schin 	if(n<=0)
7594887Schin 		return("");
7604887Schin 	val = mp->val+mp->match[2*sub];
7614887Schin 	if(mp->val[mp->match[2*sub+1]]==0)
7624887Schin 		return(val);
7634887Schin 	mp->rval = (char*)malloc(n+1);
7644887Schin 	mp->lastsub = sub;
7654887Schin 	memcpy(mp->rval,val,n);
7664887Schin 	mp->rval[n] = 0;
7674887Schin 	return(mp->rval);
7684887Schin }
7694887Schin 
7708462SApril.Chin@Sun.COM static const Namdisc_t SH_MATCH_disc  = { sizeof(struct match), 0, get_match };
7718462SApril.Chin@Sun.COM 
7728462SApril.Chin@Sun.COM static char* get_version(register Namval_t* np, Namfun_t *fp)
7738462SApril.Chin@Sun.COM {
7748462SApril.Chin@Sun.COM 	return(nv_getv(np,fp));
7758462SApril.Chin@Sun.COM }
7768462SApril.Chin@Sun.COM 
7778462SApril.Chin@Sun.COM static Sfdouble_t nget_version(register Namval_t* np, Namfun_t *fp)
7788462SApril.Chin@Sun.COM {
7798462SApril.Chin@Sun.COM 	register const char	*cp = e_version + strlen(e_version)-10;
7808462SApril.Chin@Sun.COM 	register int		c;
7818462SApril.Chin@Sun.COM 	Sflong_t		t = 0;
7828462SApril.Chin@Sun.COM 	NOT_USED(fp);
7838462SApril.Chin@Sun.COM 
7848462SApril.Chin@Sun.COM 	while (c = *cp++)
7858462SApril.Chin@Sun.COM 		if (c >= '0' && c <= '9')
7868462SApril.Chin@Sun.COM 		{
7878462SApril.Chin@Sun.COM 			t *= 10;
7888462SApril.Chin@Sun.COM 			t += c - '0';
7898462SApril.Chin@Sun.COM 		}
7908462SApril.Chin@Sun.COM 	return((Sfdouble_t)t);
7918462SApril.Chin@Sun.COM }
7928462SApril.Chin@Sun.COM 
7938462SApril.Chin@Sun.COM static const Namdisc_t SH_VERSION_disc	= {  0, 0, get_version, nget_version };
7944887Schin 
7954887Schin #if SHOPT_FS_3D
7964887Schin     /*
7974887Schin      * set or unset the mappings given a colon separated list of directories
7984887Schin      */
7994887Schin     static void vpath_set(char *str, int mode)
8004887Schin     {
8014887Schin 	register char *lastp, *oldp=str, *newp=strchr(oldp,':');
8024887Schin 	if(!sh.lim.fs3d)
8034887Schin 		return;
8044887Schin 	while(newp)
8054887Schin 	{
8064887Schin 		*newp++ = 0;
8074887Schin 		if(lastp=strchr(newp,':'))
8084887Schin 			*lastp = 0;
8094887Schin 		mount((mode?newp:""),oldp,FS3D_VIEW,0);
8104887Schin 		newp[-1] = ':';
8114887Schin 		oldp = newp;
8124887Schin 		newp=lastp;
8134887Schin 	}
8144887Schin     }
8154887Schin 
8164887Schin     /* catch vpath assignments */
8174887Schin     static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
8184887Schin     {
8194887Schin 	register char *cp;
8204887Schin 	if(cp = nv_getval(np))
8214887Schin 		vpath_set(cp,0);
8224887Schin 	if(val)
8234887Schin 		vpath_set((char*)val,1);
8244887Schin 	nv_putv(np,val,flags,fp);
8254887Schin     }
8264887Schin     static const Namdisc_t VPATH_disc	= { 0, put_vpath  };
8274887Schin     static Namfun_t VPATH_init	= { &VPATH_disc, 1  };
8284887Schin #endif /* SHOPT_FS_3D */
8294887Schin 
8304887Schin 
8314887Schin static const Namdisc_t IFS_disc		= {  sizeof(struct ifs), put_ifs, get_ifs };
8328462SApril.Chin@Sun.COM const Namdisc_t RESTRICTED_disc	= {  sizeof(Namfun_t), put_restricted };
8338462SApril.Chin@Sun.COM static const Namdisc_t CDPATH_disc	= {  sizeof(Namfun_t), put_cdpath };
8348462SApril.Chin@Sun.COM static const Namdisc_t EDITOR_disc	= {  sizeof(Namfun_t), put_ed };
8358462SApril.Chin@Sun.COM static const Namdisc_t HISTFILE_disc	= {  sizeof(Namfun_t), put_history };
8368462SApril.Chin@Sun.COM static const Namdisc_t OPTINDEX_disc	= {  sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex };
8374887Schin static const Namdisc_t SECONDS_disc	= {  sizeof(struct seconds), put_seconds, get_seconds, nget_seconds };
8384887Schin static const Namdisc_t RAND_disc	= {  sizeof(struct rand), put_rand, get_rand, nget_rand };
8398462SApril.Chin@Sun.COM static const Namdisc_t LINENO_disc	= {  sizeof(Namfun_t), put_lineno, get_lineno, nget_lineno };
8408462SApril.Chin@Sun.COM static const Namdisc_t L_ARG_disc	= {  sizeof(Namfun_t), put_lastarg, get_lastarg };
8414887Schin 
8424887Schin #if SHOPT_NAMESPACE
8434887Schin     static char* get_nspace(Namval_t* np, Namfun_t *fp)
8444887Schin     {
8454887Schin 	if(sh.namespace)
8464887Schin 		return(nv_name(sh.namespace));
8474887Schin 	return((char*)np->nvalue.cp);
8484887Schin     }
8494887Schin     static const Namdisc_t NSPACE_disc	= {  0, 0, get_nspace };
8504887Schin     static Namfun_t NSPACE_init	= {  &NSPACE_disc, 1};
8514887Schin #endif /* SHOPT_NAMESPACE */
8524887Schin 
8534887Schin #ifdef _hdr_locale
8548462SApril.Chin@Sun.COM     static const Namdisc_t LC_disc	= {  sizeof(Namfun_t), put_lang };
8554887Schin #endif /* _hdr_locale */
8564887Schin 
8574887Schin /*
8584887Schin  * This function will get called whenever a configuration parameter changes
8594887Schin  */
8604887Schin static int newconf(const char *name, const char *path, const char *value)
8614887Schin {
8624887Schin 	register char *arg;
8634887Schin 	if(!name)
8644887Schin 		setenviron(value);
8654887Schin 	else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
8664887Schin 	{
8674887Schin 		sh.universe = 0;
8684887Schin 		/* set directory in new universe */
8694887Schin 		if(*(arg = path_pwd(0))=='/')
8704887Schin 			chdir(arg);
8714887Schin 		/* clear out old tracked alias */
8724887Schin 		stakseek(0);
8734887Schin 		stakputs(nv_getval(PATHNOD));
8744887Schin 		stakputc(0);
8754887Schin 		nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
8764887Schin 	}
8774887Schin 	return(1);
8784887Schin }
8794887Schin 
8804887Schin #if	(CC_NATIVE != CC_ASCII)
8814887Schin     static void a2e(char *d, const char *s)
8824887Schin     {
8834887Schin 	register const unsigned char *t;
8844887Schin 	register int i;
8854887Schin 	t = CCMAP(CC_ASCII, CC_NATIVE);
8864887Schin 	for(i=0; i<(1<<CHAR_BIT); i++)
8874887Schin 		d[t[i]] = s[i];
8884887Schin     }
8894887Schin 
8904887Schin     static void init_ebcdic(void)
8914887Schin     {
8924887Schin 	int i;
8934887Schin 	char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT));
8944887Schin 	for(i=0; i < ST_NONE; i++)
8954887Schin 	{
8964887Schin 		a2e(cp,sh_lexrstates[i]);
8974887Schin 		sh_lexstates[i] = cp;
8984887Schin 		cp += (1<<CHAR_BIT);
8994887Schin 	}
9004887Schin     }
9014887Schin #endif
9024887Schin 
9034887Schin /*
9044887Schin  * return SH_TYPE_* bitmask for path
9054887Schin  * 0 for "not a shell"
9064887Schin  */
9074887Schin int sh_type(register const char *path)
9084887Schin {
9094887Schin 	register const char*	s;
9104887Schin 	register int		t = 0;
9114887Schin 
9124887Schin 	if (s = (const char*)strrchr(path, '/'))
9134887Schin 	{
9144887Schin 		if (*path == '-')
9154887Schin 			t |= SH_TYPE_LOGIN;
9164887Schin 		s++;
9174887Schin 	}
9184887Schin 	else
9194887Schin 		s = path;
9204887Schin 	if (*s == '-')
9214887Schin 	{
9224887Schin 		s++;
9234887Schin 		t |= SH_TYPE_LOGIN;
9244887Schin 	}
9254887Schin 	for (;;)
9264887Schin 	{
9274887Schin 		if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH)))
9284887Schin 		{
9294887Schin 			if (*s == 'k')
9304887Schin 			{
9314887Schin 				s++;
9324887Schin 				t |= SH_TYPE_KSH;
9334887Schin 				continue;
9344887Schin 			}
9354887Schin #if SHOPT_BASH
9364887Schin 			if (*s == 'b' && *(s+1) == 'a')
9374887Schin 			{
9384887Schin 				s += 2;
9394887Schin 				t |= SH_TYPE_BASH;
9404887Schin 				continue;
9414887Schin 			}
9424887Schin #endif
9434887Schin 		}
9444887Schin 		if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED)))
9454887Schin 		{
9464887Schin #if SHOPT_PFSH
9474887Schin 			if (*s == 'p' && *(s+1) == 'f')
9484887Schin 			{
9494887Schin 				s += 2;
9504887Schin 				t |= SH_TYPE_PROFILE;
9514887Schin 				continue;
9524887Schin 			}
9534887Schin #endif
9544887Schin 			if (*s == 'r')
9554887Schin 			{
9564887Schin 				s++;
9574887Schin 				t |= SH_TYPE_RESTRICTED;
9584887Schin 				continue;
9594887Schin 			}
9604887Schin 		}
9614887Schin 		break;
9624887Schin 	}
9638462SApril.Chin@Sun.COM 	if (*s++ == 's' && (*s == 'h' || *s == 'u'))
9648462SApril.Chin@Sun.COM 	{
9658462SApril.Chin@Sun.COM 		s++;
9668462SApril.Chin@Sun.COM 		t |= SH_TYPE_SH;
9678462SApril.Chin@Sun.COM 		if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3')
9688462SApril.Chin@Sun.COM 			s += 2;
9694887Schin #if _WINIX
9708462SApril.Chin@Sun.COM 		if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e')
9718462SApril.Chin@Sun.COM 			s += 4;
9724887Schin #endif
9738462SApril.Chin@Sun.COM 		if (!isalnum(*s))
9748462SApril.Chin@Sun.COM 			return t;
9758462SApril.Chin@Sun.COM 	}
9768462SApril.Chin@Sun.COM 	return t & ~(SH_TYPE_BASH|SH_TYPE_KSH|SH_TYPE_PROFILE|SH_TYPE_RESTRICTED);
9778462SApril.Chin@Sun.COM }
9788462SApril.Chin@Sun.COM 
9798462SApril.Chin@Sun.COM 
9808462SApril.Chin@Sun.COM static char *get_mode(Namval_t* np, Namfun_t* nfp)
9818462SApril.Chin@Sun.COM {
9828462SApril.Chin@Sun.COM 	mode_t mode = nv_getn(np,nfp);
9838462SApril.Chin@Sun.COM 	return(fmtperm(mode));
9844887Schin }
9854887Schin 
9868462SApril.Chin@Sun.COM static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
9878462SApril.Chin@Sun.COM {
9888462SApril.Chin@Sun.COM 	if(val)
9898462SApril.Chin@Sun.COM 	{
9908462SApril.Chin@Sun.COM 		mode_t mode;
9918462SApril.Chin@Sun.COM 		char *last;
9928462SApril.Chin@Sun.COM 		if(flag&NV_INTEGER)
9938462SApril.Chin@Sun.COM 		{
9948462SApril.Chin@Sun.COM 			if(flag&NV_LONG)
9958462SApril.Chin@Sun.COM 				mode = *(Sfdouble_t*)val;
9968462SApril.Chin@Sun.COM 			else
9978462SApril.Chin@Sun.COM 				mode = *(double*)val;
9988462SApril.Chin@Sun.COM 		}
9998462SApril.Chin@Sun.COM 		else
10008462SApril.Chin@Sun.COM 			mode = strperm(val, &last,0);
10018462SApril.Chin@Sun.COM 		if(*last)
10028462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val);
10038462SApril.Chin@Sun.COM 		nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
10048462SApril.Chin@Sun.COM 	}
10058462SApril.Chin@Sun.COM 	else
10068462SApril.Chin@Sun.COM 		nv_putv(np,val,flag,nfp);
10078462SApril.Chin@Sun.COM }
10088462SApril.Chin@Sun.COM 
10098462SApril.Chin@Sun.COM static const Namdisc_t modedisc =
10108462SApril.Chin@Sun.COM {
10118462SApril.Chin@Sun.COM 	0,
10128462SApril.Chin@Sun.COM         put_mode,
10138462SApril.Chin@Sun.COM         get_mode,
10148462SApril.Chin@Sun.COM };
10158462SApril.Chin@Sun.COM 
10168462SApril.Chin@Sun.COM 
10174887Schin /*
10184887Schin  * initialize the shell
10194887Schin  */
10208462SApril.Chin@Sun.COM Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
10214887Schin {
10228462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
10234887Schin 	register int n;
10244887Schin 	int type;
10254887Schin 	static char *login_files[3];
1026*10898Sroland.mainz@nrubsig.org 	memfatal();
10274887Schin 	n = strlen(e_version);
10284887Schin 	if(e_version[n-1]=='$' && e_version[n-2]==' ')
10294887Schin 		e_version[n-2]=0;
10304887Schin #if	(CC_NATIVE == CC_ASCII)
10314887Schin 	memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
10324887Schin #else
10334887Schin 	init_ebcdic();
10344887Schin #endif
10358462SApril.Chin@Sun.COM 	umask(shp->mask=umask(0));
10368462SApril.Chin@Sun.COM 	shp->mac_context = sh_macopen(shp);
10378462SApril.Chin@Sun.COM 	shp->arg_context = sh_argopen(shp);
10388462SApril.Chin@Sun.COM 	shp->lex_context = (void*)sh_lexopen(0,shp,1);
10398462SApril.Chin@Sun.COM 	shp->ed_context = (void*)ed_open(shp);
10408462SApril.Chin@Sun.COM 	shp->strbuf = sfstropen();
10418462SApril.Chin@Sun.COM 	shp->stk = stkstd;
10428462SApril.Chin@Sun.COM 	sfsetbuf(shp->strbuf,(char*)0,64);
10434887Schin 	sh_onstate(SH_INIT);
10444887Schin 	error_info.exit = sh_exit;
10454887Schin 	error_info.id = path_basename(argv[0]);
10464887Schin #if ERROR_VERSION >= 20000102L
10474887Schin 	error_info.catalog = e_dict;
10484887Schin #endif
1049*10898Sroland.mainz@nrubsig.org #if SHOPT_REGRESS
1050*10898Sroland.mainz@nrubsig.org 	{
1051*10898Sroland.mainz@nrubsig.org 		Opt_t*	nopt;
1052*10898Sroland.mainz@nrubsig.org 		Opt_t*	oopt;
1053*10898Sroland.mainz@nrubsig.org 		char*	a;
1054*10898Sroland.mainz@nrubsig.org 		char**	av = argv;
1055*10898Sroland.mainz@nrubsig.org 		char*	regress[3];
1056*10898Sroland.mainz@nrubsig.org 
1057*10898Sroland.mainz@nrubsig.org 		sh_regress_init(shp);
1058*10898Sroland.mainz@nrubsig.org 		regress[0] = "__regress__";
1059*10898Sroland.mainz@nrubsig.org 		regress[2] = 0;
1060*10898Sroland.mainz@nrubsig.org 		/* NOTE: only shp is used by __regress__ at this point */
1061*10898Sroland.mainz@nrubsig.org 		shp->bltindata.shp = shp;
1062*10898Sroland.mainz@nrubsig.org 		while ((a = *++av) && a[0] == '-' && (a[1] == 'I' || a[1] == '-' && a[2] == 'r'))
1063*10898Sroland.mainz@nrubsig.org 		{
1064*10898Sroland.mainz@nrubsig.org 			if (a[1] == 'I')
1065*10898Sroland.mainz@nrubsig.org 			{
1066*10898Sroland.mainz@nrubsig.org 				if (a[2])
1067*10898Sroland.mainz@nrubsig.org 					regress[1] = a + 2;
1068*10898Sroland.mainz@nrubsig.org 				else if (!(regress[1] = *++av))
1069*10898Sroland.mainz@nrubsig.org 					break;
1070*10898Sroland.mainz@nrubsig.org 			}
1071*10898Sroland.mainz@nrubsig.org 			else if (strncmp(a+2, "regress", 7))
1072*10898Sroland.mainz@nrubsig.org 				break;
1073*10898Sroland.mainz@nrubsig.org 			else if (a[9] == '=')
1074*10898Sroland.mainz@nrubsig.org 				regress[1] = a + 10;
1075*10898Sroland.mainz@nrubsig.org 			else if (!(regress[1] = *++av))
1076*10898Sroland.mainz@nrubsig.org 				break;
1077*10898Sroland.mainz@nrubsig.org 			nopt = optctx(0, 0);
1078*10898Sroland.mainz@nrubsig.org 			oopt = optctx(nopt, 0);
1079*10898Sroland.mainz@nrubsig.org 			b___regress__(2, regress, &shp->bltindata);
1080*10898Sroland.mainz@nrubsig.org 			optctx(oopt, nopt);
1081*10898Sroland.mainz@nrubsig.org 		}
1082*10898Sroland.mainz@nrubsig.org 	}
1083*10898Sroland.mainz@nrubsig.org #endif
10848462SApril.Chin@Sun.COM 	shp->cpipe[0] = -1;
10858462SApril.Chin@Sun.COM 	shp->coutpipe = -1;
10868462SApril.Chin@Sun.COM 	shp->userid=getuid();
10878462SApril.Chin@Sun.COM 	shp->euserid=geteuid();
10888462SApril.Chin@Sun.COM 	shp->groupid=getgid();
10898462SApril.Chin@Sun.COM 	shp->egroupid=getegid();
10904887Schin 	for(n=0;n < 10; n++)
10914887Schin 	{
10924887Schin 		/* don't use lower bits when rand() generates large numbers */
10934887Schin 		if(rand() > RANDMASK)
10944887Schin 		{
10954887Schin 			rand_shift = 3;
10964887Schin 			break;
10974887Schin 		}
10984887Schin 	}
10998462SApril.Chin@Sun.COM 	shp->lim.clk_tck = getconf("CLK_TCK");
11008462SApril.Chin@Sun.COM 	shp->lim.arg_max = getconf("ARG_MAX");
11018462SApril.Chin@Sun.COM 	shp->lim.open_max = getconf("OPEN_MAX");
11028462SApril.Chin@Sun.COM 	shp->lim.child_max = getconf("CHILD_MAX");
11038462SApril.Chin@Sun.COM 	shp->lim.ngroups_max = getconf("NGROUPS_MAX");
11048462SApril.Chin@Sun.COM 	shp->lim.posix_version = getconf("VERSION");
11058462SApril.Chin@Sun.COM 	shp->lim.posix_jobcontrol = getconf("JOB_CONTROL");
11068462SApril.Chin@Sun.COM 	if(shp->lim.arg_max <=0)
11078462SApril.Chin@Sun.COM 		shp->lim.arg_max = ARG_MAX;
11088462SApril.Chin@Sun.COM 	if(shp->lim.child_max <=0)
11098462SApril.Chin@Sun.COM 		shp->lim.child_max = CHILD_MAX;
11108462SApril.Chin@Sun.COM 	if(shp->lim.open_max <0)
11118462SApril.Chin@Sun.COM 		shp->lim.open_max = OPEN_MAX;
11128462SApril.Chin@Sun.COM 	if(shp->lim.open_max > (SHRT_MAX-2))
11138462SApril.Chin@Sun.COM 		shp->lim.open_max = SHRT_MAX-2;
11148462SApril.Chin@Sun.COM 	if(shp->lim.clk_tck <=0)
11158462SApril.Chin@Sun.COM 		shp->lim.clk_tck = CLK_TCK;
11164887Schin #if SHOPT_FS_3D
11174887Schin 	if(fs3d(FS3D_TEST))
11188462SApril.Chin@Sun.COM 		shp->lim.fs3d = 1;
11194887Schin #endif /* SHOPT_FS_3D */
11208462SApril.Chin@Sun.COM 	sh_ioinit(shp);
11214887Schin 	/* initialize signal handling */
11228462SApril.Chin@Sun.COM 	sh_siginit(shp);
11234887Schin 	stakinstall(NIL(Stak_t*),nospace);
11244887Schin 	/* set up memory for name-value pairs */
11258462SApril.Chin@Sun.COM 	shp->init_context =  nv_init(shp);
11264887Schin 	/* read the environment */
11274887Schin 	if(argc>0)
11284887Schin 	{
11294887Schin 		type = sh_type(*argv);
11304887Schin 		if(type&SH_TYPE_LOGIN)
11318462SApril.Chin@Sun.COM 			shp->login_sh = 2;
11324887Schin 	}
11338462SApril.Chin@Sun.COM 	env_init(shp);
1134*10898Sroland.mainz@nrubsig.org 	if(!ENVNOD->nvalue.cp)
1135*10898Sroland.mainz@nrubsig.org 	{
1136*10898Sroland.mainz@nrubsig.org 		sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME));
1137*10898Sroland.mainz@nrubsig.org 		nv_putval(ENVNOD,sfstruse(shp->strbuf),NV_RDONLY);
1138*10898Sroland.mainz@nrubsig.org 	}
11398462SApril.Chin@Sun.COM 	*SHLVL->nvalue.ip +=1;
11404887Schin #if SHOPT_SPAWN
11414887Schin 	{
11424887Schin 		/*
11434887Schin 		 * try to find the pathname for this interpreter
11444887Schin 		 * try using environment variable _ or argv[0]
11454887Schin 		 */
1146*10898Sroland.mainz@nrubsig.org 		char *cp=nv_getval(L_ARGNOD);
11474887Schin 		char buff[PATH_MAX+1];
11488462SApril.Chin@Sun.COM 		shp->shpath = 0;
1149*10898Sroland.mainz@nrubsig.org #if _AST_VERSION >= 20090202L
1150*10898Sroland.mainz@nrubsig.org 		if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff))
1151*10898Sroland.mainz@nrubsig.org 			shp->shpath = strdup(buff);
1152*10898Sroland.mainz@nrubsig.org #else
11538462SApril.Chin@Sun.COM 		sfprintf(shp->strbuf,"/proc/%d/exe",getpid());
11548462SApril.Chin@Sun.COM 		if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0)
11554887Schin 		{
11564887Schin 			buff[n] = 0;
11578462SApril.Chin@Sun.COM 			shp->shpath = strdup(buff);
11584887Schin 		}
1159*10898Sroland.mainz@nrubsig.org #endif
11604887Schin 		else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
11614887Schin 		{
11624887Schin 			if(*cp=='/')
11638462SApril.Chin@Sun.COM 				shp->shpath = strdup(cp);
11644887Schin 			else if(cp = nv_getval(PWDNOD))
11654887Schin 			{
11664887Schin 				int offset = staktell();
11674887Schin 				stakputs(cp);
11684887Schin 				stakputc('/');
11694887Schin 				stakputs(argv[0]);
11704887Schin 				pathcanon(stakptr(offset),PATH_DOTDOT);
11718462SApril.Chin@Sun.COM 				shp->shpath = strdup(stakptr(offset));
11724887Schin 				stakseek(offset);
11734887Schin 			}
11744887Schin 		}
11754887Schin 	}
11764887Schin #endif
11774887Schin 	nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
11784887Schin #if SHOPT_FS_3D
11794887Schin 	nv_stack(VPATHNOD, &VPATH_init);
11804887Schin #endif /* SHOPT_FS_3D */
11814887Schin 	astconfdisc(newconf);
11824887Schin #if SHOPT_TIMEOUT
11838462SApril.Chin@Sun.COM 	shp->st.tmout = SHOPT_TIMEOUT;
11844887Schin #endif /* SHOPT_TIMEOUT */
11854887Schin 	/* initialize jobs table */
11864887Schin 	job_clear();
11874887Schin 	if(argc>0)
11884887Schin 	{
11894887Schin 		/* check for restricted shell */
11904887Schin 		if(type&SH_TYPE_RESTRICTED)
11914887Schin 			sh_onoption(SH_RESTRICTED);
11924887Schin #if SHOPT_PFSH
11934887Schin 		/* check for profile shell */
11944887Schin 		else if(type&SH_TYPE_PROFILE)
11954887Schin 			sh_onoption(SH_PFSH);
11964887Schin #endif
11974887Schin #if SHOPT_BASH
11984887Schin 		/* check for invocation as bash */
11994887Schin 		if(type&SH_TYPE_BASH)
12004887Schin 		{
12018462SApril.Chin@Sun.COM 		        shp->userinit = userinit = bash_init;
12024887Schin 			sh_onoption(SH_BASH);
12034887Schin 			sh_onstate(SH_PREINIT);
12048462SApril.Chin@Sun.COM 			(*userinit)(shp, 0);
12054887Schin 			sh_offstate(SH_PREINIT);
12064887Schin 		}
12074887Schin #endif
12084887Schin 		/* look for options */
12098462SApril.Chin@Sun.COM 		/* shp->st.dolc is $#	*/
12108462SApril.Chin@Sun.COM 		if((shp->st.dolc = sh_argopts(-argc,argv,shp)) < 0)
12114887Schin 		{
12128462SApril.Chin@Sun.COM 			shp->exitval = 2;
12138462SApril.Chin@Sun.COM 			sh_done(shp,0);
12144887Schin 		}
12154887Schin 		opt_info.disc = 0;
12168462SApril.Chin@Sun.COM 		shp->st.dolv=argv+(argc-1)-shp->st.dolc;
12178462SApril.Chin@Sun.COM 		shp->st.dolv[0] = argv[0];
12188462SApril.Chin@Sun.COM 		if(shp->st.dolc < 1)
12194887Schin 			sh_onoption(SH_SFLAG);
12204887Schin 		if(!sh_isoption(SH_SFLAG))
12214887Schin 		{
12228462SApril.Chin@Sun.COM 			shp->st.dolc--;
12238462SApril.Chin@Sun.COM 			shp->st.dolv++;
12244887Schin #if _WINIX
12254887Schin 			{
12264887Schin 				char*	name;
12278462SApril.Chin@Sun.COM 				name = shp->st.dolv[0];
12284887Schin 				if(name[1]==':' && (name[2]=='/' || name[2]=='\\'))
12294887Schin 				{
12304887Schin #if _lib_pathposix
12314887Schin 					char*	p;
12324887Schin 
12334887Schin 					if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n)))
12344887Schin 					{
12354887Schin 						pathposix(name, p, n);
12364887Schin 						name = p;
12374887Schin 					}
12384887Schin 					else
12394887Schin #endif
12404887Schin 					{
12414887Schin 						name[1] = name[0];
12424887Schin 						name[0] = name[2] = '/';
12434887Schin 					}
12444887Schin 				}
12454887Schin 			}
12464887Schin #endif /* _WINIX */
12474887Schin 		}
12484887Schin 	}
12494887Schin #if SHOPT_PFSH
12504887Schin 	if (sh_isoption(SH_PFSH))
12514887Schin 	{
12528462SApril.Chin@Sun.COM 		struct passwd *pw = getpwuid(shp->userid);
12534887Schin 		if(pw)
12548462SApril.Chin@Sun.COM 			shp->user = strdup(pw->pw_name);
12554887Schin 
12564887Schin 	}
12574887Schin #endif
12584887Schin 	/* set[ug]id scripts require the -p flag */
12598462SApril.Chin@Sun.COM 	if(shp->userid!=shp->euserid || shp->groupid!=shp->egroupid)
12604887Schin 	{
1261*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_P_SUID
12624887Schin 		/* require sh -p to run setuid and/or setgid */
1263*10898Sroland.mainz@nrubsig.org 		if(!sh_isoption(SH_PRIVILEGED) && shp->userid >= SHOPT_P_SUID)
12644887Schin 		{
12658462SApril.Chin@Sun.COM 			setuid(shp->euserid=shp->userid);
12668462SApril.Chin@Sun.COM 			setgid(shp->egroupid=shp->groupid);
12674887Schin 		}
12684887Schin 		else
1269*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_P_SUID */
12704887Schin 			sh_onoption(SH_PRIVILEGED);
12714887Schin #ifdef SHELLMAGIC
12724887Schin 		/* careful of #! setuid scripts with name beginning with - */
12738462SApril.Chin@Sun.COM 		if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0)
12744887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_prohibited);
12754887Schin #endif /*SHELLMAGIC*/
12764887Schin 	}
12774887Schin 	else
12784887Schin 		sh_offoption(SH_PRIVILEGED);
12794887Schin 	/* shname for $0 in profiles and . scripts */
12804887Schin 	if(strmatch(argv[1],e_devfdNN))
12818462SApril.Chin@Sun.COM 		shp->shname = strdup(argv[0]);
12824887Schin 	else
12838462SApril.Chin@Sun.COM 		shp->shname = strdup(shp->st.dolv[0]);
12844887Schin 	/*
12854887Schin 	 * return here for shell script execution
12864887Schin 	 * but not for parenthesis subshells
12874887Schin 	 */
12888462SApril.Chin@Sun.COM 	error_info.id = strdup(shp->st.dolv[0]); /* error_info.id is $0 */
12898462SApril.Chin@Sun.COM 	shp->jmpbuffer = (void*)&shp->checkbase;
12908462SApril.Chin@Sun.COM 	sh_pushcontext(&shp->checkbase,SH_JMPSCRIPT);
12918462SApril.Chin@Sun.COM 	shp->st.self = &shp->global;
12928462SApril.Chin@Sun.COM         shp->topscope = (Shscope_t*)shp->st.self;
12934887Schin 	sh_offstate(SH_INIT);
12944887Schin 	login_files[0] = (char*)e_profile;
12954887Schin 	login_files[1] = ".profile";
12968462SApril.Chin@Sun.COM 	shp->login_files = login_files;
12978462SApril.Chin@Sun.COM 	shp->bltindata.version = SH_VERSION;
12988462SApril.Chin@Sun.COM 	shp->bltindata.shp = shp;
12998462SApril.Chin@Sun.COM 	shp->bltindata.shrun = sh_run;
13008462SApril.Chin@Sun.COM 	shp->bltindata.shtrap = sh_trap;
13018462SApril.Chin@Sun.COM 	shp->bltindata.shexit = sh_exit;
13028462SApril.Chin@Sun.COM 	shp->bltindata.shbltin = sh_addbuiltin;
13038462SApril.Chin@Sun.COM #if _AST_VERSION >= 20080617L
13048462SApril.Chin@Sun.COM 	shp->bltindata.shgetenv = getenv;
13058462SApril.Chin@Sun.COM 	shp->bltindata.shsetenv = setenviron;
13068462SApril.Chin@Sun.COM 	astintercept(&shp->bltindata,1);
13078462SApril.Chin@Sun.COM #endif
13088462SApril.Chin@Sun.COM #if 0
13098462SApril.Chin@Sun.COM #define NV_MKINTTYPE(x,y,z)	nv_mkinttype(#x,sizeof(x),(x)-1<0,(y),(Namdisc_t*)z);
13108462SApril.Chin@Sun.COM 	NV_MKINTTYPE(pid_t,"process id",0);
13118462SApril.Chin@Sun.COM 	NV_MKINTTYPE(gid_t,"group id",0);
13128462SApril.Chin@Sun.COM 	NV_MKINTTYPE(uid_t,"user id",0);
13138462SApril.Chin@Sun.COM 	NV_MKINTTYPE(size_t,(const char*)0,0);
13148462SApril.Chin@Sun.COM 	NV_MKINTTYPE(ssize_t,(const char*)0,0);
13158462SApril.Chin@Sun.COM 	NV_MKINTTYPE(off_t,"offset in bytes",0);
13168462SApril.Chin@Sun.COM 	NV_MKINTTYPE(ino_t,"\ai-\anode number",0);
13178462SApril.Chin@Sun.COM 	NV_MKINTTYPE(mode_t,(const char*)0,&modedisc);
13188462SApril.Chin@Sun.COM 	NV_MKINTTYPE(dev_t,"device id",0);
13198462SApril.Chin@Sun.COM 	NV_MKINTTYPE(nlink_t,"hard link count",0);
13208462SApril.Chin@Sun.COM 	NV_MKINTTYPE(blkcnt_t,"block count",0);
13218462SApril.Chin@Sun.COM 	NV_MKINTTYPE(time_t,"seconds since the epoch",0);
13228462SApril.Chin@Sun.COM 	nv_mkstat();
13238462SApril.Chin@Sun.COM #endif
13248462SApril.Chin@Sun.COM 	if(shp->userinit=userinit)
13258462SApril.Chin@Sun.COM 		(*userinit)(shp, 0);
13268462SApril.Chin@Sun.COM 	return(shp);
13274887Schin }
13284887Schin 
13294887Schin Shell_t *sh_getinterp(void)
13304887Schin {
13314887Schin 	return(&sh);
13324887Schin }
13334887Schin 
13344887Schin /*
13354887Schin  * reinitialize before executing a script
13364887Schin  */
13374887Schin int sh_reinit(char *argv[])
13384887Schin {
13398462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
13404887Schin 	Shopt_t opt;
13418462SApril.Chin@Sun.COM 	Namval_t *np,*npnext;
13428462SApril.Chin@Sun.COM 	Dt_t	*dp;
13438462SApril.Chin@Sun.COM 	for(np=dtfirst(shp->fun_tree);np;np=npnext)
13444887Schin 	{
13458462SApril.Chin@Sun.COM 		if((dp=shp->fun_tree)->walk)
13468462SApril.Chin@Sun.COM 			dp = dp->walk;
13478462SApril.Chin@Sun.COM 		npnext = (Namval_t*)dtnext(shp->fun_tree,np);
13488462SApril.Chin@Sun.COM 		if(np>= shp->bltin_cmds && np < &shp->bltin_cmds[nbltins])
13498462SApril.Chin@Sun.COM 			continue;
13508462SApril.Chin@Sun.COM 		if(is_abuiltin(np) && nv_isattr(np,NV_EXPORT))
13518462SApril.Chin@Sun.COM 			continue;
13528462SApril.Chin@Sun.COM 		if(*np->nvname=='/')
13538462SApril.Chin@Sun.COM 			continue;
13548462SApril.Chin@Sun.COM 		nv_delete(np,dp,NV_NOFREE);
13558462SApril.Chin@Sun.COM 	}
13568462SApril.Chin@Sun.COM 	dtclose(shp->alias_tree);
13578462SApril.Chin@Sun.COM 	shp->alias_tree = inittree(shp,shtab_aliases);
13588462SApril.Chin@Sun.COM 	shp->last_root = shp->var_tree;
13598462SApril.Chin@Sun.COM 	shp->namespace = 0;
13608462SApril.Chin@Sun.COM 	shp->inuse_bits = 0;
13618462SApril.Chin@Sun.COM 	if(shp->userinit)
13628462SApril.Chin@Sun.COM 		(*shp->userinit)(shp, 1);
13638462SApril.Chin@Sun.COM 	if(shp->heredocs)
13648462SApril.Chin@Sun.COM 	{
13658462SApril.Chin@Sun.COM 		sfclose(shp->heredocs);
13668462SApril.Chin@Sun.COM 		shp->heredocs = 0;
13674887Schin 	}
13684887Schin 	/* remove locals */
13694887Schin 	sh_onstate(SH_INIT);
13708462SApril.Chin@Sun.COM 	nv_scan(shp->var_tree,sh_envnolocal,(void*)0,NV_EXPORT,0);
13718462SApril.Chin@Sun.COM 	nv_scan(shp->var_tree,sh_envnolocal,(void*)0,NV_ARRAY,NV_ARRAY);
13724887Schin 	sh_offstate(SH_INIT);
13738462SApril.Chin@Sun.COM 	memset(shp->st.trapcom,0,(shp->st.trapmax+1)*sizeof(char*));
13744887Schin 	memset((void*)&opt,0,sizeof(opt));
13754887Schin 	if(sh_isoption(SH_TRACKALL))
13764887Schin 		on_option(&opt,SH_TRACKALL);
13774887Schin 	if(sh_isoption(SH_EMACS))
13784887Schin 		on_option(&opt,SH_EMACS);
13794887Schin 	if(sh_isoption(SH_GMACS))
13804887Schin 		on_option(&opt,SH_GMACS);
13814887Schin 	if(sh_isoption(SH_VI))
13824887Schin 		on_option(&opt,SH_VI);
13834887Schin 	if(sh_isoption(SH_VIRAW))
13844887Schin 		on_option(&opt,SH_VIRAW);
13858462SApril.Chin@Sun.COM 	shp->options = opt;
13864887Schin 	/* set up new args */
13874887Schin 	if(argv)
13888462SApril.Chin@Sun.COM 		shp->arglist = sh_argcreate(argv);
13898462SApril.Chin@Sun.COM 	if(shp->arglist)
13908462SApril.Chin@Sun.COM 		sh_argreset(shp,shp->arglist,NIL(struct dolnod*));
13918462SApril.Chin@Sun.COM 	shp->envlist=0;
13928462SApril.Chin@Sun.COM 	shp->curenv = 0;
13938462SApril.Chin@Sun.COM 	shp->shname = error_info.id = strdup(shp->st.dolv[0]);
13944887Schin 	sh_offstate(SH_FORKED);
13958462SApril.Chin@Sun.COM 	shp->fn_depth = shp->dot_depth = 0;
13964887Schin 	sh_sigreset(0);
1397*10898Sroland.mainz@nrubsig.org 	if(!(SHLVL->nvalue.ip))
1398*10898Sroland.mainz@nrubsig.org 	{
1399*10898Sroland.mainz@nrubsig.org 		shlvl = 0;
1400*10898Sroland.mainz@nrubsig.org 		SHLVL->nvalue.ip = &shlvl;
1401*10898Sroland.mainz@nrubsig.org 		nv_onattr(SHLVL,NV_INTEGER|NV_EXPORT|NV_NOFREE);
1402*10898Sroland.mainz@nrubsig.org 	}
14038462SApril.Chin@Sun.COM 	*SHLVL->nvalue.ip +=1;
1404*10898Sroland.mainz@nrubsig.org 	shp->st.filename = strdup(shp->lastarg);
14054887Schin 	return(1);
14064887Schin }
14074887Schin 
14084887Schin /*
14094887Schin  * set when creating a local variable of this name
14104887Schin  */
14114887Schin Namfun_t *nv_cover(register Namval_t *np)
14124887Schin {
1413*10898Sroland.mainz@nrubsig.org 	if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS || np==ENVNOD)
14144887Schin 		return(np->nvfun);
14154887Schin #ifdef _hdr_locale
14164887Schin 	if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD)
14174887Schin 		return(np->nvfun);
14184887Schin #endif
14194887Schin 	 return(0);
14204887Schin }
14214887Schin 
14224887Schin static const char *shdiscnames[] = { "tilde", 0};
14234887Schin 
14248462SApril.Chin@Sun.COM #ifdef SHOPT_STATS
14258462SApril.Chin@Sun.COM struct Stats
14268462SApril.Chin@Sun.COM {
14278462SApril.Chin@Sun.COM 	Namfun_t	hdr;
14288462SApril.Chin@Sun.COM 	Shell_t		*sh;
14298462SApril.Chin@Sun.COM 	char		*nodes;
14308462SApril.Chin@Sun.COM 	int		numnodes;
14318462SApril.Chin@Sun.COM 	int		current;
14328462SApril.Chin@Sun.COM };
14338462SApril.Chin@Sun.COM 
14348462SApril.Chin@Sun.COM static Namval_t *next_stat(register Namval_t* np, Dt_t *root,Namfun_t *fp)
14358462SApril.Chin@Sun.COM {
14368462SApril.Chin@Sun.COM 	struct Stats *sp = (struct Stats*)fp;
14378462SApril.Chin@Sun.COM 	if(!root)
14388462SApril.Chin@Sun.COM 		sp->current = 0;
14398462SApril.Chin@Sun.COM 	else if(++sp->current>=sp->numnodes)
14408462SApril.Chin@Sun.COM 		return(0);
14418462SApril.Chin@Sun.COM 	return(nv_namptr(sp->nodes,sp->current));
14428462SApril.Chin@Sun.COM }
14438462SApril.Chin@Sun.COM 
14448462SApril.Chin@Sun.COM static Namval_t *create_stat(Namval_t *np,const char *name,int flag,Namfun_t *fp)
14458462SApril.Chin@Sun.COM {
14468462SApril.Chin@Sun.COM 	struct Stats		*sp = (struct Stats*)fp;
14478462SApril.Chin@Sun.COM 	register const char	*cp=name;
14488462SApril.Chin@Sun.COM 	register int		i=0,n;
14498462SApril.Chin@Sun.COM 	Namval_t		*nq=0;
14508462SApril.Chin@Sun.COM 	Shell_t			*shp = sp->sh;
14518462SApril.Chin@Sun.COM 	if(!name)
14528462SApril.Chin@Sun.COM 		return(SH_STATS);
14538462SApril.Chin@Sun.COM 	while((i=*cp++) && i != '=' && i != '+' && i!='[');
14548462SApril.Chin@Sun.COM 	n = (cp-1) -name;
14558462SApril.Chin@Sun.COM 	for(i=0; i < sp->numnodes; i++)
14568462SApril.Chin@Sun.COM 	{
14578462SApril.Chin@Sun.COM 		nq = nv_namptr(sp->nodes,i);
14588462SApril.Chin@Sun.COM 		if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0)
14598462SApril.Chin@Sun.COM 			goto found;
14608462SApril.Chin@Sun.COM 	}
14618462SApril.Chin@Sun.COM 	nq = 0;
14628462SApril.Chin@Sun.COM found:
14638462SApril.Chin@Sun.COM 	if(nq)
14648462SApril.Chin@Sun.COM 	{
14658462SApril.Chin@Sun.COM 		fp->last = (char*)&name[n];
14668462SApril.Chin@Sun.COM 		shp->last_table = SH_STATS;
14678462SApril.Chin@Sun.COM 	}
14688462SApril.Chin@Sun.COM 	else
14698462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np));
14708462SApril.Chin@Sun.COM 	return(nq);
14718462SApril.Chin@Sun.COM }
14728462SApril.Chin@Sun.COM 
14738462SApril.Chin@Sun.COM static const Namdisc_t stat_disc =
14748462SApril.Chin@Sun.COM {
14758462SApril.Chin@Sun.COM 	0, 0, 0, 0, 0,
14768462SApril.Chin@Sun.COM 	create_stat,
14778462SApril.Chin@Sun.COM 	0, 0,
14788462SApril.Chin@Sun.COM 	next_stat
14798462SApril.Chin@Sun.COM };
14808462SApril.Chin@Sun.COM 
14818462SApril.Chin@Sun.COM static char *name_stat(Namval_t *np, Namfun_t *fp)
14828462SApril.Chin@Sun.COM {
14838462SApril.Chin@Sun.COM 	Shell_t	*shp = sh_getinterp();
14848462SApril.Chin@Sun.COM 	sfprintf(shp->strbuf,".sh.stats.%s",np->nvname);
14858462SApril.Chin@Sun.COM 	return(sfstruse(shp->strbuf));
14868462SApril.Chin@Sun.COM }
14878462SApril.Chin@Sun.COM 
14888462SApril.Chin@Sun.COM static const Namdisc_t	stat_child_disc =
14898462SApril.Chin@Sun.COM {
14908462SApril.Chin@Sun.COM 	0,0,0,0,0,0,0,
14918462SApril.Chin@Sun.COM 	name_stat
14928462SApril.Chin@Sun.COM };
14938462SApril.Chin@Sun.COM 
14948462SApril.Chin@Sun.COM static Namfun_t	 stat_child_fun =
14958462SApril.Chin@Sun.COM {
14968462SApril.Chin@Sun.COM 	&stat_child_disc, 1, 0, sizeof(Namfun_t)
14978462SApril.Chin@Sun.COM };
14988462SApril.Chin@Sun.COM 
14998462SApril.Chin@Sun.COM static void stat_init(Shell_t *shp)
15008462SApril.Chin@Sun.COM {
15018462SApril.Chin@Sun.COM 	int		i,nstat = STAT_SUBSHELL+1;
15028462SApril.Chin@Sun.COM 	struct Stats	*sp = newof(0,struct Stats,1,nstat*NV_MINSZ);
15038462SApril.Chin@Sun.COM 	Namval_t	*np;
15048462SApril.Chin@Sun.COM 	sp->numnodes = nstat;
15058462SApril.Chin@Sun.COM 	sp->nodes = (char*)(sp+1);
15068462SApril.Chin@Sun.COM 	shp->stats = (int*)calloc(sizeof(int*),nstat);
15078462SApril.Chin@Sun.COM 	sp->sh = shp;
15088462SApril.Chin@Sun.COM 	for(i=0; i < nstat; i++)
15098462SApril.Chin@Sun.COM 	{
15108462SApril.Chin@Sun.COM 		np = nv_namptr(sp->nodes,i);
15118462SApril.Chin@Sun.COM 		np->nvfun = &stat_child_fun;
15128462SApril.Chin@Sun.COM 		np->nvname = (char*)shtab_stats[i].sh_name;
15138462SApril.Chin@Sun.COM 		nv_onattr(np,NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER);
15148462SApril.Chin@Sun.COM 		nv_setsize(np,10);
15158462SApril.Chin@Sun.COM 		np->nvalue.ip = &shp->stats[i];
15168462SApril.Chin@Sun.COM 	}
15178462SApril.Chin@Sun.COM 	sp->hdr.dsize = sizeof(struct Stats) + nstat*(sizeof(int)+NV_MINSZ);
15188462SApril.Chin@Sun.COM 	sp->hdr.disc = &stat_disc;
15198462SApril.Chin@Sun.COM 	nv_stack(SH_STATS,&sp->hdr);
15208462SApril.Chin@Sun.COM 	sp->hdr.nofree = 1;
15218462SApril.Chin@Sun.COM 	nv_setvtree(SH_STATS);
15228462SApril.Chin@Sun.COM }
15238462SApril.Chin@Sun.COM #else
15248462SApril.Chin@Sun.COM #   define stat_init(x)
15258462SApril.Chin@Sun.COM #endif /* SHOPT_STATS */
15268462SApril.Chin@Sun.COM 
15274887Schin /*
15284887Schin  * Initialize the shell name and alias table
15294887Schin  */
15304887Schin static Init_t *nv_init(Shell_t *shp)
15314887Schin {
15324887Schin 	Namval_t *np;
15334887Schin 	register Init_t *ip;
15344887Schin 	double d=0;
15354887Schin 	ip = newof(0,Init_t,1,0);
15364887Schin 	if(!ip)
15374887Schin 		return(0);
15388462SApril.Chin@Sun.COM 	shp->nvfun.last = (char*)shp;
15398462SApril.Chin@Sun.COM 	shp->nvfun.nofree = 1;
15404887Schin 	ip->sh = shp;
15414887Schin 	shp->var_base = shp->var_tree = inittree(shp,shtab_variables);
15428462SApril.Chin@Sun.COM 	SHLVL->nvalue.ip = &shlvl;
15434887Schin 	ip->IFS_init.hdr.disc = &IFS_disc;
15444887Schin 	ip->IFS_init.hdr.nofree = 1;
15458462SApril.Chin@Sun.COM 	ip->PATH_init.disc = &RESTRICTED_disc;
15468462SApril.Chin@Sun.COM 	ip->PATH_init.nofree = 1;
15478462SApril.Chin@Sun.COM 	ip->FPATH_init.disc = &RESTRICTED_disc;
15488462SApril.Chin@Sun.COM 	ip->FPATH_init.nofree = 1;
15498462SApril.Chin@Sun.COM 	ip->CDPATH_init.disc = &CDPATH_disc;
15508462SApril.Chin@Sun.COM 	ip->CDPATH_init.nofree = 1;
15518462SApril.Chin@Sun.COM 	ip->SHELL_init.disc = &RESTRICTED_disc;
15528462SApril.Chin@Sun.COM 	ip->SHELL_init.nofree = 1;
15538462SApril.Chin@Sun.COM 	ip->ENV_init.disc = &RESTRICTED_disc;
15548462SApril.Chin@Sun.COM 	ip->ENV_init.nofree = 1;
15558462SApril.Chin@Sun.COM 	ip->VISUAL_init.disc = &EDITOR_disc;
15568462SApril.Chin@Sun.COM 	ip->VISUAL_init.nofree = 1;
15578462SApril.Chin@Sun.COM 	ip->EDITOR_init.disc = &EDITOR_disc;
15588462SApril.Chin@Sun.COM 	ip->EDITOR_init.nofree = 1;
15598462SApril.Chin@Sun.COM 	ip->HISTFILE_init.disc = &HISTFILE_disc;
15608462SApril.Chin@Sun.COM 	ip->HISTFILE_init.nofree = 1;
15618462SApril.Chin@Sun.COM 	ip->HISTSIZE_init.disc = &HISTFILE_disc;
15628462SApril.Chin@Sun.COM 	ip->HISTSIZE_init.nofree = 1;
15638462SApril.Chin@Sun.COM 	ip->OPTINDEX_init.disc = &OPTINDEX_disc;
15648462SApril.Chin@Sun.COM 	ip->OPTINDEX_init.nofree = 1;
15654887Schin 	ip->SECONDS_init.hdr.disc = &SECONDS_disc;
15664887Schin 	ip->SECONDS_init.hdr.nofree = 1;
15674887Schin 	ip->RAND_init.hdr.disc = &RAND_disc;
15684887Schin 	ip->RAND_init.hdr.nofree = 1;
15694887Schin 	ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc;
15704887Schin 	ip->SH_MATCH_init.hdr.nofree = 1;
15718462SApril.Chin@Sun.COM 	ip->SH_VERSION_init.disc = &SH_VERSION_disc;
15728462SApril.Chin@Sun.COM 	ip->SH_VERSION_init.nofree = 1;
15738462SApril.Chin@Sun.COM 	ip->LINENO_init.disc = &LINENO_disc;
15748462SApril.Chin@Sun.COM 	ip->LINENO_init.nofree = 1;
15758462SApril.Chin@Sun.COM 	ip->L_ARG_init.disc = &L_ARG_disc;
15768462SApril.Chin@Sun.COM 	ip->L_ARG_init.nofree = 1;
15774887Schin #ifdef _hdr_locale
15788462SApril.Chin@Sun.COM 	ip->LC_TYPE_init.disc = &LC_disc;
15798462SApril.Chin@Sun.COM 	ip->LC_TYPE_init.nofree = 1;
15808462SApril.Chin@Sun.COM 	ip->LC_NUM_init.disc = &LC_disc;
15818462SApril.Chin@Sun.COM 	ip->LC_NUM_init.nofree = 1;
15828462SApril.Chin@Sun.COM 	ip->LC_COLL_init.disc = &LC_disc;
15838462SApril.Chin@Sun.COM 	ip->LC_COLL_init.nofree = 1;
15848462SApril.Chin@Sun.COM 	ip->LC_MSG_init.disc = &LC_disc;
15858462SApril.Chin@Sun.COM 	ip->LC_MSG_init.nofree = 1;
15868462SApril.Chin@Sun.COM 	ip->LC_ALL_init.disc = &LC_disc;
15878462SApril.Chin@Sun.COM 	ip->LC_ALL_init.nofree = 1;
15888462SApril.Chin@Sun.COM 	ip->LANG_init.disc = &LC_disc;
15898462SApril.Chin@Sun.COM 	ip->LANG_init.nofree = 1;
15904887Schin #endif /* _hdr_locale */
15914887Schin 	nv_stack(IFSNOD, &ip->IFS_init.hdr);
15928462SApril.Chin@Sun.COM 	nv_stack(PATHNOD, &ip->PATH_init);
15938462SApril.Chin@Sun.COM 	nv_stack(FPATHNOD, &ip->FPATH_init);
15948462SApril.Chin@Sun.COM 	nv_stack(CDPNOD, &ip->CDPATH_init);
15958462SApril.Chin@Sun.COM 	nv_stack(SHELLNOD, &ip->SHELL_init);
15968462SApril.Chin@Sun.COM 	nv_stack(ENVNOD, &ip->ENV_init);
15978462SApril.Chin@Sun.COM 	nv_stack(VISINOD, &ip->VISUAL_init);
15988462SApril.Chin@Sun.COM 	nv_stack(EDITNOD, &ip->EDITOR_init);
15998462SApril.Chin@Sun.COM 	nv_stack(HISTFILE, &ip->HISTFILE_init);
16008462SApril.Chin@Sun.COM 	nv_stack(HISTSIZE, &ip->HISTSIZE_init);
16018462SApril.Chin@Sun.COM 	nv_stack(OPTINDNOD, &ip->OPTINDEX_init);
16024887Schin 	nv_stack(SECONDS, &ip->SECONDS_init.hdr);
16038462SApril.Chin@Sun.COM 	nv_stack(L_ARGNOD, &ip->L_ARG_init);
16048462SApril.Chin@Sun.COM 	nv_putval(SECONDS, (char*)&d, NV_DOUBLE);
16054887Schin 	nv_stack(RANDNOD, &ip->RAND_init.hdr);
16064887Schin 	d = (shp->pid&RANDMASK);
16078462SApril.Chin@Sun.COM 	nv_putval(RANDNOD, (char*)&d, NV_DOUBLE);
16088462SApril.Chin@Sun.COM 	nv_stack(LINENO, &ip->LINENO_init);
16094887Schin 	nv_putsub(SH_MATCHNOD,(char*)0,10);
16104887Schin 	nv_onattr(SH_MATCHNOD,NV_RDONLY);
16114887Schin 	nv_stack(SH_MATCHNOD, &ip->SH_MATCH_init.hdr);
16128462SApril.Chin@Sun.COM 	nv_stack(SH_VERSIONNOD, &ip->SH_VERSION_init);
16134887Schin #ifdef _hdr_locale
16148462SApril.Chin@Sun.COM 	nv_stack(LCTYPENOD, &ip->LC_TYPE_init);
16158462SApril.Chin@Sun.COM 	nv_stack(LCALLNOD, &ip->LC_ALL_init);
16168462SApril.Chin@Sun.COM 	nv_stack(LCMSGNOD, &ip->LC_MSG_init);
16178462SApril.Chin@Sun.COM 	nv_stack(LCCOLLNOD, &ip->LC_COLL_init);
16188462SApril.Chin@Sun.COM 	nv_stack(LCNUMNOD, &ip->LC_NUM_init);
16198462SApril.Chin@Sun.COM 	nv_stack(LANGNOD, &ip->LANG_init);
16204887Schin #endif /* _hdr_locale */
16214887Schin 	(PPIDNOD)->nvalue.lp = (&shp->ppid);
16224887Schin 	(TMOUTNOD)->nvalue.lp = (&shp->st.tmout);
16234887Schin 	(MCHKNOD)->nvalue.lp = (&sh_mailchk);
16244887Schin 	(OPTINDNOD)->nvalue.lp = (&shp->st.optindex);
16254887Schin 	/* set up the seconds clock */
16264887Schin 	shp->alias_tree = inittree(shp,shtab_aliases);
16274887Schin 	shp->track_tree = dtopen(&_Nvdisc,Dtset);
16284887Schin 	shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins);
16294887Schin 	shp->fun_tree = dtopen(&_Nvdisc,Dtoset);
16304887Schin 	dtview(shp->fun_tree,shp->bltin_tree);
16314887Schin #if SHOPT_NAMESPACE
16324887Schin 	if(np = nv_mount(DOTSHNOD, "global", shp->var_tree))
16334887Schin 		nv_onattr(np,NV_RDONLY);
16344887Schin 	np = nv_search("namespace",nv_dict(DOTSHNOD),NV_ADD);
16354887Schin 	nv_putval(np,".sh.global",NV_RDONLY|NV_NOFREE);
16364887Schin 	nv_stack(np, &NSPACE_init);
16374887Schin #endif /* SHOPT_NAMESPACE */
16388462SApril.Chin@Sun.COM 	np = nv_mount(DOTSHNOD, "type", shp->typedict=dtopen(&_Nvdisc,Dtoset));
16394887Schin 	nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0);
16408462SApril.Chin@Sun.COM 	SH_LINENO->nvalue.ip = &shp->st.lineno;
16418462SApril.Chin@Sun.COM 	VERSIONNOD->nvalue.nrp = newof(0,struct Namref,1,0);
16428462SApril.Chin@Sun.COM         VERSIONNOD->nvalue.nrp->np = SH_VERSIONNOD;
16438462SApril.Chin@Sun.COM         VERSIONNOD->nvalue.nrp->root = nv_dict(DOTSHNOD);
16448462SApril.Chin@Sun.COM         VERSIONNOD->nvalue.nrp->table = DOTSHNOD;
16458462SApril.Chin@Sun.COM 	nv_onattr(VERSIONNOD,NV_RDONLY|NV_REF);
16468462SApril.Chin@Sun.COM 	stat_init(shp);
16474887Schin 	return(ip);
16484887Schin }
16494887Schin 
16504887Schin /*
16514887Schin  * initialize name-value pairs
16524887Schin  */
16534887Schin 
16544887Schin static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
16554887Schin {
16564887Schin 	register Namval_t *np;
16574887Schin 	register const struct shtable2 *tp;
16584887Schin 	register unsigned n = 0;
16594887Schin 	register Dt_t *treep;
16604887Schin 	Dt_t *base_treep, *dict;
16614887Schin 	for(tp=name_vals;*tp->sh_name;tp++)
16624887Schin 		n++;
16634887Schin 	np = (Namval_t*)calloc(n,sizeof(Namval_t));
16644887Schin 	if(!shp->bltin_nodes)
16658462SApril.Chin@Sun.COM 	{
16664887Schin 		shp->bltin_nodes = np;
16678462SApril.Chin@Sun.COM 		shp->bltin_nnodes = n;
16688462SApril.Chin@Sun.COM 	}
16694887Schin 	else if(name_vals==(const struct shtable2*)shtab_builtins)
16708462SApril.Chin@Sun.COM 	{
16714887Schin 		shp->bltin_cmds = np;
16728462SApril.Chin@Sun.COM 		nbltins = n;
16738462SApril.Chin@Sun.COM 	}
16744887Schin 	base_treep = treep = dtopen(&_Nvdisc,Dtoset);
16758462SApril.Chin@Sun.COM 	treep->user = (void*)shp;
16764887Schin 	for(tp=name_vals;*tp->sh_name;tp++,np++)
16774887Schin 	{
16784887Schin 		if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name))
16794887Schin 			np->nvname++;
16804887Schin 		else
16814887Schin 		{
16824887Schin 			np->nvname = (char*)tp->sh_name;
16834887Schin 			treep = base_treep;
16844887Schin 		}
16854887Schin 		np->nvenv = 0;
16864887Schin 		if(name_vals==(const struct shtable2*)shtab_builtins)
16874887Schin 			np->nvalue.bfp = ((struct shtable3*)tp)->sh_value;
16884887Schin 		else
16898462SApril.Chin@Sun.COM 		{
16908462SApril.Chin@Sun.COM 			if(name_vals == shtab_variables)
16918462SApril.Chin@Sun.COM 				np->nvfun = &sh.nvfun;
16924887Schin 			np->nvalue.cp = (char*)tp->sh_value;
16938462SApril.Chin@Sun.COM 		}
16944887Schin 		nv_setattr(np,tp->sh_number);
16954887Schin 		if(nv_istable(np))
16964887Schin 			nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset));
16974887Schin 		if(nv_isattr(np,NV_INTEGER))
16984887Schin 			nv_setsize(np,10);
16994887Schin 		else
17004887Schin 			nv_setsize(np,0);
17014887Schin 		dtinsert(treep,np);
17024887Schin 		if(nv_istable(np))
17034887Schin 			treep = dict;
17044887Schin 	}
17054887Schin 	return(treep);
17064887Schin }
17074887Schin 
17084887Schin /*
17094887Schin  * read in the process environment and set up name-value pairs
17104887Schin  * skip over items that are not name-value pairs
17114887Schin  */
17124887Schin 
17134887Schin static void env_init(Shell_t *shp)
17144887Schin {
17154887Schin 	register char *cp;
17164887Schin 	register Namval_t	*np;
17174887Schin 	register char **ep=environ;
17184887Schin 	register char *next=0;
17194887Schin #ifdef _ENV_H
17204887Schin 	shp->env = env_open(environ,3);
17214887Schin 	env_delete(shp->env,"_");
17224887Schin #endif
17234887Schin 	if(ep)
17244887Schin 	{
17254887Schin 		while(cp= *ep++)
17264887Schin 		{
17274887Schin 			if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=')
17284887Schin 				next = cp+4;
17294887Schin 			else if(np=nv_open(cp,shp->var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN|NV_NOFAIL)))
17304887Schin 			{
17314887Schin 				nv_onattr(np,NV_IMPORT);
17324887Schin 				np->nvenv = cp;
17334887Schin 				nv_close(np);
17344887Schin 			}
17358462SApril.Chin@Sun.COM 			else  /* swap with fron */
17368462SApril.Chin@Sun.COM 			{
17378462SApril.Chin@Sun.COM 				ep[-1] = environ[shp->nenv];
17388462SApril.Chin@Sun.COM 				environ[shp->nenv++] = cp;
17398462SApril.Chin@Sun.COM 			}
17404887Schin 		}
17414887Schin 		while(cp=next)
17424887Schin 		{
17434887Schin 			if(next = strchr(++cp,'='))
17444887Schin 				*next = 0;
17454887Schin 			np = nv_search(cp+2,shp->var_tree,NV_ADD);
17464887Schin 			if(nv_isattr(np,NV_IMPORT|NV_EXPORT))
17474887Schin 			{
17484887Schin 				int flag = *(unsigned char*)cp-' ';
17494887Schin 				int size = *(unsigned char*)(cp+1)-' ';
17504887Schin 				if((flag&NV_INTEGER) && size==0)
17514887Schin 				{
17524887Schin 					/* check for floating*/
17534887Schin 					char *ep,*val = nv_getval(np);
17544887Schin 					strtol(val,&ep,10);
17554887Schin 					if(*ep=='.' || *ep=='e' || *ep=='E')
17564887Schin 					{
17574887Schin 						char *lp;
17584887Schin 						flag |= NV_DOUBLE;
17594887Schin 						if(*ep=='.')
17604887Schin 						{
17614887Schin 							strtol(ep+1,&lp,10);
17624887Schin 							if(*lp)
17634887Schin 								ep = lp;
17644887Schin 						}
17654887Schin 						if(*ep && *ep!='.')
17664887Schin 						{
17674887Schin 							flag |= NV_EXPNOTE;
17684887Schin 							size = ep-val;
17694887Schin 						}
17704887Schin 						else
17714887Schin 							size = strlen(ep);
17724887Schin 						size--;
17734887Schin 					}
17744887Schin 				}
17754887Schin 				nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
17764887Schin 			}
17774887Schin 		}
17784887Schin 	}
17794887Schin #ifdef _ENV_H
17808462SApril.Chin@Sun.COM 	env_delete(shp->env,e_envmarker);
17814887Schin #endif
17824887Schin 	if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
17834887Schin 	{
17844887Schin 		nv_offattr(PWDNOD,NV_TAGGED);
17854887Schin 		path_pwd(0);
17864887Schin 	}
17874887Schin 	if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
17884887Schin 		sh_onoption(SH_RESTRICTED); /* restricted shell */
17894887Schin 	return;
17904887Schin }
17914887Schin 
17924887Schin /*
17934887Schin  * terminate shell and free up the space
17944887Schin  */
17954887Schin int sh_term(void)
17964887Schin {
17974887Schin 	sfdisc(sfstdin,SF_POPDISC);
17984887Schin 	free((char*)sh.outbuff);
17994887Schin 	stakset(NIL(char*),0);
18004887Schin 	return(0);
18014887Schin }
18024887Schin 
18034887Schin /* function versions of these */
18044887Schin 
18054887Schin #define DISABLE	/* proto workaround */
18064887Schin 
18074887Schin unsigned long sh_isoption DISABLE (int opt)
18084887Schin {
18094887Schin 	return(sh_isoption(opt));
18104887Schin }
18114887Schin 
18124887Schin unsigned long sh_onoption DISABLE (int opt)
18134887Schin {
18144887Schin 	return(sh_onoption(opt));
18154887Schin }
18164887Schin 
18174887Schin unsigned long sh_offoption DISABLE (int opt)
18184887Schin {
18194887Schin 	return(sh_offoption(opt));
18204887Schin }
18214887Schin 
18224887Schin void	sh_sigcheck DISABLE (void)
18234887Schin {
18244887Schin 	sh_sigcheck();
18254887Schin }
18264887Schin 
18274887Schin Dt_t*	sh_bltin_tree DISABLE (void)
18284887Schin {
18294887Schin 	return(sh.bltin_tree);
18304887Schin }
1831