xref: /original-bsd/local/toolchest/ksh/sh/xec.c (revision 1aa52444)
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 /* @(#)xec.c	1.1 */
14 /*
15  * UNIX shell
16  *
17  * S. R. Bourne
18  * Rewritten by David Korn
19  * AT&T Bell Laboratories
20  *
21  */
22 
23 #include	<sys/types.h>
24 #include	<sys/times.h>
25 #include	<errno.h>
26 #ifdef SXT
27 #include	<sys/tty.h>
28 #include	<sys/sxt.h>
29 #endif	/* SXT */
30 #include	"defs.h"
31 #include	"sym.h"
32 #include	"mode.h"
33 #include	"flags.h"
34 #include	"name.h"
35 #include	"brkincr.h"
36 #include	"stak.h"
37 #include	"builtins.h"
38 #include	"shtype.h"
39 #include	"jobs.h"
40 #include	"io.h"
41 #ifdef BSD
42 #define TIC_SEC		60
43 #include	<sys/timeb.h>
44 #endif	/* BSD */
45 
46 /* These routines are defined by this module */
47 int execute();
48 void trace_command();
49 
50 /* These routines are referenced by this module */
51 extern char	**arg_build();
52 extern DOLPTR	arg_use();
53 extern DOLPTR	arg_free();
54 extern void	assign();
55 extern void	await();
56 extern FILE	*chkopen();
57 extern void	builtin();
58 extern void	chktrap();
59 extern void	chkpipe();
60 extern void	done();
61 extern void	execa();
62 extern void	exfunct();
63 extern void	exitsh();
64 extern void	failed();
65 extern void	free();
66 extern NAMPTR	findnod();
67 extern char	*getpath();
68 extern char	*heap();
69 extern char	*itos();
70 extern NAMPTR	lookup();
71 extern char	*macro();
72 extern char	*mactrim();
73 extern void	mem_scope();
74 extern void	mem_unscope();
75 extern char	*movstr();
76 extern char	*malloc();
77 extern void	oldsigs();
78 extern void	p_sub();
79 extern void	p_num();
80 extern void	p_str();
81 extern void	p_time();
82 extern void	p_flush();
83 extern void	p_setout();
84 extern void	p_list();
85 extern void	pipe_close();
86 extern void	postclr();
87 extern char	*qvalup();
88 extern void	restore();
89 extern void	rmtemp();
90 extern char	*strcpy();
91 extern void	setlist();
92 extern void	swap_iodoc_nm();
93 extern void	sync_io();
94 extern void	tdystak();
95 extern long	times();
96 #ifdef DEVFD
97 extern void	close_pipes();
98 #endif	/* DEVFD */
99 #ifdef VFORK
100 extern int	vfork_check();
101 extern int	vfork_save();
102 extern void	vfork_restore();
103 #endif	/* VFORK */
104 
105 static int trim_eq();
106 static char locbuf[TMPSIZ]; 	/* store last argument here if it fits */
107 
108 
109 /* ========	command execution	========*/
110 
111 
112 /* VARARGS */
113 execute(argt, execflg, apf1, apf2)
114 TREPTR 	argt;
115 unsigned execflg;
116 FILE	*apf1[],*apf2[];
117 {
118 	/* `stakbot' is preserved by this routine */
119 	register TREPTR t;
120 	STKPTR 	sav=savstak();
121 	FILE *inpipe[2],*otpipe[2];
122 	FILE **pf1 = apf1;
123 	FILE **pf2 = apf2;
124 	unsigned errorflg = (execflg&ERRFLG);
125 #ifdef VFORK
126 	int v_fork;
127 #endif	/* VFORK */
128 	if(trapnote&SIGSET)
129 		exitsh(SIGFAIL);
130 	if(errorflg==0)
131 		states &= ~ERRFLG;
132 	if((t=argt) && execbrk==0)
133 	{
134 		register int 	type;
135 		char	**com;
136 		int	argn;
137 		char *com0 = NIL;
138 		type = t->tretyp;
139 		oldexit=exitval;
140 		exitval=0;
141 		switch(type&COMMSK)
142 		{
143 			case TCOM:
144 			{
145 				register IOPTR		io;
146 				register ARGPTR		argp;
147 				NAMPTR np;
148 				type >>= (COMBITS+1);
149 				cmdline = ((COMPTR)t)->comline;
150 				com = arg_build(&argn,((COMPTR)t));
151 				if(t->tretyp&COMSCAN)
152 				{
153 					argp = ((COMPTR)t)->comarg;
154 					if(argp && (argp->argflag&A_RAW)==0)
155 						type = syslook(com[0],commands);
156 					if(trapnote&SIGSET)
157 						exitsh(SIGFAIL);
158 				}
159 				com0 = com[0];
160 				argp = ((COMPTR)t)->comset;
161 				io = t->treio;
162 				if(argn==0 || (type>0 && type<=SYSSPECIAL))
163 				{
164 					setlist(argp, 0);
165 					argp = NULL;
166 				}
167 				if((io||argn) && is_option(NOEXEC)==0)
168 					/* print command if EXECPR */
169 				{
170 					if(argn==0)
171 					{
172 						/* fake a built-in */
173 						argn=1;
174 						type = SYSMAX;
175 					}
176 					/* set +x doesn't echo */
177 					else if(type!=SYSSET)
178 					{
179 						trace_command(com);
180 					}
181 					if(io)
182 						p_flush();
183 #ifdef apollo
184 					if(is_option(INPROC) &&  type==0
185 						&& (states&FORKED)==0 &&
186 						!findnod(com0,prnames,CHK_FOR))
187 					{
188 						type = SYSINPROCESS;
189 						com--;
190 						argn++;
191 					}
192 #endif	/* apollo */
193 					/* check for builtins */
194 					if(type)
195 					{
196 						/* failures on built-ins not fatal */
197 						jmp_buf retbuf;
198 						jmp_buf *savreturn = freturn;
199 						int indx = topfd;
200 						int scope=0;
201 						if(type>=SYSNULL)
202 							freturn = (jmp_buf*)retbuf;
203 						if(setjmp(retbuf) == 0)
204 						{
205 							int flag = 1;
206 							if(type>=SYSNULL)
207 								states |= BUILTIN;
208 							else
209 							{
210 								flag = (type!=SYSLOGIN);
211 								if(type==SYSEXEC)
212 									flag = -(com[1]==0);
213 							}
214 							indx = initio(io,flag);
215 							if(argp)
216 							{
217 								mem_scope(argp);
218 								scope++;
219 							}
220 							builtin(type,argn,com,t);
221 						}
222 						states &= ~BUILTIN;
223 						freturn = savreturn;
224 						if(scope)
225 							mem_unscope();
226 						restore(indx);
227 						goto setexit;
228 					}
229 					/* check for functions */
230 					if((np=findnod(com0,prnames,CHK_FOR))
231 							 && np->value.namval.ip)
232 					{
233 						int indx;
234 						indx = initio(io,1);
235 						exfunct((TREPTR)(*funtree(np))
236 							,com
237 							,execflg|(attest(np,T_FLAG)?EXECPR:0)
238 							,((COMPTR)t)->comset);
239 						restore(indx);
240 						goto setexit;
241 					}
242 					/* track alias if possible */
243 					getpath(com0);
244 				}
245 				else if(io==0)
246 				{
247 				setexit:
248 					exitset();
249 					chktrap();
250 					break;
251 				}
252 				type = TCOM;
253 			}
254 			case TFORK:
255 			{
256 				int no_fork;
257 				sync_io();
258 #ifdef SXT
259 				/* find job number and create synchronization pipe */
260 				if((jobstat.cur_job = next_job()) < jobstat.maxjob)
261 					if(pipe(jobstat.pipe)<0)
262 						jobstat.maxjob = 0;
263 #endif	/* SXT */
264 				no_fork = (execflg&1) && (type&(FAMP|FPOU))==0;
265 				if(no_fork)
266 					parent=0;
267 				else
268 				/* FORKLIM is the max period between forks -
269 					power of 2 usually.  Currently shell tries after
270 					2,4,8,16, and 32 seconds and then quits */
271 				{
272 					register int forkcnt=1;
273 					if(type&FTMP)
274 					{
275 						link_iodocs(iotemp);
276 						linked = 1;
277 					}
278 					if((type&(FPCL|FPIN|FPOU)) == (FPIN|FPOU))
279 					/* set up pipe for cooperating process */
280 					{
281 						if(cpid)
282 							failed(cmdadr,pexists);
283 						chkpipe(pf2=otpipe);
284 						cpipe[INPIPE] = frenumber(pf2[INPIPE],CINPIPE);
285 						chkpipe(pf1=inpipe);
286 						cpipe[OTPIPE] = frenumber(pf1[OTPIPE],COTPIPE);
287 					}
288 #ifdef VFORK
289 					if(v_fork=vfork_check(t))
290 						vfork_save();
291 					while((parent=(v_fork?vfork():fork())) == -1)
292 #else
293 					while((parent=fork()) == -1)
294 #endif	/* VFORK */
295 					{
296 						if((forkcnt *= 2) > FORKLIM)
297 						{
298 							switch(errno)
299 							{
300 								case ENOMEM:
301 									error(noswap);
302 									 break;
303 								default:
304 								case EAGAIN:
305 									error(nofork);
306 									break;
307 							}
308 						}
309 						if(trapnote&SIGSET)
310 							exitsh(SIGFAIL);
311 						alarm(forkcnt);
312 						pause();
313 						alarm(0);
314 					}
315 				}
316 
317 				if(parent)
318 					/* This is the parent branch of fork;    */
319 				/* it may or may not wait for the child. */
320 				{
321 					register int pno;
322 #ifdef VFORK
323 					if(v_fork)
324 						vfork_restore();
325 #endif	/* VFORK */
326 #ifdef JOBS
327 # ifdef SXT
328 					if(jobstat.pipe[1] > 0)
329 						close(jobstat.pipe[1]);
330 # endif /* SXT */
331 					/* assign each pipeline its own process group */
332 					if(jobstat.j_flag==0||(states&MONITOR)==0)
333 						jobstat.cur_pgrp = parent;
334 #endif	/* JOBS */
335 					if(type&FPCL)
336 						fclose(pf1[INPIPE]);
337 					else if((type&FPIN)&&(type&FPOU))
338 					{
339 						cpid = parent;
340 						fclose(pf1[INPIPE]);
341 						fclose(pf2[OTPIPE]);
342 					}
343 					if((type&(FAMP|FPOU))==0)
344 					{
345 #ifdef DEVFD
346 						close_pipes();
347 #endif	/* DEVFD */
348 						await(parent,0);
349 					}
350 					else if(type&(FPOU|FPIN))
351 					{
352 						int flag;
353 						if(cpid==parent)
354 							flag = 0;
355 #ifdef JOBS
356 						else
357 							flag = P_PIPEJOB;
358 						pno = post(parent,flag);
359 #else
360 						pno = post(parent);
361 #endif	/* JOBS */
362 					}
363 					else
364 					{
365 #ifdef JOBS
366 						pno = post(parent,0);
367 #else
368 						pno = post(parent);
369 #endif
370 						movstr(itos(parent),pcsadr);
371 					}
372 					if((type&FPRS) && (states&TTYFLG))
373 					{
374 						p_setout(stderr);
375 #ifdef JOBS
376 						/* print job number */
377 						p_sub(pno,'\t');
378 #endif	/* JOBS */
379 						p_num(parent,NL);
380 					}
381 					chktrap();
382 					break;
383 				}
384 
385 				else
386 				/*
387 				 * this is the FORKED branch (child) of execute
388 				 */
389 				{
390 					if(standout != stdout)
391 						standout = frenumber(standout,1);
392 					states |= FORKED;
393 					off_option(HASHALL);
394 					if(no_fork==0)
395 					{
396 						states &= ~(RM_TMP|IS_TMP);
397 						states |= NO_TMP;
398 						if(linked == 1)
399 						{
400 							swap_iodoc_nm(iotemp);
401 							linked = 2;
402 						}
403 						else
404 							iotemp=0;
405 					}
406 #ifdef ACCT
407 					suspacct();
408 #endif	/* ACCT */
409 					/* child should not unlink the tmpfile */
410 					cpipe[INPIPE] = cpipe[OTPIPE] = NULL;
411 					cpid = 0;
412 					/* Turn off INTR and QUIT if `FINT'  */
413 					/* Reset remaining signals to parent */
414 					/* except for those `lost' by trap   */
415 					oldsigs();
416 #ifdef JOBS
417 					if(states&MONITOR)
418 					{
419 # ifdef BSD
420 						register int pid = getpid();
421 						int pgrp;
422 						if(jobstat.j_flag==0)
423 							pgrp = pid;
424 						else
425 							pgrp = jobstat.cur_pgrp;
426 						setpgrp(pid,pgrp);
427 						if(states&NONSTOP)
428 							signal(SIGTSTP,SIG_IGN);
429 						else
430 						{
431 							signal(SIGTTIN,SIG_DFL);
432 							signal(SIGTTOU,SIG_DFL);
433 							signal(SIGTSTP,SIG_DFL);
434 						}
435 #else
436 # ifdef SXT
437 						if(jobstat.cur_job < jobstat.maxjob
438 							|| (type&FAMP))
439 # else
440 #  ifdef DEVFD
441 						if((type&(FINT|FAMP))==(FINT|FAMP))
442 #  else
443 						if(type&FAMP)
444 #  endif /* DEVFD */
445 # endif /* SXT */
446 							setpgrp();
447 #endif	/* BSD */
448 					}
449 					else
450 #endif	/* JOBS */
451 					if(type&FINT)
452 					{
453 						signal(SIGINT,SIG_IGN);
454 						signal(SIGQUIT,SIG_IGN);
455 					}
456 					/* pipe in or out */
457 					if((type&FAMP) && is_option(BGNICE))
458 						nice(4);
459 #if VSH || ESH
460 					if(type&(FAMP|FPOU))
461 						off_option(EMACS|EDITVI|GMACS);
462 #endif
463 					if(type&FPIN)
464 					{
465 						frenumber(pf1[INPIPE],0);
466 						if((type&FPOU)==0)
467 							fclose(pf1[OTPIPE]);
468 						setbuf(stdin,NIL);
469 					}
470 					if(type&FPOU)
471 					{
472 						frenumber(pf2[OTPIPE],1);
473 						pipe_close(pf2);
474 					}
475 					/* default std input for & */
476 #ifdef JOBS
477 # ifdef BSD
478 					if((states&MONITOR) == 0)
479 # endif /* BSD */
480 # ifdef SXT
481 					if((states&MONITOR)==0 ||
482 						jobstat.cur_job >= jobstat.maxjob)
483 				 	{
484 # endif /* SXT */
485 #endif	/* JOBS */
486 						if((type&FINT) && ioset==0)
487 						{
488 							fclose(stdin);
489 							chkopen(devnull);
490 						}
491 						/* io redirection */
492 #ifdef JOBS
493 # ifdef SXT
494 					}
495 					else
496 						j_new_chan();
497 # endif /* SXT */
498 					states &= ~MONITOR;
499 #endif	/* JOBS */
500 					initio(t->treio,0);
501 					if(type!=TCOM)
502 					{
503 						/* don't clear job table for out
504 						   pipes so that jobs can be
505 						   piped
506 						 */
507 						if(no_fork==0 && (type&FPOU)==0)
508 							postclr();
509 						execute(((FORKPTR) t)->forktre,execflg|1);
510 					}
511 					else if(com0!=ENDARGS)
512 					{
513 						off_option(ERRFLG);
514 						rmtemp((IOPTR)0);
515 						execa(com,((COMPTR)t)->comset);
516 					}
517 					done(0);
518 				}
519 			}
520 
521 			case TSETIO:
522 			{
523 			/*
524 			 * don't create a new process, just
525 			 * save and restore io-streams
526 			 */
527 				int indx = initio(((FORKPTR)t)->forkio,1);
528 				execute(((FORKPTR)t)->forktre,execflg);
529 				restore(indx);
530 				break;
531 			}
532 
533 			case TPAR:
534 				execute(((PARPTR) t)->partre,execflg);
535 				done(0);
536 
537 			case TFIL:
538 			{
539 			/*
540 			 * This code sets up a pipe.
541 			 * All elements of the pipe are started by the parent.
542 			 * Only the last one is waited for.
543 			 */
544 				register FORKPTR tf;
545 				FILE *pvo[2];	/* old pipe for multi-pipeline */
546 				FILE *pvn[2];	/* set up pipe */
547 				register int rc = 1;
548 				do
549 				{
550 					/* create the pipe */
551 					chkpipe(pvn);
552 					tf = (FORKPTR)(((LSTPTR)t)->lstlef);
553 					/* rc==0 on multi-stage pipe */
554 					if(rc==0)
555 						tf->forktyp |= FPCL|FPIN;
556 					/* execute out part of pipe no wait */
557 					rc = execute((TREPTR)tf, errorflg, pvo, pvn);
558 					tf = (FORKPTR)(((LSTPTR)t)->lstrit);
559 					t = tf->forktre;
560 					/* save the pipe stream-ids */
561 					pvo[0] = pvn[0];
562 					/*close out-part of pipe as soon as possible */
563 					fclose(pvn[OTPIPE]);
564 #ifdef JOBS
565 					/* pipeline all in one process group */
566 					jobstat.j_flag++;
567 #endif	/* JOBS */
568 				}
569 				/* repeat until end of pipeline */
570 				while(rc==0 && tf->forkio==NULL && t->tretyp==TFIL);
571 				if(rc == 0)
572 					execute((TREPTR)tf, execflg,pvn,pf2);
573 				else
574 					/* execution failure, close pipe */
575 					pipe_close(pvn);
576 				break;
577 			}
578 
579 			case TLST:
580 			{
581 				/*  a list of commands are executed here */
582 				do
583 				{
584 					execute(((LSTPTR) t)->lstlef,errorflg);
585 					t = (TREPTR)(((LSTPTR)t)->lstrit);
586 				}
587 				while(t->tretyp == TLST);
588 				execute(t,execflg);
589 				break;
590 			}
591 
592 			case TAND:
593 #ifdef JOBS
594 				states |= NONSTOP;
595 #endif	/* JOBS */
596 				if(execute(((LSTPTR) t)->lstlef,0)==0)
597 					execute(((LSTPTR) t)->lstrit,execflg);
598 				break;
599 
600 			case TORF:
601 #ifdef JOBS
602 				states |= NONSTOP;
603 #endif	/* JOBS */
604 				if(execute(((LSTPTR) t)->lstlef,0)!=0)
605 					execute(((LSTPTR) t)->lstrit,execflg);
606 				break;
607 
608 			case TFOR:
609 			case TSELECT:
610 			{
611 				register char **args;
612 				register int nargs;
613 				NAMPTR n = lookup(((FORPTR) t)->fornam);
614 				char **arglist;
615 				DOLPTR	argsav=NULL;
616 				COMPTR	tp;
617 				char *nullptr = NULL;
618 #ifdef JOBS
619 				states |= NONSTOP;
620 #endif	/* JOBS */
621 				if((tp=((FORPTR)t)->forlst)==NULL)
622 				{
623 					args=dolv+1;
624 					nargs = dolc;
625 					argsav=arg_use();
626 				}
627 				else
628 				{
629 					args=arg_build(&argn,tp);
630 					nargs = argn;
631 				}
632 				if(type==TSELECT)
633 				{
634 					p_setout(stderr);
635 					p_list(nargs,arglist=args);
636 				}
637 				loopcnt++;
638 				while(*args !=ENDARGS && execbrk == 0)
639 				{
640 					if(t->tretyp==TSELECT)
641 					{
642 						char *val,*cp;
643 						/* reuse register */
644 #define c	type
645 						chkpr(1);
646 						if(isatty(0))
647 							states |= PROMPT;
648 						readvar(&nullptr,stdin,R_FLAG);
649 						if(feof(stdin))
650 						{
651 							exitval = 1;
652 							clearerr(stdin);
653 							break;
654 						}
655 						if((val=qvalup(REPLYNOD))==NULL)
656 							continue;
657 						else
658 						{
659 							if(*(cp=val) == 0)
660 							{
661 								p_list(nargs,args);
662 								continue;
663 							}
664 							while(c = *cp++)
665 							if(c < '0' && c > '9')
666 								break;
667 							if(c!=0)
668 								c = nargs;
669 							else
670 								c = atoi(val)-1;
671 							if(c<0 || c >= nargs)
672 								c = nargs;
673 							args += c;
674 						}
675 					}
676 #undef c
677 					assign(n, *args);
678 					if(t->tretyp != TSELECT)
679 						args++;
680 					else
681 						args = arglist;
682 					execute(((FORPTR) t)->fortre,errorflg);
683 					if(breakcnt<0)
684 						execbrk = (++breakcnt !=0);
685 					}
686 				if(breakcnt>0)
687 					execbrk = (--breakcnt !=0);
688 				loopcnt--;
689 				arg_free(argsav,0);
690 				break;
691 			}
692 
693 			case TWH:
694 			case TUN:
695 			{
696 				register int 	i=0;
697 #ifdef JOBS
698 				states |= NONSTOP;
699 #endif	/* JOBS */
700 				loopcnt++;
701 				while(execbrk==0 && (execute(((WHPTR)t)->whtre,0)==0)==(type==TWH))
702 				{
703 					i = execute(((WHPTR) t)->dotre,errorflg);
704 					if(breakcnt<0)
705 						execbrk = (++breakcnt !=0);
706 				}
707 				if(breakcnt>0)
708 					execbrk = (--breakcnt !=0);
709 				loopcnt--;
710 				exitval= i;
711 				break;
712 			}
713 
714 			case TIF:
715 #ifdef JOBS
716 				states |= NONSTOP;
717 #endif	/* JOBS */
718 				if(execute(((IFPTR) t)->iftre,0)==0)
719 					execute(((IFPTR) t)->thtre,execflg);
720 				else if(((IFPTR) t)->eltre)
721 					execute(((IFPTR) t)->eltre, execflg);
722 				else
723 					exitval=0; /* force zero exit for if-then-fi */
724 				break;
725 
726 			case TSW:
727 			{
728 				char *r = mactrim(((SWPTR) t)->swarg,0);
729 				t=(TREPTR)((SWPTR) t)->swlst;
730 				while(t)
731 				{
732 					register ARGPTR	rex=(ARGPTR)((REGPTR)t)->regptr;
733 					while(rex)
734 					{
735 						register char *s;
736 						if(rex->argflag&A_MAC)
737 							s = macro(rex->argval);
738 						else
739 							s = rex->argval;
740 						if(((rex->argflag&A_RAW)==0&&gmatch(r,s))
741 							|| trim_eq(r,s))
742 						{
743 							execute(((REGPTR)t)->regcom,errorflg);
744 							t=0;
745 							break;
746 						}
747 						else
748 							rex=rex->argnxt;
749 					}
750 					if(t)
751 						t=(TREPTR)((REGPTR)t)->regnxt;
752 				}
753 				break;
754 			}
755 
756 			case TTIME:
757 			{
758 				/* time the command */
759 				struct tms before,after;
760 				long at,bt;
761 #ifdef BSD
762 				struct timeb tb,ta;
763 				ftime(&tb);
764 #endif	/* BSD */
765 				bt = times(&before);
766 				execute(((PARPTR) t)->partre,0);
767 				at = times(&after);
768 #ifdef BSD
769 				ftime(&ta);
770 				at = TIC_SEC*(ta.time-tb.time);
771 				at +=  ((TIC_SEC*((long)(ta.millitm-tb.millitm)))/1000);
772 #else
773 				at -= bt;
774 #endif	/* BSD */
775 				p_setout(stderr);
776 				p_str(t_real,'\t');
777 				p_time(at,NL);
778 				p_str(t_user,'\t');
779 				at = after.tms_utime - before.tms_utime;
780 				at += after.tms_cutime - before.tms_cutime;
781 				p_time(at,NL);
782 				p_str(t_sys,'\t');
783 				at = after.tms_stime - before.tms_stime;
784 				at += after.tms_cstime - before.tms_cstime;
785 				p_time(at,NL);
786 				break;
787 			}
788 			case TPROC:
789 			{
790 				register NAMPTR np;
791 				register char *fname = ((PROCPTR)t)->procnam;
792 				if(!isalpha(*fname))
793 					failed(fname,notid);
794 				np = findnod(fname,prnames,1);
795 				if(np->value.namval.rp)
796 					free(np->value.namval.rp->ptree);
797 				else
798 					np->value.namval.rp = (struct Ufunction*)
799 						malloc(sizeof(struct Ufunction));
800 				funtree(np) = (int**)((PROCPTR)t)->proctre;
801 				np->value.namval.rp->hoffset = ((PROCPTR)t)->procloc;
802 				sattrib(np,L_FLAG|INT_GER);
803 				break;
804 			}
805 		}
806 #ifdef JOBS
807 		jobstat.j_flag = 0;
808 #endif	/* JOBS */
809 		/* set $. */
810 		if( com0)
811 		{
812 			if(lastarg!= locbuf)
813 				free(lastarg);
814 			if(strlen(com[argn-1]) < TMPSIZ)
815 				lastarg = strcpy(locbuf,com[argn-1]);
816 			else
817 				lastarg = heap(com[argn-1]);
818 		}
819 		exitset();
820 	}
821 	if(trapnote&SIGSET)
822 		exitsh(SIGFAIL|exitval);
823 	tdystak(sav);
824 	states |= errorflg;
825 	linked = 0;
826 	return(exitval);
827 }
828 
829 /*
830  * test for equality with second argument trimmed
831  * returns 1 if r == trim(s) otherwise 0
832  */
833 
834 static trim_eq(r,s)
835 register char *r,*s;
836 {
837 	register char c;
838 	while(c = *s++)
839 	{
840 		if(c==ESCAPE)
841 			c = *s++;
842 		if(c != *r++)
843 			return(0);
844 	}
845 	return(*r==0);
846 }
847 
848 /*
849  * print out the command line if set -x is on
850  */
851 
852 void trace_command(com)
853 char **com;
854 {
855 	if(is_option(EXECPR))
856 	{
857 		p_setout(stderr);
858 		fputs(execpmsg,output);
859 		echo_list(1,com,output);
860 		newline();
861 	}
862 }
863 
864