1 /*
2
3 * Copyright (c) 1984, 1985, 1986 AT&T
4 * All Rights Reserved
5
6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE
7 * CODE OF AT&T.
8 * The copyright notice above does not
9 * evidence any actual or intended
10 * publication of such source code.
11
12 */
13 /*
14 * AT&T Bell Laboratories
15 *
16 */
17
18 #include "defs.h"
19 #include "io.h"
20 #include "flags.h"
21 #include "name.h"
22 #include "shtype.h"
23 #include "sym.h"
24 #include "stak.h"
25 #include "brkincr.h"
26 #include "builtins.h"
27 #include "history.h"
28 #include "timeout.h"
29
30 /* This module defines the following routines */
31 NAMPTR checkfor();
32 void do_whence();
33 #ifdef ECHO_N
34 char *echo_mode();
35 #endif /* ECHO_N */
36 #ifdef apollo
37 void ev_$set_var();
38 #endif /* apollo */
39 int genenv();
40 char *heap();
41 void meminit();
42 void mem_scope();
43 void mem_unscope();
44 char *movstr();
45 void name_unscope();
46 char *qvalup();
47 void prinscan();
48 int printnam();
49 void printflg();
50 int readvar();
51 void rmlocal();
52 char **setenv();
53 void setlist();
54 NAMPTR setname();
55 int syslook();
56
57 /* This module references the following external routines */
58 extern void assign();
59 extern char *bracket_match();
60 extern unsigned chkid();
61 #ifdef ECHO_N
62 extern MSG echo_bin;
63 extern MSG echo_opt;
64 #endif /* ECHO_N */
65 extern char **environ;
66 extern void exitsh();
67 extern void failed();
68 extern void free();
69 extern NAMPTR findnod();
70 extern char *fullname();
71 extern char *getstak();
72 extern struct Amemory *gettree();
73 extern void gsort();
74 extern long hist_list();
75 extern void hist_flush();
76 extern void initf();
77 extern void gscan_all();
78 extern void gscan_some();
79 extern NAMPTR lookup();
80 extern void linknod();
81 extern char *mactrim();
82 extern char *malloc();
83 extern char *movstr();
84 extern unsigned rand();
85 extern void p_num();
86 extern void p_str();
87 extern void p_sub();
88 extern void p_setout();
89 extern void scan_all();
90 extern char *simple();
91 extern int srand();
92 extern char *strchr();
93 extern char *strcpy();
94 extern void rmnval();
95 extern void unassign();
96 extern long time();
97 extern char *utos();
98 extern char *valup();
99
100 static void countnam();
101 #ifdef ECHO_N
102 static char *echo_arg;
103 #endif /* ECHO_N */
104 static long get_rand();
105 static long get_second();
106 static struct Amemory *inittree();
107 static void no_export();
108 static void pr_name();
109 static void pushnam();
110 static void pushnid();
111 static void rehash();
112 static void rm_node();
113 static int set_second();
114 static int set_rand();
115 static char *staknam();
116
117
118 static rsflag; /* used to see if "SHELL" has been set in the environment */
119 static int namec;
120 static char **argnam;
121 static struct Amemory *namebase;
122
123 struct Bfunction seconds = { get_second, set_second};
124 struct Bfunction randnum = { get_rand, set_rand};
125
126
127
128 /* ======== variable and string handling ======== */
129
130 /*
131 * Table lookup routine
132 * The table <syswds> is searched for string <w> and corresponding value is returned
133 */
syslook(w,syswds)134 syslook(w,syswds)
135 register char *w;
136 SYSTAB syswds;
137 {
138 register int first;
139 register SYSPTR syscan;
140 register int c;
141 if(w==0 || (first= *w)==0)
142 return(0);
143 syscan=syswds;
144 while((c= *syscan->sysnam) && c <= first)
145 {
146 if(first == c && eq(w,syscan->sysnam))
147 return(syscan->sysval);
148 syscan++;
149 }
150 return(0);
151 }
152
153 /*
154 * perform parameter assignment on an argument list
155 */
156
setlist(arg,xp)157 void setlist(arg,xp)
158 register ARGPTR arg;
159 register int xp;
160 {
161 if(is_option(ALLEXP))
162 xp |= N_EXPORT;
163 while(arg)
164 {
165 register char *s;
166 if(arg->argflag&A_MAC)
167 s=mactrim(arg->argval,0);
168 else
169 s = arg->argval;
170 setname(s, xp);
171 arg=arg->argnxt;
172 if(is_option(EXECPR))
173 {
174 p_setout(stderr);
175 p_str(s,arg?SP:NL);
176 }
177 }
178 }
179
180 /*
181 * Put <arg> into associative memory.
182 * If <xp> & V_FLAG then the alias list is used instead
183 * If <xp> & S_FLAG then use the current scope only
184 */
185
186
setname(argi,xp)187 NAMPTR setname(argi, xp)
188 char *argi;
189 int xp;
190 {
191 register char *argscan=argi;
192 register NAMPTR n;
193 register int sep = *argscan;
194 char *sim;
195 if(isalpha(sep) || ((xp&V_FLAG) && !expchar(sep)))
196 {
197 do
198 {
199 sep = *++argscan;
200 }
201 while(isalnum(sep));
202 /* check for subscript*/
203 if(sep=='[')
204 {
205 argscan = bracket_match(argscan)+1;
206 }
207 if((sep = *argscan) && sep!='=')
208 failed(argi,notid);
209 *argscan = 0;
210 if(xp&V_FLAG)
211 {
212 n = findnod(argi,alias,1);
213 if(attest(n,T_FLAG|NO_ALIAS))
214 pattrib(n,~(NO_ALIAS|T_FLAG|N_EXPORT));
215 }
216 else if(xp&S_FLAG)
217 /* scoped name must be in first tree */
218 n = findnod(argi,namep,1);
219 else
220 n = lookup(argi);
221 *argscan++ = sep;
222 if(sep == '=')
223 {
224 if(n==PATHNOD || n==ENVNOD || n==SHELLNOD)
225 {
226 if(is_option(RSHFLG))
227 failed(argi,restricted);
228 if(n==SHELLNOD)
229 {
230 sim = simple(argscan);
231 if(strchr(sim,'r') != NULL)
232 rsflag = 0; /* restricted shell */
233 }
234 }
235 assign (n, argscan);
236 attrib(n, xp&~(S_FLAG|V_FLAG));
237 #ifdef apollo
238 if(attest(n,N_EXPORT) && attest(n,N_IMPORT)==0
239 && (xp&(S_FLAG|V_FLAG))==0)
240 {
241 short namlen,vallen;
242 namlen =strlen(n->namid);
243 vallen = strlen(argscan);
244 ev_$set_var(n->namid,&namlen,argscan,&vallen);
245 }
246 #endif /* apollo */
247 if(n==PATHNOD)
248 {
249 gscan_some(rehash,alias,T_FLAG,T_FLAG);
250 #ifdef ECHO_N
251 echo_arg = NIL;
252 #endif /* ECHO_N */
253 }
254 if(n==VISINOD || ((n==EDITNOD)&&isnull(VISINOD)))
255 {
256 /* turn on vi or emacs option if editor name is either*/
257 argscan = simple(argscan);
258 if(gmatch(argscan,"*vi"))
259 {
260 off_option(EDITVI|EMACS|GMACS);
261 on_option(EDITVI);
262 }
263 if(gmatch(argscan,"*macs"))
264 {
265 off_option(EDITVI|EMACS|GMACS);
266 if(*argscan=='g')
267 on_option(GMACS);
268 else
269 on_option(EMACS);
270 }
271 }
272 }
273 return(n);
274 }
275 failed (argi, notid);
276 /* NOTREACHED */
277 }
278
279 /*
280 * Mark each node is invalid
281 */
282
rehash(np)283 static void rehash(np)
284 register NAMPTR np;
285 {
286 attrib(np,NO_ALIAS);
287 }
288
289 /*
290 * alias each name to full path name
291 * realias returns the pathname or NULL if not found
292 */
293
realias(np)294 char *realias(np)
295 register NAMPTR np;
296 {
297 register char *sp;
298 register char *vp = np->value.namval.cp;
299 int flag = namflag(np)&(N_EXPORT|NO_ALIAS|T_FLAG);
300 /* turn of T_FLAG to avoid recursion */
301 pattrib(np,~(NO_ALIAS|T_FLAG));
302 sp = fullname(np->namid);
303 if(sp==NIL)
304 {
305 unassign(np);
306 return(NIL);
307 }
308 else if(*sp!= '/')
309 {
310 sattrib(np,flag);
311 return(NIL);
312 }
313 if(vp==0 || strcmp(sp,vp)!=0)
314 assign(np,sp);
315 /* turn T_FLAG back on */
316 attrib(np,T_FLAG|N_EXPORT);
317 return(sp);
318 }
319
320
readvar(names,fd,raw)321 int readvar(names,fd,raw)
322 register char **names;
323 FILE *fd;
324 {
325 FILEBLK fb;
326 SHFILE f;
327 register int c;
328 int issep;
329 register NAMPTR n;
330 int checksep = 1; /* set when looking for separators */
331 STKPTR rel;
332 char *seps;
333 char is_eol;
334 FILE *savef;
335 states |= RWAIT;
336 /* save in history file if S_FLAG is set */
337 if((raw&S_FLAG) && fc_fix)
338 states |= FIXFLG;
339 raw &= R_FLAG;
340 f = &fb;
341 if(*names)
342 {
343 if(seps=strchr(*names,'?'))
344 *seps = 0;
345 n = lookup(*names++);
346 if(seps)
347 *seps = '?';
348 }
349 else
350 n = REPLYNOD;
351 rel=(STKPTR)relstak();
352 seps = qvalup(IFSNOD);
353 if(seps==NULL)
354 seps = sptbnl;
355 savef = input;
356 if(fd==NULL)
357 failed(bread,noquery);
358 if(fd != input)
359 {
360 /* buffer the input stream if possible */
361 if(fnobuff(fd) && (fd!=stdin || !ispipe(stdin)))
362 setbuf(fd,malloc((unsigned)BUFSIZ));
363 push(f);
364 initf(fd);
365 }
366 while(1)
367 {
368 c = (raw?readc():nextc());
369 issep = (strchr(seps,c)!=0);
370 is_eol = eolchar(c);
371 if(checksep && issep && !is_eol)
372 {
373 /* visable adjacent separators signify null fields*/
374 if(strchr(sptbnl,c)!=0)
375 continue;
376 }
377 checksep = 0;
378 if((issep && *names) || is_eol) /* from non-separator to separator */
379 {
380 if(*names==NULL && staktop>stakbot)
381 {
382 /* remove trailing separators */
383 while(strchr(seps,*--staktop));
384 staktop++;
385 }
386 zerostak();
387 assign(n,absstak(rel)); setstak(rel);
388 if(is_option(ALLEXP))
389 attrib(n,N_EXPORT);
390 n = (*names?lookup(*names++):0);
391 if(is_eol)
392 break;
393 checksep = 1;
394 }
395 else /* not a separator */
396 pushstak(c);
397 }
398 while(n)
399 {
400 assign(n, nullstr);
401 if(is_option(ALLEXP))
402 attrib(n,N_EXPORT);
403 n = (*names?lookup(*names++):0);
404 }
405 if(savef != fd)
406 pop(1);
407 if(states&FIXFLG)
408 hist_flush();
409 states &= ~(RWAIT|PROMPT);
410 states |= is_option(INTFLG);
411 return;
412 }
413
414 /*
415 * put string v onto the heap and return the heap pointer
416 */
417
heap(v)418 char *heap(v)
419 register char *v;
420 {
421 register char *p;
422 if(v)
423 {
424 movstr(v,p=malloc((unsigned)strlen(v)+1));
425 return(p);
426 }
427 else
428 return(0);
429 }
430
431
432 /*
433 * print out the name and value of a name-value pair <n>
434 */
435
printnam(n,flag)436 int printnam(n,flag)
437 register NAMPTR n;
438 register int flag;
439 {
440 register FILE *fd;
441 register char *s;
442 union Namval *up= &n->value.namval;
443 if(trapnote&SIGSET)
444 exitsh(SIGFAIL);
445 fd = output;
446 if(attest(n,NO_ALIAS)==NO_ALIAS)
447 {
448 return(0);
449 }
450 if(is_afunction(n))
451 {
452 fputs(bltfn,fd);
453 fputs(n->namid,fd);
454 if(flag==0 && n->value.namval.rp->hoffset >=0 )
455 {
456 fputs(fn_hdr,fd);
457 hist_list(n->value.namval.rp->hoffset,EOF,"\n");
458 }
459 else
460 putc('\n',fd);
461 return(n->namsz+1);
462 }
463 if(s=valup(n))
464 {
465 char numbuf[30];
466 pr_name(n,0);
467 flag = (flag?NL:'=');
468 if (attest (n, ARRAY))
469 {
470 if(attest(n,INT_GER))
471 {
472 /* copy to a save place */
473 strcpy(numbuf,s);
474 s = numbuf;
475 }
476 p_sub((int)up->aray->adot,flag);
477 }
478 else
479 putc(flag,fd);
480 if(flag != NL)
481 p_str(s,NL);
482 return(1);
483 }
484 return(0);
485 }
486
487 /*
488 * print the name of a node followed by the character c
489 */
490
pr_name(n,c)491 static void pr_name(n,c)
492 register NAMPTR n;
493 int c;
494 {
495 register char *cp = strchr(n->namid,'=');
496 if(cp)
497 *cp = 0;
498 p_str(n->namid,c);
499 if(cp)
500 *cp = '=';
501 }
502
pushnid(np)503 static void pushnid(np)
504 NAMPTR np;
505 {
506 *argnam++ = np->namid;
507 namec++;
508 if(attest(np,ARRAY))
509 arayp(np)->adot = arayp(np)->maxi;
510 }
511
512 /*
513 * print the nodes in tree <root> which have attributes <flag> set
514 */
515
prinscan(file,flag,root,option)516 void prinscan(file,flag,root,option)
517 FILE *file;
518 struct Amemory *root;
519 {
520 register char **argv;
521 register NAMPTR np;
522 p_setout(file);
523 argv = argnam = (char**)locstak();
524 namec = 0;
525 if(flag)
526 gscan_some(pushnid,root,flag,flag);
527 else
528 gscan_all(pushnid,root);
529 gsort(argv,namec);
530 while(namec--)
531 {
532 {
533 register char *cp;
534 if(cp = strchr(*argv,'='))
535 *cp = 0;
536 np = checkfor(*argv++,root);
537 if(cp)
538 *cp = '=';
539 }
540 if(np)
541 {
542 if(attest(np,ARRAY))
543 {
544 register struct Namaray *ap = arayp (np);
545 register int i, imax;
546 i = ap->adot = 0;
547 imax = ap->maxi;
548 for (; i <= imax; i++)
549 {
550 ap->adot = i;
551 if (ap->val[i])
552 printnam(np,option);
553 }
554 }
555 else
556 printnam(np,option);
557 }
558 }
559 }
560
staknam(n,value)561 static char *staknam(n,value)
562 char * value;
563 register NAMPTR n;
564 {
565 register char *p,*q;
566 q = getstak(strlen(n->namid)+strlen(value)+2);
567 p=movstr(n->namid,q);
568 *p++ = '=';
569 strcpy(p,value);
570 return(q);
571 }
572
573
printflg(n)574 void printflg(n)
575 register NAMPTR n;
576 {
577 register SYSPTR syscan;
578 register int val;
579 if (namflag(n) != N_DEFAULT)
580 {
581 syscan=attributes;
582 while(*syscan->sysnam)
583 {
584 val = syscan->sysval;
585 if(attest(n,val)==val)
586 {
587 p_str(syscan->sysnam,SP);
588 if (attest (n, L_JUST|R_JUST|Z_FILL))
589 p_num(n->namsz,SP);
590 if(val == (BLT_NOD|INT_GER))
591 break;
592 }
593 if(val == INT_GER && attest(n,INT_GER))
594 {
595 if(n->namsz != 10)
596 {
597 p_str(intbase,SP);
598 p_num(n->namsz,SP);
599 }
600 break;
601 }
602 syscan++;
603 }
604 pr_name(n,NL);
605 }
606 }
607
genenv()608 int genenv()
609 {
610 register char **e=environ;
611 register NAMPTR n;
612 rsflag = 1;
613 if(e)
614 {
615 while(*e)
616 {
617 n = setname(*e, (N_IMPORT|N_EXPORT));
618 n->namid = *e++;
619 }
620 }
621 return(rsflag);
622 }
623
624
countnam()625 static void countnam()
626 {
627 namec++;
628 }
629
630
pushnam(n)631 static void pushnam(n)
632 register NAMPTR n;
633 {
634 register char *value;
635 if(attest(n,N_IMPORT))
636 *argnam++ = n->namid;
637 else if(value=valup(n))
638 *argnam++ = staknam(n,value);
639 }
640
641 /*
642 * Generate the environment list for the child.
643 */
644
645
setenv()646 char **setenv()
647 {
648 register char **er;
649 namec = 0;
650 /* L_ARGNOD gets generated automatically as full path name of command */
651 pattrib(L_ARGNOD,~N_EXPORT);
652 gscan_some (countnam,namep, N_EXPORT|N_IMPORT, N_EXPORT);
653 er = (char**)getstak((namec+2)*BYTESPERWORD);
654 argnam = ++er;
655 gscan_some (pushnam, namep, N_EXPORT|N_IMPORT, N_EXPORT);
656 *argnam++ = 0;
657 return(er);
658 }
659
660 /*
661 * Initialize the shell name and alias table
662 */
663
meminit()664 void meminit()
665 {
666 register NAMPTR np;
667 bltin_nodes = (NAMPTR)malloc((unsigned)(NNODES*sizeof(struct Namnod)));
668 namebase = namep = inittree(node_names,bltin_nodes,0);
669 /* set up random number generator */
670 #ifdef apollo
671 (PPIDNOD)->value.namval.cp = (char*)(&ppid);
672 (L_ARGNOD)->value.namval.cp = (char*)(&lastarg);
673 (TMOUTNOD)->value.namval.cp = (char*)(&timeout);
674 (SECONDS)->value.namval.cp = (char*)(&seconds);
675 (MCHKNOD)->value.namval.cp = (char*)(&mailchk);
676 (RANDNOD)->value.namval.cp = (char*)(&randnum);
677 #endif /* apollo */
678 namflag(RANDNOD) = N_FREE|INT_GER|BLT_NOD;
679 /* set up the seconds clock */
680 namflag(SECONDS) = N_FREE|INT_GER|BLT_NOD;
681 set_second(0L);
682 namflag(MCHKNOD) = N_FREE|INT_GER;
683 namflag(TMOUTNOD) = INT_GER;
684 namflag(PPIDNOD) = (N_FREE|INT_GER|N_RDONLY);
685 namflag(L_ARGNOD) = N_FREE|IN_DIR;
686 np = (NAMPTR)malloc(NALIAS*sizeof(struct Namnod));
687 alias = inittree(alias_names,np,N_EXPORT);
688 prnames = gettree(MEMSIZE/4);
689 }
690
691 /*
692 * re-initialize name-value pairs after fork
693 */
694
695
inittree(name_vals,nodes,atflag)696 static struct Amemory *inittree(name_vals,nodes,atflag)
697 struct name_value *name_vals;
698 NAMPTR nodes;
699 {
700 register struct Amemory *treep;
701 register NAMPTR np;
702 register struct name_value *nv;
703 int flag;
704 treep = gettree (MEMSIZE);
705 for(np=nodes,nv=name_vals;*nv->nv_name;nv++,np++)
706 {
707 np->namid = nv->nv_name;
708 np->value.namval.cp = nv->nv_value;
709 flag = 0;
710 #ifdef apollo
711 if(*nv->nv_value==0)
712 np->value.namval.cp = 0;
713 else
714 #else
715 if(nv->nv_value)
716 #endif /* apollo */
717 {
718 flag = atflag|N_FREE;
719 if(atflag && *nv->nv_value=='/')
720 flag |= T_FLAG;
721 }
722 sattrib(np,flag);
723 np->namsz = 10;
724 linknod (np, treep);
725 }
726 return(treep);
727 }
728
729 /*
730 * create a new environment scope
731 */
732
mem_scope(envlist)733 void mem_scope(envlist)
734 ARGPTR envlist;
735 {
736 register struct Amemory *sav_namep = namep;
737 register struct Amemory *newscope;
738 newscope = gettree(MEMSIZE/8);
739 newscope->nexttree = sav_namep;
740 namep = newscope;
741 setlist(envlist,N_EXPORT|S_FLAG);
742 newscope->nexttree = NULL;
743 namep = sav_namep;
744 scan_all(no_export,newscope);
745 newscope->nexttree = sav_namep;
746 namep = newscope;
747 }
748
749 /*
750 * Temporarily remove name from export list of previous scopes
751 */
752
no_export(nnod)753 static void no_export(nnod)
754 register struct Namnod *nnod;
755 {
756 register struct Namnod *np = checkfor(nnod->namid,namep);
757 if(np && attest(np,N_EXPORT))
758 {
759 pattrib(np,~N_EXPORT);
760 attrib(np,E_FLAG);
761 }
762 }
763
764 /*
765 * free up top environment scope
766 */
767
mem_unscope()768 void mem_unscope()
769 {
770 register struct Amemory *ap = namep;
771 if((namep = ap->nexttree)==NULL)
772 namep = namebase;
773 scan_all(rm_node,ap);
774 free((char*)ap);
775 }
776
777 /*
778 * free up all environment scopes except the first
779 */
780
name_unscope()781 void name_unscope()
782 {
783 while(namep->nexttree)
784 mem_unscope();
785 }
786
787 /*
788 * Remove a node and free up all the space
789 * Restate export attribute for hidden nodes if necessary
790 */
rm_node(nnod)791 static void rm_node(nnod)
792 register struct Namnod *nnod;
793 {
794 register struct Namnod *np = checkfor(nnod->namid,namep);
795 if(np && attest(np,E_FLAG))
796 {
797 pattrib(np,~E_FLAG);
798 attrib(np,N_EXPORT);
799 }
800 pattrib(nnod,~N_EXPORT);
801 rmlocal(nnod);
802 free((char*)nnod);
803 }
804
805 /*
806 * Remove freeable local space associated with the namval field
807 * of nnod. This includes any strings representing the value(s) of the
808 * node, as well as its dope vector, if it is an array.
809 */
810
rmlocal(nnod)811 void rmlocal (nnod)
812 register struct Namnod *nnod;
813 {
814 register int i;
815 register struct Nodval *nv;
816 register struct Namaray *ap;
817 register union Namval *up = &nnod->value.namval;
818
819 /* return if the node is global or unfreeable */
820
821 if (attest (nnod, N_EXPORT|N_FREE))
822 return;
823 /*
824 * If the node is a freeable array, then free both the stringspace
825 * associated with it and its dope vector.
826 */
827
828 else if (attest (nnod, ARRAY))
829 {
830 ap = up->aray;
831 i = ap->maxi;
832 while(i >= 0)
833 {
834 nv = ap->val[i--];
835 if (nv)
836 {
837 if (freeble (nv))
838 rmnval (unmark (nv));
839 else
840 {
841 up = &nv->namval;
842 if ((up->cp) && ((nv->namflg & (N_FREE|N_ALLOC)) == 0))
843 free ((nv->namflg & IN_DIR)?up->up->cp:up->cp);
844 }
845 }
846 }
847 free ((char*)(arayp(nnod)));
848 nnod->value.namval.cp = NULL;
849 }
850 /*
851 * otherwise node is a freeable scalar, so free the string
852 * representing its value.
853 */
854 else
855 {
856 unassign (nnod);
857 }
858 sattrib (nnod, N_DEFAULT);
859 }
860
861 /*
862 * Get the value of a built-in node
863 * A lookup may not be necessary
864 */
865
qvalup(n)866 char *qvalup(n)
867 register NAMPTR n;
868 {
869 if(namep->nexttree)
870 n = lookup((node_names+(n-bltin_nodes))->nv_name);
871 return(valup(n));
872 }
873
874 /*
875 * lookup name in trees root and return Namnod pointer with this name.
876 * If none exists, it will not be created.
877 */
878
checkfor(name,root)879 NAMPTR checkfor(name,root)
880 char *name;
881 struct Amemory *root;
882 {
883 register struct Namnod *np = NULL;
884 register struct Amemory *app = root;
885 struct Namnod *findnod();
886 while(app && np==NULL)
887 {
888 np = findnod(name,app,0);
889 app = app->nexttree;
890 }
891 return((np==NULL||isnull(np))?NULL:np);
892 }
893
894 /*
895 * for the whence command
896 */
897
do_whence(com,flag)898 void do_whence(com,flag)
899 char **com;
900 register int flag;
901 {
902 register char *a1;
903 register struct Namnod *np;
904 register char *cp;
905 struct Namnod *fp;
906 while(a1 = *++com)
907 {
908 if(flag)
909 fputs(a1,output);
910 np = NULL;
911 /* reserved words first */
912 if(syslook(a1,reserved))
913 {
914 if(flag)
915 a1 = is_reserved;
916 }
917 /* non-tracked aliases */
918 else if((np=findnod(a1,alias,CHK_FOR)) && !isnull(np)
919 && attest(np,T_FLAG)==0 && (a1=valup(np)))
920 {
921 if(flag)
922 {
923 if(attest(np,N_EXPORT))
924 cp = is_xalias;
925 else
926 cp = is_alias;
927 fputs(cp,output);
928 }
929 }
930 /* built-in commands next */
931 else if(syslook(a1,commands))
932 {
933 if(flag)
934 a1 = is_builtin;
935 }
936 /* functions next */
937 else if((fp=findnod(a1,prnames,CHK_FOR))&& !isnull(fp))
938 {
939 if(flag)
940 a1=attest(fp,N_EXPORT)?is_xfunction:is_function;
941 }
942 else
943 {
944 /* find full pathname */
945 a1 = fullname(a1);
946 if(a1)
947 {
948 if(flag)
949 {
950 /* tracked aliases next */
951 if(np && attest(np,T_FLAG) && *a1 == '/')
952 fputs(is_talias,output);
953 else
954 fputs(is_,output);
955 }
956 }
957 else
958 {
959 a1 = (flag?notfound:nullstr);
960 exitval |= 1;
961 }
962 }
963 p_str(a1,NL);
964 }
965 }
966
967 /*
968 * these functions are used to get and set the SECONDS variable
969 */
970
971 static long sec_offset;
972
set_second(n)973 static int set_second(n)
974 long n;
975 {
976 sec_offset = time((long*)0) - n ;
977 }
978
get_second()979 static long get_second()
980 {
981 return(time((long*)0)-sec_offset);
982 }
983
984 /*
985 * These functions are used to get and set the RANDOM variable
986 */
987
set_rand(n)988 static int set_rand(n)
989 long n;
990 {
991 srand((int)n);
992 }
993
get_rand()994 static long get_rand()
995 {
996 return((long)rand());
997 }
998
999 #ifdef ECHO_N
echo_mode()1000 char *echo_mode()
1001 {
1002 register char *cp;
1003 optflag savopts;
1004 if(echo_arg==0)
1005 {
1006 #ifdef apollo
1007 register NAMPTR np = checkfor("SYSTYPE",namep);
1008 if(np && (cp=valup(np)))
1009 {
1010 echo_arg = (*cp=='b'?echo_opt:minus);
1011 return(echo_arg);
1012 }
1013 #endif /* apollo */
1014 savopts = flags;
1015 off_option(HASHALL);
1016 cp = fullname(echo_bin+5);
1017 flags = savopts;
1018 if(eq(cp,echo_bin))
1019 echo_arg = echo_opt;
1020 else
1021 echo_arg = minus;
1022 }
1023 return(echo_arg);
1024 }
1025 #endif /* ECHO_N */
1026