1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1982-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A *
1N/A * Shell initialization
1N/A *
1N/A * David Korn
1N/A * AT&T Labs
1N/A *
1N/A */
1N/A
1N/A#include "defs.h"
1N/A#include <stak.h>
1N/A#include <ccode.h>
1N/A#include <pwd.h>
1N/A#include <tmx.h>
1N/A#include "variables.h"
1N/A#include "path.h"
1N/A#include "fault.h"
1N/A#include "name.h"
1N/A#include "edit.h"
1N/A#include "jobs.h"
1N/A#include "io.h"
1N/A#include "shlex.h"
1N/A#include "builtins.h"
1N/A#include "FEATURE/time"
1N/A#include "FEATURE/dynamic"
1N/A#include "FEATURE/externs"
1N/A#include "lexstates.h"
1N/A#include "version.h"
1N/A
1N/A#if _hdr_wctype
1N/A#include <ast_wchar.h>
1N/A#include <wctype.h>
1N/A#endif
1N/A#if !_typ_wctrans_t
1N/A#undef wctrans_t
1N/A#define wctrans_t sh_wctrans_t
1N/Atypedef long wctrans_t;
1N/A#endif
1N/A#if !_lib_wctrans
1N/A#undef wctrans
1N/A#define wctrans sh_wctrans
1N/Astatic wctrans_t wctrans(const char *name)
1N/A{
1N/A if(strcmp(name,e_tolower)==0)
1N/A return(1);
1N/A else if(strcmp(name,e_toupper)==0)
1N/A return(2);
1N/A return(0);
1N/A}
1N/A#endif
1N/A#if !_lib_towctrans
1N/A#undef towctrans
1N/A#define towctrans sh_towctrans
1N/Astatic int towctrans(int c, wctrans_t t)
1N/A{
1N/A if(t==1 && isupper(c))
1N/A c = tolower(c);
1N/A else if(t==2 && isupper(c))
1N/A c = toupper(c);
1N/A return(c);
1N/A}
1N/A#endif
1N/A
1N/Achar e_version[] = "\n@(#)$Id: Version "
1N/A#if SHOPT_AUDIT
1N/A#define ATTRS 1
1N/A "A"
1N/A#endif
1N/A#if SHOPT_BASH
1N/A#define ATTRS 1
1N/A "B"
1N/A#endif
1N/A#if SHOPT_COSHELL
1N/A#define ATTRS 1
1N/A "J"
1N/A#else
1N/A#if SHOPT_BGX
1N/A#define ATTRS 1
1N/A "j"
1N/A#endif
1N/A#endif
1N/A#if SHOPT_ACCT
1N/A#define ATTRS 1
1N/A "L"
1N/A#endif
1N/A#if SHOPT_MULTIBYTE
1N/A#define ATTRS 1
1N/A "M"
1N/A#endif
1N/A#if SHOPT_PFSH && _hdr_exec_attr
1N/A#define ATTRS 1
1N/A "P"
1N/A#endif
1N/A#if SHOPT_REGRESS
1N/A#define ATTRS 1
1N/A "R"
1N/A#endif
1N/A#if ATTRS
1N/A " "
1N/A#endif
1N/A SH_RELEASE " $\0\n";
1N/A
1N/A#if SHOPT_BASH
1N/A extern void bash_init(Shell_t*,int);
1N/A#endif
1N/A
1N/A#define RANDMASK 0x7fff
1N/A
1N/A#ifndef ARG_MAX
1N/A# define ARG_MAX (1*1024*1024)
1N/A#endif
1N/A#ifndef CHILD_MAX
1N/A# define CHILD_MAX (1*1024)
1N/A#endif
1N/A#ifndef CLK_TCK
1N/A# define CLK_TCK 60
1N/A#endif /* CLK_TCK */
1N/A
1N/A#ifndef environ
1N/A extern char **environ;
1N/A#endif
1N/A
1N/A#undef getconf
1N/A#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0)
1N/A
1N/Astruct seconds
1N/A{
1N/A Namfun_t hdr;
1N/A Shell_t *sh;
1N/A};
1N/A
1N/Astruct rand
1N/A{
1N/A Namfun_t hdr;
1N/A Shell_t *sh;
1N/A int32_t rand_last;
1N/A};
1N/A
1N/Astruct ifs
1N/A{
1N/A Namfun_t hdr;
1N/A Namval_t *ifsnp;
1N/A};
1N/A
1N/Astruct match
1N/A{
1N/A Namfun_t hdr;
1N/A char *val;
1N/A char *rval;
1N/A int vsize;
1N/A int nmatch;
1N/A int lastsub;
1N/A int match[2*(MATCH_MAX+1)];
1N/A};
1N/A
1N/Atypedef struct _init_
1N/A{
1N/A Shell_t *sh;
1N/A#if SHOPT_FS_3D
1N/A Namfun_t VPATH_init;
1N/A#endif /* SHOPT_FS_3D */
1N/A struct ifs IFS_init;
1N/A Namfun_t PATH_init;
1N/A Namfun_t FPATH_init;
1N/A Namfun_t CDPATH_init;
1N/A Namfun_t SHELL_init;
1N/A Namfun_t ENV_init;
1N/A Namfun_t VISUAL_init;
1N/A Namfun_t EDITOR_init;
1N/A Namfun_t HISTFILE_init;
1N/A Namfun_t HISTSIZE_init;
1N/A Namfun_t OPTINDEX_init;
1N/A struct seconds SECONDS_init;
1N/A struct rand RAND_init;
1N/A Namfun_t LINENO_init;
1N/A Namfun_t L_ARG_init;
1N/A Namfun_t SH_VERSION_init;
1N/A struct match SH_MATCH_init;
1N/A Namfun_t SH_MATH_init;
1N/A#if SHOPT_COSHELL
1N/A Namfun_t SH_JOBPOOL_init;
1N/A#endif /* SHOPT_COSHELL */
1N/A#ifdef _hdr_locale
1N/A Namfun_t LC_TYPE_init;
1N/A Namfun_t LC_NUM_init;
1N/A Namfun_t LC_COLL_init;
1N/A Namfun_t LC_MSG_init;
1N/A Namfun_t LC_ALL_init;
1N/A Namfun_t LANG_init;
1N/A#endif /* _hdr_locale */
1N/A} Init_t;
1N/A
1N/Astatic int lctype;
1N/Astatic int nbltins;
1N/Astatic void env_init(Shell_t*);
1N/Astatic Init_t *nv_init(Shell_t*);
1N/Astatic Dt_t *inittree(Shell_t*,const struct shtable2*);
1N/Astatic int shlvl;
1N/A
1N/A#ifdef _WINIX
1N/A# define EXE "?(.exe)"
1N/A#else
1N/A# define EXE
1N/A#endif
1N/A
1N/Astatic int rand_shift;
1N/A
1N/A
1N/A/*
1N/A * Invalidate all path name bindings
1N/A */
1N/Astatic void rehash(register Namval_t *np,void *data)
1N/A{
1N/A NOT_USED(data);
1N/A nv_onattr(np,NV_NOALIAS);
1N/A}
1N/A
1N/A/*
1N/A * out of memory routine for stak routines
1N/A */
1N/Astatic char *nospace(int unused)
1N/A{
1N/A NOT_USED(unused);
1N/A errormsg(SH_DICT,ERROR_exit(3),e_nospace);
1N/A return(NIL(char*));
1N/A}
1N/A
1N/A/* Trap for VISUAL and EDITOR variables */
1N/Astatic void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A register const char *cp, *name=nv_name(np);
1N/A register int newopt=0;
1N/A Shell_t *shp = nv_shell(np);
1N/A if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD)))
1N/A goto done;
1N/A if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD)))))
1N/A goto done;
1N/A /* turn on vi or emacs option if editor name is either*/
1N/A cp = path_basename(cp);
1N/A if(strmatch(cp,"*[Vv][Ii]*"))
1N/A newopt=SH_VI;
1N/A else if(strmatch(cp,"*gmacs*"))
1N/A newopt=SH_GMACS;
1N/A else if(strmatch(cp,"*macs*"))
1N/A newopt=SH_EMACS;
1N/A if(newopt)
1N/A {
1N/A sh_offoption(SH_VI);
1N/A sh_offoption(SH_EMACS);
1N/A sh_offoption(SH_GMACS);
1N/A sh_onoption(newopt);
1N/A }
1N/Adone:
1N/A nv_putv(np, val, flags, fp);
1N/A}
1N/A
1N/A/* Trap for HISTFILE and HISTSIZE variables */
1N/Astatic void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A void *histopen = shp->gd->hist_ptr;
1N/A char *cp;
1N/A if(val && histopen)
1N/A {
1N/A if(np==HISTFILE && (cp=nv_getval(np)) && strcmp(val,cp)==0)
1N/A return;
1N/A if(np==HISTSIZE && sh_arith(shp,val)==nv_getnum(HISTSIZE))
1N/A return;
1N/A hist_close(shp->gd->hist_ptr);
1N/A }
1N/A nv_putv(np, val, flags, fp);
1N/A if(histopen)
1N/A {
1N/A if(val)
1N/A sh_histinit(shp);
1N/A else
1N/A hist_close(histopen);
1N/A }
1N/A}
1N/A
1N/A/* Trap for OPTINDEX */
1N/Astatic void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A shp->st.opterror = shp->st.optchar = 0;
1N/A nv_putv(np, val, flags, fp);
1N/A if(!val)
1N/A nv_disc(np,fp,NV_POP);
1N/A}
1N/A
1N/Astatic Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A return((Sfdouble_t)*np->nvalue.lp);
1N/A}
1N/A
1N/Astatic Namfun_t *clone_optindex(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
1N/A{
1N/A Namfun_t *dp = (Namfun_t*)malloc(sizeof(Namfun_t));
1N/A memcpy((void*)dp,(void*)fp,sizeof(Namfun_t));
1N/A mp->nvalue.lp = np->nvalue.lp;
1N/A dp->nofree = 0;
1N/A return(dp);
1N/A}
1N/A
1N/A
1N/A/* Trap for restricted variables FPATH, PATH, SHELL, ENV */
1N/Astatic void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A int path_scoped = 0, fpath_scoped=0;
1N/A Pathcomp_t *pp;
1N/A char *name = nv_name(np);
1N/A if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
1N/A errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
1N/A if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
1N/A {
1N/A nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
1N/A if(path_scoped && !val)
1N/A val = PATHNOD->nvalue.cp;
1N/A }
1N/A if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0)
1N/A return;
1N/A if(np==FPATHNOD || (fpath_scoped=(strcmp(name,FPATHNOD->nvname)==0)))
1N/A shp->pathlist = (void*)path_unsetfpath(shp);
1N/A nv_putv(np, val, flags, fp);
1N/A shp->universe = 0;
1N/A if(shp->pathlist)
1N/A {
1N/A val = np->nvalue.cp;
1N/A if(np==PATHNOD || path_scoped)
1N/A pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_PATH);
1N/A else if(val && (np==FPATHNOD || fpath_scoped))
1N/A pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
1N/A else
1N/A return;
1N/A if(shp->pathlist = (void*)pp)
1N/A pp->shp = shp;
1N/A if(!val && (flags&NV_NOSCOPE))
1N/A {
1N/A Namval_t *mp = dtsearch(shp->var_tree,np);
1N/A if(mp && (val=nv_getval(mp)))
1N/A nv_putval(mp,val,NV_RDONLY);
1N/A }
1N/A#if 0
1N/Asfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val);
1N/Apath_dump((Pathcomp_t*)shp->pathlist);
1N/A#endif
1N/A }
1N/A}
1N/A
1N/Astatic void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A Pathcomp_t *pp;
1N/A Shell_t *shp = nv_shell(np);
1N/A nv_putv(np, val, flags, fp);
1N/A if(!shp->cdpathlist)
1N/A return;
1N/A val = np->nvalue.cp;
1N/A pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH);
1N/A if(shp->cdpathlist = (void*)pp)
1N/A pp->shp = shp;
1N/A}
1N/A
1N/A#ifdef _hdr_locale
1N/A /*
1N/A * This function needs to be modified to handle international
1N/A * error message translations
1N/A */
1N/A#if ERROR_VERSION >= 20000101L
1N/A static char* msg_translate(const char* catalog, const char* message)
1N/A {
1N/A NOT_USED(catalog);
1N/A return((char*)message);
1N/A }
1N/A#else
1N/A static char* msg_translate(const char* message, int type)
1N/A {
1N/A NOT_USED(type);
1N/A return((char*)message);
1N/A }
1N/A#endif
1N/A
1N/A /* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */
1N/A static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A {
1N/A Shell_t *shp = nv_shell(np);
1N/A int type;
1N/A char *name = nv_name(np);
1N/A if(name==(LCALLNOD)->nvname)
1N/A type = LC_ALL;
1N/A else if(name==(LCTYPENOD)->nvname)
1N/A type = LC_CTYPE;
1N/A else if(name==(LCMSGNOD)->nvname)
1N/A type = LC_MESSAGES;
1N/A else if(name==(LCCOLLNOD)->nvname)
1N/A type = LC_COLLATE;
1N/A else if(name==(LCNUMNOD)->nvname)
1N/A type = LC_NUMERIC;
1N/A#ifdef LC_LANG
1N/A else if(name==(LANGNOD)->nvname)
1N/A type = LC_LANG;
1N/A#else
1N/A#define LC_LANG LC_ALL
1N/A else if(name==(LANGNOD)->nvname && (!(name=nv_getval(LCALLNOD)) || !*name))
1N/A type = LC_LANG;
1N/A#endif
1N/A else
1N/A type= -1;
1N/A if(!sh_isstate(SH_INIT) && (type>=0 || type==LC_ALL || type==LC_LANG))
1N/A {
1N/A char* r;
1N/A#ifdef AST_LC_setenv
1N/A ast.locale.set |= AST_LC_setenv;
1N/A#endif
1N/A r = setlocale(type,val?val:"");
1N/A#ifdef AST_LC_setenv
1N/A ast.locale.set ^= AST_LC_setenv;
1N/A#endif
1N/A if(!r && val)
1N/A {
1N/A if(!sh_isstate(SH_INIT) || shp->login_sh==0)
1N/A errormsg(SH_DICT,0,e_badlocale,val);
1N/A return;
1N/A }
1N/A }
1N/A nv_putv(np, val, flags, fp);
1N/A if(CC_NATIVE!=CC_ASCII && (type==LC_ALL || type==LC_LANG || type==LC_CTYPE))
1N/A {
1N/A if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
1N/A free((void*)sh_lexstates[ST_BEGIN]);
1N/A lctype++;
1N/A if(ast.locale.set&(1<<AST_LC_CTYPE))
1N/A {
1N/A register int c;
1N/A char *state[4];
1N/A sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
1N/A memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
1N/A sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
1N/A memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
1N/A sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
1N/A memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
1N/A sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
1N/A memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
1N/A for(c=0; c<(1<<CHAR_BIT); c++)
1N/A {
1N/A if(state[0][c]!=S_REG)
1N/A continue;
1N/A if(state[2][c]!=S_ERR)
1N/A continue;
1N/A if(isblank(c))
1N/A {
1N/A state[0][c]=0;
1N/A state[1][c]=S_BREAK;
1N/A state[2][c]=S_BREAK;
1N/A continue;
1N/A }
1N/A if(!isalpha(c))
1N/A continue;
1N/A state[0][c]=S_NAME;
1N/A if(state[1][c]==S_REG)
1N/A state[1][c]=0;
1N/A state[2][c]=S_ALP;
1N/A if(state[3][c]==S_ERR)
1N/A state[3][c]=0;
1N/A }
1N/A }
1N/A else
1N/A {
1N/A sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
1N/A sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
1N/A sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
1N/A sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
1N/A }
1N/A }
1N/A#if ERROR_VERSION < 20000101L
1N/A if(type==LC_ALL || type==LC_MESSAGES)
1N/A error_info.translate = msg_translate;
1N/A#endif
1N/A }
1N/A#endif /* _hdr_locale */
1N/A
1N/A/* Trap for IFS assignment and invalidates state table */
1N/Astatic void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A register struct ifs *ip = (struct ifs*)fp;
1N/A Shell_t *shp;
1N/A ip->ifsnp = 0;
1N/A if(!val)
1N/A {
1N/A fp = nv_stack(np, NIL(Namfun_t*));
1N/A if(fp && !fp->nofree)
1N/A free((void*)fp);
1N/A }
1N/A if(val != np->nvalue.cp)
1N/A nv_putv(np, val, flags, fp);
1N/A if(!val && !(flags&NV_CLONE) && (fp=np->nvfun) && !fp->disc && (shp=(Shell_t*)(fp->last)))
1N/A nv_stack(np,&((Init_t*)shp->init_context)->IFS_init.hdr);
1N/A}
1N/A
1N/A/*
1N/A * This is the lookup function for IFS
1N/A * It keeps the sh.ifstable up to date
1N/A */
1N/Astatic char* get_ifs(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A register struct ifs *ip = (struct ifs*)fp;
1N/A register char *cp, *value;
1N/A register int c,n;
1N/A register Shell_t *shp = nv_shell(np);
1N/A value = nv_getv(np,fp);
1N/A if(np!=ip->ifsnp)
1N/A {
1N/A ip->ifsnp = np;
1N/A memset(shp->ifstable,0,(1<<CHAR_BIT));
1N/A if(cp=value)
1N/A {
1N/A#if SHOPT_MULTIBYTE
1N/A while(n=mbsize(cp),c= *(unsigned char*)cp)
1N/A#else
1N/A while(c= *(unsigned char*)cp++)
1N/A#endif /* SHOPT_MULTIBYTE */
1N/A {
1N/A#if SHOPT_MULTIBYTE
1N/A cp++;
1N/A if(n>1)
1N/A {
1N/A cp += (n-1);
1N/A shp->ifstable[c] = S_MBYTE;
1N/A continue;
1N/A }
1N/A#endif /* SHOPT_MULTIBYTE */
1N/A n = S_DELIM;
1N/A if(c== *cp)
1N/A cp++;
1N/A else if(c=='\n')
1N/A n = S_NL;
1N/A else if(isspace(c))
1N/A n = S_SPACE;
1N/A shp->ifstable[c] = n;
1N/A }
1N/A }
1N/A else
1N/A {
1N/A shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE;
1N/A shp->ifstable['\n'] = S_NL;
1N/A }
1N/A }
1N/A return(value);
1N/A}
1N/A
1N/A/*
1N/A * these functions are used to get and set the SECONDS variable
1N/A */
1N/A#ifdef timeofday
1N/A# define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
1N/A# define tms timeval
1N/A#else
1N/A# define dtime(tp) (((double)times(tp))/shgd->lim.clk_tck)
1N/A# define timeofday(a)
1N/A#endif
1N/A
1N/Astatic void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A double d;
1N/A struct tms tp;
1N/A if(!val)
1N/A {
1N/A fp = nv_stack(np, NIL(Namfun_t*));
1N/A if(fp && !fp->nofree)
1N/A free((void*)fp);
1N/A nv_putv(np, val, flags, fp);
1N/A return;
1N/A }
1N/A if(!np->nvalue.dp)
1N/A {
1N/A nv_setsize(np,3);
1N/A nv_onattr(np,NV_DOUBLE);
1N/A np->nvalue.dp = new_of(double,0);
1N/A }
1N/A nv_putv(np, val, flags, fp);
1N/A d = *np->nvalue.dp;
1N/A timeofday(&tp);
1N/A *np->nvalue.dp = dtime(&tp)-d;
1N/A}
1N/A
1N/Astatic char* get_seconds(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A register int places = nv_size(np);
1N/A struct tms tp;
1N/A double d, offset = (np->nvalue.dp?*np->nvalue.dp:0);
1N/A NOT_USED(fp);
1N/A timeofday(&tp);
1N/A d = dtime(&tp)- offset;
1N/A sfprintf(shp->strbuf,"%.*f",places,d);
1N/A return(sfstruse(shp->strbuf));
1N/A}
1N/A
1N/Astatic Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A struct tms tp;
1N/A double offset = (np->nvalue.dp?*np->nvalue.dp:0);
1N/A NOT_USED(fp);
1N/A timeofday(&tp);
1N/A return(dtime(&tp)- offset);
1N/A}
1N/A
1N/A/*
1N/A * These three functions are used to get and set the RANDOM variable
1N/A */
1N/Astatic void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A struct rand *rp = (struct rand*)fp;
1N/A register long n;
1N/A if(!val)
1N/A {
1N/A fp = nv_stack(np, NIL(Namfun_t*));
1N/A if(fp && !fp->nofree)
1N/A free((void*)fp);
1N/A _nv_unset(np,0);
1N/A return;
1N/A }
1N/A if(flags&NV_INTEGER)
1N/A n = *(double*)val;
1N/A else
1N/A n = sh_arith(rp->sh,val);
1N/A srand((int)(n&RANDMASK));
1N/A rp->rand_last = -1;
1N/A if(!np->nvalue.lp)
1N/A np->nvalue.lp = &rp->rand_last;
1N/A}
1N/A
1N/A/*
1N/A * get random number in range of 0 - 2**15
1N/A * never pick same number twice in a row
1N/A */
1N/Astatic Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A register long cur, last= *np->nvalue.lp;
1N/A NOT_USED(fp);
1N/A do
1N/A cur = (rand()>>rand_shift)&RANDMASK;
1N/A while(cur==last);
1N/A *np->nvalue.lp = cur;
1N/A return((Sfdouble_t)cur);
1N/A}
1N/A
1N/Astatic char* get_rand(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A register long n = nget_rand(np,fp);
1N/A return(fmtbase(n, 10, 0));
1N/A}
1N/A
1N/A/*
1N/A * These three routines are for LINENO
1N/A */
1N/Astatic Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp)
1N/A{
1N/A double d=1;
1N/A if(error_info.line >0)
1N/A d = error_info.line;
1N/A else if(error_info.context && error_info.context->line>0)
1N/A d = error_info.context->line;
1N/A NOT_USED(np);
1N/A NOT_USED(fp);
1N/A return(d);
1N/A}
1N/A
1N/Astatic void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A register long n;
1N/A Shell_t *shp = nv_shell(np);
1N/A if(!val)
1N/A {
1N/A fp = nv_stack(np, NIL(Namfun_t*));
1N/A if(fp && !fp->nofree)
1N/A free((void*)fp);
1N/A _nv_unset(np,0);
1N/A return;
1N/A }
1N/A if(flags&NV_INTEGER)
1N/A n = *(double*)val;
1N/A else
1N/A n = sh_arith(shp,val);
1N/A shp->st.firstline += nget_lineno(np,fp)+1-n;
1N/A}
1N/A
1N/Astatic char* get_lineno(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A register long n = nget_lineno(np,fp);
1N/A return(fmtbase(n, 10, 0));
1N/A}
1N/A
1N/Astatic char* get_lastarg(Namval_t* np, Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A char *cp;
1N/A int pid;
1N/A if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*')
1N/A nv_putval(np,(pid==shp->gd->ppid?cp+1:0),0);
1N/A return(shp->lastarg);
1N/A}
1N/A
1N/Astatic void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A if(flags&NV_INTEGER)
1N/A {
1N/A sfprintf(shp->strbuf,"%.*g",12,*((double*)val));
1N/A val = sfstruse(shp->strbuf);
1N/A }
1N/A if(val)
1N/A val = strdup(val);
1N/A if(shp->lastarg && !nv_isattr(np,NV_NOFREE))
1N/A free((void*)shp->lastarg);
1N/A else
1N/A nv_offattr(np,NV_NOFREE);
1N/A shp->lastarg = (char*)val;
1N/A nv_offattr(np,NV_EXPORT);
1N/A np->nvenv = 0;
1N/A}
1N/A
1N/Astatic int hasgetdisc(register Namfun_t *fp)
1N/A{
1N/A while(fp && !fp->disc->getnum && !fp->disc->getval)
1N/A fp = fp->next;
1N/A return(fp!=0);
1N/A}
1N/A
1N/A/*
1N/A * store the most recent value for use in .sh.match
1N/A */
1N/Avoid sh_setmatch(const char *v, int vsize, int nmatch, int match[])
1N/A{
1N/A struct match *mp = (struct match*)(SH_MATCHNOD->nvfun->next);
1N/A register int i,n;
1N/A if(mp->nmatch = nmatch)
1N/A {
1N/A memcpy(mp->match,match,nmatch*2*sizeof(match[0]));
1N/A for(n=match[0],vsize=0,i=0; i < 2*nmatch; i++)
1N/A {
1N/A if(mp->match[i]>=0 && (mp->match[i] -= n) > vsize)
1N/A vsize = mp->match[i];
1N/A }
1N/A v += n;
1N/A if(vsize >= mp->vsize)
1N/A {
1N/A if(mp->vsize)
1N/A mp->val = (char*)realloc(mp->val,vsize+1);
1N/A else
1N/A mp->val = (char*)malloc(vsize+1);
1N/A mp->vsize = vsize;
1N/A }
1N/A memcpy(mp->val,v,vsize);
1N/A mp->val[vsize] = 0;
1N/A nv_putsub(SH_MATCHNOD, NIL(char*), (nmatch-1)|ARRAY_FILL|ARRAY_SETSUB);
1N/A for(n=match[0],i=1; i < nmatch; i++)
1N/A {
1N/A if(mp->match[2*i] < 0)
1N/A {
1N/A nv_putsub(SH_MATCHNOD,NIL(char*),i);
1N/A _nv_unset(SH_MATCHNOD,NV_RDONLY);
1N/A }
1N/A }
1N/A mp->lastsub = -1;
1N/A }
1N/A}
1N/A
1N/A#define array_scan(np) ((nv_arrayptr(np)->nelem&ARRAY_SCAN))
1N/A
1N/Astatic char* get_match(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A struct match *mp = (struct match*)fp;
1N/A int sub,n;
1N/A char *val;
1N/A sub = nv_aindex(np);
1N/A if(sub>=mp->nmatch)
1N/A return(0);
1N/A if(sub==mp->lastsub)
1N/A return(mp->rval);
1N/A if(mp->rval)
1N/A {
1N/A free((void*)mp->rval);
1N/A mp->rval = 0;
1N/A }
1N/A n = mp->match[2*sub+1]-mp->match[2*sub];
1N/A if(n<=0)
1N/A return("");
1N/A val = mp->val+mp->match[2*sub];
1N/A if(mp->val[mp->match[2*sub+1]]==0)
1N/A return(val);
1N/A mp->rval = (char*)malloc(n+1);
1N/A mp->lastsub = sub;
1N/A memcpy(mp->rval,val,n);
1N/A mp->rval[n] = 0;
1N/A return(mp->rval);
1N/A}
1N/A
1N/Astatic const Namdisc_t SH_MATCH_disc = { sizeof(struct match), 0, get_match };
1N/A
1N/Astatic char* get_version(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A return(nv_getv(np,fp));
1N/A}
1N/A
1N/Astatic Sfdouble_t nget_version(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A register const char *cp = e_version + strlen(e_version)-10;
1N/A register int c;
1N/A Sflong_t t = 0;
1N/A NOT_USED(fp);
1N/A
1N/A while (c = *cp++)
1N/A if (c >= '0' && c <= '9')
1N/A {
1N/A t *= 10;
1N/A t += c - '0';
1N/A }
1N/A return((Sfdouble_t)t);
1N/A}
1N/A
1N/Astatic const Namdisc_t SH_VERSION_disc = { 0, 0, get_version, nget_version };
1N/A
1N/A#if SHOPT_FS_3D
1N/A /*
1N/A * set or unset the mappings given a colon separated list of directories
1N/A */
1N/A static void vpath_set(char *str, int mode)
1N/A {
1N/A register char *lastp, *oldp=str, *newp=strchr(oldp,':');
1N/A if(!shgd->lim.fs3d)
1N/A return;
1N/A while(newp)
1N/A {
1N/A *newp++ = 0;
1N/A if(lastp=strchr(newp,':'))
1N/A *lastp = 0;
1N/A mount((mode?newp:""),oldp,FS3D_VIEW,0);
1N/A newp[-1] = ':';
1N/A oldp = newp;
1N/A newp=lastp;
1N/A }
1N/A }
1N/A
1N/A /* catch vpath assignments */
1N/A static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A {
1N/A register char *cp;
1N/A if(cp = nv_getval(np))
1N/A vpath_set(cp,0);
1N/A if(val)
1N/A vpath_set((char*)val,1);
1N/A nv_putv(np,val,flags,fp);
1N/A }
1N/A static const Namdisc_t VPATH_disc = { 0, put_vpath };
1N/A static Namfun_t VPATH_init = { &VPATH_disc, 1 };
1N/A#endif /* SHOPT_FS_3D */
1N/A
1N/A
1N/Astatic const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs };
1N/Aconst Namdisc_t RESTRICTED_disc = { sizeof(Namfun_t), put_restricted };
1N/Astatic const Namdisc_t CDPATH_disc = { sizeof(Namfun_t), put_cdpath };
1N/Astatic const Namdisc_t EDITOR_disc = { sizeof(Namfun_t), put_ed };
1N/Astatic const Namdisc_t HISTFILE_disc = { sizeof(Namfun_t), put_history };
1N/Astatic const Namdisc_t OPTINDEX_disc = { sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex };
1N/Astatic const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds };
1N/Astatic const Namdisc_t RAND_disc = { sizeof(struct rand), put_rand, get_rand, nget_rand };
1N/Astatic const Namdisc_t LINENO_disc = { sizeof(Namfun_t), put_lineno, get_lineno, nget_lineno };
1N/Astatic const Namdisc_t L_ARG_disc = { sizeof(Namfun_t), put_lastarg, get_lastarg };
1N/A
1N/A
1N/A#define MAX_MATH_ARGS 3
1N/A
1N/Astatic char *name_math(Namval_t *np, Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = sh_getinterp();
1N/A sfprintf(shp->strbuf,".sh.math.%s",np->nvname);
1N/A return(sfstruse(shp->strbuf));
1N/A}
1N/A
1N/Astatic const Namdisc_t math_child_disc =
1N/A{
1N/A 0,0,0,0,0,0,0,
1N/A name_math
1N/A};
1N/A
1N/Astatic Namfun_t math_child_fun =
1N/A{
1N/A &math_child_disc, 1, 0, sizeof(Namfun_t)
1N/A};
1N/A
1N/Astatic void math_init(Shell_t *shp)
1N/A{
1N/A Namval_t *np;
1N/A char *name;
1N/A int i;
1N/A shp->mathnodes = (char*)calloc(1,MAX_MATH_ARGS*(NV_MINSZ+5));
1N/A name = shp->mathnodes+MAX_MATH_ARGS*NV_MINSZ;
1N/A for(i=0; i < MAX_MATH_ARGS; i++)
1N/A {
1N/A np = nv_namptr(shp->mathnodes,i);
1N/A np->nvfun = &math_child_fun;
1N/A memcpy(name,"arg",3);
1N/A name[3] = '1'+i;
1N/A np->nvname = name;
1N/A name+=5;
1N/A nv_onattr(np,NV_MINIMAL|NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
1N/A }
1N/A}
1N/A
1N/Astatic Namval_t *create_math(Namval_t *np,const char *name,int flag,Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A if(!name)
1N/A return(SH_MATHNOD);
1N/A if(name[0]!='a' || name[1]!='r' || name[2]!='g' || name[4] || !isdigit(name[3]) || (name[3]=='0' || (name[3]-'0')>MAX_MATH_ARGS))
1N/A return(0);
1N/A fp->last = (char*)&name[4];
1N/A return(nv_namptr(shp->mathnodes,name[3]-'1'));
1N/A}
1N/A
1N/Astatic char* get_math(register Namval_t* np, Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = nv_shell(np);
1N/A Namval_t *mp,fake;
1N/A char *val;
1N/A int first=0;
1N/A fake.nvname = ".sh.math.";
1N/A mp = (Namval_t*)dtprev(shp->fun_tree,&fake);
1N/A while(mp=(Namval_t*)dtnext(shp->fun_tree,mp))
1N/A {
1N/A if(memcmp(mp->nvname,".sh.math.",9))
1N/A break;
1N/A if(first++)
1N/A sfputc(shp->strbuf,' ');
1N/A sfputr(shp->strbuf,mp->nvname+9,-1);
1N/A }
1N/A val = sfstruse(shp->strbuf);
1N/A return(val);
1N/A
1N/A}
1N/A
1N/Astatic char *setdisc_any(Namval_t *np, const char *event, Namval_t *action, Namfun_t *fp)
1N/A{
1N/A Shell_t *shp=nv_shell(np);
1N/A Namval_t *mp,fake;
1N/A char *name;
1N/A int getname=0, off=staktell();
1N/A fake.nvname = nv_name(np);
1N/A if(!event)
1N/A {
1N/A if(!action)
1N/A {
1N/A mp = (Namval_t*)dtprev(shp->fun_tree,&fake);
1N/A return((char*)dtnext(shp->fun_tree,mp));
1N/A }
1N/A getname = 1;
1N/A }
1N/A stakputs(fake.nvname);
1N/A stakputc('.');
1N/A stakputs(event);
1N/A stakputc(0);
1N/A name = stakptr(off);
1N/A mp = nv_search(name, shp->fun_tree, action?NV_ADD:0);
1N/A stakseek(off);
1N/A if(getname)
1N/A return(mp?(char*)dtnext(shp->fun_tree,mp):0);
1N/A if(action==np)
1N/A action = mp;
1N/A return(action?(char*)action:"");
1N/A}
1N/A
1N/Astatic const Namdisc_t SH_MATH_disc = { 0, 0, get_math, 0, setdisc_any, create_math, };
1N/A
1N/A#if SHOPT_COSHELL
1N/Astatic const Namdisc_t SH_JOBPOOL_disc = { 0, 0, 0, 0, setdisc_any, 0, };
1N/A#endif /* SHOPT_COSHELL */
1N/A
1N/A#if SHOPT_NAMESPACE
1N/A static char* get_nspace(Namval_t* np, Namfun_t *fp)
1N/A {
1N/A if(sh.namespace)
1N/A return(nv_name(sh.namespace));
1N/A return((char*)np->nvalue.cp);
1N/A }
1N/A static const Namdisc_t NSPACE_disc = { 0, 0, get_nspace };
1N/A static Namfun_t NSPACE_init = { &NSPACE_disc, 1};
1N/A#endif /* SHOPT_NAMESPACE */
1N/A
1N/A#ifdef _hdr_locale
1N/A static const Namdisc_t LC_disc = { sizeof(Namfun_t), put_lang };
1N/A#endif /* _hdr_locale */
1N/A
1N/A/*
1N/A * This function will get called whenever a configuration parameter changes
1N/A */
1N/Astatic int newconf(const char *name, const char *path, const char *value)
1N/A{
1N/A Shell_t *shp = sh_getinterp();
1N/A register char *arg;
1N/A if(!name)
1N/A setenviron(value);
1N/A else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
1N/A {
1N/A shp->universe = 0;
1N/A /* set directory in new universe */
1N/A if(*(arg = path_pwd(shp,0))=='/')
1N/A chdir(arg);
1N/A /* clear out old tracked alias */
1N/A stakseek(0);
1N/A stakputs(nv_getval(PATHNOD));
1N/A stakputc(0);
1N/A nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
1N/A }
1N/A return(1);
1N/A}
1N/A
1N/A#if (CC_NATIVE != CC_ASCII)
1N/A static void a2e(char *d, const char *s)
1N/A {
1N/A register const unsigned char *t;
1N/A register int i;
1N/A t = CCMAP(CC_ASCII, CC_NATIVE);
1N/A for(i=0; i<(1<<CHAR_BIT); i++)
1N/A d[t[i]] = s[i];
1N/A }
1N/A
1N/A static void init_ebcdic(void)
1N/A {
1N/A int i;
1N/A char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT));
1N/A for(i=0; i < ST_NONE; i++)
1N/A {
1N/A a2e(cp,sh_lexrstates[i]);
1N/A sh_lexstates[i] = cp;
1N/A cp += (1<<CHAR_BIT);
1N/A }
1N/A }
1N/A#endif
1N/A
1N/A/*
1N/A * return SH_TYPE_* bitmask for path
1N/A * 0 for "not a shell"
1N/A */
1N/Aint sh_type(register const char *path)
1N/A{
1N/A register const char* s;
1N/A register int t = 0;
1N/A
1N/A if (s = (const char*)strrchr(path, '/'))
1N/A {
1N/A if (*path == '-')
1N/A t |= SH_TYPE_LOGIN;
1N/A s++;
1N/A }
1N/A else
1N/A s = path;
1N/A if (*s == '-')
1N/A {
1N/A s++;
1N/A t |= SH_TYPE_LOGIN;
1N/A }
1N/A for (;;)
1N/A {
1N/A if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH)))
1N/A {
1N/A if (*s == 'k')
1N/A {
1N/A s++;
1N/A t |= SH_TYPE_KSH;
1N/A continue;
1N/A }
1N/A#if SHOPT_BASH
1N/A if (*s == 'b' && *(s+1) == 'a')
1N/A {
1N/A s += 2;
1N/A t |= SH_TYPE_BASH;
1N/A continue;
1N/A }
1N/A#endif
1N/A }
1N/A if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED)))
1N/A {
1N/A#if SHOPT_PFSH
1N/A if (*s == 'p' && *(s+1) == 'f')
1N/A {
1N/A s += 2;
1N/A t |= SH_TYPE_PROFILE;
1N/A continue;
1N/A }
1N/A#endif
1N/A if (*s == 'r')
1N/A {
1N/A s++;
1N/A t |= SH_TYPE_RESTRICTED;
1N/A continue;
1N/A }
1N/A }
1N/A break;
1N/A }
1N/A if (*s++ == 's' && (*s == 'h' || *s == 'u'))
1N/A {
1N/A s++;
1N/A t |= SH_TYPE_SH;
1N/A if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3')
1N/A s += 2;
1N/A#if _WINIX
1N/A if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e')
1N/A s += 4;
1N/A#endif
1N/A if (!isalnum(*s))
1N/A return t;
1N/A }
1N/A return t & ~(SH_TYPE_BASH|SH_TYPE_KSH|SH_TYPE_PROFILE|SH_TYPE_RESTRICTED);
1N/A}
1N/A
1N/A
1N/Astatic char *get_mode(Namval_t* np, Namfun_t* nfp)
1N/A{
1N/A mode_t mode = nv_getn(np,nfp);
1N/A return(fmtperm(mode));
1N/A}
1N/A
1N/Astatic void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1N/A{
1N/A if(val)
1N/A {
1N/A mode_t mode;
1N/A char *last;
1N/A if(flag&NV_INTEGER)
1N/A {
1N/A if(flag&NV_LONG)
1N/A mode = *(Sfdouble_t*)val;
1N/A else
1N/A mode = *(double*)val;
1N/A }
1N/A else
1N/A mode = strperm(val, &last,0);
1N/A if(*last)
1N/A errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val);
1N/A nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
1N/A }
1N/A else
1N/A nv_putv(np,val,flag,nfp);
1N/A}
1N/A
1N/Astatic const Namdisc_t modedisc =
1N/A{
1N/A 0,
1N/A put_mode,
1N/A get_mode,
1N/A};
1N/A
1N/A
1N/A/*
1N/A * initialize the shell
1N/A */
1N/AShell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
1N/A{
1N/A static int beenhere;
1N/A Shell_t *shp;
1N/A register int n;
1N/A int type;
1N/A static char *login_files[3];
1N/A memfatal();
1N/A n = strlen(e_version);
1N/A if(e_version[n-1]=='$' && e_version[n-2]==' ')
1N/A e_version[n-2]=0;
1N/A#if (CC_NATIVE == CC_ASCII)
1N/A memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
1N/A#else
1N/A init_ebcdic();
1N/A#endif
1N/A if(!beenhere)
1N/A {
1N/A beenhere = 1;
1N/A shp = &sh;
1N/A shgd = newof(0,struct shared,1,0);
1N/A shgd->pid = getpid();
1N/A shgd->ppid = getppid();
1N/A shgd->userid=getuid();
1N/A shgd->euserid=geteuid();
1N/A shgd->groupid=getgid();
1N/A shgd->egroupid=getegid();
1N/A shgd->lim.clk_tck = getconf("CLK_TCK");
1N/A shgd->lim.arg_max = getconf("ARG_MAX");
1N/A shgd->lim.child_max = getconf("CHILD_MAX");
1N/A shgd->lim.ngroups_max = getconf("NGROUPS_MAX");
1N/A shgd->lim.posix_version = getconf("VERSION");
1N/A shgd->lim.posix_jobcontrol = getconf("JOB_CONTROL");
1N/A if(shgd->lim.arg_max <=0)
1N/A shgd->lim.arg_max = ARG_MAX;
1N/A if(shgd->lim.child_max <=0)
1N/A shgd->lim.child_max = CHILD_MAX;
1N/A if(shgd->lim.clk_tck <=0)
1N/A shgd->lim.clk_tck = CLK_TCK;
1N/A#if SHOPT_FS_3D
1N/A if(fs3d(FS3D_TEST))
1N/A shgd->lim.fs3d = 1;
1N/A#endif /* SHOPT_FS_3D */
1N/A shgd->ed_context = (void*)ed_open(shp);
1N/A error_info.exit = sh_exit;
1N/A error_info.id = path_basename(argv[0]);
1N/A }
1N/A else
1N/A newof(0,Shell_t,1,0);
1N/A umask(shp->mask=umask(0));
1N/A shp->gd = shgd;
1N/A shp->mac_context = sh_macopen(shp);
1N/A shp->arg_context = sh_argopen(shp);
1N/A shp->lex_context = (void*)sh_lexopen(0,shp,1);
1N/A shp->strbuf = sfstropen();
1N/A shp->stk = stkstd;
1N/A sfsetbuf(shp->strbuf,(char*)0,64);
1N/A sh_onstate(SH_INIT);
1N/A#if ERROR_VERSION >= 20000102L
1N/A error_info.catalog = e_dict;
1N/A#endif
1N/A#if SHOPT_REGRESS
1N/A {
1N/A Opt_t* nopt;
1N/A Opt_t* oopt;
1N/A char* a;
1N/A char** av = argv;
1N/A char* regress[3];
1N/A
1N/A sh_regress_init(shp);
1N/A regress[0] = "__regress__";
1N/A regress[2] = 0;
1N/A /* NOTE: only shp is used by __regress__ at this point */
1N/A shp->bltindata.shp = shp;
1N/A while ((a = *++av) && a[0] == '-' && (a[1] == 'I' || a[1] == '-' && a[2] == 'r'))
1N/A {
1N/A if (a[1] == 'I')
1N/A {
1N/A if (a[2])
1N/A regress[1] = a + 2;
1N/A else if (!(regress[1] = *++av))
1N/A break;
1N/A }
1N/A else if (strncmp(a+2, "regress", 7))
1N/A break;
1N/A else if (a[9] == '=')
1N/A regress[1] = a + 10;
1N/A else if (!(regress[1] = *++av))
1N/A break;
1N/A nopt = optctx(0, 0);
1N/A oopt = optctx(nopt, 0);
1N/A b___regress__(2, regress, &shp->bltindata);
1N/A optctx(oopt, nopt);
1N/A }
1N/A }
1N/A#endif
1N/A shp->cpipe[0] = -1;
1N/A shp->coutpipe = -1;
1N/A for(n=0;n < 10; n++)
1N/A {
1N/A /* don't use lower bits when rand() generates large numbers */
1N/A if(rand() > RANDMASK)
1N/A {
1N/A rand_shift = 3;
1N/A break;
1N/A }
1N/A }
1N/A sh_ioinit(shp);
1N/A /* initialize signal handling */
1N/A sh_siginit(shp);
1N/A stakinstall(NIL(Stak_t*),nospace);
1N/A /* set up memory for name-value pairs */
1N/A shp->init_context = nv_init(shp);
1N/A /* read the environment */
1N/A if(argc>0)
1N/A {
1N/A type = sh_type(*argv);
1N/A if(type&SH_TYPE_LOGIN)
1N/A shp->login_sh = 2;
1N/A }
1N/A env_init(shp);
1N/A if(!ENVNOD->nvalue.cp)
1N/A {
1N/A sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME));
1N/A nv_putval(ENVNOD,sfstruse(shp->strbuf),NV_RDONLY);
1N/A }
1N/A *SHLVL->nvalue.ip +=1;
1N/A nv_offattr(SHLVL,NV_IMPORT);
1N/A#if SHOPT_SPAWN
1N/A {
1N/A /*
1N/A * try to find the pathname for this interpreter
1N/A * try using environment variable _ or argv[0]
1N/A */
1N/A char *cp=nv_getval(L_ARGNOD);
1N/A char buff[PATH_MAX+1];
1N/A shp->gd->shpath = 0;
1N/A#if _AST_VERSION >= 20090202L
1N/A if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff))
1N/A shp->gd->shpath = strdup(buff);
1N/A#else
1N/A sfprintf(shp->strbuf,"/proc/%d/exe",getpid());
1N/A if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0)
1N/A {
1N/A buff[n] = 0;
1N/A shp->gd->shpath = strdup(buff);
1N/A }
1N/A#endif
1N/A else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
1N/A {
1N/A if(*cp=='/')
1N/A shp->gd->shpath = strdup(cp);
1N/A else if(cp = nv_getval(PWDNOD))
1N/A {
1N/A int offset = staktell();
1N/A stakputs(cp);
1N/A stakputc('/');
1N/A stakputs(argv[0]);
1N/A pathcanon(stakptr(offset),PATH_DOTDOT);
1N/A shp->gd->shpath = strdup(stakptr(offset));
1N/A stakseek(offset);
1N/A }
1N/A }
1N/A }
1N/A#endif
1N/A nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
1N/A#if SHOPT_FS_3D
1N/A nv_stack(VPATHNOD, &VPATH_init);
1N/A#endif /* SHOPT_FS_3D */
1N/A astconfdisc(newconf);
1N/A#if SHOPT_TIMEOUT
1N/A shp->st.tmout = SHOPT_TIMEOUT;
1N/A#endif /* SHOPT_TIMEOUT */
1N/A /* initialize jobs table */
1N/A job_clear();
1N/A if(argc>0)
1N/A {
1N/A int dolv_index = -1;
1N/A /* check for restricted shell */
1N/A if(type&SH_TYPE_RESTRICTED)
1N/A sh_onoption(SH_RESTRICTED);
1N/A#if SHOPT_PFSH
1N/A /* check for profile shell */
1N/A else if(type&SH_TYPE_PROFILE)
1N/A sh_onoption(SH_PFSH);
1N/A#endif
1N/A#if SHOPT_BASH
1N/A /* check for invocation as bash */
1N/A if(type&SH_TYPE_BASH)
1N/A {
1N/A shp>userinit = userinit = bash_init;
1N/A sh_onoption(SH_BASH);
1N/A sh_onstate(SH_PREINIT);
1N/A (*userinit)(shp, 0);
1N/A sh_offstate(SH_PREINIT);
1N/A }
1N/A#endif
1N/A /* look for options */
1N/A /* shp->st.dolc is $# */
1N/A if((shp->st.dolc = sh_argopts(-argc,argv,shp)) < 0)
1N/A {
1N/A shp->exitval = 2;
1N/A sh_done(shp,0);
1N/A }
1N/A opt_info.disc = 0;
1N/A dolv_index = (argc-1)-shp->st.dolc;
1N/A shp->st.dolv=argv+dolv_index;
1N/A shp->st.repl_index = dolv_index;
1N/A shp->st.repl_arg = argv[dolv_index];
1N/A shp->st.dolv[0] = argv[0];
1N/A if(shp->st.dolc < 1)
1N/A sh_onoption(SH_SFLAG);
1N/A if(!sh_isoption(SH_SFLAG))
1N/A {
1N/A shp->st.dolc--;
1N/A shp->st.dolv++;
1N/A#if _WINIX
1N/A {
1N/A char* name;
1N/A name = shp->st.dolv[0];
1N/A if(name[1]==':' && (name[2]=='/' || name[2]=='\\'))
1N/A {
1N/A#if _lib_pathposix
1N/A char* p;
1N/A
1N/A if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n)))
1N/A {
1N/A pathposix(name, p, n);
1N/A name = p;
1N/A }
1N/A else
1N/A#endif
1N/A {
1N/A name[1] = name[0];
1N/A name[0] = name[2] = '/';
1N/A }
1N/A }
1N/A }
1N/A#endif /* _WINIX */
1N/A }
1N/A if(beenhere==1)
1N/A {
1N/A struct lconv* lc;
1N/A shp->decomma = (lc=localeconv()) && lc->decimal_point && *lc->decimal_point==',';
1N/A beenhere = 2;
1N/A }
1N/A }
1N/A#if SHOPT_PFSH
1N/A if (sh_isoption(SH_PFSH))
1N/A {
1N/A struct passwd *pw = getpwuid(shp->gd->userid);
1N/A if(pw)
1N/A shp->gd->user = strdup(pw->pw_name);
1N/A
1N/A }
1N/A#endif
1N/A /* set[ug]id scripts require the -p flag */
1N/A if(shp->gd->userid!=shp->gd->euserid || shp->gd->groupid!=shp->gd->egroupid)
1N/A {
1N/A#ifdef SHOPT_P_SUID
1N/A /* require sh -p to run setuid and/or setgid */
1N/A if(!sh_isoption(SH_PRIVILEGED) && shp->gd->userid >= SHOPT_P_SUID)
1N/A {
1N/A setuid(shp->gd->euserid=shp->gd->userid);
1N/A setgid(shp->gd->egroupid=shp->gd->groupid);
1N/A }
1N/A else
1N/A#endif /* SHOPT_P_SUID */
1N/A sh_onoption(SH_PRIVILEGED);
1N/A#ifdef SHELLMAGIC
1N/A /* careful of #! setuid scripts with name beginning with - */
1N/A if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0)
1N/A errormsg(SH_DICT,ERROR_exit(1),e_prohibited);
1N/A#endif /*SHELLMAGIC*/
1N/A }
1N/A else
1N/A sh_offoption(SH_PRIVILEGED);
1N/A /* shname for $0 in profiles and . scripts */
1N/A if(sh_isdevfd(argv[1]))
1N/A shp->shname = strdup(argv[0]);
1N/A else
1N/A shp->shname = strdup(shp->st.dolv[0]);
1N/A /*
1N/A * return here for shell script execution
1N/A * but not for parenthesis subshells
1N/A */
1N/A error_info.id = strdup(shp->st.dolv[0]); /* error_info.id is $0 */
1N/A shp->jmpbuffer = (void*)&shp->checkbase;
1N/A sh_pushcontext(shp,&shp->checkbase,SH_JMPSCRIPT);
1N/A shp->st.self = &shp->global;
1N/A shp->topscope = (Shscope_t*)shp->st.self;
1N/A sh_offstate(SH_INIT);
1N/A login_files[0] = (char*)e_profile;
1N/A login_files[1] = ".profile";
1N/A shp->gd->login_files = login_files;
1N/A shp->bltindata.version = SH_VERSION;
1N/A shp->bltindata.shp = shp;
1N/A shp->bltindata.shrun = sh_run;
1N/A shp->bltindata.shtrap = sh_trap;
1N/A shp->bltindata.shexit = sh_exit;
1N/A shp->bltindata.shbltin = sh_addbuiltin;
1N/A#if _AST_VERSION >= 20080617L
1N/A shp->bltindata.shgetenv = sh_getenv;
1N/A shp->bltindata.shsetenv = sh_setenviron;
1N/A astintercept(&shp->bltindata,1);
1N/A#endif
1N/A#if 0
1N/A#define NV_MKINTTYPE(x,y,z) nv_mkinttype(#x,sizeof(x),(x)-1<0,(y),(Namdisc_t*)z);
1N/A NV_MKINTTYPE(pid_t,"process id",0);
1N/A NV_MKINTTYPE(gid_t,"group id",0);
1N/A NV_MKINTTYPE(uid_t,"user id",0);
1N/A NV_MKINTTYPE(size_t,(const char*)0,0);
1N/A NV_MKINTTYPE(ssize_t,(const char*)0,0);
1N/A NV_MKINTTYPE(off_t,"offset in bytes",0);
1N/A NV_MKINTTYPE(ino_t,"\ai-\anode number",0);
1N/A NV_MKINTTYPE(mode_t,(const char*)0,&modedisc);
1N/A NV_MKINTTYPE(dev_t,"device id",0);
1N/A NV_MKINTTYPE(nlink_t,"hard link count",0);
1N/A NV_MKINTTYPE(blkcnt_t,"block count",0);
1N/A NV_MKINTTYPE(time_t,"seconds since the epoch",0);
1N/A nv_mkstat();
1N/A#endif
1N/A if(shp->userinit=userinit)
1N/A (*userinit)(shp, 0);
1N/A return(shp);
1N/A}
1N/A
1N/AShell_t *sh_getinterp(void)
1N/A{
1N/A return(&sh);
1N/A}
1N/A
1N/A/*
1N/A * reinitialize before executing a script
1N/A */
1N/Aint sh_reinit(char *argv[])
1N/A{
1N/A Shell_t *shp = sh_getinterp();
1N/A Shopt_t opt;
1N/A Namval_t *np,*npnext;
1N/A Dt_t *dp;
1N/A struct adata
1N/A {
1N/A Shell_t *sh;
1N/A void *extra[2];
1N/A } data;
1N/A for(np=dtfirst(shp->fun_tree);np;np=npnext)
1N/A {
1N/A if((dp=shp->fun_tree)->walk)
1N/A dp = dp->walk;
1N/A npnext = (Namval_t*)dtnext(shp->fun_tree,np);
1N/A if(np>= shgd->bltin_cmds && np < &shgd->bltin_cmds[nbltins])
1N/A continue;
1N/A if(is_abuiltin(np) && nv_isattr(np,NV_EXPORT))
1N/A continue;
1N/A if(*np->nvname=='/')
1N/A continue;
1N/A nv_delete(np,dp,NV_NOFREE);
1N/A }
1N/A dtclose(shp->alias_tree);
1N/A shp->alias_tree = inittree(shp,shtab_aliases);
1N/A shp->last_root = shp->var_tree;
1N/A shp->inuse_bits = 0;
1N/A if(shp->userinit)
1N/A (*shp->userinit)(shp, 1);
1N/A if(shp->heredocs)
1N/A {
1N/A sfclose(shp->heredocs);
1N/A shp->heredocs = 0;
1N/A }
1N/A /* remove locals */
1N/A sh_onstate(SH_INIT);
1N/A memset(&data,0,sizeof(data));
1N/A data.sh = shp;
1N/A nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_EXPORT,0);
1N/A nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_ARRAY,NV_ARRAY);
1N/A sh_offstate(SH_INIT);
1N/A memset(shp->st.trapcom,0,(shp->st.trapmax+1)*sizeof(char*));
1N/A memset((void*)&opt,0,sizeof(opt));
1N/A#if SHOPT_NAMESPACE
1N/A if(shp->namespace)
1N/A {
1N/A dp=nv_dict(shp->namespace);
1N/A if(dp==shp->var_tree)
1N/A shp->var_tree = dtview(dp,0);
1N/A _nv_unset(shp->namespace,NV_RDONLY);
1N/A shp->namespace = 0;
1N/A }
1N/A#endif /* SHOPT_NAMESPACE */
1N/A if(sh_isoption(SH_TRACKALL))
1N/A on_option(&opt,SH_TRACKALL);
1N/A if(sh_isoption(SH_EMACS))
1N/A on_option(&opt,SH_EMACS);
1N/A if(sh_isoption(SH_GMACS))
1N/A on_option(&opt,SH_GMACS);
1N/A if(sh_isoption(SH_VI))
1N/A on_option(&opt,SH_VI);
1N/A if(sh_isoption(SH_VIRAW))
1N/A on_option(&opt,SH_VIRAW);
1N/A shp->options = opt;
1N/A /* set up new args */
1N/A if(argv)
1N/A shp->arglist = sh_argcreate(argv);
1N/A if(shp->arglist)
1N/A sh_argreset(shp,shp->arglist,NIL(struct dolnod*));
1N/A shp->envlist=0;
1N/A shp->curenv = 0;
1N/A shp->shname = error_info.id = strdup(shp->st.dolv[0]);
1N/A sh_offstate(SH_FORKED);
1N/A shp->fn_depth = shp->dot_depth = 0;
1N/A sh_sigreset(0);
1N/A if(!(SHLVL->nvalue.ip))
1N/A {
1N/A shlvl = 0;
1N/A SHLVL->nvalue.ip = &shlvl;
1N/A nv_onattr(SHLVL,NV_INTEGER|NV_EXPORT|NV_NOFREE);
1N/A }
1N/A *SHLVL->nvalue.ip +=1;
1N/A nv_offattr(SHLVL,NV_IMPORT);
1N/A shp->st.filename = strdup(shp->lastarg);
1N/A return(1);
1N/A}
1N/A
1N/A/*
1N/A * set when creating a local variable of this name
1N/A */
1N/ANamfun_t *nv_cover(register Namval_t *np)
1N/A{
1N/A if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS || np==ENVNOD || np==LINENO)
1N/A return(np->nvfun);
1N/A#ifdef _hdr_locale
1N/A if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD)
1N/A return(np->nvfun);
1N/A#endif
1N/A return(0);
1N/A}
1N/A
1N/Astatic const char *shdiscnames[] = { "tilde", 0};
1N/A
1N/A#ifdef SHOPT_STATS
1N/Astruct Stats
1N/A{
1N/A Namfun_t hdr;
1N/A Shell_t *sh;
1N/A char *nodes;
1N/A int numnodes;
1N/A int current;
1N/A};
1N/A
1N/Astatic Namval_t *next_stat(register Namval_t* np, Dt_t *root,Namfun_t *fp)
1N/A{
1N/A struct Stats *sp = (struct Stats*)fp;
1N/A if(!root)
1N/A sp->current = 0;
1N/A else if(++sp->current>=sp->numnodes)
1N/A return(0);
1N/A return(nv_namptr(sp->nodes,sp->current));
1N/A}
1N/A
1N/Astatic Namval_t *create_stat(Namval_t *np,const char *name,int flag,Namfun_t *fp)
1N/A{
1N/A struct Stats *sp = (struct Stats*)fp;
1N/A register const char *cp=name;
1N/A register int i=0,n;
1N/A Namval_t *nq=0;
1N/A Shell_t *shp = sp->sh;
1N/A if(!name)
1N/A return(SH_STATS);
1N/A while((i=*cp++) && i != '=' && i != '+' && i!='[');
1N/A n = (cp-1) -name;
1N/A for(i=0; i < sp->numnodes; i++)
1N/A {
1N/A nq = nv_namptr(sp->nodes,i);
1N/A if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0)
1N/A goto found;
1N/A }
1N/A nq = 0;
1N/Afound:
1N/A if(nq)
1N/A {
1N/A fp->last = (char*)&name[n];
1N/A shp->last_table = SH_STATS;
1N/A }
1N/A else
1N/A errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np));
1N/A return(nq);
1N/A}
1N/A
1N/Astatic const Namdisc_t stat_disc =
1N/A{
1N/A 0, 0, 0, 0, 0,
1N/A create_stat,
1N/A 0, 0,
1N/A next_stat
1N/A};
1N/A
1N/Astatic char *name_stat(Namval_t *np, Namfun_t *fp)
1N/A{
1N/A Shell_t *shp = sh_getinterp();
1N/A sfprintf(shp->strbuf,".sh.stats.%s",np->nvname);
1N/A return(sfstruse(shp->strbuf));
1N/A}
1N/A
1N/Astatic const Namdisc_t stat_child_disc =
1N/A{
1N/A 0,0,0,0,0,0,0,
1N/A name_stat
1N/A};
1N/A
1N/Astatic Namfun_t stat_child_fun =
1N/A{
1N/A &stat_child_disc, 1, 0, sizeof(Namfun_t)
1N/A};
1N/A
1N/Astatic void stat_init(Shell_t *shp)
1N/A{
1N/A int i,nstat = STAT_SUBSHELL+1;
1N/A struct Stats *sp = newof(0,struct Stats,1,nstat*NV_MINSZ);
1N/A Namval_t *np;
1N/A sp->numnodes = nstat;
1N/A sp->nodes = (char*)(sp+1);
1N/A shgd->stats = (int*)calloc(sizeof(int*),nstat);
1N/A sp->sh = shp;
1N/A for(i=0; i < nstat; i++)
1N/A {
1N/A np = nv_namptr(sp->nodes,i);
1N/A np->nvfun = &stat_child_fun;
1N/A np->nvname = (char*)shtab_stats[i].sh_name;
1N/A nv_onattr(np,NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER);
1N/A nv_setsize(np,10);
1N/A np->nvalue.ip = &shgd->stats[i];
1N/A }
1N/A sp->hdr.dsize = sizeof(struct Stats) + nstat*(sizeof(int)+NV_MINSZ);
1N/A sp->hdr.disc = &stat_disc;
1N/A nv_stack(SH_STATS,&sp->hdr);
1N/A sp->hdr.nofree = 1;
1N/A nv_setvtree(SH_STATS);
1N/A}
1N/A#else
1N/A# define stat_init(x)
1N/A#endif /* SHOPT_STATS */
1N/A
1N/A/*
1N/A * Initialize the shell name and alias table
1N/A */
1N/Astatic Init_t *nv_init(Shell_t *shp)
1N/A{
1N/A register Init_t *ip;
1N/A double d=0;
1N/A ip = newof(0,Init_t,1,0);
1N/A if(!ip)
1N/A return(0);
1N/A shp->nvfun.last = (char*)shp;
1N/A shp->nvfun.nofree = 1;
1N/A ip->sh = shp;
1N/A shp->var_base = shp->var_tree = inittree(shp,shtab_variables);
1N/A SHLVL->nvalue.ip = &shlvl;
1N/A ip->IFS_init.hdr.disc = &IFS_disc;
1N/A ip->PATH_init.disc = &RESTRICTED_disc;
1N/A ip->PATH_init.nofree = 1;
1N/A ip->FPATH_init.disc = &RESTRICTED_disc;
1N/A ip->FPATH_init.nofree = 1;
1N/A ip->CDPATH_init.disc = &CDPATH_disc;
1N/A ip->CDPATH_init.nofree = 1;
1N/A ip->SHELL_init.disc = &RESTRICTED_disc;
1N/A ip->SHELL_init.nofree = 1;
1N/A ip->ENV_init.disc = &RESTRICTED_disc;
1N/A ip->ENV_init.nofree = 1;
1N/A ip->VISUAL_init.disc = &EDITOR_disc;
1N/A ip->VISUAL_init.nofree = 1;
1N/A ip->EDITOR_init.disc = &EDITOR_disc;
1N/A ip->EDITOR_init.nofree = 1;
1N/A ip->HISTFILE_init.disc = &HISTFILE_disc;
1N/A ip->HISTFILE_init.nofree = 1;
1N/A ip->HISTSIZE_init.disc = &HISTFILE_disc;
1N/A ip->HISTSIZE_init.nofree = 1;
1N/A ip->OPTINDEX_init.disc = &OPTINDEX_disc;
1N/A ip->OPTINDEX_init.nofree = 1;
1N/A ip->SECONDS_init.hdr.disc = &SECONDS_disc;
1N/A ip->SECONDS_init.hdr.nofree = 1;
1N/A ip->RAND_init.hdr.disc = &RAND_disc;
1N/A ip->RAND_init.hdr.nofree = 1;
1N/A ip->RAND_init.sh = shp;
1N/A ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc;
1N/A ip->SH_MATCH_init.hdr.nofree = 1;
1N/A ip->SH_MATH_init.disc = &SH_MATH_disc;
1N/A ip->SH_MATH_init.nofree = 1;
1N/A#if SHOPT_COSHELL
1N/A ip->SH_JOBPOOL_init.disc = &SH_JOBPOOL_disc;
1N/A ip->SH_JOBPOOL_init.nofree = 1;
1N/A nv_stack(SH_JOBPOOL, &ip->SH_JOBPOOL_init);
1N/A#endif /* SHOPT_COSHELL */
1N/A ip->SH_VERSION_init.disc = &SH_VERSION_disc;
1N/A ip->SH_VERSION_init.nofree = 1;
1N/A ip->LINENO_init.disc = &LINENO_disc;
1N/A ip->LINENO_init.nofree = 1;
1N/A ip->L_ARG_init.disc = &L_ARG_disc;
1N/A ip->L_ARG_init.nofree = 1;
1N/A#ifdef _hdr_locale
1N/A ip->LC_TYPE_init.disc = &LC_disc;
1N/A ip->LC_TYPE_init.nofree = 1;
1N/A ip->LC_NUM_init.disc = &LC_disc;
1N/A ip->LC_NUM_init.nofree = 1;
1N/A ip->LC_COLL_init.disc = &LC_disc;
1N/A ip->LC_COLL_init.nofree = 1;
1N/A ip->LC_MSG_init.disc = &LC_disc;
1N/A ip->LC_MSG_init.nofree = 1;
1N/A ip->LC_ALL_init.disc = &LC_disc;
1N/A ip->LC_ALL_init.nofree = 1;
1N/A ip->LANG_init.disc = &LC_disc;
1N/A ip->LANG_init.nofree = 1;
1N/A#endif /* _hdr_locale */
1N/A nv_stack(IFSNOD, &ip->IFS_init.hdr);
1N/A ip->IFS_init.hdr.nofree = 1;
1N/A nv_stack(PATHNOD, &ip->PATH_init);
1N/A nv_stack(FPATHNOD, &ip->FPATH_init);
1N/A nv_stack(CDPNOD, &ip->CDPATH_init);
1N/A nv_stack(SHELLNOD, &ip->SHELL_init);
1N/A nv_stack(ENVNOD, &ip->ENV_init);
1N/A nv_stack(VISINOD, &ip->VISUAL_init);
1N/A nv_stack(EDITNOD, &ip->EDITOR_init);
1N/A nv_stack(HISTFILE, &ip->HISTFILE_init);
1N/A nv_stack(HISTSIZE, &ip->HISTSIZE_init);
1N/A nv_stack(OPTINDNOD, &ip->OPTINDEX_init);
1N/A nv_stack(SECONDS, &ip->SECONDS_init.hdr);
1N/A nv_stack(L_ARGNOD, &ip->L_ARG_init);
1N/A nv_putval(SECONDS, (char*)&d, NV_DOUBLE);
1N/A nv_stack(RANDNOD, &ip->RAND_init.hdr);
1N/A d = (shp->gd->pid&RANDMASK);
1N/A nv_putval(RANDNOD, (char*)&d, NV_DOUBLE);
1N/A nv_stack(LINENO, &ip->LINENO_init);
1N/A nv_stack(SH_MATCHNOD, &ip->SH_MATCH_init.hdr);
1N/A nv_putsub(SH_MATCHNOD,(char*)0,10);
1N/A nv_stack(SH_MATHNOD, &ip->SH_MATH_init);
1N/A nv_stack(SH_VERSIONNOD, &ip->SH_VERSION_init);
1N/A#ifdef _hdr_locale
1N/A nv_stack(LCTYPENOD, &ip->LC_TYPE_init);
1N/A nv_stack(LCALLNOD, &ip->LC_ALL_init);
1N/A nv_stack(LCMSGNOD, &ip->LC_MSG_init);
1N/A nv_stack(LCCOLLNOD, &ip->LC_COLL_init);
1N/A nv_stack(LCNUMNOD, &ip->LC_NUM_init);
1N/A nv_stack(LANGNOD, &ip->LANG_init);
1N/A#endif /* _hdr_locale */
1N/A (PPIDNOD)->nvalue.lp = (&shp->gd->ppid);
1N/A (TMOUTNOD)->nvalue.lp = (&shp->st.tmout);
1N/A (MCHKNOD)->nvalue.lp = (&sh_mailchk);
1N/A (OPTINDNOD)->nvalue.lp = (&shp->st.optindex);
1N/A /* set up the seconds clock */
1N/A shp->alias_tree = inittree(shp,shtab_aliases);
1N/A shp->track_tree = dtopen(&_Nvdisc,Dtset);
1N/A shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins);
1N/A shp->fun_tree = dtopen(&_Nvdisc,Dtoset);
1N/A dtview(shp->fun_tree,shp->bltin_tree);
1N/A nv_mount(DOTSHNOD, "type", shp->typedict=dtopen(&_Nvdisc,Dtoset));
1N/A nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0);
1N/A DOTSHNOD->nvalue.cp = Empty;
1N/A SH_LINENO->nvalue.ip = &shp->st.lineno;
1N/A VERSIONNOD->nvalue.nrp = newof(0,struct Namref,1,0);
1N/A VERSIONNOD->nvalue.nrp->np = SH_VERSIONNOD;
1N/A VERSIONNOD->nvalue.nrp->root = nv_dict(DOTSHNOD);
1N/A VERSIONNOD->nvalue.nrp->table = DOTSHNOD;
1N/A nv_onattr(VERSIONNOD,NV_REF);
1N/A math_init(shp);
1N/A if(!shgd->stats)
1N/A stat_init(shp);
1N/A return(ip);
1N/A}
1N/A
1N/A/*
1N/A * initialize name-value pairs
1N/A */
1N/A
1N/Astatic Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
1N/A{
1N/A register Namval_t *np;
1N/A register const struct shtable2 *tp;
1N/A register unsigned n = 0;
1N/A register Dt_t *treep;
1N/A Dt_t *base_treep, *dict;
1N/A for(tp=name_vals;*tp->sh_name;tp++)
1N/A n++;
1N/A np = (Namval_t*)calloc(n,sizeof(Namval_t));
1N/A if(!shgd->bltin_nodes)
1N/A {
1N/A shgd->bltin_nodes = np;
1N/A shgd->bltin_nnodes = n;
1N/A }
1N/A else if(name_vals==(const struct shtable2*)shtab_builtins)
1N/A {
1N/A shgd->bltin_cmds = np;
1N/A nbltins = n;
1N/A }
1N/A base_treep = treep = dtopen(&_Nvdisc,Dtoset);
1N/A treep->user = (void*)shp;
1N/A for(tp=name_vals;*tp->sh_name;tp++,np++)
1N/A {
1N/A if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name))
1N/A np->nvname++;
1N/A else
1N/A {
1N/A np->nvname = (char*)tp->sh_name;
1N/A treep = base_treep;
1N/A }
1N/A np->nvenv = 0;
1N/A if(name_vals==(const struct shtable2*)shtab_builtins)
1N/A np->nvalue.bfp = ((struct shtable3*)tp)->sh_value;
1N/A else
1N/A {
1N/A if(name_vals == shtab_variables)
1N/A np->nvfun = &shp->nvfun;
1N/A np->nvalue.cp = (char*)tp->sh_value;
1N/A }
1N/A nv_setattr(np,tp->sh_number);
1N/A if(nv_isattr(np,NV_TABLE))
1N/A nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset));
1N/A if(nv_isattr(np,NV_INTEGER))
1N/A nv_setsize(np,10);
1N/A else
1N/A nv_setsize(np,0);
1N/A dtinsert(treep,np);
1N/A if(nv_istable(np))
1N/A treep = dict;
1N/A }
1N/A return(treep);
1N/A}
1N/A
1N/A/*
1N/A * read in the process environment and set up name-value pairs
1N/A * skip over items that are not name-value pairs
1N/A */
1N/A
1N/Astatic void env_init(Shell_t *shp)
1N/A{
1N/A register char *cp;
1N/A register Namval_t *np,*mp;
1N/A register char **ep=environ;
1N/A char *dp,*next=0;
1N/A int nenv=0,k=0,size=0;
1N/A Namval_t *np0;
1N/A#ifdef _ENV_H
1N/A shp->env = env_open(environ,3);
1N/A env_delete(shp->env,"_");
1N/A#endif
1N/A if(!ep)
1N/A goto skip;
1N/A while(*ep++)
1N/A nenv++;
1N/A np = newof(0,Namval_t,nenv,0);
1N/A for(np0=np,ep=environ;cp= *ep; ep++)
1N/A {
1N/A dp = strchr(cp,'=');
1N/A if(!dp)
1N/A continue;
1N/A *dp++ = 0;
1N/A if(mp = dtmatch(shp->var_base,cp))
1N/A {
1N/A mp->nvenv = (char*)cp;
1N/A dp[-1] = '=';
1N/A }
1N/A else if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]==0)
1N/A {
1N/A dp[-1] = '=';
1N/A next = cp+4;
1N/A continue;
1N/A }
1N/A else
1N/A {
1N/A k++;
1N/A mp = np++;
1N/A mp->nvname = cp;
1N/A size += strlen(cp);
1N/A }
1N/A nv_onattr(mp,NV_IMPORT);
1N/A if(mp->nvfun || nv_isattr(mp,NV_INTEGER))
1N/A nv_putval(mp,dp,0);
1N/A else
1N/A {
1N/A mp->nvalue.cp = dp;
1N/A nv_onattr(mp,NV_NOFREE);
1N/A }
1N/A nv_onattr(mp,NV_EXPORT|NV_IMPORT);
1N/A }
1N/A np = (Namval_t*)realloc((void*)np0,k*sizeof(Namval_t));
1N/A dp = (char*)malloc(size+k);
1N/A while(k-->0)
1N/A {
1N/A size = strlen(np->nvname);
1N/A memcpy(dp,np->nvname,size+1);
1N/A np->nvname[size] = '=';
1N/A np->nvenv = np->nvname;
1N/A np->nvname = dp;
1N/A dp += size+1;
1N/A dtinsert(shp->var_base,np++);
1N/A }
1N/A while(cp=next)
1N/A {
1N/A if(next = strchr(++cp,'='))
1N/A *next = 0;
1N/A np = nv_search(cp+2,shp->var_tree,NV_ADD);
1N/A if(np!=SHLVL && nv_isattr(np,NV_IMPORT|NV_EXPORT))
1N/A {
1N/A int flag = *(unsigned char*)cp-' ';
1N/A int size = *(unsigned char*)(cp+1)-' ';
1N/A if((flag&NV_INTEGER) && size==0)
1N/A {
1N/A /* check for floating*/
1N/A char *val = nv_getval(np);
1N/A strtol(val,&dp,10);
1N/A if(*dp=='.' || *dp=='e' || *dp=='E')
1N/A {
1N/A char *lp;
1N/A flag |= NV_DOUBLE;
1N/A if(*dp=='.')
1N/A {
1N/A strtol(dp+1,&lp,10);
1N/A if(*lp)
1N/A dp = lp;
1N/A }
1N/A if(*dp && *dp!='.')
1N/A {
1N/A flag |= NV_EXPNOTE;
1N/A size = dp-val;
1N/A }
1N/A else
1N/A size = strlen(dp);
1N/A size--;
1N/A }
1N/A }
1N/A nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
1N/A if((flag&(NV_INTEGER|NV_UTOL|NV_LTOU))==(NV_UTOL|NV_LTOU))
1N/A nv_mapchar(np,(flag&NV_UTOL)?e_tolower:e_toupper);
1N/A }
1N/A else
1N/A cp += 2;
1N/A }
1N/Askip:
1N/A#ifdef _ENV_H
1N/A env_delete(shp->env,e_envmarker);
1N/A#endif
1N/A if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
1N/A {
1N/A nv_offattr(PWDNOD,NV_TAGGED);
1N/A path_pwd(shp,0);
1N/A }
1N/A if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
1N/A sh_onoption(SH_RESTRICTED); /* restricted shell */
1N/A return;
1N/A}
1N/A
1N/A/*
1N/A * terminate shell and free up the space
1N/A */
1N/Aint sh_term(void)
1N/A{
1N/A sfdisc(sfstdin,SF_POPDISC);
1N/A free((char*)sh.outbuff);
1N/A stakset(NIL(char*),0);
1N/A return(0);
1N/A}
1N/A
1N/A/* function versions of these */
1N/A
1N/A#define DISABLE /* proto workaround */
1N/A
1N/Aunsigned long sh_isoption DISABLE (int opt)
1N/A{
1N/A return(sh_isoption(opt));
1N/A}
1N/A
1N/Aunsigned long sh_onoption DISABLE (int opt)
1N/A{
1N/A return(sh_onoption(opt));
1N/A}
1N/A
1N/Aunsigned long sh_offoption DISABLE (int opt)
1N/A{
1N/A return(sh_offoption(opt));
1N/A}
1N/A
1N/Avoid sh_sigcheck DISABLE (void)
1N/A{
1N/A Shell_t *shp = sh_getinterp();
1N/A sh_sigcheck(shp);
1N/A}
1N/A
1N/ADt_t* sh_bltin_tree DISABLE (void)
1N/A{
1N/A return(sh.bltin_tree);
1N/A}
1N/A
1N/A/*
1N/A * This code is for character mapped variables with wctrans()
1N/A */
1N/Astruct Mapchar
1N/A{
1N/A Namfun_t hdr;
1N/A const char *name;
1N/A wctrans_t trans;
1N/A int lctype;
1N/A};
1N/A
1N/Astatic void put_trans(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1N/A{
1N/A struct Mapchar *mp = (struct Mapchar*)fp;
1N/A int c,offset = staktell(),off=offset;
1N/A if(val)
1N/A {
1N/A if(mp->lctype!=lctype)
1N/A {
1N/A mp->lctype = lctype;
1N/A mp->trans = wctrans(mp->name);
1N/A }
1N/A if(!mp->trans || (flags&NV_INTEGER))
1N/A goto skip;
1N/A while(c = mbchar(val))
1N/A {
1N/A c = towctrans(c,mp->trans);
1N/A stakseek(off+c);
1N/A stakseek(off);
1N/A c = mbconv(stakptr(off),c);
1N/A off += c;
1N/A stakseek(off);
1N/A }
1N/A stakputc(0);
1N/A val = stakptr(offset);
1N/A }
1N/A else
1N/A {
1N/A nv_disc(np,fp,NV_POP);
1N/A if(!(fp->nofree&1))
1N/A free((void*)fp);
1N/A }
1N/Askip:
1N/A nv_putv(np,val,flags,fp);
1N/A stakseek(offset);
1N/A}
1N/A
1N/Astatic const Namdisc_t TRANS_disc = { sizeof(struct Mapchar), put_trans };
1N/A
1N/ANamfun_t *nv_mapchar(Namval_t *np,const char *name)
1N/A{
1N/A wctrans_t trans = name?wctrans(name):0;
1N/A struct Mapchar *mp=0;
1N/A int n=0,low;
1N/A if(np)
1N/A mp = (struct Mapchar*)nv_hasdisc(np,&TRANS_disc);
1N/A if(!name)
1N/A return(mp?(Namfun_t*)mp->name:0);
1N/A if(!trans)
1N/A return(0);
1N/A if(!np)
1N/A return(((Namfun_t*)0)+1);
1N/A if((low=strcmp(name,e_tolower)) && strcmp(name,e_toupper))
1N/A n += strlen(name)+1;
1N/A if(mp)
1N/A {
1N/A if(strcmp(name,mp->name)==0)
1N/A return(&mp->hdr);
1N/A nv_disc(np,&mp->hdr,NV_POP);
1N/A if(!(mp->hdr.nofree&1))
1N/A free((void*)mp);
1N/A }
1N/A mp = newof(0,struct Mapchar,1,n);
1N/A mp->trans = trans;
1N/A mp->lctype = lctype;
1N/A if(low==0)
1N/A mp->name = e_tolower;
1N/A else if(n==0)
1N/A mp->name = e_toupper;
1N/A else
1N/A {
1N/A mp->name = (char*)(mp+1);
1N/A strcpy((char*)mp->name,name);
1N/A }
1N/A mp->hdr.disc = &TRANS_disc;
1N/A return(&mp->hdr);
1N/A}