xref: /titanic_52/usr/src/contrib/ast/src/cmd/ksh93/sh/init.c (revision 906afcb89d0412cc073b95c2d701a804a8cdb62c)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                  David Korn <dgk@research.att.com>                   *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  *
23  * Shell initialization
24  *
25  *   David Korn
26  *   AT&T Labs
27  *
28  */
29 
30 #include        "defs.h"
31 #include        <stak.h>
32 #include        <ccode.h>
33 #include        <pwd.h>
34 #include        <tmx.h>
35 #include        <regex.h>
36 #include        "variables.h"
37 #include        "path.h"
38 #include        "fault.h"
39 #include        "name.h"
40 #include	"edit.h"
41 #include	"jobs.h"
42 #include	"io.h"
43 #include	"shlex.h"
44 #include	"builtins.h"
45 #include	"FEATURE/time"
46 #include	"FEATURE/dynamic"
47 #include	"FEATURE/externs"
48 #include	"lexstates.h"
49 #include	"version.h"
50 
51 #if _hdr_wctype
52 #include	<ast_wchar.h>
53 #include	<wctype.h>
54 #endif
55 #if !_typ_wctrans_t
56 #undef	wctrans_t
57 #define wctrans_t	sh_wctrans_t
58 typedef long wctrans_t;
59 #endif
60 #if !_lib_wctrans
61 #undef	wctrans
62 #define wctrans		sh_wctrans
63 static wctrans_t wctrans(const char *name)
64 {
65 	if(strcmp(name,e_tolower)==0)
66 		return(1);
67 	else if(strcmp(name,e_toupper)==0)
68 		return(2);
69 	return(0);
70 }
71 #endif
72 #if !_lib_towctrans
73 #undef	towctrans
74 #define towctrans	sh_towctrans
75 static int towctrans(int c, wctrans_t t)
76 {
77 	if(t==1 && isupper(c))
78 		c = tolower(c);
79 	else if(t==2 && islower(c))
80 		c = toupper(c);
81 	return(c);
82 }
83 #endif
84 
85 char e_version[]	= "\n@(#)$Id: Version "
86 #if SHOPT_AUDIT
87 #define ATTRS		1
88 			"A"
89 #endif
90 #if SHOPT_BASH
91 #define ATTRS		1
92 			"B"
93 #endif
94 #if SHOPT_COSHELL
95 #define ATTRS		1
96 			"J"
97 #else
98 #if SHOPT_BGX
99 #define ATTRS		1
100 			"j"
101 #endif
102 #endif
103 #if SHOPT_ACCT
104 #define ATTRS		1
105 			"L"
106 #endif
107 #if SHOPT_MULTIBYTE
108 #define ATTRS		1
109 			"M"
110 #endif
111 #if SHOPT_PFSH && _hdr_exec_attr
112 #define ATTRS		1
113 			"P"
114 #endif
115 #if SHOPT_REGRESS
116 #define ATTRS		1
117 			"R"
118 #endif
119 #if ATTRS
120 			" "
121 #endif
122 			SH_RELEASE " $\0\n";
123 
124 #if SHOPT_BASH
125     extern void bash_init(Shell_t*,int);
126 #endif
127 
128 #define RANDMASK	0x7fff
129 
130 #ifndef ARG_MAX
131 #   define ARG_MAX	(1*1024*1024)
132 #endif
133 #ifndef CHILD_MAX
134 #   define CHILD_MAX	(1*1024)
135 #endif
136 #ifndef CLK_TCK
137 #   define CLK_TCK	60
138 #endif /* CLK_TCK */
139 
140 #ifndef environ
141     extern char	**environ;
142 #endif
143 
144 #undef	getconf
145 #define getconf(x)	strtol(astconf(x,NiL,NiL),NiL,0)
146 
147 struct seconds
148 {
149 	Namfun_t	hdr;
150 	Shell_t		*sh;
151 };
152 
153 struct rand
154 {
155 	Namfun_t	hdr;
156 	Shell_t		*sh;
157 	int32_t		rand_last;
158 };
159 
160 struct ifs
161 {
162 	Namfun_t	hdr;
163 	Namval_t	*ifsnp;
164 };
165 
166 struct match
167 {
168 	Namfun_t	hdr;
169 	const char	*v;
170 	char		*val;
171 	char		*rval[2];
172 	regoff_t	*match;
173 	char		node[NV_MINSZ+sizeof(char*)];
174 	regoff_t	first;
175 	int		vsize;
176 	int		nmatch;
177 	int		index;
178 	int		lastsub[2];
179 };
180 
181 typedef struct _init_
182 {
183 	Shell_t		*sh;
184 #if SHOPT_FS_3D
185 	Namfun_t	VPATH_init;
186 #endif /* SHOPT_FS_3D */
187 	struct ifs	IFS_init;
188 	Namfun_t	PATH_init;
189 	Namfun_t	FPATH_init;
190 	Namfun_t	CDPATH_init;
191 	Namfun_t	SHELL_init;
192 	Namfun_t	ENV_init;
193 	Namfun_t	VISUAL_init;
194 	Namfun_t	EDITOR_init;
195 	Namfun_t	HISTFILE_init;
196 	Namfun_t	HISTSIZE_init;
197 	Namfun_t	OPTINDEX_init;
198 	struct seconds	SECONDS_init;
199 	struct rand	RAND_init;
200 	Namfun_t	LINENO_init;
201 	Namfun_t	L_ARG_init;
202 	Namfun_t	SH_VERSION_init;
203 	struct match	SH_MATCH_init;
204 	Namfun_t	SH_MATH_init;
205 #if SHOPT_COSHELL
206 	Namfun_t	SH_JOBPOOL_init;
207 #endif /* SHOPT_COSHELL */
208 #ifdef _hdr_locale
209 	Namfun_t	LC_TYPE_init;
210 	Namfun_t	LC_NUM_init;
211 	Namfun_t	LC_COLL_init;
212 	Namfun_t	LC_MSG_init;
213 	Namfun_t	LC_ALL_init;
214 	Namfun_t	LANG_init;
215 #endif /* _hdr_locale */
216 } Init_t;
217 
218 static Init_t		*ip;
219 static int		lctype;
220 static int		nbltins;
221 static void		env_init(Shell_t*);
222 static Init_t		*nv_init(Shell_t*);
223 static Dt_t		*inittree(Shell_t*,const struct shtable2*);
224 static int		shlvl;
225 
226 #ifdef _WINIX
227 #   define EXE	"?(.exe)"
228 #else
229 #   define EXE
230 #endif
231 
232 static int		rand_shift;
233 
234 
235 /*
236  * Invalidate all path name bindings
237  */
238 static void rehash(register Namval_t *np,void *data)
239 {
240 	NOT_USED(data);
241 	nv_onattr(np,NV_NOALIAS);
242 }
243 
244 /*
245  * out of memory routine for stak routines
246  */
247 static char *nospace(int unused)
248 {
249 	NOT_USED(unused);
250 	errormsg(SH_DICT,ERROR_exit(3),e_nospace);
251 	return(NIL(char*));
252 }
253 
254 /* Trap for VISUAL and EDITOR variables */
255 static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
256 {
257 	register const char *cp, *name=nv_name(np);
258 	register int	newopt=0;
259 	Shell_t *shp = nv_shell(np);
260 	if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD)))
261 		goto done;
262 	if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD)))))
263 		goto done;
264 	/* turn on vi or emacs option if editor name is either*/
265 	cp = path_basename(cp);
266 	if(strmatch(cp,"*[Vv][Ii]*"))
267 		newopt=SH_VI;
268 	else if(strmatch(cp,"*gmacs*"))
269 		newopt=SH_GMACS;
270 	else if(strmatch(cp,"*macs*"))
271 		newopt=SH_EMACS;
272 	if(newopt)
273 	{
274 		sh_offoption(SH_VI);
275 		sh_offoption(SH_EMACS);
276 		sh_offoption(SH_GMACS);
277 		sh_onoption(newopt);
278 	}
279 done:
280 	nv_putv(np, val, flags, fp);
281 }
282 
283 /* Trap for HISTFILE and HISTSIZE variables */
284 static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
285 {
286 	Shell_t *shp = nv_shell(np);
287 	void 	*histopen = NULL;
288 	char	*cp;
289 	if( shp ) {
290 	    histopen = shp->gd->hist_ptr;
291 	}
292 	if(val && histopen)
293 	{
294 		if(np==HISTFILE && (cp=nv_getval(np)) && strcmp(val,cp)==0)
295 			return;
296 		if(np==HISTSIZE && sh_arith(shp,val)==nv_getnum(HISTSIZE))
297 			return;
298 		hist_close(shp->gd->hist_ptr);
299 	}
300 	nv_putv(np, val, flags, fp);
301 	if(histopen)
302 	{
303 		if(val)
304 			sh_histinit(shp);
305 		else
306 			hist_close(histopen);
307 	}
308 }
309 
310 /* Trap for OPTINDEX */
311 static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp)
312 {
313 	Shell_t *shp = nv_shell(np);
314 	shp->st.opterror = shp->st.optchar = 0;
315 	nv_putv(np, val, flags, fp);
316 	if(!val)
317 		nv_disc(np,fp,NV_POP);
318 }
319 
320 static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
321 {
322 	return((Sfdouble_t)*np->nvalue.lp);
323 }
324 
325 static Namfun_t *clone_optindex(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
326 {
327 	Namfun_t *dp = (Namfun_t*)malloc(sizeof(Namfun_t));
328 	memcpy((void*)dp,(void*)fp,sizeof(Namfun_t));
329 	mp->nvalue.lp = np->nvalue.lp;
330 	dp->nofree = 0;
331 	return(dp);
332 }
333 
334 
335 /* Trap for restricted variables FPATH, PATH, SHELL, ENV */
336 static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
337 {
338 	Shell_t *shp = nv_shell(np);
339 	int	path_scoped = 0, fpath_scoped=0;
340 	Pathcomp_t *pp;
341 	char *name = nv_name(np);
342 	if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
343 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
344 	if(np==PATHNOD	|| (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
345 	{
346 		nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
347 		if(path_scoped && !val)
348 			val = PATHNOD->nvalue.cp;
349 	}
350 	if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0)
351 		 return;
352 	if(np==FPATHNOD	|| (fpath_scoped=(strcmp(name,FPATHNOD->nvname)==0)))
353 		shp->pathlist = (void*)path_unsetfpath(shp);
354 	nv_putv(np, val, flags, fp);
355 	shp->universe = 0;
356 	if(shp->pathlist)
357 	{
358 		val = np->nvalue.cp;
359 		if(np==PATHNOD || path_scoped)
360 			pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_PATH);
361 		else if(val && (np==FPATHNOD || fpath_scoped))
362 			pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
363 		else
364 			return;
365 		if(shp->pathlist = (void*)pp)
366 			pp->shp = shp;
367 		if(!val && (flags&NV_NOSCOPE))
368 		{
369 			Namval_t *mp = dtsearch(shp->var_tree,np);
370 			if(mp && (val=nv_getval(mp)))
371 				nv_putval(mp,val,NV_RDONLY);
372 		}
373 #if 0
374 sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val);
375 path_dump((Pathcomp_t*)shp->pathlist);
376 #endif
377 	}
378 }
379 
380 static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
381 {
382 	Pathcomp_t *pp;
383 	Shell_t *shp = nv_shell(np);
384 	nv_putv(np, val, flags, fp);
385 	if(!shp->cdpathlist)
386 		return;
387 	val = np->nvalue.cp;
388 	pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH);
389 	if(shp->cdpathlist = (void*)pp)
390 		pp->shp = shp;
391 }
392 
393 #ifdef _hdr_locale
394     /*
395      * This function needs to be modified to handle international
396      * error message translations
397      */
398 #if ERROR_VERSION >= 20000101L
399     static char* msg_translate(const char* catalog, const char* message)
400     {
401 	NOT_USED(catalog);
402 	return((char*)message);
403     }
404 #else
405     static char* msg_translate(const char* message, int type)
406     {
407 	NOT_USED(type);
408 	return((char*)message);
409     }
410 #endif
411 
412     /* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */
413     static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp)
414     {
415 	Shell_t *shp = nv_shell(np);
416 	int type;
417 	char *name = nv_name(np);
418 	if(name==(LCALLNOD)->nvname)
419 		type = LC_ALL;
420 	else if(name==(LCTYPENOD)->nvname)
421 		type = LC_CTYPE;
422 	else if(name==(LCMSGNOD)->nvname)
423 		type = LC_MESSAGES;
424 	else if(name==(LCCOLLNOD)->nvname)
425 		type = LC_COLLATE;
426 	else if(name==(LCNUMNOD)->nvname)
427 		type = LC_NUMERIC;
428 #ifdef LC_LANG
429 	else if(name==(LANGNOD)->nvname)
430 		type = LC_LANG;
431 #else
432 #define LC_LANG		LC_ALL
433 	else if(name==(LANGNOD)->nvname && (!(name=nv_getval(LCALLNOD)) || !*name))
434 		type = LC_LANG;
435 #endif
436 	else
437 		type= -1;
438 	if(!sh_isstate(SH_INIT) && (type>=0 || type==LC_ALL || type==LC_LANG))
439 	{
440 		char*		r;
441 #ifdef AST_LC_setenv
442 		ast.locale.set |= AST_LC_setenv;
443 #endif
444 		r = setlocale(type,val?val:"");
445 #ifdef AST_LC_setenv
446 		ast.locale.set ^= AST_LC_setenv;
447 #endif
448 		if(!r && val)
449 		{
450 			if(!sh_isstate(SH_INIT) || shp->login_sh==0)
451 				errormsg(SH_DICT,0,e_badlocale,val);
452 			return;
453 		}
454 	}
455 	nv_putv(np, val, flags, fp);
456 	if(CC_NATIVE!=CC_ASCII && (type==LC_ALL || type==LC_LANG || type==LC_CTYPE))
457 	{
458 		if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
459 			free((void*)sh_lexstates[ST_BEGIN]);
460 		lctype++;
461 		if(ast.locale.set&(1<<AST_LC_CTYPE))
462 		{
463 			register int c;
464 			char *state[4];
465 			sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
466 			memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
467 			sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
468 			memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
469 			sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
470 			memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
471 			sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
472 			memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
473 			for(c=0; c<(1<<CHAR_BIT); c++)
474 			{
475 				if(state[0][c]!=S_REG)
476 					continue;
477 				if(state[2][c]!=S_ERR)
478 					continue;
479 				if(isblank(c))
480 				{
481 					state[0][c]=0;
482 					state[1][c]=S_BREAK;
483 					state[2][c]=S_BREAK;
484 					continue;
485 				}
486 				if(!isalpha(c))
487 					continue;
488 				state[0][c]=S_NAME;
489 				if(state[1][c]==S_REG)
490 					state[1][c]=0;
491 				state[2][c]=S_ALP;
492 				if(state[3][c]==S_ERR)
493 					state[3][c]=0;
494 			}
495 		}
496 		else
497 		{
498 			sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
499 			sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
500 			sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
501 			sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
502 		}
503 	}
504 #if ERROR_VERSION < 20000101L
505 	if(type==LC_ALL || type==LC_MESSAGES)
506 		error_info.translate = msg_translate;
507 #endif
508     }
509 #endif /* _hdr_locale */
510 
511 /* Trap for IFS assignment and invalidates state table */
512 static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
513 {
514 	register struct ifs *ip = (struct ifs*)fp;
515 	ip->ifsnp = 0;
516 	if(!val)
517 	{
518 		fp = nv_stack(np, NIL(Namfun_t*));
519 		if(fp && !fp->nofree)
520 		{
521 			free((void*)fp);
522 			fp = 0;
523 		}
524 	}
525 	if(val != np->nvalue.cp)
526 		nv_putv(np, val, flags, fp);
527 	if(!val)
528 	{
529 		if(fp)
530 			fp->next = np->nvfun;
531 		np->nvfun = fp;
532 	}
533 }
534 
535 /*
536  * This is the lookup function for IFS
537  * It keeps the sh.ifstable up to date
538  */
539 static char* get_ifs(register Namval_t* np, Namfun_t *fp)
540 {
541 	register struct ifs *ip = (struct ifs*)fp;
542 	register char *cp, *value;
543 	register int c,n;
544 	register Shell_t *shp = nv_shell(np);
545 	value = nv_getv(np,fp);
546 	if(np!=ip->ifsnp)
547 	{
548 		ip->ifsnp = np;
549 		memset(shp->ifstable,0,(1<<CHAR_BIT));
550 		if(cp=value)
551 		{
552 #if SHOPT_MULTIBYTE
553 			while(n=mbsize(cp),c= *(unsigned char*)cp)
554 #else
555 			while(c= *(unsigned char*)cp++)
556 #endif /* SHOPT_MULTIBYTE */
557 			{
558 #if SHOPT_MULTIBYTE
559 				cp++;
560 				if(n>1)
561 				{
562 					cp += (n-1);
563 					shp->ifstable[c] = S_MBYTE;
564 					continue;
565 				}
566 #endif /* SHOPT_MULTIBYTE */
567 				n = S_DELIM;
568 				if(c== *cp)
569 					cp++;
570 				else if(c=='\n')
571 					n = S_NL;
572 				else if(isspace(c))
573 					n = S_SPACE;
574 				shp->ifstable[c] = n;
575 			}
576 		}
577 		else
578 		{
579 			shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE;
580 			shp->ifstable['\n'] = S_NL;
581 		}
582 	}
583 	return(value);
584 }
585 
586 /*
587  * these functions are used to get and set the SECONDS variable
588  */
589 #ifdef timeofday
590 #   define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
591 #   define tms	timeval
592 #else
593 #   define dtime(tp)	(((double)times(tp))/shgd->lim.clk_tck)
594 #   define timeofday(a)
595 #endif
596 
597 static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
598 {
599 	double d;
600 	struct tms tp;
601 	if(!val)
602 	{
603 		nv_putv(np, val, flags, fp);
604 		fp = nv_stack(np, NIL(Namfun_t*));
605 		if(fp && !fp->nofree)
606 			free((void*)fp);
607 		return;
608 	}
609 	if(!np->nvalue.dp)
610 	{
611 		nv_setsize(np,3);
612 		nv_onattr(np,NV_DOUBLE);
613 		np->nvalue.dp = new_of(double,0);
614 	}
615 	nv_putv(np, val, flags, fp);
616 	d = *np->nvalue.dp;
617 	timeofday(&tp);
618 	*np->nvalue.dp = dtime(&tp)-d;
619 }
620 
621 static char* get_seconds(register Namval_t* np, Namfun_t *fp)
622 {
623 	Shell_t *shp = nv_shell(np);
624 	register int places = nv_size(np);
625 	struct tms tp;
626 	double d, offset = (np->nvalue.dp?*np->nvalue.dp:0);
627 	NOT_USED(fp);
628 	timeofday(&tp);
629 	d = dtime(&tp)- offset;
630 	sfprintf(shp->strbuf,"%.*f",places,d);
631 	return(sfstruse(shp->strbuf));
632 }
633 
634 static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp)
635 {
636 	struct tms tp;
637 	double offset = (np->nvalue.dp?*np->nvalue.dp:0);
638 	NOT_USED(fp);
639 	timeofday(&tp);
640 	return(dtime(&tp)- offset);
641 }
642 
643 /*
644  * These three functions are used to get and set the RANDOM variable
645  */
646 static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
647 {
648 	struct rand *rp = (struct rand*)fp;
649 	register long n;
650 	if(!val)
651 	{
652 		fp = nv_stack(np, NIL(Namfun_t*));
653 		if(fp && !fp->nofree)
654 			free((void*)fp);
655 		_nv_unset(np,0);
656 		return;
657 	}
658 	if(flags&NV_INTEGER)
659 		n = *(double*)val;
660 	else
661 		n = sh_arith(rp->sh,val);
662 	srand((int)(n&RANDMASK));
663 	rp->rand_last = -1;
664 	if(!np->nvalue.lp)
665 		np->nvalue.lp = &rp->rand_last;
666 }
667 
668 /*
669  * get random number in range of 0 - 2**15
670  * never pick same number twice in a row
671  */
672 static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp)
673 {
674 	register long cur, last= *np->nvalue.lp;
675 	NOT_USED(fp);
676 	do
677 		cur = (rand()>>rand_shift)&RANDMASK;
678 	while(cur==last);
679 	*np->nvalue.lp = cur;
680 	return((Sfdouble_t)cur);
681 }
682 
683 static char* get_rand(register Namval_t* np, Namfun_t *fp)
684 {
685 	register long n = nget_rand(np,fp);
686 	return(fmtbase(n, 10, 0));
687 }
688 
689 /*
690  * These three routines are for LINENO
691  */
692 static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp)
693 {
694 	double d=1;
695 	if(error_info.line >0)
696 		d = error_info.line;
697 	else if(error_info.context && error_info.context->line>0)
698 		d = error_info.context->line;
699 	NOT_USED(np);
700 	NOT_USED(fp);
701 	return(d);
702 }
703 
704 static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
705 {
706 	register long n;
707 	Shell_t *shp = nv_shell(np);
708 	if(!val)
709 	{
710 		fp = nv_stack(np, NIL(Namfun_t*));
711 		if(fp && !fp->nofree)
712 			free((void*)fp);
713 		_nv_unset(np,0);
714 		return;
715 	}
716 	if(flags&NV_INTEGER)
717 		n = *(double*)val;
718 	else
719 		n = sh_arith(shp,val);
720 	shp->st.firstline += nget_lineno(np,fp)+1-n;
721 }
722 
723 static char* get_lineno(register Namval_t* np, Namfun_t *fp)
724 {
725 	register long n = nget_lineno(np,fp);
726 	return(fmtbase(n, 10, 0));
727 }
728 
729 static char* get_lastarg(Namval_t* np, Namfun_t *fp)
730 {
731 	Shell_t	*shp = nv_shell(np);
732 	char	*cp;
733 	int	pid;
734         if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*')
735 		nv_putval(np,cp+1,0);
736 	return(shp->lastarg);
737 }
738 
739 static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp)
740 {
741 	Shell_t *shp = nv_shell(np);
742 	if(flags&NV_INTEGER)
743 	{
744 		sfprintf(shp->strbuf,"%.*g",12,*((double*)val));
745 		val = sfstruse(shp->strbuf);
746 	}
747 	if(val)
748 		val = strdup(val);
749 	if(shp->lastarg && !nv_isattr(np,NV_NOFREE))
750 		free((void*)shp->lastarg);
751 	else
752 		nv_offattr(np,NV_NOFREE);
753 	shp->lastarg = (char*)val;
754 	nv_offattr(np,NV_EXPORT);
755 	np->nvenv = 0;
756 }
757 
758 static int hasgetdisc(register Namfun_t *fp)
759 {
760         while(fp && !fp->disc->getnum && !fp->disc->getval)
761                 fp = fp->next;
762 	return(fp!=0);
763 }
764 
765 /*
766  * store the most recent value for use in .sh.match
767  * treat .sh.match as a two dimensional array
768  */
769 void sh_setmatch(Shell_t *shp,const char *v, int vsize, int nmatch, regoff_t match[],int index)
770 {
771 	struct match	*mp = &ip->SH_MATCH_init;
772 	Namval_t	*np = nv_namptr(mp->node,0);
773 	register int	i,n,x, savesub=shp->subshell;
774 	Namarr_t	*ap = nv_arrayptr(SH_MATCHNOD);
775 	shp->subshell = 0;
776 #ifndef SHOPT_2DMATCH
777 	index = 0;
778 #else
779 	if(index==0)
780 #endif /* SHOPT_2DMATCH */
781 	{
782 		if(ap->hdr.next != &mp->hdr)
783 		{
784 			free((void*)ap);
785 			ap = nv_arrayptr(np);
786 			SH_MATCHNOD->nvfun = &ap->hdr;
787 		}
788 		if(ap)
789 		{
790 			ap->nelem &= ~ARRAY_SCAN;
791 			i = array_elem(ap);
792 			ap->nelem++;
793 			while(--i>= 0)
794 			{
795 				nv_putsub(SH_MATCHNOD, (char*)0,i);
796 				_nv_unset(SH_MATCHNOD,NV_RDONLY);
797 			}
798 			ap->nelem--;
799 		}
800 		if(!nv_hasdisc(SH_MATCHNOD,mp->hdr.disc))
801 			nv_disc(SH_MATCHNOD,&mp->hdr,NV_LAST);
802 		if(nmatch)
803 			nv_putsub(SH_MATCHNOD, NIL(char*), (nmatch-1)|ARRAY_FILL|ARRAY_SETSUB);
804 		ap = nv_arrayptr(SH_MATCHNOD);
805 		ap->nelem = mp->nmatch = nmatch;
806 		mp->v = v;
807 		mp->first = match[0];
808 	}
809 #ifdef SHOPT_2DMATCH
810 	else
811 	{
812 		if(index==1)
813 		{
814 			np->nvalue.cp = Empty;
815 			np->nvfun = SH_MATCHNOD->nvfun;
816 			nv_onattr(np,NV_NOFREE|NV_ARRAY);
817 			SH_MATCHNOD->nvfun = 0;
818 			for(i=0; i < mp->nmatch; i++)
819 			{
820 				nv_putsub(SH_MATCHNOD, (char*)0, i);
821 				nv_arraychild(SH_MATCHNOD, np,0);
822 			}
823 			if(ap = nv_arrayptr(SH_MATCHNOD))
824 				ap->nelem = mp->nmatch;
825 		}
826 		ap = nv_arrayptr(np);
827 		nv_putsub(np, NIL(char*), index|ARRAY_FILL|ARRAY_SETSUB);
828 	}
829 #endif /* SHOPT_2DMATCH */
830 	shp->subshell = savesub;
831 	index *= 2*mp->nmatch;
832 	if(mp->nmatch)
833 	{
834 		for(n=mp->first+(mp->v-v),vsize=0,i=0; i < 2*nmatch; i++)
835 		{
836 			if(match[i]>=0 && (match[i] - n) > vsize)
837 				vsize = match[i] -n;
838 		}
839 		i = (index+2*mp->nmatch)*sizeof(match[0]);
840 		if((i+vsize) >= mp->vsize)
841 		{
842 			if(mp->vsize)
843 				mp->match = (int*)realloc(mp->match,i+vsize+1);
844 			else
845 				mp->match = (int*)malloc(i+vsize+1);
846 			mp->vsize = i+vsize+1;
847 		}
848 		mp->val =  ((char*)mp->match)+i;
849 		memcpy(mp->match+index,match,nmatch*2*sizeof(match[0]));
850 		for(x=0,i=0; i < 2*nmatch; i++)
851 		{
852 			if(match[i]>=0)
853 				mp->match[index+i] -= n;
854 			else
855 				x=1;
856 
857 		}
858 		ap->nelem -= x;
859 		while(i < 2*mp->nmatch)
860 			mp->match[index+i++] = -1;
861 		memcpy(mp->val,v+n,vsize);
862 		mp->val[vsize] = 0;
863 		mp->lastsub[0] = mp->lastsub[1] = -1;
864 	}
865 }
866 
867 #define array_scan(np)	((nv_arrayptr(np)->nelem&ARRAY_SCAN))
868 
869 static char* get_match(register Namval_t* np, Namfun_t *fp)
870 {
871 	struct match	*mp = (struct match*)fp;
872 	int		sub,sub2=0,n,i =!mp->index;
873 	char		*val;
874 	sub = nv_aindex(SH_MATCHNOD);
875 	if(np!=SH_MATCHNOD)
876 		sub2 = nv_aindex(np);
877 	if(sub>=mp->nmatch)
878 		return(0);
879 	if(sub2>0)
880 		sub += sub2*mp->nmatch;
881 	if(sub==mp->lastsub[!i])
882 		return(mp->rval[!i]);
883 	else if(sub==mp->lastsub[i])
884 		return(mp->rval[i]);
885 	n = mp->match[2*sub+1]-mp->match[2*sub];
886 	if(n<=0)
887 		return(mp->match[2*sub]<0?Empty:"");
888 	val = mp->val+mp->match[2*sub];
889 	if(mp->val[mp->match[2*sub+1]]==0)
890 		return(val);
891 	mp->index = i;
892 	if(mp->rval[i])
893 	{
894 		free((void*)mp->rval[i]);
895 		mp->rval[i] = 0;
896 	}
897 	mp->rval[i] = (char*)malloc(n+1);
898 	mp->lastsub[i] = sub;
899 	memcpy(mp->rval[i],val,n);
900 	mp->rval[i][n] = 0;
901 	return(mp->rval[i]);
902 }
903 
904 static const Namdisc_t SH_MATCH_disc  = { sizeof(struct match), 0, get_match };
905 
906 static char* get_version(register Namval_t* np, Namfun_t *fp)
907 {
908 	return(nv_getv(np,fp));
909 }
910 
911 static Sfdouble_t nget_version(register Namval_t* np, Namfun_t *fp)
912 {
913 	register const char	*cp = e_version + strlen(e_version)-10;
914 	register int		c;
915 	Sflong_t		t = 0;
916 	NOT_USED(fp);
917 
918 	while (c = *cp++)
919 		if (c >= '0' && c <= '9')
920 		{
921 			t *= 10;
922 			t += c - '0';
923 		}
924 	return((Sfdouble_t)t);
925 }
926 
927 static const Namdisc_t SH_VERSION_disc	= {  0, 0, get_version, nget_version };
928 
929 #if SHOPT_FS_3D
930     /*
931      * set or unset the mappings given a colon separated list of directories
932      */
933     static void vpath_set(char *str, int mode)
934     {
935 	register char *lastp, *oldp=str, *newp=strchr(oldp,':');
936 	if(!shgd->lim.fs3d)
937 		return;
938 	while(newp)
939 	{
940 		*newp++ = 0;
941 		if(lastp=strchr(newp,':'))
942 			*lastp = 0;
943 		mount((mode?newp:""),oldp,FS3D_VIEW,0);
944 		newp[-1] = ':';
945 		oldp = newp;
946 		newp=lastp;
947 	}
948     }
949 
950     /* catch vpath assignments */
951     static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
952     {
953 	register char *cp;
954 	if(cp = nv_getval(np))
955 		vpath_set(cp,0);
956 	if(val)
957 		vpath_set((char*)val,1);
958 	nv_putv(np,val,flags,fp);
959     }
960     static const Namdisc_t VPATH_disc	= { 0, put_vpath  };
961     static Namfun_t VPATH_init	= { &VPATH_disc, 1  };
962 #endif /* SHOPT_FS_3D */
963 
964 
965 static const Namdisc_t IFS_disc		= {  sizeof(struct ifs), put_ifs, get_ifs };
966 const Namdisc_t RESTRICTED_disc	= {  sizeof(Namfun_t), put_restricted };
967 static const Namdisc_t CDPATH_disc	= {  sizeof(Namfun_t), put_cdpath };
968 static const Namdisc_t EDITOR_disc	= {  sizeof(Namfun_t), put_ed };
969 static const Namdisc_t HISTFILE_disc	= {  sizeof(Namfun_t), put_history };
970 static const Namdisc_t OPTINDEX_disc	= {  sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex };
971 static const Namdisc_t SECONDS_disc	= {  sizeof(struct seconds), put_seconds, get_seconds, nget_seconds };
972 static const Namdisc_t RAND_disc	= {  sizeof(struct rand), put_rand, get_rand, nget_rand };
973 static const Namdisc_t LINENO_disc	= {  sizeof(Namfun_t), put_lineno, get_lineno, nget_lineno };
974 static const Namdisc_t L_ARG_disc	= {  sizeof(Namfun_t), put_lastarg, get_lastarg };
975 
976 
977 #define MAX_MATH_ARGS	3
978 
979 static char *name_math(Namval_t *np, Namfun_t *fp)
980 {
981 	Shell_t		*shp = sh_getinterp();
982 	sfprintf(shp->strbuf,".sh.math.%s",np->nvname);
983 	return(sfstruse(shp->strbuf));
984 }
985 
986 static const Namdisc_t	math_child_disc =
987 {
988 	0,0,0,0,0,0,0,
989 	name_math
990 };
991 
992 static Namfun_t	 math_child_fun =
993 {
994 	&math_child_disc, 1, 0, sizeof(Namfun_t)
995 };
996 
997 static void math_init(Shell_t *shp)
998 {
999 	Namval_t	*np;
1000 	char		*name;
1001 	int		i;
1002 	shp->mathnodes = (char*)calloc(1,MAX_MATH_ARGS*(NV_MINSZ+5));
1003 	name = shp->mathnodes+MAX_MATH_ARGS*NV_MINSZ;
1004 	for(i=0; i < MAX_MATH_ARGS; i++)
1005 	{
1006 		np = nv_namptr(shp->mathnodes,i);
1007 		np->nvfun = &math_child_fun;
1008 		memcpy(name,"arg",3);
1009 		name[3] = '1'+i;
1010 		np->nvname = name;
1011 		name+=5;
1012 		nv_onattr(np,NV_MINIMAL|NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
1013 	}
1014 }
1015 
1016 static Namval_t *create_math(Namval_t *np,const char *name,int flag,Namfun_t *fp)
1017 {
1018 	Shell_t		*shp = nv_shell(np);
1019 	if(!name)
1020 		return(SH_MATHNOD);
1021 	if(name[0]!='a' || name[1]!='r' || name[2]!='g' || name[4] || !isdigit(name[3]) || (name[3]=='0' || (name[3]-'0')>MAX_MATH_ARGS))
1022 		return(0);
1023 	fp->last = (char*)&name[4];
1024 	return(nv_namptr(shp->mathnodes,name[3]-'1'));
1025 }
1026 
1027 static char* get_math(register Namval_t* np, Namfun_t *fp)
1028 {
1029 	Shell_t		*shp = nv_shell(np);
1030 	Namval_t	*mp,fake;
1031 	char		*val;
1032 	int		first=0;
1033 	fake.nvname = ".sh.math.";
1034 	mp = (Namval_t*)dtprev(shp->fun_tree,&fake);
1035 	while(mp=(Namval_t*)dtnext(shp->fun_tree,mp))
1036 	{
1037 		if(memcmp(mp->nvname,".sh.math.",9))
1038 			break;
1039 		if(first++)
1040 			sfputc(shp->strbuf,' ');
1041 		sfputr(shp->strbuf,mp->nvname+9,-1);
1042 	}
1043 	val = sfstruse(shp->strbuf);
1044 	return(val);
1045 
1046 }
1047 
1048 static char *setdisc_any(Namval_t *np, const char *event, Namval_t *action, Namfun_t *fp)
1049 {
1050 	Shell_t		*shp=nv_shell(np);
1051 	Namval_t	*mp,fake;
1052 	char		*name;
1053 	int		getname=0, off=staktell();
1054 	fake.nvname = nv_name(np);
1055 	if(!event)
1056 	{
1057 		if(!action)
1058 		{
1059 			mp = (Namval_t*)dtprev(shp->fun_tree,&fake);
1060 			return((char*)dtnext(shp->fun_tree,mp));
1061 		}
1062 		getname = 1;
1063 	}
1064 	stakputs(fake.nvname);
1065 	stakputc('.');
1066 	stakputs(event);
1067 	stakputc(0);
1068 	name  = stakptr(off);
1069 	mp = nv_search(name, shp->fun_tree, action?NV_ADD:0);
1070 	stakseek(off);
1071 	if(getname)
1072 		return(mp?(char*)dtnext(shp->fun_tree,mp):0);
1073 	if(action==np)
1074 		action = mp;
1075 	return(action?(char*)action:"");
1076 }
1077 
1078 static const Namdisc_t SH_MATH_disc  = { 0, 0, get_math, 0, setdisc_any, create_math, };
1079 
1080 #if SHOPT_COSHELL
1081 static const Namdisc_t SH_JOBPOOL_disc  = { 0, 0, 0, 0, setdisc_any, 0, };
1082 #endif /*  SHOPT_COSHELL */
1083 
1084 #if SHOPT_NAMESPACE
1085     static char* get_nspace(Namval_t* np, Namfun_t *fp)
1086     {
1087 	if(sh.namespace)
1088 		return(nv_name(sh.namespace));
1089 	return((char*)np->nvalue.cp);
1090     }
1091     static const Namdisc_t NSPACE_disc	= {  0, 0, get_nspace };
1092     static Namfun_t NSPACE_init	= {  &NSPACE_disc, 1};
1093 #endif /* SHOPT_NAMESPACE */
1094 
1095 #ifdef _hdr_locale
1096     static const Namdisc_t LC_disc	= {  sizeof(Namfun_t), put_lang };
1097 #endif /* _hdr_locale */
1098 
1099 /*
1100  * This function will get called whenever a configuration parameter changes
1101  */
1102 static int newconf(const char *name, const char *path, const char *value)
1103 {
1104 	Shell_t	*shp = sh_getinterp();
1105 	register char *arg;
1106 	if(!name)
1107 		setenviron(value);
1108 	else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
1109 	{
1110 		shp->universe = 0;
1111 		/* set directory in new universe */
1112 		if(*(arg = path_pwd(shp,0))=='/')
1113 			chdir(arg);
1114 		/* clear out old tracked alias */
1115 		stakseek(0);
1116 		stakputs(nv_getval(PATHNOD));
1117 		stakputc(0);
1118 		nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
1119 	}
1120 	return(1);
1121 }
1122 
1123 #if	(CC_NATIVE != CC_ASCII)
1124     static void a2e(char *d, const char *s)
1125     {
1126 	register const unsigned char *t;
1127 	register int i;
1128 	t = CCMAP(CC_ASCII, CC_NATIVE);
1129 	for(i=0; i<(1<<CHAR_BIT); i++)
1130 		d[t[i]] = s[i];
1131     }
1132 
1133     static void init_ebcdic(void)
1134     {
1135 	int i;
1136 	char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT));
1137 	for(i=0; i < ST_NONE; i++)
1138 	{
1139 		a2e(cp,sh_lexrstates[i]);
1140 		sh_lexstates[i] = cp;
1141 		cp += (1<<CHAR_BIT);
1142 	}
1143     }
1144 #endif
1145 
1146 /*
1147  * return SH_TYPE_* bitmask for path
1148  * 0 for "not a shell"
1149  */
1150 int sh_type(register const char *path)
1151 {
1152 	register const char*	s;
1153 	register int		t = 0;
1154 
1155 	if (s = (const char*)strrchr(path, '/'))
1156 	{
1157 		if (*path == '-')
1158 			t |= SH_TYPE_LOGIN;
1159 		s++;
1160 	}
1161 	else
1162 		s = path;
1163 	if (*s == '-')
1164 	{
1165 		s++;
1166 		t |= SH_TYPE_LOGIN;
1167 	}
1168 	for (;;)
1169 	{
1170 		if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH)))
1171 		{
1172 			if (*s == 'k')
1173 			{
1174 				s++;
1175 				t |= SH_TYPE_KSH;
1176 				continue;
1177 			}
1178 #if SHOPT_BASH
1179 			if (*s == 'b' && *(s+1) == 'a')
1180 			{
1181 				s += 2;
1182 				t |= SH_TYPE_BASH;
1183 				continue;
1184 			}
1185 #endif
1186 		}
1187 		if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED)))
1188 		{
1189 #if SHOPT_PFSH
1190 			if (*s == 'p' && *(s+1) == 'f')
1191 			{
1192 				s += 2;
1193 				t |= SH_TYPE_PROFILE;
1194 				continue;
1195 			}
1196 #endif
1197 			if (*s == 'r')
1198 			{
1199 				s++;
1200 				t |= SH_TYPE_RESTRICTED;
1201 				continue;
1202 			}
1203 		}
1204 		break;
1205 	}
1206 	if (*s++ == 's' && (*s == 'h' || *s == 'u'))
1207 	{
1208 		s++;
1209 		t |= SH_TYPE_SH;
1210 		if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3')
1211 			s += 2;
1212 #if _WINIX
1213 		if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e')
1214 			s += 4;
1215 #endif
1216 		if (!isalnum(*s))
1217 			return t;
1218 	}
1219 	return t & ~(SH_TYPE_BASH|SH_TYPE_KSH|SH_TYPE_PROFILE|SH_TYPE_RESTRICTED);
1220 }
1221 
1222 
1223 static char *get_mode(Namval_t* np, Namfun_t* nfp)
1224 {
1225 	mode_t mode = nv_getn(np,nfp);
1226 	return(fmtperm(mode));
1227 }
1228 
1229 static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1230 {
1231 	if(val)
1232 	{
1233 		mode_t mode;
1234 		char *last=0;
1235 		if(flag&NV_INTEGER)
1236 		{
1237 			if(flag&NV_LONG)
1238 				mode = *(Sfdouble_t*)val;
1239 			else
1240 				mode = *(double*)val;
1241 		}
1242 		else
1243 			mode = strperm(val, &last,0);
1244 		if(*last)
1245 			errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val);
1246 		nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
1247 	}
1248 	else
1249 		nv_putv(np,val,flag,nfp);
1250 }
1251 
1252 static const Namdisc_t modedisc =
1253 {
1254 	0,
1255         put_mode,
1256         get_mode,
1257 };
1258 
1259 
1260 /*
1261  * initialize the shell
1262  */
1263 Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
1264 {
1265 	static int beenhere;
1266 	Shell_t	*shp;
1267 	register int n;
1268 	int type;
1269 	static char *login_files[3];
1270 	memfatal();
1271 	n = strlen(e_version);
1272 	if(e_version[n-1]=='$' && e_version[n-2]==' ')
1273 		e_version[n-2]=0;
1274 #if	(CC_NATIVE == CC_ASCII)
1275 	memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
1276 #else
1277 	init_ebcdic();
1278 #endif
1279 	if(!beenhere)
1280 	{
1281 		beenhere = 1;
1282 		shp = &sh;
1283 		shgd = newof(0,struct shared,1,0);
1284 		shgd->pid = getpid();
1285 		shgd->ppid = getppid();
1286 		shgd->userid=getuid();
1287 		shgd->euserid=geteuid();
1288 		shgd->groupid=getgid();
1289 		shgd->egroupid=getegid();
1290 		shgd->lim.clk_tck = getconf("CLK_TCK");
1291 		shgd->lim.arg_max = getconf("ARG_MAX");
1292 		shgd->lim.child_max = getconf("CHILD_MAX");
1293 		shgd->lim.ngroups_max = getconf("NGROUPS_MAX");
1294 		shgd->lim.posix_version = getconf("VERSION");
1295 		shgd->lim.posix_jobcontrol = getconf("JOB_CONTROL");
1296 		if(shgd->lim.arg_max <=0)
1297 			shgd->lim.arg_max = ARG_MAX;
1298 		if(shgd->lim.child_max <=0)
1299 			shgd->lim.child_max = CHILD_MAX;
1300 		if(shgd->lim.clk_tck <=0)
1301 			shgd->lim.clk_tck = CLK_TCK;
1302 #if SHOPT_FS_3D
1303 		if(fs3d(FS3D_TEST))
1304 			shgd->lim.fs3d = 1;
1305 #endif /* SHOPT_FS_3D */
1306 		shgd->ed_context = (void*)ed_open(shp);
1307 		error_info.exit = sh_exit;
1308 		error_info.id = path_basename(argv[0]);
1309 	}
1310 	else
1311 		shp = newof(0,Shell_t,1,0);
1312 	umask(shp->mask=umask(0));
1313 	shp->gd = shgd;
1314 	shp->mac_context = sh_macopen(shp);
1315 	shp->arg_context = sh_argopen(shp);
1316 	shp->lex_context = (void*)sh_lexopen(0,shp,1);
1317 	shp->strbuf = sfstropen();
1318 	shp->stk = stkstd;
1319 	sfsetbuf(shp->strbuf,(char*)0,64);
1320 	sh_onstate(SH_INIT);
1321 #if ERROR_VERSION >= 20000102L
1322 	error_info.catalog = e_dict;
1323 #endif
1324 #if SHOPT_REGRESS
1325 	{
1326 		Opt_t*	nopt;
1327 		Opt_t*	oopt;
1328 		char*	a;
1329 		char**	av = argv;
1330 		char*	regress[3];
1331 
1332 		sh_regress_init(shp);
1333 		regress[0] = "__regress__";
1334 		regress[2] = 0;
1335 		/* NOTE: only shp is used by __regress__ at this point */
1336 		shp->bltindata.shp = shp;
1337 		while ((a = *++av) && a[0] == '-' && (a[1] == 'I' || a[1] == '-' && a[2] == 'r'))
1338 		{
1339 			if (a[1] == 'I')
1340 			{
1341 				if (a[2])
1342 					regress[1] = a + 2;
1343 				else if (!(regress[1] = *++av))
1344 					break;
1345 			}
1346 			else if (strncmp(a+2, "regress", 7))
1347 				break;
1348 			else if (a[9] == '=')
1349 				regress[1] = a + 10;
1350 			else if (!(regress[1] = *++av))
1351 				break;
1352 			nopt = optctx(0, 0);
1353 			oopt = optctx(nopt, 0);
1354 			b___regress__(2, regress, &shp->bltindata);
1355 			optctx(oopt, nopt);
1356 		}
1357 	}
1358 #endif
1359 	shp->cpipe[0] = -1;
1360 	shp->coutpipe = -1;
1361 	for(n=0;n < 10; n++)
1362 	{
1363 		/* don't use lower bits when rand() generates large numbers */
1364 		if(rand() > RANDMASK)
1365 		{
1366 			rand_shift = 3;
1367 			break;
1368 		}
1369 	}
1370 	sh_ioinit(shp);
1371 	/* initialize signal handling */
1372 	sh_siginit(shp);
1373 	stakinstall(NIL(Stak_t*),nospace);
1374 	/* set up memory for name-value pairs */
1375 	shp->init_context =  nv_init(shp);
1376 	/* read the environment */
1377 	if(argc>0)
1378 	{
1379 		type = sh_type(*argv);
1380 		if(type&SH_TYPE_LOGIN)
1381 			shp->login_sh = 2;
1382 	}
1383 	env_init(shp);
1384 	if(!ENVNOD->nvalue.cp)
1385 	{
1386 		sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME));
1387 		nv_putval(ENVNOD,sfstruse(shp->strbuf),NV_RDONLY);
1388 	}
1389 	*SHLVL->nvalue.ip +=1;
1390 	nv_offattr(SHLVL,NV_IMPORT);
1391 #if SHOPT_SPAWN
1392 	{
1393 		/*
1394 		 * try to find the pathname for this interpreter
1395 		 * try using environment variable _ or argv[0]
1396 		 */
1397 		char *cp=nv_getval(L_ARGNOD);
1398 		char buff[PATH_MAX+1];
1399 		shp->gd->shpath = 0;
1400 #if _AST_VERSION >= 20090202L
1401 		if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff))
1402 			shp->gd->shpath = strdup(buff);
1403 #else
1404 		sfprintf(shp->strbuf,"/proc/%d/exe",getpid());
1405 		if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0)
1406 		{
1407 			buff[n] = 0;
1408 			shp->gd->shpath = strdup(buff);
1409 		}
1410 #endif
1411 		else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
1412 		{
1413 			if(*cp=='/')
1414 				shp->gd->shpath = strdup(cp);
1415 			else if(cp = nv_getval(PWDNOD))
1416 			{
1417 				int offset = staktell();
1418 				stakputs(cp);
1419 				stakputc('/');
1420 				stakputs(argv[0]);
1421 				pathcanon(stakptr(offset),PATH_DOTDOT);
1422 				shp->gd->shpath = strdup(stakptr(offset));
1423 				stakseek(offset);
1424 			}
1425 		}
1426 	}
1427 #endif
1428 	nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
1429 #if SHOPT_FS_3D
1430 	nv_stack(VPATHNOD, &VPATH_init);
1431 #endif /* SHOPT_FS_3D */
1432 	astconfdisc(newconf);
1433 #if SHOPT_TIMEOUT
1434 	shp->st.tmout = SHOPT_TIMEOUT;
1435 #endif /* SHOPT_TIMEOUT */
1436 	/* initialize jobs table */
1437 	job_clear();
1438 	sh_onoption(SH_MULTILINE);
1439 	if(argc>0)
1440 	{
1441 		int dolv_index = -1;
1442 		/* check for restricted shell */
1443 		if(type&SH_TYPE_RESTRICTED)
1444 			sh_onoption(SH_RESTRICTED);
1445 #if SHOPT_PFSH
1446 		/* check for profile shell */
1447 		else if(type&SH_TYPE_PROFILE)
1448 			sh_onoption(SH_PFSH);
1449 #endif
1450 #if SHOPT_BASH
1451 		/* check for invocation as bash */
1452 		if(type&SH_TYPE_BASH)
1453 		{
1454 		        shp>userinit = userinit = bash_init;
1455 			sh_onoption(SH_BASH);
1456 			sh_onstate(SH_PREINIT);
1457 			(*userinit)(shp, 0);
1458 			sh_offstate(SH_PREINIT);
1459 		}
1460 #endif
1461 		/* look for options */
1462 		/* shp->st.dolc is $#	*/
1463 		if((shp->st.dolc = sh_argopts(-argc,argv,shp)) < 0)
1464 		{
1465 			shp->exitval = 2;
1466 			sh_done(shp,0);
1467 		}
1468 		opt_info.disc = 0;
1469 		dolv_index = (argc-1)-shp->st.dolc;
1470 		shp->st.dolv=argv+dolv_index;
1471 		shp->st.repl_index = dolv_index;
1472 		shp->st.repl_arg = argv[dolv_index];
1473 		shp->st.dolv[0] = argv[0];
1474 		if(shp->st.dolc < 1)
1475 			sh_onoption(SH_SFLAG);
1476 		if(!sh_isoption(SH_SFLAG))
1477 		{
1478 			shp->st.dolc--;
1479 			shp->st.dolv++;
1480 #if _WINIX
1481 			{
1482 				char*	name;
1483 				name = shp->st.dolv[0];
1484 				if(name[1]==':' && (name[2]=='/' || name[2]=='\\'))
1485 				{
1486 #if _lib_pathposix
1487 					char*	p;
1488 
1489 					if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n)))
1490 					{
1491 						pathposix(name, p, n);
1492 						name = p;
1493 					}
1494 					else
1495 #endif
1496 					{
1497 						name[1] = name[0];
1498 						name[0] = name[2] = '/';
1499 					}
1500 				}
1501 			}
1502 #endif /* _WINIX */
1503 		}
1504 		if(beenhere==1)
1505 		{
1506 			struct lconv*	lc;
1507 			shp->decomma = (lc=localeconv()) && lc->decimal_point && *lc->decimal_point==',';
1508 			beenhere = 2;
1509 		}
1510 	}
1511 #if SHOPT_PFSH
1512 	if (sh_isoption(SH_PFSH))
1513 	{
1514 		struct passwd *pw = getpwuid(shp->gd->userid);
1515 		if(pw)
1516 			shp->gd->user = strdup(pw->pw_name);
1517 
1518 	}
1519 #endif
1520 	/* set[ug]id scripts require the -p flag */
1521 	if(shp->gd->userid!=shp->gd->euserid || shp->gd->groupid!=shp->gd->egroupid)
1522 	{
1523 #ifdef SHOPT_P_SUID
1524 		/* require sh -p to run setuid and/or setgid */
1525 		if(!sh_isoption(SH_PRIVILEGED) && shp->gd->userid >= SHOPT_P_SUID)
1526 		{
1527 			setuid(shp->gd->euserid=shp->gd->userid);
1528 			setgid(shp->gd->egroupid=shp->gd->groupid);
1529 		}
1530 		else
1531 #endif /* SHOPT_P_SUID */
1532 			sh_onoption(SH_PRIVILEGED);
1533 #ifdef SHELLMAGIC
1534 		/* careful of #! setuid scripts with name beginning with - */
1535 		if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0)
1536 			errormsg(SH_DICT,ERROR_exit(1),e_prohibited);
1537 #endif /*SHELLMAGIC*/
1538 	}
1539 	else
1540 		sh_offoption(SH_PRIVILEGED);
1541 	/* shname for $0 in profiles and . scripts */
1542 	if(sh_isdevfd(argv[1]))
1543 		shp->shname = strdup(argv[0]);
1544 	else
1545 		shp->shname = strdup(shp->st.dolv[0]);
1546 	/*
1547 	 * return here for shell script execution
1548 	 * but not for parenthesis subshells
1549 	 */
1550 	error_info.id = strdup(shp->st.dolv[0]); /* error_info.id is $0 */
1551 	shp->jmpbuffer = (void*)&shp->checkbase;
1552 	sh_pushcontext(shp,&shp->checkbase,SH_JMPSCRIPT);
1553 	shp->st.self = &shp->global;
1554         shp->topscope = (Shscope_t*)shp->st.self;
1555 	sh_offstate(SH_INIT);
1556 	login_files[0] = (char*)e_profile;
1557 	login_files[1] = ".profile";
1558 	shp->gd->login_files = login_files;
1559 	shp->bltindata.version = SH_VERSION;
1560 	shp->bltindata.shp = shp;
1561 	shp->bltindata.shrun = sh_run;
1562 	shp->bltindata.shtrap = sh_trap;
1563 	shp->bltindata.shexit = sh_exit;
1564 	shp->bltindata.shbltin = sh_addbuiltin;
1565 #if _AST_VERSION >= 20080617L
1566 	shp->bltindata.shgetenv = sh_getenv;
1567 	shp->bltindata.shsetenv = sh_setenviron;
1568 	astintercept(&shp->bltindata,1);
1569 #endif
1570 #if 0
1571 #define NV_MKINTTYPE(x,y,z)	nv_mkinttype(#x,sizeof(x),(x)-1<0,(y),(Namdisc_t*)z);
1572 	NV_MKINTTYPE(pid_t,"process id",0);
1573 	NV_MKINTTYPE(gid_t,"group id",0);
1574 	NV_MKINTTYPE(uid_t,"user id",0);
1575 	NV_MKINTTYPE(size_t,(const char*)0,0);
1576 	NV_MKINTTYPE(ssize_t,(const char*)0,0);
1577 	NV_MKINTTYPE(off_t,"offset in bytes",0);
1578 	NV_MKINTTYPE(ino_t,"\ai-\anode number",0);
1579 	NV_MKINTTYPE(mode_t,(const char*)0,&modedisc);
1580 	NV_MKINTTYPE(dev_t,"device id",0);
1581 	NV_MKINTTYPE(nlink_t,"hard link count",0);
1582 	NV_MKINTTYPE(blkcnt_t,"block count",0);
1583 	NV_MKINTTYPE(time_t,"seconds since the epoch",0);
1584 	nv_mkstat();
1585 #endif
1586 	if(shp->userinit=userinit)
1587 		(*userinit)(shp, 0);
1588 	shp->exittrap = 0;
1589 	shp->errtrap = 0;
1590 	shp->end_fn = 0;
1591 	return(shp);
1592 }
1593 
1594 Shell_t *sh_getinterp(void)
1595 {
1596 	return(&sh);
1597 }
1598 
1599 /*
1600  * reinitialize before executing a script
1601  */
1602 int sh_reinit(char *argv[])
1603 {
1604 	Shell_t	*shp = sh_getinterp();
1605 	Shopt_t opt;
1606 	Namval_t *np,*npnext;
1607 	Dt_t	*dp;
1608 	struct adata
1609 	{
1610 		Shell_t		*sh;
1611 		void		*extra[2];
1612 	} data;
1613 	for(np=dtfirst(shp->fun_tree);np;np=npnext)
1614 	{
1615 		if((dp=shp->fun_tree)->walk)
1616 			dp = dp->walk;
1617 		npnext = (Namval_t*)dtnext(shp->fun_tree,np);
1618 		if(np>= shgd->bltin_cmds && np < &shgd->bltin_cmds[nbltins])
1619 			continue;
1620 		if(is_abuiltin(np) && nv_isattr(np,NV_EXPORT))
1621 			continue;
1622 		if(*np->nvname=='/')
1623 			continue;
1624 		nv_delete(np,dp,NV_NOFREE);
1625 	}
1626 	dtclose(shp->alias_tree);
1627 	shp->alias_tree = inittree(shp,shtab_aliases);
1628 	shp->last_root = shp->var_tree;
1629 	shp->inuse_bits = 0;
1630 	if(shp->userinit)
1631 		(*shp->userinit)(shp, 1);
1632 	if(shp->heredocs)
1633 	{
1634 		sfclose(shp->heredocs);
1635 		shp->heredocs = 0;
1636 	}
1637 	/* remove locals */
1638 	sh_onstate(SH_INIT);
1639 	memset(&data,0,sizeof(data));
1640 	data.sh = shp;
1641 	nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_EXPORT,0);
1642 	nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_ARRAY,NV_ARRAY);
1643 	sh_offstate(SH_INIT);
1644 	memset(shp->st.trapcom,0,(shp->st.trapmax+1)*sizeof(char*));
1645 	memset((void*)&opt,0,sizeof(opt));
1646 #if SHOPT_NAMESPACE
1647 	if(shp->namespace)
1648 	{
1649 		dp=nv_dict(shp->namespace);
1650 		if(dp==shp->var_tree)
1651 			shp->var_tree = dtview(dp,0);
1652 		_nv_unset(shp->namespace,NV_RDONLY);
1653 		shp->namespace = 0;
1654 	}
1655 #endif /* SHOPT_NAMESPACE */
1656 	if(sh_isoption(SH_TRACKALL))
1657 		on_option(&opt,SH_TRACKALL);
1658 	if(sh_isoption(SH_EMACS))
1659 		on_option(&opt,SH_EMACS);
1660 	if(sh_isoption(SH_GMACS))
1661 		on_option(&opt,SH_GMACS);
1662 	if(sh_isoption(SH_VI))
1663 		on_option(&opt,SH_VI);
1664 	if(sh_isoption(SH_VIRAW))
1665 		on_option(&opt,SH_VIRAW);
1666 	shp->options = opt;
1667 	/* set up new args */
1668 	if(argv)
1669 		shp->arglist = sh_argcreate(argv);
1670 	if(shp->arglist)
1671 		sh_argreset(shp,shp->arglist,NIL(struct dolnod*));
1672 	shp->envlist=0;
1673 	shp->curenv = 0;
1674 	shp->shname = error_info.id = strdup(shp->st.dolv[0]);
1675 	sh_offstate(SH_FORKED);
1676 	shp->fn_depth = shp->dot_depth = 0;
1677 	sh_sigreset(0);
1678 	if(!(SHLVL->nvalue.ip))
1679 	{
1680 		shlvl = 0;
1681 		SHLVL->nvalue.ip = &shlvl;
1682 		nv_onattr(SHLVL,NV_INTEGER|NV_EXPORT|NV_NOFREE);
1683 	}
1684 	*SHLVL->nvalue.ip +=1;
1685 	nv_offattr(SHLVL,NV_IMPORT);
1686 	shp->st.filename = strdup(shp->lastarg);
1687 	nv_delete((Namval_t*)0, (Dt_t*)0, 0);
1688 	job.exitval = 0;
1689 	shp->inpipe = shp->outpipe = 0;
1690 	job_clear();
1691 	job.in_critical = 0;
1692 	shp->exittrap = 0;
1693 	shp->errtrap = 0;
1694 	shp->end_fn = 0;
1695 	return(1);
1696 }
1697 
1698 /*
1699  * set when creating a local variable of this name
1700  */
1701 Namfun_t *nv_cover(register Namval_t *np)
1702 {
1703 	if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS || np==ENVNOD || np==LINENO)
1704 		return(np->nvfun);
1705 #ifdef _hdr_locale
1706 	if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD)
1707 		return(np->nvfun);
1708 #endif
1709 	 return(0);
1710 }
1711 
1712 static const char *shdiscnames[] = { "tilde", 0};
1713 
1714 #ifdef SHOPT_STATS
1715 struct Stats
1716 {
1717 	Namfun_t	hdr;
1718 	Shell_t		*sh;
1719 	char		*nodes;
1720 	int		numnodes;
1721 	int		current;
1722 };
1723 
1724 static Namval_t *next_stat(register Namval_t* np, Dt_t *root,Namfun_t *fp)
1725 {
1726 	struct Stats *sp = (struct Stats*)fp;
1727 	if(!root)
1728 		sp->current = 0;
1729 	else if(++sp->current>=sp->numnodes)
1730 		return(0);
1731 	return(nv_namptr(sp->nodes,sp->current));
1732 }
1733 
1734 static Namval_t *create_stat(Namval_t *np,const char *name,int flag,Namfun_t *fp)
1735 {
1736 	struct Stats		*sp = (struct Stats*)fp;
1737 	register const char	*cp=name;
1738 	register int		i=0,n;
1739 	Namval_t		*nq=0;
1740 	Shell_t			*shp = sp->sh;
1741 	if(!name)
1742 		return(SH_STATS);
1743 	while((i=*cp++) && i != '=' && i != '+' && i!='[');
1744 	n = (cp-1) -name;
1745 	for(i=0; i < sp->numnodes; i++)
1746 	{
1747 		nq = nv_namptr(sp->nodes,i);
1748 		if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0)
1749 			goto found;
1750 	}
1751 	nq = 0;
1752 found:
1753 	if(nq)
1754 	{
1755 		fp->last = (char*)&name[n];
1756 		shp->last_table = SH_STATS;
1757 	}
1758 	else
1759 		errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np));
1760 	return(nq);
1761 }
1762 
1763 static const Namdisc_t stat_disc =
1764 {
1765 	0, 0, 0, 0, 0,
1766 	create_stat,
1767 	0, 0,
1768 	next_stat
1769 };
1770 
1771 static char *name_stat(Namval_t *np, Namfun_t *fp)
1772 {
1773 	Shell_t	*shp = sh_getinterp();
1774 	sfprintf(shp->strbuf,".sh.stats.%s",np->nvname);
1775 	return(sfstruse(shp->strbuf));
1776 }
1777 
1778 static const Namdisc_t	stat_child_disc =
1779 {
1780 	0,0,0,0,0,0,0,
1781 	name_stat
1782 };
1783 
1784 static Namfun_t	 stat_child_fun =
1785 {
1786 	&stat_child_disc, 1, 0, sizeof(Namfun_t)
1787 };
1788 
1789 static void stat_init(Shell_t *shp)
1790 {
1791 	int		i,nstat = STAT_SUBSHELL+1;
1792 	struct Stats	*sp = newof(0,struct Stats,1,nstat*NV_MINSZ);
1793 	Namval_t	*np;
1794 	sp->numnodes = nstat;
1795 	sp->nodes = (char*)(sp+1);
1796 	shgd->stats = (int*)calloc(sizeof(int),nstat);
1797 	sp->sh = shp;
1798 	for(i=0; i < nstat; i++)
1799 	{
1800 		np = nv_namptr(sp->nodes,i);
1801 		np->nvfun = &stat_child_fun;
1802 		np->nvname = (char*)shtab_stats[i].sh_name;
1803 		nv_onattr(np,NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER);
1804 		nv_setsize(np,10);
1805 		np->nvalue.ip = &shgd->stats[i];
1806 	}
1807 	sp->hdr.dsize = sizeof(struct Stats) + nstat*(sizeof(int)+NV_MINSZ);
1808 	sp->hdr.disc = &stat_disc;
1809 	nv_stack(SH_STATS,&sp->hdr);
1810 	sp->hdr.nofree = 1;
1811 	nv_setvtree(SH_STATS);
1812 }
1813 #else
1814 #   define stat_init(x)
1815 #endif /* SHOPT_STATS */
1816 
1817 /*
1818  * Initialize the shell name and alias table
1819  */
1820 static Init_t *nv_init(Shell_t *shp)
1821 {
1822 	double d=0;
1823 	ip = newof(0,Init_t,1,0);
1824 	if(!ip)
1825 		return(0);
1826 	shp->nvfun.last = (char*)shp;
1827 	shp->nvfun.nofree = 1;
1828 	ip->sh = shp;
1829 	shp->var_base = shp->var_tree = inittree(shp,shtab_variables);
1830 	SHLVL->nvalue.ip = &shlvl;
1831 	ip->IFS_init.hdr.disc = &IFS_disc;
1832 	ip->PATH_init.disc = &RESTRICTED_disc;
1833 	ip->PATH_init.nofree = 1;
1834 	ip->FPATH_init.disc = &RESTRICTED_disc;
1835 	ip->FPATH_init.nofree = 1;
1836 	ip->CDPATH_init.disc = &CDPATH_disc;
1837 	ip->CDPATH_init.nofree = 1;
1838 	ip->SHELL_init.disc = &RESTRICTED_disc;
1839 	ip->SHELL_init.nofree = 1;
1840 	ip->ENV_init.disc = &RESTRICTED_disc;
1841 	ip->ENV_init.nofree = 1;
1842 	ip->VISUAL_init.disc = &EDITOR_disc;
1843 	ip->VISUAL_init.nofree = 1;
1844 	ip->EDITOR_init.disc = &EDITOR_disc;
1845 	ip->EDITOR_init.nofree = 1;
1846 	ip->HISTFILE_init.disc = &HISTFILE_disc;
1847 	ip->HISTFILE_init.nofree = 1;
1848 	ip->HISTSIZE_init.disc = &HISTFILE_disc;
1849 	ip->HISTSIZE_init.nofree = 1;
1850 	ip->OPTINDEX_init.disc = &OPTINDEX_disc;
1851 	ip->OPTINDEX_init.nofree = 1;
1852 	ip->SECONDS_init.hdr.disc = &SECONDS_disc;
1853 	ip->SECONDS_init.hdr.nofree = 1;
1854 	ip->RAND_init.hdr.disc = &RAND_disc;
1855 	ip->RAND_init.hdr.nofree = 1;
1856 	ip->RAND_init.sh = shp;
1857 	ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc;
1858 	ip->SH_MATCH_init.hdr.nofree = 1;
1859 	ip->SH_MATH_init.disc = &SH_MATH_disc;
1860 	ip->SH_MATH_init.nofree = 1;
1861 #if SHOPT_COSHELL
1862 	ip->SH_JOBPOOL_init.disc = &SH_JOBPOOL_disc;
1863 	ip->SH_JOBPOOL_init.nofree = 1;
1864 	nv_stack(SH_JOBPOOL, &ip->SH_JOBPOOL_init);
1865 #endif /* SHOPT_COSHELL */
1866 	ip->SH_VERSION_init.disc = &SH_VERSION_disc;
1867 	ip->SH_VERSION_init.nofree = 1;
1868 	ip->LINENO_init.disc = &LINENO_disc;
1869 	ip->LINENO_init.nofree = 1;
1870 	ip->L_ARG_init.disc = &L_ARG_disc;
1871 	ip->L_ARG_init.nofree = 1;
1872 #ifdef _hdr_locale
1873 	ip->LC_TYPE_init.disc = &LC_disc;
1874 	ip->LC_TYPE_init.nofree = 1;
1875 	ip->LC_NUM_init.disc = &LC_disc;
1876 	ip->LC_NUM_init.nofree = 1;
1877 	ip->LC_COLL_init.disc = &LC_disc;
1878 	ip->LC_COLL_init.nofree = 1;
1879 	ip->LC_MSG_init.disc = &LC_disc;
1880 	ip->LC_MSG_init.nofree = 1;
1881 	ip->LC_ALL_init.disc = &LC_disc;
1882 	ip->LC_ALL_init.nofree = 1;
1883 	ip->LANG_init.disc = &LC_disc;
1884 	ip->LANG_init.nofree = 1;
1885 #endif /* _hdr_locale */
1886 	nv_stack(IFSNOD, &ip->IFS_init.hdr);
1887 	ip->IFS_init.hdr.nofree = 1;
1888 	nv_stack(PATHNOD, &ip->PATH_init);
1889 	nv_stack(FPATHNOD, &ip->FPATH_init);
1890 	nv_stack(CDPNOD, &ip->CDPATH_init);
1891 	nv_stack(SHELLNOD, &ip->SHELL_init);
1892 	nv_stack(ENVNOD, &ip->ENV_init);
1893 	nv_stack(VISINOD, &ip->VISUAL_init);
1894 	nv_stack(EDITNOD, &ip->EDITOR_init);
1895 	nv_stack(HISTFILE, &ip->HISTFILE_init);
1896 	nv_stack(HISTSIZE, &ip->HISTSIZE_init);
1897 	nv_stack(OPTINDNOD, &ip->OPTINDEX_init);
1898 	nv_stack(SECONDS, &ip->SECONDS_init.hdr);
1899 	nv_stack(L_ARGNOD, &ip->L_ARG_init);
1900 	nv_putval(SECONDS, (char*)&d, NV_DOUBLE);
1901 	nv_stack(RANDNOD, &ip->RAND_init.hdr);
1902 	d = (shp->gd->pid&RANDMASK);
1903 	nv_putval(RANDNOD, (char*)&d, NV_DOUBLE);
1904 	nv_stack(LINENO, &ip->LINENO_init);
1905 	SH_MATCHNOD->nvfun =  &ip->SH_MATCH_init.hdr;
1906 	nv_putsub(SH_MATCHNOD,(char*)0,10);
1907 	nv_stack(SH_MATHNOD, &ip->SH_MATH_init);
1908 	nv_stack(SH_VERSIONNOD, &ip->SH_VERSION_init);
1909 #ifdef _hdr_locale
1910 	nv_stack(LCTYPENOD, &ip->LC_TYPE_init);
1911 	nv_stack(LCALLNOD, &ip->LC_ALL_init);
1912 	nv_stack(LCMSGNOD, &ip->LC_MSG_init);
1913 	nv_stack(LCCOLLNOD, &ip->LC_COLL_init);
1914 	nv_stack(LCNUMNOD, &ip->LC_NUM_init);
1915 	nv_stack(LANGNOD, &ip->LANG_init);
1916 #endif /* _hdr_locale */
1917 	(PPIDNOD)->nvalue.lp = (&shp->gd->ppid);
1918 	(TMOUTNOD)->nvalue.lp = (&shp->st.tmout);
1919 	(MCHKNOD)->nvalue.lp = (&sh_mailchk);
1920 	(OPTINDNOD)->nvalue.lp = (&shp->st.optindex);
1921 	/* set up the seconds clock */
1922 	shp->alias_tree = inittree(shp,shtab_aliases);
1923 	shp->track_tree = dtopen(&_Nvdisc,Dtset);
1924 	shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins);
1925 	shp->fun_tree = dtopen(&_Nvdisc,Dtoset);
1926 	dtview(shp->fun_tree,shp->bltin_tree);
1927 	nv_mount(DOTSHNOD, "type", shp->typedict=dtopen(&_Nvdisc,Dtoset));
1928 	nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0);
1929 	DOTSHNOD->nvalue.cp = Empty;
1930 	nv_onattr(DOTSHNOD,NV_RDONLY);
1931 	SH_LINENO->nvalue.ip = &shp->st.lineno;
1932 	VERSIONNOD->nvalue.nrp = newof(0,struct Namref,1,0);
1933         VERSIONNOD->nvalue.nrp->np = SH_VERSIONNOD;
1934         VERSIONNOD->nvalue.nrp->root = nv_dict(DOTSHNOD);
1935         VERSIONNOD->nvalue.nrp->table = DOTSHNOD;
1936 	nv_onattr(VERSIONNOD,NV_REF);
1937 	math_init(shp);
1938 	if(!shgd->stats)
1939 		stat_init(shp);
1940 	return(ip);
1941 }
1942 
1943 /*
1944  * initialize name-value pairs
1945  */
1946 
1947 static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
1948 {
1949 	register Namval_t *np;
1950 	register const struct shtable2 *tp;
1951 	register unsigned n = 0;
1952 	register Dt_t *treep;
1953 	Dt_t *base_treep, *dict;
1954 	for(tp=name_vals;*tp->sh_name;tp++)
1955 		n++;
1956 	np = (Namval_t*)calloc(n,sizeof(Namval_t));
1957 	if(!shgd->bltin_nodes)
1958 	{
1959 		shgd->bltin_nodes = np;
1960 		shgd->bltin_nnodes = n;
1961 	}
1962 	else if(name_vals==(const struct shtable2*)shtab_builtins)
1963 	{
1964 		shgd->bltin_cmds = np;
1965 		nbltins = n;
1966 	}
1967 	base_treep = treep = dtopen(&_Nvdisc,Dtoset);
1968 	treep->user = (void*)shp;
1969 	for(tp=name_vals;*tp->sh_name;tp++,np++)
1970 	{
1971 		if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name))
1972 			np->nvname++;
1973 		else
1974 		{
1975 			np->nvname = (char*)tp->sh_name;
1976 			treep = base_treep;
1977 		}
1978 		np->nvenv = 0;
1979 		if(name_vals==(const struct shtable2*)shtab_builtins)
1980 			np->nvalue.bfp = (Nambfp_f)((struct shtable3*)tp)->sh_value;
1981 		else
1982 		{
1983 			if(name_vals == shtab_variables)
1984 				np->nvfun = &shp->nvfun;
1985 			np->nvalue.cp = (char*)tp->sh_value;
1986 		}
1987 		nv_setattr(np,tp->sh_number);
1988 		if(nv_isattr(np,NV_TABLE))
1989 			nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset));
1990 		if(nv_isattr(np,NV_INTEGER))
1991 			nv_setsize(np,10);
1992 		else
1993 			nv_setsize(np,0);
1994 		dtinsert(treep,np);
1995 		if(nv_istable(np))
1996 			treep = dict;
1997 	}
1998 	return(treep);
1999 }
2000 
2001 /*
2002  * read in the process environment and set up name-value pairs
2003  * skip over items that are not name-value pairs
2004  */
2005 
2006 static void env_init(Shell_t *shp)
2007 {
2008 	register char		*cp;
2009 	register Namval_t	*np,*mp;
2010 	register char		**ep=environ;
2011 	char			*dp,*next=0;
2012 	int			nenv=0,k=0,size=0;
2013 	Namval_t		*np0;
2014 #ifdef _ENV_H
2015 	shp->env = env_open(environ,3);
2016 	env_delete(shp->env,"_");
2017 #endif
2018 	if(!ep)
2019 		goto skip;
2020 	while(*ep++)
2021 		nenv++;
2022 	np = newof(0,Namval_t,nenv,0);
2023 	for(np0=np,ep=environ;cp= *ep; ep++)
2024 	{
2025 		dp = strchr(cp,'=');
2026 		if(!dp)
2027 			continue;
2028 		*dp++ = 0;
2029 		if(mp = dtmatch(shp->var_base,cp))
2030 		{
2031                         if(strcmp(cp,VERSIONNOD->nvname)==0)
2032                         {
2033                                 dp[-1] = '=';
2034                                 continue;
2035                         }
2036 			mp->nvenv = (char*)cp;
2037 			dp[-1] = '=';
2038 		}
2039 		else if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]==0)
2040 		{
2041 			dp[-1] = '=';
2042 			next = cp+4;
2043 			continue;
2044 		}
2045 		else
2046 		{
2047 			k++;
2048 			mp = np++;
2049 			mp->nvname = cp;
2050 			size += strlen(cp);
2051 		}
2052 			nv_onattr(mp,NV_IMPORT);
2053 		if(mp->nvfun || nv_isattr(mp,NV_INTEGER))
2054 			nv_putval(mp,dp,0);
2055 		else
2056 		{
2057 			mp->nvalue.cp = dp;
2058 			nv_onattr(mp,NV_NOFREE);
2059 		}
2060 		nv_onattr(mp,NV_EXPORT|NV_IMPORT);
2061 	}
2062 	np =  (Namval_t*)realloc((void*)np0,k*sizeof(Namval_t));
2063 	dp = (char*)malloc(size+k);
2064 	while(k-->0)
2065 	{
2066 		size = strlen(np->nvname);
2067 		memcpy(dp,np->nvname,size+1);
2068 		np->nvname[size] = '=';
2069 		np->nvenv = np->nvname;
2070 		np->nvname = dp;
2071 		dp += size+1;
2072 		dtinsert(shp->var_base,np++);
2073 	}
2074 	while(cp=next)
2075 	{
2076 		if(next = strchr(++cp,'='))
2077 			*next = 0;
2078 		np = nv_search(cp+2,shp->var_tree,NV_ADD);
2079 		if(np!=SHLVL && nv_isattr(np,NV_IMPORT|NV_EXPORT))
2080 		{
2081 			int flag = *(unsigned char*)cp-' ';
2082 			int size = *(unsigned char*)(cp+1)-' ';
2083 			if((flag&NV_INTEGER) && size==0)
2084 			{
2085 				/* check for floating*/
2086 				char *val = nv_getval(np);
2087 				strtol(val,&dp,10);
2088 				if(*dp=='.' || *dp=='e' || *dp=='E')
2089 				{
2090 					char *lp;
2091 					flag |= NV_DOUBLE;
2092 					if(*dp=='.')
2093 					{
2094 						strtol(dp+1,&lp,10);
2095 						if(*lp)
2096 							dp = lp;
2097 					}
2098 					if(*dp && *dp!='.')
2099 					{
2100 						flag |= NV_EXPNOTE;
2101 						size = dp-val;
2102 					}
2103 					else
2104 						size = strlen(dp);
2105 					size--;
2106 				}
2107 			}
2108 			nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
2109 			if((flag&(NV_INTEGER|NV_UTOL|NV_LTOU))==(NV_UTOL|NV_LTOU))
2110 				nv_mapchar(np,(flag&NV_UTOL)?e_tolower:e_toupper);
2111 		}
2112 		else
2113 			cp += 2;
2114 	}
2115 skip:
2116 #ifdef _ENV_H
2117 	env_delete(shp->env,e_envmarker);
2118 #endif
2119 	if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
2120 	{
2121 		nv_offattr(PWDNOD,NV_TAGGED);
2122 		path_pwd(shp,0);
2123 	}
2124 	if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
2125 		sh_onoption(SH_RESTRICTED); /* restricted shell */
2126 	return;
2127 }
2128 
2129 /*
2130  * terminate shell and free up the space
2131  */
2132 int sh_term(void)
2133 {
2134 	sfdisc(sfstdin,SF_POPDISC);
2135 	free((char*)sh.outbuff);
2136 	stakset(NIL(char*),0);
2137 	return(0);
2138 }
2139 
2140 /* function versions of these */
2141 
2142 #define DISABLE	/* proto workaround */
2143 
2144 unsigned long sh_isoption DISABLE (int opt)
2145 {
2146 	return(sh_isoption(opt));
2147 }
2148 
2149 unsigned long sh_onoption DISABLE (int opt)
2150 {
2151 	return(sh_onoption(opt));
2152 }
2153 
2154 unsigned long sh_offoption DISABLE (int opt)
2155 {
2156 	return(sh_offoption(opt));
2157 }
2158 
2159 void	sh_sigcheck DISABLE (Shell_t *shp)
2160 {
2161 	if(!shp)
2162 		shp = sh_getinterp();
2163 	sh_sigcheck(shp);
2164 }
2165 
2166 Dt_t*	sh_bltin_tree DISABLE (void)
2167 {
2168 	return(sh.bltin_tree);
2169 }
2170 
2171 /*
2172  * This code is for character mapped variables with wctrans()
2173  */
2174 struct Mapchar
2175 {
2176 	Namfun_t	hdr;
2177 	const char	*name;
2178 	wctrans_t	trans;
2179 	int		lctype;
2180 };
2181 
2182 static void put_trans(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
2183 {
2184 	struct Mapchar *mp = (struct Mapchar*)fp;
2185 	int	c,offset = staktell(),off=offset;
2186 	if(val)
2187 	{
2188 		if(mp->lctype!=lctype)
2189 		{
2190 			mp->lctype = lctype;
2191 			mp->trans = wctrans(mp->name);
2192 		}
2193 		if(!mp->trans || (flags&NV_INTEGER))
2194 			goto skip;
2195 		while(c = mbchar(val))
2196 		{
2197 			c = towctrans(c,mp->trans);
2198 			stakseek(off+c);
2199 			stakseek(off);
2200 			c  = mbconv(stakptr(off),c);
2201 			off += c;
2202 			stakseek(off);
2203 		}
2204 		stakputc(0);
2205 		val = stakptr(offset);
2206 	}
2207 	else
2208 	{
2209 		nv_putv(np,val,flags,fp);
2210 		nv_disc(np,fp,NV_POP);
2211 		if(!(fp->nofree&1))
2212 			free((void*)fp);
2213 		stakseek(offset);
2214 		return;
2215 	}
2216 skip:
2217 	nv_putv(np,val,flags,fp);
2218 	stakseek(offset);
2219 }
2220 
2221 static const Namdisc_t TRANS_disc      = {  sizeof(struct Mapchar), put_trans };
2222 
2223 Namfun_t	*nv_mapchar(Namval_t *np,const char *name)
2224 {
2225 	wctrans_t	trans = name?wctrans(name):0;
2226 	struct Mapchar	*mp=0;
2227 	int		n=0,low;
2228 	if(np)
2229 		mp = (struct Mapchar*)nv_hasdisc(np,&TRANS_disc);
2230 	if(!name)
2231 		return(mp?(Namfun_t*)mp->name:0);
2232 	if(!trans)
2233 		return(0);
2234 	if(!np)
2235 		return(((Namfun_t*)0)+1);
2236 	if((low=strcmp(name,e_tolower)) && strcmp(name,e_toupper))
2237 		n += strlen(name)+1;
2238 	if(mp)
2239 	{
2240 		if(strcmp(name,mp->name)==0)
2241 			return(&mp->hdr);
2242 		nv_disc(np,&mp->hdr,NV_POP);
2243 		if(!(mp->hdr.nofree&1))
2244 			free((void*)mp);
2245 	}
2246 	mp = newof(0,struct Mapchar,1,n);
2247 	mp->trans = trans;
2248 	mp->lctype = lctype;
2249 	if(low==0)
2250 		mp->name = e_tolower;
2251 	else if(n==0)
2252 		mp->name = e_toupper;
2253 	else
2254 	{
2255 		mp->name = (char*)(mp+1);
2256 		strcpy((char*)mp->name,name);
2257 	}
2258 	mp->hdr.disc =  &TRANS_disc;
2259 	return(&mp->hdr);
2260 }
2261