/* * Copyright (c) 1984, 1985, 1986 AT&T * All Rights Reserved * THIS IS UNPUBLISHED PROPRIETARY SOURCE * CODE OF AT&T. * The copyright notice above does not * evidence any actual or intended * publication of such source code. */ /* * AT&T Bell Laboratories * */ #include "defs.h" #include "io.h" #include "flags.h" #include "name.h" #include "shtype.h" #include "sym.h" #include "stak.h" #include "brkincr.h" #include "builtins.h" #include "history.h" #include "timeout.h" /* This module defines the following routines */ NAMPTR checkfor(); void do_whence(); #ifdef ECHO_N char *echo_mode(); #endif /* ECHO_N */ #ifdef apollo void ev_$set_var(); #endif /* apollo */ int genenv(); char *heap(); void meminit(); void mem_scope(); void mem_unscope(); char *movstr(); void name_unscope(); char *qvalup(); void prinscan(); int printnam(); void printflg(); int readvar(); void rmlocal(); char **setenv(); void setlist(); NAMPTR setname(); int syslook(); /* This module references the following external routines */ extern void assign(); extern char *bracket_match(); extern unsigned chkid(); #ifdef ECHO_N extern MSG echo_bin; extern MSG echo_opt; #endif /* ECHO_N */ extern char **environ; extern void exitsh(); extern void failed(); extern void free(); extern NAMPTR findnod(); extern char *fullname(); extern char *getstak(); extern struct Amemory *gettree(); extern void gsort(); extern long hist_list(); extern void hist_flush(); extern void initf(); extern void gscan_all(); extern void gscan_some(); extern NAMPTR lookup(); extern void linknod(); extern char *mactrim(); extern char *malloc(); extern char *movstr(); extern unsigned rand(); extern void p_num(); extern void p_str(); extern void p_sub(); extern void p_setout(); extern void scan_all(); extern char *simple(); extern int srand(); extern char *strchr(); extern char *strcpy(); extern void rmnval(); extern void unassign(); extern long time(); extern char *utos(); extern char *valup(); static void countnam(); #ifdef ECHO_N static char *echo_arg; #endif /* ECHO_N */ static long get_rand(); static long get_second(); static struct Amemory *inittree(); static void no_export(); static void pr_name(); static void pushnam(); static void pushnid(); static void rehash(); static void rm_node(); static int set_second(); static int set_rand(); static char *staknam(); static rsflag; /* used to see if "SHELL" has been set in the environment */ static int namec; static char **argnam; static struct Amemory *namebase; struct Bfunction seconds = { get_second, set_second}; struct Bfunction randnum = { get_rand, set_rand}; /* ======== variable and string handling ======== */ /* * Table lookup routine * The table is searched for string and corresponding value is returned */ syslook(w,syswds) register char *w; SYSTAB syswds; { register int first; register SYSPTR 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); } /* * perform parameter assignment on an argument list */ void setlist(arg,xp) register ARGPTR arg; register int xp; { if(is_option(ALLEXP)) xp |= N_EXPORT; while(arg) { register char *s; if(arg->argflag&A_MAC) s=mactrim(arg->argval,0); else s = arg->argval; setname(s, xp); arg=arg->argnxt; if(is_option(EXECPR)) { p_setout(stderr); p_str(s,arg?SP:NL); } } } /* * Put into associative memory. * If & V_FLAG then the alias list is used instead * If & S_FLAG then use the current scope only */ NAMPTR setname(argi, xp) char *argi; int xp; { register char *argscan=argi; register NAMPTR n; register int sep = *argscan; char *sim; if(isalpha(sep) || ((xp&V_FLAG) && !expchar(sep))) { do { sep = *++argscan; } while(isalnum(sep)); /* check for subscript*/ if(sep=='[') { argscan = bracket_match(argscan)+1; } if((sep = *argscan) && sep!='=') failed(argi,notid); *argscan = 0; if(xp&V_FLAG) { n = findnod(argi,alias,1); if(attest(n,T_FLAG|NO_ALIAS)) pattrib(n,~(NO_ALIAS|T_FLAG|N_EXPORT)); } else if(xp&S_FLAG) /* scoped name must be in first tree */ n = findnod(argi,namep,1); else n = lookup(argi); *argscan++ = sep; if(sep == '=') { if(n==PATHNOD || n==ENVNOD || n==SHELLNOD) { if(is_option(RSHFLG)) failed(argi,restricted); if(n==SHELLNOD) { sim = simple(argscan); if(strchr(sim,'r') != NULL) rsflag = 0; /* restricted shell */ } } assign (n, argscan); attrib(n, xp&~(S_FLAG|V_FLAG)); #ifdef apollo if(attest(n,N_EXPORT) && attest(n,N_IMPORT)==0 && (xp&(S_FLAG|V_FLAG))==0) { short namlen,vallen; namlen =strlen(n->namid); vallen = strlen(argscan); ev_$set_var(n->namid,&namlen,argscan,&vallen); } #endif /* apollo */ if(n==PATHNOD) { gscan_some(rehash,alias,T_FLAG,T_FLAG); #ifdef ECHO_N echo_arg = NIL; #endif /* ECHO_N */ } if(n==VISINOD || ((n==EDITNOD)&&isnull(VISINOD))) { /* turn on vi or emacs option if editor name is either*/ argscan = simple(argscan); if(gmatch(argscan,"*vi")) { off_option(EDITVI|EMACS|GMACS); on_option(EDITVI); } if(gmatch(argscan,"*macs")) { off_option(EDITVI|EMACS|GMACS); if(*argscan=='g') on_option(GMACS); else on_option(EMACS); } } } return(n); } failed (argi, notid); /* NOTREACHED */ } /* * Mark each node is invalid */ static void rehash(np) register NAMPTR np; { attrib(np,NO_ALIAS); } /* * alias each name to full path name * realias returns the pathname or NULL if not found */ char *realias(np) register NAMPTR np; { register char *sp; register char *vp = np->value.namval.cp; int flag = namflag(np)&(N_EXPORT|NO_ALIAS|T_FLAG); /* turn of T_FLAG to avoid recursion */ pattrib(np,~(NO_ALIAS|T_FLAG)); sp = fullname(np->namid); if(sp==NIL) { unassign(np); return(NIL); } else if(*sp!= '/') { sattrib(np,flag); return(NIL); } if(vp==0 || strcmp(sp,vp)!=0) assign(np,sp); /* turn T_FLAG back on */ attrib(np,T_FLAG|N_EXPORT); return(sp); } int readvar(names,fd,raw) register char **names; FILE *fd; { FILEBLK fb; SHFILE f; register int c; int issep; register NAMPTR n; int checksep = 1; /* set when looking for separators */ STKPTR rel; char *seps; char is_eol; FILE *savef; states |= RWAIT; /* save in history file if S_FLAG is set */ if((raw&S_FLAG) && fc_fix) states |= FIXFLG; raw &= R_FLAG; f = &fb; if(*names) { if(seps=strchr(*names,'?')) *seps = 0; n = lookup(*names++); if(seps) *seps = '?'; } else n = REPLYNOD; rel=(STKPTR)relstak(); seps = qvalup(IFSNOD); if(seps==NULL) seps = sptbnl; savef = input; if(fd==NULL) failed(bread,noquery); if(fd != input) { /* buffer the input stream if possible */ if(fnobuff(fd) && (fd!=stdin || !ispipe(stdin))) setbuf(fd,malloc((unsigned)BUFSIZ)); push(f); initf(fd); } while(1) { c = (raw?readc():nextc()); issep = (strchr(seps,c)!=0); is_eol = eolchar(c); if(checksep && issep && !is_eol) { /* visable adjacent separators signify null fields*/ if(strchr(sptbnl,c)!=0) continue; } checksep = 0; if((issep && *names) || is_eol) /* from non-separator to separator */ { if(*names==NULL && staktop>stakbot) { /* remove trailing separators */ while(strchr(seps,*--staktop)); staktop++; } zerostak(); assign(n,absstak(rel)); setstak(rel); if(is_option(ALLEXP)) attrib(n,N_EXPORT); n = (*names?lookup(*names++):0); if(is_eol) break; checksep = 1; } else /* not a separator */ pushstak(c); } while(n) { assign(n, nullstr); if(is_option(ALLEXP)) attrib(n,N_EXPORT); n = (*names?lookup(*names++):0); } if(savef != fd) pop(1); if(states&FIXFLG) hist_flush(); states &= ~(RWAIT|PROMPT); states |= is_option(INTFLG); return; } /* * put string v onto the heap and return the heap pointer */ char *heap(v) register char *v; { register char *p; if(v) { movstr(v,p=malloc((unsigned)strlen(v)+1)); return(p); } else return(0); } /* * print out the name and value of a name-value pair */ int printnam(n,flag) register NAMPTR n; register int flag; { register FILE *fd; register char *s; union Namval *up= &n->value.namval; if(trapnote&SIGSET) exitsh(SIGFAIL); fd = output; if(attest(n,NO_ALIAS)==NO_ALIAS) { return(0); } if(is_afunction(n)) { fputs(bltfn,fd); fputs(n->namid,fd); if(flag==0 && n->value.namval.rp->hoffset >=0 ) { fputs(fn_hdr,fd); hist_list(n->value.namval.rp->hoffset,EOF,"\n"); } else putc('\n',fd); return(n->namsz+1); } if(s=valup(n)) { char numbuf[30]; pr_name(n,0); flag = (flag?NL:'='); if (attest (n, ARRAY)) { if(attest(n,INT_GER)) { /* copy to a save place */ strcpy(numbuf,s); s = numbuf; } p_sub((int)up->aray->adot,flag); } else putc(flag,fd); if(flag != NL) p_str(s,NL); return(1); } return(0); } /* * print the name of a node followed by the character c */ static void pr_name(n,c) register NAMPTR n; int c; { register char *cp = strchr(n->namid,'='); if(cp) *cp = 0; p_str(n->namid,c); if(cp) *cp = '='; } static void pushnid(np) NAMPTR np; { *argnam++ = np->namid; namec++; if(attest(np,ARRAY)) arayp(np)->adot = arayp(np)->maxi; } /* * print the nodes in tree which have attributes set */ void prinscan(file,flag,root,option) FILE *file; struct Amemory *root; { register char **argv; register NAMPTR np; p_setout(file); argv = argnam = (char**)locstak(); namec = 0; if(flag) gscan_some(pushnid,root,flag,flag); else gscan_all(pushnid,root); gsort(argv,namec); while(namec--) { { register char *cp; if(cp = strchr(*argv,'=')) *cp = 0; np = checkfor(*argv++,root); if(cp) *cp = '='; } if(np) { if(attest(np,ARRAY)) { register struct Namaray *ap = arayp (np); register int i, imax; i = ap->adot = 0; imax = ap->maxi; for (; i <= imax; i++) { ap->adot = i; if (ap->val[i]) printnam(np,option); } } else printnam(np,option); } } } static char *staknam(n,value) char * value; register NAMPTR n; { register char *p,*q; q = getstak(strlen(n->namid)+strlen(value)+2); p=movstr(n->namid,q); *p++ = '='; strcpy(p,value); return(q); } void printflg(n) register NAMPTR n; { register SYSPTR syscan; register int val; if (namflag(n) != N_DEFAULT) { syscan=attributes; while(*syscan->sysnam) { val = syscan->sysval; if(attest(n,val)==val) { p_str(syscan->sysnam,SP); if (attest (n, L_JUST|R_JUST|Z_FILL)) p_num(n->namsz,SP); if(val == (BLT_NOD|INT_GER)) break; } if(val == INT_GER && attest(n,INT_GER)) { if(n->namsz != 10) { p_str(intbase,SP); p_num(n->namsz,SP); } break; } syscan++; } pr_name(n,NL); } } int genenv() { register char **e=environ; register NAMPTR n; rsflag = 1; if(e) { while(*e) { n = setname(*e, (N_IMPORT|N_EXPORT)); n->namid = *e++; } } return(rsflag); } static void countnam() { namec++; } static void pushnam(n) register NAMPTR n; { register char *value; if(attest(n,N_IMPORT)) *argnam++ = n->namid; else if(value=valup(n)) *argnam++ = staknam(n,value); } /* * Generate the environment list for the child. */ char **setenv() { register char **er; namec = 0; /* L_ARGNOD gets generated automatically as full path name of command */ pattrib(L_ARGNOD,~N_EXPORT); gscan_some (countnam,namep, N_EXPORT|N_IMPORT, N_EXPORT); er = (char**)getstak((namec+2)*BYTESPERWORD); argnam = ++er; gscan_some (pushnam, namep, N_EXPORT|N_IMPORT, N_EXPORT); *argnam++ = 0; return(er); } /* * Initialize the shell name and alias table */ void meminit() { register NAMPTR np; bltin_nodes = (NAMPTR)malloc((unsigned)(NNODES*sizeof(struct Namnod))); namebase = namep = inittree(node_names,bltin_nodes,0); /* set up random number generator */ #ifdef apollo (PPIDNOD)->value.namval.cp = (char*)(&ppid); (L_ARGNOD)->value.namval.cp = (char*)(&lastarg); (TMOUTNOD)->value.namval.cp = (char*)(&timeout); (SECONDS)->value.namval.cp = (char*)(&seconds); (MCHKNOD)->value.namval.cp = (char*)(&mailchk); (RANDNOD)->value.namval.cp = (char*)(&randnum); #endif /* apollo */ namflag(RANDNOD) = N_FREE|INT_GER|BLT_NOD; /* set up the seconds clock */ namflag(SECONDS) = N_FREE|INT_GER|BLT_NOD; set_second(0L); namflag(MCHKNOD) = N_FREE|INT_GER; namflag(TMOUTNOD) = INT_GER; namflag(PPIDNOD) = (N_FREE|INT_GER|N_RDONLY); namflag(L_ARGNOD) = N_FREE|IN_DIR; np = (NAMPTR)malloc(NALIAS*sizeof(struct Namnod)); alias = inittree(alias_names,np,N_EXPORT); prnames = gettree(MEMSIZE/4); } /* * re-initialize name-value pairs after fork */ static struct Amemory *inittree(name_vals,nodes,atflag) struct name_value *name_vals; NAMPTR nodes; { register struct Amemory *treep; register NAMPTR np; register struct name_value *nv; int flag; treep = gettree (MEMSIZE); for(np=nodes,nv=name_vals;*nv->nv_name;nv++,np++) { np->namid = nv->nv_name; np->value.namval.cp = nv->nv_value; flag = 0; #ifdef apollo if(*nv->nv_value==0) np->value.namval.cp = 0; else #else if(nv->nv_value) #endif /* apollo */ { flag = atflag|N_FREE; if(atflag && *nv->nv_value=='/') flag |= T_FLAG; } sattrib(np,flag); np->namsz = 10; linknod (np, treep); } return(treep); } /* * create a new environment scope */ void mem_scope(envlist) ARGPTR envlist; { register struct Amemory *sav_namep = namep; register struct Amemory *newscope; newscope = gettree(MEMSIZE/8); newscope->nexttree = sav_namep; namep = newscope; setlist(envlist,N_EXPORT|S_FLAG); newscope->nexttree = NULL; namep = sav_namep; scan_all(no_export,newscope); newscope->nexttree = sav_namep; namep = newscope; } /* * Temporarily remove name from export list of previous scopes */ static void no_export(nnod) register struct Namnod *nnod; { register struct Namnod *np = checkfor(nnod->namid,namep); if(np && attest(np,N_EXPORT)) { pattrib(np,~N_EXPORT); attrib(np,E_FLAG); } } /* * free up top environment scope */ void mem_unscope() { register struct Amemory *ap = namep; if((namep = ap->nexttree)==NULL) namep = namebase; scan_all(rm_node,ap); free((char*)ap); } /* * free up all environment scopes except the first */ void name_unscope() { while(namep->nexttree) mem_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 = checkfor(nnod->namid,namep); if(np && attest(np,E_FLAG)) { pattrib(np,~E_FLAG); attrib(np,N_EXPORT); } pattrib(nnod,~N_EXPORT); rmlocal(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 rmlocal (nnod) register struct Namnod *nnod; { register int i; register struct Nodval *nv; register struct Namaray *ap; register union Namval *up = &nnod->value.namval; /* return if the node is global or unfreeable */ if (attest (nnod, N_EXPORT|N_FREE)) return; /* * If the node is a freeable array, then free both the stringspace * associated with it and its dope vector. */ else if (attest (nnod, ARRAY)) { ap = up->aray; i = ap->maxi; while(i >= 0) { nv = ap->val[i--]; if (nv) { if (freeble (nv)) rmnval (unmark (nv)); else { up = &nv->namval; if ((up->cp) && ((nv->namflg & (N_FREE|N_ALLOC)) == 0)) free ((nv->namflg & IN_DIR)?up->up->cp:up->cp); } } } free ((char*)(arayp(nnod))); nnod->value.namval.cp = NULL; } /* * otherwise node is a freeable scalar, so free the string * representing its value. */ else { unassign (nnod); } sattrib (nnod, N_DEFAULT); } /* * Get the value of a built-in node * A lookup may not be necessary */ char *qvalup(n) register NAMPTR n; { if(namep->nexttree) n = lookup((node_names+(n-bltin_nodes))->nv_name); return(valup(n)); } /* * lookup name in trees root and return Namnod pointer with this name. * If none exists, it will not be created. */ NAMPTR checkfor(name,root) char *name; struct Amemory *root; { register struct Namnod *np = NULL; register struct Amemory *app = root; struct Namnod *findnod(); while(app && np==NULL) { np = findnod(name,app,0); app = app->nexttree; } return((np==NULL||isnull(np))?NULL:np); } /* * for the whence command */ void do_whence(com,flag) char **com; register int flag; { register char *a1; register struct Namnod *np; register char *cp; struct Namnod *fp; while(a1 = *++com) { if(flag) fputs(a1,output); np = NULL; /* reserved words first */ if(syslook(a1,reserved)) { if(flag) a1 = is_reserved; } /* non-tracked aliases */ else if((np=findnod(a1,alias,CHK_FOR)) && !isnull(np) && attest(np,T_FLAG)==0 && (a1=valup(np))) { if(flag) { if(attest(np,N_EXPORT)) cp = is_xalias; else cp = is_alias; fputs(cp,output); } } /* built-in commands next */ else if(syslook(a1,commands)) { if(flag) a1 = is_builtin; } /* functions next */ else if((fp=findnod(a1,prnames,CHK_FOR))&& !isnull(fp)) { if(flag) a1=attest(fp,N_EXPORT)?is_xfunction:is_function; } else { /* find full pathname */ a1 = fullname(a1); if(a1) { if(flag) { /* tracked aliases next */ if(np && attest(np,T_FLAG) && *a1 == '/') fputs(is_talias,output); else fputs(is_,output); } } else { a1 = (flag?notfound:nullstr); exitval |= 1; } } p_str(a1,NL); } } /* * these functions are used to get and set the SECONDS variable */ static long sec_offset; static int set_second(n) long n; { sec_offset = time((long*)0) - n ; } static long get_second() { return(time((long*)0)-sec_offset); } /* * These functions are used to get and set the RANDOM variable */ static int set_rand(n) long n; { srand((int)n); } static long get_rand() { return((long)rand()); } #ifdef ECHO_N char *echo_mode() { register char *cp; optflag savopts; if(echo_arg==0) { #ifdef apollo register NAMPTR np = checkfor("SYSTYPE",namep); if(np && (cp=valup(np))) { echo_arg = (*cp=='b'?echo_opt:minus); return(echo_arg); } #endif /* apollo */ savopts = flags; off_option(HASHALL); cp = fullname(echo_bin+5); flags = savopts; if(eq(cp,echo_bin)) echo_arg = echo_opt; else echo_arg = minus; } return(echo_arg); } #endif /* ECHO_N */