1206 lines
23 KiB
C
Executable File
1206 lines
23 KiB
C
Executable File
#ident "@(#)name.c 1.11 95/03/06 SMI" /* From AT&T Toolchest */
|
|
|
|
/*
|
|
* AT&T Bell Laboratories
|
|
*
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include "defs.h"
|
|
#include "sym.h"
|
|
#include "builtins.h"
|
|
#include "history.h"
|
|
#include "timeout.h"
|
|
#ifdef _locale_
|
|
# include <locale.h>
|
|
# ifdef MULTIBYTE
|
|
# include "national.h"
|
|
extern unsigned char _ctype[];
|
|
# endif /* MULTIBYTE */
|
|
#endif /* _locale_ */
|
|
|
|
#ifdef ECHOPRINT
|
|
# undef ECHO_RAW
|
|
# undef ECHO_N
|
|
#endif /* ECHOPRINT */
|
|
|
|
#ifdef ECHO_RAW
|
|
char *echo_mode();
|
|
#endif /* ECHO_RAW */
|
|
#ifdef apollo
|
|
void ev_$set_var();
|
|
#endif /* apollo */
|
|
void name_unscope();
|
|
|
|
/* This module references the following external routines */
|
|
extern char **environ;
|
|
extern struct Amemory *gettree();
|
|
extern void gsort();
|
|
extern int gscan_all();
|
|
extern int gscan_some();
|
|
extern int rand();
|
|
extern int scan_all();
|
|
extern void srand();
|
|
extern int strcmp();
|
|
extern char *utos();
|
|
|
|
#ifdef ECHO_RAW
|
|
static char *echo_arg;
|
|
#endif /* ECHO_RAW */
|
|
static void attstore();
|
|
static long get_rand();
|
|
static long get_second();
|
|
static struct Amemory *inittree();
|
|
static void no_export();
|
|
static void pushnam();
|
|
static void pushnid();
|
|
void rehash();
|
|
static void rm_node();
|
|
static int set_second();
|
|
static int set_rand();
|
|
static long get_lineno();
|
|
static int set_lineno();
|
|
static long get_errno();
|
|
static int set_errno();
|
|
static char *staknam();
|
|
|
|
|
|
static int rsflag; /* used to see if "SHELL" has been set in the environment */
|
|
static int initenv;
|
|
static int pwdset;
|
|
static char **argnam;
|
|
static struct Amemory *namebase;
|
|
static int attsize;
|
|
static char *attval;
|
|
|
|
struct Bfunction sh_seconds = { get_second, set_second};
|
|
struct Bfunction sh_randnum = { get_rand, set_rand};
|
|
struct Bfunction line_numbers = { get_lineno, set_lineno};
|
|
struct Bfunction sh_errno = { get_errno, set_errno };
|
|
|
|
|
|
|
|
/* ======== variable and string handling ======== */
|
|
|
|
/*
|
|
* Table lookup routine
|
|
* The table <syswds> is searched for string <w> and corresponding value is returned
|
|
*/
|
|
sh_lookup(w,syswds)
|
|
register const char *w;
|
|
SYSTAB syswds;
|
|
{
|
|
register int first;
|
|
register const struct sysnod *syscan;
|
|
register int c;
|
|
if(w==0 || (first= *w)==0)
|
|
return(0);
|
|
syscan=syswds;
|
|
while((c= *syscan->sysnam) && c <= first)
|
|
{
|
|
if(first == c && eq(w,syscan->sysnam))
|
|
return(syscan->sysval);
|
|
syscan++;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
#ifdef FS_3D
|
|
/*
|
|
* set or unset the mappings given a colon separated list of directories
|
|
*/
|
|
static void vpath_set(str,mode)
|
|
char *str;
|
|
int mode;
|
|
{
|
|
register char *lastp, *oldp=str, *newp=strchr(oldp,':');
|
|
while(newp)
|
|
{
|
|
*newp++ = 0;
|
|
if(lastp=strchr(newp,':'))
|
|
*lastp = 0;
|
|
mount((mode?newp:""),oldp,2);
|
|
newp[-1] = ':';
|
|
oldp = newp;
|
|
newp=lastp;
|
|
}
|
|
}
|
|
#endif /* FS_3D */
|
|
/*
|
|
* perform parameter assignment on an argument list
|
|
*/
|
|
|
|
void env_setlist(arg,xp)
|
|
register struct argnod *arg;
|
|
register int xp;
|
|
{
|
|
register char *s;
|
|
int traceon;
|
|
if(is_option(ALLEXP))
|
|
xp |= N_EXPORT;
|
|
if(arg)
|
|
traceon = sh_trace((char**)0,0);
|
|
while(arg)
|
|
{
|
|
if(arg->argflag&A_MAC)
|
|
s=mac_trim(arg->argval,0);
|
|
else
|
|
s = arg->argval;
|
|
env_namset(s,sh.var_tree,xp);
|
|
arg=arg->argnxt.ap;
|
|
if(traceon)
|
|
{
|
|
p_setout(ERRIO);
|
|
p_str(s,arg?SP:NL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Put <arg> into associative memory.
|
|
* If <xp> & V_FLAG then subscript is not allowed
|
|
* If <xp> & G_FLAG then use the current scope only
|
|
* If <xp> & P_FLAG then assignment is not allowed
|
|
*/
|
|
|
|
|
|
struct namnod *env_namset(argi,root,xp)
|
|
char *argi;
|
|
struct Amemory *root;
|
|
int xp;
|
|
{
|
|
register char *argscan=argi;
|
|
register struct namnod *n;
|
|
register int sep = *argscan;
|
|
char *sim;
|
|
|
|
/*
|
|
* XPG4: Allow file name starts with '-'
|
|
* ie.: hash -- -fooy
|
|
*/
|
|
if(root==sh.alias_tree || root == sh.track_tree)
|
|
{
|
|
while((sep= *argscan) != '=' && !expchar(sep) && sep!='/')
|
|
argscan++;
|
|
}
|
|
else if(isalpha(sep))
|
|
{
|
|
do
|
|
{
|
|
sep = *++argscan;
|
|
}
|
|
#ifdef apollo
|
|
/*
|
|
* dsee defines environment variables that contain .(dots),
|
|
* allow then to be passed through.
|
|
*/
|
|
while(isalnum(sep) || sep == '.');
|
|
#else
|
|
while(isalnum(sep));
|
|
#endif /* apollo */
|
|
}
|
|
if(argscan!=argi)
|
|
{
|
|
*argscan = 0;
|
|
n = nam_search(argi,root,N_ADD|(xp&G_FLAG));
|
|
*argscan = sep;
|
|
/* check for subscript*/
|
|
if(sep=='[' && !(xp&V_FLAG))
|
|
{
|
|
argscan = array_subscript(n,argscan);
|
|
sep = *argscan;
|
|
}
|
|
else if(nam_istype(n,N_ARRAY))
|
|
array_dotset(n,ARRAY_UNDEF);
|
|
if(sep && ((sep!='=')||(xp&P_FLAG)))
|
|
{
|
|
if(initenv)
|
|
return(0);
|
|
goto failed;
|
|
}
|
|
if(root==sh.alias_tree)
|
|
{
|
|
if(nam_istype(n,T_FLAG|NO_ALIAS))
|
|
nam_offtype(n,~(NO_ALIAS|T_FLAG|N_EXPORT));
|
|
}
|
|
if(sep == '=')
|
|
{
|
|
argscan++;
|
|
if(n==SHELLNOD)
|
|
{
|
|
sim = path_basename(argscan);
|
|
if(strmatch(sim,"*r*sh"))
|
|
rsflag = 0; /* restricted shell */
|
|
}
|
|
if(initenv)
|
|
{
|
|
nam_fputval(n, argscan);
|
|
if(n==PWDNOD)
|
|
pwdset++;
|
|
}
|
|
else
|
|
{
|
|
#ifdef FS_3D
|
|
if(n==VPATHNOD)
|
|
{
|
|
char *cp = nam_fstrval(n);
|
|
if(cp)
|
|
vpath_set(cp,0);
|
|
vpath_set(argscan,1);
|
|
}
|
|
#endif /* FS_3D */
|
|
nam_putval(n, argscan);
|
|
}
|
|
nam_ontype(n, xp&~(G_FLAG|V_FLAG|P_FLAG));
|
|
#ifdef apollo
|
|
/*
|
|
* Set environment variable defined in the underlying
|
|
* DOMAIN_OS cache. This is done because dsee will only
|
|
* process the path if it has changed since the last
|
|
* time it looked.
|
|
*/
|
|
if(nam_istype(n,N_EXPORT) && !nam_istype(n,N_IMPORT)
|
|
&& !(xp&(G_FLAG|V_FLAG|P_FLAG)))
|
|
{
|
|
short namlen,vallen;
|
|
namlen =strlen(n->namid);
|
|
vallen = strlen(argscan);
|
|
ev_$set_var(n->namid,&namlen,argscan,&vallen);
|
|
}
|
|
/*
|
|
* if env variable is PATH or SYSTYPE then rehash
|
|
* the shells tracked_tree.
|
|
*/
|
|
if(n==PATHNOD || n==SYSTYPENOD)
|
|
#else
|
|
if(n==PATHNOD)
|
|
#endif /* apollo */
|
|
{
|
|
sh.lastpath = 0;
|
|
gscan_some(rehash,sh.track_tree,T_FLAG,T_FLAG);
|
|
#ifdef ECHO_RAW
|
|
echo_arg = NIL;
|
|
#endif /* ECHO_RAW */
|
|
}
|
|
else if(n==VISINOD || ((n==EDITNOD)&&isnull(VISINOD)))
|
|
{
|
|
/* turn on vi or emacs option if editor name is either*/
|
|
argscan = path_basename(argscan);
|
|
if(strmatch(argscan,"*vi"))
|
|
{
|
|
off_option(EDITVI|EMACS|GMACS);
|
|
on_option(EDITVI);
|
|
}
|
|
if(strmatch(argscan,"*macs"))
|
|
{
|
|
off_option(EDITVI|EMACS|GMACS);
|
|
if(*argscan=='g')
|
|
on_option(GMACS);
|
|
else
|
|
on_option(EMACS);
|
|
}
|
|
}
|
|
#ifdef _locale_
|
|
else if(n==LCTYPENOD || ((n==LANGNOD)&&isnull(LCTYPENOD)))
|
|
{
|
|
setlocale(LC_CTYPE,argscan);
|
|
# ifdef MULTIBYTE
|
|
argscan = (char*)(&_ctype[514]);
|
|
for(sep=1; sep<=3; sep++)
|
|
int_charsize[sep] = *argscan++;
|
|
for(sep=5; sep<=7; sep++)
|
|
int_charsize[sep] = *argscan++;
|
|
# endif /* MULTIBYTE */
|
|
}
|
|
#endif /* _locale_ */
|
|
#ifdef MULTIBYTE
|
|
else if(n==CSWIDTHNOD)
|
|
{
|
|
if(ed_setwidth(argscan) && !initenv)
|
|
sh_fail(n->namid,e_format);
|
|
}
|
|
#endif /* MULTIBYTE */
|
|
}
|
|
return(n);
|
|
}
|
|
if(initenv)
|
|
return(0);
|
|
failed:
|
|
sh_fail (argi,(root==sh.alias_tree?e_aliname:e_ident));
|
|
/* NOTREACHED */
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Mark each node is invalid
|
|
*/
|
|
|
|
void rehash(np)
|
|
register struct namnod *np;
|
|
{
|
|
nam_ontype(np,NO_ALIAS);
|
|
}
|
|
|
|
/*
|
|
* Assign values to an array
|
|
*/
|
|
|
|
void env_arrayset(np, argn, argv)
|
|
register struct namnod *np;
|
|
register int argn;
|
|
register char *argv[];
|
|
{
|
|
while(--argn > 0)
|
|
{
|
|
if(argn>1 || nam_istype(np,N_ARRAY))
|
|
array_dotset(np,argn-1);
|
|
nam_putval(np,argv[argn]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is the code to read a line and to split it into tokens
|
|
*/
|
|
|
|
void env_readline(names,fd,raw)
|
|
char **names;
|
|
int fd;
|
|
{
|
|
register struct fileblk *fp;
|
|
register int c;
|
|
int issep;
|
|
int mask;
|
|
int maxtry = 10;
|
|
register struct namnod *n;
|
|
register char *name;
|
|
int checksep = 1; /* set when looking for separators */
|
|
int rel;
|
|
int escape;
|
|
char *seps;
|
|
char is_eol;
|
|
int savstates = st.states;
|
|
/* save in history file if S_FLAG is set */
|
|
if((raw&S_FLAG) && hist_open())
|
|
st.states |= (RWAIT|FIXFLG);
|
|
if(raw&R_FLAG)
|
|
escape = 0;
|
|
else
|
|
escape = ESCAPE;
|
|
if(names && (name = *names))
|
|
{
|
|
if(seps=strchr(name,'?'))
|
|
*seps = 0;
|
|
n = env_namset(name,sh.var_tree,P_FLAG);
|
|
name = *++names;
|
|
if(seps)
|
|
*seps = '?';
|
|
}
|
|
else
|
|
{
|
|
name = 0;
|
|
if(sh.var_tree->nexttree)
|
|
n = nam_search((node_names+(REPLYNOD-sh.bltin_nodes))->nv_name,sh.var_tree,N_ADD);
|
|
else
|
|
n = REPLYNOD;
|
|
}
|
|
seps = nam_fstrval(IFSNOD);
|
|
if(seps==NULL)
|
|
seps = (char*)e_sptbnl;
|
|
if(strcmp(seps,e_sptbnl)==0)
|
|
mask = ~(' '|'\t'|'\n');
|
|
else
|
|
mask = 0;
|
|
fp = io_ftable[fd];
|
|
if(!fp || fp == &io_stdout)
|
|
{
|
|
io_init(fd,(struct fileblk*)0,(char*)0);
|
|
fp = io_ftable[fd];
|
|
}
|
|
if(fp->flag&IOWRT)
|
|
{
|
|
int saveout = output;
|
|
output = fd;
|
|
p_flush();
|
|
output = saveout;
|
|
fp->flag &= ~IOWRT;
|
|
fp->last = fp->ptr;
|
|
}
|
|
if(fp->flag&IOSLOW)
|
|
fp->flag |= IOEDIT;
|
|
rel= staktell();
|
|
while(1)
|
|
{
|
|
while((c=io_getc(fd))==0);
|
|
/* check for interrupt */
|
|
if(c == escape)
|
|
{
|
|
if(io_getc(fd)==NL && (fp->flag&IOEDIT))
|
|
{
|
|
sh_prompt(0);
|
|
continue;
|
|
}
|
|
fp->ptr--;
|
|
}
|
|
else if(c==EOF && !fiseof(fp) && io_intr(fp)<0)
|
|
{
|
|
if(--maxtry > 0)
|
|
continue;
|
|
fp->flag |= IOERR;
|
|
}
|
|
issep = !(c&mask) && (strchr(seps,c)!=0);
|
|
is_eol = (c==NL || c==EOF);
|
|
if(checksep && issep && !is_eol)
|
|
{
|
|
/* visible adjacent separators signify null fields*/
|
|
if(mask || strchr(e_sptbnl,c)!=0)
|
|
continue;
|
|
}
|
|
checksep = 0;
|
|
if((issep && name) || is_eol) /* from non-separator to separator */
|
|
{
|
|
if(name==NULL)
|
|
{
|
|
/* remove trailing separators */
|
|
c = staktell();
|
|
while(c > rel)
|
|
{
|
|
if(strchr(seps,*stakptr(--c)))
|
|
continue;
|
|
c++;
|
|
break;
|
|
}
|
|
stakseek(c);
|
|
}
|
|
stakputc(0);
|
|
nam_putval(n,stakptr(rel));
|
|
stakseek(rel);
|
|
again:
|
|
if(is_option(ALLEXP))
|
|
nam_ontype(n,N_EXPORT);
|
|
if(name)
|
|
{
|
|
n = env_namset(name,sh.var_tree,P_FLAG);
|
|
name = *++names;
|
|
}
|
|
else
|
|
n = 0;
|
|
if(is_eol)
|
|
{
|
|
if(n==0)
|
|
break;
|
|
nam_putval(n, NULLSTR);
|
|
goto again;
|
|
|
|
}
|
|
checksep = 1;
|
|
}
|
|
else /* not a separator */
|
|
{
|
|
if(c==escape)
|
|
c = io_getc(fd);
|
|
stakputc(c);
|
|
}
|
|
}
|
|
if(st.states&FIXFLG)
|
|
hist_flush();
|
|
st.states = savstates;
|
|
}
|
|
|
|
|
|
/*
|
|
* print out the name and value of a name-value pair <n>
|
|
*/
|
|
|
|
int env_prnamval(n,flag)
|
|
register struct namnod *n;
|
|
register int flag;
|
|
{
|
|
register char *s;
|
|
|
|
if(sh.trapnote&SIGSET)
|
|
sh_exit(SIGFAIL);
|
|
if(flag)
|
|
flag = NL;
|
|
if(nam_istype(n,NO_PRINT)==NO_PRINT)
|
|
return(0);
|
|
if(is_afunction(n))
|
|
{
|
|
if(!flag)
|
|
p_str(e_bltfn,0);
|
|
if(n->value.namval.ip==0 || n->value.namval.rp->hoffset <0)
|
|
flag = NL;
|
|
p_str(n->namid,flag);
|
|
if(!flag)
|
|
{
|
|
p_str(e_fnhdr,0);
|
|
hist_list(n->value.namval.rp->hoffset,0,"\n");
|
|
}
|
|
return(n->value.namsz+1);
|
|
}
|
|
if(s=nam_strval(n))
|
|
{
|
|
char numbuf[30];
|
|
#ifdef MULTIDIM
|
|
struct Nodval *nv= &n->value;
|
|
#endif /* MULTIDIM */
|
|
p_str(n->namid,0);
|
|
if(!flag)
|
|
flag = '=';
|
|
if (nam_istype (n, N_ARRAY))
|
|
{
|
|
#ifdef MULTIDIM
|
|
int i = 0;
|
|
#endif /* MULTIDIM */
|
|
if(nam_istype(n,N_INTGER))
|
|
{
|
|
/* copy to a save place */
|
|
strcpy(numbuf,s);
|
|
s = numbuf;
|
|
}
|
|
#ifdef MULTIDIM
|
|
do
|
|
{
|
|
int dot = array_ptr(n)->cur[i++]&ARRAY_MASK;
|
|
p_sub(dot,0);
|
|
nv = nv->namval.aray->val[dot];
|
|
}
|
|
while(nv && (nv->namflg&N_ARRAY));
|
|
#else
|
|
p_sub(((int)array_ptr(n)->cur[0]&ARRAY_MASK)-1,0);
|
|
#endif /* MULTIDIM */
|
|
}
|
|
p_char(flag);
|
|
if(flag != NL)
|
|
#ifdef POSIX
|
|
p_qstr(s,NL);
|
|
#else
|
|
p_str(s,NL);
|
|
#endif /* POSIX */
|
|
return(1);
|
|
}
|
|
else
|
|
p_str(n->namid,NL);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* print the name of a node followed by the character c
|
|
*/
|
|
|
|
|
|
static void pushnid(np)
|
|
struct namnod *np;
|
|
{
|
|
*argnam++ = np->namid;
|
|
}
|
|
|
|
/*
|
|
* print the nodes in tree <root> which have attributes <flag> set
|
|
*/
|
|
|
|
void env_scan(file,flag,root,option)
|
|
int file;
|
|
struct Amemory *root;
|
|
{
|
|
register char **argv;
|
|
register struct namnod *np;
|
|
register int namec;
|
|
struct namnod *onp = 0;
|
|
p_setout(file);
|
|
namec = gscan_some((void(*)())0,root,flag,flag);
|
|
argv = argnam = (char**)stakalloc((namec+1)*BYTESPERWORD);
|
|
namec = gscan_some(pushnid,root,flag,flag);
|
|
gsort(argv,namec,strcmp);
|
|
while(namec--)
|
|
{
|
|
if((np = nam_search(*argv++,root,N_NULL)) && np!=onp)
|
|
{
|
|
onp = np;
|
|
if(nam_istype(np,N_ARRAY))
|
|
{
|
|
array_dotset(np,ARRAY_AT);
|
|
do
|
|
{
|
|
env_prnamval(np,option);
|
|
}
|
|
while(array_next(np));
|
|
}
|
|
else
|
|
env_prnamval(np,option);
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *staknam(n,value)
|
|
char * value;
|
|
register struct namnod *n;
|
|
{
|
|
register char *p,*q;
|
|
q = stakalloc(strlen(n->namid)+(value?strlen(value):0)+2);
|
|
p=sh_copy(n->namid,q);
|
|
if(value)
|
|
{
|
|
*p++ = '=';
|
|
strcpy(p,value);
|
|
}
|
|
return(q);
|
|
}
|
|
|
|
|
|
/*
|
|
* print the attributes of name value pair give by <n>
|
|
*/
|
|
|
|
void env_prattr(n)
|
|
register struct namnod *n;
|
|
{
|
|
register const struct sysnod *syscan;
|
|
register unsigned val;
|
|
#ifdef FLOAT
|
|
register unsigned mask;
|
|
#endif /* FLOAT */
|
|
if (namflag(n) != N_DEFAULT)
|
|
{
|
|
syscan=tab_attributes;
|
|
while(*syscan->sysnam)
|
|
{
|
|
val = syscan->sysval;
|
|
#ifdef FLOAT
|
|
mask = val;
|
|
if(val&N_INTGER)
|
|
mask |= N_DOUBLE;
|
|
if(nam_istype(n,mask)==val)
|
|
#else
|
|
if(nam_istype(n,val)==val)
|
|
#endif /* FLOAT */
|
|
{
|
|
p_str(syscan->sysnam,SP);
|
|
if(val == (N_BLTNOD|N_INTGER))
|
|
break;
|
|
if (nam_istype (n, N_LJUST|N_RJUST|N_ZFILL))
|
|
p_num(n->value.namsz,SP);
|
|
}
|
|
if(val == N_INTGER && nam_istype(n,N_INTGER))
|
|
{
|
|
if(n->value.namsz != 10)
|
|
{
|
|
#ifdef FLOAT
|
|
if(nam_istype(n, N_DOUBLE))
|
|
p_str(e_precision,SP);
|
|
else
|
|
#endif /* FLOAT */
|
|
p_str(e_intbase,SP);
|
|
p_num(n->value.namsz,SP);
|
|
}
|
|
break;
|
|
}
|
|
syscan++;
|
|
}
|
|
p_str(n->namid,NL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* read in the process environment and set up name-value pairs
|
|
* skip over items that are not name-value pairs
|
|
*/
|
|
|
|
int env_init()
|
|
{
|
|
register char *cp;
|
|
register struct namnod *n;
|
|
register char **e=environ;
|
|
char *next=0;
|
|
rsflag = 1;
|
|
initenv = 1;
|
|
if(e)
|
|
{
|
|
while(cp= *e++)
|
|
{
|
|
if(*cp=='A' && cp[1]=='_' && cp[2]=='_' &&
|
|
cp[3]=='z' && cp[4]=='=')
|
|
next = cp +4;
|
|
else if(n=env_namset(cp,sh.var_tree,(N_IMPORT|N_EXPORT)))
|
|
n->value.namenv = cp;
|
|
}
|
|
while(cp=next)
|
|
{
|
|
if(next = strchr(++cp,'='))
|
|
*next = 0;
|
|
if(cp[2])
|
|
{
|
|
if(n=nam_search(cp+2,sh.var_tree,0))
|
|
nam_newtype(n,(unsigned)(cp[0]-' ')|N_IMPORT|N_EXPORT,cp[1]-' ');
|
|
}
|
|
}
|
|
}
|
|
initenv = 0;
|
|
if(pwdset)
|
|
path_pwd(0);
|
|
return(rsflag);
|
|
}
|
|
|
|
/*
|
|
* put the name and attribute into value of attributes variable
|
|
*/
|
|
|
|
static void attstore(n)
|
|
register struct namnod *n;
|
|
{
|
|
register int flag = namflag(n);
|
|
if(!(flag&N_EXPORT) || ((flag&N_INTGER) && (flag&N_BLTNOD)))
|
|
return;
|
|
flag &= (N_RDONLY|N_UTOL|N_LTOU|N_RJUST|N_LJUST|N_ZFILL|N_INTGER);
|
|
*attval++ = '=';
|
|
*attval++ = ' '+flag;
|
|
if(flag&N_INTGER)
|
|
*attval = ' '+n->value.namsz;
|
|
else
|
|
*attval = ' ';
|
|
attval = sh_copy(n->namid,++attval);
|
|
}
|
|
|
|
static void pushnam(n)
|
|
register struct namnod *n;
|
|
{
|
|
register char *value;
|
|
if(nam_istype(n,N_IMPORT))
|
|
{
|
|
if(n->value.namenv)
|
|
*argnam++ = n->value.namenv;
|
|
}
|
|
else if(value=nam_strval(n))
|
|
*argnam++ = staknam(n,value);
|
|
if(nam_istype(n,N_RDONLY|N_UTOL|N_LTOU|N_RJUST|N_LJUST|N_ZFILL|N_INTGER))
|
|
attsize += (strlen(n->namid)+4);
|
|
}
|
|
|
|
/*
|
|
* Generate the environment list for the child.
|
|
*/
|
|
|
|
|
|
char **env_gen()
|
|
{
|
|
register char **er;
|
|
register int namec;
|
|
register char *cp;
|
|
/* L_ARGNOD gets generated automatically as full path name of command */
|
|
nam_offtype(L_ARGNOD,~N_EXPORT);
|
|
attsize = 6;
|
|
namec = gscan_some ((void(*)())0,sh.var_tree, N_EXPORT|N_IMPORT, N_EXPORT);
|
|
er = (char**)stakalloc((namec+3)*BYTESPERWORD);
|
|
argnam = ++er;
|
|
gscan_some (pushnam, sh.var_tree, N_EXPORT|N_IMPORT, N_EXPORT);
|
|
*argnam = (char*)stakalloc(attsize);
|
|
cp = attval = sh_copy(e_envmarker,*argnam);
|
|
gscan_some(attstore,sh.var_tree,
|
|
(N_RDONLY|N_UTOL|N_LTOU|N_RJUST|N_LJUST|N_ZFILL|N_INTGER),
|
|
(N_RDONLY|N_UTOL|N_LTOU|N_RJUST|N_LJUST|N_ZFILL|N_INTGER));
|
|
*attval = 0;
|
|
if(cp!=attval)
|
|
argnam++;
|
|
*argnam = 0;
|
|
return(er);
|
|
}
|
|
|
|
/*
|
|
* Initialize the shell name and alias table
|
|
*/
|
|
|
|
void nam_init()
|
|
{
|
|
namebase = sh.var_tree = inittree(node_names);
|
|
/* set up random number generator */
|
|
#ifdef apollo
|
|
(PPIDNOD)->value.namval.cp = (char*)(&sh.ppid);
|
|
(L_ARGNOD)->value.namval.cp = (char*)(&sh.lastarg);
|
|
(TMOUTNOD)->value.namval.cp = (char*)(&sh_timeout);
|
|
(SECONDS)->value.namval.cp = (char*)(&sh_seconds);
|
|
(MCHKNOD)->value.namval.cp = (char*)(&sh_mailchk);
|
|
(RANDNOD)->value.namval.cp = (char*)(&sh_randnum);
|
|
(ERRNO)->value.namval.cp = (char*)(&sh_errno);
|
|
(LINENO)->value.namval.cp = (char*)(&line_numbers);
|
|
(OPTIND)->value.namval.cp = (char*)(&opt_index);
|
|
#endif /* apollo */
|
|
/* set up the seconds clock */
|
|
set_second(0L);
|
|
sh.alias_tree = inittree(alias_names);
|
|
sh.track_tree = inittree(tracked_names);
|
|
/* for back compatibility scope alias in front of tracked pathnames */
|
|
sh.alias_tree->nexttree = sh.track_tree;
|
|
sh.fun_tree = inittree(built_ins);
|
|
}
|
|
|
|
/*
|
|
* initialize name-value pairs
|
|
*/
|
|
|
|
static struct Amemory *inittree(name_vals)
|
|
struct name_value *name_vals;
|
|
{
|
|
register struct namnod *np;
|
|
register struct name_value *nv;
|
|
{
|
|
register unsigned flag = 0;
|
|
for(nv=name_vals;*nv->nv_name;nv++)
|
|
flag++;
|
|
np = (struct namnod*)malloc(flag*sizeof(struct namnod));
|
|
if(sh.bltin_nodes==0)
|
|
sh.bltin_nodes = np;
|
|
else if(name_vals==built_ins)
|
|
sh.bltin_cmds = np;
|
|
}
|
|
{
|
|
register struct Amemory *treep;
|
|
treep = gettree(MEMSIZE);
|
|
for(nv=name_vals;*nv->nv_name;nv++,np++)
|
|
{
|
|
np->namid = (char*)nv->nv_name;
|
|
np->value.namval.cp = (char*)nv->nv_value;
|
|
#ifdef apollo
|
|
if(*nv->nv_value==0)
|
|
np->value.namval.cp = 0;
|
|
#endif /* apollo */
|
|
nam_typeset(np,nv->nv_flags);
|
|
if(nam_istype(np,N_INTGER))
|
|
np->value.namsz = 10;
|
|
else
|
|
np->value.namsz = 0;
|
|
nam_link(np, treep);
|
|
np->value.namenv = 0;
|
|
}
|
|
return(treep);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* create a new environment scope
|
|
*/
|
|
|
|
void nam_scope(envlist)
|
|
struct argnod *envlist;
|
|
{
|
|
register struct Amemory *sav_var_tree = sh.var_tree;
|
|
register struct Amemory *newscope;
|
|
newscope = gettree(MEMSIZE/8);
|
|
newscope->nexttree = sav_var_tree;
|
|
sh.var_tree = newscope;
|
|
env_setlist(envlist,N_EXPORT|G_FLAG);
|
|
newscope->nexttree = NULL;
|
|
sh.var_tree = sav_var_tree;
|
|
scan_all(no_export,newscope);
|
|
newscope->nexttree = sav_var_tree;
|
|
sh.var_tree = newscope;
|
|
}
|
|
|
|
/*
|
|
* Temporarily remove name from export list of previous scopes
|
|
*/
|
|
|
|
static void no_export(nnod)
|
|
register struct namnod *nnod;
|
|
{
|
|
register struct namnod *np = nam_search(nnod->namid,sh.var_tree,N_NULL);
|
|
if(np && nam_istype(np,N_EXPORT))
|
|
{
|
|
nam_offtype(np,~N_EXPORT);
|
|
nam_ontype(np,E_FLAG);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* free up top environment scope
|
|
*/
|
|
|
|
void nam_unscope()
|
|
{
|
|
register struct Amemory *ap = sh.var_tree;
|
|
if((sh.var_tree = ap->nexttree)==NULL)
|
|
sh.var_tree = namebase;
|
|
scan_all(rm_node,ap);
|
|
free((char*)ap);
|
|
}
|
|
|
|
/*
|
|
* free up all environment scopes except the first
|
|
*/
|
|
|
|
void name_unscope()
|
|
{
|
|
while(sh.var_tree->nexttree)
|
|
nam_unscope();
|
|
}
|
|
|
|
/*
|
|
* Remove a node and free up all the space
|
|
* Restate export attribute for hidden nodes if necessary
|
|
*/
|
|
static void rm_node(nnod)
|
|
register struct namnod *nnod;
|
|
{
|
|
register struct namnod *np = nam_search(nnod->namid,sh.var_tree,N_NULL);
|
|
if(np && nam_istype(np,E_FLAG))
|
|
{
|
|
nam_offtype(np,~E_FLAG);
|
|
nam_ontype(np,N_EXPORT);
|
|
}
|
|
nam_offtype(nnod,~N_EXPORT);
|
|
env_nolocal(nnod);
|
|
free((char*)nnod);
|
|
}
|
|
|
|
/*
|
|
* Remove freeable local space associated with the namval field
|
|
* of nnod. This includes any strings representing the value(s) of the
|
|
* node, as well as its dope vector, if it is an array.
|
|
*/
|
|
|
|
void env_nolocal (nnod)
|
|
register struct namnod *nnod;
|
|
{
|
|
if (nam_istype(nnod, N_EXPORT|N_FREE))
|
|
return;
|
|
if (nam_istype(nnod, N_ARRAY))
|
|
array_dotset(nnod,ARRAY_AT);
|
|
nam_free(nnod);
|
|
nam_typeset(nnod, N_DEFAULT);
|
|
}
|
|
|
|
/*
|
|
* Get the value of a built-in node
|
|
* A nam_search may not be necessary
|
|
*/
|
|
|
|
char *nam_fstrval(n)
|
|
register struct namnod *n;
|
|
{
|
|
if(sh.var_tree->nexttree)
|
|
n = nam_search((node_names+(n-sh.bltin_nodes))->nv_name,sh.var_tree,N_ADD);
|
|
return(nam_strval(n));
|
|
}
|
|
|
|
/*
|
|
* for the whence command
|
|
*/
|
|
|
|
int sh_whence(com,flag)
|
|
char **com;
|
|
register int flag;
|
|
{
|
|
register const char *a1;
|
|
register struct namnod *np;
|
|
register const char *cp;
|
|
char tmpbuf[LINE_MAX];
|
|
|
|
int notrack;
|
|
int q = 0;
|
|
int r;
|
|
int pflag = (flag&P_FLAG);
|
|
flag &= ~P_FLAG;
|
|
while(a1 = *++com)
|
|
{
|
|
notrack = 1;
|
|
tmpbuf[0] = 0; /* Initialize buffer */
|
|
r = 0;
|
|
if(flag)
|
|
strcat(tmpbuf, a1);
|
|
if(pflag)
|
|
goto search;
|
|
/* reserved words first */
|
|
if(sh_lookup(a1,tab_reserved))
|
|
{
|
|
if(flag)
|
|
a1 = is_reserved;
|
|
}
|
|
/* non-tracked aliases */
|
|
else if((np=nam_search(a1,sh.alias_tree,N_NULL))
|
|
&& (notrack=(nam_istype(np,T_FLAG)==0))
|
|
&& (a1=nam_strval(np)))
|
|
{
|
|
if(flag)
|
|
{
|
|
if(nam_istype(np,N_EXPORT))
|
|
cp = is_xalias;
|
|
else
|
|
cp = is_alias;
|
|
strcat(tmpbuf, cp);
|
|
}
|
|
}
|
|
/* built-ins and functions next */
|
|
else if(np=nam_search(a1,sh.fun_tree,N_NULL))
|
|
{
|
|
if(flag)
|
|
{
|
|
if(isnull(np))
|
|
{
|
|
if(!nam_istype(np,N_FUNCTION))
|
|
goto search;
|
|
a1 = is_ufunction;
|
|
}
|
|
else if(is_abuiltin(np)) {
|
|
if (is_asbuiltin(np))
|
|
a1 = is_sbuiltin;
|
|
else
|
|
a1 = is_builtin;
|
|
} else if(nam_istype(np,N_EXPORT))
|
|
a1 = is_xfunction;
|
|
else
|
|
a1 = is_function;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
search:
|
|
if(path_search(a1,2)==0)
|
|
a1 = sh.lastpath;
|
|
sh.lastpath = 0;
|
|
if(a1)
|
|
{
|
|
if(flag)
|
|
{
|
|
if(*a1!= '/')
|
|
a1 = is_ufunction;
|
|
else
|
|
/* tracked aliases next */
|
|
if(!notrack && *a1 == '/')
|
|
strcat(tmpbuf, is_talias);
|
|
else
|
|
strcat(tmpbuf, is_);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
r = ENOTFOUND;
|
|
if(flag)
|
|
a1 = e_found;
|
|
else
|
|
a1 = e_nullstr;
|
|
}
|
|
}
|
|
if (r)
|
|
p_setout(ERRIO);
|
|
else
|
|
p_setout(st.standout);
|
|
strcat(tmpbuf, a1);
|
|
|
|
a1 = tmpbuf;
|
|
if (tmpbuf[0])
|
|
#ifdef notdef /* ifdef POSIX */
|
|
p_qstr(a1,NL);
|
|
#else
|
|
p_str(a1,NL);
|
|
#endif /* POSIX */
|
|
if (!q && r)
|
|
q = r; /* Save results */
|
|
}
|
|
return(q);
|
|
}
|
|
|
|
/*
|
|
* these functions are used to get and set the SECONDS variable
|
|
*/
|
|
|
|
static time_t sec_offset;
|
|
|
|
static int set_second(n)
|
|
long n;
|
|
{
|
|
sec_offset = time((time_t*)0) - (time_t)n ;
|
|
}
|
|
|
|
static long get_second()
|
|
{
|
|
return((long)(time((time_t*)0)-sec_offset));
|
|
}
|
|
|
|
/*
|
|
* These functions are used to get and set the RANDOM variable
|
|
*/
|
|
|
|
static unsigned last_rand;
|
|
static int set_rand(n)
|
|
long n;
|
|
{
|
|
srand(n&0x7fff);
|
|
last_rand = 0;
|
|
}
|
|
|
|
/*
|
|
* get random number in range of 0 - 2**15
|
|
* never pick same number twice in a row
|
|
*/
|
|
|
|
static long get_rand()
|
|
{
|
|
register int cur;
|
|
do
|
|
cur = sh_rand(0);
|
|
while(cur==last_rand);
|
|
last_rand = cur;
|
|
return((long)cur);
|
|
}
|
|
|
|
static long get_lineno()
|
|
{
|
|
return((long)st.cmdline);
|
|
}
|
|
|
|
static int set_lineno(n)
|
|
{
|
|
if(!initenv)
|
|
st.standin->flin = n;
|
|
}
|
|
|
|
static long get_errno()
|
|
{
|
|
return((long)errno);
|
|
}
|
|
|
|
static int set_errno(n)
|
|
long n;
|
|
{
|
|
errno = n;
|
|
}
|
|
|
|
#ifdef ECHO_RAW
|
|
char *echo_mode()
|
|
{
|
|
register char *cp;
|
|
optflag savopts;
|
|
if(echo_arg==0)
|
|
{
|
|
#ifdef apollo
|
|
register struct namnod *np = nam_search("SYSTYPE",sh.var_tree,0);
|
|
if(np && (cp=nam_strval(np)))
|
|
{
|
|
echo_arg = (*cp=='b'?(char*)e_echoflag:(char*)e_minus);
|
|
return(echo_arg);
|
|
}
|
|
#endif /* apollo */
|
|
savopts = opt_flags;
|
|
off_option(HASHALL);
|
|
#ifdef ECHO_N
|
|
/* BSD style echo is default */
|
|
cp = path_absolute(e_echobin+5); /* 5 == strlen("/bin/") */
|
|
opt_flags = savopts;
|
|
if(cp && eq(cp,e_echobin))
|
|
echo_arg = (char*)e_echoflag;
|
|
else
|
|
echo_arg = (char*)e_minus;
|
|
#else
|
|
/* System V style echo is default */
|
|
/* for SVR4 /bin and /usr/bin are equivalent */
|
|
cp = path_absolute(e_echobin+9); /* 9 == strlen("/usr/bin/") */
|
|
opt_flags = savopts;
|
|
/* anything except /usr/ucb/echo gives System V behavior */
|
|
if(cp && eq(cp,e_echoucb))
|
|
echo_arg = (char*)e_echoflag;
|
|
else
|
|
echo_arg = (char*)e_minus;
|
|
#endif
|
|
}
|
|
return(echo_arg);
|
|
}
|
|
#endif /* ECHO_RAW */
|