summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshell/common/sh/init.c
diff options
context:
space:
mode:
authorchin <none@none>2007-08-17 12:01:52 -0700
committerchin <none@none>2007-08-17 12:01:52 -0700
commitda2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch)
tree5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libshell/common/sh/init.c
parent073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff)
downloadillumos-gate-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93 PSARC/2006/550 Korn Shell 93 Integration PSARC/2006/587 /etc/ksh.kshrc for ksh93 PSARC/2007/035 ksh93 Amendments Contributed by Roland Mainz <roland.mainz@nrubsig.org> --HG-- rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libshell/common/sh/init.c')
-rw-r--r--usr/src/lib/libshell/common/sh/init.c1465
1 files changed, 1465 insertions, 0 deletions
diff --git a/usr/src/lib/libshell/common/sh/init.c b/usr/src/lib/libshell/common/sh/init.c
new file mode 100644
index 0000000000..fbb6e5c6bc
--- /dev/null
+++ b/usr/src/lib/libshell/common/sh/init.c
@@ -0,0 +1,1465 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ *
+ * Shell initialization
+ *
+ * David Korn
+ * AT&T Labs
+ *
+ */
+
+#include "defs.h"
+#include <stak.h>
+#include <ctype.h>
+#include <ccode.h>
+#include <pwd.h>
+#include "variables.h"
+#include "path.h"
+#include "fault.h"
+#include "name.h"
+#include "edit.h"
+#include "jobs.h"
+#include "io.h"
+#include "shlex.h"
+#include "builtins.h"
+#include "FEATURE/time"
+#include "FEATURE/dynamic"
+#include "lexstates.h"
+#include "version.h"
+
+#if SHOPT_MULTIBYTE
+ char e_version[] = "\n@(#)$Id: Version M "SH_RELEASE" $\0\n";
+#else
+ char e_version[] = "\n@(#)$Id: Version "SH_RELEASE" $\0\n";
+#endif /* SHOPT_MULTIBYTE */
+
+#if SHOPT_BASH
+ extern void bash_init(int);
+#endif
+
+#define RANDMASK 0x7fff
+#ifndef CLK_TCK
+# define CLK_TCK 60
+#endif /* CLK_TCK */
+
+#ifndef environ
+ extern char **environ;
+#endif
+
+#undef getconf
+#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0)
+
+struct seconds
+{
+ Namfun_t hdr;
+ Shell_t *sh;
+};
+
+struct rand
+{
+ Namfun_t hdr;
+ Shell_t *sh;
+ int32_t rand_last;
+};
+
+struct ifs
+{
+ Namfun_t hdr;
+ Shell_t *sh;
+ Namval_t *ifsnp;
+};
+
+struct shell
+{
+ Namfun_t hdr;
+ Shell_t *sh;
+};
+
+struct match
+{
+ Namfun_t hdr;
+ char *val;
+ char *rval;
+ int vsize;
+ int nmatch;
+ int lastsub;
+ int match[2*(MATCH_MAX+1)];
+};
+
+typedef struct _init_
+{
+ Shell_t *sh;
+#if SHOPT_FS_3D
+ Namfun_t VPATH_init;
+#endif /* SHOPT_FS_3D */
+ struct ifs IFS_init;
+ struct shell PATH_init;
+#ifdef PATH_BFPATH
+ struct shell FPATH_init;
+ struct shell CDPATH_init;
+#endif
+ struct shell SHELL_init;
+ struct shell ENV_init;
+ struct shell VISUAL_init;
+ struct shell EDITOR_init;
+ struct shell OPTINDEX_init;
+ struct seconds SECONDS_init;
+ struct rand RAND_init;
+ struct shell LINENO_init;
+ struct shell L_ARG_init;
+ struct match SH_MATCH_init;
+#ifdef _hdr_locale
+ struct shell LC_TYPE_init;
+ struct shell LC_NUM_init;
+ struct shell LC_COLL_init;
+ struct shell LC_MSG_init;
+ struct shell LC_ALL_init;
+ struct shell LANG_init;
+#endif /* _hdr_locale */
+} Init_t;
+
+static void env_init(Shell_t*);
+static Init_t *nv_init(Shell_t*);
+static Dt_t *inittree(Shell_t*,const struct shtable2*);
+
+#ifdef _WINIX
+# define EXE "?(.exe)"
+#else
+# define EXE
+#endif
+
+static int rand_shift;
+
+
+/*
+ * Invalidate all path name bindings
+ */
+static void rehash(register Namval_t *np,void *data)
+{
+ NOT_USED(data);
+ nv_onattr(np,NV_NOALIAS);
+}
+
+/*
+ * out of memory routine for stak routines
+ */
+static char *nospace(int unused)
+{
+ NOT_USED(unused);
+ errormsg(SH_DICT,ERROR_exit(3),e_nospace);
+ return(NIL(char*));
+}
+
+/* Trap for VISUAL and EDITOR variables */
+static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ register const char *cp, *name=nv_name(np);
+ if(*name=='E' && nv_getval(nv_scoped(VISINOD)))
+ goto done;
+ sh_offoption(SH_VI);
+ sh_offoption(SH_EMACS);
+ sh_offoption(SH_GMACS);
+ if(!(cp=val) && (*name=='E' || !(cp=nv_getval(nv_scoped(EDITNOD)))))
+ goto done;
+ /* turn on vi or emacs option if editor name is either*/
+ cp = path_basename(cp);
+ if(strmatch(cp,"*[Vv][Ii]*"))
+ sh_onoption(SH_VI);
+ else if(strmatch(cp,"*gmacs*"))
+ sh_onoption(SH_GMACS);
+ else if(strmatch(cp,"*macs*"))
+ sh_onoption(SH_EMACS);
+done:
+ nv_putv(np, val, flags, fp);
+}
+
+/* Trap for OPTINDEX */
+static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ Shell_t *shp = ((struct shell*)fp)->sh;
+ shp->st.opterror = shp->st.optchar = 0;
+ nv_putv(np, val, flags, fp);
+}
+
+static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
+{
+ return((Sfdouble_t)*np->nvalue.lp);
+}
+
+/* Trap for restricted variables FPATH, PATH, SHELL, ENV */
+static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ Shell_t *shp = ((struct shell*)fp)->sh;
+ int path_scoped = 0;
+#ifdef PATH_BFPATH
+ Pathcomp_t *pp;
+ char *name = nv_name(np);
+#endif
+ if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
+ errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
+ if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
+ {
+#ifndef PATH_BFPATH
+ shp->lastpath = 0;
+#endif
+ nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
+ if(path_scoped && !val)
+ val = PATHNOD->nvalue.cp;
+ }
+ if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0)
+ return;
+#ifdef PATH_BFPATH
+ if(shp->pathlist && np==FPATHNOD)
+ shp->pathlist = (void*)path_unsetfpath((Pathcomp_t*)shp->pathlist);
+#endif
+ nv_putv(np, val, flags, fp);
+#ifdef PATH_BFPATH
+ if(shp->pathlist)
+ {
+ val = np->nvalue.cp;
+ if(np==PATHNOD || path_scoped)
+ pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
+ else if(val && np==FPATHNOD)
+ pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
+ else
+ return;
+ if(shp->pathlist = (void*)pp)
+ pp->shp = shp;
+ if(!val && (flags&NV_NOSCOPE))
+ {
+ Namval_t *mp = dtsearch(shp->var_tree,np);
+ if(mp && (val=nv_getval(mp)))
+ nv_putval(mp,val,NV_RDONLY);
+ }
+#if 0
+sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val);
+path_dump((Pathcomp_t*)shp->pathlist);
+#endif
+ }
+#endif
+}
+
+#ifdef PATH_BFPATH
+static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ Pathcomp_t *pp;
+ Shell_t *shp = ((struct shell*)fp)->sh;
+ nv_putv(np, val, flags, fp);
+ if(!shp->cdpathlist)
+ return;
+ val = np->nvalue.cp;
+ pp = (void*)path_addpath((Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH);
+ if(shp->cdpathlist = (void*)pp)
+ pp->shp = shp;
+}
+#endif
+
+#ifdef _hdr_locale
+ /*
+ * This function needs to be modified to handle international
+ * error message translations
+ */
+#if ERROR_VERSION >= 20000101L
+ static char* msg_translate(const char* catalog, const char* message)
+ {
+ NOT_USED(catalog);
+ return((char*)message);
+ }
+#else
+ static char* msg_translate(const char* message, int type)
+ {
+ NOT_USED(type);
+ return((char*)message);
+ }
+#endif
+
+ /* Trap for LC_ALL, LC_TYPE, LC_MESSAGES, LC_COLLATE and LANG */
+ static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp)
+ {
+ int type;
+ char *lc_all = nv_getval(LCALLNOD);
+ char *name = nv_name(np);
+ if(name==(LCALLNOD)->nvname)
+ type = LC_ALL;
+ else if(name==(LCTYPENOD)->nvname)
+ type = LC_CTYPE;
+ else if(name==(LCMSGNOD)->nvname)
+ type = LC_MESSAGES;
+ else if(name==(LCCOLLNOD)->nvname)
+ type = LC_COLLATE;
+ else if(name==(LCNUMNOD)->nvname)
+ type = LC_NUMERIC;
+ else if(name==(LANGNOD)->nvname && (!lc_all || *lc_all==0))
+ type = LC_ALL;
+ else
+ type= -1;
+ if(sh_isstate(SH_INIT) && type>=0 && type!=LC_ALL && lc_all && *lc_all)
+ type= -1;
+ if(type>=0)
+ {
+ if(!setlocale(type,val?val:""))
+ {
+ if(!sh_isstate(SH_INIT) || sh.login_sh==0)
+ errormsg(SH_DICT,0,e_badlocale,val);
+ return;
+ }
+ }
+ if(CC_NATIVE==CC_ASCII && (type==LC_ALL || type==LC_CTYPE))
+ {
+ if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
+ free((void*)sh_lexstates[ST_BEGIN]);
+ if(ast.locale.set&(1<<AST_LC_CTYPE))
+ {
+ register int c;
+ char *state[4];
+ sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
+ memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
+ sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
+ memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
+ sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
+ memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
+ sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
+ memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
+ for(c=0; c<(1<<CHAR_BIT); c++)
+ {
+ if(state[0][c]!=S_REG)
+ continue;
+ if(state[2][c]!=S_ERR)
+ continue;
+ if(isblank(c))
+ {
+ state[0][c]=0;
+ state[1][c]=S_BREAK;
+ state[2][c]=S_BREAK;
+ continue;
+ }
+ if(!isalpha(c))
+ continue;
+ state[0][c]=S_NAME;
+ if(state[1][c]==S_REG)
+ state[1][c]=0;
+ state[2][c]=S_ALP;
+ if(state[3][c]==S_ERR)
+ state[3][c]=0;
+ }
+ }
+ else
+ {
+ sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
+ sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
+ sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
+ sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
+ }
+ }
+#if ERROR_VERSION < 20000101L
+ if(type==LC_ALL || type==LC_MESSAGES)
+ error_info.translate = msg_translate;
+#endif
+ nv_putv(np, val, flags, fp);
+ }
+#endif /* _hdr_locale */
+
+/* Trap for IFS assignment and invalidates state table */
+static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ register struct ifs *ip = (struct ifs*)fp;
+ ip->ifsnp = 0;
+ if(val != np->nvalue.cp)
+ nv_putv(np, val, flags, fp);
+
+}
+
+/*
+ * This is the lookup function for IFS
+ * It keeps the sh.ifstable up to date
+ */
+static char* get_ifs(register Namval_t* np, Namfun_t *fp)
+{
+ register struct ifs *ip = (struct ifs*)fp;
+ register char *cp, *value;
+ register int c,n;
+ register Shell_t *shp = ip->sh;
+ value = nv_getv(np,fp);
+ if(np!=ip->ifsnp)
+ {
+ ip->ifsnp = np;
+ memset(shp->ifstable,0,(1<<CHAR_BIT));
+ if(cp=value)
+ {
+#if SHOPT_MULTIBYTE
+ while(n=mbsize(cp),c= *(unsigned char*)cp)
+#else
+ while(c= *(unsigned char*)cp++)
+#endif /* SHOPT_MULTIBYTE */
+ {
+#if SHOPT_MULTIBYTE
+ cp++;
+ if(n>1)
+ {
+ cp += (n-1);
+ shp->ifstable[c] = S_MBYTE;
+ continue;
+ }
+#endif /* SHOPT_MULTIBYTE */
+ n = S_DELIM;
+ if(c== *cp)
+ cp++;
+ else if(c=='\n')
+ n = S_NL;
+ else if(isspace(c))
+ n = S_SPACE;
+ shp->ifstable[c] = n;
+ }
+ }
+ else
+ {
+ shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE;
+ shp->ifstable['\n'] = S_NL;
+ }
+ }
+ return(value);
+}
+
+/*
+ * these functions are used to get and set the SECONDS variable
+ */
+#ifdef timeofday
+# define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
+# define tms timeval
+#else
+# define dtime(tp) (((double)times(tp))/sh.lim.clk_tck)
+# define timeofday(a)
+#endif
+
+static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ double d;
+ struct tms tp;
+ if(!val)
+ {
+ nv_stack(np, NIL(Namfun_t*));
+ nv_unset(np);
+ return;
+ }
+ if(!np->nvalue.dp)
+ {
+ nv_setsize(np,3);
+ np->nvalue.dp = new_of(double,0);
+ }
+ nv_putv(np, val, flags, fp);
+ d = *np->nvalue.dp;
+ timeofday(&tp);
+ *np->nvalue.dp = dtime(&tp)-d;
+}
+
+static char* get_seconds(register Namval_t* np, Namfun_t *fp)
+{
+ register int places = nv_size(np);
+ struct tms tp;
+ double d, offset = (np->nvalue.dp?*np->nvalue.dp:0);
+ NOT_USED(fp);
+ timeofday(&tp);
+ d = dtime(&tp)- offset;
+ sfprintf(sh.strbuf,"%.*f",places,d);
+ return(sfstruse(sh.strbuf));
+}
+
+static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp)
+{
+ struct tms tp;
+ double offset = (np->nvalue.dp?*np->nvalue.dp:0);
+ NOT_USED(fp);
+ timeofday(&tp);
+ return(dtime(&tp)- offset);
+}
+
+/*
+ * These three functions are used to get and set the RANDOM variable
+ */
+static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ struct rand *rp = (struct rand*)fp;
+ register long n;
+ if(!val)
+ {
+ nv_stack(np, NIL(Namfun_t*));
+ nv_unset(np);
+ return;
+ }
+ if(flags&NV_INTEGER)
+ n = *(double*)val;
+ else
+ n = sh_arith(val);
+ srand((int)(n&RANDMASK));
+ rp->rand_last = -1;
+ if(!np->nvalue.lp)
+ np->nvalue.lp = &rp->rand_last;
+}
+
+/*
+ * get random number in range of 0 - 2**15
+ * never pick same number twice in a row
+ */
+static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp)
+{
+ register long cur, last= *np->nvalue.lp;
+ NOT_USED(fp);
+ do
+ cur = (rand()>>rand_shift)&RANDMASK;
+ while(cur==last);
+ *np->nvalue.lp = cur;
+ return((Sfdouble_t)cur);
+}
+
+static char* get_rand(register Namval_t* np, Namfun_t *fp)
+{
+ register long n = nget_rand(np,fp);
+ return(fmtbase(n, 10, 0));
+}
+
+/*
+ * These three routines are for LINENO
+ */
+static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp)
+{
+ double d=1;
+ if(error_info.line >0)
+ d = error_info.line;
+ else if(error_info.context && error_info.context->line>0)
+ d = error_info.context->line;
+ NOT_USED(np);
+ NOT_USED(fp);
+ return(d);
+}
+
+static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ register long n;
+ Shell_t *shp = ((struct shell*)fp)->sh;
+ if(!val)
+ {
+ nv_stack(np, NIL(Namfun_t*));
+ nv_unset(np);
+ return;
+ }
+ if(flags&NV_INTEGER)
+ n = *(double*)val;
+ else
+ n = sh_arith(val);
+ shp->st.firstline += nget_lineno(np,fp)+1-n;
+}
+
+static char* get_lineno(register Namval_t* np, Namfun_t *fp)
+{
+ register long n = nget_lineno(np,fp);
+ return(fmtbase(n, 10, 0));
+}
+
+static char* get_lastarg(Namval_t* np, Namfun_t *fp)
+{
+ NOT_USED(np);
+ return(sh.lastarg);
+}
+
+static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp)
+{
+ if(flags&NV_INTEGER)
+ {
+ sfprintf(sh.strbuf,"%.*g",12,*((double*)val));
+ val = sfstruse(sh.strbuf);
+ }
+ if(sh.lastarg && !nv_isattr(np,NV_NOFREE))
+ free((void*)sh.lastarg);
+ else
+ nv_offattr(np,NV_NOFREE);
+ if(val)
+ sh.lastarg = strdup(val);
+ else
+ sh.lastarg = 0;
+}
+
+static int hasgetdisc(register Namfun_t *fp)
+{
+ while(fp && !fp->disc->getnum && !fp->disc->getval)
+ fp = fp->next;
+ return(fp!=0);
+}
+
+/*
+ * store the most recent value for use in .sh.match
+ */
+void sh_setmatch(const char *v, int vsize, int nmatch, int match[])
+{
+ struct match *mp = (struct match*)(SH_MATCHNOD->nvfun);
+ register int i,n;
+ if(mp->nmatch = nmatch)
+ {
+ memcpy(mp->match,match,nmatch*2*sizeof(match[0]));
+ for(n=match[0],i=1; i < 2*nmatch; i++)
+ {
+ if(mp->match[i] < n)
+ n = mp->match[i];
+ }
+ for(vsize=0,i=0; i < 2*nmatch; i++)
+ {
+ if((mp->match[i] -= n) > vsize)
+ vsize = mp->match[i];
+ }
+ v += n;
+ if(vsize >= mp->vsize)
+ {
+ if(mp->vsize)
+ mp->val = (char*)realloc(mp->val,vsize+1);
+ else
+ mp->val = (char*)malloc(vsize+1);
+ mp->vsize = vsize;
+ }
+ memcpy(mp->val,v,vsize);
+ mp->val[vsize] = 0;
+ nv_putsub(SH_MATCHNOD, NIL(char*), nmatch|ARRAY_FILL);
+ mp->lastsub = -1;
+ }
+}
+
+#define array_scan(np) ((nv_arrayptr(np)->nelem&ARRAY_SCAN))
+
+static char* get_match(register Namval_t* np, Namfun_t *fp)
+{
+ struct match *mp = (struct match*)fp;
+ int sub,n;
+ char *val;
+ sub = nv_aindex(np);
+ if(sub>=mp->nmatch)
+ return(0);
+ if(sub==mp->lastsub)
+ return(mp->rval);
+ if(mp->rval)
+ {
+ free((void*)mp->rval);
+ mp->rval = 0;
+ }
+ n = mp->match[2*sub+1]-mp->match[2*sub];
+ if(n<=0)
+ return("");
+ val = mp->val+mp->match[2*sub];
+ if(mp->val[mp->match[2*sub+1]]==0)
+ return(val);
+ mp->rval = (char*)malloc(n+1);
+ mp->lastsub = sub;
+ memcpy(mp->rval,val,n);
+ mp->rval[n] = 0;
+ return(mp->rval);
+}
+
+static const Namdisc_t SH_MATCH_disc = { sizeof(struct match), 0, get_match };
+
+#if SHOPT_FS_3D
+ /*
+ * set or unset the mappings given a colon separated list of directories
+ */
+ static void vpath_set(char *str, int mode)
+ {
+ register char *lastp, *oldp=str, *newp=strchr(oldp,':');
+ if(!sh.lim.fs3d)
+ return;
+ while(newp)
+ {
+ *newp++ = 0;
+ if(lastp=strchr(newp,':'))
+ *lastp = 0;
+ mount((mode?newp:""),oldp,FS3D_VIEW,0);
+ newp[-1] = ':';
+ oldp = newp;
+ newp=lastp;
+ }
+ }
+
+ /* catch vpath assignments */
+ static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
+ {
+ register char *cp;
+ if(cp = nv_getval(np))
+ vpath_set(cp,0);
+ if(val)
+ vpath_set((char*)val,1);
+ nv_putv(np,val,flags,fp);
+ }
+ static const Namdisc_t VPATH_disc = { 0, put_vpath };
+ static Namfun_t VPATH_init = { &VPATH_disc, 1 };
+#endif /* SHOPT_FS_3D */
+
+
+static const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs };
+const Namdisc_t RESTRICTED_disc = { sizeof(struct shell), put_restricted };
+#ifdef PATH_BFPATH
+static const Namdisc_t CDPATH_disc = { sizeof(struct shell), put_cdpath };
+#endif
+static const Namdisc_t EDITOR_disc = { sizeof(struct shell), put_ed };
+static const Namdisc_t OPTINDEX_disc = { sizeof(struct shell), put_optindex, 0, nget_optindex };
+static const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds };
+static const Namdisc_t RAND_disc = { sizeof(struct rand), put_rand, get_rand, nget_rand };
+static const Namdisc_t LINENO_disc = { sizeof(struct shell), put_lineno, get_lineno, nget_lineno };
+static const Namdisc_t L_ARG_disc = { sizeof(struct shell), put_lastarg, get_lastarg };
+
+#if SHOPT_NAMESPACE
+ static char* get_nspace(Namval_t* np, Namfun_t *fp)
+ {
+ if(sh.namespace)
+ return(nv_name(sh.namespace));
+ return((char*)np->nvalue.cp);
+ }
+ static const Namdisc_t NSPACE_disc = { 0, 0, get_nspace };
+ static Namfun_t NSPACE_init = { &NSPACE_disc, 1};
+#endif /* SHOPT_NAMESPACE */
+
+#ifdef _hdr_locale
+ static const Namdisc_t LC_disc = { sizeof(struct shell), put_lang };
+#endif /* _hdr_locale */
+
+/*
+ * This function will get called whenever a configuration parameter changes
+ */
+static int newconf(const char *name, const char *path, const char *value)
+{
+ register char *arg;
+ if(!name)
+ setenviron(value);
+ else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
+ {
+ sh.universe = 0;
+ /* set directory in new universe */
+ if(*(arg = path_pwd(0))=='/')
+ chdir(arg);
+ /* clear out old tracked alias */
+ stakseek(0);
+ stakputs(nv_getval(PATHNOD));
+ stakputc(0);
+ nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
+ }
+ return(1);
+}
+
+#if (CC_NATIVE != CC_ASCII)
+ static void a2e(char *d, const char *s)
+ {
+ register const unsigned char *t;
+ register int i;
+ t = CCMAP(CC_ASCII, CC_NATIVE);
+ for(i=0; i<(1<<CHAR_BIT); i++)
+ d[t[i]] = s[i];
+ }
+
+ static void init_ebcdic(void)
+ {
+ int i;
+ char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT));
+ for(i=0; i < ST_NONE; i++)
+ {
+ a2e(cp,sh_lexrstates[i]);
+ sh_lexstates[i] = cp;
+ cp += (1<<CHAR_BIT);
+ }
+ }
+#endif
+
+/*
+ * return SH_TYPE_* bitmask for path
+ * 0 for "not a shell"
+ */
+int sh_type(register const char *path)
+{
+ register const char* s;
+ register int t = 0;
+
+ if (s = (const char*)strrchr(path, '/'))
+ {
+ if (*path == '-')
+ t |= SH_TYPE_LOGIN;
+ s++;
+ }
+ else
+ s = path;
+ if (*s == '-')
+ {
+ s++;
+ t |= SH_TYPE_LOGIN;
+ }
+ for (;;)
+ {
+ if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH)))
+ {
+ if (*s == 'k')
+ {
+ s++;
+ t |= SH_TYPE_KSH;
+ continue;
+ }
+#if SHOPT_BASH
+ if (*s == 'b' && *(s+1) == 'a')
+ {
+ s += 2;
+ t |= SH_TYPE_BASH;
+ continue;
+ }
+#endif
+ }
+ if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED)))
+ {
+#if SHOPT_PFSH
+ if (*s == 'p' && *(s+1) == 'f')
+ {
+ s += 2;
+ t |= SH_TYPE_PROFILE;
+ continue;
+ }
+#endif
+ if (*s == 'r')
+ {
+ s++;
+ t |= SH_TYPE_RESTRICTED;
+ continue;
+ }
+ }
+ break;
+ }
+ if (*s++ != 's' || *s++ != 'h')
+ return 0;
+ t |= SH_TYPE_SH;
+ if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3')
+ s += 2;
+#if _WINIX
+ if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e')
+ s += 4;
+#endif
+ if (*s)
+ t &= ~(SH_TYPE_PROFILE|SH_TYPE_RESTRICTED);
+ return t;
+}
+
+/*
+ * initialize the shell
+ */
+Shell_t *sh_init(register int argc,register char *argv[], void(*userinit)(int))
+{
+ register int n;
+ int type;
+ static char *login_files[3];
+ n = strlen(e_version);
+ if(e_version[n-1]=='$' && e_version[n-2]==' ')
+ e_version[n-2]=0;
+#if (CC_NATIVE == CC_ASCII)
+ memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
+#else
+ init_ebcdic();
+#endif
+ umask(umask(0));
+ sh.mac_context = sh_macopen(&sh);
+ sh.arg_context = sh_argopen(&sh);
+ sh.lex_context = (void*)sh_lexopen(0,&sh,1);
+ sh.ed_context = (void*)ed_open(&sh);
+ sh.strbuf = sfstropen();
+ sfsetbuf(sh.strbuf,(char*)0,64);
+ sh_onstate(SH_INIT);
+ error_info.exit = sh_exit;
+ error_info.id = path_basename(argv[0]);
+#if ERROR_VERSION >= 20000102L
+ error_info.catalog = e_dict;
+#endif
+ sh.cpipe[0] = -1;
+ sh.coutpipe = -1;
+ sh.userid=getuid();
+ sh.euserid=geteuid();
+ sh.groupid=getgid();
+ sh.egroupid=getegid();
+ for(n=0;n < 10; n++)
+ {
+ /* don't use lower bits when rand() generates large numbers */
+ if(rand() > RANDMASK)
+ {
+ rand_shift = 3;
+ break;
+ }
+ }
+ sh.lim.clk_tck = getconf("CLK_TCK");
+ sh.lim.arg_max = getconf("ARG_MAX");
+ sh.lim.open_max = getconf("OPEN_MAX");
+ sh.lim.child_max = getconf("CHILD_MAX");
+ sh.lim.ngroups_max = getconf("NGROUPS_MAX");
+ sh.lim.posix_version = getconf("VERSION");
+ sh.lim.posix_jobcontrol = getconf("JOB_CONTROL");
+ if(sh.lim.arg_max <=0)
+ sh.lim.arg_max = ARG_MAX;
+ if(sh.lim.child_max <=0)
+ sh.lim.child_max = CHILD_MAX;
+ if(sh.lim.open_max <0)
+ sh.lim.open_max = OPEN_MAX;
+ if(sh.lim.open_max > (SHRT_MAX-2))
+ sh.lim.open_max = SHRT_MAX-2;
+ if(sh.lim.clk_tck <=0)
+ sh.lim.clk_tck = CLK_TCK;
+#if SHOPT_FS_3D
+ if(fs3d(FS3D_TEST))
+ sh.lim.fs3d = 1;
+#endif /* SHOPT_FS_3D */
+ sh_ioinit();
+ /* initialize signal handling */
+ sh_siginit();
+ stakinstall(NIL(Stak_t*),nospace);
+ /* set up memory for name-value pairs */
+ sh.init_context = nv_init(&sh);
+ /* read the environment */
+ if(argc>0)
+ {
+ type = sh_type(*argv);
+ if(type&SH_TYPE_LOGIN)
+ sh.login_sh = 2;
+ }
+ env_init(&sh);
+#if SHOPT_SPAWN
+ {
+ /*
+ * try to find the pathname for this interpreter
+ * try using environment variable _ or argv[0]
+ */
+ char *last, *cp=nv_getval(L_ARGNOD);
+ char buff[PATH_MAX+1];
+ sh.shpath = 0;
+ sfprintf(sh.strbuf,"/proc/%d/exe",getpid());
+ if((n=readlink(sfstruse(sh.strbuf),buff,sizeof(buff)-1))>0)
+ {
+ buff[n] = 0;
+ sh.shpath = strdup(buff);
+ }
+ else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
+ {
+ if(*cp=='/')
+ sh.shpath = strdup(cp);
+ else if(cp = nv_getval(PWDNOD))
+ {
+ int offset = staktell();
+ stakputs(cp);
+ stakputc('/');
+ stakputs(argv[0]);
+ pathcanon(stakptr(offset),PATH_DOTDOT);
+ sh.shpath = strdup(stakptr(offset));
+ stakseek(offset);
+ }
+ }
+ }
+#endif
+ nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
+#if SHOPT_FS_3D
+ nv_stack(VPATHNOD, &VPATH_init);
+#endif /* SHOPT_FS_3D */
+ astconfdisc(newconf);
+#if SHOPT_TIMEOUT
+ sh.st.tmout = SHOPT_TIMEOUT;
+#endif /* SHOPT_TIMEOUT */
+ /* initialize jobs table */
+ job_clear();
+ if(argc>0)
+ {
+ /* check for restricted shell */
+ if(type&SH_TYPE_RESTRICTED)
+ sh_onoption(SH_RESTRICTED);
+#if SHOPT_PFSH
+ /* check for profile shell */
+ else if(type&SH_TYPE_PROFILE)
+ sh_onoption(SH_PFSH);
+#endif
+#if SHOPT_BASH
+ /* check for invocation as bash */
+ if(type&SH_TYPE_BASH)
+ {
+ sh.userinit = userinit = bash_init;
+ sh_onoption(SH_BASH);
+ sh_onstate(SH_PREINIT);
+ (*userinit)(0);
+ sh_offstate(SH_PREINIT);
+ }
+#endif
+ /* look for options */
+ /* sh.st.dolc is $# */
+ if((sh.st.dolc = sh_argopts(-argc,argv)) < 0)
+ {
+ sh.exitval = 2;
+ sh_done(0);
+ }
+ opt_info.disc = 0;
+ sh.st.dolv=argv+(argc-1)-sh.st.dolc;
+ sh.st.dolv[0] = argv[0];
+ if(sh.st.dolc < 1)
+ sh_onoption(SH_SFLAG);
+ if(!sh_isoption(SH_SFLAG))
+ {
+ sh.st.dolc--;
+ sh.st.dolv++;
+#if _WINIX
+ {
+ char* name;
+ name = sh.st.dolv[0];
+ if(name[1]==':' && (name[2]=='/' || name[2]=='\\'))
+ {
+#if _lib_pathposix
+ char* p;
+
+ if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n)))
+ {
+ pathposix(name, p, n);
+ name = p;
+ }
+ else
+#endif
+ {
+ name[1] = name[0];
+ name[0] = name[2] = '/';
+ }
+ }
+ }
+#endif /* _WINIX */
+ }
+ }
+#if SHOPT_PFSH
+ if (sh_isoption(SH_PFSH))
+ {
+ struct passwd *pw = getpwuid(sh.userid);
+ if(pw)
+ sh.user = strdup(pw->pw_name);
+
+ }
+#endif
+ /* set[ug]id scripts require the -p flag */
+ if(sh.userid!=sh.euserid || sh.groupid!=sh.egroupid)
+ {
+#if SHOPT_P_SUID
+ /* require sh -p to run setuid and/or setgid */
+ if(!sh_isoption(SH_PRIVILEGED) && sh.euserid < SHOPT_P_SUID)
+ {
+ setuid(sh.euserid=sh.userid);
+ setgid(sh.egroupid=sh.groupid);
+ }
+ else
+#else
+ sh_onoption(SH_PRIVILEGED);
+#endif /* SHOPT_P_SUID */
+#ifdef SHELLMAGIC
+ /* careful of #! setuid scripts with name beginning with - */
+ if(sh.login_sh && argv[1] && strcmp(argv[0],argv[1])==0)
+ errormsg(SH_DICT,ERROR_exit(1),e_prohibited);
+#endif /*SHELLMAGIC*/
+ }
+ else
+ sh_offoption(SH_PRIVILEGED);
+ /* shname for $0 in profiles and . scripts */
+ if(strmatch(argv[1],e_devfdNN))
+ sh.shname = strdup(argv[0]);
+ else
+ sh.shname = strdup(sh.st.dolv[0]);
+ /*
+ * return here for shell script execution
+ * but not for parenthesis subshells
+ */
+ error_info.id = strdup(sh.st.dolv[0]); /* error_info.id is $0 */
+ sh.jmpbuffer = (void*)&sh.checkbase;
+ sh_pushcontext(&sh.checkbase,SH_JMPSCRIPT);
+ sh.st.self = &sh.global;
+ sh.topscope = (Shscope_t*)sh.st.self;
+ sh_offstate(SH_INIT);
+ login_files[0] = (char*)e_profile;
+ login_files[1] = ".profile";
+ sh.login_files = login_files;
+ if(sh.userinit=userinit)
+ (*userinit)(0);
+ return(&sh);
+}
+
+Shell_t *sh_getinterp(void)
+{
+ return(&sh);
+}
+
+/*
+ * reinitialize before executing a script
+ */
+int sh_reinit(char *argv[])
+{
+ Shopt_t opt;
+ dtclear(sh.fun_tree);
+ dtclose(sh.alias_tree);
+ sh.alias_tree = inittree(&sh,shtab_aliases);
+ sh.namespace = 0;
+ sh.inuse_bits = 0;
+ if(sh.userinit)
+ (*sh.userinit)(1);
+ if(sh.heredocs)
+ {
+ sfclose(sh.heredocs);
+ sh.heredocs = 0;
+ }
+ /* remove locals */
+ sh_onstate(SH_INIT);
+ nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_EXPORT,0);
+ nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_ARRAY,NV_ARRAY);
+ sh_offstate(SH_INIT);
+ memset(sh.st.trapcom,0,(sh.st.trapmax+1)*sizeof(char*));
+ memset((void*)&opt,0,sizeof(opt));
+ if(sh_isoption(SH_TRACKALL))
+ on_option(&opt,SH_TRACKALL);
+ if(sh_isoption(SH_EMACS))
+ on_option(&opt,SH_EMACS);
+ if(sh_isoption(SH_GMACS))
+ on_option(&opt,SH_GMACS);
+ if(sh_isoption(SH_VI))
+ on_option(&opt,SH_VI);
+ if(sh_isoption(SH_VIRAW))
+ on_option(&opt,SH_VIRAW);
+ sh.options = opt;
+ /* set up new args */
+ if(argv)
+ sh.arglist = sh_argcreate(argv);
+ if(sh.arglist)
+ sh_argreset(sh.arglist,NIL(struct dolnod*));
+ sh.envlist=0;
+ sh.curenv = 0;
+ sh.shname = error_info.id = strdup(sh.st.dolv[0]);
+ sh_offstate(SH_FORKED);
+ sh.fn_depth = sh.dot_depth = 0;
+ sh_sigreset(0);
+ return(1);
+}
+
+/*
+ * set when creating a local variable of this name
+ */
+Namfun_t *nv_cover(register Namval_t *np)
+{
+#ifdef PATH_BFPATH
+ if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS)
+#else
+ if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==SECONDS)
+#endif
+ return(np->nvfun);
+#ifdef _hdr_locale
+ if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD)
+ return(np->nvfun);
+#endif
+ return(0);
+}
+
+static Namtype_t typeset;
+static const char *shdiscnames[] = { "tilde", 0};
+
+/*
+ * Initialize the shell name and alias table
+ */
+static Init_t *nv_init(Shell_t *shp)
+{
+ Namval_t *np;
+ register Init_t *ip;
+ double d=0;
+ ip = newof(0,Init_t,1,0);
+ if(!ip)
+ return(0);
+ ip->sh = shp;
+ shp->var_base = shp->var_tree = inittree(shp,shtab_variables);
+ ip->IFS_init.hdr.disc = &IFS_disc;
+ ip->IFS_init.hdr.nofree = 1;
+ ip->IFS_init.sh = shp;
+ ip->PATH_init.hdr.disc = &RESTRICTED_disc;
+ ip->PATH_init.hdr.nofree = 1;
+ ip->PATH_init.sh = shp;
+#ifdef PATH_BFPATH
+ ip->FPATH_init.hdr.disc = &RESTRICTED_disc;
+ ip->FPATH_init.hdr.nofree = 1;
+ ip->FPATH_init.sh = shp;
+ ip->CDPATH_init.hdr.disc = &CDPATH_disc;
+ ip->CDPATH_init.hdr.nofree = 1;
+ ip->CDPATH_init.sh = shp;
+#endif
+ ip->SHELL_init.hdr.disc = &RESTRICTED_disc;
+ ip->SHELL_init.sh = shp;
+ ip->SHELL_init.hdr.nofree = 1;
+ ip->ENV_init.hdr.disc = &RESTRICTED_disc;
+ ip->ENV_init.hdr.nofree = 1;
+ ip->ENV_init.sh = shp;
+ ip->VISUAL_init.hdr.disc = &EDITOR_disc;
+ ip->VISUAL_init.hdr.nofree = 1;
+ ip->VISUAL_init.sh = shp;
+ ip->EDITOR_init.hdr.disc = &EDITOR_disc;
+ ip->EDITOR_init.hdr.nofree = 1;
+ ip->EDITOR_init.sh = shp;
+ ip->OPTINDEX_init.hdr.disc = &OPTINDEX_disc;
+ ip->OPTINDEX_init.hdr.nofree = 1;
+ ip->OPTINDEX_init.sh = shp;
+ ip->SECONDS_init.hdr.disc = &SECONDS_disc;
+ ip->SECONDS_init.hdr.nofree = 1;
+ ip->SECONDS_init.sh = shp;
+ ip->RAND_init.hdr.disc = &RAND_disc;
+ ip->RAND_init.hdr.nofree = 1;
+ ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc;
+ ip->SH_MATCH_init.hdr.nofree = 1;
+ ip->LINENO_init.hdr.disc = &LINENO_disc;
+ ip->LINENO_init.hdr.nofree = 1;
+ ip->LINENO_init.sh = shp;
+ ip->L_ARG_init.hdr.disc = &L_ARG_disc;
+ ip->L_ARG_init.hdr.nofree = 1;
+#ifdef _hdr_locale
+ ip->LC_TYPE_init.hdr.disc = &LC_disc;
+ ip->LC_TYPE_init.hdr.nofree = 1;
+ ip->LC_NUM_init.hdr.disc = &LC_disc;
+ ip->LC_NUM_init.hdr.nofree = 1;
+ ip->LC_COLL_init.hdr.disc = &LC_disc;
+ ip->LC_COLL_init.hdr.nofree = 1;
+ ip->LC_MSG_init.hdr.disc = &LC_disc;
+ ip->LC_MSG_init.hdr.nofree = 1;
+ ip->LC_ALL_init.hdr.disc = &LC_disc;
+ ip->LC_ALL_init.hdr.nofree = 1;
+ ip->LANG_init.hdr.disc = &LC_disc;
+ ip->LANG_init.hdr.nofree = 1;
+ ip->LC_TYPE_init.sh = shp;
+ ip->LC_NUM_init.sh = shp;
+ ip->LC_COLL_init.sh = shp;
+ ip->LC_MSG_init.sh = shp;
+ ip->LANG_init.sh = shp;
+#endif /* _hdr_locale */
+ nv_stack(IFSNOD, &ip->IFS_init.hdr);
+ nv_stack(PATHNOD, &ip->PATH_init.hdr);
+#ifdef PATH_BFPATH
+ nv_stack(FPATHNOD, &ip->FPATH_init.hdr);
+ nv_stack(CDPNOD, &ip->CDPATH_init.hdr);
+#endif
+ nv_stack(SHELLNOD, &ip->SHELL_init.hdr);
+ nv_stack(ENVNOD, &ip->ENV_init.hdr);
+ nv_stack(VISINOD, &ip->VISUAL_init.hdr);
+ nv_stack(EDITNOD, &ip->EDITOR_init.hdr);
+ nv_stack(OPTINDNOD, &ip->OPTINDEX_init.hdr);
+ nv_stack(SECONDS, &ip->SECONDS_init.hdr);
+ nv_stack(L_ARGNOD, &ip->L_ARG_init.hdr);
+ nv_putval(SECONDS, (char*)&d, NV_INTEGER|NV_DOUBLE);
+ nv_stack(RANDNOD, &ip->RAND_init.hdr);
+ d = (shp->pid&RANDMASK);
+ nv_putval(RANDNOD, (char*)&d, NV_INTEGER|NV_DOUBLE);
+ nv_stack(LINENO, &ip->LINENO_init.hdr);
+ nv_putsub(SH_MATCHNOD,(char*)0,10);
+ nv_onattr(SH_MATCHNOD,NV_RDONLY);
+ nv_stack(SH_MATCHNOD, &ip->SH_MATCH_init.hdr);
+#ifdef _hdr_locale
+ nv_stack(LCTYPENOD, &ip->LC_TYPE_init.hdr);
+ nv_stack(LCALLNOD, &ip->LC_ALL_init.hdr);
+ nv_stack(LCMSGNOD, &ip->LC_MSG_init.hdr);
+ nv_stack(LCCOLLNOD, &ip->LC_COLL_init.hdr);
+ nv_stack(LCNUMNOD, &ip->LC_NUM_init.hdr);
+ nv_stack(LANGNOD, &ip->LANG_init.hdr);
+#endif /* _hdr_locale */
+ (PPIDNOD)->nvalue.lp = (&shp->ppid);
+ (TMOUTNOD)->nvalue.lp = (&shp->st.tmout);
+ (MCHKNOD)->nvalue.lp = (&sh_mailchk);
+ (OPTINDNOD)->nvalue.lp = (&shp->st.optindex);
+ /* set up the seconds clock */
+ shp->alias_tree = inittree(shp,shtab_aliases);
+ shp->track_tree = dtopen(&_Nvdisc,Dtset);
+ shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins);
+ typeset.shp = shp;
+ typeset.optstring = sh_opttypeset;
+ nv_search("typeset",shp->bltin_tree,0)->nvfun = (void*)&typeset;
+#if SHOPT_BASH
+ nv_search("local",shp->bltin_tree,0)->nvfun = (void*)&typeset;
+#endif
+ shp->fun_tree = dtopen(&_Nvdisc,Dtoset);
+ dtview(shp->fun_tree,shp->bltin_tree);
+#if SHOPT_NAMESPACE
+ if(np = nv_mount(DOTSHNOD, "global", shp->var_tree))
+ nv_onattr(np,NV_RDONLY);
+ np = nv_search("namespace",nv_dict(DOTSHNOD),NV_ADD);
+ nv_putval(np,".sh.global",NV_RDONLY|NV_NOFREE);
+ nv_stack(np, &NSPACE_init);
+#endif /* SHOPT_NAMESPACE */
+ np = nv_mount(DOTSHNOD, "type", dtopen(&_Nvdisc,Dtoset));
+ nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0);
+ return(ip);
+}
+
+/*
+ * initialize name-value pairs
+ */
+
+static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
+{
+ register Namval_t *np;
+ register const struct shtable2 *tp;
+ register unsigned n = 0;
+ register Dt_t *treep;
+ Dt_t *base_treep, *dict;
+ for(tp=name_vals;*tp->sh_name;tp++)
+ n++;
+ np = (Namval_t*)calloc(n,sizeof(Namval_t));
+ if(!shp->bltin_nodes)
+ shp->bltin_nodes = np;
+ else if(name_vals==(const struct shtable2*)shtab_builtins)
+ shp->bltin_cmds = np;
+ base_treep = treep = dtopen(&_Nvdisc,Dtoset);
+ for(tp=name_vals;*tp->sh_name;tp++,np++)
+ {
+ if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name))
+ np->nvname++;
+ else
+ {
+ np->nvname = (char*)tp->sh_name;
+ treep = base_treep;
+ }
+ np->nvenv = 0;
+ if(name_vals==(const struct shtable2*)shtab_builtins)
+ np->nvalue.bfp = ((struct shtable3*)tp)->sh_value;
+ else
+ np->nvalue.cp = (char*)tp->sh_value;
+ nv_setattr(np,tp->sh_number);
+ if(nv_istable(np))
+ nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset));
+ if(nv_isattr(np,NV_INTEGER))
+ nv_setsize(np,10);
+ else
+ nv_setsize(np,0);
+ dtinsert(treep,np);
+ if(nv_istable(np))
+ treep = dict;
+ }
+ return(treep);
+}
+
+/*
+ * read in the process environment and set up name-value pairs
+ * skip over items that are not name-value pairs
+ */
+
+static void env_init(Shell_t *shp)
+{
+ register char *cp;
+ register Namval_t *np;
+ register char **ep=environ;
+ register char *next=0;
+#ifdef _ENV_H
+ shp->env = env_open(environ,3);
+ env_delete(shp->env,"_");
+#endif
+ if(ep)
+ {
+ while(cp= *ep++)
+ {
+ if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=')
+ next = cp+4;
+ else if(np=nv_open(cp,shp->var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN|NV_NOFAIL)))
+ {
+ nv_onattr(np,NV_IMPORT);
+ np->nvenv = cp;
+ nv_close(np);
+ }
+ }
+ while(cp=next)
+ {
+ if(next = strchr(++cp,'='))
+ *next = 0;
+ np = nv_search(cp+2,shp->var_tree,NV_ADD);
+ if(nv_isattr(np,NV_IMPORT|NV_EXPORT))
+ {
+ int flag = *(unsigned char*)cp-' ';
+ int size = *(unsigned char*)(cp+1)-' ';
+ if((flag&NV_INTEGER) && size==0)
+ {
+ /* check for floating*/
+ char *ep,*val = nv_getval(np);
+ strtol(val,&ep,10);
+ if(*ep=='.' || *ep=='e' || *ep=='E')
+ {
+ char *lp;
+ flag |= NV_DOUBLE;
+ if(*ep=='.')
+ {
+ strtol(ep+1,&lp,10);
+ if(*lp)
+ ep = lp;
+ }
+ if(*ep && *ep!='.')
+ {
+ flag |= NV_EXPNOTE;
+ size = ep-val;
+ }
+ else
+ size = strlen(ep);
+ size--;
+ }
+ }
+ nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
+ }
+ }
+ }
+#ifdef _ENV_H
+ env_delete(sh.env,e_envmarker);
+#endif
+ if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
+ {
+ nv_offattr(PWDNOD,NV_TAGGED);
+ path_pwd(0);
+ }
+ if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
+ sh_onoption(SH_RESTRICTED); /* restricted shell */
+ return;
+}
+
+/*
+ * terminate shell and free up the space
+ */
+int sh_term(void)
+{
+ sfdisc(sfstdin,SF_POPDISC);
+ free((char*)sh.outbuff);
+ stakset(NIL(char*),0);
+ return(0);
+}
+
+/* function versions of these */
+
+#define DISABLE /* proto workaround */
+
+unsigned long sh_isoption DISABLE (int opt)
+{
+ return(sh_isoption(opt));
+}
+
+unsigned long sh_onoption DISABLE (int opt)
+{
+ return(sh_onoption(opt));
+}
+
+unsigned long sh_offoption DISABLE (int opt)
+{
+ return(sh_offoption(opt));
+}
+
+void sh_sigcheck DISABLE (void)
+{
+ sh_sigcheck();
+}
+
+Dt_t* sh_bltin_tree DISABLE (void)
+{
+ return(sh.bltin_tree);
+}